New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically resized maps #260

Closed
Asmageddon opened this Issue Aug 12, 2012 · 20 comments

Comments

Projects
None yet
4 participants
@Asmageddon

Asmageddon commented Aug 12, 2012

In other words, maps that are automatically resized when you paint outside of map boundaries.

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Aug 12, 2012

Owner

Yeah, that would be nice. :-)

Owner

bjorn commented Aug 12, 2012

Yeah, that would be nice. :-)

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Mar 22, 2017

Contributor

What exactly would be the point of this? If by mistake someone paints a tile outside the boundary, then the map would automatically be resized even if the user does not want so. And while drawing on the boundary, this is something that would frequently happen.

Contributor

ketanhwr commented Mar 22, 2017

What exactly would be the point of this? If by mistake someone paints a tile outside the boundary, then the map would automatically be resized even if the user does not want so. And while drawing on the boundary, this is something that would frequently happen.

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Mar 22, 2017

Owner

What exactly would be the point of this? If by mistake someone paints a tile outside the boundary, then the map would automatically be resized even if the user does not want so. And while drawing on the boundary, this is something that would frequently happen.

When somebody would enable automatic resizing of maps, then he would probably not care at all about "painting outside the boundary". The whole point after all is that you don't want to think about such a boundary while mapping, and just have the idea of an infinite canvas. Check out MyPaint for an example of a painting application that has no boundaries on its canvas.

Owner

bjorn commented Mar 22, 2017

What exactly would be the point of this? If by mistake someone paints a tile outside the boundary, then the map would automatically be resized even if the user does not want so. And while drawing on the boundary, this is something that would frequently happen.

When somebody would enable automatic resizing of maps, then he would probably not care at all about "painting outside the boundary". The whole point after all is that you don't want to think about such a boundary while mapping, and just have the idea of an infinite canvas. Check out MyPaint for an example of a painting application that has no boundaries on its canvas.

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Mar 22, 2017

Contributor

Oh, I'll try to work on this one now. Should I add an option to enable/disable it in preferences?

Contributor

ketanhwr commented Mar 22, 2017

Oh, I'll try to work on this one now. Should I add an option to enable/disable it in preferences?

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Mar 22, 2017

Owner

@ketanhwr Hmm, I think you're vastly underestimating the complexity of this. It will need efficient data structures (probably allocating tile layer memory in blocks), and the automatic expansion should work per tile layer and not on the map. It needs to be thought out well before you start. I think it's a project of a month at least.

Just saying this because simply an automatic invocation of the "resize map" action is unlikely to cut it. It would quickly consume a huge amount of memory and probably there would be noticeable performance issues when you go over the "invisible edge" while painting.

Owner

bjorn commented Mar 22, 2017

@ketanhwr Hmm, I think you're vastly underestimating the complexity of this. It will need efficient data structures (probably allocating tile layer memory in blocks), and the automatic expansion should work per tile layer and not on the map. It needs to be thought out well before you start. I think it's a project of a month at least.

Just saying this because simply an automatic invocation of the "resize map" action is unlikely to cut it. It would quickly consume a huge amount of memory and probably there would be noticeable performance issues when you go over the "invisible edge" while painting.

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Mar 23, 2017

Contributor

Oh. I didn't really think of it that way, thanks for your feedback! :-)

Contributor

ketanhwr commented Mar 23, 2017

Oh. I didn't really think of it that way, thanks for your feedback! :-)

@Asmageddon

This comment has been minimized.

Show comment
Hide comment
@Asmageddon

Asmageddon Mar 28, 2017

I do chunks and infinite maps in all tile-based code I do with almost no exceptions, you're gonna be fine with just allocating 16x16 chunks and storing/indexing them from a hashmap.

Automatic invocation of existing map expansion would probably work, save for the part where the map sizes can get potentially big enough to need the sparse storage.

Asmageddon commented Mar 28, 2017

I do chunks and infinite maps in all tile-based code I do with almost no exceptions, you're gonna be fine with just allocating 16x16 chunks and storing/indexing them from a hashmap.

Automatic invocation of existing map expansion would probably work, save for the part where the map sizes can get potentially big enough to need the sparse storage.

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Mar 28, 2017

Owner

I do chunks and infinite maps in all tile-based code I do with almost no exceptions, you're gonna be fine with just allocating 16x16 chunks and storing/indexing them from a hashmap.

Maybe it's something @ketanhwr could consider adding to his Google Summer of Code proposal. While the data changes may not be so complicated, it may affect large amounts of existing code to actually fully support an infinite map.

Owner

bjorn commented Mar 28, 2017

I do chunks and infinite maps in all tile-based code I do with almost no exceptions, you're gonna be fine with just allocating 16x16 chunks and storing/indexing them from a hashmap.

Maybe it's something @ketanhwr could consider adding to his Google Summer of Code proposal. While the data changes may not be so complicated, it may affect large amounts of existing code to actually fully support an infinite map.

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Mar 29, 2017

Contributor

@bjorn, yes, thanks!

Contributor

ketanhwr commented Mar 29, 2017

@bjorn, yes, thanks!

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Mar 29, 2017

Contributor

.. blocks), and the automatic expansion should work per tile layer and not on the map.

@bjorn, what exactly do you mean by this? If we were to resize the layer, we will have to resize the map too nevertheless.

Contributor

ketanhwr commented Mar 29, 2017

.. blocks), and the automatic expansion should work per tile layer and not on the map.

@bjorn, what exactly do you mean by this? If we were to resize the layer, we will have to resize the map too nevertheless.

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Mar 29, 2017

Contributor

Have a look at this: https://github.com/Squarific/TiledCanvas

Is this what we're looking for?

Contributor

ketanhwr commented Mar 29, 2017

Have a look at this: https://github.com/Squarific/TiledCanvas

Is this what we're looking for?

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Mar 29, 2017

Owner

@ketanhwr Well, the technique is similar, yes. But I think MyPaint is a better example of how it would work in Tiled.

@bjorn, what exactly do you mean by this? If we were to resize the layer, we will have to resize the map too nevertheless.

No, the tile layers should grow independently of the map. That of course complicates the feature a little, because so far tile layers have always matched the map size (though this may not be the case for some TMX files you could load), so some new bugs may be found.

Owner

bjorn commented Mar 29, 2017

@ketanhwr Well, the technique is similar, yes. But I think MyPaint is a better example of how it would work in Tiled.

@bjorn, what exactly do you mean by this? If we were to resize the layer, we will have to resize the map too nevertheless.

No, the tile layers should grow independently of the map. That of course complicates the feature a little, because so far tile layers have always matched the map size (though this may not be the case for some TMX files you could load), so some new bugs may be found.

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Jul 3, 2017

Contributor

Alright so a couple of doubts and observations here:

  • As of now, I need to rewrite the functions of flipping, rotating, resize and offset so that they don't iterate over the whole matrix.

  • TileLayers are not only used within the map, but also for previewing tile stamps/terrains/showing tilesets, etc. I think we cannot completely remove mWidth and mHeight from the TileLayer class. We can introduce a variable mInfinite which would denote whether the current layer is infinite or not. mInfinite would be true when a tile layer is a part of map, and false otherwise. Also, the main purpose would be to remove mWidth and mHeight from the Map class.

  • An additional iterator needs to be introduced so that we can traverse over all the chunks. I don't have much idea how I'll implement this as of now.

  • We'll need to modify all the classes which inherit MapRenderer to render an infinite grid. Obviously that won't be possible, so we can render a large enough grid and the user can zoom out only to a maximum level so that this large enough grid is completely visible. And at this maximum zoom level, the user can only scroll to see the rest of the map/grid. This is how MyPaint does it.

  • The Bucket Fill Tool, will have a different way to flood fill now. MyPaint handles the fill tool rather weirdly, so I won't go with that.

Contributor

ketanhwr commented Jul 3, 2017

Alright so a couple of doubts and observations here:

  • As of now, I need to rewrite the functions of flipping, rotating, resize and offset so that they don't iterate over the whole matrix.

  • TileLayers are not only used within the map, but also for previewing tile stamps/terrains/showing tilesets, etc. I think we cannot completely remove mWidth and mHeight from the TileLayer class. We can introduce a variable mInfinite which would denote whether the current layer is infinite or not. mInfinite would be true when a tile layer is a part of map, and false otherwise. Also, the main purpose would be to remove mWidth and mHeight from the Map class.

  • An additional iterator needs to be introduced so that we can traverse over all the chunks. I don't have much idea how I'll implement this as of now.

  • We'll need to modify all the classes which inherit MapRenderer to render an infinite grid. Obviously that won't be possible, so we can render a large enough grid and the user can zoom out only to a maximum level so that this large enough grid is completely visible. And at this maximum zoom level, the user can only scroll to see the rest of the map/grid. This is how MyPaint does it.

  • The Bucket Fill Tool, will have a different way to flood fill now. MyPaint handles the fill tool rather weirdly, so I won't go with that.

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Jul 3, 2017

Owner

As of now, I need to rewrite the functions of flipping, rotating, resize and offset so that they don't iterate over the whole matrix.

While that would be ideal, I think the most important bit is that they won't allocate the entire area as a single block, and instead copy from one set of chunks to a new set of chunks. Changing it to only iterate the relevant chunks is an optimization that can be made later.

I don't see a reason to introduce mInfinite for making a distinction between layers that are part of the map or layers that are used for tile stamps. Either case the layer will still have its bounds, and the difference is only whether the layer will automatically grow when cells are filled outside of those bounds. So I think the only reason to have mInfinite is for the user, to control whether he wants his layers to automatically grow or not.

An additional iterator needs to be introduced so that we can traverse over all the chunks. I don't have much idea how I'll implement this as of now.

Implementing an iterator won't be trivial, but I think it should be an interesting project. Just start by looking up which operators an iterator is expected to provide and then consider how to implement each of them.

We'll need to modify all the classes which inherit MapRenderer to render an infinite grid. Obviously that won't be possible, so we can render a large enough grid and the user can zoom out only to a maximum level so that this large enough grid is completely visible. And at this maximum zoom level, the user can only scroll to see the rest of the map/grid. This is how MyPaint does it.

Yes, Tiled already has a minimum zoom level of 1%, but rendering the grid at that size will be slow and not useful at all. We should probably automatically adjust the number of grid lines when the user zooms out a lot, like only draw a line every 5 or 10 cells. However, the important bit is first of all to render the grid only based on the viewport boundaries and to not take the map size into account.

The Bucket Fill Tool, will have a different way to flood fill now. MyPaint handles the fill tool rather weirdly, so I won't go with that.

I think it's fine that it will first of all just fill up to the current bounds of a layer, and never grow it. It would be interesting of course, to allow filling an empty layer by just changing its "empty cell", and when painting a layer its "empty cell" should be used in places where the cell is empty. However, that will introduce quite a few challenges.

Owner

bjorn commented Jul 3, 2017

As of now, I need to rewrite the functions of flipping, rotating, resize and offset so that they don't iterate over the whole matrix.

While that would be ideal, I think the most important bit is that they won't allocate the entire area as a single block, and instead copy from one set of chunks to a new set of chunks. Changing it to only iterate the relevant chunks is an optimization that can be made later.

I don't see a reason to introduce mInfinite for making a distinction between layers that are part of the map or layers that are used for tile stamps. Either case the layer will still have its bounds, and the difference is only whether the layer will automatically grow when cells are filled outside of those bounds. So I think the only reason to have mInfinite is for the user, to control whether he wants his layers to automatically grow or not.

An additional iterator needs to be introduced so that we can traverse over all the chunks. I don't have much idea how I'll implement this as of now.

Implementing an iterator won't be trivial, but I think it should be an interesting project. Just start by looking up which operators an iterator is expected to provide and then consider how to implement each of them.

We'll need to modify all the classes which inherit MapRenderer to render an infinite grid. Obviously that won't be possible, so we can render a large enough grid and the user can zoom out only to a maximum level so that this large enough grid is completely visible. And at this maximum zoom level, the user can only scroll to see the rest of the map/grid. This is how MyPaint does it.

Yes, Tiled already has a minimum zoom level of 1%, but rendering the grid at that size will be slow and not useful at all. We should probably automatically adjust the number of grid lines when the user zooms out a lot, like only draw a line every 5 or 10 cells. However, the important bit is first of all to render the grid only based on the viewport boundaries and to not take the map size into account.

The Bucket Fill Tool, will have a different way to flood fill now. MyPaint handles the fill tool rather weirdly, so I won't go with that.

I think it's fine that it will first of all just fill up to the current bounds of a layer, and never grow it. It would be interesting of course, to allow filling an empty layer by just changing its "empty cell", and when painting a layer its "empty cell" should be used in places where the cell is empty. However, that will introduce quite a few challenges.

bjorn added a commit that referenced this issue Jul 4, 2017

Changed TileLayer data to be allocated in chunks (#1635)
Now TileLayer data is allocated on-demand in 16x16 chunks.

In preparation of issue #260.
@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Jul 15, 2017

Contributor

So, will all the maps be infinite after this? Or will the user have an option to use the auto-growing functionality while creating a new map?

Contributor

ketanhwr commented Jul 15, 2017

So, will all the maps be infinite after this? Or will the user have an option to use the auto-growing functionality while creating a new map?

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Jul 17, 2017

Owner

@ketanhwr It will need to be an option, because some people need to keep their layers an exact size. This will likely most often be the case for maps that form chunks within a larger context, so I think this makes sense as an option of the Map class.

Owner

bjorn commented Jul 17, 2017

@ketanhwr It will need to be an option, because some people need to keep their layers an exact size. This will likely most often be the case for maps that form chunks within a larger context, so I think this makes sense as an option of the Map class.

@bjorn bjorn closed this in 59b3747 Aug 15, 2017

@HeadClot

This comment has been minimized.

Show comment
Hide comment
@HeadClot

HeadClot Aug 31, 2017

Hey @bjorn Just curious about when we can expect this to be in a stable release?

HeadClot commented Aug 31, 2017

Hey @bjorn Just curious about when we can expect this to be in a stable release?

@ketanhwr

This comment has been minimized.

Show comment
Hide comment
@ketanhwr

ketanhwr Aug 31, 2017

Contributor

@HeadClot you can use this feature in the snapshot release. And I think, Tiled 1.1 will get released within a month, so you can access it there then.

Contributor

ketanhwr commented Aug 31, 2017

@HeadClot you can use this feature in the snapshot release. And I think, Tiled 1.1 will get released within a month, so you can access it there then.

@HeadClot

This comment has been minimized.

Show comment
Hide comment
@HeadClot

HeadClot Aug 31, 2017

Thanks for the info @ketanhwr :)

HeadClot commented Aug 31, 2017

Thanks for the info @ketanhwr :)

@bjorn

This comment has been minimized.

Show comment
Hide comment
@bjorn

bjorn Aug 31, 2017

Owner

There are still some things to improve, most notably the viewport scroll range needs to adjust without interfering with the current scroll position. This is tricky because the code that throws off the current scroll position is in private Qt code and there appears to be no way to disable it.

But still, please don't hesitate to try a development snapshot to see if this feature in general will fit your needs. It's better to get feedback now than after the 1.1 release. :-)

And yes, I hope to release 1.1 within a month, but I'm skeptical whether it will be doable.

Owner

bjorn commented Aug 31, 2017

There are still some things to improve, most notably the viewport scroll range needs to adjust without interfering with the current scroll position. This is tricky because the code that throws off the current scroll position is in private Qt code and there appears to be no way to disable it.

But still, please don't hesitate to try a development snapshot to see if this feature in general will fit your needs. It's better to get feedback now than after the 1.1 release. :-)

And yes, I hope to release 1.1 within a month, but I'm skeptical whether it will be doable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment