Tiled TMX to Orx (incl. isometric). The way to go?

edited January 2013 in Help request
Hello everybody and happy holiday season,

I am back from my vacation and resuming work with Orx. I discussed a bit with sausage and his wonderful Tiled TMX to Orx converter, and decided that Tiled will be the way to go for our game. However, I would like an isometric game, not just orthogonal, and therefore a more complete converter would be needed. Sausage, unfortunately, doesn't really have plans for one, so I am taking this enterprise.

In order to do that, however, I need to know more about both Orx and Tiled, to make sure this is done the best, most efficient, and cleanest way.

As I see it, I have two main options:
  1. Modify tmxviewer (part of the Tiled project) replacing Qt rendering with Orx.
  2. Writing a plugin for Tiled or external converter to ini file that Orx understands natively, and code the map renderer in Orx.

Number 1 above has the advantage of least code rewriting, no need to worry about parsing TMX files, and therefore being less error prone. As a disadvantage, looking at the code, however, it seems Qt is pretty deeply embedded inside of libtiled and might be quite messy to surgically remove. Another problem is that it would require parsing XML files with potential compression on the fly for every single map to be displayed. For android and iOS might not be ideal! Finally, I would be rather limited in the way Orx would render this, for I would essentially be using their rendering method.

Number 2 has many advantages (pretty much all disadvantages of number 1 are solved this way). Also, there is already an ini file exporter (for Flare format) that is similar to Orx. But of course, there is the big disadvantage of having to parse and display exported maps with Orx. I would write this map renderer/manager which gives me flexibility but is obviously somewhat complex and more bug-prone.

So, my question is: Given what Orx can do, what do you think is better?

For example, I imagine Orx handles rendering of objects outside of camera view in an clever way. But how about the processing of config files and pushing/popping sections, searching for keys, parsing values, etc? Does it make more sense to just have a custom render of essentially external (TMX) data, or have everything in Orx configs and be able to use fully the data-driven approach of Orx?

Anyway, sorry for the lengthy question/post!

Cheers,

Edgar

Comments

  • edited January 2013
    Hi duenez,

    I'm not familiar with tmxviewer unfortunately, so I can only offer guidelines and details about orx's internals.

    I'd go with option 2, as it sounds to me to be the most customizable one and would probably benefit other people in the community.

    Again, I don't know what tmxviewer is capable of, but orx allows you to use custom shaders on anything, display freeform geometries (texture-mapped triangle strips or untextured geometric shapes), supports compositing (ie. render to texture), supports culling before rendering, will organize render calls in order to batch them as most as possible for performances, etc...

    Also I'm not sure what you mean by parsing. You shouldn't have to write nor read .ini format directly (which is good as orx is using a custom enhanced format that supports inheritance, for example). You simply need to use the orxConfig API in order to read/write data. Even in your exporter, you can use a stripped down version of orx: for example by using the non-embedded static version and only initializing the config module. This is what's done with the tool called orxcrypt. The advantage is that you won't have to worry about any syntax or parsing issue, and everything should be compliant.

    If you have any questions, don't hesitate, but for now, those are my 0.02$. :)

    Cheers!
  • edited January 2013
    Hi and thanks for the reply iarwain. Helpful as always! :)

    I really shouldn't have said parse, really... I meant, deal with the semantics of the parsed ini file. In other words, I can come up with a transformation between TMX file format (xml based) and an ini file by pretty much directly translating tag elements into config sections. But of course, I would need to meaningfully deal with them once I got them in order to correctly display them in Orx.

    In any case, I think you have convinced me about translating the TMX format into Orx config files. Just some other quick, marginally related, questions: I imagine once a config file is read, it is parsed and stored in memory, right? So, when I try to read a value associated with a key, there is no file access, nor is there to create a list or string from the original text, right? And finally, the only potential parsing would be transforming a value string into a number (say, a double) when needed?

    Cheers and thanks a bunch again,
  • edited January 2013
    duenez wrote:
    Hi and thanks for the reply iarwain. Helpful as always! :)
    My pleasure!
    In any case, I think you have convinced me about translating the TMX format into Orx config files.
    Great! :)
    Just some other quick, marginally related, questions: I imagine once a config file is read, it is parsed and stored in memory, right? So, when I try to read a value associated with a key, there is no file access, nor is there to create a list or string from the original text, right? And finally, the only potential parsing would be transforming a value string into a number (say, a double) when needed?
    Yes, as you expect, all the config data is stored in memory and the only functions that will trigger a disk access are orxConfig_Load() & orxConfig_Save().

    Everything is parsed and hashed at loading time, storing the sections in a hash table and every sub-entry in a local list.
    Values are stored as strings, as they're type-less data.
    However there's a cache system that will remember the last type requested for a value and will cache the result in that format: if you call orxConfig_GetFloat("MyValue"), MyValue will have its float value cached as a float, in addition to the original string format.
    Cache will remember boundaries for random values too.
    The only "reparsing" that will happen is when requesting a list value as orx doesn't store an index (yet, it's something I'm considering) and will just go through the whole string to find the start of the indexed value.
    When a value is inherited, it's flagged as such and the parent is stored as a hashed key that orx will use to find the parenting section in the hash table.

    I think that's about it. ;)

    Cheers!
  • edited January 2013
  • N_KN_K
    edited February 2013
    Sorry for bumping this, but since I have some free time, I'm about to experiment integrating tmx-parser to my Orx application, and see how it goes.

    I used tmx-parser with SFML before, and although I don't like the XML-based TMX format at all, this parser just loads up pretty much everything (including object layers) that you design in Tiled.

    However, I'd like to know where to start exactly. The reason I've abandoned working on an SFML-based engine was because the way SFML handles its sprites. To render an efficient tile map, I had to combine the tiles into vertex arrays, which was fine for static tiles, but even after months, I was not able to come up with any working implementation for animated tiles, or tiles that can be modified by the player or affected by physics. Normally, a tile engine would render each tile a separate sprite, and test the map against the view frustum, so it would only display the ones that are visible. SFML has no built-in visibility determination system (well, I know it's a bit unfair to compare SFML to Orx, as the former is a general-purpose multimedia framework, and the latter is a complete game engine), and while I was able to display a sprite-based tile map without any performance problems on my machine, everyone on the SFML forum recommended to not to do this, as each sprite will have its own transformation information, and while it runs okay on a powerful machine, it will lag on older systems, or with low-end GPUs. But because of the dynamic tile problems mentioned before (and because after 3 months, I finally wanted to work on the game, and not on building an engine), I had to start looking for an engine that could handle the sprite-based approach.

    One of the reasons I've chosen to work with Orx is because it has a complete frustum culling implementation. This would already make my job much easier, but what about sprite batching? When I create many instances of the same sprite, will they be rendered in the same draw call?

    (Wow, too much story, too few information. Sorry... :side: )
  • edited February 2013
    N_K wrote:
    Sorry for bumping this, but since I have some free time, I'm about to experiment integrating tmx-parser to my Orx application, and see how it goes.

    No worries, don't hesitate to bump any topics!

    I'm not familiar with tmx-parser, though I know that sausage wrote his own tmx -> orx converter. It can be found here: https://bitbucket.org/orx/tiledtoorx

    I'm not sure in which state the project currently is though, as I have not used it myself.
    One of the reasons I've chosen to work with Orx is because it has a complete frustum culling implementation. This would already make my job much easier, but what about sprite batching? When I create many instances of the same sprite, will they be rendered in the same draw call?

    So yes, there's frustum culling in orx (performed by the render plugin), but I also have plans of optimizing it for very crowded worlds (think 15000+ objects) using some partitioning scheme.
    The first step will be to modify the render plugin to prevent unnecessary proxy creation/deletion, and I'll be working on this shortly. Here's the associated issue: https://bitbucket.org/orx/orx/issue/15/optimize-render-plugin

    As for draw calls batching, orx is also trying its best there.
    However knowing how it is internally done will help the users in preparing the data in order to get optimal results.

    Not only objects using the same sprite will be batched together, but object whose "sprite" are part of the same textures will get batched. However there are conditions for this to happen in an optimal way:
    Objects will get gathered and grouped first according to their depth (Z coordinate). Then they'll get grouped according to their "material": ie. combination of the texture they use, the custom shader applied on them (if used), their blending mode and their smoothing attribute (aka texture filtering).

    If that isn't very clear, please let me know, I'll be happy to get into the details. :)

    If you display orx's in-game profiler (only active for orx's internals in profile and debug builds, not in release ones), looking at the entry for "orxDisplay_DrawArrays", the number of time it's called per frame is actually the number of batches that were pushed to the GPU (keep in mind that if you display the FPS with the ShowFPS config option, it alone will be on its own batch).

    In the case of the bounce demo, it should be between 4+1 and 7+1:
    - 1 for the walls
    - 1 for the cursor
    - 1 for the + shaped particles
    - 1 for the X shaped particles (yes, they're different ^^)
    - 1 for the balls (if active)
    - 1 for the texts-as-balls (if active)
    - 1 for the smoke trail (if active)
    - 1 for the FPS display

    And this won't change no matter how many objects are actually rendered (which you can see with the profiler entry orxRender_RenderObject).
    (Wow, too much story, too few information. Sorry... :side: )

    Ahah, no, on the contrary, it's always better to ask questions when in doubt! :)
  • N_KN_K
    edited February 2013
    iarwain wrote:
    I'm not familiar with tmx-parser, though I know that sausage wrote his own tmx -> orx converter. It can be found here: https://bitbucket.org/orx/tiledtoorx
    It's a nice tool for simpe maps, but with larger ones with multiple layers, the ini file could get quite big and complicated, that's why using the TMX format is preferable, in my opinion. It's an XML-based format, but the tile data itself is Base64 encoded, then compressed using Zlib, resulting in a very compact map file which is relatively fast to parse, and is also protected from unwanted tampering (but both the encoding and the compression can be turned off in Tiled).

    (Also, if I can do this, I believe that many beginners could be attracted to Orx, as there are almost no 2D engines (or none at all?) that are just able to load up and display a vanilla TMX map. :laugh: )

    My ultimate goal, however, is to write a simple zlib-compressed binary format to store map data (and either write an import/export plugin for Tiled, or write a tool that converts to- and from TMX), but it's not very likely to happen, I'll just go with TMX, I think.

    iarwain wrote:
    Not only objects using the same sprite will be batched together, but object whose "sprite" are part of the same textures will get batched.
    So map tiles that are "clipped out" of various parts of a larger tileset are considered to be the same texture?

    iarwain wrote:
    Objects will get gathered and grouped first according to their depth (Z coordinate).
    So let's say we have a base layer, filled with, for example, ground tiles. Then we have another layer atop of this, containing a house. And so the tiles on the ground layer that are directly beneath the house are not rendered? If yes, what happens when the overlapping tile is semi-transparent?

    iarwain wrote:
    Ahah, no, on the contrary, it's always better to ask questions when in doubt!
    Thanks. Next time, however, I'll open my own topic instead of hijacking existing ones, I promise! :cheer:
  • jimjim
    edited February 2013
    Hey N_K,

    Having a tmx loader would be a great plus for ORX, recent version of Tilemap editor introduced some cool features that are hard to resist, also you can provide collision box or define polygon object, which can be great for collision or creating box2d bodies. So its a great tool to make tiled based games easily.
    (Also, if I can do this, I believe that many beginners could be attracted to Orx, as there are almost no 2D engines (or none at all?) that are just able to load up and display a vanilla TMX map. )
    I wont lie but there are some game engine or library that has native support for tmx loading along with some that don't support it out of the box. I would also try integrating tmx with ORX but I cant do it now, my finals going on :(
    iarwain wrote:
    Not only objects using the same sprite will be batched together, but object whose "sprite" are part of the same textures will get batched.
    So map tiles that are "clipped out" of various parts of a larger tileset are considered to be the same texture?
    I dont know what you meant, but I think I know what Iarwain was trying to say, for example, you will find a desert.tmx map in examples folder in tilemap, which has only one tileset or uses a single image. If you export that map, then the map object consists of a single image hence shares same texture.
    iarwain wrote:
    Objects will get gathered and grouped first according to their depth (Z coordinate).
    So let's say we have a base layer, filled with, for example, ground tiles. Then we have another layer atop of this, containing a house. And so the tiles on the ground layer that are directly beneath the house are not rendered? If yes, what happens when the overlapping tile is semi-transparent?
    They are rendered but using 2 draw calls afaik. So if you have 3 layers, objects would be drawn using at least 3 draw calls, if they all belong to 1 texture or 3 textures at most. So the ground layer would be drawn first, then the house layer. I am considering each layer has different Z- value, I don't know what would happen if you assign same Z-value to all the layers. If your map uses 4 tileset or image but has one layer then your map would be drawn using 4 draw calls. That's what I think but Iarwin would make it more clear.
  • edited February 2013
    N_K wrote:
    It's a nice tool for simpe maps, but with larger ones with multiple layers, the ini file could get quite big and complicated, that's why using the TMX format is preferable, in my opinion. It's an XML-based format, but the tile data itself is Base64 encoded, then compressed using Zlib, resulting in a very compact map file which is relatively fast to parse, and is also protected from unwanted tampering (but both the encoding and the compression can be turned off in Tiled).

    Sure, sounds good.
    However I wanted to point out some details about sausage's choices.
    He chose the orx INI format to not have to do any parsing. It's simply loaded in memory by orx's config module and all the data can then be accessed via the orxConfig API.
    If compression/encoding are important, orx support native encoding for config files (both in read/write modes) and compression can be handled from a resource point of view (the resource tutorial I mentioned earlier is a good example of that, though it's not with a native support in orx this time).
    (Also, if I can do this, I believe that many beginners could be attracted to Orx, as there are almost no 2D engines (or none at all?) that are just able to load up and display a vanilla TMX map. :laugh: )

    Sounds good to me! If you want to host your converter/loader on the orx bitbucket project page, let me know, I'll be happy to grant you access to it. :)
    My ultimate goal, however, is to write a simple zlib-compressed binary format to store map data (and either write an import/export plugin for Tiled, or write a tool that converts to- and from TMX), but it's not very likely to happen, I'll just go with TMX, I think.

    As I said, the compression can be handled on a different layer, via a custom resource type, as demonstrated in the resource tutorial. And in this case any resource data can benefit from it, not only maps.
    Btw, the orxResource API can be used by the end users for handling his/her own resources, it not just meant to be only used by orx's core.
    So map tiles that are "clipped out" of various parts of a larger tileset are considered to be the same texture?

    Yes. Everything that comes from the same file is physically stored on the same texture. Orx will try to do as little context/texture switches as possible when rendering scenes.
    Textures can also be modified, or entirely procedurally created, at runtime.
    So let's say we have a base layer, filled with, for example, ground tiles. Then we have another layer atop of this, containing a house. And so the tiles on the ground layer that are directly beneath the house are not rendered? If yes, what happens when the overlapping tile is semi-transparent?

    No: everything will get rendered, but the render order is based on the depth/Z coordinate. Even within a same draw batch this order will be respected.

    In your case, if your tiles and house are physically stored on the same texture (and assuming there's no custom shader and no smoothing/blending mode differences), everything will be rendered within a single draw batch.
    If they're stored on two separate textures, two draw batches will be needed.
    However, in both cases the result on screen will be strictly identical: everything will get rendered, from far objects to near ones.
    Thanks. Next time, however, I'll open my own topic instead of hijacking existing ones, I promise! :cheer:

    Sounds good! :)
  • edited February 2013
    jim wrote:
    Having a tmx loader would be a great plus for ORX, recent version of Tilemap editor introduced some cool features that are hard to resist, also you can provide collision box or define polygon object, which can be great for collision or creating box2d bodies. So its a great tool to make tiled based games easily.

    Having never really used that map editor, would you mind listing the features that you really enjoy?
    As I plan on enhancing ScrollEd soon, any features idea will be helpful! :)
    I dont know what you meant, but I think I know what Iarwain was trying to say, for example, you will find a desert.tmx map in examples folder in tilemap, which has only one tileset or uses a single image. If you export that map, then the map object consists of a single image hence shares same texture.

    Exactly. :)
    They are rendered but using 2 draw calls afaik. So if you have 3 layers, objects would be drawn using at least 3 draw calls, if they all belong to 1 texture or 3 textures at most.

    Well, not exactly: if all the "sprites" come from the same texture, they'll get rendered in a single draw call, no matter at which depth they are.
    Orx first sorts objects according to their depth, but that doesn't mean that having different depths will generate more draw calls. Actually if your whole scene only uses one texture as input, there'll only be one single batch pushed to the GPU (assuming same shader, same smoothing and same blending mode).

    Actually it's not entirely true: batches have a size limit, from memory I think it's 2048 objects on windows/linux/mac and 1024 on iOS/Android. :)
  • jimjim
    edited February 2013
    Well, not exactly: if all the "sprites" come from the same texture, they'll get rendered in a single draw call, no matter at which depth they are.
    Orx first sorts objects according to their depth, but that doesn't mean that having different depths will generate more draw calls. Actually if your whole scene only uses one texture as input, there'll only be one single batch pushed to the GPU (assuming same shader, same smoothing and same blending mode).
    Thanks for clearing that up :) I think I missed the "sort" part.
    Having never really used that map editor, would you mind listing the features that you really enjoy?
    As I plan on enhancing ScrollEd soon, any features idea will be helpful!
    I have not used TME extensively, also may not be aware of all the features, but here are some that I find interesting :

    1. You can define object layer, and you can set bounding box on any object or in any place in the map. One can define rectangular, elliptical or polygonal bounding area. There is also polyline, Which can be used to define NPC's walking path in many games.

    2. A new feature they added in the last release is Terrain auotmapping, I think best explanation about them can be found below, I can say they automate map creating process and makes level building more easier
    https://github.com/bjorn/tiled/wiki/Automapping
    https://github.com/bjorn/tiled/wiki/Using-the-Terrain-Tool
Sign In or Register to comment.