Score: inject 3DPB msg font into dat struct.

Fixed double free in sound.
This commit is contained in:
Muzychenko Andrey 2021-10-10 12:22:21 +03:00
parent 43593b168d
commit 69ecce88df
8 changed files with 117 additions and 141 deletions

View File

@ -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<MsgFont*>(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<uint32_t>(ftell(fileHandle));
auto rcData = reinterpret_cast<MsgFont*>(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<char*>(font->Data);
for (auto charInd = 32; charInd < 128; charInd++, groupId++)
{
auto curChar = reinterpret_cast<MsgFontChar*>(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<char*>(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<int16_t*>(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);
}
}

View File

@ -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);
};

View File

@ -35,6 +35,7 @@ void Sound::Deactivate()
void Sound::Close()
{
delete[] TimeStamps;
TimeStamps = nullptr;
Mix_CloseAudio();
Mix_Quit();
}

View File

@ -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++)

View File

@ -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<char*>(bmp);
entryData->Buffer = reinterpret_cast<char*>(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;
}

View File

@ -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();
}

View File

@ -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<int16_t*>(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<int16_t*>(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);
}
}
}

View File

@ -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);
};