From d83c4e2b2618833c8e14d7029057e98703f4e00b Mon Sep 17 00:00:00 2001 From: oz Date: Sun, 29 Nov 2020 18:50:49 +0300 Subject: [PATCH] Proj v1, ready. port_draw in multiple T classes. pb v1. proj v1, ready. WinMain v3. --- Doc/FuncStats.xlsx | Bin 31530 -> 31931 bytes SpaceCadetPinball/Sound.cpp | 4 + SpaceCadetPinball/Sound.h | 3 +- SpaceCadetPinball/SpaceCadetPinball.cpp | 25 ++-- SpaceCadetPinball/SpaceCadetPinball.vcxproj | 4 + .../SpaceCadetPinball.vcxproj.filters | 12 ++ SpaceCadetPinball/TCollisionComponent.cpp | 9 ++ SpaceCadetPinball/TCollisionComponent.h | 1 + SpaceCadetPinball/TEdgeSegment.cpp | 4 + SpaceCadetPinball/TEdgeSegment.h | 9 +- SpaceCadetPinball/TPinballComponent.cpp | 4 + SpaceCadetPinball/TPinballComponent.h | 1 + SpaceCadetPinball/TPinballTable.cpp | 9 ++ SpaceCadetPinball/TPinballTable.h | 1 + SpaceCadetPinball/TTextBox.cpp | 10 +- SpaceCadetPinball/TTextBox.h | 2 + SpaceCadetPinball/maths.cpp | 11 ++ SpaceCadetPinball/maths.h | 1 + SpaceCadetPinball/partman.cpp | 30 +---- SpaceCadetPinball/partman.h | 3 - SpaceCadetPinball/pb.cpp | 120 ++++++++++++++++++ SpaceCadetPinball/pb.h | 17 ++- SpaceCadetPinball/pinball.cpp | 29 ++++- SpaceCadetPinball/pinball.h | 3 +- SpaceCadetPinball/proj.cpp | 62 +++++++++ SpaceCadetPinball/proj.h | 32 +++++ SpaceCadetPinball/render.cpp | 2 +- SpaceCadetPinball/score.cpp | 5 + SpaceCadetPinball/score.h | 1 + SpaceCadetPinball/timer.cpp | 38 ++++++ SpaceCadetPinball/timer.h | 21 +++ SpaceCadetPinball/winmain.cpp | 115 ++++++++++++++--- SpaceCadetPinball/winmain.h | 6 +- SpaceCadetPinball/zdrv.cpp | 2 +- 34 files changed, 519 insertions(+), 77 deletions(-) create mode 100644 SpaceCadetPinball/proj.cpp create mode 100644 SpaceCadetPinball/proj.h create mode 100644 SpaceCadetPinball/timer.cpp create mode 100644 SpaceCadetPinball/timer.h diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index a4ce67b0c3786e49129646380df3b59d7c7af18e..8031207d30f2117e8b1bebe262de0a56f671f5f3 100644 GIT binary patch delta 21843 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 PZey`gzq3?_(KG)K!%puG diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index 115418e..9c4df2e 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -8,3 +8,7 @@ void Sound::Enable(int a1, int a2, int a3) void Sound::nullsub_1(int a1, int a2, int a3) { } + +void Sound::Idle() +{ +} diff --git a/SpaceCadetPinball/Sound.h b/SpaceCadetPinball/Sound.h index a7f123f..1fca981 100644 --- a/SpaceCadetPinball/Sound.h +++ b/SpaceCadetPinball/Sound.h @@ -3,5 +3,6 @@ class Sound { public: static void Enable(int a1, int a2, int a3); - static void nullsub_1(int a1, int a2, int a3); + static void nullsub_1(int a1, int a2, int a3); + static void Idle(); }; diff --git a/SpaceCadetPinball/SpaceCadetPinball.cpp b/SpaceCadetPinball/SpaceCadetPinball.cpp index 6654938..92292a6 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.cpp +++ b/SpaceCadetPinball/SpaceCadetPinball.cpp @@ -9,6 +9,7 @@ #include "DatParser.h" #include "gdrv.h" #include "loader.h" +#include "pb.h" #include "pinball.h" #include "score.h" #include "TPinballTable.h" @@ -17,17 +18,19 @@ int main() { std::cout << "Hello World!\n"; - - pinball::hinst = GetModuleHandleA(nullptr); - char cmdLine[1]{}; - //WinMain(pinball::hinst, 0, cmdLine, 10); + { + // Testing with UI + /* lstrcpyA(pinball::DatFileName, "PINBALL.DAT"); + pinball::hinst = GetModuleHandleA(nullptr); + char cmdLine[1]{}; + pb::init(); + WinMain(pinball::hinst, 0, cmdLine, 10);*/ + } gdrv::init(0, 0); auto dib = gdrv::DibCreate(8, 1, 1); gdrv::DibSetUsage(dib, 0, 1); - render::init(0, 1, 2, 800, 600); - objlist_class d = objlist_class(2, 4); for (int i = 0; i < 100; i++) { @@ -37,10 +40,9 @@ int main() auto xx = sizeof(datFileHeader); - char dataFileName[300]; - partman::make_path_name(dataFileName, "PINBALL.DAT"); - auto datFile = partman::load_records(dataFileName); - assert(datFile); + lstrcpyA(pinball::DatFileName, "PINBALL.DAT"); + pb::init(); + auto datFile = pb::record_table; assert(partman::field_size_nth(datFile, 0, datFieldTypes::String, 0) == 43); assert(partman::field_size_nth(datFile, 2, datFieldTypes::Palette, 0) == 1024); @@ -55,7 +57,6 @@ int main() assert(memcmp(partman::field_labeled(datFile, "table_size", datFieldTypes::ShortArray), new short[2]{ 600, 416 }, 2 * 2) == 0); //loader::error(25, 26); - loader::loadfrom(datFile); loader::get_sound_id(18); visualStruct visual1{}; loader::material(96, &visual1); @@ -65,7 +66,7 @@ int main() auto score1 = score::create("score1", nullptr); - auto pinballTable = new TPinballTable(); + auto pinballTable = pb::MainTable; //pinballTable->find_component(1); for (int i = 0; i < 190; i++) diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj b/SpaceCadetPinball/SpaceCadetPinball.vcxproj index fbbd5a2..5350bc3 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj @@ -165,6 +165,7 @@ + @@ -182,6 +183,7 @@ + @@ -226,6 +228,7 @@ Create + @@ -243,6 +246,7 @@ + diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters index 52e0826..56254e7 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters @@ -195,6 +195,12 @@ Header Files\TCollisionComponent + + Header Files + + + Header Files + @@ -356,6 +362,12 @@ Source Files\TCollisionComponent + + Source Files + + + Source Files + diff --git a/SpaceCadetPinball/TCollisionComponent.cpp b/SpaceCadetPinball/TCollisionComponent.cpp index 1dc273e..5da51ae 100644 --- a/SpaceCadetPinball/TCollisionComponent.cpp +++ b/SpaceCadetPinball/TCollisionComponent.cpp @@ -48,3 +48,12 @@ TCollisionComponent::~TCollisionComponent() } delete this->EdgeList; } + + +void TCollisionComponent::port_draw() +{ + for (int index = EdgeList->Count() - 1; index >= 0; index--) + { + static_cast(EdgeList->Get(index))->port_draw(); + } +} diff --git a/SpaceCadetPinball/TCollisionComponent.h b/SpaceCadetPinball/TCollisionComponent.h index b31b30d..738c49f 100644 --- a/SpaceCadetPinball/TCollisionComponent.h +++ b/SpaceCadetPinball/TCollisionComponent.h @@ -17,4 +17,5 @@ public: TCollisionComponent(TPinballTable* table, int groupIndex, bool createWall); ~TCollisionComponent(); + void port_draw() override; }; diff --git a/SpaceCadetPinball/TEdgeSegment.cpp b/SpaceCadetPinball/TEdgeSegment.cpp index 8669db5..95235b7 100644 --- a/SpaceCadetPinball/TEdgeSegment.cpp +++ b/SpaceCadetPinball/TEdgeSegment.cpp @@ -11,6 +11,10 @@ TEdgeSegment::TEdgeSegment(TCollisionComponent* collComp, char* someFlag, unsign this->Unknown3_0 = 0; } +void TEdgeSegment::port_draw() +{ +} + TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* collComp, char* flagPtr, unsigned int visual_flag, float offset, int someValue) diff --git a/SpaceCadetPinball/TEdgeSegment.h b/SpaceCadetPinball/TEdgeSegment.h index e652f7c..286a218 100644 --- a/SpaceCadetPinball/TEdgeSegment.h +++ b/SpaceCadetPinball/TEdgeSegment.h @@ -19,14 +19,13 @@ public: int VisualFlag; TEdgeSegment(TCollisionComponent* collComp, char* someFlag, unsigned int visualFlag); + virtual ~TEdgeSegment() = default; - virtual ~TEdgeSegment() - { - } - + virtual void EdgeCollision(TBall* ball, float coef) = 0; + virtual void port_draw(); virtual void place_in_grid() = 0; virtual double FindCollisionDistance(ray_type* ray) = 0; - virtual void EdgeCollision(TBall* ball, float coef) = 0; + static TEdgeSegment* install_wall(float* floatArr, TCollisionComponent* collComp, char* flagPtr, unsigned int visual_flag, float offset, int someValue); }; diff --git a/SpaceCadetPinball/TPinballComponent.cpp b/SpaceCadetPinball/TPinballComponent.cpp index 26447d9..982e5d9 100644 --- a/SpaceCadetPinball/TPinballComponent.cpp +++ b/SpaceCadetPinball/TPinballComponent.cpp @@ -95,6 +95,10 @@ int TPinballComponent::Message(int message1, float message2) return 0; } +void TPinballComponent::port_draw() +{ +} + void TPinballComponent::put_scoring(int score1, int score2) { } diff --git a/SpaceCadetPinball/TPinballComponent.h b/SpaceCadetPinball/TPinballComponent.h index 5a26850..3bdc99f 100644 --- a/SpaceCadetPinball/TPinballComponent.h +++ b/SpaceCadetPinball/TPinballComponent.h @@ -10,6 +10,7 @@ public: TPinballComponent(TPinballTable* table, int groupIndex, bool loadVisuals); virtual ~TPinballComponent(); virtual int Message(int message1, float message2); + virtual void port_draw(); virtual void put_scoring(int score1, int score2); virtual int get_scoring(int score1); diff --git a/SpaceCadetPinball/TPinballTable.cpp b/SpaceCadetPinball/TPinballTable.cpp index c64ebf2..a12da8b 100644 --- a/SpaceCadetPinball/TPinballTable.cpp +++ b/SpaceCadetPinball/TPinballTable.cpp @@ -262,3 +262,12 @@ TPinballComponent* TPinballTable::find_component(int groupIndex) MessageBoxA(nullptr, "Table cant find (lh):", Buffer, 0x2000u); return nullptr; } + + +void TPinballTable::port_draw() +{ + for (int index = ListP1->Count() - 1; index >= 0; index--) + { + static_cast(ListP1->Get(index))->port_draw(); + } +} \ No newline at end of file diff --git a/SpaceCadetPinball/TPinballTable.h b/SpaceCadetPinball/TPinballTable.h index 2b648b1..e78d0ad 100644 --- a/SpaceCadetPinball/TPinballTable.h +++ b/SpaceCadetPinball/TPinballTable.h @@ -14,6 +14,7 @@ public: ~TPinballTable(); TPinballComponent* find_component(LPCSTR componentName); TPinballComponent* find_component(int groupIndex); + void port_draw() override; TFlipper* FlipperL; TFlipper* FlipperR; diff --git a/SpaceCadetPinball/TTextBox.cpp b/SpaceCadetPinball/TTextBox.cpp index 4f9984b..6eb2a78 100644 --- a/SpaceCadetPinball/TTextBox.cpp +++ b/SpaceCadetPinball/TTextBox.cpp @@ -5,4 +5,12 @@ int TTextBox::Message(int a2, float a3) { return 0; -} \ No newline at end of file +} + +void TTextBox::Clear() +{ +} + +void TTextBox::Display(char* text, float time) +{ +} diff --git a/SpaceCadetPinball/TTextBox.h b/SpaceCadetPinball/TTextBox.h index bf27bcd..bd85f56 100644 --- a/SpaceCadetPinball/TTextBox.h +++ b/SpaceCadetPinball/TTextBox.h @@ -10,4 +10,6 @@ public: } int Message(int a2, float a3) override; + void Clear(); + void Display(char* text, float time); }; diff --git a/SpaceCadetPinball/maths.cpp b/SpaceCadetPinball/maths.cpp index a0b78b1..cd5f23c 100644 --- a/SpaceCadetPinball/maths.cpp +++ b/SpaceCadetPinball/maths.cpp @@ -252,3 +252,14 @@ void maths::cross(vector_type* vec1, vector_type* vec2, vector_type* dstVec) dstVec->Y = vec2->X * vec1->Z - vec1->X * vec2->Z; dstVec->Z = vec1->X * vec2->Y - vec2->X * vec1->Y; } + +float maths::magnitude(vector_type* vec) +{ + float result; + auto magSq = vec->X * vec->X + vec->Y * vec->Y + vec->Z * vec->Z; + if (magSq == 0.0) + result = 0.0; + else + result = sqrt(magSq); + return result; +} \ No newline at end of file diff --git a/SpaceCadetPinball/maths.h b/SpaceCadetPinball/maths.h index 74f6d57..b433246 100644 --- a/SpaceCadetPinball/maths.h +++ b/SpaceCadetPinball/maths.h @@ -54,4 +54,5 @@ public: static void line_init(line_type* line, float x0, float y0, float x1, float y1); static float ray_intersect_line(ray_type* ray, line_type* line); static void cross(vector_type* vec1, vector_type* vec2, vector_type* dstVec); + static float magnitude(vector_type* vec); }; diff --git a/SpaceCadetPinball/partman.cpp b/SpaceCadetPinball/partman.cpp index 1d77b4c..0070842 100644 --- a/SpaceCadetPinball/partman.cpp +++ b/SpaceCadetPinball/partman.cpp @@ -99,7 +99,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName) { auto entryType = static_cast(_lread_char(fileHandle)); entryData->EntryType = entryType; - int fieldSize = _field_size[(int)entryType]; + int fieldSize = _field_size[static_cast(entryType)]; if (fieldSize < 0) { fieldSize = _lread_long(fileHandle); @@ -165,8 +165,8 @@ void partman::unload_records(datFileStruct* datFile) { if (entry->Buffer) { - //if (HIWORD(entry->EntryType) == 1) - //gdrv_destroy_bitmap(entry->Buffer); + if (entry->EntryType == datFieldTypes::Bitmap8bit) + gdrv::destroy_bitmap((gdrv_bitmap8*)entry->Buffer); memory::free(entry->Buffer); } ++entryIndex; @@ -323,30 +323,6 @@ char* partman::field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTy return result; } - -int partman::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize) -{ - int nameSize = GetModuleFileNameA(nullptr, lpFilename, nSize); - if (!nameSize || nameSize == nSize) - return 1; - for (CHAR* i = &lpFilename[nameSize]; i > lpFilename; --i) - { - if (*i == '\\' || *i == ':') - { - i[1] = 0; - break; - } - --nameSize; - } - if (nameSize + 13 < nSize) - { - lstrcatA(lpFilename, lpString2); - return 0; - } - lstrcatA(lpFilename, "?"); - return 1; -} - char partman::_lread_char(HFILE hFile) { char Buffer = 0; diff --git a/SpaceCadetPinball/partman.h b/SpaceCadetPinball/partman.h index f54c573..77a7ac0 100644 --- a/SpaceCadetPinball/partman.h +++ b/SpaceCadetPinball/partman.h @@ -89,9 +89,6 @@ public: static int field_size(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType); static int record_labeled(datFileStruct* datFile, LPCSTR targetGroupName); static char* field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType); - - static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu); - private: static short _field_size[]; static char _lread_char(HFILE hFile); diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 298b92e..a566fef 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -1,8 +1,89 @@ #include "pch.h" #include "pb.h" + +#include "memory.h" +#include "pinball.h" +#include "proj.h" #include "render.h" +#include "loader.h" +#include "options.h" +#include "timer.h" TPinballTable* pb::MainTable = nullptr; +datFileStruct* pb::record_table = nullptr; +int pb::time_ticks = 0, pb::demo_mode = 0; + +int pb::init() +{ + float projMat[12], zMin = 0, zScaler = 0; + CHAR datFileName[300]; + CHAR dataFilePath[300]; + + ++memory::critical_allocation; + lstrcpyA(datFileName, pinball::DatFileName); + pinball::make_path_name(dataFilePath, datFileName, 300); + record_table = partman::load_records(dataFilePath); + + auto useBmpFont = 0; + pinball::get_rc_int(158, &useBmpFont); + if (useBmpFont) + score::load_msg_font("pbmsg_ft"); + + if (!record_table) + return (int)&record_table->NumberOfGroups + 1; + + auto plt = (PALETTEENTRY*)partman::field_labeled(record_table, "background", datFieldTypes::Palette); + gdrv::display_palette(plt); + + auto tableSize = (__int16*)partman::field_labeled(record_table, "table_size", datFieldTypes::ShortArray); + auto backgroundBmp = (gdrv_bitmap8*)partman::field_labeled(record_table, "background", datFieldTypes::Bitmap8bit); + auto cameraInfo = (float*)partman::field_labeled(record_table, "camera_info", datFieldTypes::FloatArray); + + if (cameraInfo) + { + memcpy(&projMat, cameraInfo, sizeof(float) * 4 * 3); + cameraInfo += 12; + + auto projCenterX = tableSize[0] * 0.5f; + auto projCenterY = tableSize[1] * 0.5f; + auto projD = cameraInfo[0]; + proj::init(projMat, projD, projCenterX, projCenterY); + zMin = cameraInfo[1]; + zScaler = cameraInfo[2]; + } + + render::init(nullptr, zMin, zScaler, tableSize[0], tableSize[1]); + gdrv::copy_bitmap( + &render::vscreen, + backgroundBmp->Width, + backgroundBmp->Height, + backgroundBmp->XPosition, + backgroundBmp->YPosition, + backgroundBmp, + 0, + 0); + + gdrv::destroy_bitmap(backgroundBmp); + loader::loadfrom(record_table); + + if (pinball::quickFlag) + mode_change(1); + else + mode_change(3); + + time_ticks = 0; + timer::init(150); + score::init(); + + MainTable = new TPinballTable(); + + //high_score_read(highscore_table, (int)&pb_state); + //v11 = *(float*)((char*)MainTable->ListP2.ListPtr->Array[0] + 154); + //ball_speed_limit = v11 * 200.0; + + --memory::critical_allocation; + return 0; +} void pb::reset_table() { @@ -21,4 +102,43 @@ void pb::firsttime_setup() void pb::paint() { render::paint(); +} + +void pb::mode_change(int mode) +{ +} + +void pb::toggle_demo() +{ + if (demo_mode) + { + demo_mode = 0; + MainTable->Message(1024, 0.0); + mode_change(2); + pinball::MissTextBox->Clear(); + auto text = pinball::get_rc_string(24, 0); + pinball::InfoTextBox->Display(text, -1.0); + } + else + { + replay_level(1); + } +} + +void pb::replay_level(int demoMode) +{ + demo_mode = demoMode; + mode_change(1); + //if (options::Options.Music) + //midi_play_pb_theme(0); + MainTable->Message(1014, static_cast(options::Options.Players)); +} + +void pb::ballset(int x, int y) +{ +} + +int pb::frame(int time) +{ + return 1; } \ No newline at end of file diff --git a/SpaceCadetPinball/pb.h b/SpaceCadetPinball/pb.h index d1d044b..31b3d62 100644 --- a/SpaceCadetPinball/pb.h +++ b/SpaceCadetPinball/pb.h @@ -1,13 +1,24 @@ #pragma once +#include "partman.h" #include "TPinballTable.h" class pb { public: + static int time_ticks; + static int ball_speed_limit; + static datFileStruct* record_table; + static TPinballTable* MainTable; + + static int init(); static void reset_table(); static void firsttime_setup(); static void paint(); -private: - static TPinballTable* MainTable; + static void mode_change(int mode); + static void toggle_demo(); + static void replay_level(int demoMode); + static void ballset(int x, int y); + static int frame(int time); +private : + static int demo_mode; }; - diff --git a/SpaceCadetPinball/pinball.cpp b/SpaceCadetPinball/pinball.cpp index d3a35e7..8c9ff66 100644 --- a/SpaceCadetPinball/pinball.cpp +++ b/SpaceCadetPinball/pinball.cpp @@ -14,8 +14,6 @@ char pinball::DatFileName[300]{}; int pinball::LeftShift = -1; int pinball::RightShift = -1; HWND pinball::hwnd_frame = nullptr; -int pinball::has_focus = 1; -int pinball::single_step = 0; char* pinball::get_rc_string(int uID, int a2) @@ -30,8 +28,8 @@ char* pinball::get_rc_string(int uID, int a2) int pinball::get_rc_int(int uID, int* dst) { - char buffer[50]; - int result = LoadStringA(pinball::hinst, uID, buffer, 255); + char buffer[50]; + int result = LoadStringA(hinst, uID, buffer, 255); if (!result) return result; *dst = atoi(buffer); @@ -106,3 +104,26 @@ HANDLE pinball::adjust_priority(int priority) } return result; } + +int pinball::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize) +{ + int nameSize = GetModuleFileNameA(nullptr, lpFilename, nSize); + if (!nameSize || nameSize == nSize) + return 1; + for (CHAR* i = &lpFilename[nameSize]; i > lpFilename; --i) + { + if (*i == '\\' || *i == ':') + { + i[1] = 0; + break; + } + --nameSize; + } + if (nameSize + 13 < nSize) + { + lstrcatA(lpFilename, lpString2); + return 0; + } + lstrcatA(lpFilename, "?"); + return 1; +} diff --git a/SpaceCadetPinball/pinball.h b/SpaceCadetPinball/pinball.h index d7cf97a..f15c00b 100644 --- a/SpaceCadetPinball/pinball.h +++ b/SpaceCadetPinball/pinball.h @@ -13,13 +13,12 @@ public: static int RightShift; static int LeftShift; static HWND hwnd_frame; - static int has_focus; - static int single_step; static char* get_rc_string(int uID, int a2); static int get_rc_int(int uID, int* dst); static void FindShiftKeys(); static HANDLE adjust_priority(int priority); + static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu); private: static char getRcBuffer[256 * 6]; static int rc_string_slot; diff --git a/SpaceCadetPinball/proj.cpp b/SpaceCadetPinball/proj.cpp new file mode 100644 index 0000000..9bd33d6 --- /dev/null +++ b/SpaceCadetPinball/proj.cpp @@ -0,0 +1,62 @@ +#include "pch.h" +#include "proj.h" + +mat4_row_major proj::matrix; +float proj::d_, proj::centerx, proj::centery; + +void proj::init(float* mat4x3, float d, float centerX, float centerY) +{ + //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; + matrix.Row3.Y = 0.0; + matrix.Row3.Z = 0.0; + matrix.Row3.W = 1.0; + + d_ = d; + centerx = centerX; + centery = centerY; +} + +void proj::matrix_vector_multiply(mat4_row_major* mat, vector_type* vec, vector_type* dstVec) +{ + const float x = vec->X, y = vec->Y, z = vec->Z; + dstVec->X = z * mat->Row0.Z + y * mat->Row0.Y + x * mat->Row0.X + mat->Row0.W; + dstVec->Y = z * mat->Row1.Z + y * mat->Row1.Y + x * mat->Row1.X + mat->Row1.W; + dstVec->Z = z * mat->Row2.Z + y * mat->Row2.Y + x * mat->Row2.X + mat->Row2.W; +} + +float proj::z_distance(vector_type* vec) +{ + vector_type dstVec{}; + matrix_vector_multiply(&matrix, vec, &dstVec); + return maths::magnitude(&dstVec); +} + +void proj::xform_to_2d(vector_type* vec, int* dst) +{ + float projCoef; + vector_type dstVec2{}; + + matrix_vector_multiply(&matrix, vec, &dstVec2); + if (0.0 == dstVec2.Z) + projCoef = 999999.88f; + else + projCoef = d_ / dstVec2.Z; + dst[0] = static_cast(dstVec2.X * projCoef + centerx); + dst[1] = static_cast(dstVec2.Y * projCoef + centery); +} + +void proj::recenter(float centerX, float centerY) +{ + centerx = centerX; + centery = centerY; +} diff --git a/SpaceCadetPinball/proj.h b/SpaceCadetPinball/proj.h new file mode 100644 index 0000000..8cb4c61 --- /dev/null +++ b/SpaceCadetPinball/proj.h @@ -0,0 +1,32 @@ +#pragma once +#include "maths.h" + +struct vector_type4 +{ + float X; + float Y; + float Z; + float W; +}; + +struct mat4_row_major +{ + vector_type4 Row0; + vector_type4 Row1; + vector_type4 Row2; + vector_type4 Row3; +}; + + +class proj +{ +public: + static void init(float* mat4x3, float d, float centerX, float centerY); + static void matrix_vector_multiply(mat4_row_major* mat, vector_type* vec, vector_type* dstVec); + static float z_distance(vector_type* vec); + static void xform_to_2d(vector_type* vec, int* dst); + static void recenter(float centerX, float centerY); +private: + static mat4_row_major matrix; + static float d_, centerx, centery; +}; diff --git a/SpaceCadetPinball/render.cpp b/SpaceCadetPinball/render.cpp index 7884145..3e098ff 100644 --- a/SpaceCadetPinball/render.cpp +++ b/SpaceCadetPinball/render.cpp @@ -31,7 +31,7 @@ void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int h vscreen.YPosition = 0; vscreen.XPosition = 0; gdrv_bitmap8* ballBmp = ball_bitmap; - while (ballBmp <= &ball_bitmap[20]) + while (ballBmp < &ball_bitmap[20]) { gdrv::create_raw_bitmap(ballBmp, 64, 64, 1); ++ballBmp; diff --git a/SpaceCadetPinball/score.cpp b/SpaceCadetPinball/score.cpp index a987dc8..e6c42ab 100644 --- a/SpaceCadetPinball/score.cpp +++ b/SpaceCadetPinball/score.cpp @@ -48,3 +48,8 @@ scoreStruct* score::dup(scoreStruct* score, int scoreIndex) memcpy(result, score, sizeof(scoreStruct)); return result; } + +HRSRC score::load_msg_font(LPCSTR lpName) +{ + return nullptr; +} diff --git a/SpaceCadetPinball/score.h b/SpaceCadetPinball/score.h index 215e37b..50e22eb 100644 --- a/SpaceCadetPinball/score.h +++ b/SpaceCadetPinball/score.h @@ -28,4 +28,5 @@ public: static int init(); static scoreStruct* create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp); static scoreStruct* dup(scoreStruct* score, int scoreIndex); + static HRSRC load_msg_font(LPCSTR lpName); }; diff --git a/SpaceCadetPinball/timer.cpp b/SpaceCadetPinball/timer.cpp new file mode 100644 index 0000000..b277614 --- /dev/null +++ b/SpaceCadetPinball/timer.cpp @@ -0,0 +1,38 @@ +#include "pch.h" +#include "timer.h" + +#include "memory.h" + +timer_struct timer::timer_struct; +int timer::setCount; + +int timer::init(int count) +{ + char* buf; // eax + int index; // edx + int* v4; // ecx + + buf = memory::allocate(20 * count); + timer_struct.buffer1 = buf; + if (!buf) + return 1; + timer_struct.target = 0; + index = count - 1; + timer_struct.count = count; + setCount = 1; + if (count - 1 > 0) + { + v4 = (int*)(buf + 12); + do + { + *v4 = (int)(v4 + 2); + v4 += 5; + --index; + } + while (index); + } + *(int*)&buf[20 * count - 8] = 0; + timer_struct.target2 = 0; + timer_struct.buffer2 = buf; + return 0; +} diff --git a/SpaceCadetPinball/timer.h b/SpaceCadetPinball/timer.h new file mode 100644 index 0000000..3c596a1 --- /dev/null +++ b/SpaceCadetPinball/timer.h @@ -0,0 +1,21 @@ +#pragma once + +struct __declspec(align(4)) timer_struct +{ + int target2; + int count; + int target; + char* buffer2; + char* buffer1; +}; + + +class timer +{ +public: + static int init(int count); + +private: + static timer_struct timer_struct; + static int setCount; +}; diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 13aec7b..3f9c6ca 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -6,8 +6,13 @@ #include "pinball.h" #include "options.h" #include "pb.h" +#include "Sound.h" int winmain::iFrostUniqueMsg, winmain::return_value = 0, winmain::bQuit = 0; +DWORD winmain::then, winmain::now; +gdrv_bitmap8 winmain::gfr_display{}; +int winmain::DispFrameRate = 1, winmain::DispGRhistory = 1, winmain::single_step = 0; +int winmain::has_focus = 1, winmain::last_mouse_x, winmain::last_mouse_y, winmain::mouse_down, winmain::no_time_loss; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { @@ -152,36 +157,114 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi }*/ pinball::adjust_priority(options::Options.PriorityAdj); - auto getTimeFunc = timeGetTime; const auto startTime = timeGetTime(); MSG wndMessage{}; while (timeGetTime() >= startTime && timeGetTime() - startTime < 2000) PeekMessageA(&wndMessage, pinball::hwnd_frame, 0, 0, 1u); + if (strstr(lpCmdLine, "-demo")) + pb::toggle_demo(); + else + pb::replay_level(0); + + DWORD someTimeCounter = 300u, prevTime = 0u; + then = timeGetTime(); while (true) { - if(false) + if (!someTimeCounter) { - auto plt = (PALETTEENTRY*)malloc(1024u); - auto gg = sizeof(LOGPALETTEx256); - auto pltPtr = &plt[10]; - for (int i1 = 0, i2 = 0; i1 < 256 - 10; ++i1, i2 += 8) + someTimeCounter = 300; + if (DispFrameRate) { - unsigned char blue = i2, redGreen = i2; - if (i2 > 255) + auto curTime = timeGetTime(); + if (prevTime) { - blue = 255; - redGreen = i1; - } + char buf[60]; + sprintf_s(buf, "Frames/sec = %02.02f", 300.0f / (static_cast(curTime - prevTime) * 0.001f)); + SetWindowTextA(pinball::hwnd_frame, buf); - *pltPtr++ = { redGreen, redGreen, blue }; + if (DispGRhistory) + { + if (!gfr_display.BmpBufPtr1) + { + auto plt = static_cast(malloc(1024u)); + auto pltPtr = &plt[10]; + for (int i1 = 0, i2 = 0; i1 < 256 - 10; ++i1, i2 += 8) + { + unsigned char blue = i2, redGreen = i2; + if (i2 > 255) + { + blue = 255; + redGreen = i1; + } + + *pltPtr++ = {redGreen, redGreen, blue}; + } + gdrv::display_palette(plt); + free(plt); + gdrv::create_bitmap(&gfr_display, 400, 15); + } + + gdrv::blit(&gfr_display, 0, 0, 0, 0, 300, 10); + gdrv::fill_bitmap(&gfr_display, 300, 10, 0, 0, 0); + } + } + prevTime = curTime; + } + else + { + prevTime = 0; } - gdrv::display_palette(plt); } - + + Sound::Idle(); if (!ProcessWindowMessages() || bQuit) break; - Sleep(8); + + if (has_focus) + { + if (mouse_down) + { + now = timeGetTime(); + if (now - then >= 2) + { + POINT Point; + GetCursorPos(&Point); + pb::ballset(last_mouse_x - Point.x, Point.y - last_mouse_y); + SetCursorPos(last_mouse_x, last_mouse_y); + } + } + if (!single_step) + { + auto curTime = timeGetTime(); + now = curTime; + if (no_time_loss) + { + then = curTime; + no_time_loss = 0; + } + + if (curTime == then) + { + Sleep(8u); + } + else if (pb::frame(curTime - then)) + { + if (gfr_display.BmpBufPtr1) + { + auto deltaT = now - then + 10; + auto fillChar = static_cast(deltaT); + if (deltaT > 236) + { + fillChar = -7; + } + gdrv::fill_bitmap(&gfr_display, 1, 10, 299u - someTimeCounter, 0, fillChar); + } + --someTimeCounter; + then = now; + } + } + } } return return_value; @@ -196,7 +279,7 @@ int winmain::ProcessWindowMessages() { MSG Msg{}; // [esp+8h] [ebp-1Ch] - if (pinball::has_focus && !pinball::single_step) + if (has_focus && !single_step) { while (PeekMessageA(&Msg, nullptr, 0, 0, 1u)) { diff --git a/SpaceCadetPinball/winmain.h b/SpaceCadetPinball/winmain.h index d0e4115..c424130 100644 --- a/SpaceCadetPinball/winmain.h +++ b/SpaceCadetPinball/winmain.h @@ -1,4 +1,5 @@ #pragma once +#include "gdrv.h" class winmain { @@ -11,7 +12,10 @@ public: static HDC _GetDC(HWND hWnd); static int a_dialog(HINSTANCE hInstance, HWND hWnd); private: - static int iFrostUniqueMsg, return_value , bQuit; + static int iFrostUniqueMsg, return_value, bQuit, DispFrameRate, DispGRhistory; + static int has_focus, single_step, mouse_down, last_mouse_x, last_mouse_y, no_time_loss; + static DWORD then, now; + static gdrv_bitmap8 gfr_display; static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); }; diff --git a/SpaceCadetPinball/zdrv.cpp b/SpaceCadetPinball/zdrv.cpp index 5463949..ae93468 100644 --- a/SpaceCadetPinball/zdrv.cpp +++ b/SpaceCadetPinball/zdrv.cpp @@ -38,7 +38,7 @@ int zdrv::destroy_zmap(zmap_header_type* zmap) void zdrv::fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, unsigned __int16 fillChar) { int fillCharInt = fillChar | (fillChar << 16); - auto zmapPtr = &zmap->ZPtr1[2 * (xOff + zmap->Stride * (zmap->Height - height - yOff))]; + auto zmapPtr = &zmap->ZPtr1[xOff + zmap->Stride * (zmap->Height - height - yOff)]; for (int y = height; width > 0 && y > 0; y--) {