Extra zoom vs. fences alignment - quick view on a problem

Discuss, get help with, or post new graphics for TTDPatch and OpenTTD, using the NewGRF system, here. Graphics for plain TTD also acceptable here.

Moderator: Graphics Moderators

Post Reply
LeXa2
Engineer
Engineer
Posts: 87
Joined: 15 Jul 2012 03:54
Location: Moscow, Russian Federation

Extra zoom vs. fences alignment - quick view on a problem

Post by LeXa2 »

Hello to all TTD fans and devs, it's good to see that the game is still rolling after all the years that had passed.

It's been a while for me since I last looked at the OpenTTD, last time I remember doing something with TDD it ages back to 2004. At that moment unicode support hadn't been implemented yet and thus Russian translation of the game had been using latin1 "translit encoding" instead of normal cyrillic alphabet. Back to those days I've spent some time implementing a Russian-font NewGRF and rewriting translation to use cyrillic alphabet. Several months later that work was obsoleted by newly implemented unicode support in trunk :-). Later on work and IRL things pulled me off from the video games for the most part for several years, but now I had managed to sneak some time to return to gaming again and one of the first projects to look at was good-old OpenTTD.

As it is well known, with the 1.2 release things got quite disappointing wrt 32bit graphics support. Prior to 1.2 plain png 32bpp was supported (with extra-zoom levels if using out-of-tree patch) and one could easily install and use lots of freely available 32bpp sprite packs (most of them were with unclean licensing policy, but its not the thing "usual player" would care about). Release 1.2 introduced official 2x and 4x zoom levels support, but at the same time removed support of the "plain png files" for sprites. All existing 32bpp packs were expected to be converted into new 32bpp NewGRF format, but it was mostly impossible to do "officially" due to licensing concerns. Net result is that half a year past the 1.2 release we still have to stick with the original (or OpenGFX) supplied 8bpp sprites for the most part, making the game look "not up to the 2012 standards" at 2x and 4x zoom levels.

Some of the existing 32bpp sprites were accompanied with permissive licensing, so I had tried to play a bit with a number of them trying to produce 32bpp NewGRFs. To prevent some questions: I know that it is possible to bulk-convert so-called "32bpp dev megapack" - and I had done it for myself - but my intention was to try to produce some NewGRFs which could be distributed in a (mostly) license-compliant way and could be used by end-users up until to the moment when OpenGFX+ (or some other) team would catch up and - hopefully - release full 32bpp baseset.

As land and field tiles by Ben Robbins already were converted into NewGRFs and as Ben Robbins had released all of his TTD-related gfx work posted to the tt-forums under GPLv2 and as this work included 32bpp 4x zoom sprites for fences - I had decided to try to convert fences into NewGRF as a "first attempt to so something".

Writing nfo file and composing grf wasn't a hard task really (some shell-fu magic is all that needed to do the trick, IMO its not worth bothering with NML when dealing with simple sprites replacements), but the produced visual result wan't perfect: fences seemed to be located where they should be - i.e. at the edges of the tiles - but the alignment at the corner crossing was certainly off (i.e. some corners looked like "X" instead of "L" in shape). Playing a bit with OpenTTD's built-in NewGRF alignment tool and analyzing how does the corner crossing look for different directions I've come to a conclusion that with current engine implementation for fences it might be impossible to align their sprites in a way that fences would be (a) continous and (b) align precisely at corner crossings.

In order to prove this assumption I've took a look into OpenTTD source and it seems that I had found the answer (dig into "src/clear_cmd.cpp" and "src/table/clear_land.h" for actual code).

Here is the math:

a) Tiles in TTD world use isometric projection of the pseudo-3D world, with tile coordinate system used having it's base point at the north corner of the tile, X axis is directed south-west (i.e. downwards and to the left) collinear with the northwest edge of the tile. Z axis is "height" and after projection "shifts" sprite up at the screen space, Y axis is similar to X but is collinear with the north-east edge of the tile. Tile has the square shape if looked from above (i.e. when projected orthogonally to a plane which is orthogonal to Z axis) with edges being 16 "units" wide. Projection is done in a way that after the projection to a screen space flat tile looks like rhomb with longer diagonal being 64 pixels wide (normal zoom) and shorter diagonal being 32 pixels wide. It gives us 16x16 units wide XY coordinate space per a flat tile.

b) Fences are a part of the so-called "base tile set" and like some other base tile set sprites doesn't have bounding box defined for them. Fences placement relative to the tile is handled by the game engine itself (i.e. it is hard-coded into the source and there are no means of changing it other than patching the source and recompiling the engine), and the engine uses the same sprites for north-west/south-east and north-east/south-west fences. Things are a bit more complicated for sloped tiles, but the general point is the same: shared sprite being used whenever possible. From this "sharing" fact one conclusion could be made: there's no way to distinctively align fences for sides that use shared sprite. Change the alignment for the sprite that is being used for north-west and you would at the same time change the alignment of the south-east fence. Same for north-east and south-west, e.t.c.

c) Actual fence placement inside the tile is not aligned with 16 "units" granularity on the X and Y sides by the engine, fences are placed with the assumption that they are 15 units in length. In other words, coordinates for fences vertex inside the like are (0;0), (0;15), (15;15) and (15;0). It is illustrated on the Pic.1 I attach to this message (click on thumbnail to the bottom to see it fullsize). And here is the core of the problem - it means that by the nature of engine fence placement they are not expected to be continous - i.e. there are 1 "unit" wide gaps between placed fences at the neighboring tiles.
Image

Common misbelieve is that "fencing could be aligned properly - as they are in base set, it's just designer/artist hands that should be fixed".
It is wrong, and here is pic.2 which demonstrates why (original Windows TTD baseset used):

Image

OK, so now we know the problem. How could we solve it?

As I had already written on Pic.1, one could simply accept the fact that the fences are not expected to be continous and that some crossings wouldn't be "perfect" and live with it. It is totally possible to do right now and I had done it. Results are, ughm, not the most visually pleasant thing I'd ever seen.

Here are screenshots so one would be able to judje by himself (be sure to click on thumbnails to see _the_real_ picture!):

Zoom 4x:
ImageImage
ImageImage

Zoom 2x:
ImageImage

Normal zoom:
ImageImage

That's it. For now I had only "fixed" normal fences, hedges and stone fences are to be looked at. It could be seen that the gaps between fences are barely noticeable at "Normal" zoom level. My next experiment would be try to patch the engine so it would place the fences aligned to 16 unit grid and check if that would "fix" the things in the way I expect it. Be tuned :-).

P.S. I'm going to post here resulting NewGRF + sources as soon as I would make sure that there are not licensing problems with used sprites and would be more or less satisfied with the achieved visual results. Comments concerning licensing issues for the used sprites are welcome. Also I'm in search for "stone fence" sprites as the 32bpp fences "tar" I have use "hedge" sprites by Ben Robbins for both hedges and stone fences, and that's not what I want ;-).

P.P.S. Any NFO, GRF or source code files I post to this forum which are written by me or contain some amount of changes done by me are licensed under GNU/GPL v2 license unless specifically stated otherwise. In case the work posted is based on sources which are licensed in incompatible way with GNU/GPLv2 it should be assumed that I license my changes in a way that is compatible with the licensing of the original work. I.e., if the original work was licensed under creative commons derivate - my changes are assumed to be licensed the same. Same stands for other widely used "liberate" licensing schemes, like "BSD-style", "Apache", e.t.c.
Attachments
OpenTTD-Fences-Pic1.jpeg
(248.4 KiB) Downloaded 3 times
OpenTTD-Fences-Pic1-thumb.jpeg
OpenTTD-Fences-Pic1-thumb.jpeg (7.22 KiB) Viewed 8027 times
2012-07-15_OpenTTD-Fences-Pic2.jpg
(279.77 KiB) Downloaded 3 times
LeXa2
Engineer
Engineer
Posts: 87
Joined: 15 Jul 2012 03:54
Location: Moscow, Russian Federation

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by LeXa2 »

For last several weeks I've been spending my free time on another OTTD-related project, namely 32bpp sprite-based anti-aliased blitter a.k.a. "perform zooming out properly so resulting picture won't hurt eyes", but as a part of the development process I've been able to spend a tiny amount of time addressing "the fences alignment problem" I've peen posting about in this thread.

With a small (two lines affected changing number "15" into 16) patch to clear_cmd.cpp it is possible to achieve pixel-perfect fences alignment. This is essentially (c) way of solving the problem as was detailed here.

Here is a screenshot displaying that this solution works and looks perfect, here I had been using zBase tileset as fence sprites source (click on it to get full-sized pic in lossless PNG):

Image

P.S. It'd be cool if PHP BB allowed for disabling auto-displaying attached images by setting appropriate checkbox in the attachments section, without it posts like this one get thumbnail pics double-displayed :-(.
Attachments
2012-08-04_OpenTTD-Fences-01.png
(4.04 MiB) Downloaded 3 times
2012-08-04_OpenTTD-Fences-01_thumb.jpg
2012-08-04_OpenTTD-Fences-01_thumb.jpg (59.58 KiB) Viewed 7812 times
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by FooBar »

Then don't inline the thumbnail using [img], but using the "place inline" button below the text area ;)

Question: how does it handle situations where you have double fences, like below?
Knipsel.PNG
Knipsel.PNG (258.42 KiB) Viewed 7792 times
Or did you change it so that no double fences are drawn? Which would be better, as they're silly anyways. Case and point: how would one use this gate?
Attachments
Knipsel2.PNG
Knipsel2.PNG (98.48 KiB) Viewed 7792 times
LeXa2
Engineer
Engineer
Posts: 87
Joined: 15 Jul 2012 03:54
Location: Moscow, Russian Federation

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by LeXa2 »

FooBar wrote:Then don't inline the thumbnail using [img], but using the "place inline" button below the text area ;)
It won't allow me to have url tag around thumb linking to fullsize lossless-compressed original. Or would it? Actually I hadn't tried enclosing attachment tag in url (or wise versa), maybe it'd work for my needs.
FooBar wrote:Question: how does it handle situations where you have double fences, like below?
Or did you change it so that no double fences are drawn? Which would be better, as they're silly anyways. Case and point: how would one use this gate?
It doesn't handle such case at all, meaning that double fences are drawn at places like that, just like as on second screenshot you attached here.
It could be addressed though, but isn't that simple. As I already concluded in the initial analysis of the problem, we have to either decouple sprite offsets from sprites themselves when drawing fences (or simply teach engine to use different sprites when drawing fences for north/south and west/east sides of the tile) or align sprites in grid matching landscape tile alignment and cope somehow (for example, by simply ignoring the problem and getting by with it - having properly aligned fences IMO is of a more importance than "making it possible to open the gates like that" :-) ) with double-fences problem.
LeXa2
Engineer
Engineer
Posts: 87
Joined: 15 Jul 2012 03:54
Location: Moscow, Russian Federation

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by LeXa2 »

LeXa2 wrote:...It could be addressed though, but isn't that simple....
Or is. It took me about 30 minutes to track back to a function that causes double-fences issue and fix it so the engine would no longer generate double-fences for farm fields.
Here is the screenshot with this patch working:
2012-08-04_OpenTTD-Fences-02.png
2012-08-04_OpenTTD-Fences-02.png (245.37 KiB) Viewed 7774 times
This patch won't fix fences that had already been generated, i.e. it won't fix your savegames that are affected by this.
You could find a patch in the attachments to this post.
Attachments
2012-08-04-OTTD-Fix-fences.patch
(2.38 KiB) Downloaded 261 times
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by FooBar »

Nice!
If you tidy the code up a bit, I recommend you post this to the bugtracker, as I'm quite certain the devs are interested in this fix.
LeXa2
Engineer
Engineer
Posts: 87
Joined: 15 Jul 2012 03:54
Location: Moscow, Russian Federation

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by LeXa2 »

FooBar wrote:Nice!
If you tidy the code up a bit, I recommend you post this to the bugtracker, as I'm quite certain the devs are interested in this fix.
IMO formally following exact letter of formatting guidelines for this specific case (i.e. introduce {} for each conditional branch) isn't a good idea, but that's a matter of personal preference. As for submitting the patch there - it seems that devs are frequent visitors to these forums so most probably they had already seen this topic. Let's wait a bit and see if there'd be any input from guys like planetmaker, Michi_cc, rubidium, Yexo. Alberth and other respected persons about the approach this patch takes, because I haven't got a deep knowledge about OTTD internals and what could seem to be a viable solution after 30 mins of hacking might turn out to be a disaster that breaks everything.
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by FooBar »

LeXa2 wrote:i.e. introduce {} for each conditional branch
Not necessary, there's also this:
http://wiki.openttd.org/Coding_style#Control_flow wrote:When only a single statement is contained, the brackets can be omitted. In this case, put the single statement on the same line as the preceding keyword (if, while, etc.). Note that this is only allowed for if statements without an else clause.
I don't want to be nitpicking, as the fix is three seconds work in this case. But it's easier to have it "by the rules" if you at some point have larger patches ready for trunk inclusion :)
J0anJosep
Traffic Manager
Traffic Manager
Posts: 139
Joined: 06 Aug 2011 15:51
Location: Spain

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by J0anJosep »

It looks to me that the two last parameters SetupFarmFieldFence(..., Axis direction, bool north) are the equivalent of a DiagDirection. Maybe rewriting the function passing a DiagDirection would help. But not sure.

Great work, BTW.

Edit: TileAddByDiagDir(). Possibly you should check if it returns a valid tile. Hope it helps.
Formerly known as Juanjo
LeXa2
Engineer
Engineer
Posts: 87
Joined: 15 Jul 2012 03:54
Location: Moscow, Russian Federation

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by LeXa2 »

Juanjo wrote:It looks to me that the two last parameters SetupFarmFieldFence(..., Axis direction, bool north) are the equivalent of a DiagDirection. Maybe rewriting the function passing a DiagDirection would help. But not sure.

Great work, BTW.

Edit: TileAddByDiagDir(). Possibly you should check if it returns a valid tile. Hope it helps.
Yeah, surely SetupFarmFieldFence() could be rewritten using TileAddByDiagDir(). On the other hand I don't see an urgent need for that as it works as it is.
As for checking for tile to be correct - looks like it might be required, but only for negative offsets passed to TileAddXY, as farm fields never could be placed on MP_VOID tiles and thus we would always have a valid neighbour for any given tile. On the other hand UpdateFences() in clear_cmd.cpp seems not to worry about hitting such case and unconditionally checks all the possible neighbours for their type which makes me to believe that - as the game don't crash on this one - it is not possible for a fields to be placed on a tile with y==0.

Upd. Reading code a bit more reveals that all tiles with either x or y coordinate equal to 0 would be MP_VOID (in case freeform edges are enabled) or indestructible MP_WATER, thus we are also safe for negative neighbours offsets. Thanks to clever initial design we're free from doing extra check here.
J0anJosep
Traffic Manager
Traffic Manager
Posts: 139
Joined: 06 Aug 2011 15:51
Location: Spain

Re: Extra zoom vs. fences alignment - quick view on a proble

Post by J0anJosep »

LeXa2 wrote:As for checking for tile to be correct...
:oops: It wasn't necessary then.
LeXa2 wrote:Yeah, surely SetupFarmFieldFence() could be rewritten using TileAddByDiagDir(). On the other hand I don't see an urgent need for that as it works as it is.
Avoiding the "if else if else", if that can be done. I'm not saying it is possible.
Formerly known as Juanjo
Post Reply

Return to “Graphics Development”

Who is online

Users browsing this forum: No registered users and 23 guests