Author Topic: Understanding the graphics code: vehicle positioning  (Read 1784 times)

0 Members and 1 Guest are viewing this topic.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Understanding the graphics code: vehicle positioning
« on: July 06, 2017, 11:42:26 PM »
Apologies for troubling you all with this question; I hope that this is in the right forum; my apologies if it is not.

As some of you may know, Simutrans-Extended has had for some time a difficulty with gaps between rail vehicles. Specifically, when a steam locomotive with a tender reverse, a gap appears between the locomotive and the carriages/wagons.

I have never been able to understand this problem well enough to fix it, largely because I do not understand the graphics code. I suspect that it might not be too hard to solve if I were to understand the relevant graphics code.

I suspect that the problem is fundamentally derived from the fact that, in Simutrans-Extended, some rail vehicles do and some rail vehicles do not flip directions when they reach a reversing point in their schedule, such as a terminus station. In Simutrans-Standard, the whole train will always flip directions, so this issue cannot occur. However, in Simutrans-Extended, a steam locomotive with a tender will always flip directions, but the carriages will stay in their original orientation, and just travel backwards behind the flipped locomotive. If the alignment of the carriages (in the backwards direction) and the locomotive (in the forewards direction) are not identical in the pakset, then I can see where the gaps might form. This might also explain why I did not see this problem on some tests in Pak64 many years ago.

I had thought of a possible solution to this by attempting to apply an additional offset to vehicles in the reversed orientation. Looking at the code, however, I realise that I do not understand enough about how the graphics code works in order to do this without spending weeks just picking through the code and trying to work out what it means.

If any of the Standard developers can give any insight into the working of the graphics code, especially as regards vehicle positioning, I should be very grateful. Thank you all in advance.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Leartin

Re: Understanding the graphics code: vehicle positioning
« Reply #1 on: July 07, 2017, 04:56:01 AM »
I can't give you insight on how the code works, but knowing how graphics work, the problem seems pretty obvious.

Simutrans started out with vehicles of length 8 only, and vehicle graphics work around that fact. If you compare the positions of a l8-vehicle with one of l2 or l12, you will notice that it grows shorter or longer only on the back end of the vehicle, while the front end remains in position. For the same reason, you can create an l8-vehicle with only 4 graphics, while you need 8 graphics for any other lenght, since their positions would not be identical (well, or you use offset, but you still need to define 8 graphics)

If you tested with pak64 many years ago, you probably had l8-vehicles, since the pakset is so old, and would not get any issue with them.


So currently, each vehicle behaves like an l8 vehicle, with the length-flag only indicating the position of the next wagon behind it and whether it fits a station. In order to achieve what you want, you could add another hack to offset vehicles that move backwards according to their length parameter. (that would be length-8*(paksize/16)). This would likely be another hack on top of a lot of hacks that came before, which is probably why you can't understand the code in the first place.

For clean code, you'd probably need to rework a lot more, since you'd likely position each individual vehicle based on it's length parameter, rather then revolving the code around length 8. Not that I know anything about the actual coding involved.
« Last Edit: July 07, 2017, 06:57:02 AM by Leartin »

Offline Dwachs

  • DevTeam, Coder/patcher
  • Administrator
  • *
  • Posts: 4279
  • Total likes: 195
  • Helpful: 149
  • Languages: EN, DE, AT
Re: Understanding the graphics code: vehicle positioning
« Reply #2 on: July 07, 2017, 07:40:23 PM »
I have never understood the positioning of vehicles graphics.

What is your code doing with respect to reversing? Does it just show a different graphic? Or does this involve some fiddling with internal steps, offsets etc?

I fear there is no easy way to show reverse graphics correctly for all vehicles of all paksets with the same piece of code :(
Parsley, sage, rosemary, and maggikraut.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #3 on: July 07, 2017, 08:41:43 PM »
Thank you both very much for your replies: I am always struck by how helpful that people are on this forum.

To answer Dwachs' question: the code for reversing convoys is in void convoi_t::reverse_order(bool rev). I reproduce it below:

Code: [Select]
void convoi_t::reverse_order(bool rev)
{
// Code snippet obtained and adapted from:
// http://www.cprogramming.com/snippets/show.php?tip=15&count=30&page=0
// by John Shao (public domain work)

uint8 a = 0;
    vehicle_t* reverse;
uint8 b  = vehicle_count;

working_method_t wm = drive_by_sight;
if(front()->get_waytype() == track_wt || front()->get_waytype() == tram_wt || front()->get_waytype() == maglev_wt || front()->get_waytype() == monorail_wt)
{
rail_vehicle_t* w = (rail_vehicle_t*)front();
wm = w->get_working_method();
}

if(rev)
{
front()->set_leading(false);
}
else
{
if(!back()->get_desc()->is_bidirectional())
{
// Do not change the order at all if the last vehicle is not bidirectional
return;
}

a++;
if(front()->get_desc()->get_power() > 0)
{
// If this is a locomotive, check for tenders/pair units.
if (front()->get_desc()->get_trailer_count() > 0 && vehicle[1]->get_desc()->get_leader_count() > 0)
{
a ++;
}

// Check for double-headed (and triple headed, etc.) tender locomotives
uint8 first = a;
uint8 second = a + 1;
while(vehicle_count > second && (vehicle[first]->get_desc()->get_power() > 0 || vehicle[second]->get_desc()->get_power() > 0))
{
if(vehicle[first]->get_desc()->get_trailer_count() > 0 && vehicle[second]->get_desc()->get_leader_count() > 0)
{
a ++;
}
first++;
second++;
}
if (vehicle_count > 1 && vehicle[1]->get_desc()->get_power() == 0 && vehicle[1]->get_desc()->get_trailer_count() == 1 && vehicle[1]->get_desc()->get_trailer(0) && vehicle[1]->get_desc()->get_trailer(0)->get_power() == 0 && vehicle[1]->get_desc()->get_trailer(0)->get_value() == 0)
{
// Multiple tenders or Garretts with powered front units.
a ++;
}
}

// Check whether this is a Garrett type vehicle (with unpowered front units).
if(vehicle[0]->get_desc()->get_power() == 0 && vehicle[0]->get_desc()->get_capacity() == 0)
{
// Possible Garrett
const uint8 count = front()->get_desc()->get_trailer_count();
if(count > 0 && vehicle[1]->get_desc()->get_power() > 0 && vehicle[1]->get_desc()->get_trailer_count() > 0)
{
// Garrett detected
a ++;
}
}

// Check for a goods train with a brake van
if((vehicle[vehicle_count - 2]->get_desc()->get_freight_type()->get_catg_index() > 1)
&& vehicle[vehicle_count - 2]->get_desc()->get_can_be_at_rear() == false)
{
b--;
}

for(uint8 i = 1; i < vehicle_count; i++)
{
if(vehicle[i]->get_desc()->get_power() > 0)
{
a++;
}
}
}

back()->set_last(false);

for( ; a<--b; a++) //increment a and decrement b until they meet each other
{
reverse = vehicle[a]; //put what's in a into swap spacekarte_t::load(
vehicle[a] = vehicle[b]; //put what's in b into a
vehicle[b] = reverse; //put what's in the swap (a) into b
}

if(!rev)
{
front()->set_leading(true);
}

back()->set_last(true);

reversed = !reversed;
if (rev)
{
re_ordered = !re_ordered;
}

for(const_iterator i = begin(); i != end(); ++i)
{
(*i)->set_reversed(reversed);
}

if(front()->get_waytype() == track_wt || front()->get_waytype()  == tram_wt || front()->get_waytype() == maglev_wt || front()->get_waytype() == monorail_wt)
{
rail_vehicle_t* w = (rail_vehicle_t*)front();
w->set_working_method(wm);
}

welt->set_dirty();
}

The code that calls the above code is as follows:

Code: [Select]
const bool reverse_as_unit = re_ordered ? front()->get_desc()->get_can_lead_from_rear() : back()->get_desc()->get_can_lead_from_rear();

reversable = reverse_as_unit || (vehicle_count == 1 && front()->get_desc()->is_bidirectional());

reverse_delay = calc_reverse_delay();

state = REVERSING;
if(front()->last_stop_pos == front()->get_pos())
{
// The convoy does not depart until it has reversed.
book_departure_time(welt->get_ticks() + reverse_delay);
}

reverse_order(reversable);

In essence, what it does is it reverses the order of vehicles in a convoy, excepting some particular cases (vehicles not marked as "bidirectional" in their .dat files). In other words, the code for reversing does not have any direct interaction with the graphics code at all.

Leartin's suggestion seems worth trying, but first I have to work out where the algorithm that he suggested should actually be placed in the code. I have found the following method:

Code: [Select]
void vehicle_base_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const

Is this where I should be looking to place Leartin's algorithm, does anyone think?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Ters

  • Coder/patcher
  • Devotee
  • *
  • Posts: 4900
  • Total likes: 217
  • Helpful: 108
  • Languages: EN, NO
Re: Understanding the graphics code: vehicle positioning
« Reply #4 on: July 07, 2017, 08:50:32 PM »
Having dedicated images for reversing might have some advantages beyond not having to fiddle with offsets. End lights would show the proper colors, and for electric vehicles, the correct pantograph would be raised.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #5 on: July 07, 2017, 10:17:04 PM »
That is an interesting idea, but the number of vehicles in Pak128.Britain-Ex makes this unfeasible.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Dwachs

  • DevTeam, Coder/patcher
  • Administrator
  • *
  • Posts: 4279
  • Total likes: 195
  • Helpful: 149
  • Languages: EN, DE, AT
Re: Understanding the graphics code: vehicle positioning
« Reply #6 on: July 08, 2017, 08:39:38 AM »
void vehicle_base_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const

is indeed the right place to adjust offsets.
Parsley, sage, rosemary, and maggikraut.

Offline Ters

  • Coder/patcher
  • Devotee
  • *
  • Posts: 4900
  • Total likes: 217
  • Helpful: 108
  • Languages: EN, NO
Re: Understanding the graphics code: vehicle positioning
« Reply #7 on: July 08, 2017, 01:24:19 PM »
That is an interesting idea, but the number of vehicles in Pak128.Britain-Ex makes this unfeasible.

I don't think that will stop people from requesting it, so you may want to think a bit ahead, unless you intend to veto such a feature.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #8 on: July 08, 2017, 05:43:15 PM »
The trouble is that it will increase the amount of work required to produce any rail vehicle considerably, so the economics of this feature are not workable in the long-term.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Leartin

Re: Understanding the graphics code: vehicle positioning
« Reply #9 on: July 08, 2017, 07:20:36 PM »
That is an interesting idea, but the number of vehicles in Pak128.Britain-Ex makes this unfeasible.
[...]
The trouble is that it will increase the amount of work required to produce any rail vehicle considerably, so the economics of this feature are not workable in the long-term.

I think there is another option.
Your current approach is to have the vehicle in the game as always, and then use some calculation on runtime to create an offset.
You could instead use a tool to do the same kind of calculation on the dat-files, and writing new graphic definitions for reverse with an offset, using the images already present. Thus, you let that tool run over all the existing vehicles, which - being an automation - is feasable for any number of vehicles. As far as I remember, identical graphics with different offset are still the same and only stored once in the pak-file and during the game, so it should not affect the image limit or space needed.

Thinking it further, instead of a seperate tool, you could use makeobj to do this kind of calculation, similar to how shorthand dats work. Have a symbol you can use in the dat instead of a written offset, eg. writing OFFSET. When makeobj is creating pak-files, have it replace any instance of OFFSET with the offset as it would be calculated in the game. Do this by storing the length-parameter of each object, and further looking at the direction in the graphics definition. You also know the pak-size, since makeobj was started with that parameter.

Thus, a typical graphics definition could look like this:
Code: [Select]
emptyimage[s,w,e,n,ne,sw,nw,se]=image.<$0/4>.<$0%4>
emptyreverse[s,w,e,n,ne,sw,nw,se]=image.<$0/4>.<$0%4>,OFFSET

Which of course would need to be used in all the existing graphics definitions, but this is just duplicating each image-definition, replacing "image" with "reverse", and adding ",OFFSET" at the end - at least for the bulk, it would clash with vehicles already utilyzing offsets, but that's not common.

It would have the same result als calculating offset on runtime, except creators CAN choose to use different graphics for reversed vehicles - which they don't need to align anew, since OFFSET could still be used.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #10 on: July 08, 2017, 07:59:54 PM »
That is an interesting idea, although the coding overhead for that way of doing it would be much higher than for the original more straightforward plan, for a feature that nobody has requested at this stage.

I will have to look into the code and give some consideration to the matter.

Edit: I have made an initial attempt to test how to implement the code based fix. (The makeobj fix is likely to be unworkable, as it would require a four dimensional array of images, with indices for the direction, livery, freight image and whether reversed or not; I am not sure whether the three dimensional array that I created for freight images combined with liveries even works).

The relevant additional code is as follows (at the top of get_screen_offset()):

Code: [Select]
// Just TESTing for now (all below code before the space)
    //  length-8*(paksize/16))
    sint32 adjusted_steps = steps;
    const vehicle_t* veh = obj_cast<vehicle_t>(this);
    if (false && veh && (veh->is_leading() || (veh->get_desc()->get_leader_count() > 0 && veh->get_desc()->get_trailer_count() == 0 && veh->get_desc()->get_power() == 0)) && veh->get_convoi()->is_reversed())
    {
        adjusted_steps -= (veh->get_desc()->get_length_in_steps() - VEHICLE_STEPS_PER_CARUNIT);
    }

I have put this first attempt at a fix on the reverse-graphics-fix branch for testing purposes.

The code,

Code: [Select]
(veh->is_leading() || (veh->get_desc()->get_leader_count() > 0 && veh->get_desc()->get_trailer_count() == 0 && veh->get_desc()->get_power() == 0))

is temporary testing code designed to isolate the locomotive and tender from the carriages. If I do not include that code, then the whole train, with gaps exactly as before, is simply displayed about a tile or half a tile further back.

The results are as follows: without the new code applied, the gaps appear in the train as follows:



With the new code applied, instead of gaps, the train is compressed as follows, with the locomotive overlapping the tender:



Notice that the short carriages overlap the longer carriages in reverse formation in both cases. In the forward orientation, there are no gaps or overlapping:



For reference, the locomotive has a length of 6, the tender a length of 4, the short carriages have a length of 5 and the long carriages have a length of 9.

Interestingly, the gaps seem only to appear when there are short carriages in the train. When I remove the short carriages (with the unmodified code), I do not get the gaps when the train is reversed:



This suggests that the issue is somewhat more complex than it may have first appeared. Indeed, looking carefully at the first image with the gaps, if the short carriages were in the right place, there would not be any gap between the locomotive and the rest of the train.

The longer carriages that I used have a length of 9, very close to the default, so I tried the experiment again with some extra long carriages, with a length of 11. With the same locomotive, it can be seen that these carriages overlap the tender significantly:



For reference, this is the effect when the train is composed only of short carriages:




Thus, it appears that the problem only occurs when vehicles of different lengths (1) to one another; and (2) to 8 are present in a train.

I am not entirely sure quite what to make of this and how to go about fixing it, but any guidance would be welcome.
« Last Edit: July 08, 2017, 10:25:47 PM by jamespetts »
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Ters

  • Coder/patcher
  • Devotee
  • *
  • Posts: 4900
  • Total likes: 217
  • Helpful: 108
  • Languages: EN, NO
Re: Understanding the graphics code: vehicle positioning
« Reply #11 on: July 09, 2017, 12:39:50 PM »
The trouble is that it will increase the amount of work required to produce any rail vehicle considerably, so the economics of this feature are not workable in the long-term.

It is my impression that it is often artists who ask for these things. And you don't have to make reverse images mandatory. In fact, you shouldn't. You don't even have to make the feature now. It was just some advice to make sure what you do do now doesn't make dedicated reverse images harder to do later than it otherwise would have been.

Offline Leartin

Re: Understanding the graphics code: vehicle positioning
« Reply #12 on: July 09, 2017, 02:24:21 PM »
Thus, it appears that the problem only occurs when vehicles of different lengths (1) to one another; and (2) to 8 are present in a train.
I am not entirely sure quite what to make of this and how to go about fixing it, but any guidance would be welcome.

certainly, if all vehicles have the same length, even though they are all misplaced, they are misplaced the same way, so you would not notice it on an open track. You should still be able to notice at stations and signals, though.

Quote
is temporary testing code designed to isolate the locomotive and tender from the carriages. If I do not include that code, then the whole train, with gaps exactly as before, is simply displayed about a tile or half a tile further back.
It shouldn't be possible for the whole train to move a bit, since only reversed vehicles should be affected by the offset in the first place. The locomotives position should not be affected, as it is already correct - it's not in reverse.

I do not understand the code, and it's just a comment anyway, but it should not be "length-8*(paksize/16))" and rather "(length-8)*(paksize/16)". The "paksize-16"-part is pretty much just there to give you a basic offset-unit in pixels, while "length-8" tells you how many of these units you need. If the vehicle has length 8, it does not need offset. The offset can either be positive or negative, depending on whether the vehicle is shorter or longer, since shorter vehicles need to be put forward a bit, while longer vehicles need to stay back.


Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #13 on: July 09, 2017, 03:07:15 PM »
It shouldn't be possible for the whole train to move a bit, since only reversed vehicles should be affected by the offset in the first place. The locomotives position should not be affected, as it is already correct - it's not in reverse.

I must confess to being rather confused by this. The line:

Code: [Select]
if (veh && (veh->is_leading() || (veh->get_desc()->get_leader_count() > 0 && veh->get_desc()->get_trailer_count() == 0 && veh->get_desc()->get_power() == 0)) && veh->get_convoi()->is_reversed())

is the only thing that determines whether any given vehicle applies the new offset (the "false &&" in the excerpt above was incorrectly copied: it was just a hack to turn the code on and off for testing that I had forgot to remove when copying above). The  veh->get_convoi()->is_reversed() tells us whether the whole convoy is reversed, but does not tell us anything about whether the individual vehicle is reversed: as stated, the steam locomotive with a tender does not reverse, whereas the carriages reverse. This is why it was necessary to have the means of telling apart the locomotive and tender from the carriages. As stated, this code is temporary for testing purposes at present.


Quote
I do not understand the code, and it's just a comment anyway, but it should not be "length-8*(paksize/16))" and rather "(length-8)*(paksize/16)". The "paksize-16"-part is pretty much just there to give you a basic offset-unit in pixels, while "length-8" tells you how many of these units you need. If the vehicle has length 8, it does not need offset. The offset can either be positive or negative, depending on whether the vehicle is shorter or longer, since shorter vehicles need to be put forward a bit, while longer vehicles need to stay back.

The code comment was copied verbatim from your post above; I have in any event adapted it to this:

Code: [Select]
adjusted_steps -= (veh->get_desc()->get_length_in_steps() - VEHICLE_STEPS_PER_CARUNIT);

as using that original (psudo)code did not work in any event. The use of get_length_in_steps() and VEHICLE_STEPS_PER_CARUNIT are intended to remove the need for multiplying by the pakset size and dividing by zero every time.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Leartin

Re: Understanding the graphics code: vehicle positioning
« Reply #14 on: July 09, 2017, 04:41:51 PM »
I need to point this out again: I don't actually know the code at all, nor programming language - just a bit of logic, and a grasp of how things probably work. So yes, all I could possibly provide is pseudo code to display an approach of how to tackle a problem, never a solution in it's own right.

I assumed you already had a way to know which vehicles are in reverse and which are turned around, as you would need to know which display their "West" graphic and which display their "East" graphic. But even so, if your temporary code succeeds, then the tender should not move at all in relation to the locomotive. Perhaps it would be best to test with trains that reverse in full, but have vehicles of different length, to avoid issues due to temporary code.


I do not know what "get_length_in_steps()" and "VEHICLE_STEPS_PER_CARUNIT" are. I don't know what "adjusted_steps" is. But I can assume again: Steps are the different positions a vehicle can have within a tile, and the length_in_steps is probably to count how many steps after this vehicle a following vehicle would enter the tile, while VEHICLE_STEPS_PER_CARUNIT is a constant for length 8 in steps. Correct so far? If 'adjusted steps' is the position of the vehicle after it is 'moved' from it's original step-position, your code might succeed in getting rid of the gaps, BUT a reversed vehicle would behave differently in a curve than a non-reversed vehicle, long vehicles would turn earlier and short vehicles would turn later than their non-reversed counterparts, since the steps indicate where the vehicle actually is on the tile, not just where the graphic is.

I attached a graphic to show what I mean. I drew a red grid around the first coach to show where it is positioned. The grid is (supposed to be) length 8, and we might call it a 'hitbox' for lack of better terminology. The bottom image shows how it would be with a normal wagon - the graphic of the wagon starts at the same position as the 'hitbox', and the last part of the 'hitbox' is empty. When you reverse a car, you currently run into the problem that the hitbox stays the same, but the graphic is on it's end, rather it's beginning. This causes the gaps.
Your current approach - IF I understood it - would be to move the hitbox including the graphic, rather than just the graphic within the hitbox.


Let me stress again that I do not know the code and just work with assumptions and logic here, so I could be totally off - so don't trust me on this, or anything related to code, just take it as an idea that you can follow upon. Or I can shut up - it's a code thread, and I know nothing. Choice is yours ;)

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #15 on: July 09, 2017, 05:07:26 PM »
Thank you for your reply. I should note that I need to test with the locomotive and tender (i.e., non-reversing vehicles) because a train in which all vehicles reverse does not have the gaps at all, even with different lengths of vehicles. See this test, with the same carriages, but a different (tank) locomotive that reverses in the same way as the carriages:



Thinking about it, it is extremely odd that the locomotive should affect the relative positioning of the carriages in this way - I cannot understand that at all.

I sympathise with you not knowing the details of the code - Simutrans code can be very arcane in many places. The corrolory of that sometimes this older code is faster than the equivalent modern, more easily maintainable code, but it can be very awkward while trying to modify it.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Vladki

Re: Understanding the graphics code: vehicle positioning
« Reply #16 on: July 09, 2017, 08:20:11 PM »
Hello all. This is very interesting topic.

I skipped quickly through this discussion, and I must support the suggestion for having optional reversed images. In pak128.CS we already have the necessary graphics for some railway engines that are asymmetric, like steam tank engines. Now they are coded as separate vehicles, like class_310, and class_310_reversed. Also, unlike in pak128.Britain, all vehicles use special colors for front and tail lights, and that makes them even more awkward when running reversed, even if the vehicle is otherwise symmetric.

Another think that is worth considering with vehicle positioning is that vehicle waiting at signal often "overshoots" ahead of signal. It is independent of pakset, std/ext, seems to be more apparent in some directions, than others. Also road vehicles sometimes overshoot over the dead end stop.


Offline TurfIt

Re: Understanding the graphics code: vehicle positioning
« Reply #17 on: July 10, 2017, 02:05:05 AM »
I would suggest your adjustment should simply be:
Code: [Select]
sint32 adjusted_steps = steps;
const vehicle_t* veh = obj_cast<vehicle_t>(this);
if(  veh  &&  veh->is_reversed()  ) {
adjusted_steps += (VEHICLE_STEPS_PER_TILE / 2 - veh->get_desc()->get_length_in_steps());
}
All reversed images need an offset, and being reversed is the only condition.

For the typical alignment in Pak128.Britain-EX, this seems to mostly work. Not withstanding the misaligned and/or wrong specified length on some vehicles... (i.e. they have gaps/overlaps even when not reversed)

The question is, do you want to force this paks alignment as the only one? If not, the adjustment will vary depending upon the paksets authors chosen alignments - perhaps on a per vehicle basis too. Once you've gone to specifying different offsets in the .dats for forward and reversed images, you might as well add separate reversed images entirely...



Another think that is worth considering with vehicle positioning is that vehicle waiting at signal often "overshoots" ahead of signal. It is independent of pakset, std/ext, seems to be more apparent in some directions, than others. Also road vehicles sometimes overshoot over the dead end stop.
It's a trade off by the pak author with how he aligns the graphics. Either the graphics jump when changing directions, or they overshoot the stop positions. When stopping at stations, north and westbound convois are special cased to stop half a tile short, but when stopping at signals or intersections, they graphically overshoot. This is a fundamental limitation of the tile-by-tile movement in the game engine - not likely to be changed anytime soon.


---
As a side note, you might want to look into the variable shadowing of 'reversed'....
And get rid of this beauty:
Code: [Select]
# define reversed y
yeesh.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #18 on: July 10, 2017, 11:01:51 AM »
TurfIt - thank you very much for that: that is most helpful. I have applied your patch on the reverse-graphics-fix branch. The results are interesting. While steam trains with tender locomotives no longer display the problem with gaps/overlapping:



trains where all vehicles reverse (such as steam trains pulled by tank engines) now do have this problem, whereas previously they did not:



(Both of the trains above have more or less the same carriages and both are in reversed orientation).

In theory, I imagine that this could be fixed by simply storing whether, if the train is reversed, all the vehicles reversed or not, and then deciding whether to run your code based on checking this conditional, however it might be sensible to understand better what is going on before doing this.

Incidentally, the variable shadowing was intended to allow "reversed" to be used inside a koord object for use in a hashtable, if I recall correctly.

Edit: Testing with other paksets: pak128.CS-Ex appears fine so far, although (1) I have not tested steam locomotives (I am not sure whether it has any); and (2) it has the same problem with trains where locomotives change ends but do not change directions as with the tank engine above). Pak128.Sweden-Ex appears to work well with trains with tender engines in both forward and reverse on the straight, but has gaps in reverse orientation on the diagonal, which I do not understand: it is not clear to me why there should be a difference between straight and diagonal.
« Last Edit: July 10, 2017, 11:17:46 AM by jamespetts »
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Offline Vladki

Re: Understanding the graphics code: vehicle positioning
« Reply #19 on: July 10, 2017, 04:16:38 PM »
Pak128.cs has a lot of steam engines, but they do not have the extended options specified yet. Same is for most of the train wagons. Only some diesel engines have set bidirectional = 1 and class 810 railbuses (bidirectional + lead from rear on some pieces). Check out one of the save games used to report bugs. The vehicles in that game should be all bidirectional.




Offline TurfIt

Re: Understanding the graphics code: vehicle positioning
« Reply #20 on: July 10, 2017, 06:53:05 PM »
trains where all vehicles reverse (such as steam trains pulled by tank engines) now do have this problem, whereas previously they did not:
Forgot I had nuked other wrong code. In convoi_t::vorfahren() kill the entire:
Code: [Select]
if(reversed && (reversable || front()->is_reversed()))
clause. i.e. Just use the else.

The actual internal positioning of vehicles doesn't care if anything is reversed, only the appropriate graphic offsets are required. (use of OBJECT_OFFSET_STEPS incorrectly in this clause doesn't help either...)

The code special casing the positioning for reversing north and west trains needs a tweak too - the back of the convoi hangs off the end of the platforms when the convoi pulls in all the way. Strangely the convoi sometimes stops a full tile short - Extended seems to have some weird behaviour with stop positions.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #21 on: July 10, 2017, 11:08:11 PM »
Excellent, thank you very much. I have just pushed your fix to the reverse-graphics-fix branch, and this now seems to work well. That is extremely helpful and much appreciated.

It also seems to obviate the problems with the Swedish steam locomotives and the gaps on diagonals, and I cannot find any difficulty with the Czech vehicles in one of the saved games uploaded for signalling debugging either.

I wonder whether Vladki and/or Ves could check to see whether this causes any particular difficulty with the Czech/Swedish paksets before I commit this to master?

This fix is lightweight enough so as not to cause any problems with any potential future addition of reversed graphics should anybody want this, although I still anticipate this being a very difficult job owing to the need to create a four dimensional array.

I am extremely grateful to TurfIt for the help in fixing a long-standing anomaly that has worsened the appearance of trains quite considerably.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Online Ves

Re: Understanding the graphics code: vehicle positioning
« Reply #22 on: July 11, 2017, 09:22:33 PM »
An interresting topic!
I dont know what could cause the strange gap you saw on the swedish pakset, I know there is ONE vehicle where I have experimented with offsets in the dat-file (one of the blue cars called "Se_B7_1980") for one diagonal, because, due to their length of 18 vehicle steps, the transition between diagonal and straight tends to be "gappy".

I know that the british pakset has almost all graphich in a more or less complete state, but I must second Vladki that it would be nice to be able make difference between frontal and reversal driving. If (once upon a time in the future, maybe... :::) ) more layers are allowed to vehicle images, ie front and back image, then that would be really handy combination with different graphics on reversal. But its nice to hear that you have made it in the code so that it is possible to implement at a later stage!

I have briefly tested the branch with pak.sweden and it appears to work very well! Thanks for your efforts, everybody! :thumbsup:


Offline Vladki

Re: Understanding the graphics code: vehicle positioning
« Reply #23 on: July 11, 2017, 09:50:08 PM »
I did some more testing, with steam engine with tender, asymmetric diesel engine, and it looks OK.

I found one glitch with cars that are pax+mail which are a piece of hack by themselves (same graphics, and first part is length=0, second part is price+weight=0)
You can see the second part on corners, when the train goes in reverse. Anyway I think the graphics is ok. Oerhaps we cold find some other way to make combined cars work better.

Online jamespetts

  • Simitrans-Extended project coordinator
  • Devotee
  • *
  • Posts: 16149
  • Total likes: 446
  • Helpful: 178
  • Cake baker
    • Bridgewater-Brunel
  • Languages: EN
Re: Understanding the graphics code: vehicle positioning
« Reply #24 on: July 11, 2017, 11:07:53 PM »
Splendid - I have now pushed this to the master branch: thank you all very much for your help and testing: that is much appreciated.

Reversed vehicle graphics, as I noted, will be difficult to implement because of the complexity of having a four-dimensional array, but are theoretically possible at least, as TurfIt's code does nothing to preclude this (and even if this restively small change has to be reversed in future to implement this, it would not affect existing paksets). I should note, however, that this is currently regarded as a very low priority (but, of course, if someone else would like to write the code for it, that is another matter).

As to vehicles with combined cargoes, this is a difficult topic indeed, and altering this would mean a very large overhaul of lots of fundamental parts of the code, which would be a lot of work. It is possible that this might be implemented one day, but is not currently a priority.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.