mapeditor / tiled

Flexible level editor
https://www.mapeditor.org/
Other
10.83k stars 1.72k forks source link

Allow implementation of own projection algorithms #775

Open JeremyWildsmith opened 9 years ago

JeremyWildsmith commented 9 years ago

This feature would be incredibly simple to implement. Simply delegate the projection calculation to a user defined script (it doesn't even have to be a script, just something that can parse simple algebraic expressions.)

At the moment, looking at the source code, the orientation code is not well delegated (a hard-coded enum... Seriously, why an enumeration?) Changing that could be a pain, assuming the actual algorithms for projecting in those orientations are scattered across somewhere else? I am sure I could locate them with enough effort, but IMO that is a terrible way to describe an orientation (ie with an enum) since adding and removing them requires considering all references to that enumeration...

At the moment, working with assets rendered in the Cavalier Oblique projection is impossible, due to a very small obstacle that should event exist IMO.

Thanks.

bjorn commented 9 years ago

Can you please leave your opinions to yourself next issue you open, especially when you didn't take the time to make sure you're well informed? Also, please try not to tell me what is or isn't incredibly simple to implement. If it's so easy, why is this an issue instead of a pull request?

The enum just specifies the valid values, and it's actually barely used because the orientations are abstracted through the MapRenderer interface. Feel free to add a ScriptedRenderer or something class that does what you want.

The thing is that I entirely agree that Tiled should be more scriptable. At the moment it's only possible to write scripts in Python for adding input or output formats. But, obviously scripts should be able to perform actions on the current map, should be able to add custom tools and indeed maybe also custom rendering logic. However, contrary to your belief I do not think this is a trivial thing to add and I simply did not have time for this yet.

Btw, isn't cavalier oblique like the perspective_walls.tmx example? What's the difference that makes you need special rendering logic?

JeremyWildsmith commented 9 years ago

Some programmable projection matrix that isn't hard-coded. It doesn't have to be via a script engine. It can literally be asking for a Matrix to transform from world space to screen space. Like, literally asking for an array of 2X2 or 3X3 floating points to define a transformation matrix.

Opinion is a huge factor IMO. There are a lot of people out there with opinions on how something should be done. None of them are 'right.' The way enums were used to describe projection isn't ideal, in my opinion.

I don't need 'special rendering logic.' I need something that just so happens not to be isometric or orthogonal... And there are a lot of such projections.

I don't understand how perspective_walls.tmx helps me with my issue though...

bjorn commented 9 years ago

It can literally be asking for a Matrix to transform from world space to screen space. Like, literally asking for an array of 2X2 or 3X3 floating points to define a transformation matrix.

Actually the map renderers implement quite a bit more than just a projection matrix. Some things, like the staggered renderer, would not even be possible using a projection matrix. The same goes for a hexagonal renderer. In any case, since you maintain that it's so simple the invitation to submit a patch is still open.

Opinion is a huge factor IMO. There are a lot of people out there with opinions on how something should be done. None of them are 'right.' The way enums were used to describe projection isn't ideal, in my opinion.

Of course opinions are important, but again as I said you should make sure to inform yourself appropriately. You made false assumptions about the code and then went on to say how terrible it all was. I do this project for fun and share my code so that it may be useful to people. I'm open to suggestions for improvement, but I don't like being insulted for my design decisions.

I don't understand how perspective_walls.tmx helps me with my issue though...

Yet, you failed to include any information that would have answered my question about the difference. Maybe you have a screenshot of what you're trying to achieve? Because for example Ultima VII used a similar projection and it would work the same way as the example shipping with Tiled:

Ultima VII

However, I guess your "depth axis" is not the height but rather the y axis in which case you would need a new kind of renderer.

JeremyWildsmith commented 9 years ago

I don't understand why a staggered render would not be possible if projections were described by a transformation matrix. A general algorithm for all projection matrixes could be a applied to achieve a staggered effect. Ie, offset y by -1 for every x (something like that, either way its just a matter for projecting through the matrix Ina different fashion, being independent from the transformation matrix itself.). You would still use the same algorithm for every transformation matrix.

I didn't make any false assumptions about "your" code. I simply pointed out that the use of an enumeration there (whatever the purpose) is inappropriate. The only way for me to appreciate the scope of impact of that enum is by being familiar with all the code (which I obviously am not) or by being told by you, which is also why I'd not think it should be used.

Anyways, my projection axis do not align with the screen space axis (not sure if that's the proper way to say it?) Thus I cannot use the orthogonal orientation.

You can appreciate from my perspective that I don't have the environment setup to compile tiled and I don't have any days off coming soon. Its a bit of a hassle to pull the repo, initialize the environment (download dependencies etc) to perform a relatively small change . A lot of people use tiled for convenience.

I use tiled to package my smaller tilesets into larger entities (ie compile a bunch of road tiles into a road slab.) Then I can import that into my editor and it is easier to work with (ie, entities need more metadata, such as aabb etc to perform proper depth sorting.) The point I'm getting at is that I use tiled because it saves me a lot of time. I would love to contribute, but I simply don't have enough time on my hands at the moment.

bjorn commented 9 years ago

I didn't make any false assumptions about "your" code.

The false assumptions were "the orientation code is not well delegated" and "the actual algorithms for projecting in those orientations are scattered across somewhere else". I realize the latter was framed as a question, but you had already made your assumption and continued to explain how terrible it was.

It's actually quite straight-forward to add a new renderer. Sure judging by the three renderers implemented it's actually about 500 lines of code, which is a lot more than would be needed if your approach had been taken. But it does not require adapting code scattered throughout the editor.

Anyway, I accept your ideas for improvement.

I would love to contribute, but I simply don't have enough time on my hands at the moment.

Same here, unfortunately.

stefanbeller commented 9 years ago

just skimming over this issue, having not read all your walls of text, this sounds like #698 ?

bjorn commented 9 years ago

@stefanbeller Hmm, no, that has nothing to do with it.

stefanbeller commented 9 years ago

Sorry for the noise then.

kheftel-old commented 9 years ago

Tiled isn't a 3D program. It's not a simple matter of adding a different matrix to change the projection. It's 2D which kind of simulates 3D, in the way retro games simulate 3D, and as such, each different projection does have to be coded by hand., as it's a lot of specific coding, "smoke-and-mirrors", etc, to try and simulate pseudo-3D using a 2D engine. There is no way to base that on a projection matrix so you can just "throw in a different matrix" and have it work. Several projections have been coded for, if you want to add another, as Bjorn said, feel free to make a pull request.

JeremyWildsmith commented 9 years ago

Kheftl I don't agree. Can you provide any concrete examples?

Rybadour commented 9 years ago

I wasn't able to read through all of this yet and I'm not exactly sure if it's relevant but I came looking for a solution to my problem. I was hoping to use Tiled to place tiles from these sets: http://opengameart.org/content/tower-defense-assets-isometric

The problem is the tiles are not perfect square diamonds but rather tilted. So the "height" is smaller than the width in these sets. I assume this is an issue with how they were generated being a different projection then Tiled expects.

Wouldn't it be possible to have a slider for isometric maps that allows you to define the "angle" that the tiles are rendered?

I can provide screenshots, just let me know.

kheftel-old commented 9 years ago

JeremyWildsmith I suggest you research more on the differences between 2D engines and 3D ones. I don't have time to list all the differences, there are many. Suffice it to say that it's not as easy as you think. The isometric projection is not determined by a matrix, so if you pass it a matrix it wouldn't know what to do with it.

For one concrete example, think of the legend of zelda: a link to the past. Yes, it's not isometric, but it uses an orthogonal projection. Both isometric and orthogonal projections are not true 3D, but pseudo-3D, and wouldn't know what to do with a projection matrix if you did supply one.

Rybadour commented 9 years ago

Nevermind, my use case is covered by changing the height of each tile. Didn't expect it to have that effect.

JeremyWildsmith commented 9 years ago

Kheftel, I believe the core thesis to your argument is "The isometric projection is not determined by a matrix, so if you pass it a matrix it wouldn't know what to do with it."

Is that to say that it cannot be, or that it isn't inside of Tiled? I know that it isn't inside of Tiled, but yes it can be (and it would signfiicantly simplify the solution while removing tons of boilerplate code I saw last time I looked at tiled.) It has nothing to do with "3D Space" at all. Matrices are not exclusive to 3D applications.

You have two spaces, screen space and world space. You can project world space into screen space without it having anything at all to do with 3D or 2D for that matter. In this case, both spaces are 2D...

You can use an X by Y matrix to translate your world space into your isometric, orthogonal, or whatever screen space. It just represents a system of equations to translate between the two. Nothing to do with isometric, orthogonal, 3D or 2D. It's just projecting from one space to another using a device.

In this case, Tiled works in 2D space, and that device is most optimally a 2X2 Matrix. You can project from you 2D world space along a 2D Isometric "plane" by using the respective matrix. Absolutely none of that has anything to do with a third coordinate.

kheftel-old commented 9 years ago

I believe the core thesis of your argument is "this feature would be incredibly easy to implement", which it is not.

I apologize if I came across as rude, I didn't intend to, but in reading back on my words I was a little hasty to judge.

Of course it's doable, but as far as I can tell it would require a major rewrite of tile's internals and be a lot of work. I also think a lot of the special cases of various 2D projections would have to be taken into account, in order to support the simplicity of changing a matrix and the whole projection changes.

bjorn commented 9 years ago

While it may work for isometric, it would not cover the staggered and hexagonal map renderers, which are really not doable with a matrix multiplication (if you believe it is, correct me by explaining how). Also the grid rendering would still need to be customly implemented.

So while this may be an interesting feature addition, I don't see it replacing the orientation enumeration as suggested in this issue.

JeremyWildsmith commented 9 years ago

kheftel, as per bjorn's own words "orientations are abstracted through the MapRenderer interface." So, despite some UI Code modifications, it would simply be a matter of implementing a MapRenderer that is passed a projection Matrix... It definitely doesn't (or it shouldn't) require a "major rewrite." Granted, IMO that MapRenderer abstract class seems a little bulky for it's purpose and I fear there might be a lot of boilerplate code between the renderers. ~500 lines of code for each renderer seems to suggest that.

Bjorn, the existence of the orientation enum has nothing to do with my feature request. That is a different issue enitrely and either of the two issues can be resolved entirely independent of each-other.

In terms of hex tiles... that doesn't have anything to do with the projection between screen and world space. If you want to draw a square object in world space, you project its four corners via the matrix and (in the case of an isometric world) you would get a triangle like figure. Same logic & procedure for a hex-figure. You want to project a hex figure through to screen space from world space? Project each of the six points that define its shape. There is no difference there. A matrix cannot create shapes for you.

There is a clean general purpose solution for all map types in terms of staggered tiles. You can merely create a wrapper class that staggers (ie, shifts left/right) each second "row/column" of a tile's world coordinate as it it passed in or fed out of the "wrappee."

Anyways, this is an old issues and I have since resolved it by some other internal means. Thanks for your time on reading this.