News:

Simutrans Wiki Manual
The official on-line manual for Simutrans. Read and contribute.

Tunnel internal images query

Started by jamespetts, December 11, 2016, 01:13:54 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

jamespetts

To take a break from the intensive work for the last two weeks or so in making passenger generation work multi-threadedly, I thought that it would be a good idea to implement proper internal images for tunnels that are not tied to ways, so that players can replace ways inside the tunnels without replacing the tunnel internal graphics (Simutrans-Experimental already recognises the tunnel's way as being distinct from the tunnel itself and allows it to be upgraded).

However, to do this, I need to delve into a complex and not easy to understand system in Simutrans with which I have not worked much before: the node system for reading/writing images. I should therefore be most grateful for the assistance of any Standard developers in helping me to understand this part of the code to enable me to add this feature.

Essentially, what I need to do is to store the tunnel internal images after the existing tunnel portal images in Makeobj (tunnel_writer.cc), and then enable those to be retrieved by applying suitable offsets in tunnel_besch.h.

Am I right, first of all, in thinking that the tunnel internal images can simply be appended by adding code adapted from way_writer.cc to tunnel_writer.cc after the existing image writing code?

Secondly, if that is correct, am I also correct in thinking that the existing code in weg_besch.h could likewise be used to retrieve these images if copied to tunnel_besch.h with the modification of adding further offset numbers based on the number of tunnel portal images already stored?

If I am correct in both of those thoughts, how would I determine the correct offset number to apply?

For reference, the existing code for retrieving tunnel portal images in tunnel_besch.h is:


const bild_besch_t *get_hintergrund(hang_t::typ hang, uint8 season, uint8 type ) const
    {
        int const n = season && number_seasons == 1 ? 5 : 2;
        return get_child<bildliste_besch_t>(n)->get_image(hang_indices[hang] + 4 * type);
    }

    image_id get_hintergrund_nr(hang_t::typ hang, uint8 season, uint8 type ) const
    {
        const bild_besch_t *besch = get_hintergrund(hang, season, type );
        return besch != NULL ? besch->get_nummer() : IMG_LEER;
    }

    const bild_besch_t *get_vordergrund(hang_t::typ hang, uint8 season, uint8 type ) const
    {
        int const n = season && number_seasons == 1 ? 6 : 3;
        return get_child<bildliste_besch_t>(n)->get_image(hang_indices[hang] + 4 * type);
    }

    image_id get_vordergrund_nr(hang_t::typ hang, uint8 season, uint8 type) const
    {
        const bild_besch_t *besch = get_vordergrund(hang, season, type );
        return besch != NULL ? besch->get_nummer() : IMG_LEER;
    }


and the code for retrieving way images in weg_besch.h is:


uint16 image_list_base_index(bool snow, bool front) const
    {
        if (number_seasons == 0  ||  !snow) {
            if (front  &&  front_images) {
                return (number_seasons == 0) ? 6 : 9;
            }
            else {
                return 2;
            }
        }
        else { // winter images
            if (front  &&  front_images) {
                return 12;
            }
            else {
                return 6;
            }
        }
    }


and


image_id get_bild_nr(ribi_t::ribi ribi, uint8 season, bool front = false) const
    {
        if (front  &&  !front_images) {
            return IMG_LEER;
        }
        int const n = image_list_base_index(season, front);
        return get_child<bildliste_besch_t>(n)->get_bild_nr(ribi);
    }

    image_id get_bild_nr_switch(ribi_t::ribi ribi, uint8 season, bool nw, bool front = false) const
    {
        if (front  &&  !front_images) {
            return IMG_LEER;
        }
        int const n = image_list_base_index(season, front);
        bildliste_besch_t const* const bl = get_child<bildliste_besch_t>(n);
        // only do this if extended switches are there
        if(  bl->get_anzahl()>16  ) {
            static uint8 ribi_to_extra[16] = {
                255, 255, 255, 255, 255, 255, 255, 0,
                255, 255, 255, 1, 255, 2, 3, 4
            };
            return bl->get_bild_nr( ribi_to_extra[ribi]+16+(nw*5) );
        }
        // else return standard values
        return bl->get_bild_nr( ribi );
    }

    image_id get_hang_bild_nr(hang_t::typ hang, uint8 season, bool front = false) const
    {
        if (front  &&  !front_images) {
            return IMG_LEER;
        }
        int const n = image_list_base_index(season, front) + 1;
        int nr;
        switch(hang) {
            case 4:
                nr = 0;
                break;
            case 12:
                nr = 1;
                break;
            case 28:
                nr = 2;
                break;
            case 36:
                nr = 3;
                break;
            case 8:
                nr = 4;
                break;
            case 24:
                nr = 5;
                break;
            case 56:
                nr = 6;
                break;
            case 72:
                nr = 7;
                break;
            default:
                return IMG_LEER;
        }
        image_id hang_img = get_child<bildliste_besch_t>(n)->get_bild_nr(nr);
        if(  nr > 3  &&  hang_img == IMG_LEER  &&  get_child<bildliste_besch_t>(n)->get_anzahl()<=4  ) {
            // hack for old ways without double height images to use single slope images for both
            nr -= 4;
            hang_img = get_child<bildliste_besch_t>(n)->get_bild_nr(nr);
        }
        return hang_img;
    }

    image_id get_diagonal_bild_nr(ribi_t::ribi ribi, uint8 season, bool front = false) const
    {
        if (front  &&  !front_images) {
            return IMG_LEER;
        }
        const uint16 n = image_list_base_index(season, front) + 2;
        return get_child<bildliste_besch_t>(n)->get_bild_nr(ribi / 3 - 1);
    }

    bool has_double_slopes() const {
        return get_child<bildliste_besch_t>(3)->get_anzahl() > 4
        ||     get_child<bildliste_besch_t>(image_list_base_index(false, true) + 1)->get_anzahl() > 4;
    }

    bool has_diagonal_bild() const {
        return get_child<bildliste_besch_t>(4)->get_bild_nr(0) != IMG_LEER
        ||     get_child<bildliste_besch_t>(image_list_base_index(false, true)+2)->get_bild_nr(0) != IMG_LEER;
    }

    bool has_switch_bild() const {
        return get_child<bildliste_besch_t>(2)->get_anzahl() > 16
        ||     get_child<bildliste_besch_t>(image_list_base_index(false, true))->get_anzahl() > 16;
    }
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.

jamespetts

I have been spending some considerable time attempting to work this out, but am finding capricious and unpredictable results.

I have added the following code to makeobj:


// These are the internal images
// Code adapted from the way writer
slist_tpl<string> keys;
static const char* const image_type[] = { "", "front" };
for (int backtofront = 0; backtofront<2; backtofront++)
{
char buf[64];
sprintf(buf, "%sundergroundimage[new2][0]", image_type[backtofront]);
// test for switch images
const uint8 ribinr = *(obj.get(buf)) == 0 ? 16 : 26;
for (ribi = 0; ribi < ribinr; ribi++)
{
char buf[64];

sprintf(buf, "%sundergroundimage[%s]", image_type[backtofront], ribi_codes[ribi]);
string str = obj.get(buf);
keys.append(str);
}
imagelist_writer_t::instance()->write_obj(fp, node, keys);

keys.clear();
for (hang = 3; hang <= 12; hang += 3)
{
char buf[64];

sprintf(buf, "%sundergroundimageup[%d]", image_type[backtofront], hang);
string str = obj.get(buf);
keys.append(str);
}
for (hang = 3; hang <= 12; hang += 3)
{
char buf[64];

sprintf(buf, "%sundergroundimageup2[%d]", image_type[backtofront], hang);
string str = obj.get(buf);
if (!str.empty())
{
keys.append(str);
}
}
imagelist_writer_t::instance()->write_obj(fp, node, keys);

keys.clear();
for (ribi = 3; ribi <= 12; ribi += 3)
{
char buf[64];

sprintf(buf, "%sundergrounddiagonal[%s]", image_type[backtofront], ribi_codes[ribi]);
string str = obj.get(buf);
keys.append(str);
}
imagelist_writer_t::instance()->write_obj(fp, node, keys);
keys.clear();
}


To tunnel_besch.h, I have added:


image_id get_underground_backimage_nr(ribi_t::ribi ribi) const
{
//int const n = addition_for_underground_images();
int n = 8;
return get_child<bildliste_besch_t>(n)->get_bild_nr(ribi);
}

image_id get_underground_frontimage_nr(ribi_t::ribi ribi) const
{
int const n = addition_for_underground_images();
return get_child<bildliste_besch_t>(n)->get_bild_nr(ribi);
}


and


uint8 addition_for_underground_images() const
{
// One of each for each position (back, front)
uint8 number = 2;

if (number_seasons > 1)
{
// One of each for each season (normal, snow)
number *= 2;
}

if (broad_portals)
{
// One of each for each portal type (single, left, middle, right)
number *= 4;
}

return number;
}


I have added code to call get_underground_frontimage_nr and get_underground_backimage_nr in the appropriate places in tunnel.cc.

What actually happens, however, is that, in two rotations, the double height incline ("hang" no. 6 for Up2) is shown, and in the other two rotations, no images are shown. This seems to happen for any value of "n" that does not cause a crash by access violation in get_image.

What I had expected to happen would be for the correct value of n, being a number to take into account all of the portal images already in the object, would give the correct images for tunnels on level ground (and I could then go on to add code for slopes later).

I do not understand why it is behaving in this way. The code is based on the code for the ways. My difficulty is that I do not understand how the code for storing images works, which seems to be very complex and undocumented. Can anyone explain this at all? Having even an overview would save me a truly enormous amount of time in attempting to make this work by trial and error.
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.

jamespetts

I have eventually managed to make this work, and have added some code comments explaining what I have found out about the node system in the process.
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.