diff options
-rw-r--r-- | engine.c | 30 | ||||
-rw-r--r-- | grfspecial.c | 84 | ||||
-rw-r--r-- | rail_cmd.c | 5 | ||||
-rw-r--r-- | sprite.h | 78 | ||||
-rw-r--r-- | station.h | 11 | ||||
-rw-r--r-- | station_cmd.c | 36 |
6 files changed, 189 insertions, 55 deletions
@@ -196,6 +196,9 @@ void SetWagonOverrideSprites(byte engine, struct SpriteGroup *group, wos->overrides_count * sizeof(struct WagonOverride)); wo = &wos->overrides[wos->overrides_count - 1]; + /* FIXME: If we are replacing an override, release original SpriteGroup + * to prevent leaks. But first we need to refcount the SpriteGroup. + * --pasky */ wo->group = *group; wo->trains = trains; wo->train_id = malloc(trains); @@ -207,8 +210,10 @@ static struct SpriteGroup *GetWagonOverrideSpriteSet(byte engine, byte overridin struct WagonOverrides *wos = &_engine_wagon_overrides[engine]; int i; - // XXX: This could turn out to be a timesink on profiles. We could always just - // dedicate 65535 bytes for an [engine][train] trampoline. + // XXX: This could turn out to be a timesink on profiles. We could + // always just dedicate 65535 bytes for an [engine][train] trampoline + // for O(1). Or O(logMlogN) and searching binary tree or smt. like + // that. --pasky for (i = 0; i < wos->overrides_count; i++) { struct WagonOverride *wo = &wos->overrides[i]; @@ -232,7 +237,9 @@ static struct SpriteGroup _engine_custom_sprites[256][NUM_CID]; void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group) { - assert(group->sprites_per_set == 4 || group->sprites_per_set == 8); + /* FIXME: If we are replacing an override, release original SpriteGroup + * to prevent leaks. But first we need to refcount the SpriteGroup. + * --pasky */ _engine_custom_sprites[engine][cargo] = *group; } @@ -240,6 +247,7 @@ int GetCustomEngineSprite(byte engine, uint16 overriding_engine, byte cargo, byte loaded, byte in_motion, byte direction) { struct SpriteGroup *group = &_engine_custom_sprites[engine][cargo]; + struct RealSpriteGroup *rsg; int totalsets, spriteset; int r; @@ -250,22 +258,26 @@ int GetCustomEngineSprite(byte engine, uint16 overriding_engine, byte cargo, if (overset) group = overset; } - if (!group->sprites_per_set && cargo != 29) { + /* TODO: Resolve surreal groups properly. --pasky */ + rsg = TriviallyGetRSG(group); + + if (!rsg->sprites_per_set && cargo != 29) { // This group is empty but perhaps there'll be a default one. - group = &_engine_custom_sprites[engine][29]; + /* TODO: Resolve surreal groups properly. --pasky */ + rsg = TriviallyGetRSG(&_engine_custom_sprites[engine][29]); } - if (!group->sprites_per_set) { + if (!rsg->sprites_per_set) { // This group is empty. This function users should therefore // look up the sprite number in _engine_original_sprites. return 0; } direction %= 8; - if (group->sprites_per_set == 4) + if (rsg->sprites_per_set == 4) direction %= 4; - totalsets = in_motion ? group->loaded_count : group->loading_count; + totalsets = in_motion ? rsg->loaded_count : rsg->loading_count; // My aim here is to make it possible to visually determine absolutely // empty and totally full vehicles. --pasky @@ -282,7 +294,7 @@ int GetCustomEngineSprite(byte engine, uint16 overriding_engine, byte cargo, spriteset--; } - r = (in_motion ? group->loaded[spriteset] : group->loading[spriteset]) + direction; + r = (in_motion ? rsg->loaded[spriteset] : rsg->loading[spriteset]) + direction; return r; } diff --git a/grfspecial.c b/grfspecial.c index dcf55a53e..3afda1d81 100644 --- a/grfspecial.c +++ b/grfspecial.c @@ -1055,6 +1055,7 @@ static void NewSpriteGroup(byte *buf, int len) uint8 numloaded; uint8 numloading; struct SpriteGroup *group; + struct RealSpriteGroup *rg; byte *loaded_ptr; byte *loading_ptr; int i; @@ -1065,27 +1066,59 @@ static void NewSpriteGroup(byte *buf, int len) numloaded = buf[3]; numloading = buf[4]; - if (numloaded == 0x81) { - /* XXX: This just goes for the default superset for now, - * straight and safe. --pasky */ - uint8 var = buf[4]; - //uint8 shiftnum = buf[5]; - //uint8 andmask = buf[6]; - uint8 nvar = buf[7]; - //uint32 val; - uint16 def; + if (numloaded == 0x81 || numloaded == 0x82) { + struct DeterministicSpriteGroup *dg; + int i; - grfmsg(GMS_WARN, "NewSpriteGroup(0x81): Unsupported variable %x. Using default cid.", var); + // Ok, this is gonna get a little wild, so hold your breath... - //val = (0xff << shiftnum) & andmask; + /* This stuff is getting actually evaluated in + * EvalDeterministicSpriteGroup(). */ + + buf += 4; len -= 4; + check_length(len, 6, "NewSpriteGroup 0x81/0x82"); if (setid >= _cur_grffile->spritegroups_count) { _cur_grffile->spritegroups_count = setid + 1; _cur_grffile->spritegroups = realloc(_cur_grffile->spritegroups, _cur_grffile->spritegroups_count * sizeof(struct SpriteGroup)); } - buf += 8 + nvar * 4; - def = grf_load_word(&buf); - _cur_grffile->spritegroups[setid] = _cur_grffile->spritegroups[def]; + + group = &_cur_grffile->spritegroups[setid]; + memset(group, 0, sizeof(struct SpriteGroup)); + group->type = SGT_DETERMINISTIC; + dg = &group->g.determ; + + /* XXX: We don't free() anything, assuming that if there was + * some action here before, it got associated by action 3. + * We should perhaps keep some refcount? --pasky */ + + dg->var_scope = numloaded == 0x82 ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; + dg->variable = grf_load_byte(&buf); + + dg->shift_num = grf_load_byte(&buf); + dg->and_mask = grf_load_byte(&buf); + dg->operation = dg->shift_num >> 6; /* w00t */ + dg->shift_num &= 0x3F; + if (dg->operation != DSG_OP_NONE) { + dg->add_val = grf_load_byte(&buf); + dg->divmod_val = grf_load_byte(&buf); + } + + dg->num_ranges = grf_load_byte(&buf); + dg->ranges = calloc(dg->num_ranges, sizeof(*dg->ranges)); + for (i = 0; i < dg->num_ranges; i++) { + uint16 setid = grf_load_word(&buf); + + /* XXX: If multiple surreal sets attach a surreal + * set this way, we are in trouble. */ + dg->ranges[i].group = _cur_grffile->spritegroups[setid]; + dg->ranges[i].range_low = grf_load_byte(&buf); + dg->ranges[i].range_high = grf_load_byte(&buf); + } + + dg->default_group = malloc(sizeof(*dg->default_group)); + memcpy(dg->default_group, &_cur_grffile->spritegroups[grf_load_word(&buf)], sizeof(*dg->default_group)); + return; } else if (numloaded & 0x80) { @@ -1124,25 +1157,28 @@ static void NewSpriteGroup(byte *buf, int len) } group = &_cur_grffile->spritegroups[setid]; memset(group, 0, sizeof(struct SpriteGroup)); - group->sprites_per_set = _cur_grffile->spriteset_numents; - group->loaded_count = numloaded; - group->loading_count = numloading; + group->type = SGT_REAL; + rg = &group->g.real; + + rg->sprites_per_set = _cur_grffile->spriteset_numents; + rg->loaded_count = numloaded; + rg->loading_count = numloading; DEBUG(grf, 6) ("NewSpriteGroup: New SpriteGroup 0x%02hhx, %u views, %u loaded, %u loading, sprites %u - %u", - setid, group->sprites_per_set, group->loaded_count, group->loading_count, + setid, rg->sprites_per_set, rg->loaded_count, rg->loading_count, _cur_grffile->spriteset_start - _cur_grffile->sprite_offset, _cur_grffile->spriteset_start + (_cur_grffile->spriteset_numents * (numloaded + numloading)) - _cur_grffile->sprite_offset); for (i = 0; i < numloaded; i++) { uint16 spriteset_id = grf_load_word(&loaded_ptr); - group->loaded[i] = _cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents; - DEBUG(grf, 8) ("NewSpriteGroup: + group->loaded[%i] = %u (subset %u)", i, group->loaded[i], spriteset_id); + rg->loaded[i] = _cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents; + DEBUG(grf, 8) ("NewSpriteGroup: + rg->loaded[%i] = %u (subset %u)", i, rg->loaded[i], spriteset_id); } for (i = 0; i < numloading; i++) { uint16 spriteset_id = grf_load_word(&loading_ptr); - group->loading[i] = _cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents; - DEBUG(grf, 8) ("NewSpriteGroup: + group->loading[%i] = %u (subset %u)", i, group->loading[i], spriteset_id); + rg->loading[i] = _cur_grffile->spriteset_start + spriteset_id * _cur_grffile->spriteset_numents; + DEBUG(grf, 8) ("NewSpriteGroup: + rg->loading[%i] = %u (subset %u)", i, rg->loading[i], spriteset_id); } } @@ -1214,7 +1250,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len) continue; } - stat->relocation[1] = _cur_grffile->spritegroups[groupid]; + stat->spritegroup[1] = _cur_grffile->spritegroups[groupid]; } } @@ -1232,7 +1268,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len) uint8 stid = buf[3 + i]; struct StationSpec *stat = &_cur_grffile->stations[stid]; - stat->relocation[0] = _cur_grffile->spritegroups[groupid]; + stat->spritegroup[0] = _cur_grffile->spritegroups[groupid]; stat->grfid = _cur_grffile->grfid; SetCustomStation(stid, stat); stat->classid = 0; diff --git a/rail_cmd.c b/rail_cmd.c index 2406c800c..51e95f7f4 100644 --- a/rail_cmd.c +++ b/rail_cmd.c @@ -1551,7 +1551,8 @@ static void DrawTile_Track(TileInfo *ti) DrawTileSeqStruct const *seq; // emulate station tile - open with building DrawTileSprites *cust = &stat->renderdata[2 + (m5 & 0x1)]; - uint32 relocation = GetCustomStationRelocation(stat, 0); + /* FIXME: NULL Station! --pasky */ + uint32 relocation = GetCustomStationRelocation(stat, NULL, 0); image = cust->ground_sprite; if (image & 0x8000) image = (image & 0x7FFF) + tracktype_offs; @@ -1633,7 +1634,7 @@ void DrawWaypointSprite(int x, int y, int stat_id) assert(stat); - relocation = GetCustomStationRelocation(stat, 1); + relocation = GetCustomStationRelocation(stat, NULL, 1); // emulate station tile - open with building // add 1 to get the other direction cust = &stat->renderdata[2]; @@ -7,7 +7,7 @@ * depots or stations): */ typedef struct DrawTileSeqStruct { - int8 delta_x; + int8 delta_x; // 0x80 is sequence terminator int8 delta_y; int8 delta_z; byte width,height; @@ -20,12 +20,16 @@ typedef struct DrawTileSprites { DrawTileSeqStruct const *seq; } DrawTileSprites; +// Iterate through all DrawTileSeqStructs in DrawTileSprites. #define foreach_draw_tile_seq(idx, list) for (idx = list; ((byte) idx->delta_x) != 0x80; idx++) /* This is for custom sprites: */ -struct SpriteGroup { + +struct SpriteGroup; + +struct RealSpriteGroup { // XXX: Would anyone ever need more than 16 spritesets? Maybe we should // use even less, now we take whole 8kb for custom sprites table, oh my! byte sprites_per_set; // means number of directions - 4 or 8 @@ -43,4 +47,74 @@ struct SpriteGroup { uint16 loading[16]; // sprite ids }; +/* Shared by deterministic and random groups. */ +enum VarSpriteGroupScope { + VSG_SCOPE_SELF, + // Engine of consists for vehicles, city for stations. + VSG_SCOPE_PARENT, +}; + +struct DeterministicSpriteGroupRanges; + +struct DeterministicSpriteGroup { + // Take this variable: + enum VarSpriteGroupScope var_scope; + byte variable; + + // Do this with it: + byte shift_num; + byte and_mask; + + // Then do this with it: + enum DeterministicSpriteGroupOperation { + DSG_OP_NONE, + DSG_OP_DIV, + DSG_OP_MOD, + } operation; + byte add_val; + byte divmod_val; + + // And apply it to this: + byte num_ranges; + struct DeterministicSpriteGroupRanges *ranges; // Dynamically allocated + + // Dynamically allocated, this is the sole owner + struct SpriteGroup *default_group; +}; + +struct SpriteGroup { + enum SpriteGroupType { + SGT_REAL, + SGT_DETERMINISTIC, + SGT_RANDOM, /* TODO */ + } type; + + union { + struct RealSpriteGroup real; + struct DeterministicSpriteGroup determ; + } g; +}; + +struct DeterministicSpriteGroupRanges { + struct SpriteGroup group; + byte range_low; + byte range_high; +}; + +/* This is a temporary helper for SpriteGroup users not supporting variational + * sprite groups yet - it just traverses those cowardly, always taking the + * default choice until it hits a real sprite group, returning it. */ +static struct RealSpriteGroup *TriviallyGetRSG(struct SpriteGroup *sg); + + + +/**** Inline functions ****/ + +static INLINE struct RealSpriteGroup *TriviallyGetRSG(struct SpriteGroup *sg) +{ + if (sg->type == SGT_REAL) + return &sg->g.real; + return TriviallyGetRSG(sg->g.determ.default_group); +} + #endif @@ -102,9 +102,9 @@ struct StationSpec { byte tiles; DrawTileSprites renderdata[8]; - /* Sprite offsets for renderdata->seq->image. relocation[0] is default - * whilst relocation[1] is "CID_PURCHASE". */ - struct SpriteGroup relocation[2]; + /* Sprite offsets for renderdata->seq->image. spritegroup[0] is default + * whilst spritegroup[1] is "CID_PURCHASE". */ + struct SpriteGroup spritegroup[2]; }; /* Here, @stid is local per-GRFFile station index. If spec->localidx is not yet @@ -115,7 +115,10 @@ void SetCustomStation(byte stid, struct StationSpec *spec); /* Here, @stid is global station index (in continous range 0..GetCustomStationsCount()) * (lookup is therefore very fast as we do this very frequently). */ struct StationSpec *GetCustomStation(uint32 classid, byte stid); -uint32 GetCustomStationRelocation(struct StationSpec *spec, byte ctype); +/* Get sprite offset for a given custom station and station structure (may be + * NULL if ctype is set - that means we are in a build dialog). The station + * structure is used for variational sprite groups. */ +uint32 GetCustomStationRelocation(struct StationSpec *spec, struct Station *stat, byte ctype); int GetCustomStationsCount(uint32 classid); #endif /* STATION_H */ diff --git a/station_cmd.c b/station_cmd.c index 40a4137df..da83d893e 100644 --- a/station_cmd.c +++ b/station_cmd.c @@ -977,6 +977,9 @@ void SetCustomStation(byte local_stid, struct StationSpec *spec) if (_waypoint_data[i].grfid == spec->grfid && _waypoint_data[i].localidx == local_stid + 1) { stid = i; + /* FIXME: Release original SpriteGroup to + * prevent leaks. But first we need to + * refcount the SpriteGroup. --pasky */ break; } } @@ -1003,25 +1006,30 @@ struct StationSpec *GetCustomStation(uint32 classid, byte stid) return &_waypoint_data[stid]; } -uint32 GetCustomStationRelocation(struct StationSpec *spec, byte ctype) +uint32 GetCustomStationRelocation(struct StationSpec *spec, struct Station *stat, byte ctype) { + struct RealSpriteGroup *rsg; + assert(spec->classid == 'WAYP'); /* In the future, variational spritegroups will kick in through this - * accessor. */ - - if (spec->relocation[ctype].loading_count != 0) { - return spec->relocation[ctype].loading[0]; - } else if (spec->relocation[ctype].loading_count != 0) { - return spec->relocation[ctype].loaded[0]; - } else { - error("Custom station 0x%08x::0x%02x has no sprites associated.", - spec->grfid, spec->localidx); - /* This is what gets subscribed of dtss->image in grfspecial.c, - * so it's probably kinda "default offset". Try to use it as - * emergency measure. */ - return 0x42D; + * accessor, using @stat. */ + rsg = TriviallyGetRSG(&spec->spritegroup[ctype]); + + if (rsg->sprites_per_set != 0) { + if (rsg->loading_count != 0) { + return rsg->loading[0]; + } else if (rsg->loading_count != 0) { + return rsg->loaded[0]; + } } + + error("Custom station 0x%08x::0x%02x has no sprites associated.", + spec->grfid, spec->localidx); + /* This is what gets subscribed of dtss->image in grfspecial.c, + * so it's probably kinda "default offset". Try to use it as + * emergency measure. */ + return 0x42D; } int GetCustomStationsCount(uint32 classid) |