darkvater@406: #ifndef SPRITE_H darkvater@406: #define SPRITE_H darkvater@406: darkvater@406: darkvater@406: /* The following describes bunch of sprites to be drawn together in a single 3D darkvater@406: * bounding box. Used especially for various multi-sprite buildings (like darkvater@406: * depots or stations): */ darkvater@406: darkvater@406: typedef struct DrawTileSeqStruct { darkvater@408: int8 delta_x; // 0x80 is sequence terminator darkvater@406: int8 delta_y; darkvater@406: int8 delta_z; darkvater@406: byte width,height; darkvater@406: byte unk; // 'depth', just z-size; TODO: rename darkvater@406: uint32 image; darkvater@406: } DrawTileSeqStruct; darkvater@406: darkvater@406: typedef struct DrawTileSprites { darkvater@406: SpriteID ground_sprite; darkvater@406: DrawTileSeqStruct const *seq; darkvater@406: } DrawTileSprites; darkvater@406: darkvater@408: // Iterate through all DrawTileSeqStructs in DrawTileSprites. darkvater@406: #define foreach_draw_tile_seq(idx, list) for (idx = list; ((byte) idx->delta_x) != 0x80; idx++) darkvater@406: darkvater@406: darkvater@406: /* This is for custom sprites: */ darkvater@406: darkvater@408: darkvater@408: struct SpriteGroup; darkvater@408: darkvater@408: struct RealSpriteGroup { darkvater@406: // XXX: Would anyone ever need more than 16 spritesets? Maybe we should darkvater@406: // use even less, now we take whole 8kb for custom sprites table, oh my! darkvater@406: byte sprites_per_set; // means number of directions - 4 or 8 darkvater@406: darkvater@406: // Loaded = in motion, loading = not moving darkvater@406: // Each group contains several spritesets, for various loading stages darkvater@406: darkvater@406: // XXX: For stations the meaning is different - loaded is for stations darkvater@406: // with small amount of cargo whilst loading is for stations with a lot darkvater@406: // of da stuff. darkvater@406: darkvater@406: byte loaded_count; darkvater@406: uint16 loaded[16]; // sprite ids darkvater@406: byte loading_count; darkvater@406: uint16 loading[16]; // sprite ids darkvater@406: }; darkvater@406: darkvater@408: /* Shared by deterministic and random groups. */ darkvater@408: enum VarSpriteGroupScope { darkvater@408: VSG_SCOPE_SELF, darkvater@408: // Engine of consists for vehicles, city for stations. darkvater@408: VSG_SCOPE_PARENT, darkvater@408: }; darkvater@408: darkvater@408: struct DeterministicSpriteGroupRanges; darkvater@408: darkvater@408: struct DeterministicSpriteGroup { darkvater@408: // Take this variable: darkvater@408: enum VarSpriteGroupScope var_scope; darkvater@408: byte variable; darkvater@408: darkvater@408: // Do this with it: darkvater@408: byte shift_num; darkvater@408: byte and_mask; darkvater@408: darkvater@408: // Then do this with it: darkvater@408: enum DeterministicSpriteGroupOperation { darkvater@408: DSG_OP_NONE, darkvater@408: DSG_OP_DIV, darkvater@408: DSG_OP_MOD, darkvater@408: } operation; darkvater@408: byte add_val; darkvater@408: byte divmod_val; tron@915: darkvater@408: // And apply it to this: darkvater@408: byte num_ranges; darkvater@413: struct DeterministicSpriteGroupRange *ranges; // Dynamically allocated darkvater@408: darkvater@408: // Dynamically allocated, this is the sole owner darkvater@408: struct SpriteGroup *default_group; darkvater@408: }; darkvater@408: tron@445: struct RandomizedSpriteGroup { tron@445: // Take this object: tron@445: enum VarSpriteGroupScope var_scope; tron@445: tron@445: // Check for these triggers: tron@445: enum RandomizedSpriteGroupCompareMode { tron@445: RSG_CMP_ANY, tron@445: RSG_CMP_ALL, tron@445: } cmp_mode; tron@445: byte triggers; tron@445: tron@445: // Look for this in the per-object randomized bitmask: tron@445: byte lowest_randbit; tron@445: byte num_groups; // must be power of 2 tron@445: tron@445: // Take the group with appropriate index: tron@445: struct SpriteGroup *groups; tron@445: }; tron@445: darkvater@408: struct SpriteGroup { darkvater@408: enum SpriteGroupType { darkvater@408: SGT_REAL, darkvater@408: SGT_DETERMINISTIC, tron@445: SGT_RANDOMIZED, darkvater@408: } type; darkvater@408: darkvater@408: union { darkvater@408: struct RealSpriteGroup real; darkvater@408: struct DeterministicSpriteGroup determ; tron@445: struct RandomizedSpriteGroup random; darkvater@408: } g; darkvater@408: }; darkvater@408: darkvater@413: struct DeterministicSpriteGroupRange { darkvater@408: struct SpriteGroup group; darkvater@413: byte low; darkvater@413: byte high; darkvater@408: }; darkvater@408: darkvater@413: /* This takes value (probably of the variable specified in the group) and darkvater@413: * chooses corresponding SpriteGroup accordingly to the given darkvater@413: * DeterministicSpriteGroup. */ darkvater@413: struct SpriteGroup *EvalDeterministicSpriteGroup(struct DeterministicSpriteGroup *dsg, int value); darkvater@413: /* Get value of a common deterministic SpriteGroup variable. */ darkvater@413: int GetDeterministicSpriteValue(byte var); darkvater@408: tron@445: /* This takes randomized bitmask (probably associated with tron@445: * vehicle/station/whatever) and chooses corresponding SpriteGroup tron@445: * accordingly to the given RandomizedSpriteGroup. */ tron@445: struct SpriteGroup *EvalRandomizedSpriteGroup(struct RandomizedSpriteGroup *rsg, byte random_bits); tron@445: /* Triggers given RandomizedSpriteGroup with given bitmask and returns and-mask tron@445: * of random bits to be reseeded, or zero if there were no triggers matched tron@445: * (then they are |ed to @waiting_triggers instead). */ tron@445: byte RandomizedSpriteGroupTriggeredBits(struct RandomizedSpriteGroup *rsg, byte triggers, byte *waiting_triggers); tron@445: darkvater@406: #endif