From 69ecce88df932c87a459d52e5f8ee9dc042f3b89 Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Sun, 10 Oct 2021 12:22:21 +0300 Subject: [PATCH] Score: inject 3DPB msg font into dat struct. Fixed double free in sound. --- SpaceCadetPinball/GroupData.cpp | 81 +++++++++++++++++++++++- SpaceCadetPinball/GroupData.h | 25 ++++++++ SpaceCadetPinball/Sound.cpp | 1 + SpaceCadetPinball/gdrv.cpp | 1 - SpaceCadetPinball/partman.cpp | 6 +- SpaceCadetPinball/render.cpp | 21 ------ SpaceCadetPinball/score.cpp | 109 ++------------------------------ SpaceCadetPinball/score.h | 14 +--- 8 files changed, 117 insertions(+), 141 deletions(-) diff --git a/SpaceCadetPinball/GroupData.cpp b/SpaceCadetPinball/GroupData.cpp index 96912d4..5ef2542 100644 --- a/SpaceCadetPinball/GroupData.cpp +++ b/SpaceCadetPinball/GroupData.cpp @@ -2,8 +2,11 @@ #include "GroupData.h" +#include "EmbeddedData.h" #include "fullscrn.h" #include "gdrv.h" +#include "pb.h" +#include "pinball.h" #include "zdrv.h" @@ -105,7 +108,7 @@ void GroupData::SplitSplicedBitmap(const gdrv_bitmap8& srcBmp, gdrv_bitmap8& bmp bmp.XPosition = srcBmp.XPosition; bmp.YPosition = srcBmp.YPosition; bmp.Resolution = srcBmp.Resolution; - + zdrv::fill(&zMap, zMap.Width, zMap.Height, 0, 0, 0xFFFF); zMap.Resolution = srcBmp.Resolution; @@ -277,3 +280,79 @@ zmap_header_type* DatFile::GetZMap(int groupIndex) auto group = Groups[groupIndex]; return group->GetZMap(fullscrn::GetResolution()); } + +void DatFile::Finalize() +{ + if (!pb::FullTiltMode) + { + int groupIndex = record_labeled("pbmsg_ft"); + assertm(groupIndex < 0, "DatFile: pbmsg_ft is already in .dat"); + + // Load 3DPB font into dat to simplify pipeline + auto rcData = reinterpret_cast(ImFontAtlas::DecompressCompressedBase85Data( + EmbeddedData::PB_MSGFT_bin_compressed_data_base85)); + AddMsgFont(rcData, "pbmsg_ft"); + IM_FREE(rcData); + + // PINBALL2.MID is an alternative font provided in 3DPB data + /*auto file = pinball::make_path_name("PINBALL2.MID"); + auto fileHandle = fopen(file.c_str(), "rb"); + fseek(fileHandle, 0, SEEK_END); + auto fileSize = static_cast(ftell(fileHandle)); + auto rcData = reinterpret_cast(new uint8_t[fileSize]); + fseek(fileHandle, 0, SEEK_SET); + fread(rcData, 1, fileSize, fileHandle); + fclose(fileHandle); + AddMsgFont(rcData, "pbmsg_ft"); + delete[] rcData;*/ + } + + for (auto group : Groups) + { + group->FinalizeGroup(); + } +} + +void DatFile::AddMsgFont(MsgFont* font, const std::string& fontName) +{ + auto groupId = Groups.back()->GroupId + 1; + auto ptrToData = reinterpret_cast(font->Data); + for (auto charInd = 32; charInd < 128; charInd++, groupId++) + { + auto curChar = reinterpret_cast(ptrToData); + assertm(curChar->Width == font->CharWidths[charInd], "Score: mismatched font width"); + ptrToData += curChar->Width * font->Height + 1; + + auto bmp = new gdrv_bitmap8(curChar->Width, font->Height, true); + auto srcPtr = curChar->Data; + auto dstPtr = &bmp->IndexedBmpPtr[bmp->Stride * (bmp->Height - 1)]; + for (auto y = 0; y < font->Height; ++y) + { + memcpy(dstPtr, srcPtr, curChar->Width); + srcPtr += curChar->Width; + dstPtr -= bmp->Stride; + } + + auto group = new GroupData(groupId); + group->AddEntry(new EntryData(FieldTypes::Bitmap8bit, reinterpret_cast(bmp))); + if (charInd == 32) + { + // First font group holds font name and gap width + auto groupName = new char[fontName.length() + 1]; + strcpy(groupName, fontName.c_str()); + group->AddEntry(new EntryData(FieldTypes::GroupName, groupName)); + + auto gaps = new char[2]; + *reinterpret_cast(gaps) = font->GapWidth; + group->AddEntry(new EntryData(FieldTypes::ShortArray, gaps)); + } + else + { + auto groupName = new char[30]; + sprintf(groupName, "char %d='%c'", charInd, charInd); + group->AddEntry(new EntryData(FieldTypes::GroupName, groupName)); + } + + Groups.push_back(group); + } +} diff --git a/SpaceCadetPinball/GroupData.h b/SpaceCadetPinball/GroupData.h index f754ad2..63d670d 100644 --- a/SpaceCadetPinball/GroupData.h +++ b/SpaceCadetPinball/GroupData.h @@ -55,6 +55,27 @@ struct EntryData char* Buffer{}; }; + +#pragma pack(push, 1) +struct MsgFontChar +{ + uint8_t Width; + char Data[1]; +}; + +struct MsgFont +{ + int16_t GapWidth; + int16_t Unknown1; + int16_t Height; + uint8_t CharWidths[128]; + MsgFontChar Data[1]; +}; +#pragma pack(pop) + +static_assert(sizeof(MsgFont) == 136, "Wrong size of MsgFont"); + + class GroupData { public: @@ -100,4 +121,8 @@ public: char* field_labeled(LPCSTR lpString, FieldTypes fieldType); gdrv_bitmap8* GetBitmap(int groupIndex); zmap_header_type* GetZMap(int groupIndex); + void Finalize(); + +private: + void AddMsgFont(MsgFont* font, const std::string& fontName); }; diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index bad0a95..902c042 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -35,6 +35,7 @@ void Sound::Deactivate() void Sound::Close() { delete[] TimeStamps; + TimeStamps = nullptr; Mix_CloseAudio(); Mix_Quit(); } diff --git a/SpaceCadetPinball/gdrv.cpp b/SpaceCadetPinball/gdrv.cpp index 759bbc5..b060ca0 100644 --- a/SpaceCadetPinball/gdrv.cpp +++ b/SpaceCadetPinball/gdrv.cpp @@ -119,7 +119,6 @@ int gdrv::display_palette(ColorRgba* plt) current_palette[255].Color = 0xffFFFFFF; - score::ApplyPalette(); for (const auto group : pb::record_table->Groups) { for (int i = 0; i <= 2; i++) diff --git a/SpaceCadetPinball/partman.cpp b/SpaceCadetPinball/partman.cpp index 2033f81..5c89df9 100644 --- a/SpaceCadetPinball/partman.cpp +++ b/SpaceCadetPinball/partman.cpp @@ -75,7 +75,7 @@ DatFile* partman::load_records(LPCSTR lpFileName, bool fullTiltMode) assertm(bmpHeader.Resolution <= 2, "partman: bitmap resolution out of bounds"); auto bmp = new gdrv_bitmap8(bmpHeader); - entryData->Buffer = reinterpret_cast(bmp); + entryData->Buffer = reinterpret_cast(bmp); fread(bmp->IndexedBmpPtr, 1, bmpHeader.Size, fileHandle); } else if (entryType == FieldTypes::Bitmap16bit) @@ -120,13 +120,15 @@ DatFile* partman::load_records(LPCSTR lpFileName, bool fullTiltMode) groupData->AddEntry(entryData); } - groupData->FinalizeGroup(); datFile->Groups.push_back(groupData); } fclose(fileHandle); if (datFile->Groups.size() == header.NumberOfGroups) + { + datFile->Finalize(); return datFile; + } delete datFile; return nullptr; } diff --git a/SpaceCadetPinball/render.cpp b/SpaceCadetPinball/render.cpp index bfe9936..30d6b35 100644 --- a/SpaceCadetPinball/render.cpp +++ b/SpaceCadetPinball/render.cpp @@ -521,27 +521,6 @@ void render::SpriteViewer(bool* show) } } } - - // 3DPB font is not in dat file. - if (!pb::FullTiltMode) - { - int index = -1; - for (auto bmp : score::msg_fontp->Chars) - { - index++; - if (!bmp) - continue; - - ImGui::Text("Char: %d, symbol:'%c'", index, index); - - gdrv::CreatePreview(*bmp); - if (bmp->Texture) - { - ImGui::Image(bmp->Texture, ImVec2(bmp->Width * scale, bmp->Height * scale), - uv_min, uv_max, tint_col, border_col); - } - } - } } ImGui::End(); } diff --git a/SpaceCadetPinball/score.cpp b/SpaceCadetPinball/score.cpp index 7e9d0e6..243b56d 100644 --- a/SpaceCadetPinball/score.cpp +++ b/SpaceCadetPinball/score.cpp @@ -53,100 +53,23 @@ scoreStruct* score::dup(scoreStruct* score, int scoreIndex) } void score::load_msg_font(LPCSTR lpName) -{ - /*3DPB stores font in resources, FT in dat. FT font has multiple resolutions*/ - if (pb::FullTiltMode) - load_msg_font_FT(lpName); - else - load_msg_font_3DPB(lpName); -} - -void score::load_msg_font_3DPB(LPCSTR lpName) -{ - if (strcmp(lpName, "pbmsg_ft") != 0) - return; - - auto rcData = reinterpret_cast(ImFontAtlas::DecompressCompressedBase85Data( - EmbeddedData::PB_MSGFT_bin_compressed_data_base85)); - - auto fontp = new score_msg_font_type(); - msg_fontp = fontp; - if (!fontp) - { - return; - } - memset(fontp->Chars, 0, sizeof fontp->Chars); - - auto maxWidth = 0; - auto ptrToWidths = (char*)rcData + 6; - for (auto index = 128; index; index--) - { - if (*ptrToWidths > maxWidth) - maxWidth = *ptrToWidths; - ++ptrToWidths; - } - - auto height = rcData[2]; - auto tmpCharBur = new char[maxWidth * height + 4]; - if (!tmpCharBur) - { - delete msg_fontp; - msg_fontp = nullptr; - IM_FREE(rcData); - return; - } - - msg_fontp->GapWidth = rcData[0]; - msg_fontp->Height = height; - - auto ptrToData = (char*)(rcData + 67); - int charInd; - for (charInd = 0; charInd < 128; charInd++) - { - auto width = *((char*)rcData + 6 + charInd); - if (!width) - continue; - - auto bmp = new gdrv_bitmap8(width, height, true); - msg_fontp->Chars[charInd] = bmp; - - auto sizeInBytes = height * width + 1; - memcpy(tmpCharBur + 3, ptrToData, sizeInBytes); - ptrToData += sizeInBytes; - - auto srcPtr = tmpCharBur + 4; - auto dstPtr = &bmp->IndexedBmpPtr[bmp->Stride * (bmp->Height - 1)]; - for (auto y = 0; y < height; ++y) - { - memcpy(dstPtr, srcPtr, width); - srcPtr += width; - dstPtr -= bmp->Stride; - } - } - - delete[] tmpCharBur; - IM_FREE(rcData); - if (charInd != 128) - unload_msg_font(); -} - -void score::load_msg_font_FT(LPCSTR lpName) { if (!pb::record_table) return; + int groupIndex = pb::record_table->record_labeled(lpName); if (groupIndex < 0) return; - msg_fontp = new score_msg_font_type(); - if (!msg_fontp) - return; - memset(msg_fontp, 0, sizeof(score_msg_font_type)); + msg_fontp = new score_msg_font_type(); + + // FT font has multiple resolutions auto gapArray = reinterpret_cast(pb::record_table->field(groupIndex, FieldTypes::ShortArray)); if (gapArray) msg_fontp->GapWidth = gapArray[fullscrn::GetResolution()]; else msg_fontp->GapWidth = 0; + for (auto charIndex = 32; charIndex < 128; charIndex++, ++groupIndex) { auto bmp = pb::record_table->GetBitmap(groupIndex); @@ -158,16 +81,11 @@ void score::load_msg_font_FT(LPCSTR lpName) } } + void score::unload_msg_font() { if (msg_fontp) { - /*3DBP creates bitmaps, FT just references them from partman*/ - if (!pb::FullTiltMode) - for (auto& Char : msg_fontp->Chars) - { - delete Char; - } delete msg_fontp; msg_fontp = nullptr; } @@ -267,18 +185,3 @@ void score::string_format(int score, char* str) } } } - -void score::ApplyPalette() -{ - if (!msg_fontp || pb::FullTiltMode) - return; - - // Only 3DPB font needs this, because it is not loaded by partman - for (auto& Char : msg_fontp->Chars) - { - if (Char) - { - gdrv::ApplyPalette(*Char); - } - } -} diff --git a/SpaceCadetPinball/score.h b/SpaceCadetPinball/score.h index 39d5529..533a49f 100644 --- a/SpaceCadetPinball/score.h +++ b/SpaceCadetPinball/score.h @@ -17,15 +17,7 @@ struct score_msg_font_type { int GapWidth; int Height; - gdrv_bitmap8* Chars[128]; -}; - -struct score_font_rc -{ - short Header0; - short Header1; - short Height; - char SomeLen[128]; + gdrv_bitmap8* Chars[128]{}; }; @@ -42,8 +34,4 @@ public: static void set(scoreStruct* score, int value); static void update(scoreStruct* score); static void string_format(int score, char* str); - static void ApplyPalette(); -private : - static void load_msg_font_3DPB(LPCSTR lpName); - static void load_msg_font_FT(LPCSTR lpName); };