From e0fb7cbf9c4e4d2b2be1122064edb2e644913521 Mon Sep 17 00:00:00 2001 From: MaikelChan Date: Sun, 31 Oct 2021 21:30:11 +0100 Subject: [PATCH] The game now loads the good font that's embedded in pinball.exe. Also deleted the font that was included in EmbeddedData.cpp and changed colors of the PINBALL2.MID font. --- CMakeLists.txt | 4 +- SpaceCadetPinball/EmbeddedData.cpp | 46 ------- SpaceCadetPinball/EmbeddedData.h | 8 -- SpaceCadetPinball/GroupData.cpp | 214 ++++++++++++++++++++++++++--- SpaceCadetPinball/GroupData.h | 3 +- SpaceCadetPinball/score.cpp | 1 - 6 files changed, 197 insertions(+), 79 deletions(-) delete mode 100644 SpaceCadetPinball/EmbeddedData.cpp delete mode 100644 SpaceCadetPinball/EmbeddedData.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a7bf214..49b22fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,8 @@ endforeach() set(SOURCE_FILES SpaceCadetPinball/control.cpp SpaceCadetPinball/control.h - SpaceCadetPinball/EmbeddedData.cpp - SpaceCadetPinball/EmbeddedData.h + + SpaceCadetPinball/fullscrn.cpp SpaceCadetPinball/fullscrn.h SpaceCadetPinball/gdrv.cpp diff --git a/SpaceCadetPinball/EmbeddedData.cpp b/SpaceCadetPinball/EmbeddedData.cpp deleted file mode 100644 index 9ed514e..0000000 --- a/SpaceCadetPinball/EmbeddedData.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "EmbeddedData.h" - -#if 1 -// File: './PB_MSGFT.bin' (21702 bytes) -// Exported using binary_to_compressed_c.cpp -const char EmbeddedData::PB_MSGFT_bin_compressed_data_base85[5380 + 1] = - "7])#######>s+cc'/###Y[fi'.Y`+V*KI@%CtjT%QRR8%D[eW$G$^m&MQ>3'QK#n&FnJm&Vp:0(SWPN'SgYn&E09q%`sYn&V9B6&Z#dn&Hnj5&8uhV$Q?p2'L0K6&;@@<$SA`.2EIes$" - "RTp6&A.MZ#?@R8%]IN:-42$4CT5(a4`%5DN$rJfLe7^-#`cb*&]u#K262Q_/CR*a4qTjjMHug;-PgRfM-sJfL9#?9RqM>=-/WDa->?1I$[R/qLuqJfLxj/gLPCg;-r28r7H-ge$wKiWh" - "vR.(8.C@lL/r&gL-0pKN?lgwL[BCTM5>UkL]`kgMw3US->aDY$,oF &j-HA3nw'/%=2C:FW'8..w-$ae`n*a2Kwp:(t-$X<8w^V`w_/*TKs-" - ";c>]OW>pgLSHJ_%=0[GMZMFgMmZGhN>4ZtMsg&gL%o^wL)e6#%'Qg@c(NAvYT%Lc68%WcU4+%pwTM" - "3nf8RF:g1We=0W$c%q44SR%UM(nj-$_')B6-&R]4vlm*Mw7gV-1?=$g1cap9>;)6Ms=UkL8L)^%Q`1IN,Dn]-ICHh,flTq)s?[o#Ov1b91_ZGMW($a$Xl1s)?ESw.`EqS-n5TW&goD*8" - "9[o?9r3R4$LjYI8n2?2CNT3hc)N:(&%6l'&fDxGMi1$##2j(/NMxGp79r*C9Y&o8Bdh8x0fbMmLkv^)&qwuND;t#hO?mxC%*vbJ2jlW*I2.=2C3[;dMtk?m%Z-'TR[u,JWj>Lh$'j#n8" - "`=ujDCQ@J&GeJR9Dfd--eIi,i(]^@%71pauR?VIM)NiIMa6`;-2][N'=,HXCh4`/:lwLG'7i=k#C[-L,$oi/:XaAQ(por''<3,d;kRF&#,56vPnbR'M13oj%nSZEcXG:@-/g#pL;2669" - "4WIvRsv]O&LwQHM3l_;-TD[V9R;5r)j4NE5:t4X8" - "^/l3+Z#_K:7,G$IR.V^)E]JF%wY'q7o&Xt&mV(J;ptLQ(v>Y1'xwvq72F?T0EdRf&=$Rd=oNOg$&;mVQjQn?Gq['dk>IY)NJ27BO`r)aF749_4Y_-11jv7U-W&H9n7mL.iL;-o_)+O08)>&=]4^Z`K[r7t9#f$^t7j91r,QqSILQ89aTx9/p/hLX%co7" - "rr;p&6*Mb%a,#?POJri%XKxI4A.Eu$ZArt8`97r72T):2X[x&=8GWX(l0^&=3SaJ2R6Q&#a;;6&*]iO9q;H*5?rMY$V)9O$<,Dh:trF_JNx&?>0dY,.h5*g$BC5v([3p6EJs#t&_DIu%" - "l5A@':GuP8BD[`&V'/W-hs+^ZrT2qF&#t`V^=mb3dXkx/W&WCCgLV8UM9ew4oh;#Bgh;Kas-#`?Q8]JeKul^]m8ctB6X%1fN^#qR<^LFPa*vp(?>?Lc'&" - "?Swa<=Mc'&U2u`4w080:h%dm:draZ%U_%?P1_W3M#>w.%?Pm7$)N?@-`bPl$uQh'&]ZDA>fa(4Dq#1a)+a;i#I;[#>G27w%l0=S,=%h)&D=57*dR6@.[?kc%Ia(E<#kPFYb/3M2#D*F." - "i<,UVYBoe)vS2.Kg%QRJ^?UbmC?c67l)rTjj&]1lgLNih`^q)[T%AOPFJZ$YMg58He`q2I6w:@,[F&#YJ7#:s8fdMM_%Z>]8M'S/8D_6.;jbMa.h1&`d8m8@C-tJ]6^w'6kv;]cdTD&" - "gv7*P`Bbc%9*l8KZ@,6;n)F7K.4e;/6F2aYML@--;ZT%Z-DIm`KJ<-?22$Xp&Z7@AK@kX;-FQ85ohKaa.k<9wi4ed]XJQ(d@sv7f3i/<]gMeMk+V'F>]ZYo)kMB%" - "P^mkie1Fp=Q]2U2i$a#P;.r.*QD>Q8?Wi[(fp.M$s$&(SdVJT@bq):i/2u-MQ;6L-TV,<-9K$n:glR0<,k3B&ZaJ2fMhG;HY:_A9TAdM3qB#>B?C[I>Y2m&NIb#>[haJ2@5('O" - "^o8V%qfQ^?FtjW;2,j;9RD&e@hg_$'e59U)b=;s%2Q_698exI.DM5Kji033&f]fEW5@a$>aV`sBWbm-NOg9[%u%K;/c`'6)RC`N'AeA-ow,=&k_3TRfnxv$" - "n()<-0klw$aeIjMB*;.&@&fJ.DUo,;H(6+Y9N[mfE^A0:^IRqL@PD6MxZN$'.21q7#3NoIDf3l3+Q5#Q8erke#?2tHW" - "9xMY$Qtr&OfkCX%nou#PV:8Z$i1dm8,%(@0n*7EH5=+nMk`rS@It$@'M9XCf(DSgWZf=k%dZQqYTc<%Q4_$f`-1n85X?hGidK_mlK8f$Lt@KCDihv@C^Hn:dLDc##bp_-Q[J;gcdAh:8_2cYtoL/;=tq$'^XRvR" - "@B`/9Lu%=BWKR3<:kRvRFbG-&BU+a<41bJ2e[SoUAjo?MX'-a&&R[k4C4A_8_RrS&t25394Xk,k(XDY&.Svj9176e4'8]u%&.(B@pM?.%,ABgLs[1]$$SF&#NfBdMmp$>+LqZdM.ih;-" - "ba1Q*noHjR=iJs?0@Y)=%&3MHXWn891[w'@aop7" - "JUx>._mko&:V6j9BY%`?=TA?&erCj9OTF&#xR7p&Il:Q8B>u`4]/g;-L=hRAS,=LsLISn&w1aZ@&*9,(lv]Gu)#)f;M4.`AK?`i>9'KZ_h#" - "^96>DuNT@-1XurCV<@`&oe6N;n##?-eGVD&ftt?0=4vV%^>WAJF%3q%k>k(7Q+x4ARL:a4auH6Mg3%4CGo5mACC$=12^0^#DOUV-8)xZgO=1eZ2e+d;J6G]:lRpX'=)I6TBV+@(Q2r,;" - "bwgtoAeYd&TrtGM2T6i$dn;m8:[o(m+?B4&bnsG;DT^_I-l9n$.^d7+_^wGMrnXo&0D]gUfQGNA4`FaIZ>wIf#.q0Ii&i1s`FCAR]ea+h`(x#%#AL'U=R;B=Wac>bpg%'I49R=,.78DdN)Y1D[A-cCULM&<;Y&qsRg:@6q=8e(sP:YG,iLf,jlJh&s22](6=*bX]aFu`4jmlsHvJ]c5,kAY'hgE&OEpvw&A@^B'%;Xk#=3`2;0n`=g/K(w'Zok,M82^m@`:bH=>6r`$p.0QJ;#qDlbS;s?OP5'Z.a%G=NsX0NUQ1X%7Bbm8-Kdgtq,WOvYaNWhZMOH##TWvNb@(%9rSllV$+^8I%OuBv$`)bJ2UiCQ8gjo6*uS)`%-`W/%?)c;-d&?s%GWRh*@O/w7=$O#Rix,`%`a=&FC6$XLYxDH;" - "Y5=2C`Fws7Bhki$MJ$-++`_8RWmU9R$ui$G;6Na,I8g$&g5x9f$nwTWJ']jk=-3^^m2vZ8@(#O,W8$Gj9DZRV49/J=P;" - "``a;&#pbJ28k)eAA`/s+j&BH>:oB&&g1<-N:md$bSYm8#u^7).4H0&q3n0#B[G&#" - "%baa*`3t,;Nm>v]^JtC(mC:/%*WN7:aarL7;f[=-XbnHbSm`I&Z?ap7[pZ@1dIa:8FZkL:p,kRM^$lf%92@v&mCeA-XHFK&t/c9BBP)CZSu>*(]G8l#>aDL'k$XRf2Nn-8V8*lb`69FF3N@uNe+.AYXS9ALPSV/-Y$GetZMap(fullscrn::GetResolution()); } +MsgFont *DatFile::ReadPEMsgFontResource(const std::string peName) +{ + auto file = pinball::make_path_name(peName); + auto fileHandle = fopen(file.c_str(), "rb"); + + if (fileHandle == nullptr) + return nullptr; + + fseek(fileHandle, 0x3C, SEEK_SET); + constexpr uint8_t peHeaderSize = 0x18; + uint32_t peHeaderOffset; + fread(&peHeaderOffset, sizeof(uint32_t), 1, fileHandle); + + fseek(fileHandle, peHeaderOffset + 0x6, SEEK_SET); + uint16_t numberOfSections; + fread(&numberOfSections, sizeof(uint16_t), 1, fileHandle); + + if (numberOfSections != 3) + { + fclose(fileHandle); + return nullptr; + } + + fseek(fileHandle, peHeaderOffset + 0x14, SEEK_SET); + uint16_t sizeOfOptionalHeader; + fread(&sizeOfOptionalHeader, sizeof(uint16_t), 1, fileHandle); + + constexpr uint8_t sizeOfSectionHeader = 0x28; + uint32_t sectionHeadersOffset = peHeaderOffset + peHeaderSize + sizeOfOptionalHeader; + uint32_t thirdSectionHeaderOffset = sectionHeadersOffset + sizeOfSectionHeader * 2; + fseek(fileHandle, thirdSectionHeaderOffset, SEEK_SET); + + char sectionName[0x8] = {}; + fread(sectionName, sizeof(char), 0x8, fileHandle); + + if (strcmp(sectionName, ".rsrc\0") != 0) + { + fclose(fileHandle); + return nullptr; + } + + fseek(fileHandle, thirdSectionHeaderOffset + 0xc, SEEK_SET); + uint32_t rsrcSectionVirtualAddress; + fread(&rsrcSectionVirtualAddress, sizeof(uint32_t), 1, fileHandle); + + fseek(fileHandle, thirdSectionHeaderOffset + 0x14, SEEK_SET); + uint32_t rsrcSectionDataOffset; + fread(&rsrcSectionDataOffset, sizeof(uint32_t), 1, fileHandle); + + fseek(fileHandle, rsrcSectionDataOffset + 0xe, SEEK_SET); + uint16_t numberOfIDEntries; + fread(&numberOfIDEntries, sizeof(uint16_t), 1, fileHandle); + + if (numberOfIDEntries == 0) + { + fclose(fileHandle); + return nullptr; + } + + uint32_t subdirectoryOffset = 0; + + for (uint16_t e = 0; e < numberOfIDEntries; e++) + { + fseek(fileHandle, rsrcSectionDataOffset + 0x10 + (0x8 * e), SEEK_SET); + int32_t entryIntegerID; + fread(&entryIntegerID, sizeof(int32_t), 1, fileHandle); + + if (entryIntegerID == 0xa) // RCDATA + { + fread(&subdirectoryOffset, sizeof(uint32_t), 1, fileHandle); + subdirectoryOffset &= 0x7fffffff; + subdirectoryOffset += rsrcSectionDataOffset; + break; + } + } + + if (subdirectoryOffset == 0) + { + fclose(fileHandle); + return nullptr; + } + + fseek(fileHandle, subdirectoryOffset + 0xc, SEEK_SET); + uint16_t numberOfNameEntries; + fread(&numberOfNameEntries, sizeof(uint16_t), 1, fileHandle); + + if (numberOfNameEntries == 0) + { + fclose(fileHandle); + return nullptr; + } + + fseek(fileHandle, subdirectoryOffset + 0x10, SEEK_SET); + + uint32_t nameOffset; + fread(&nameOffset, sizeof(uint32_t), 1, fileHandle); + nameOffset &= 0x7fffffff; + nameOffset += rsrcSectionDataOffset; + + fread(&subdirectoryOffset, sizeof(uint32_t), 1, fileHandle); + subdirectoryOffset &= 0x7fffffff; + subdirectoryOffset += rsrcSectionDataOffset; + + fseek(fileHandle, nameOffset, SEEK_SET); + uint16_t expectedName[9] = {0x08, 0x50, 0x42, 0x4d, 0x53, 0x47, 0x5f, 0x46, 0x54}; // PBMSG_FT + uint16_t name[9]; + fread(name, sizeof(uint16_t), 9, fileHandle); + + for (int n = 0; n < 9; n++) + { + if (name[n] != expectedName[n]) + { + fclose(fileHandle); + return nullptr; + } + } + + fseek(fileHandle, subdirectoryOffset + 0xe, SEEK_SET); + fread(&numberOfIDEntries, sizeof(uint16_t), 1, fileHandle); + + if (numberOfIDEntries == 0) + { + fclose(fileHandle); + return nullptr; + } + + // If the user has some pinball.exe in a language other than English, + // or multiple languages, there would be one IDEntry for each language here. + + /*fseek(fileHandle, subdirectoryOffset + 0x10, SEEK_SET); + uint32_t languageID; + fread(&languageID, sizeof(uint32_t), 1, fileHandle);*/ + + fseek(fileHandle, subdirectoryOffset + 0x14, SEEK_SET); + uint32_t dataEntryOffset; + fread(&dataEntryOffset, sizeof(uint32_t), 1, fileHandle); + dataEntryOffset &= 0x7fffffff; + dataEntryOffset += rsrcSectionDataOffset; + + fseek(fileHandle, dataEntryOffset, SEEK_SET); + uint32_t dataOffset, dataSize; + fread(&dataOffset, sizeof(uint32_t), 1, fileHandle); + fread(&dataSize, sizeof(uint32_t), 1, fileHandle); + + fseek(fileHandle, (rsrcSectionDataOffset - rsrcSectionVirtualAddress) + dataOffset, SEEK_SET); + MsgFont *msgFont = reinterpret_cast(new uint8_t[dataSize]); + fread(msgFont, 1, dataSize, fileHandle); + + fclose(fileHandle); + + return msgFont; +} + void DatFile::Finalize() { if (!pb::FullTiltMode) @@ -288,27 +440,34 @@ void DatFile::Finalize() 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); + MsgFont *rcData = ReadPEMsgFontResource("pinball.exe"); + + if (rcData != nullptr) + { + AddMsgFont(rcData, "pbmsg_ft", false); + } + else + { + // PINBALL2.MID is an alternative font provided in 3DPB data + // Scaled down because it is too large for top text box + + 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)); + rcData = reinterpret_cast(new uint8_t[fileSize]); + fseek(fileHandle, 0, SEEK_SET); + fread(rcData, 1, fileSize, fileHandle); + fclose(fileHandle); + + auto groupId = Groups.back()->GroupId + 1u; + AddMsgFont(rcData, "pbmsg_ft", true); + + for (auto i = groupId; i < Groups.size(); i++) + Groups[i]->GetBitmap(0)->ScaleIndexed(0.84f, 0.84f); + } - // PINBALL2.MID is an alternative font provided in 3DPB data - // Scaled down because it is too large for top text box - /*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); - auto groupId = Groups.back()->GroupId + 1u; - AddMsgFont(rcData, "pbmsg_ft"); delete[] rcData; - for (auto i = groupId; i < Groups.size(); i++) - Groups[i]->GetBitmap(0)->ScaleIndexed(0.84f, 0.84f);*/ } for (auto group : Groups) @@ -317,7 +476,7 @@ void DatFile::Finalize() } } -void DatFile::AddMsgFont(MsgFont* font, const std::string& fontName) +void DatFile::AddMsgFont(MsgFont* font, const std::string& fontName, const bool changePaletteIndices) { auto groupId = Groups.back()->GroupId + 1; auto ptrToData = reinterpret_cast(font->Data); @@ -325,6 +484,19 @@ void DatFile::AddMsgFont(MsgFont* font, const std::string& fontName) { auto curChar = reinterpret_cast(ptrToData); assertm(curChar->Width == font->CharWidths[charInd], "Score: mismatched font width"); + + if (changePaletteIndices) + { + // The alternate font in PINBALL2.MID is hard to read due to having dark colors. + // Modify the pixels so it matches the other font. + + for (int i = 0; i < curChar->Width * font->Height; i++) + { + if (curChar->Data[i] == 0x50) curChar->Data[i] = 0x30; + if (curChar->Data[i] == 0x69) curChar->Data[i] = 0x64; + } + } + ptrToData += curChar->Width * font->Height + 1; auto bmp = new gdrv_bitmap8(curChar->Width, font->Height, true); diff --git a/SpaceCadetPinball/GroupData.h b/SpaceCadetPinball/GroupData.h index 63d670d..9cc6e5c 100644 --- a/SpaceCadetPinball/GroupData.h +++ b/SpaceCadetPinball/GroupData.h @@ -121,8 +121,9 @@ public: char* field_labeled(LPCSTR lpString, FieldTypes fieldType); gdrv_bitmap8* GetBitmap(int groupIndex); zmap_header_type* GetZMap(int groupIndex); + MsgFont* ReadPEMsgFontResource(const std::string peName); void Finalize(); private: - void AddMsgFont(MsgFont* font, const std::string& fontName); + void AddMsgFont(MsgFont* font, const std::string& fontName, const bool changePaletteIndices); }; diff --git a/SpaceCadetPinball/score.cpp b/SpaceCadetPinball/score.cpp index 243b56d..4405c62 100644 --- a/SpaceCadetPinball/score.cpp +++ b/SpaceCadetPinball/score.cpp @@ -1,7 +1,6 @@ #include "pch.h" #include "score.h" -#include "EmbeddedData.h" #include "fullscrn.h" #include "loader.h" #include "GroupData.h"