diff options
author | frosch <frosch@openttd.org> | 2016-10-16 14:59:44 +0000 |
---|---|---|
committer | frosch <frosch@openttd.org> | 2016-10-16 14:59:44 +0000 |
commit | 117e73751c9aeea9f9663c15226c52541d2c8723 (patch) | |
tree | 694627f8d7396e81945fc84bce6b951f229add22 | |
parent | c175067ed9c17d43feaf356cd575dddddd699889 (diff) | |
download | openttd-117e73751c9aeea9f9663c15226c52541d2c8723.tar.xz |
(svn r27668) -Feature: [NewGRF] Allow composing vehicles from multiple sprites.
-rw-r--r-- | src/aircraft_cmd.cpp | 2 | ||||
-rw-r--r-- | src/disaster_vehicle.cpp | 2 | ||||
-rw-r--r-- | src/effectvehicle.cpp | 9 | ||||
-rw-r--r-- | src/engine_type.h | 1 | ||||
-rw-r--r-- | src/newgrf_engine.cpp | 41 | ||||
-rw-r--r-- | src/saveload/oldloader_sl.cpp | 6 | ||||
-rw-r--r-- | src/saveload/vehicle_sl.cpp | 6 | ||||
-rw-r--r-- | src/vehicle.cpp | 37 | ||||
-rw-r--r-- | src/vehicle_base.h | 30 | ||||
-rw-r--r-- | src/vehicle_gui.cpp | 16 |
10 files changed, 106 insertions, 44 deletions
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 28680ad92..c9cddbf97 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -525,7 +525,7 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z) safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); u->z_pos = GetSlopePixelZ(safe_x, safe_y); - u->sprite_seq.sprite = v->sprite_seq.sprite; + u->sprite_seq.CopyWithoutPalette(v->sprite_seq); // the shadow is never coloured u->UpdatePositionAndViewport(); diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 65a9187e3..98978ddfb 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -499,7 +499,7 @@ static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v) v->tick_counter++; if (HasBit(v->tick_counter, 0)) return true; - SpriteID &cur_image = v->sprite_seq.sprite; + SpriteID &cur_image = v->sprite_seq.seq[0].sprite; if (++cur_image > SPR_ROTOR_MOVING_3) cur_image = SPR_ROTOR_MOVING_1; v->UpdatePositionAndViewport(); diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 266a8e096..5921cd190 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -30,8 +30,8 @@ */ static bool IncrementSprite(EffectVehicle *v, SpriteID last) { - if (v->sprite_seq.sprite != last) { - v->sprite_seq.sprite++; + if (v->sprite_seq.seq[0].sprite != last) { + v->sprite_seq.seq[0].sprite++; return true; } else { return false; @@ -476,9 +476,8 @@ static bool BubbleTick(EffectVehicle *v) if ((v->progress & 3) != 0) return true; if (v->spritenum == 0) { - SpriteID &cur_image = v->sprite_seq.sprite; - cur_image++; - if (cur_image < SPR_BUBBLE_GENERATE_3) { + v->sprite_seq.seq[0].sprite++; + if (v->sprite_seq.seq[0].sprite < SPR_BUBBLE_GENERATE_3) { v->UpdatePositionAndViewport(); return true; } diff --git a/src/engine_type.h b/src/engine_type.h index aeebcb352..8356fda8f 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -158,6 +158,7 @@ enum EngineMiscFlags { EF_AUTO_REFIT = 4, ///< Automatic refitting is allowed EF_NO_DEFAULT_CARGO_MULTIPLIER = 5, ///< Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipliers. CB 15 is also called in purchase list. EF_NO_BREAKDOWN_SMOKE = 6, ///< Do not show black smoke during a breakdown. + EF_SPRITE_STACK = 7, ///< Draw vehicle by stacking multiple sprites. }; /** diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index ba8367c7d..8dd8d545a 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1025,13 +1025,23 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) { - VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK, image_type); + VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK); result->Clear(); - const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->GetNumResults() == 0) return; - - result->Set(group->GetResult() + (direction % group->GetNumResults())); + bool sprite_stack = HasBit(EngInfo(engine)->misc_flags, EF_SPRITE_STACK); + uint max_stack = sprite_stack ? lengthof(result->seq) : 1; + for (uint stack = 0; stack < max_stack; ++stack) { + object.ResetState(); + object.callback_param1 = image_type | (stack << 8); + const SpriteGroup *group = object.Resolve(); + uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0; + if (group != NULL && group->GetNumResults() != 0) { + result->seq[result->count].sprite = group->GetResult() + (direction % group->GetNumResults()); + result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring + result->count++; + } + if (!HasBit(reg100, 31)) break; + } } @@ -1043,15 +1053,24 @@ void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info assert(e->type == VEH_AIRCRAFT); assert(!(e->u.air.subtype & AIR_CTOL)); - VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK, image_type); + VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK); result->Clear(); uint rotor_pos = v == NULL || info_view ? 0 : v->Next()->Next()->state; - const SpriteGroup *group = object.Resolve(); - - if (group == NULL || group->GetNumResults() == 0) return; - - result->Set(group->GetResult() + (rotor_pos % group->GetNumResults())); + bool sprite_stack = HasBit(e->info.misc_flags, EF_SPRITE_STACK); + uint max_stack = sprite_stack ? lengthof(result->seq) : 1; + for (uint stack = 0; stack < max_stack; ++stack) { + object.ResetState(); + object.callback_param1 = image_type | (stack << 8); + const SpriteGroup *group = object.Resolve(); + uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0; + if (group != NULL && group->GetNumResults() != 0) { + result->seq[result->count].sprite = group->GetResult() + (rotor_pos % group->GetNumResults()); + result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring + result->count++; + } + if (!HasBit(reg100, 31)) break; + } } diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 561df3361..0c5716681 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1165,7 +1165,7 @@ static const OldChunks vehicle_chunk[] = { OCL_SVAR( OC_UINT8, Vehicle, owner ), OCL_SVAR( OC_TILE, Vehicle, tile ), - OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, sprite_seq.sprite ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, sprite_seq.seq[0].sprite ), OCL_NULL( 8 ), ///< Vehicle sprite box, calculated automatically @@ -1258,7 +1258,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) if (v == NULL) continue; v->refit_cap = v->cargo_cap; - SpriteID sprite = v->sprite_seq.sprite; + SpriteID sprite = v->sprite_seq.seq[0].sprite; /* no need to override other sprites */ if (IsInsideMM(sprite, 1460, 1465)) { sprite += 580; // aircraft smoke puff @@ -1269,7 +1269,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) } else if (IsInsideMM(sprite, 2516, 2539)) { sprite += 1385; // rotor or disaster-related vehicles } - v->sprite_seq.sprite = sprite; + v->sprite_seq.seq[0].sprite = sprite; switch (v->type) { case VEH_TRAIN: { diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 4c40f52b2..86ca590e4 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -445,7 +445,7 @@ void AfterLoadVehicles(bool part_of_load) /* The plane's shadow will have the same image as the plane, but no colour */ Vehicle *shadow = v->Next(); - shadow->sprite_seq.sprite = v->sprite_seq.sprite; + shadow->sprite_seq.CopyWithoutPalette(v->sprite_seq); /* In the case of a helicopter we will update the rotor sprites */ if (v->subtype == AIR_HELICOPTER) { @@ -796,7 +796,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, 0, 163), SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, 164, SL_MAX_VERSION), - SLE_VAR(Vehicle, sprite_seq.sprite, SLE_FILE_U16 | SLE_VAR_U32), + SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDNULL(5, 0, 57), SLE_VAR(Vehicle, progress, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), @@ -836,7 +836,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, 5, SL_MAX_VERSION), - SLE_VAR(Vehicle, sprite_seq.sprite, SLE_FILE_U16 | SLE_VAR_U32), + SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), SLE_VAR(Vehicle, tick_counter, SLE_UINT8), diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 54a2bfa28..b68646131 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -75,11 +75,23 @@ INSTANTIATE_POOL_METHODS(Vehicle) */ void VehicleSpriteSeq::GetBounds(Rect *bounds) const { - const Sprite *spr = GetSprite(this->sprite, ST_NORMAL); - bounds->left = spr->x_offs; - bounds->top = spr->y_offs; - bounds->right = spr->width + spr->x_offs - 1; - bounds->bottom = spr->height + spr->y_offs - 1; + bounds->left = bounds->top = bounds->right = bounds->bottom = 0; + for (uint i = 0; i < this->count; ++i) { + const Sprite *spr = GetSprite(this->seq[i].sprite, ST_NORMAL); + if (i == 0) { + bounds->left = spr->x_offs; + bounds->top = spr->y_offs; + bounds->right = spr->width + spr->x_offs - 1; + bounds->bottom = spr->height + spr->y_offs - 1; + } else { + if (spr->x_offs < bounds->left) bounds->left = spr->x_offs; + if (spr->y_offs < bounds->top) bounds->top = spr->y_offs; + int right = spr->width + spr->x_offs - 1; + int bottom = spr->height + spr->y_offs - 1; + if (right > bounds->right) bounds->right = right; + if (bottom > bounds->bottom) bounds->bottom = bottom; + } + } } /** @@ -91,7 +103,10 @@ void VehicleSpriteSeq::GetBounds(Rect *bounds) const */ void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const { - DrawSprite(this->sprite, default_pal, x, y); + for (uint i = 0; i < this->count; ++i) { + PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal; + DrawSprite(this->seq[i].sprite, pal, x, y); + } } /** @@ -1048,8 +1063,14 @@ static void DoDrawVehicle(const Vehicle *v) if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return; } - AddSortableSpriteToDraw(v->sprite_seq.sprite, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs, - v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs); + StartSpriteCombine(); + for (uint i = 0; i < v->sprite_seq.count; ++i) { + PaletteID pal2 = v->sprite_seq.seq[i].pal; + if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal; + AddSortableSpriteToDraw(v->sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs, + v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs); + } + EndSpriteCombine(); } /** diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 0b5f2e1de..f2a02072a 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -128,11 +128,12 @@ struct VehicleCache { /** Sprite sequence for a vehicle part. */ struct VehicleSpriteSeq { - SpriteID sprite; + PalSpriteID seq[4]; + uint count; bool operator==(const VehicleSpriteSeq &other) const { - return this->sprite == other.sprite; + return this->count == other.count && MemCmpT<PalSpriteID>(this->seq, other.seq, this->count) == 0; } bool operator!=(const VehicleSpriteSeq &other) const @@ -145,7 +146,7 @@ struct VehicleSpriteSeq { */ bool IsValid() const { - return this->sprite != 0; + return this->count != 0; } /** @@ -153,7 +154,7 @@ struct VehicleSpriteSeq { */ void Clear() { - this->sprite = 0; + this->count = 0; } /** @@ -161,7 +162,21 @@ struct VehicleSpriteSeq { */ void Set(SpriteID sprite) { - this->sprite = sprite; + this->count = 1; + this->seq[0].sprite = sprite; + this->seq[0].pal = 0; + } + + /** + * Copy data from another sprite sequence, while dropping all recolouring information. + */ + void CopyWithoutPalette(const VehicleSpriteSeq &src) + { + this->count = src.count; + for (uint i = 0; i < src.count; ++i) { + this->seq[i].sprite = src.seq[i].sprite; + this->seq[i].pal = 0; + } } void GetBounds(Rect *bounds) const; @@ -982,7 +997,10 @@ struct SpecializedVehicle : public Vehicle { /** * Set vehicle type correctly */ - inline SpecializedVehicle<T, Type>() : Vehicle(Type) { } + inline SpecializedVehicle<T, Type>() : Vehicle(Type) + { + this->sprite_seq.count = 1; + } /** * Get the first vehicle in the chain diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 29b3b30fa..acef86408 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2880,20 +2880,24 @@ void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type) _cursor.sprite_count = 0; int total_width = 0; for (; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { - if (_cursor.sprite_count == lengthof(_cursor.sprite_seq)) break; if (total_width >= 2 * (int)VEHICLEINFO_FULL_VEHICLE_WIDTH) break; PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); VehicleSpriteSeq seq; v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq); - _cursor.sprite_seq[_cursor.sprite_count].sprite = seq.sprite; - _cursor.sprite_seq[_cursor.sprite_count].pal = pal; - _cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width; - _cursor.sprite_pos[_cursor.sprite_count].y = 0; + if (_cursor.sprite_count + seq.count > lengthof(_cursor.sprite_seq)) break; + + for (uint i = 0; i < seq.count; ++i) { + PaletteID pal2 = (v->vehstatus & VS_CRASHED) || !seq.seq[i].pal ? pal : seq.seq[i].pal; + _cursor.sprite_seq[_cursor.sprite_count].sprite = seq.seq[i].sprite; + _cursor.sprite_seq[_cursor.sprite_count].pal = pal2; + _cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width; + _cursor.sprite_pos[_cursor.sprite_count].y = 0; + _cursor.sprite_count++; + } total_width += GetSingleVehicleWidth(v, image_type); - _cursor.sprite_count++; } int offs = ((int)VEHICLEINFO_FULL_VEHICLE_WIDTH - total_width) / 2; |