diff --git a/README.md b/README.md index 1f369e8..bd1f99b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -# 3D Pinball - Space Cadet for DS(i) +# 3D Pinball - Space Cadet for DS -Port of 3D Pinball - Space Cadet to the Nintendo DS(i), based on the [decompilation project](https://github.com/k4zmu2a/SpaceCadetPinball) +Port of 3D Pinball - Space Cadet to the Nintendo DS, based on the [decompilation project](https://github.com/k4zmu2a/SpaceCadetPinball) -![image](screenshot.png) +![image](screenshot1.png) +![image](screenshot2.png) +![image](screenshot3.png) Built with the [BlocksDS SDK](https://github.com/blocksds/sdk) This port has some bugs which are currently being fixed: -* Does not run on original DS due to running out of memory while loading. It can only run in DSi mode -* Can't load all sound files due to running out of memory +* Sprites on the pinball table do not appear correctly due to being downscaled by half diff --git a/arm9/src/GroupData.h b/arm9/src/GroupData.h index 1f31292..ffcdbb4 100644 --- a/arm9/src/GroupData.h +++ b/arm9/src/GroupData.h @@ -85,8 +85,8 @@ class GroupData GroupData(int groupId); void AddEntry(EntryData* entry); void FinalizeGroup(); - const std::vector& GetEntries() const { return Entries; } - const EntryData* GetEntry(size_t index) const { return Entries[index]; } + std::vector& GetEntries() { return Entries; } + EntryData* GetEntry(size_t index) { return Entries[index]; } size_t EntryCount() const { return Entries.size(); } void ReserveEntries(size_t count) { Entries.reserve(count); } gdrv_bitmap8* GetBitmap(int resolution) const; diff --git a/arm9/src/Sound.cpp b/arm9/src/Sound.cpp index 38f9e60..a6c492a 100644 --- a/arm9/src/Sound.cpp +++ b/arm9/src/Sound.cpp @@ -1,5 +1,7 @@ #include "pch.h" +#include "loader.h" #include "Sound.h" +#include "winmain.h" #define DR_WAV_IMPLEMENTATION #include @@ -48,14 +50,12 @@ void Sound::PlaySound(s16* wavePtr, int time, int size, int samplerate) } } -s16* Sound::LoadWaveFile(const std::string& lpName) +s16* Sound::LoadWaveFile(const std::string& lpName, int* outSize, int* outSampleRate, int* outChannels) { drwav wavfp; if (!drwav_init_file(&wavfp, lpName.c_str(), NULL)) - { return 0; - } s16* pSampleData = new s16[(u32)wavfp.totalPCMFrameCount * wavfp.channels]; if (pSampleData == 0) @@ -63,6 +63,7 @@ s16* Sound::LoadWaveFile(const std::string& lpName) drwav_uninit(&wavfp); return 0; } + u32 totalRead = drwav_read_pcm_frames(&wavfp, wavfp.totalPCMFrameCount, pSampleData); if (!totalRead) { @@ -79,6 +80,10 @@ s16* Sound::LoadWaveFile(const std::string& lpName) pSampleData = _8bitdata; } + *outSize = wavfp.totalPCMFrameCount * wavfp.channels; + *outSampleRate = wavfp.sampleRate; + *outChannels = wavfp.channels; + drwav_uninit(&wavfp); return pSampleData; } diff --git a/arm9/src/Sound.h b/arm9/src/Sound.h index de64143..bb00402 100644 --- a/arm9/src/Sound.h +++ b/arm9/src/Sound.h @@ -9,7 +9,7 @@ class Sound static void Deactivate(); static void Close(); static void PlaySound(s16* wavePtr, int time, int size, int samplerate); - static s16* LoadWaveFile(const std::string& lpName); + static s16* LoadWaveFile(const std::string& lpName, int* outSize, int* outSampleRate, int* outChannels); static void FreeSound(s16* wave); static void SetChannels(int channels); private: diff --git a/arm9/src/TBall.cpp b/arm9/src/TBall.cpp index 367f9ce..f5b23a9 100644 --- a/arm9/src/TBall.cpp +++ b/arm9/src/TBall.cpp @@ -81,8 +81,8 @@ void TBall::Repaint() RenderSprite, bmp, zDepth, - pos2D[0] - bmp->Width / 2, - pos2D[1] - bmp->Height / 2); + pos2D[0]/2 - bmp->Width / 2, + pos2D[1]/2 - bmp->Height / 2); } void TBall::not_again(TEdgeSegment* edge) diff --git a/arm9/src/TTextBox.cpp b/arm9/src/TTextBox.cpp index 093a7fb..d732578 100644 --- a/arm9/src/TTextBox.cpp +++ b/arm9/src/TTextBox.cpp @@ -26,10 +26,10 @@ TTextBox::TTextBox(TPinballTable* table, int groupIndex) : TPinballComponent(tab /*Full tilt: text box dimensions index is offset by resolution*/ int arrLength; auto dimensions = loader::query_iattribute(groupIndex + fullscrn::GetResolution(), 1500, &arrLength); - OffsetX = dimensions[0]; - OffsetY = dimensions[1]; - Width = dimensions[2]; - Height = dimensions[3]; + OffsetX = dimensions[0]/2; + OffsetY = dimensions[1]/2; + Width = dimensions[2]/2; + Height = dimensions[3]/2; } } diff --git a/arm9/src/gdrv.cpp b/arm9/src/gdrv.cpp index 94f93fe..445d37e 100644 --- a/arm9/src/gdrv.cpp +++ b/arm9/src/gdrv.cpp @@ -101,9 +101,9 @@ void gdrv_bitmap8::ScaleIndexed(float scaleX, float scaleY) Stride = IndexedStride = Width = newWidht; Height = newHeight; - delete IndexedBmpPtr; + delete[] IndexedBmpPtr; IndexedBmpPtr = newIndBuf; - delete BmpBufPtr1; + delete[] BmpBufPtr1; BmpBufPtr1 = new ColorRgba[Stride * Height]; } diff --git a/arm9/src/loader.cpp b/arm9/src/loader.cpp index 319a054..4862e84 100644 --- a/arm9/src/loader.cpp +++ b/arm9/src/loader.cpp @@ -136,8 +136,6 @@ int loader::get_sound_id(int groupIndex) if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr) { - WaveHeader wavHeader{}; - int soundGroupId = sound_list[soundIndex].GroupIndex; sound_list[soundIndex].Duration = 0.0; if (soundGroupId > 0 && !pinball::quickFlag) @@ -159,19 +157,17 @@ int loader::get_sound_id(int groupIndex) } auto filePath = pinball::make_path_name(fileName); - auto file = fopen(filePath.c_str(), "rb"); - if (file) + + int data_size, sample_rate, channels; + sound_list[soundIndex].WavePtr = Sound::LoadWaveFile(filePath, &data_size, &sample_rate, &channels); + if (sound_list[soundIndex].WavePtr) { - fread(&wavHeader, 1, sizeof wavHeader, file); - fclose(file); - } + sound_list[soundIndex].DurationSamples = data_size; + sound_list[soundIndex].SampleRate = sample_rate; - auto sampleCount = wavHeader.data_size / (wavHeader.channels * (wavHeader.bits_per_sample / 8.0)); - sound_list[soundIndex].Duration = static_cast(sampleCount / wavHeader.sample_rate); - sound_list[soundIndex].DurationSamples = wavHeader.data_size; - sound_list[soundIndex].SampleRate = wavHeader.sample_rate; - sound_list[soundIndex].WavePtr = (sound_list[soundIndex].Duration < 2.f) ? Sound::LoadWaveFile(filePath) : 0; - //sound_list[soundIndex].WavePtr = 0; + auto sampleCount = data_size / (channels * (16 / 8.0)); + sound_list[soundIndex].Duration = static_cast(sampleCount / sample_rate); + } } } } diff --git a/arm9/src/ndsfb_graphics.cpp b/arm9/src/ndsfb_graphics.cpp index 22fa730..eda275e 100644 --- a/arm9/src/ndsfb_graphics.cpp +++ b/arm9/src/ndsfb_graphics.cpp @@ -120,7 +120,7 @@ void ndsfb_graphics::UpdateFull(bool sub) { for (int x = 0; x < 360; x++) { - int smallX = f32toint( mulf32( divf32( inttof32(x), inttof32(192) ), inttof32(360) ) ); + int smallX = f32toint( mulf32( divf32( inttof32(x), inttof32(192) ), inttof32(360/2) ) ); int smallY = f32toint( mulf32( divf32( inttof32(y), inttof32(224) ), inttof32(render::vscreen->Height) ) ); Rgba color = render::vscreen->BmpBufPtr1[smallY * render::vscreen->Width + smallX].rgba; @@ -136,7 +136,7 @@ void ndsfb_graphics::UpdateFull(bool sub) { for (int x = 328; x < 328+192; x++) { - int smallX = f32toint( mulf32( divf32( inttof32(x), inttof32(192) ), inttof32(render::vscreen->Width-380) ) ); + int smallX = f32toint( mulf32( divf32( inttof32(x), inttof32(192) ), inttof32(render::vscreen->Width-380/2) ) ); int smallY = f32toint( mulf32( divf32( inttof32(y), inttof32(256) ), inttof32(render::vscreen->Height) ) ); u16* vram_ptr = bgGetGfxPtr(bgSubID); @@ -205,17 +205,17 @@ void ndsfb_graphics::UpdateRotatedMode() for (int x = dirty.XPosition; x < dirty.XPosition+dirty.Width; x++) { int smallX, smallY, ind; - u16* vram_ptr = (dirty.XPosition < 370) ? VRAM_A : bgGetGfxPtr(bgSubID); + u16* vram_ptr = (dirty.XPosition < 370/2) ? VRAM_A : bgGetGfxPtr(bgSubID); if (vram_ptr == VRAM_A) { - smallX = f32toint( ceilf32(mulf32( divf32( inttof32(x), inttof32(360) ), inttof32(192) ) ) ); + smallX = f32toint( ceilf32(mulf32( divf32( inttof32(x), inttof32(360/2) ), inttof32(192) ) ) ); smallY = f32toint( ceilf32(mulf32( divf32( inttof32(y), inttof32(render::vscreen->Height) ), inttof32(224) ) ) ); ind = tableStartPos + ((smallX-3) * 256 + (256-1-smallY)); } else { - smallX = f32toint( ceilf32(mulf32( divf32( inttof32(x), inttof32(render::vscreen->Width-380) ), inttof32(192) ) ) ); + smallX = f32toint( ceilf32(mulf32( divf32( inttof32(x), inttof32(render::vscreen->Width-380/2) ), inttof32(192) ) ) ); smallY = f32toint( ceilf32(mulf32( divf32( inttof32(y), inttof32(render::vscreen->Height) ), inttof32(256) ) ) ); ind = (smallX-328) * 256 + (256-1-smallY); } diff --git a/arm9/src/partman.cpp b/arm9/src/partman.cpp index 1c4f881..89f7c3a 100644 --- a/arm9/src/partman.cpp +++ b/arm9/src/partman.cpp @@ -129,6 +129,17 @@ DatFile* partman::load_records(LPCSTR lpFileName, bool fullTiltMode) fclose(fileHandle); if (datFile->Groups.size() == header.NumberOfGroups) { + for (auto groupData : datFile->Groups) + { + for (auto entryData : groupData->GetEntries()) + { + if (entryData->EntryType != FieldTypes::Bitmap8bit) continue; + gdrv_bitmap8* bmp = reinterpret_cast(entryData->Buffer); + bmp->ScaleIndexed(0.5f, 0.5f); + bmp->XPosition /= 2; + bmp->YPosition /= 2; + } + } datFile->Finalize(); return datFile; } diff --git a/arm9/src/pb.cpp b/arm9/src/pb.cpp index c66a577..122ee9c 100644 --- a/arm9/src/pb.cpp +++ b/arm9/src/pb.cpp @@ -69,15 +69,15 @@ int pb::init() memcpy(&projMat, cameraInfo, sizeof(float) * 4 * 3); cameraInfo += 12; - auto projCenterX = resInfo->TableWidth * 0.5f; - auto projCenterY = resInfo->TableHeight * 0.5f; + auto projCenterX = resInfo->TableWidth * 0.25f; + auto projCenterY = resInfo->TableHeight * 0.25f; auto projD = cameraInfo[0]; proj::init(projMat, projD, projCenterX, projCenterY); zMin = cameraInfo[1]; zScaler = cameraInfo[2]; } - render::init(nullptr, zMin, zScaler, resInfo->TableWidth, resInfo->TableHeight); + render::init(nullptr, zMin, zScaler, resInfo->TableWidth*0.5f, resInfo->TableHeight*0.5f); gdrv::copy_bitmap( render::vscreen, backgroundBmp->Width, diff --git a/arm9/src/render.cpp b/arm9/src/render.cpp index 28df178..b4eb35d 100644 --- a/arm9/src/render.cpp +++ b/arm9/src/render.cpp @@ -33,7 +33,7 @@ void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int h vscreen->XPosition = 0; for (auto& ballBmp : ball_bitmap) { - ballBmp = new gdrv_bitmap8(64, 64, false); + ballBmp = new gdrv_bitmap8(32, 32, false); } background_bitmap = bmp; @@ -392,6 +392,12 @@ void render::unpaint_balls() curBall->DirtyRectPrev.Width, curBall->DirtyRectPrev.Height, }); + dirty_regions.push_back({ + curBall->DirtyRect.XPosition, + curBall->DirtyRect.YPosition, + curBall->DirtyRect.Width, + curBall->DirtyRect.Height, + }); } curBall->DirtyRectPrev = curBall->DirtyRect; diff --git a/arm9/src/score.cpp b/arm9/src/score.cpp index 08e2d90..b1921bd 100644 --- a/arm9/src/score.cpp +++ b/arm9/src/score.cpp @@ -33,10 +33,10 @@ scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp) return nullptr; } int groupIndex = *dimensions++; - score->OffsetX = *dimensions++; - score->OffsetY = *dimensions++; - score->Width = *dimensions++; - score->Height = *dimensions; + score->OffsetX = *dimensions++/2; + score->OffsetY = *dimensions++/2; + score->Width = *dimensions++/2; + score->Height = *dimensions/2; for (int index = 0; index < 10; index++) { @@ -65,7 +65,7 @@ void score::load_msg_font(LPCSTR lpName) // FT font has multiple resolutions auto gapArray = reinterpret_cast(pb::record_table->field(groupIndex, FieldTypes::ShortArray)); if (gapArray) - msg_fontp->GapWidth = gapArray[fullscrn::GetResolution()]; + msg_fontp->GapWidth = gapArray[fullscrn::GetResolution()]/2; else msg_fontp->GapWidth = 0; @@ -74,9 +74,12 @@ void score::load_msg_font(LPCSTR lpName) auto bmp = pb::record_table->GetBitmap(groupIndex); if (!bmp) break; + msg_fontp->Chars[charIndex] = bmp; + bmp->ScaleIndexed(0.5f, 0.5f); if (!msg_fontp->Height) msg_fontp->Height = bmp->Height; - msg_fontp->Chars[charIndex] = bmp; + //bmp->XPosition /= 2; + //bmp->YPosition /= 2; } } diff --git a/arm9/src/winmain.cpp b/arm9/src/winmain.cpp index 1c00f11..6fbc8ac 100644 --- a/arm9/src/winmain.cpp +++ b/arm9/src/winmain.cpp @@ -109,16 +109,16 @@ int winmain::WinMain(LPCSTR lpCmdLine) pb::reset_table(); pb::firsttime_setup(); - pb::replay_level(0); ndsfb_graphics::AskRotationMode(); ndsfb_graphics::SetSubScreenConsole(false); - ndsfb_graphics::UpdateFull(); nds_input::Initialize(); nds_input::ScanPads(); + pb::replay_level(0); + // Begin main loop bQuit = false; diff --git a/screenshot.png b/screenshot.png deleted file mode 100644 index efe8bad..0000000 Binary files a/screenshot.png and /dev/null differ diff --git a/screenshot1.png b/screenshot1.png new file mode 100644 index 0000000..e9918e7 Binary files /dev/null and b/screenshot1.png differ diff --git a/screenshot2.png b/screenshot2.png new file mode 100644 index 0000000..78218a9 Binary files /dev/null and b/screenshot2.png differ diff --git a/screenshot3.png b/screenshot3.png new file mode 100644 index 0000000..adb376a Binary files /dev/null and b/screenshot3.png differ