From 9f0ae0434ecfabb3ee501564535ab3b07f736c57 Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Wed, 21 Sep 2022 16:43:04 +0300 Subject: [PATCH] Render tweaks part 1: refactored sprite struct. Optimized sprite handling in render. Fixed switch warning in control. --- SpaceCadetPinball/TBall.cpp | 9 +- SpaceCadetPinball/TBlocker.cpp | 6 +- SpaceCadetPinball/TBumper.cpp | 6 +- SpaceCadetPinball/TFlagSpinner.cpp | 6 +- SpaceCadetPinball/TFlipper.cpp | 3 +- SpaceCadetPinball/TGate.cpp | 6 +- SpaceCadetPinball/TKickback.cpp | 8 +- SpaceCadetPinball/TLight.cpp | 14 +- SpaceCadetPinball/TLightRollover.cpp | 8 +- SpaceCadetPinball/TPinballComponent.cpp | 13 +- SpaceCadetPinball/TPinballComponent.h | 4 +- SpaceCadetPinball/TPlunger.cpp | 9 +- SpaceCadetPinball/TPopupTarget.cpp | 4 +- SpaceCadetPinball/TRollover.cpp | 12 +- SpaceCadetPinball/TSoloTarget.cpp | 3 +- SpaceCadetPinball/TTableLayer.cpp | 2 +- SpaceCadetPinball/TWall.cpp | 6 +- SpaceCadetPinball/control.cpp | 1 + SpaceCadetPinball/pb.cpp | 10 +- SpaceCadetPinball/proj.cpp | 29 +- SpaceCadetPinball/proj.h | 4 +- SpaceCadetPinball/render.cpp | 367 ++++++++++-------------- SpaceCadetPinball/render.h | 49 ++-- 23 files changed, 258 insertions(+), 321 deletions(-) diff --git a/SpaceCadetPinball/TBall.cpp b/SpaceCadetPinball/TBall.cpp index 3318625..d81c0b7 100644 --- a/SpaceCadetPinball/TBall.cpp +++ b/SpaceCadetPinball/TBall.cpp @@ -52,7 +52,7 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false) auto zDepth = proj::z_distance(*visVec); VisualZArray[index] = zDepth; } - RenderSprite = render::create_sprite(VisualTypes::Ball, nullptr, nullptr, 0, 0, nullptr); + RenderSprite = new render_sprite(VisualTypes::Ball, nullptr, nullptr, 0, 0, nullptr); PinballTable->CollisionCompOffset = Offset; Position.Z = Offset; } @@ -78,8 +78,7 @@ void TBall::Repaint() } auto bmp = ListBitmap->at(index); - render::ball_set( - RenderSprite, + RenderSprite->ball_set( bmp, zDepth, pos2D.X - bmp->Width / 2, @@ -110,7 +109,7 @@ int TBall::Message(MessageCode code, float value) { if (code == MessageCode::Reset) { - render::ball_set(RenderSprite, nullptr, 0.0, 0, 0); + RenderSprite->ball_set(nullptr, 0.0, 0, 0); Position.X = 0.0; CollisionComp = nullptr; Position.Y = 0.0; @@ -145,5 +144,5 @@ vector2 TBall::get_coordinates() void TBall::Disable() { ActiveFlag = false; - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); } diff --git a/SpaceCadetPinball/TBlocker.cpp b/SpaceCadetPinball/TBlocker.cpp index 5313b71..65b8eb2 100644 --- a/SpaceCadetPinball/TBlocker.cpp +++ b/SpaceCadetPinball/TBlocker.cpp @@ -20,7 +20,7 @@ TBlocker::TBlocker(TPinballTable* table, int groupIndex) : TCollisionComponent(t Timer = 0; MessageField = 0; ActiveFlag = 0; - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); } int TBlocker::Message(MessageCode code, float value) @@ -38,14 +38,14 @@ int TBlocker::Message(MessageCode code, float value) } MessageField = 0; ActiveFlag = 0; - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); if (code == MessageCode::TBlockerDisable) loader::play_sound(SoundIndex3, this, "TBlocker1"); break; case MessageCode::TBlockerEnable: ActiveFlag = 1; loader::play_sound(SoundIndex4, this, "TBlocker2"); - render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); + RenderSprite->set_bitmap(ListBitmap->at(0)); if (Timer) timer::kill(Timer); Timer = timer::set(std::max(value, 0.0f), this, TimerExpired); diff --git a/SpaceCadetPinball/TBumper.cpp b/SpaceCadetPinball/TBumper.cpp index 4d21cf8..78c7ddc 100644 --- a/SpaceCadetPinball/TBumper.cpp +++ b/SpaceCadetPinball/TBumper.cpp @@ -113,8 +113,7 @@ void TBumper::TimerExpired(int timerId, void* caller) auto bmp = bump->ListBitmap->at(bump->BmpIndex * 2); auto zMap = bump->ListZMap->at(bump->BmpIndex * 2); bump->Timer = 0; - render::sprite_set( - bump->RenderSprite, + bump->RenderSprite->set( bmp, zMap, bmp->XPosition - bump->PinballTable->XOffset, @@ -127,8 +126,7 @@ void TBumper::Fire() int bmpIndex = 2 * BmpIndex + 1; auto bmp = ListBitmap->at(bmpIndex); auto zMap = ListZMap->at(bmpIndex); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, diff --git a/SpaceCadetPinball/TFlagSpinner.cpp b/SpaceCadetPinball/TFlagSpinner.cpp index 9c295b0..f82272f 100644 --- a/SpaceCadetPinball/TFlagSpinner.cpp +++ b/SpaceCadetPinball/TFlagSpinner.cpp @@ -62,8 +62,7 @@ int TFlagSpinner::Message(MessageCode code, float value) BmpIndex = 0; auto bmp = ListBitmap->at(0); auto zMap = ListZMap->at(0); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, @@ -113,8 +112,7 @@ void TFlagSpinner::NextFrame() auto bmp = ListBitmap->at(BmpIndex); auto zMap = ListZMap->at(BmpIndex); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, diff --git a/SpaceCadetPinball/TFlipper.cpp b/SpaceCadetPinball/TFlipper.cpp index 21d65b1..819d3cf 100644 --- a/SpaceCadetPinball/TFlipper.cpp +++ b/SpaceCadetPinball/TFlipper.cpp @@ -121,8 +121,7 @@ void TFlipper::UpdateSprite(float timeNow) BmpIndex = newBmpIndex; auto bmp = ListBitmap->at(BmpIndex); auto zMap = ListZMap->at(BmpIndex); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, diff --git a/SpaceCadetPinball/TGate.cpp b/SpaceCadetPinball/TGate.cpp index 8915040..4c82c9b 100644 --- a/SpaceCadetPinball/TGate.cpp +++ b/SpaceCadetPinball/TGate.cpp @@ -14,7 +14,7 @@ TGate::TGate(TPinballTable* table, int groupIndex) : TCollisionComponent(table, SoundIndex4 = visual.SoundIndex4; SoundIndex3 = visual.SoundIndex3; ActiveFlag = 1; - render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); + RenderSprite->set_bitmap(ListBitmap->at(0)); control::handler(MessageCode::Reset, this); } @@ -24,13 +24,13 @@ int TGate::Message(MessageCode code, float value) { case MessageCode::TGateDisable: ActiveFlag = 0; - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); loader::play_sound(SoundIndex3, this, "TGate1"); break; case MessageCode::Reset: case MessageCode::TGateEnable: ActiveFlag = 1; - render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); + RenderSprite->set_bitmap(ListBitmap->at(0)); if (code == MessageCode::TGateEnable) loader::play_sound(SoundIndex4, this, "TGate2"); break; diff --git a/SpaceCadetPinball/TKickback.cpp b/SpaceCadetPinball/TKickback.cpp index 9f269ee..af32dc4 100644 --- a/SpaceCadetPinball/TKickback.cpp +++ b/SpaceCadetPinball/TKickback.cpp @@ -25,7 +25,7 @@ int TKickback::Message(MessageCode code, float value) { timer::kill(Timer); if (ListBitmap) - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); Timer = 0; KickActiveFlag = 0; Threshold = 1000000000.0; @@ -67,8 +67,7 @@ void TKickback::TimerExpired(int timerId, void* caller) { auto bmp = kick->ListBitmap->at(1); auto zMap = kick->ListZMap->at(1); - render::sprite_set( - kick->RenderSprite, + kick->RenderSprite->set( bmp, zMap, bmp->XPosition - kick->PinballTable->XOffset, @@ -81,8 +80,7 @@ void TKickback::TimerExpired(int timerId, void* caller) { auto bmp = kick->ListBitmap->at(0); auto zMap = kick->ListZMap->at(0); - render::sprite_set( - kick->RenderSprite, + kick->RenderSprite->set( bmp, zMap, bmp->XPosition - kick->PinballTable->XOffset, diff --git a/SpaceCadetPinball/TLight.cpp b/SpaceCadetPinball/TLight.cpp index ce41917..7a11b92 100644 --- a/SpaceCadetPinball/TLight.cpp +++ b/SpaceCadetPinball/TLight.cpp @@ -225,7 +225,8 @@ int TLight::Message(MessageCode code, float value) case MessageCode::TLightFtTmpOverrideOn: case MessageCode::TLightFtTmpOverrideOff: // FT codes in negative to avoid overlap with 3DPB TLightGroup codes - render::sprite_set_bitmap(RenderSprite, BmpArr[code == MessageCode::TLightFtTmpOverrideOn]); + if (ListBitmap) + RenderSprite->set_bitmap(BmpArr[code == MessageCode::TLightFtTmpOverrideOn]); if (UndoOverrideTimer) timer::kill(UndoOverrideTimer); UndoOverrideTimer = 0; @@ -240,7 +241,8 @@ int TLight::Message(MessageCode code, float value) timer::kill(UndoOverrideTimer); UndoOverrideTimer = 0; TemporaryOverrideFlag = false; - render::sprite_set_bitmap(RenderSprite, PreviousBitmap); + if (ListBitmap) + RenderSprite->set_bitmap(PreviousBitmap); break; default: break; @@ -267,10 +269,12 @@ void TLight::Reset() TemporaryOverrideFlag = false; TurnOffAfterFlashingFg = false; PreviousBitmap = nullptr; - render::sprite_set_bitmap(RenderSprite, nullptr); BmpArr[0] = nullptr; if (ListBitmap) + { BmpArr[1] = ListBitmap->at(0); + RenderSprite->set_bitmap(nullptr); + } MessageField = 0; } @@ -326,8 +330,8 @@ void TLight::flasher_start(bool bmpIndex) void TLight::SetSpriteBmp(gdrv_bitmap8* bmp) { PreviousBitmap = bmp; - if (!TemporaryOverrideFlag) - render::sprite_set_bitmap(RenderSprite, bmp); + if (!TemporaryOverrideFlag && RenderSprite) + RenderSprite->set_bitmap(bmp); } void TLight::flasher_callback(int timerId, void* caller) diff --git a/SpaceCadetPinball/TLightRollover.cpp b/SpaceCadetPinball/TLightRollover.cpp index 88ad1ca..1332caa 100644 --- a/SpaceCadetPinball/TLightRollover.cpp +++ b/SpaceCadetPinball/TLightRollover.cpp @@ -14,7 +14,7 @@ TLightRollover::TLightRollover(TPinballTable* table, int groupIndex) : TRollover RolloverFlag = 0; Timer = 0; if (ListBitmap != nullptr) - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); build_walls(groupIndex); FloatArr = *loader::query_float_attribute(groupIndex, 0, 407); } @@ -29,7 +29,7 @@ int TLightRollover::Message(MessageCode code, float value) timer::kill(Timer); Timer = 0; if (ListBitmap) - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); } return 0; } @@ -57,7 +57,7 @@ void TLightRollover::Collision(TBall* ball, vector2* nextPosition, vector2* dire control::handler(MessageCode::ControlCollision, this); RolloverFlag = RolloverFlag == 0; if (ListBitmap) - render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); + RenderSprite->set_bitmap(ListBitmap->at(0)); } } } @@ -65,6 +65,6 @@ void TLightRollover::Collision(TBall* ball, vector2* nextPosition, vector2* dire void TLightRollover::delay_expired(int timerId, void* caller) { auto roll = static_cast(caller); - render::sprite_set_bitmap(roll->RenderSprite, nullptr); + roll->RenderSprite->set_bitmap(nullptr); roll->Timer = 0; } diff --git a/SpaceCadetPinball/TPinballComponent.cpp b/SpaceCadetPinball/TPinballComponent.cpp index 516495c..ed591a2 100644 --- a/SpaceCadetPinball/TPinballComponent.cpp +++ b/SpaceCadetPinball/TPinballComponent.cpp @@ -23,10 +23,12 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool Control = nullptr; VisualPosNormX= -1.0f; VisualPosNormY = -1.0f; + GroupIndex = groupIndex; if (table) table->ComponentList.push_back(this); if (groupIndex >= 0) GroupName = loader::query_name(groupIndex); + if (loadVisuals && groupIndex >= 0) { int visualCount = loader::query_visual_states(groupIndex); @@ -37,15 +39,13 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool { if (!ListBitmap) ListBitmap = new std::vector(); - if (ListBitmap) - ListBitmap->push_back(visual.Bitmap); + ListBitmap->push_back(visual.Bitmap); } if (visual.ZMap) { if (!ListZMap) ListZMap = new std::vector(); - if (ListZMap) - ListZMap->push_back(visual.ZMap); + ListZMap->push_back(visual.ZMap); } } @@ -68,8 +68,8 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool maths::enclosing_box(bmp1Rect, tmpRect, bmp1Rect); } - RenderSprite = render::create_sprite( - visualCount > 0 ? VisualTypes::Sprite : VisualTypes::None, + RenderSprite = new render_sprite( + VisualTypes::Sprite, rootBmp, zMap, rootBmp->XPosition - table->XOffset, @@ -85,7 +85,6 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool VisualPosNormY = posNorm.Y; } } - GroupIndex = groupIndex; } diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index ec4c1e2..7964dbc 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -2,7 +2,7 @@ struct zmap_header_type; struct gdrv_bitmap8; -struct render_sprite_type_struct; +struct render_sprite; struct component_control; struct vector2; class TPinballTable; @@ -145,7 +145,7 @@ public: char* GroupName; component_control* Control; int GroupIndex; - render_sprite_type_struct* RenderSprite; + render_sprite* RenderSprite; TPinballTable* PinballTable; std::vector* ListBitmap; std::vector* ListZMap; diff --git a/SpaceCadetPinball/TPlunger.cpp b/SpaceCadetPinball/TPlunger.cpp index d164ee6..f976789 100644 --- a/SpaceCadetPinball/TPlunger.cpp +++ b/SpaceCadetPinball/TPlunger.cpp @@ -133,8 +133,7 @@ int TPlunger::Message(MessageCode code, float value) loader::play_sound(SoundIndexP2, this, "TPlunger3"); auto bmp = ListBitmap->at(0); auto zMap = ListZMap->at(0); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, @@ -156,8 +155,7 @@ int TPlunger::Message(MessageCode code, float value) auto bmp = ListBitmap->at(0); auto zMap = ListZMap->at(0); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, @@ -204,8 +202,7 @@ void TPlunger::PullbackTimer(int timerId, void* caller) (plunger->Boost / plunger->MaxPullback))); auto bmp = plunger->ListBitmap->at(index); auto zMap = plunger->ListZMap->at(index); - render::sprite_set( - plunger->RenderSprite, + plunger->RenderSprite->set( bmp, zMap, bmp->XPosition - plunger->PinballTable->XOffset, diff --git a/SpaceCadetPinball/TPopupTarget.cpp b/SpaceCadetPinball/TPopupTarget.cpp index de6c9b7..eaa4705 100644 --- a/SpaceCadetPinball/TPopupTarget.cpp +++ b/SpaceCadetPinball/TPopupTarget.cpp @@ -20,7 +20,7 @@ int TPopupTarget::Message(MessageCode code, float value) { case MessageCode::TPopupTargetDisable: ActiveFlag = 0; - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); break; case MessageCode::TPopupTargetEnable: Timer = timer::set(TimerTime, this, TimerExpired); @@ -79,7 +79,7 @@ void TPopupTarget::TimerExpired(int timerId, void* caller) auto target = static_cast(caller); target->Timer = 0; target->ActiveFlag = 1; - render::sprite_set_bitmap(target->RenderSprite, target->ListBitmap->at(0)); + target->RenderSprite->set_bitmap(target->ListBitmap->at(0)); if (timerId) { if (target->SoftHitSoundId) diff --git a/SpaceCadetPinball/TRollover.cpp b/SpaceCadetPinball/TRollover.cpp index ed59f92..42cb247 100644 --- a/SpaceCadetPinball/TRollover.cpp +++ b/SpaceCadetPinball/TRollover.cpp @@ -20,7 +20,7 @@ TRollover::TRollover(TPinballTable* table, int groupIndex, bool createWall) : TC TRollover::TRollover(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false) { if (ListBitmap) - render::sprite_set_bitmap(RenderSprite, ListBitmap->at(0)); + RenderSprite->set_bitmap(ListBitmap->at(0)); build_walls(groupIndex); } @@ -29,10 +29,10 @@ int TRollover::Message(MessageCode code, float value) { if (code == MessageCode::Reset) { - this->ActiveFlag = 1; - this->RolloverFlag = 0; - if (this->ListBitmap) - render::sprite_set_bitmap(this->RenderSprite, this->ListBitmap->at(0)); + ActiveFlag = 1; + RolloverFlag = 0; + if (ListBitmap) + RenderSprite->set_bitmap(ListBitmap->at(0)); } return 0; } @@ -62,7 +62,7 @@ void TRollover::Collision(TBall* ball, vector2* nextPosition, vector2* direction { if (!RolloverFlag) bmp = ListBitmap->at(0); - render::sprite_set_bitmap(RenderSprite, bmp); + RenderSprite->set_bitmap(bmp); } } } diff --git a/SpaceCadetPinball/TSoloTarget.cpp b/SpaceCadetPinball/TSoloTarget.cpp index cd29ba4..11df798 100644 --- a/SpaceCadetPinball/TSoloTarget.cpp +++ b/SpaceCadetPinball/TSoloTarget.cpp @@ -42,8 +42,7 @@ int TSoloTarget::Message(MessageCode code, float value) auto index = 1 - ActiveFlag; auto bmp = ListBitmap->at(index); auto zMap = ListZMap->at(index); - render::sprite_set( - RenderSprite, + RenderSprite->set( bmp, zMap, bmp->XPosition - PinballTable->XOffset, diff --git a/SpaceCadetPinball/TTableLayer.cpp b/SpaceCadetPinball/TTableLayer.cpp index bfb5d28..d558f8e 100644 --- a/SpaceCadetPinball/TTableLayer.cpp +++ b/SpaceCadetPinball/TTableLayer.cpp @@ -32,7 +32,7 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f rect.YPosition = 0; rect.Width = bmp->Width; rect.Height = bmp->Height; - render::create_sprite(VisualTypes::None, bmp, visual.ZMap, 0, 0, &rect); + new render_sprite(VisualTypes::Background, bmp, visual.ZMap, 0, 0, &rect); PinballTable->SoundIndex1 = visual.SoundIndex4; PinballTable->SoundIndex2 = visual.SoundIndex3; diff --git a/SpaceCadetPinball/TWall.cpp b/SpaceCadetPinball/TWall.cpp index 77d313a..e90bbca 100644 --- a/SpaceCadetPinball/TWall.cpp +++ b/SpaceCadetPinball/TWall.cpp @@ -9,7 +9,7 @@ TWall::TWall(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) { if (RenderSprite) - render::sprite_set_bitmap(RenderSprite, nullptr); + RenderSprite->set_bitmap(nullptr); if (ListBitmap) BmpPtr = ListBitmap->at(0); } @@ -30,7 +30,7 @@ void TWall::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl { if (BmpPtr) { - render::sprite_set_bitmap(RenderSprite, BmpPtr); + RenderSprite->set_bitmap(BmpPtr); Timer = timer::set(0.1f, this, TimerExpired); } control::handler(MessageCode::ControlCollision, this); @@ -40,7 +40,7 @@ void TWall::Collision(TBall* ball, vector2* nextPosition, vector2* direction, fl void TWall::TimerExpired(int timerId, void* caller) { auto wall = static_cast(caller); - render::sprite_set_bitmap(wall->RenderSprite, nullptr); + wall->RenderSprite->set_bitmap(nullptr); wall->Timer = 0; wall->MessageField = 0; } diff --git a/SpaceCadetPinball/control.cpp b/SpaceCadetPinball/control.cpp index 2d8acea..647d368 100644 --- a/SpaceCadetPinball/control.cpp +++ b/SpaceCadetPinball/control.cpp @@ -2081,6 +2081,7 @@ void control::GravityWellKickoutControl(MessageCode code, TPinballComponent* cal case MessageCode::Reset: kickout1->ActiveFlag = 0; break; + default: break; } } diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 983ff34..6746580 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -42,7 +42,7 @@ TTextBox *pb::InfoTextBox, *pb::MissTextBox; int pb::init() { - float projMat[12], zMin = 0, zScaler = 0; + float projMat[12]; if (DatFileName.empty()) return 1; @@ -75,12 +75,12 @@ int pb::init() auto projCenterX = resInfo->TableWidth * 0.5f; auto projCenterY = resInfo->TableHeight * 0.5f; auto projD = cameraInfo[0]; - proj::init(projMat, projD, projCenterX, projCenterY); - zMin = cameraInfo[1]; - zScaler = cameraInfo[2]; + auto zMin = cameraInfo[1]; + auto zScaler = cameraInfo[2]; + proj::init(projMat, projD, projCenterX, projCenterY, zMin, zScaler); } - render::init(nullptr, zMin, zScaler, resInfo->TableWidth, resInfo->TableHeight); + render::init(nullptr, resInfo->TableWidth, resInfo->TableHeight); gdrv::copy_bitmap( render::vscreen, backgroundBmp->Width, diff --git a/SpaceCadetPinball/proj.cpp b/SpaceCadetPinball/proj.cpp index f8f4661..f2e12f1 100644 --- a/SpaceCadetPinball/proj.cpp +++ b/SpaceCadetPinball/proj.cpp @@ -3,17 +3,10 @@ mat4_row_major proj::matrix; float proj::d_, proj::centerx, proj::centery; +float proj::zscaler, proj::zmin, proj::zmax; -void proj::init(float* mat4x3, float d, float centerX, float centerY) +void proj::init(float* mat4x3, float d, float centerX, float centerY, float zMin, float zScaler) { - /*for (auto colIndex = 0; colIndex < 4; ++colIndex) - { - // Todo: out of bounds read from mat4x3? - for (int rowIndex = colIndex, i = 4; i > 0; rowIndex += 4, --i) - { - ((float*)&matrix)[rowIndex] = mat4x3[rowIndex]; - } - }*/ memcpy(&matrix, mat4x3, sizeof(float) * 4 * 3); matrix.Row3.X = 0.0; @@ -24,6 +17,10 @@ void proj::init(float* mat4x3, float d, float centerX, float centerY) d_ = d; centerx = centerX; centery = centerY; + + zscaler = zScaler; + zmin = zMin; + zmax = static_cast(0xffFFffFF) / zScaler + zMin; } vector3 proj::matrix_vector_multiply(const mat4_row_major& mat, const vector3& vec) @@ -103,3 +100,17 @@ void proj::recenter(float centerX, float centerY) centerx = centerX; centery = centerY; } + +uint16_t proj::NormalizeDepth(float depth) +{ + uint16_t result = 0; + if (depth >= zmin) + { + auto depthScaled = (depth - zmin) * zscaler; + if (depthScaled <= zmax) + result = static_cast(depthScaled); + else + result = 0xffFF; + } + return result; +} diff --git a/SpaceCadetPinball/proj.h b/SpaceCadetPinball/proj.h index 4e57b7f..3a05a0b 100644 --- a/SpaceCadetPinball/proj.h +++ b/SpaceCadetPinball/proj.h @@ -21,14 +21,16 @@ struct mat4_row_major class proj { public: - static void init(float* mat4x3, float d, float centerX, float centerY); + static void init(float* mat4x3, float d, float centerX, float centerY, float zMin, float zScaler); static vector3 matrix_vector_multiply(const mat4_row_major& mat, const vector3& vec); static float z_distance(const vector3& vec); static vector2i xform_to_2d(const vector3& vec); static vector2i xform_to_2d(const vector2& vec); static vector3 ReverseXForm(const vector2i& vec); static void recenter(float centerX, float centerY); + static uint16_t NormalizeDepth(float depth); private: static mat4_row_major matrix; static float d_, centerx, centery; + static float zscaler, zmin, zmax; }; diff --git a/SpaceCadetPinball/render.cpp b/SpaceCadetPinball/render.cpp index 0a36f96..c010bae 100644 --- a/SpaceCadetPinball/render.cpp +++ b/SpaceCadetPinball/render.cpp @@ -9,21 +9,95 @@ #include "TPinballTable.h" #include "winmain.h" #include "DebugOverlay.h" +#include "proj.h" -std::vector render::dirty_list, render::sprite_list, render::ball_list; +std::vector render::sprite_list, render::ball_list; zmap_header_type* render::background_zmap; -int render::zmap_offset, render::zmap_offsetY, render::offset_x, render::offset_y; -float render::zscaler, render::zmin, render::zmax; +int render::zmap_offsetX, render::zmap_offsetY, render::offset_x, render::offset_y; rectangle_type render::vscreen_rect; gdrv_bitmap8 *render::vscreen, *render::background_bitmap, *render::ball_bitmap[20]; zmap_header_type* render::zscreen; SDL_Rect render::DestinationRect{}; -void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int height) +render_sprite::render_sprite(VisualTypes visualType, gdrv_bitmap8* bmp, zmap_header_type* zMap, + int xPosition, int yPosition, rectangle_type* boundingRect) +{ + Bmp = bmp; + ZMap = zMap; + VisualType = visualType; + DeleteFlag = false; + OccludedSprites = nullptr; + DirtyRect = rectangle_type{}; + DirtyFlag = visualType != VisualTypes::Ball; + ZMapOffestX = 0; + ZMapOffestY = 0; + Depth = 0xffFF; + + if (boundingRect) + { + BoundingRect = *boundingRect; + } + else + { + BoundingRect.Width = -1; + BoundingRect.Height = -1; + BoundingRect.XPosition = 0; + BoundingRect.YPosition = 0; + } + + BmpRect.YPosition = yPosition; + BmpRect.XPosition = xPosition; + if (bmp) + { + BmpRect.Width = bmp->Width; + BmpRect.Height = bmp->Height; + } + else + { + BmpRect.Width = 0; + BmpRect.Height = 0; + } + DirtyRectPrev = BmpRect; + + render::AddSprite(*this); +} + +render_sprite::~render_sprite() +{ + render::RemoveSprite(*this); + delete OccludedSprites; +} + +void render_sprite::set(gdrv_bitmap8* bmp, zmap_header_type* zMap, int xPos, int yPos) +{ + if (Bmp == bmp && ZMap == zMap && BmpRect.XPosition == xPos && BmpRect.YPosition == yPos) + return; + + Bmp = bmp; + ZMap = zMap; + DirtyFlag = VisualType != VisualTypes::Ball; + BmpRect.XPosition = xPos; + BmpRect.YPosition = yPos; + if (bmp) + { + BmpRect.Width = bmp->Width; + BmpRect.Height = bmp->Height; + } +} + +void render_sprite::set_bitmap(gdrv_bitmap8* bmp) +{ + set(bmp, ZMap, BmpRect.XPosition, BmpRect.YPosition); +} + +void render_sprite::ball_set(gdrv_bitmap8* bmp, float depth, int xPos, int yPos) +{ + set(bmp, ZMap,xPos, yPos); + Depth = proj::NormalizeDepth(depth); +} + +void render::init(gdrv_bitmap8* bmp, int width, int height) { - zscaler = zScaler; - zmin = zMin; - zmax = 4294967300.0f / zScaler + zMin; vscreen = new gdrv_bitmap8(width, height, false); zscreen = new zmap_header_type(width, height, width); zdrv::fill(zscreen, zscreen->Width, zscreen->Height, 0, 0, 0xFFFF); @@ -49,15 +123,12 @@ void render::uninit() { delete vscreen; delete zscreen; - for (auto sprite : sprite_list) - remove_sprite(sprite, false); - for (auto ball : ball_list) - remove_ball(ball, false); - for (auto& ballBmp : ball_bitmap) - delete ballBmp; - ball_list.clear(); - dirty_list.clear(); - sprite_list.clear(); + + // Sprite destructor removes it from the list. + while (!sprite_list.empty()) + delete sprite_list[0]; + while (!ball_list.empty()) + delete ball_list[0]; DebugOverlay::UnInit(); } @@ -70,36 +141,39 @@ void render::update() { unpaint_balls(); - // Clip dirty sprites with vScreen, clear clipping (dirty) rectangles - for (auto curSprite : dirty_list) + // Clip dirty sprites with vScreen, clear clipping (dirty) rectangles + for (const auto sprite : sprite_list) { + if (!sprite->DirtyFlag) + continue; + bool clearSprite = false; - switch (curSprite->VisualType) + switch (sprite->VisualType) { case VisualTypes::Sprite: - if (curSprite->DirtyRectPrev.Width > 0) - maths::enclosing_box(curSprite->DirtyRectPrev, curSprite->BmpRect, curSprite->DirtyRect); + if (sprite->DirtyRectPrev.Width > 0) + maths::enclosing_box(sprite->DirtyRectPrev, sprite->BmpRect, sprite->DirtyRect); - if (maths::rectangle_clip(curSprite->DirtyRect, vscreen_rect, &curSprite->DirtyRect)) + if (maths::rectangle_clip(sprite->DirtyRect, vscreen_rect, &sprite->DirtyRect)) clearSprite = true; else - curSprite->DirtyRect.Width = -1; + sprite->DirtyRect.Width = -1; break; - case VisualTypes::None: - if (maths::rectangle_clip(curSprite->BmpRect, vscreen_rect, &curSprite->DirtyRect)) - clearSprite = !curSprite->Bmp; + case VisualTypes::Background: + if (maths::rectangle_clip(sprite->BmpRect, vscreen_rect, &sprite->DirtyRect)) + clearSprite = !sprite->Bmp; else - curSprite->DirtyRect.Width = -1; + sprite->DirtyRect.Width = -1; break; default: break; } if (clearSprite) { - auto yPos = curSprite->DirtyRect.YPosition; - auto width = curSprite->DirtyRect.Width; - auto xPos = curSprite->DirtyRect.XPosition; - auto height = curSprite->DirtyRect.Height; + auto yPos = sprite->DirtyRect.YPosition; + auto width = sprite->DirtyRect.Width; + auto xPos = sprite->DirtyRect.XPosition; + auto height = sprite->DirtyRect.Height; zdrv::fill(zscreen, width, height, xPos, yPos, 0xFFFF); if (background_bitmap) gdrv::copy_bitmap(vscreen, width, height, xPos, yPos, background_bitmap, xPos, yPos); @@ -109,191 +183,60 @@ void render::update() } // Paint dirty rectangles of dirty sprites - for (auto sprite : dirty_list) + for (auto sprite : sprite_list) { - if (sprite->DirtyRect.Width > 0 && (sprite->VisualType == VisualTypes::None || sprite->VisualType == - VisualTypes::Sprite)) - repaint(sprite); + if (!sprite->DirtyFlag) + continue; + + repaint(*sprite); + sprite->DirtyFlag = false; + sprite->DirtyRectPrev = sprite->DirtyRect; + if (sprite->DeleteFlag) + delete sprite; } paint_balls(); - - // In the original, this used to blit dirty sprites and balls - for (auto sprite : dirty_list) - { - sprite->DirtyRectPrev = sprite->DirtyRect; - if (sprite->UnknownFlag != 0) - remove_sprite(sprite, true); - } - - dirty_list.clear(); } -void render::sprite_modified(render_sprite_type_struct* sprite) +void render::AddSprite(render_sprite& sprite) { - if (sprite->VisualType != VisualTypes::Ball && dirty_list.size() < 999) - dirty_list.push_back(sprite); + if (!sprite.ZMap && sprite.VisualType != VisualTypes::Ball) + { + sprite.ZMap = background_zmap; + sprite.ZMapOffestY = sprite.BmpRect.XPosition - zmap_offsetX; + sprite.ZMapOffestX = sprite.BmpRect.YPosition - zmap_offsetY; + } + + auto& list = sprite.VisualType == VisualTypes::Ball ? ball_list : sprite_list; + list.push_back(&sprite); } -render_sprite_type_struct* render::create_sprite(VisualTypes visualType, gdrv_bitmap8* bmp, zmap_header_type* zMap, - int xPosition, int yPosition, rectangle_type* rect) +void render::RemoveSprite(render_sprite& sprite) { - auto sprite = new render_sprite_type_struct(); - if (!sprite) - return nullptr; - sprite->BmpRect.YPosition = yPosition; - sprite->BmpRect.XPosition = xPosition; - sprite->Bmp = bmp; - sprite->VisualType = visualType; - sprite->UnknownFlag = 0; - sprite->SpriteArray = nullptr; - sprite->DirtyRect = rectangle_type{}; - if (rect) - { - sprite->BoundingRect = *rect; - } - else - { - sprite->BoundingRect.Width = -1; - sprite->BoundingRect.Height = -1; - sprite->BoundingRect.XPosition = 0; - sprite->BoundingRect.YPosition = 0; - } - if (bmp) - { - sprite->BmpRect.Width = bmp->Width; - sprite->BmpRect.Height = bmp->Height; - } - else - { - sprite->BmpRect.Width = 0; - sprite->BmpRect.Height = 0; - } - sprite->ZMap = zMap; - sprite->ZMapOffestX = 0; - sprite->ZMapOffestY = 0; - if (!zMap && visualType != VisualTypes::Ball) - { - sprite->ZMap = background_zmap; - sprite->ZMapOffestY = xPosition - zmap_offset; - sprite->ZMapOffestX = yPosition - zmap_offsetY; - } - sprite->DirtyRectPrev = sprite->BmpRect; - if (visualType == VisualTypes::Ball) - { - ball_list.push_back(sprite); - } - else - { - sprite_list.push_back(sprite); - sprite_modified(sprite); - } - return sprite; + auto& list = sprite.VisualType == VisualTypes::Ball ? ball_list : sprite_list; + auto it = std::find(list.begin(), list.end(), &sprite); + if (it != list.end()) + list.erase(it); } - -void render::remove_sprite(render_sprite_type_struct* sprite, bool removeFromList) -{ - if (removeFromList) - { - auto it = std::find(sprite_list.begin(), sprite_list.end(), sprite); - if (it != sprite_list.end()) - sprite_list.erase(it); - } - - delete sprite->SpriteArray; - delete sprite; -} - -void render::remove_ball(render_sprite_type_struct* ball, bool removeFromList) -{ - if (removeFromList) - { - auto it = std::find(ball_list.begin(), ball_list.end(), ball); - if (it != ball_list.end()) - ball_list.erase(it); - } - - delete ball->SpriteArray; - delete ball; -} - -void render::sprite_set(render_sprite_type_struct* sprite, gdrv_bitmap8* bmp, zmap_header_type* zMap, int xPos, - int yPos) -{ - if (sprite) - { - sprite->BmpRect.XPosition = xPos; - sprite->BmpRect.YPosition = yPos; - sprite->Bmp = bmp; - if (bmp) - { - sprite->BmpRect.Width = bmp->Width; - sprite->BmpRect.Height = bmp->Height; - } - sprite->ZMap = zMap; - sprite_modified(sprite); - } -} - -void render::sprite_set_bitmap(render_sprite_type_struct* sprite, gdrv_bitmap8* bmp) -{ - if (sprite && sprite->Bmp != bmp) - { - sprite->Bmp = bmp; - if (bmp) - { - sprite->BmpRect.Width = bmp->Width; - sprite->BmpRect.Height = bmp->Height; - } - sprite_modified(sprite); - } -} - -void render::set_background_zmap(struct zmap_header_type* zMap, int offsetX, int offsetY) +void render::set_background_zmap(zmap_header_type* zMap, int offsetX, int offsetY) { background_zmap = zMap; - zmap_offset = offsetX; + zmap_offsetX = offsetX; zmap_offsetY = offsetY; } -void render::ball_set(render_sprite_type_struct* sprite, gdrv_bitmap8* bmp, float depth, int xPos, int yPos) -{ - if (sprite) - { - sprite->Bmp = bmp; - if (bmp) - { - sprite->BmpRect.XPosition = xPos; - sprite->BmpRect.YPosition = yPos; - sprite->BmpRect.Width = bmp->Width; - sprite->BmpRect.Height = bmp->Height; - } - if (depth >= zmin) - { - float depth2 = (depth - zmin) * zscaler; - if (depth2 <= zmax) - sprite->Depth = static_cast(depth2); - else - sprite->Depth = -1; - } - else - { - sprite->Depth = 0; - } - } -} - -void render::repaint(struct render_sprite_type_struct* sprite) +void render::repaint(const render_sprite& sprite) { rectangle_type clipRect{}; - if (!sprite->SpriteArray) + if (!sprite.OccludedSprites || sprite.VisualType == VisualTypes::Ball || sprite.DirtyRect.Width <= 0) return; - for (auto refSprite : *sprite->SpriteArray) + + for (auto refSprite : *sprite.OccludedSprites) { - if (!refSprite->UnknownFlag && refSprite->Bmp) + if (!refSprite->DeleteFlag && refSprite->Bmp) { - if (maths::rectangle_clip(refSprite->BmpRect, sprite->DirtyRect, &clipRect)) + if (maths::rectangle_clip(refSprite->BmpRect, sprite.DirtyRect, &clipRect)) zdrv::paint( clipRect.Width, clipRect.Height, @@ -316,20 +259,11 @@ void render::repaint(struct render_sprite_type_struct* sprite) void render::paint_balls() { - // Sort ball sprites by depth - for (auto i = 0u; i < ball_list.size(); i++) + // Sort ball sprites by ascending depth + std::sort(ball_list.begin(), ball_list.end(), [](const render_sprite* lhs, const render_sprite* rhs) { - for (auto j = i; j < ball_list.size() / 2; ++j) - { - auto ballA = ball_list[j]; - auto ballB = ball_list[i]; - if (ballB->Depth > ballA->Depth) - { - ball_list[i] = ballA; - ball_list[j] = ballB; - } - } - } + return lhs->Depth < rhs->Depth; + }); // For balls that clip vScreen: save original vScreen contents and paint ball bitmap. for (auto index = 0u; index < ball_list.size(); ++index) @@ -391,26 +325,25 @@ void render::shift(int offsetX, int offsetY) void render::build_occlude_list() { - std::vector* spriteArr = nullptr; + std::vector* spriteArr = nullptr; for (auto mainSprite : sprite_list) { - if (mainSprite->SpriteArray) + if (mainSprite->OccludedSprites) { - delete mainSprite->SpriteArray; - mainSprite->SpriteArray = nullptr; + delete mainSprite->OccludedSprites; + mainSprite->OccludedSprites = nullptr; } - if (!mainSprite->UnknownFlag && mainSprite->BoundingRect.Width != -1) + if (!mainSprite->DeleteFlag && mainSprite->BoundingRect.Width != -1) { if (!spriteArr) - spriteArr = new std::vector(); + spriteArr = new std::vector(); for (auto refSprite : sprite_list) { - if (!refSprite->UnknownFlag + if (!refSprite->DeleteFlag && refSprite->BoundingRect.Width != -1 - && maths::rectangle_clip(mainSprite->BoundingRect, refSprite->BoundingRect, nullptr) - && spriteArr) + && maths::rectangle_clip(mainSprite->BoundingRect, refSprite->BoundingRect, nullptr)) { spriteArr->push_back(refSprite); } @@ -420,7 +353,7 @@ void render::build_occlude_list() spriteArr->clear(); if (!spriteArr->empty()) { - mainSprite->SpriteArray = spriteArr; + mainSprite->OccludedSprites = spriteArr; spriteArr = nullptr; } } diff --git a/SpaceCadetPinball/render.h b/SpaceCadetPinball/render.h index 46310b2..7cfc176 100644 --- a/SpaceCadetPinball/render.h +++ b/SpaceCadetPinball/render.h @@ -5,25 +5,33 @@ enum class VisualTypes : char { - None = 0, + Background = 0, Sprite = 1, Ball = 2 }; -struct render_sprite_type_struct +struct render_sprite { - rectangle_type BmpRect; + rectangle_type BmpRect{}; gdrv_bitmap8* Bmp; zmap_header_type* ZMap; - char UnknownFlag; + bool DeleteFlag; VisualTypes VisualType; - int16_t Depth; - rectangle_type DirtyRectPrev; + uint16_t Depth; + rectangle_type DirtyRectPrev{}; int ZMapOffestY; int ZMapOffestX; - rectangle_type DirtyRect; - std::vector* SpriteArray; - rectangle_type BoundingRect; + rectangle_type DirtyRect{}; + std::vector* OccludedSprites; + rectangle_type BoundingRect{}; + bool DirtyFlag{}; + + render_sprite(VisualTypes visualType, gdrv_bitmap8* bmp, zmap_header_type* zMap, + int xPosition, int yPosition, rectangle_type* boundingRect); + ~render_sprite(); + void set(gdrv_bitmap8* bmp, zmap_header_type* zMap, int xPos, int yPos); + void set_bitmap(gdrv_bitmap8* bmp); + void ball_set(gdrv_bitmap8* bmp, float depth, int xPos, int yPos); }; @@ -33,35 +41,26 @@ public: static gdrv_bitmap8 *vscreen, *background_bitmap; static SDL_Rect DestinationRect; - static void init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int height); + static void init(gdrv_bitmap8* bmp, int width, int height); static void uninit(); static void recreate_screen_texture(); static void update(); - static void sprite_modified(render_sprite_type_struct* sprite); - static render_sprite_type_struct* create_sprite(VisualTypes visualType, gdrv_bitmap8* bmp, - zmap_header_type* zMap, - int xPosition, int yPosition, rectangle_type* rect); - static void remove_sprite(render_sprite_type_struct* sprite, bool removeFromList); - static void remove_ball(render_sprite_type_struct* ball, bool removeFromList); - static void sprite_set(render_sprite_type_struct* sprite, gdrv_bitmap8* bmp, zmap_header_type* zMap, int xPos, - int yPos); - static void sprite_set_bitmap(render_sprite_type_struct* sprite, gdrv_bitmap8* bmp); - static void set_background_zmap(struct zmap_header_type* zMap, int offsetX, int offsetY); - static void ball_set(render_sprite_type_struct* sprite, gdrv_bitmap8* bmp, float depth, int xPos, int yPos); + static void AddSprite(render_sprite& sprite); + static void RemoveSprite(render_sprite& sprite); + static void set_background_zmap(zmap_header_type* zMap, int offsetX, int offsetY); static void shift(int offsetX, int offsetY); static void build_occlude_list(); static void SpriteViewer(bool* show); static void PresentVScreen(); private: - static std::vector dirty_list, sprite_list, ball_list; + static std::vector sprite_list, ball_list; static zmap_header_type* background_zmap; - static int zmap_offset, zmap_offsetY, offset_x, offset_y; - static float zscaler, zmin, zmax; + static int zmap_offsetX, zmap_offsetY, offset_x, offset_y; static rectangle_type vscreen_rect; static gdrv_bitmap8 *ball_bitmap[20]; static zmap_header_type* zscreen; - static void repaint(struct render_sprite_type_struct* sprite); + static void repaint(const render_sprite& sprite); static void paint_balls(); static void unpaint_balls(); };