diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a65ae81..7d688877 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,8 @@ jobs: sudo apt-get update sudo apt-get install -y \ libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ - libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev + libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \ + libasound2-dev - name: Install macOS dependencies (brew) if: ${{ matrix.brew }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 92b31a20..0e4c6cc9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,7 +45,8 @@ jobs: sudo apt-get update sudo apt-get install -y \ libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ - libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev + libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \ + libasound2-dev - name: Install macOS dependencies (brew) if: ${{ matrix.brew }} diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 9c8a1152..1e153bd9 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -30,16 +30,6 @@ target_compile_definitions(miniaudio PUBLIC MA_NO_RUNTIME_LINKING ) - - -if(PSP) - target_compile_definitions(miniaudio PUBLIC - MA_NO_RUNTIME_LINKING - ) -endif() - - - if(DOWNLOAD_DEPENDENCIES) include(FetchContent) FetchContent_Declare( diff --git a/CMakeLists.txt b/CMakeLists.txt index ed0e85d1..91cd9fd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ else() endif() find_program(SDL_SHADERCROSS_BIN NAMES "shadercross") -find_package(Python3 COMPONENTS Interpreter) +find_package(Python3 3.11 COMPONENTS Interpreter) option(ISLE_BUILD_APP "Build isle application" ON) option(ISLE_ASAN "Enable Address Sanitizer" OFF) @@ -51,6 +51,8 @@ message(STATUS "Internal miniwin: ${ISLE_MINIWIN}") message(STATUS "Isle debugging: ${ISLE_DEBUG}") message(STATUS "Compile shaders: ${ISLE_COMPILE_SHADERS}") +add_library(Isle::iniparser INTERFACE IMPORTED) + if (DOWNLOAD_DEPENDENCIES) # FetchContent downloads and configures dependencies include(FetchContent) @@ -77,6 +79,7 @@ if (DOWNLOAD_DEPENDENCIES) set(BUILD_DOCS off) set(BUILD_SHARED_LIBS off) FetchContent_MakeAvailable(iniparser) + target_link_libraries(Isle::iniparser INTERFACE iniparser-static) endblock() else() # find_package looks for already-installed system packages. @@ -84,10 +87,8 @@ else() # to add search paths. find_package(SDL3 CONFIG REQUIRED) - find_package(iniparser CONFIG COMPONENTS static) - if (NOT TARGET iniparser-static) - find_package(iniparser REQUIRED MODULE COMPONENTS static) - endif() + find_package(iniparser REQUIRED CONFIG COMPONENTS shared) + target_link_libraries(Isle::iniparser INTERFACE iniparser-shared) endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -493,7 +494,7 @@ if (ISLE_BUILD_APP) target_link_libraries(isle PRIVATE $<$:DirectX5::DirectX5>) # Link SDL and iniparser - target_link_libraries(isle PRIVATE SDL3::SDL3 iniparser-static) + target_link_libraries(isle PRIVATE SDL3::SDL3 Isle::iniparser) # Allow unconditional include of miniwin/miniwindevice.h target_link_libraries(isle PRIVATE miniwin-headers) @@ -559,7 +560,7 @@ if (ISLE_BUILD_CONFIG) target_link_libraries(config PRIVATE DirectX5::DirectX5) endif() target_compile_definitions(config PRIVATE DIRECT3D_VERSION=0x500) - target_link_libraries(config PRIVATE SDL3::SDL3 iniparser-static) + target_link_libraries(config PRIVATE SDL3::SDL3 Isle::iniparser) if (NOT ISLE_MINIWIN) target_link_libraries(config PRIVATE ddraw dxguid) endif() @@ -672,4 +673,3 @@ else() set(CPACK_GENERATOR TGZ) endif() include(CPack) - diff --git a/ISLE/emscripten/libwasmfs_fetch.js.patch b/ISLE/emscripten/libwasmfs_fetch.js.patch index 6c598e3f..eb16caf0 100644 --- a/ISLE/emscripten/libwasmfs_fetch.js.patch +++ b/ISLE/emscripten/libwasmfs_fetch.js.patch @@ -1,5 +1,5 @@ diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js -index e8c9f7e21..5c3a3dfbe 100644 +index e8c9f7e21..1c0eea957 100644 --- a/src/lib/libwasmfs_fetch.js +++ b/src/lib/libwasmfs_fetch.js @@ -38,36 +38,7 @@ addToLibrary({ @@ -49,7 +49,7 @@ index e8c9f7e21..5c3a3dfbe 100644 allPresent = false; break; } -@@ -90,16 +61,36 @@ addToLibrary({ +@@ -90,16 +61,37 @@ addToLibrary({ // one request for all the chunks we need, rather than one // request per chunk. var start = firstChunk * chunkSize; @@ -66,8 +66,10 @@ index e8c9f7e21..5c3a3dfbe 100644 if (!response.ok) { throw response; } +- var bytes = await response['bytes'](); + - var bytes = await response['bytes'](); ++ const buffer = await response.arrayBuffer(); ++ const bytes = new Uint8Array(buffer); + if (!(file in wasmFS$JSMemoryRanges)) { + var size = Math.max( + parseInt(response.headers.get('Content-Range').split('/')[1], 10), @@ -87,7 +89,7 @@ index e8c9f7e21..5c3a3dfbe 100644 return Promise.resolve(); } -@@ -164,6 +155,21 @@ addToLibrary({ +@@ -164,6 +156,21 @@ addToLibrary({ return wasmFS$JSMemoryRanges[file].size; }, }; diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index ae8760ff..b097eb3b 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -109,7 +109,7 @@ IsleApp::IsleApp() m_drawCursor = FALSE; m_use3dSound = TRUE; m_useMusic = TRUE; - m_useJoystick = FALSE; + m_useJoystick = TRUE; m_joystickIndex = 0; m_wideViewAngle = TRUE; m_islandQuality = 2; @@ -394,6 +394,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) #endif switch (event->type) { + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: @@ -433,8 +434,14 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) } SDL_Keycode keyCode = event->key.key; - if (InputManager()) { - InputManager()->QueueEvent(c_notificationKeyPress, keyCode, 0, 0, keyCode); + + if (event->key.mod == SDL_KMOD_LALT && keyCode == SDLK_RETURN) { + SDL_SetWindowFullscreen(window, !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)); + } + else { + if (InputManager()) { + InputManager()->QueueEvent(c_notificationKeyPress, keyCode, 0, 0, keyCode); + } } break; } @@ -652,6 +659,7 @@ MxResult IsleApp::SetupWindow() SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE); #ifdef MINIWIN SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); #endif window = SDL_CreateWindowWithProperties(props); @@ -788,6 +796,7 @@ bool IsleApp::LoadConfig() return false; } + char buf[32]; dict = iniparser_load(iniConfig); iniparser_set(dict, "isle", NULL); @@ -804,12 +813,11 @@ bool IsleApp::LoadConfig() iniparser_set(dict, "isle:Music", m_useMusic ? "true" : "false"); iniparser_set(dict, "isle:UseJoystick", m_useJoystick ? "true" : "false"); - iniparser_set(dict, "isle:JoystickIndex", m_joystickIndex ? "true" : "false"); + iniparser_set(dict, "isle:JoystickIndex", SDL_itoa(m_joystickIndex, buf, 10)); iniparser_set(dict, "isle:Draw Cursor", m_drawCursor ? "true" : "false"); iniparser_set(dict, "isle:Back Buffers in Video RAM", "-1"); - char buf[32]; iniparser_set(dict, "isle:Island Quality", SDL_itoa(m_islandQuality, buf, 10)); iniparser_set(dict, "isle:Island Texture", SDL_itoa(m_islandTexture, buf, 10)); SDL_snprintf(buf, sizeof(buf), "%f", m_maxLod); @@ -1056,11 +1064,22 @@ MxResult IsleApp::VerifyFilesystem() Emscripten_SetupFilesystem(); #else for (const char* file : g_files) { - MxString path(&file[1]); - path.MapPathToFilesystem(); + const char* searchPaths[] = {".", m_hdPath, m_cdPath}; + bool found = false; - if (!SDL_GetPathInfo(path.GetData(), NULL)) { - char buffer[512]; + for (const char* base : searchPaths) { + MxString path(base); + path += file; + path.MapPathToFilesystem(); + + if (SDL_GetPathInfo(path.GetData(), NULL)) { + found = true; + break; + } + } + + if (!found) { + char buffer[1024]; SDL_snprintf( buffer, sizeof(buffer), diff --git a/ISLE/isledebug.cpp b/ISLE/isledebug.cpp index c89ed3fa..a8950fa3 100644 --- a/ISLE/isledebug.cpp +++ b/ISLE/isledebug.cpp @@ -183,7 +183,11 @@ void IsleDebug_Init() } g_videoPalette = SDL_CreateTexture(g_debugRenderer, SDL_PIXELFORMAT_RGBX32, SDL_TEXTUREACCESS_STREAMING, 16, 16); - SDL_SetTextureScaleMode(g_videoPalette, SDL_SCALEMODE_LINEAR); +#if SDL_VERSION_ATLEAST(3, 3, 0) + SDL_SetTextureScaleMode(g_videoPalette, SDL_SCALEMODE_PIXELART); +#else + SDL_SetTextureScaleMode(g_videoPalette, SDL_SCALEMODE_NEAREST); +#endif if (!ImGui_ImplSDLRenderer3_Init(g_debugRenderer)) { g_debugEnabled = false; break; @@ -288,9 +292,9 @@ void IsleDebug_Render() ImGui::Text("Actor Name: %s", gameState->GetActorName()); ImGui::Text("Current act: %d", gameState->GetCurrentAct()); ImGui::Text("Loaded act: %d", gameState->GetLoadedAct()); - ImGui::Text("Previous area: %d", gameState->GetPreviousArea()); - ImGui::Text("Unknown 0x42c: %d", gameState->GetUnknown0x42c()); - ImGui::Value("Player count", gameState->GetPlayerCount()); + ImGui::Text("Previous area: %d", gameState->m_previousArea); + ImGui::Text("Unknown 0x42c: %d", gameState->m_unk0x42c); + ImGui::Value("Player count", gameState->m_playerCount); ImGui::TreePop(); } if (ImGui::TreeNode("Renderer")) { @@ -305,7 +309,7 @@ void IsleDebug_Render() if (ImGui::TreeNode("Sound Manager")) { LegoSoundManager* soundManager = lego->GetSoundManager(); Sint32 oldVolume = soundManager->GetVolume(); - int volume = oldVolume; + Sint32 volume = oldVolume; ImGui::SliderInt("volume", &volume, 0, 100); if (volume != oldVolume) { soundManager->SetVolume(volume); diff --git a/LEGO1/lego/legoomni/include/legogamestate.h b/LEGO1/lego/legoomni/include/legogamestate.h index d65d3a55..28e5b47d 100644 --- a/LEGO1/lego/legoomni/include/legogamestate.h +++ b/LEGO1/lego/legoomni/include/legogamestate.h @@ -157,7 +157,18 @@ class LegoGameState { MxS16 m_totalScore; // 0x00 MxU8 m_scores[5][5]; // 0x02 Username m_name; // 0x1c - MxS16 m_unk0x2a; // 0x2a + MxS16 m_playerId; // 0x2a + + ScoreItem& operator=(const ScoreItem& p_other) + { + // MSVC auto-generates an operator=, but LegoGameState::WriteScoreHistory() has a much better match + // with a manual implementation. + m_totalScore = p_other.m_totalScore; + memcpy(m_scores, p_other.m_scores, sizeof(m_scores)); + m_name = p_other.m_name; + m_playerId = p_other.m_playerId; + return *this; + } }; // SIZE 0x372 @@ -165,7 +176,7 @@ class LegoGameState { History(); void WriteScoreHistory(); MxResult Serialize(LegoStorage* p_storage); - ScoreItem* FUN_1003cc90(Username* p_player, MxS16 p_unk0x24, MxS32& p_unk0x2c); + ScoreItem* FindPlayerInScoreHistory(Username* p_player, MxS16 p_unk0x24, MxS32& p_unk0x2c); // FUNCTION: BETA10 0x1002c2b0 MxS16 GetCount() { return m_count; } @@ -174,9 +185,12 @@ class LegoGameState { // FUNCTION: BETA10 0x1002c540 ScoreItem* GetScore(MxS32 p_index) { return p_index >= m_count ? NULL : &m_scores[p_index]; } - MxS16 m_count; // 0x00 - ScoreItem m_scores[20]; // 0x02 - MxS16 m_unk0x372; // 0x372 + MxS16 m_count; // 0x00 +#ifdef BETA10 + MxS16 m_indices[20]; // 0x02 +#endif + ScoreItem m_scores[20]; // 0x02 (0x22 for BETA10) + MxS16 m_nextPlayerId; // 0x372 (0x392 for BETA10) }; LEGO1_EXPORT LegoGameState(); @@ -216,14 +230,8 @@ class LegoGameState { Act GetCurrentAct() { return m_currentAct; } Act GetLoadedAct() { return m_loadedAct; } - Area GetPreviousArea() { return m_previousArea; } - Area GetUnknown0x42c() { return m_unk0x42c; } - void SetDirty(MxBool p_isDirty) { m_isDirty = p_isDirty; } - void SetPreviousArea(Area p_previousArea) { m_previousArea = p_previousArea; } void SetActorId(MxU8 p_actorId) { m_actorId = p_actorId; } - Username* GetPlayersIndex(MxS32 p_index) { return &m_players[p_index]; } - MxS16 GetPlayerCount() { return m_playerCount; } LegoBackgroundColor* GetBackgroundColor() { return m_backgroundColor; } void SetCurrentAct(Act p_currentAct); @@ -249,14 +257,11 @@ class LegoGameState { LegoBackgroundColor* m_tempBackgroundColor; // 0x1c LegoFullScreenMovie* m_fullScreenMovie; // 0x20 - // TODO: Most likely getters/setters are not used according to BETA for the following members: - public: - MxS16 m_unk0x24; // 0x24 + MxS16 m_currentPlayerId; // 0x24 MxS16 m_playerCount; // 0x26 Username m_players[9]; // 0x28 History m_history; // 0xa6 - undefined2 m_unk0x41a; // 0x41a JukeboxScript::Script m_jukeboxMusic; // 0x41c MxBool m_isDirty; // 0x420 Area m_currentArea; // 0x424 diff --git a/LEGO1/lego/legoomni/include/legovideomanager.h b/LEGO1/lego/legoomni/include/legovideomanager.h index e28c581d..6c12d863 100644 --- a/LEGO1/lego/legoomni/include/legovideomanager.h +++ b/LEGO1/lego/legoomni/include/legovideomanager.h @@ -78,6 +78,9 @@ class LegoVideoManager : public MxVideoManager { inline void DrawCursor(); + void DrawDigitToBuffer32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, int p_digit, uint32_t p_color); + void DrawTextToSurface32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, const char* p_text, uint32_t p_color); + Tgl::Renderer* m_renderer; // 0x64 Lego3DManager* m_3dManager; // 0x68 LegoROI* m_viewROI; // 0x6c diff --git a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp index 2d3d688a..a76987dd 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuildpresenter.cpp @@ -579,10 +579,10 @@ void LegoCarBuildAnimPresenter::RotateAroundYAxis(MxFloat p_angle) newRotation.EqualsHamiltonProduct(currentRotation, additionalRotation); if (newRotation[3] < 0.9999) { - rotationKey->FUN_100739a0(TRUE); + rotationKey->SetActive(TRUE); } else { - rotationKey->FUN_100739a0(FALSE); + rotationKey->SetActive(FALSE); } m_platformAnimNodeData->GetRotationKey(0)->SetX(newRotation[0]); diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index 170842ea..93665ee3 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -290,7 +290,7 @@ MxResult LegoGameState::Save(MxULong p_slot) } storage.WriteS32(0x1000c); - storage.WriteS16(m_unk0x24); + storage.WriteS16(m_currentPlayerId); storage.WriteU16(m_currentAct); storage.WriteU8(m_actorId); @@ -386,7 +386,7 @@ MxResult LegoGameState::Load(MxULong p_slot) goto done; } - storage.ReadS16(m_unk0x24); + storage.ReadS16(m_currentPlayerId); storage.ReadS16(actArea); SetCurrentAct((Act) actArea); @@ -630,8 +630,8 @@ MxResult LegoGameState::AddPlayer(Username& p_player) m_playerCount++; m_players[0].Set(p_player); - m_unk0x24 = m_history.m_unk0x372; - m_history.m_unk0x372 = m_unk0x24 + 1; + m_currentPlayerId = m_history.m_nextPlayerId; + m_history.m_nextPlayerId = m_currentPlayerId + 1; m_history.WriteScoreHistory(); SetCurrentAct(e_act1); @@ -1422,7 +1422,7 @@ MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage) } m_name.Serialize(p_storage); - p_storage->ReadS16(m_unk0x2a); + p_storage->ReadS16(m_playerId); } else if (p_storage->IsWriteMode()) { p_storage->WriteS16(m_totalScore); @@ -1434,7 +1434,7 @@ MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage) } m_name.Serialize(p_storage); - p_storage->WriteS16(m_unk0x2a); + p_storage->WriteS16(m_playerId); } return SUCCESS; @@ -1445,7 +1445,7 @@ MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage) LegoGameState::History::History() { m_count = 0; - m_unk0x372 = 0; + m_nextPlayerId = 0; } // FUNCTION: LEGO1 0x1003c870 @@ -1456,83 +1456,128 @@ void LegoGameState::History::WriteScoreHistory() MxU8 scores[5][5]; InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState"); - if (state->m_letters[0]) { - JetskiRaceState* jetskiRaceState = (JetskiRaceState*) GameState()->GetState("JetskiRaceState"); - CarRaceState* carRaceState = (CarRaceState*) GameState()->GetState("CarRaceState"); - TowTrackMissionState* towTrackMissionState = - (TowTrackMissionState*) GameState()->GetState("TowTrackMissionState"); - PizzaMissionState* pizzaMissionState = (PizzaMissionState*) GameState()->GetState("PizzaMissionState"); - AmbulanceMissionState* ambulanceMissionState = - (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState"); - for (MxS32 actor = 1; actor <= 5; actor++) { - scores[0][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0; - totalScore += scores[0][actor - 1]; + if (!state->m_letters[0]) { + return; + } - scores[1][actor - 1] = jetskiRaceState ? jetskiRaceState->GetState(actor)->GetHighScore() : 0; - totalScore += scores[1][actor - 1]; + JetskiRaceState* jetskiRaceState = (JetskiRaceState*) GameState()->GetState("JetskiRaceState"); + CarRaceState* carRaceState = (CarRaceState*) GameState()->GetState("CarRaceState"); + TowTrackMissionState* towTrackMissionState = (TowTrackMissionState*) GameState()->GetState("TowTrackMissionState"); + PizzaMissionState* pizzaMissionState = (PizzaMissionState*) GameState()->GetState("PizzaMissionState"); + AmbulanceMissionState* ambulanceMissionState = + (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState"); - scores[2][actor - 1] = pizzaMissionState ? pizzaMissionState->GetHighScore(actor) : 0; - totalScore += scores[2][actor - 1]; + for (MxS32 actor = 1; actor <= 5; actor++) { + scores[0][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0; + totalScore += scores[0][actor - 1]; - scores[3][actor - 1] = towTrackMissionState ? towTrackMissionState->GetHighScore(actor) : 0; - totalScore += scores[3][actor - 1]; +#ifdef BETA10 + // likely a bug in BETA10 + scores[1][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0; +#else + scores[1][actor - 1] = jetskiRaceState ? jetskiRaceState->GetState(actor)->GetHighScore() : 0; +#endif + totalScore += scores[1][actor - 1]; - scores[4][actor - 1] = ambulanceMissionState ? ambulanceMissionState->GetHighScore(actor) : 0; - totalScore += scores[4][actor - 1]; - } + scores[2][actor - 1] = pizzaMissionState ? pizzaMissionState->GetHighScore(actor) : 0; + totalScore += scores[2][actor - 1]; - MxS32 unk0x2c; - ScoreItem* p_scorehist = FUN_1003cc90(&GameState()->m_players[0], GameState()->m_unk0x24, unk0x2c); + scores[3][actor - 1] = towTrackMissionState ? towTrackMissionState->GetHighScore(actor) : 0; + totalScore += scores[3][actor - 1]; - if (p_scorehist != NULL) { - p_scorehist->m_totalScore = totalScore; - memcpy(p_scorehist->m_scores, scores, sizeof(p_scorehist->m_scores)); - } - else { - if (m_count < (MxS16) sizeOfArray(m_scores)) { - m_scores[m_count].m_totalScore = totalScore; - memcpy(m_scores[m_count].m_scores, scores, sizeof(m_scores[m_count].m_scores)); - m_scores[m_count].m_name = GameState()->m_players[0]; - m_scores[m_count].m_unk0x2a = GameState()->m_unk0x24; - m_count++; - } - else if (m_scores[19].m_totalScore <= totalScore) { - m_scores[19].m_totalScore = totalScore; - memcpy(m_scores[19].m_scores, scores, sizeof(m_scores[19].m_scores)); - m_scores[19].m_name = GameState()->m_players[0]; - m_scores[19].m_unk0x2a = GameState()->m_unk0x24; + scores[4][actor - 1] = ambulanceMissionState ? ambulanceMissionState->GetHighScore(actor) : 0; + totalScore += scores[4][actor - 1]; + } + + MxS32 playerScoreHistoryIndex; + ScoreItem* p_scorehist = + FindPlayerInScoreHistory(GameState()->m_players, GameState()->m_currentPlayerId, playerScoreHistoryIndex); + +#ifdef BETA10 + if (!p_scorehist) { + MxS32 playerScoreRank; + // LINE: BETA10 0x100870ee + for (playerScoreRank = 0; playerScoreRank < m_count; playerScoreRank++) { + if (totalScore > m_scores[m_indices[playerScoreRank]].m_totalScore) { + break; } } + // LINE: BETA10 0x1008713f + if (playerScoreRank < m_count) { + if (m_count < 20) { + playerScoreHistoryIndex = m_count++; + } + else { + playerScoreHistoryIndex = m_indices[19]; + } - MxU8 tmpScores[5][5]; - Username tmpPlayer; - MxS16 tmpUnk0x2a; + MxS32 max = m_count - 1; + for (MxS32 j = max; playerScoreRank < j; j--) { + m_indices[j - 1] = m_indices[j - 2]; + } - // TODO: Match bubble sort loops - for (MxS32 i = m_count - 1; i > 0; i--) { - for (MxS32 j = 1; j <= i; j++) { - if (m_scores[j - 1].m_totalScore < m_scores[j].m_totalScore) { - memcpy(tmpScores, m_scores[j - 1].m_scores, sizeof(tmpScores)); - tmpPlayer = m_scores[j - 1].m_name; - tmpUnk0x2a = m_scores[j - 1].m_unk0x2a; + m_indices[playerScoreRank] = playerScoreHistoryIndex; + p_scorehist = &m_scores[playerScoreHistoryIndex]; + } + else if (playerScoreRank < 20) { + m_indices[m_count] = m_count; + p_scorehist = &m_scores[m_count++]; + } + } + else if (p_scorehist->m_totalScore != totalScore) { + assert(totalScore > p_scorehist->m_totalScore); - memcpy(m_scores[j - 1].m_scores, m_scores[j].m_scores, sizeof(m_scores[j - 1].m_scores)); - m_scores[j - 1].m_name = m_scores[j].m_name; - m_scores[j - 1].m_unk0x2a = m_scores[j].m_unk0x2a; + for (MxS32 i = playerScoreHistoryIndex; i > 0 && m_indices[i - 1] < m_indices[i]; i--) { + MxU8 tmp = m_indices[i - 1]; + m_indices[i - 1] = m_indices[i]; + m_indices[i] = tmp; + } + } + if (p_scorehist) { + p_scorehist->m_totalScore = totalScore; + memcpy(p_scorehist->m_scores[0], scores[0], sizeof(scores)); + p_scorehist->m_name = GameState()->m_players[0]; + p_scorehist->m_playerId = GameState()->m_currentPlayerId; + } +#else + if (p_scorehist != NULL) { + p_scorehist->m_totalScore = totalScore; + memcpy(p_scorehist->m_scores, scores, sizeof(p_scorehist->m_scores)); + } + else { + if (m_count < (MxS16) sizeOfArray(m_scores)) { + m_scores[m_count].m_totalScore = totalScore; + memcpy(m_scores[m_count].m_scores, scores, sizeof(m_scores[m_count].m_scores)); + m_scores[m_count].m_name = GameState()->m_players[0]; + m_scores[m_count].m_playerId = GameState()->m_currentPlayerId; + m_count++; + } + else if (m_scores[19].m_totalScore <= totalScore) { + m_scores[19].m_totalScore = totalScore; + memcpy(m_scores[19].m_scores, scores, sizeof(m_scores[19].m_scores)); + m_scores[19].m_name = GameState()->m_players[0]; + m_scores[19].m_playerId = GameState()->m_currentPlayerId; + } + } - memcpy(m_scores[j].m_scores, tmpScores, sizeof(m_scores[j].m_scores)); - m_scores[j].m_name = tmpPlayer; - m_scores[j].m_unk0x2a = tmpUnk0x2a; - } + ScoreItem tmpItem; + + for (MxS32 i = m_count - 1; i >= 0; i--) { + for (MxS32 j = 1; j <= i; j++) { + if (m_scores[j].m_totalScore > m_scores[j - 1].m_totalScore) { + tmpItem = m_scores[j - 1]; + m_scores[j - 1] = m_scores[j]; + m_scores[j] = tmpItem; } } } +#endif } // FUNCTION: LEGO1 0x1003cc90 // FUNCTION: BETA10 0x1008732a -LegoGameState::ScoreItem* LegoGameState::History::FUN_1003cc90( +LegoGameState::ScoreItem* LegoGameState::History::FindPlayerInScoreHistory( LegoGameState::Username* p_player, MxS16 p_unk0x24, MxS32& p_unk0x2c @@ -1540,7 +1585,7 @@ LegoGameState::ScoreItem* LegoGameState::History::FUN_1003cc90( { MxS32 i = 0; for (; i < m_count; i++) { - if (!memcmp(p_player, &m_scores[i].m_name, sizeof(*p_player)) && m_scores[i].m_unk0x2a == p_unk0x24) { + if (!memcmp(p_player, &m_scores[i].m_name, sizeof(*p_player)) && m_scores[i].m_playerId == p_unk0x24) { break; } } @@ -1559,7 +1604,7 @@ LegoGameState::ScoreItem* LegoGameState::History::FUN_1003cc90( MxResult LegoGameState::History::Serialize(LegoStorage* p_storage) { if (p_storage->IsReadMode()) { - p_storage->ReadS16(m_unk0x372); + p_storage->ReadS16(m_nextPlayerId); p_storage->ReadS16(m_count); for (MxS16 i = 0; i < m_count; i++) { @@ -1569,7 +1614,7 @@ MxResult LegoGameState::History::Serialize(LegoStorage* p_storage) } } else if (p_storage->IsWriteMode()) { - p_storage->WriteS16(m_unk0x372); + p_storage->WriteS16(m_nextPlayerId); p_storage->WriteS16(m_count); for (MxS16 i = 0; i < m_count; i++) { @@ -1599,6 +1644,7 @@ void LegoGameState::SerializeScoreHistory(MxS16 p_flags) } // FUNCTION: LEGO1 0x1003cea0 +// FUNCTION: BETA10 0x10017840 void LegoGameState::SetCurrentAct(Act p_currentAct) { m_currentAct = p_currentAct; diff --git a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp index 1444571f..5385a86a 100644 --- a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp @@ -214,7 +214,7 @@ LegoEntity* LegoPlantManager::CreatePlant(MxS32 p_index, LegoWorld* p_world, Leg { LegoEntity* entity = NULL; - if (p_index < sizeOfArray(g_plantInfo)) { + if (p_worldId != LegoOmni::e_undefined && p_index < sizeOfArray(g_plantInfo)) { MxU32 world = 1 << (MxU8) p_worldId; if (g_plantInfo[p_index].m_worlds & world && g_plantInfo[p_index].m_counter != 0) { diff --git a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp index 46dad6dc..eb639d84 100644 --- a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp +++ b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp @@ -83,7 +83,7 @@ LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_text memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) != DD_OK) { + if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) != DD_OK) { goto done; } @@ -193,7 +193,7 @@ LegoResult LegoTextureInfo::LoadBits(const LegoU8* p_bits) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { MxU8* surface = (MxU8*) desc.lpSurface; const LegoU8* bits = p_bits; diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index 26948049..9d3f3c7d 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -708,7 +708,7 @@ void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { LegoImage* image = new LegoImage(desc.dwWidth, desc.dwHeight); if (image != NULL) { diff --git a/LEGO1/lego/legoomni/src/common/legovariables.cpp b/LEGO1/lego/legoomni/src/common/legovariables.cpp index 28a54907..8269dfde 100644 --- a/LEGO1/lego/legoomni/src/common/legovariables.cpp +++ b/LEGO1/lego/legoomni/src/common/legovariables.cpp @@ -1,6 +1,7 @@ #include "legovariables.h" #include "3dmanager/lego3dmanager.h" +#include "legoactor.h" #include "legogamestate.h" #include "legonavcontroller.h" #include "legovideomanager.h" @@ -159,18 +160,18 @@ void WhoAmIVariable::SetValue(const char* p_value) MxVariable::SetValue(p_value); if (!SDL_strcasecmp(p_value, g_papa)) { - GameState()->SetActorId(3); + GameState()->SetActorId(LegoActor::c_papa); } else if (!SDL_strcasecmp(p_value, g_mama)) { - GameState()->SetActorId(2); + GameState()->SetActorId(LegoActor::c_mama); } else if (!SDL_strcasecmp(p_value, g_pepper)) { - GameState()->SetActorId(1); + GameState()->SetActorId(LegoActor::c_pepper); } else if (!SDL_strcasecmp(p_value, g_nick)) { - GameState()->SetActorId(4); + GameState()->SetActorId(LegoActor::c_nick); } else if (!SDL_strcasecmp(p_value, g_laura)) { - GameState()->SetActorId(5); + GameState()->SetActorId(LegoActor::c_laura); } } diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 6cd73584..b251c1c0 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -210,10 +210,10 @@ void MxTransitionManager::DissolveTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -402,10 +402,10 @@ void MxTransitionManager::WipeDownTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -439,10 +439,10 @@ void MxTransitionManager::WindowsTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -483,10 +483,10 @@ void MxTransitionManager::BrokenTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { diff --git a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp index 6c67b9ea..00b877bd 100644 --- a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp @@ -393,7 +393,7 @@ MxResult LegoWorldPresenter::LoadWorldModel(ModelDbModel& p_model, SDL_IOStream* } modelPresenter.SetAction(&action); - modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_unk0x34, p_world); + modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_visible, p_world); delete[] buff; return SUCCESS; diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index d8f946b3..28642bab 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -224,10 +224,10 @@ void LegoAnimPresenter::FUN_100692b0() for (LegoU32 i = 0; i < numActors; i++) { LegoChar* str = GetVariableOrIdentity(m_anim->GetActorName(i), NULL); - undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); + LegoU32 actorType = m_anim->GetActorType(i); LegoROI* roi = NULL; - if (unk0x04 == 2) { + if (actorType == LegoAnimActorEntry::e_actorType2) { LegoChar* src; if (str[0] == '*') { src = str + 1; @@ -242,7 +242,7 @@ void LegoAnimPresenter::FUN_100692b0() roi->SetVisibility(FALSE); } } - else if (unk0x04 == 4) { + else if (actorType == LegoAnimActorEntry::e_actorType4) { LegoChar* baseName = new LegoChar[strlen(str)]; strcpy(baseName, str + 1); SDL_strlwr(baseName); @@ -257,7 +257,7 @@ void LegoAnimPresenter::FUN_100692b0() delete[] baseName; delete[] und; } - else if (unk0x04 == 3) { + else if (actorType == LegoAnimActorEntry::e_actorType3) { LegoChar* lodName = new LegoChar[strlen(str)]; strcpy(lodName, str + 1); @@ -303,9 +303,9 @@ void LegoAnimPresenter::FUN_100695c0() for (LegoU32 i = 0; i < numActors; i++) { if (FUN_100698b0(rois, m_anim->GetActorName(i)) == FALSE) { - undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); + LegoU32 actorType = m_anim->GetActorType(i); - if (unk0x04 == 5 || unk0x04 == 6) { + if (actorType == LegoAnimActorEntry::e_actorType5 || actorType == LegoAnimActorEntry::e_actorType6) { LegoChar lodName[256]; const LegoChar* actorName = m_anim->GetActorName(i); diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 66a3b9b9..a0173224 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -406,37 +406,14 @@ inline void LegoVideoManager::DrawCursor() // FUNCTION: LEGO1 0x1007bbc0 void LegoVideoManager::DrawFPS() { - char zeros[8] = "0000.00"; - if (m_unk0x528 == NULL) { - m_arialFont = CreateFont( - 12, - 0, - 0, - 0, - FW_NORMAL, - FALSE, - FALSE, - FALSE, - ANSI_CHARSET, - OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, - FF_DONTCARE | VARIABLE_PITCH, - "Arial" - ); + int width = 64; // Big enough for 9999.99 + int height = 16; - HDC dc = GetDC(NULL); - SelectObject(dc, m_arialFont); - GetTextExtentPoint(dc, zeros, strlen(zeros), &m_fpsSize); - ReleaseDC(NULL, dc); - - m_unk0x528 = m_displaySurface->FUN_100bc8b0(m_fpsSize.cx, m_fpsSize.cy); - SetRect(&m_fpsRect, 0, 0, m_fpsSize.cx, m_fpsSize.cy); + m_unk0x528 = m_displaySurface->FUN_100bc8b0(width, height); + SetRect(&m_fpsRect, 0, 0, width, height); if (m_unk0x528 == NULL) { - DeleteObject(m_arialFont); - m_arialFont = NULL; return; } @@ -450,9 +427,7 @@ void LegoVideoManager::DrawFPS() if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) != DD_OK) { m_unk0x528->Release(); - DeleteObject(m_arialFont); m_unk0x528 = NULL; - m_arialFont = NULL; } else { DWORD i; @@ -472,8 +447,7 @@ void LegoVideoManager::DrawFPS() if (Timer()->GetTime() > m_unk0x54c + 5000.f) { char buffer[32]; MxFloat time = (Timer()->GetTime() - m_unk0x54c) / 1000.0f; - MxS32 nb = sprintf(buffer, "%.02f", m_unk0x550 / time); - SDL_Log("%.02f", m_unk0x550 / time); + sprintf(buffer, "%.02f", m_unk0x550 / time); m_unk0x54c = Timer()->GetTime(); DDSURFACEDESC surfaceDesc; @@ -481,37 +455,13 @@ void LegoVideoManager::DrawFPS() surfaceDesc.dwSize = sizeof(surfaceDesc); if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) { - DWORD i; - char* ptr = (char*) surfaceDesc.lpSurface; + memset(surfaceDesc.lpSurface, 0, surfaceDesc.lPitch * surfaceDesc.dwHeight); - for (i = 0; i < surfaceDesc.dwHeight; i++) { - memset(ptr, 0, surfaceDesc.lPitch); - ptr += surfaceDesc.lPitch; - } + DrawTextToSurface32((uint8_t*) surfaceDesc.lpSurface, surfaceDesc.lPitch, 0, 0, buffer, 0xFF0000FF); m_unk0x528->Unlock(surfaceDesc.lpSurface); + m_unk0x550 = 1.f; } - - HDC dc; - if (m_unk0x528->GetDC(&dc) != DD_OK) { - m_unk0x528->Release(); - m_unk0x528 = NULL; - DeleteObject(m_arialFont); - m_arialFont = NULL; - return; - } - - SelectObject(dc, m_arialFont); - SetTextColor(dc, RGB(255, 255, 0)); - SetBkColor(dc, RGB(0, 0, 0)); - SetBkMode(dc, OPAQUE); - GetTextExtentPoint32(dc, buffer, nb, &m_fpsSize); - - RECT rect; - SetRect(&rect, 0, 0, m_fpsSize.cx, m_fpsSize.cy); - ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, buffer, nb, NULL); - m_unk0x528->ReleaseDC(dc); - m_unk0x550 = 1.f; } else { m_unk0x550 += 1.f; @@ -826,3 +776,63 @@ MxResult LegoVideoManager::ConfigureD3DRM() return SUCCESS; } + +void LegoVideoManager::DrawDigitToBuffer32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, int p_digit, uint32_t p_color) +{ + if (p_digit < 0 || p_digit > 9) { + return; + } + + uint32_t* pixels = (uint32_t*) p_dst; + int rowStride = p_pitch / 4; + + // 4x5 bitmap font + const uint8_t digitFont[5][10] = { + {0b1111, 0b0001, 0b1111, 0b1111, 0b1001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111}, + {0b1001, 0b0001, 0b0001, 0b0001, 0b1001, 0b1000, 0b1000, 0b0001, 0b1001, 0b1001}, + {0b1001, 0b0001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111, 0b0010, 0b1111, 0b1111}, + {0b1001, 0b0001, 0b1000, 0b0001, 0b0001, 0b0001, 0b1001, 0b0010, 0b1001, 0b0001}, + {0b1111, 0b0001, 0b1111, 0b1111, 0b0001, 0b1111, 0b1111, 0b0100, 0b1111, 0b1111}, + }; + + for (int row = 0; row < 5; ++row) { + uint8_t bits = digitFont[row][p_digit]; + for (int col = 0; col < 5; ++col) { + if (bits & (1 << (4 - col))) { + for (int dy = 0; dy < 2; ++dy) { + for (int dx = 0; dx < 2; ++dx) { + pixels[(p_y + row * 2 + dy) * rowStride + (p_x + col * 2 + dx)] = p_color; + } + } + } + } + } +} + +void LegoVideoManager::DrawTextToSurface32( + uint8_t* p_dst, + int p_pitch, + int p_x, + int p_y, + const char* p_text, + uint32_t p_color +) +{ + while (*p_text) { + if (*p_text >= '0' && *p_text <= '9') { + DrawDigitToBuffer32(p_dst, p_pitch, p_x, p_y, *p_text - '0', p_color); + p_x += 10; + } + else if (*p_text == '.') { + uint32_t* pixels = (uint32_t*) p_dst; + int rowStride = p_pitch / 4; + for (int dy = 0; dy < 2; ++dy) { + for (int dx = 0; dx < 2; ++dx) { + pixels[(p_y + 10 + dy) * rowStride + (p_x + 2 + dx)] = p_color; + } + } + p_x += 4; + } + ++p_text; + } +} diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp index 47838720..0166c9d7 100644 --- a/LEGO1/lego/legoomni/src/worlds/act3.cpp +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -489,7 +489,7 @@ MxResult Act3::Create(MxDSAction& p_dsAction) case LegoGameState::e_act1: case LegoGameState::e_actNotFound: GameState()->StopArea(LegoGameState::e_undefined); - if (GameState()->GetPreviousArea() == LegoGameState::e_infomain) { + if (GameState()->m_previousArea == LegoGameState::e_infomain) { GameState()->StopArea(LegoGameState::e_isle); } } @@ -506,7 +506,7 @@ MxResult Act3::Create(MxDSAction& p_dsAction) GameState()->m_currentArea = LegoGameState::e_act3script; GameState()->SetCurrentAct(LegoGameState::e_act3); - GameState()->SetDirty(TRUE); + GameState()->m_isDirty = TRUE; } return result; @@ -884,7 +884,7 @@ void Act3::Enable(MxBool p_enable) FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); PlayMusic(JukeboxScript::c_Act3Music); - GameState()->SetDirty(TRUE); + GameState()->m_isDirty = TRUE; if (m_time > 0) { MxFloat delta = Timer()->GetTime() - m_time - 100.0f; diff --git a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp index 114ee32f..f9bfb4eb 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp @@ -219,7 +219,7 @@ MxResult Infocenter::Create(MxDSAction& p_dsAction) if (m_infocenterState->m_unk0x74 == 4) { LegoGameState* state = GameState(); - state->SetPreviousArea(GameState()->GetUnknown0x42c()); + state->m_previousArea = GameState()->m_unk0x42c; } InputManager()->Register(this); @@ -1024,13 +1024,13 @@ MxU8 Infocenter::HandleControl(LegoControlManagerNotificationParam& p_param) case InfomainScript::c_BigInfo_Ctl: switch (state->GetCurrentAct()) { case LegoGameState::e_act1: - if (state->GetPreviousArea()) { - switch (state->GetPreviousArea()) { + if (state->m_previousArea) { + switch (state->m_previousArea) { case LegoGameState::e_infodoor: case LegoGameState::e_regbook: case LegoGameState::e_infoscor: m_infocenterState->m_unk0x74 = 5; - m_destLocation = state->GetPreviousArea(); + m_destLocation = state->m_previousArea; actionToPlay = (InfomainScript::Script) m_infocenterState->GetNextLeaveDialogue(); m_radio.Stop(); InputManager()->DisableInputProcessing(); @@ -1085,7 +1085,7 @@ MxU8 Infocenter::HandleControl(LegoControlManagerNotificationParam& p_param) actionToPlay = GameState()->GetCurrentAct() != LegoGameState::e_act1 ? InfomainScript::c_GoTo_RegBook_Red : InfomainScript::c_GoTo_RegBook; m_radio.Stop(); - GameState()->m_unk0x42c = GameState()->GetPreviousArea(); + GameState()->m_unk0x42c = GameState()->m_previousArea; InputManager()->DisableInputProcessing(); break; case InfomainScript::c_Mama_Ctl: @@ -1394,7 +1394,7 @@ void Infocenter::Reset() AnimationManager()->Reset(FALSE); CharacterManager()->ReleaseAllActors(); GameState()->SetCurrentAct(LegoGameState::e_act1); - GameState()->SetPreviousArea(LegoGameState::e_undefined); + GameState()->m_previousArea = LegoGameState::e_undefined; GameState()->m_unk0x42c = LegoGameState::e_undefined; InitializeBitmaps(); diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index 5de5a487..4d2c5b29 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -121,7 +121,7 @@ MxResult Isle::Create(MxDSAction& p_dsAction) m_act1state = act1state; EnableAnimations(TRUE); - GameState()->SetDirty(TRUE); + GameState()->m_isDirty = TRUE; } return result; diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp index 6ad242aa..094bdac9 100644 --- a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -141,7 +141,7 @@ MxResult LegoAct2::Create(MxDSAction& p_dsAction) case LegoGameState::e_act1: case LegoGameState::e_actNotFound: GameState()->StopArea(LegoGameState::e_undefined); - if (GameState()->GetPreviousArea() == LegoGameState::e_infomain) { + if (GameState()->m_previousArea == LegoGameState::e_infomain) { GameState()->StopArea(LegoGameState::e_isle); } } @@ -149,7 +149,7 @@ MxResult LegoAct2::Create(MxDSAction& p_dsAction) GameState()->m_currentArea = LegoGameState::e_act2main; GameState()->SetCurrentAct(LegoGameState::e_act2); InputManager()->Register(this); - GameState()->SetDirty(TRUE); + GameState()->m_isDirty = TRUE; } return result; @@ -536,7 +536,7 @@ void LegoAct2::Enable(MxBool p_enable) ((IslePathActor*) m_pepper->GetEntity())->VTable0xec(m_unk0x10dc, m_unk0x1124, TRUE); - if (GameState()->GetPreviousArea() == LegoGameState::e_infomain) { + if (GameState()->m_previousArea == LegoGameState::e_infomain) { GameState()->StopArea(LegoGameState::e_infomain); } diff --git a/LEGO1/lego/legoomni/src/worlds/score.cpp b/LEGO1/lego/legoomni/src/worlds/score.cpp index ebeca836..69b4305a 100644 --- a/LEGO1/lego/legoomni/src/worlds/score.cpp +++ b/LEGO1/lego/legoomni/src/worlds/score.cpp @@ -254,7 +254,7 @@ void Score::Paint() memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - HRESULT result = cube->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL); + HRESULT result = cube->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL); if (result == DD_OK) { if (desc.lPitch != desc.dwWidth) { cube->m_surface->Unlock(desc.lpSurface); diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.cpp b/LEGO1/lego/sources/3dmanager/lego3dview.cpp index 0a4779a4..1cc272e1 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dview.cpp +++ b/LEGO1/lego/sources/3dmanager/lego3dview.cpp @@ -154,7 +154,7 @@ double Lego3DView::Render(double p_und) } // FUNCTION: LEGO1 0x100ab2b0 -ViewROI* Lego3DView::Pick(unsigned int x, unsigned int y) +ViewROI* Lego3DView::Pick(int x, int y) { return m_pViewManager->Pick(GetView(), x, y); } diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.h b/LEGO1/lego/sources/3dmanager/lego3dview.h index baec8f43..4441b85e 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dview.h +++ b/LEGO1/lego/sources/3dmanager/lego3dview.h @@ -27,7 +27,7 @@ class Lego3DView : public LegoView1 { double Render(double p_und); - ViewROI* Pick(unsigned int x, unsigned int y); + ViewROI* Pick(int x, int y); ViewROI* GetPointOfView(); ViewManager* GetViewManager(); diff --git a/LEGO1/lego/sources/anim/legoanim.cpp b/LEGO1/lego/sources/anim/legoanim.cpp index 3b8caafc..8ec3ee2d 100644 --- a/LEGO1/lego/sources/anim/legoanim.cpp +++ b/LEGO1/lego/sources/anim/legoanim.cpp @@ -725,6 +725,7 @@ void LegoAnimNodeData::SetName(LegoChar* p_name) } // FUNCTION: LEGO1 0x100a03c0 +// FUNCTION: BETA10 0x1017f254 LegoResult LegoAnimNodeData::CreateLocalTransform(LegoFloat p_time, Matrix4& p_matrix) { LegoU32 index; @@ -1062,7 +1063,7 @@ LegoResult LegoAnim::Read(LegoStorage* p_storage, LegoS32 p_parseScene) m_modelList[i].m_name[length] = '\0'; - if (p_storage->Read(&m_modelList[i].m_unk0x04, sizeof(undefined4)) != SUCCESS) { + if (p_storage->Read(&m_modelList[i].m_type, sizeof(LegoU32)) != SUCCESS) { goto done; } } @@ -1123,7 +1124,7 @@ LegoResult LegoAnim::Write(LegoStorage* p_storage) goto done; } - if (p_storage->Write(&m_modelList[i].m_unk0x04, sizeof(m_modelList[i].m_unk0x04)) != SUCCESS) { + if (p_storage->Write(&m_modelList[i].m_type, sizeof(m_modelList[i].m_type)) != SUCCESS) { goto done; } } @@ -1158,10 +1159,10 @@ const LegoChar* LegoAnim::GetActorName(LegoU32 p_index) // FUNCTION: LEGO1 0x100a0f40 // FUNCTION: BETA10 0x1018023c -undefined4 LegoAnim::GetActorUnknown0x04(LegoU32 p_index) +LegoU32 LegoAnim::GetActorType(LegoU32 p_index) { if (p_index < m_numActors) { - return m_modelList[p_index].m_unk0x04; + return m_modelList[p_index].m_type; } return 0; diff --git a/LEGO1/lego/sources/anim/legoanim.h b/LEGO1/lego/sources/anim/legoanim.h index 9b81b531..372128b5 100644 --- a/LEGO1/lego/sources/anim/legoanim.h +++ b/LEGO1/lego/sources/anim/legoanim.h @@ -30,9 +30,9 @@ class LegoAnimKey { LegoU32 ShouldSkipInterpolation() { return m_flags & c_skipInterpolation; } // FUNCTION: BETA10 0x100739a0 - void FUN_100739a0(MxS32 p_param) + void SetActive(MxS32 p_active) { - if (p_param) { + if (p_active) { m_flags |= c_active; } else { @@ -289,8 +289,16 @@ class LegoAnimNodeData : public LegoTreeNodeData { // SIZE 0x08 struct LegoAnimActorEntry { - LegoChar* m_name; // 0x00 - undefined4 m_unk0x04; // 0x04 + enum { + e_actorType2 = 2, + e_actorType3 = 3, + e_actorType4 = 4, + e_actorType5 = 5, + e_actorType6 = 6, + }; + + LegoChar* m_name; // 0x00 + LegoU32 m_type; // 0x04 }; // TODO: Possibly called `LegoCameraAnim(ation)`? @@ -338,7 +346,7 @@ class LegoAnim : public LegoTree { virtual LegoResult Read(LegoStorage* p_storage, LegoS32 p_parseScene); // vtable+0x10 const LegoChar* GetActorName(LegoU32 p_index); - undefined4 GetActorUnknown0x04(LegoU32 p_index); + LegoU32 GetActorType(LegoU32 p_index); // FUNCTION: BETA10 0x1005abf0 LegoAnimScene* GetCamAnim() { return m_camAnim; } diff --git a/LEGO1/lego/sources/misc/legocontainer.cpp b/LEGO1/lego/sources/misc/legocontainer.cpp index 6928a5c3..98836d6a 100644 --- a/LEGO1/lego/sources/misc/legocontainer.cpp +++ b/LEGO1/lego/sources/misc/legocontainer.cpp @@ -22,7 +22,7 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { width = desc.dwWidth; height = desc.dwHeight; p_textureInfo->m_surface->Unlock(desc.lpSurface); @@ -35,7 +35,7 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&newDesc, 0, sizeof(newDesc)); newDesc.dwSize = sizeof(newDesc); - if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { BOOL und = FALSE; if (newDesc.dwWidth == width && newDesc.dwHeight == height) { und = TRUE; diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp index 88710174..81d8c3d0 100644 --- a/LEGO1/lego/sources/roi/legoroi.cpp +++ b/LEGO1/lego/sources/roi/legoroi.cpp @@ -59,8 +59,12 @@ ColorOverride g_colorOverride = NULL; TextureHandler g_textureHandler = NULL; // FUNCTION: LEGO1 0x100a81b0 -void LegoROI::FUN_100a81b0(const LegoChar* p_error, const LegoChar* p_name) +// FUNCTION: BETA10 0x101898c0 +// FUNCTION: ALPHA 0x100bb1c0 +void LegoROI::FUN_100a81b0(const LegoChar* p_error, ...) { + // Probably a printf-like debug function that was removed early. + // No known implementation in any of the binaries. } // FUNCTION: LEGO1 0x100a81c0 @@ -70,6 +74,7 @@ void LegoROI::configureLegoROI(int p_roiConfig) } // FUNCTION: LEGO1 0x100a81d0 +// FUNCTION: BETA10 0x101898e8 LegoROI::LegoROI(Tgl::Renderer* p_renderer) : ViewROI(p_renderer, NULL) { m_parentROI = NULL; @@ -78,6 +83,7 @@ LegoROI::LegoROI(Tgl::Renderer* p_renderer) : ViewROI(p_renderer, NULL) } // FUNCTION: LEGO1 0x100a82d0 +// FUNCTION: BETA10 0x10189994 LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_renderer, p_lodList) { m_parentROI = NULL; @@ -86,6 +92,7 @@ LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_ } // FUNCTION: LEGO1 0x100a83c0 +// FUNCTION: BETA10 0x10189a42 LegoROI::~LegoROI() { if (comp) { @@ -106,6 +113,7 @@ LegoROI::~LegoROI() } // FUNCTION: LEGO1 0x100a84a0 +// FUNCTION: BETA10 0x10189b99 LegoResult LegoROI::Read( OrientableROI* p_unk0xd4, Tgl::Renderer* p_renderer, @@ -338,6 +346,7 @@ LegoResult LegoROI::Read( } // FUNCTION: LEGO1 0x100a8cb0 +// FUNCTION: BETA10 0x1018a7e8 LegoResult LegoROI::CreateLocalTransform(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix) { p_matrix.SetIdentity(); @@ -380,6 +389,7 @@ LegoROI* LegoROI::FindChildROI(const LegoChar* p_name, LegoROI* p_roi) } // FUNCTION: LEGO1 0x100a8da0 +// FUNCTION: BETA10 0x1018a9fb LegoResult LegoROI::ApplyAnimationTransformation( LegoTreeNode* p_node, const Matrix4& p_matrix, @@ -474,6 +484,7 @@ void LegoROI::FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_t } // FUNCTION: LEGO1 0x100a90f0 +// FUNCTION: BETA10 0x1018ada8 LegoResult LegoROI::SetFrame(LegoAnim* p_anim, LegoTime p_time) { LegoTreeNode* root = p_anim->GetRoot(); @@ -513,6 +524,7 @@ LegoResult LegoROI::SetLodColor(LegoFloat p_red, LegoFloat p_green, LegoFloat p_ } // FUNCTION: LEGO1 0x100a9210 +// FUNCTION: BETA10 0x1018af25 LegoResult LegoROI::SetTextureInfo(LegoTextureInfo* p_textureInfo) { LegoResult result = SUCCESS; @@ -736,6 +748,7 @@ LegoU32 LegoROI::FUN_100a9410( } // FUNCTION: LEGO1 0x100a9a50 +// FUNCTION: BETA10 0x1018bb6b TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time) : LegoROI(p_renderer, p_lodList) { m_time = p_time; @@ -761,6 +774,7 @@ void TimeROI::FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time) } // FUNCTION: LEGO1 0x100a9bf0 +// FUNCTION: BETA10 0x1018bc93 LegoBool LegoROI::GetRGBAColor(const LegoChar* p_name, float& p_red, float& p_green, float& p_blue, float& p_alpha) { if (p_name == NULL) { @@ -851,12 +865,14 @@ void LegoROI::SetDisplayBB(int p_displayBB) } // FUNCTION: LEGO1 0x100aa340 +// FUNCTION: BETA10 0x1018cca0 float LegoROI::IntrinsicImportance() const { return .5; } // FUNCTION: LEGO1 0x100aa350 +// FUNCTION: BETA10 0x1018ccc0 void LegoROI::UpdateWorldBoundingVolumes() { CalcWorldBoundingVolumes(m_sphere, m_local2world, m_world_bounding_box, m_world_bounding_sphere); diff --git a/LEGO1/lego/sources/roi/legoroi.h b/LEGO1/lego/sources/roi/legoroi.h index e1cced55..bef2c580 100644 --- a/LEGO1/lego/sources/roi/legoroi.h +++ b/LEGO1/lego/sources/roi/legoroi.h @@ -18,6 +18,7 @@ class LegoTreeNode; struct LegoAnimActorEntry; // VTABLE: LEGO1 0x100dbe38 +// VTABLE: BETA10 0x101c3898 // SIZE 0x108 class LegoROI : public ViewROI { public: @@ -58,7 +59,7 @@ class LegoROI : public ViewROI { void SetDisplayBB(int p_displayBB); static LegoResult CreateLocalTransform(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix); - static void FUN_100a81b0(const LegoChar* p_error, const LegoChar* p_name); + static void FUN_100a81b0(const LegoChar* p_error, ...); LEGO1_EXPORT static void configureLegoROI(int p_roi); static void SetColorOverride(ColorOverride p_colorOverride); static LegoBool GetRGBAColor(const LegoChar* p_name, float& p_red, float& p_green, float& p_blue, float& p_alpha); @@ -87,6 +88,7 @@ class LegoROI : public ViewROI { void SetBoundingBox(const BoundingBox& p_box) { m_bounding_box = p_box; } // SYNTHETIC: LEGO1 0x100a82b0 + // SYNTHETIC: BETA10 0x1018c490 // LegoROI::`scalar deleting destructor' private: @@ -99,15 +101,20 @@ class LegoROI : public ViewROI { }; // VTABLE: LEGO1 0x100dbea8 +// VTABLE: BETA10 0x101c38d0 // SIZE 0x10c class TimeROI : public LegoROI { public: TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time); + void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time); + // SYNTHETIC: LEGO1 0x100a9ad0 + // SYNTHETIC: BETA10 0x1018c540 // TimeROI::`scalar deleting destructor' - void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time); + // SYNTHETIC: BETA10 0x1018c580 + // TimeROI::~TimeROI private: LegoTime m_time; // 0x108 diff --git a/LEGO1/modeldb/modeldb.cpp b/LEGO1/modeldb/modeldb.cpp index 90803570..919e8685 100644 --- a/LEGO1/modeldb/modeldb.cpp +++ b/LEGO1/modeldb/modeldb.cpp @@ -52,7 +52,7 @@ MxResult ModelDbModel::Read(SDL_IOStream* p_file) if (SDL_ReadIO(p_file, m_up, 3 * sizeof(float)) != 3 * sizeof(float)) { return FAILURE; } - if (SDL_ReadIO(p_file, &m_unk0x34, sizeof(undefined)) != sizeof(undefined)) { + if (SDL_ReadIO(p_file, &m_visible, sizeof(MxU8)) != sizeof(MxU8)) { return FAILURE; } diff --git a/LEGO1/modeldb/modeldb.h b/LEGO1/modeldb/modeldb.h index ab3cf10b..46bb8d2b 100644 --- a/LEGO1/modeldb/modeldb.h +++ b/LEGO1/modeldb/modeldb.h @@ -102,7 +102,7 @@ struct ModelDbModel { float m_location[3]; // 0x10 float m_direction[3]; // 0x1c float m_up[3]; // 0x28 - undefined m_unk0x34; // 0x34 + MxU8 m_visible; // 0x34 }; // SIZE 0x18 diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index 9ce37cf5..d6043a2c 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -174,7 +174,7 @@ BOOL MxDirect3D::D3DSetMode() memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) { + if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { unsigned char* surface = (unsigned char*) desc.lpSurface; for (int i = 0; i < mode.height; i++) { @@ -192,7 +192,7 @@ BOOL MxDirect3D::D3DSetMode() memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) { + if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { unsigned char* surface = (unsigned char*) desc.lpSurface; for (int i = 0; i < mode.height; i++) { diff --git a/LEGO1/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp index 6f3dfd78..104b6836 100644 --- a/LEGO1/mxdirectx/mxdirectdraw.cpp +++ b/LEGO1/mxdirectx/mxdirectdraw.cpp @@ -539,10 +539,10 @@ void MxDirectDraw::ClearBackBuffers() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (result == DDERR_SURFACELOST) { m_pBackBuffer->Restore(); - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (result != DD_OK) { diff --git a/LEGO1/omni/include/mxstring.h b/LEGO1/omni/include/mxstring.h index 89ebcd5f..eaa58181 100644 --- a/LEGO1/omni/include/mxstring.h +++ b/LEGO1/omni/include/mxstring.h @@ -24,7 +24,7 @@ class MxString : public MxCore { const MxString& operator=(const char* p_str); MxString operator+(const MxString& p_str) const; MxString operator+(const char* p_str) const; - MxString& operator+=(const char* p_str); + LEGO1_EXPORT MxString& operator+=(const char* p_str); static void CharSwap(char* p_a, char* p_b); LEGO1_EXPORT static void MapPathToFilesystem(char* p_path); diff --git a/LEGO1/omni/src/audio/mxsoundmanager.cpp b/LEGO1/omni/src/audio/mxsoundmanager.cpp index afb9b21e..f865ebf0 100644 --- a/LEGO1/omni/src/audio/mxsoundmanager.cpp +++ b/LEGO1/omni/src/audio/mxsoundmanager.cpp @@ -9,6 +9,8 @@ #include "mxticklethread.h" #include "mxwavepresenter.h" +#include + DECOMP_SIZE_ASSERT(MxSoundManager, 0x3c); // GLOBAL LEGO1 0x10101420 @@ -98,12 +100,17 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) spec.format = SDL_AUDIO_F32; spec.channels = ma_engine_get_channels(m_engine); - if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) == + if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) != NULL) { - goto done; + SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream)); + } + else { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, + "Failed to open default audio device for playback: %s", + SDL_GetError() + ); } - - SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream)); if (p_createThread) { m_thread = new MxTickleThread(this, p_frequencyMS); diff --git a/LEGO1/omni/src/common/mxstring.cpp b/LEGO1/omni/src/common/mxstring.cpp index 8ddc6a86..e8167a0c 100644 --- a/LEGO1/omni/src/common/mxstring.cpp +++ b/LEGO1/omni/src/common/mxstring.cpp @@ -217,7 +217,6 @@ void MxString::MapPathToFilesystem(char* p_path) } else if (j == 1) { SDL_strlcpy(&p_path[i - 1], file.GetData(), file.GetLength() + 1); - SDL_Log("Resolved file path to %s", p_path); return true; } } @@ -229,5 +228,14 @@ void MxString::MapPathToFilesystem(char* p_path) if (!mapPath(MxOmni::GetHDFiles())) { mapPath(MxOmni::GetCDFiles()); } +#else + char* path = p_path; + while (*path) { + if (*path == '/') { + *path = '\\'; + } + + path++; + } #endif } diff --git a/LEGO1/omni/src/video/flic.cpp b/LEGO1/omni/src/video/flic.cpp index 3a434b50..29473c5e 100644 --- a/LEGO1/omni/src/video/flic.cpp +++ b/LEGO1/omni/src/video/flic.cpp @@ -289,7 +289,7 @@ void DecodeBrun(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_da while (--line >= 0) { short column = 0; data++; - char count = 0; + signed char count = 0; while ((column += count) < width2) { count = *data++; @@ -332,7 +332,7 @@ void DecodeLC(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data while (packets > 0) { column += *data++; // skip byte - char type = *((char*) data++); + signed char type = *((signed char*) data++); if (type < 0) { type = -type; @@ -418,7 +418,7 @@ void DecodeSS2(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_dat // LINE: BETA10 0x1013e726 column += *data.byte++; // LINE: BETA10 0x1013e73a - short type = *(char*) data.byte++; + short type = *(signed char*) data.byte++; type += type; if (type >= 0) { diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 9b7d321e..6c93a0e7 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -402,10 +402,10 @@ void MxDisplaySurface::VTable0x28( memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { @@ -514,10 +514,10 @@ void MxDisplaySurface::VTable0x30( memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { @@ -726,11 +726,11 @@ void MxDisplaySurface::VTable0x34(MxU8* p_pixels, MxS32 p_bpp, MxS32 p_width, Mx memset(&surfaceDesc, 0, sizeof(surfaceDesc)); surfaceDesc.dwSize = sizeof(surfaceDesc); - HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL); + HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (result == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL); + result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (result == DD_OK) { @@ -784,7 +784,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) { + if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { MxU8* surface = (MxU8*) ddsd.lpSurface; MxS32 height = m_videoParam.GetRect().GetHeight(); @@ -891,7 +891,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44( memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT, 0) != DD_OK) { + if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0) != DD_OK) { surface->Release(); surface = NULL; } @@ -1067,7 +1067,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) { + if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { goto done; } else { diff --git a/LEGO1/realtime/orientableroi.cpp b/LEGO1/realtime/orientableroi.cpp index f479ca7d..92c9ac9e 100644 --- a/LEGO1/realtime/orientableroi.cpp +++ b/LEGO1/realtime/orientableroi.cpp @@ -108,6 +108,7 @@ void OrientableROI::SetLocal2World(const Matrix4& p_local2world) } // FUNCTION: LEGO1 0x100a5910 +// FUNCTION: BETA10 0x10167bac void OrientableROI::UpdateWorldData() { UpdateWorldBoundingVolumes(); @@ -115,6 +116,7 @@ void OrientableROI::UpdateWorldData() } // FUNCTION: LEGO1 0x100a5930 +// FUNCTION: BETA10 0x10167bd8 void OrientableROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform) { m_local2world = p_transform; @@ -123,6 +125,7 @@ void OrientableROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform } // FUNCTION: LEGO1 0x100a5960 +// FUNCTION: BETA10 0x10167c19 void OrientableROI::UpdateWorldDataWithTransform(const Matrix4& p_transform) { MxMatrix l_matrix(m_local2world); @@ -132,6 +135,7 @@ void OrientableROI::UpdateWorldDataWithTransform(const Matrix4& p_transform) } // FUNCTION: LEGO1 0x100a59b0 +// FUNCTION: BETA10 0x10167c6d void OrientableROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& p_transform) { MxMatrix l_matrix(m_local2world); @@ -155,11 +159,13 @@ void OrientableROI::SetWorldVelocity(const Vector3& p_world_velocity) } // FUNCTION: LEGO1 0x100a5a50 +// FUNCTION: BETA10 0x10167d65 void OrientableROI::UpdateWorldVelocity() { } // FUNCTION: LEGO1 0x100a5a60 +// FUNCTION: BETA10 0x10167d7b void CalcWorldBoundingVolumes( const BoundingSphere& modelling_sphere, const Matrix4& local2world, @@ -186,18 +192,21 @@ void CalcWorldBoundingVolumes( } // FUNCTION: LEGO1 0x100a5d80 +// FUNCTION: BETA10 0x10168760 const float* OrientableROI::GetWorldVelocity() const { return m_world_velocity.GetData(); } // FUNCTION: LEGO1 0x100a5d90 +// FUNCTION: BETA10 0x10168790 const BoundingBox& OrientableROI::GetWorldBoundingBox() const { return m_world_bounding_box; } // FUNCTION: LEGO1 0x100a5da0 +// FUNCTION: BETA10 0x101687b0 const BoundingSphere& OrientableROI::GetWorldBoundingSphere() const { return m_world_bounding_sphere; diff --git a/LEGO1/realtime/orientableroi.h b/LEGO1/realtime/orientableroi.h index dc3d5cd0..cb30b7fc 100644 --- a/LEGO1/realtime/orientableroi.h +++ b/LEGO1/realtime/orientableroi.h @@ -27,6 +27,7 @@ class OrientableROI : public ROI { const BoundingSphere& GetWorldBoundingSphere() const override; // vtable+0x10 // FUNCTION: LEGO1 0x100a5db0 + // FUNCTION: BETA10 0x101687d0 virtual void WrappedUpdateWorldData() { UpdateWorldData(); } // vtable+0x14 virtual void UpdateWorldBoundingVolumes() = 0; // vtable+0x18 @@ -85,6 +86,7 @@ class OrientableROI : public ROI { // OrientableROI::`scalar deleting destructor' // SYNTHETIC: LEGO1 0x100aa2f0 +// SYNTHETIC: BETA10 0x10168600 // OrientableROI::~OrientableROI #endif // ORIENTABLEROI_H diff --git a/LEGO1/realtime/roi.h b/LEGO1/realtime/roi.h index 87cbe8f1..dd5b9993 100644 --- a/LEGO1/realtime/roi.h +++ b/LEGO1/realtime/roi.h @@ -15,9 +15,16 @@ // SIZE 0x28 class BoundingBox { public: + // The BETA10 matches may reference the wrong version + + // FUNCTION: BETA10 0x1004a7a0 const Vector3& Min() const { return min; } + Vector3& Min() { return min; } + + // FUNCTION: BETA10 0x1004a7c0 const Vector3& Max() const { return max; } + Vector3& Max() { return max; } private: @@ -31,14 +38,26 @@ class BoundingBox { // SIZE 0x18 class BoundingSphere { public: + // The BETA10 matches may reference the wrong version + + // FUNCTION: BETA10 0x1001fac0 const Vector3& Center() const { return center; } + + // FUNCTION: BETA10 0x100d55a0 Vector3& Center() { return center; } + + // FUNCTION: BETA10 0x1001fd30 const float& Radius() const { return radius; } + + // FUNCTION: BETA10 0x1001fae0 float& Radius() { return radius; } // SYNTHETIC: BETA10 0x1001fb90 // BoundingSphere::operator= + // SYNTHETIC: BETA10 0x1001fc50 + // BoundingSphere::BoundingSphere + private: Mx3DPointFloat center; // 0x00 float radius; // 0x14 @@ -136,6 +155,7 @@ class ROI { // list >::~list > // SYNTHETIC: LEGO1 0x100a5d50 +// SYNTHETIC: BETA10 0x101686a0 // ROI::~ROI #endif // ROI_H diff --git a/LEGO1/tgl/d3drm/impl.h b/LEGO1/tgl/d3drm/impl.h index 92f886f8..4c834521 100644 --- a/LEGO1/tgl/d3drm/impl.h +++ b/LEGO1/tgl/d3drm/impl.h @@ -252,8 +252,8 @@ class ViewImpl : public View { Result TransformWorldToScreen(const float world[3], float screen[4]) override; Result TransformScreenToWorld(const float screen[4], float world[3]) override; Result Pick( - unsigned int x, - unsigned int y, + int x, + int y, const Group** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, @@ -277,8 +277,8 @@ class ViewImpl : public View { Result SetCamera(const CameraImpl& rCamera); Result Render(const GroupImpl& rScene); Result Pick( - unsigned int x, - unsigned int y, + int x, + int y, const GroupImpl** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, @@ -867,4 +867,7 @@ inline D3DRMMATERIALMODE Translate(MaterialMode mode) // GLOBAL: LEGO1 0x100dd1e0 // IID_IDirect3DRMMeshBuilder +// GLOBAL: LEGO1 0x100dd1f0 +// IID_IDirect3DRMMesh + #endif diff --git a/LEGO1/tgl/d3drm/mesh.cpp b/LEGO1/tgl/d3drm/mesh.cpp index 1921d8ee..68f765a7 100644 --- a/LEGO1/tgl/d3drm/mesh.cpp +++ b/LEGO1/tgl/d3drm/mesh.cpp @@ -17,7 +17,7 @@ void* MeshImpl::ImplementationDataPtr() } // FUNCTION: BETA10 0x10170590 -inline Tgl::Result MeshSetColor(MeshImpl::MeshData* pMesh, float r, float g, float b, float a) +inline Result MeshSetColor(MeshImpl::MeshData* pMesh, float r, float g, float b, float a) { if (a > 0) { D3DCOLOR color = D3DRMCreateColorRGBA(r, g, b, a); @@ -30,7 +30,7 @@ inline Tgl::Result MeshSetColor(MeshImpl::MeshData* pMesh, float r, float g, flo // FUNCTION: LEGO1 0x100a3ee0 // FUNCTION: BETA10 0x10170520 -Tgl::Result MeshImpl::SetColor(float r, float g, float b, float a) +Result MeshImpl::SetColor(float r, float g, float b, float a) { assert(m_data); @@ -38,14 +38,14 @@ Tgl::Result MeshImpl::SetColor(float r, float g, float b, float a) } // FUNCTION: BETA10 0x10171320 -inline Tgl::Result MeshSetTexture(MeshImpl::MeshData* pMesh, IDirect3DRMTexture* pD3DTexture) +inline Result MeshSetTexture(MeshImpl::MeshData* pMesh, IDirect3DRMTexture* pD3DTexture) { - Tgl::Result result = ResultVal(pMesh->groupMesh->SetGroupTexture(pMesh->groupIndex, pD3DTexture)); + Result result = ResultVal(pMesh->groupMesh->SetGroupTexture(pMesh->groupIndex, pD3DTexture)); return result; } // FUNCTION: BETA10 0x10171260 -inline Tgl::Result MeshImpl::SetTexture(const TextureImpl* pTexture) +inline Result MeshImpl::SetTexture(const TextureImpl* pTexture) { assert(m_data); assert(!pTexture || pTexture->ImplementationData()); @@ -56,7 +56,7 @@ inline Tgl::Result MeshImpl::SetTexture(const TextureImpl* pTexture) // FUNCTION: LEGO1 0x100a3f50 // FUNCTION: BETA10 0x10170630 -Tgl::Result MeshImpl::SetTexture(const Texture* pTexture) +Result MeshImpl::SetTexture(const Texture* pTexture) { assert(m_data); @@ -65,7 +65,7 @@ Tgl::Result MeshImpl::SetTexture(const Texture* pTexture) // FUNCTION: LEGO1 0x100a3f80 // FUNCTION: BETA10 0x10170690 -Tgl::Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode) +Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode) { assert(m_data); @@ -73,7 +73,7 @@ Tgl::Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode) } // FUNCTION: BETA10 0x10170750 -inline Tgl::Result MeshSetShadingModel(MeshImpl::MeshData* pMesh, ShadingModel model) +inline Result MeshSetShadingModel(MeshImpl::MeshData* pMesh, ShadingModel model) { D3DRMRENDERQUALITY mode = Translate(model); return ResultVal(pMesh->groupMesh->SetGroupQuality(pMesh->groupIndex, mode)); @@ -81,14 +81,14 @@ inline Tgl::Result MeshSetShadingModel(MeshImpl::MeshData* pMesh, ShadingModel m // FUNCTION: LEGO1 0x100a3fc0 // FUNCTION: BETA10 0x101706f0 -Tgl::Result MeshImpl::SetShadingModel(ShadingModel model) +Result MeshImpl::SetShadingModel(ShadingModel model) { assert(m_data); return MeshSetShadingModel(m_data, model); } // FUNCTION: BETA10 0x101714e0 -inline Tgl::Result MeshDeepClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData*& rpTarget, IDirect3DRMMesh* pMesh) +inline Result MeshDeepClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData*& rpTarget, IDirect3DRMMesh* pMesh) { rpTarget = new MeshImpl::MeshData(); rpTarget->groupMesh = pMesh; @@ -97,13 +97,13 @@ inline Tgl::Result MeshDeepClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData DWORD dataSize; unsigned int vcount, fcount, vperface; - Tgl::Result result = - ResultVal(pSource->groupMesh->GetGroup(pSource->groupIndex, (unsigned int*)&vcount, (unsigned int*)&fcount, (unsigned int*)&vperface, &dataSize, NULL)); + Result result = + ResultVal(pSource->groupMesh->GetGroup(pSource->groupIndex, &vcount, &fcount, &vperface, &dataSize, NULL)); assert(Succeeded(result)); unsigned int* faceBuffer = new unsigned int[dataSize]; result = - ResultVal(pSource->groupMesh->GetGroup(pSource->groupIndex, (unsigned int*)&vcount, (unsigned int*)&fcount, (unsigned int*)&vperface, &dataSize, (unsigned int*)&faceBuffer) + ResultVal(pSource->groupMesh->GetGroup(pSource->groupIndex, &vcount, &fcount, &vperface, &dataSize, faceBuffer) ); assert(Succeeded(result)); @@ -122,7 +122,7 @@ inline Tgl::Result MeshDeepClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData // Push information to new group D3DRMGROUPINDEX index; - result = ResultVal(pMesh->AddGroup(vcount, fcount, 3, (long unsigned int*)&faceBuffer, &index)); + result = ResultVal(pMesh->AddGroup(vcount, fcount, 3, faceBuffer, &index)); assert(Succeeded(result)); rpTarget->groupIndex = index; @@ -180,9 +180,9 @@ Mesh* MeshImpl::DeepClone(MeshBuilder* pMesh) return DeepClone(*static_cast(pMesh)); } -inline Tgl::Result MeshShallowClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData*& rpTarget, IDirect3DRMMesh* pMesh) +inline Result MeshShallowClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData*& rpTarget, IDirect3DRMMesh* pMesh) { - Tgl::Result result = Error; + Result result = Error; rpTarget = new MeshImpl::MeshData(); if (rpTarget) { @@ -220,13 +220,13 @@ Mesh* MeshImpl::ShallowClone(MeshBuilder* pMeshBuilder) } // FUNCTION: BETA10 0x10171ac0 -inline Tgl::Result MeshGetTexture(MeshImpl::MeshData* pMesh, IDirect3DRMTexture** pD3DTexture) +inline Result MeshGetTexture(MeshImpl::MeshData* pMesh, IDirect3DRMTexture** pD3DTexture) { return ResultVal(pMesh->groupMesh->GetGroupTexture(pMesh->groupIndex, pD3DTexture)); } // FUNCTION: BETA10 0x10171980 -inline Tgl::Result MeshImpl::GetTexture(TextureImpl** ppTexture) +inline Result MeshImpl::GetTexture(TextureImpl** ppTexture) { assert(m_data); assert(ppTexture); @@ -236,7 +236,7 @@ inline Tgl::Result MeshImpl::GetTexture(TextureImpl** ppTexture) // TODO: This helps retail match, but it adds to the stack IDirect3DRMTexture* tex; - Tgl::Result result = MeshGetTexture(m_data, &tex); + Result result = MeshGetTexture(m_data, &tex); #ifndef BETA10 if (Succeeded(result)) { @@ -251,7 +251,7 @@ inline Tgl::Result MeshImpl::GetTexture(TextureImpl** ppTexture) // FUNCTION: LEGO1 0x100a4330 // FUNCTION: BETA10 0x10170820 -Tgl::Result MeshImpl::GetTexture(Texture*& rpTexture) +Result MeshImpl::GetTexture(Texture*& rpTexture) { assert(m_data); diff --git a/LEGO1/tgl/d3drm/meshbuilder.cpp b/LEGO1/tgl/d3drm/meshbuilder.cpp index 18701001..9111e7fd 100644 --- a/LEGO1/tgl/d3drm/meshbuilder.cpp +++ b/LEGO1/tgl/d3drm/meshbuilder.cpp @@ -15,6 +15,7 @@ void* MeshBuilderImpl::ImplementationDataPtr() } // FUNCTION: LEGO1 0x100a3840 +// FUNCTION: BETA10 0x1016ca40 Mesh* MeshBuilderImpl::CreateMesh( unsigned int faceCount, unsigned int vertexCount, @@ -26,6 +27,8 @@ Mesh* MeshBuilderImpl::CreateMesh( ShadingModel shadingModel ) { + assert(m_data); + MeshImpl* pMeshImpl = new MeshImpl; if (CreateMeshImpl( pMeshImpl, @@ -45,63 +48,67 @@ Mesh* MeshBuilderImpl::CreateMesh( return pMeshImpl; } -inline Tgl::Result CreateMesh( +// FUNCTION: BETA10 0x1016fef0 +inline Result CreateMesh( IDirect3DRMMesh* pD3DRM, - unsigned int faceCount, - unsigned int vertexCount, - float (*pPositions)[3], - float (*pNormals)[3], - float (*pTextureCoordinates)[2], - unsigned int (*pFaceIndices)[3], - unsigned int (*pTextureIndices)[3], + unsigned int p_numFaces, + unsigned int p_numVertices, + float(*p_positions), + float(*p_normals), + float(*p_textureCoordinates), + unsigned int (*p_faceIndices)[3], + unsigned int (*p_textureIndices)[3], ShadingModel shadingModel, MeshImpl::MeshDataType& rpMesh ) { - unsigned int* faceIndices = (unsigned int*) pFaceIndices; + unsigned short* faceIndices = (unsigned short*) p_faceIndices; D3DRMGROUPINDEX groupIndex = 0; - int count = faceCount * 3; - int index = 0; + int faceCount = p_numFaces * 3; + int count = 0; - unsigned int* fData = new unsigned int[count]; + unsigned int* fData = new unsigned int[faceCount]; - D3DRMVERTEX* vertices = new D3DRMVERTEX[vertexCount]; - memset(vertices, 0, sizeof(*vertices) * vertexCount); + D3DRMVERTEX* vertices = new D3DRMVERTEX[p_numVertices]; + memset(vertices, 0, sizeof(*vertices) * p_numVertices); rpMesh = new MeshImpl::MeshData; rpMesh->groupMesh = pD3DRM; - for (int i = 0; i < count; i++) { - if ((*((unsigned short*) &faceIndices[i] + 1) >> 0x0f) & 0x01) { - unsigned int j = *(unsigned short*) &faceIndices[i]; - vertices[index].position.x = pPositions[j][0]; - vertices[index].position.y = pPositions[j][1]; - vertices[index].position.z = pPositions[j][2]; - j = *((unsigned short*) &faceIndices[i] + 1) & MAXSHORT; - vertices[index].normal.x = pNormals[j][0]; - vertices[index].normal.y = pNormals[j][1]; - vertices[index].normal.z = pNormals[j][2]; + for (int i = 0; i < faceCount; i++) { + if (((faceIndices[2 * i + 1]) >> 0x0f) & 0x01) { + unsigned int j = 3 * faceIndices[2 * i]; + vertices[count].position.x = p_positions[j]; + vertices[count].position.y = p_positions[j + 1]; + vertices[count].position.z = p_positions[j + 2]; - if (pTextureIndices != NULL && pTextureCoordinates != NULL) { - j = ((unsigned int*) pTextureIndices)[i]; - vertices[index].tu = pTextureCoordinates[j][0]; - vertices[index].tv = pTextureCoordinates[j][1]; + int k = 3 * (faceIndices[2 * i + 1] & MAXSHORT); + vertices[count].normal.x = p_normals[k]; + vertices[count].normal.y = p_normals[k + 1]; + vertices[count].normal.z = p_normals[k + 2]; + + if (p_textureIndices != NULL && p_textureCoordinates != NULL) { + int kk = 2 * ((unsigned int*) p_textureIndices)[i]; + vertices[count].tu = p_textureCoordinates[kk]; + vertices[count].tv = p_textureCoordinates[kk + 1]; } - fData[i] = index; - index++; + fData[i] = count; + count++; } else { - fData[i] = *(unsigned short*) &faceIndices[i]; + fData[i] = faceIndices[2 * i]; } } - Tgl::Result result; - result = ResultVal(pD3DRM->AddGroup(vertexCount, faceCount, 3, (long unsigned int*)fData, &groupIndex)); + assert(count == (int) p_numVertices); + + Result result; + result = ResultVal(pD3DRM->AddGroup(p_numVertices, p_numFaces, 3, fData, &groupIndex)); if (Succeeded(result)) { rpMesh->groupIndex = groupIndex; - result = ResultVal(pD3DRM->SetVertices(groupIndex, 0, vertexCount, vertices)); + result = ResultVal(pD3DRM->SetVertices(groupIndex, 0, p_numVertices, vertices)); } if (!Succeeded(result)) { @@ -112,6 +119,7 @@ inline Tgl::Result CreateMesh( } else { result = MeshSetTextureMappingMode(rpMesh, PerspectiveCorrect); + assert(Succeeded(result)); } if (fData != NULL) { @@ -125,7 +133,8 @@ inline Tgl::Result CreateMesh( return result; } -inline Tgl::Result MeshBuilderImpl::CreateMeshImpl( +// FUNCTION: BETA10 0x1016fe40 +inline Result MeshBuilderImpl::CreateMeshImpl( MeshImpl* pMeshImpl, unsigned int faceCount, unsigned int vertexCount, @@ -137,13 +146,16 @@ inline Tgl::Result MeshBuilderImpl::CreateMeshImpl( ShadingModel shadingModel ) { + assert(m_data); + assert(!pMeshImpl->ImplementationData()); + return ::CreateMesh( m_data, faceCount, vertexCount, - pPositions, - pNormals, - pTextureCoordinates, + reinterpret_cast(pPositions), + reinterpret_cast(pNormals), + reinterpret_cast(pTextureCoordinates), pFaceIndices, pTextureIndices, shadingModel, @@ -152,10 +164,10 @@ inline Tgl::Result MeshBuilderImpl::CreateMeshImpl( } // FUNCTION: BETA10 0x1016e060 -inline Tgl::Result MeshBuilderGetBoundingBox(IDirect3DRMMesh* pMesh, float min[3], float max[3]) +inline Result MeshBuilderGetBoundingBox(IDirect3DRMMesh* pMesh, float min[3], float max[3]) { D3DRMBOX box; - Tgl::Result result = ResultVal(pMesh->GetBox(&box)); + Result result = ResultVal(pMesh->GetBox(&box)); if (Succeeded(result)) { min[0] = box.min.x; min[1] = box.min.y; @@ -169,7 +181,7 @@ inline Tgl::Result MeshBuilderGetBoundingBox(IDirect3DRMMesh* pMesh, float min[3 // FUNCTION: LEGO1 0x100a3ae0 // FUNCTION: BETA10 0x1016ce00 -Tgl::Result MeshBuilderImpl::GetBoundingBox(float min[3], float max[3]) const +Result MeshBuilderImpl::GetBoundingBox(float min[3], float max[3]) const { assert(m_data); diff --git a/LEGO1/tgl/d3drm/view.cpp b/LEGO1/tgl/d3drm/view.cpp index 4a000178..92e5e107 100644 --- a/LEGO1/tgl/d3drm/view.cpp +++ b/LEGO1/tgl/d3drm/view.cpp @@ -495,8 +495,8 @@ Result ViewImpl::ForceUpdate(unsigned int x, unsigned int y, unsigned int width, // FUNCTION: BETA10 0x101710f0 inline Result ViewImpl::Pick( - unsigned int x, - unsigned int y, + int x, + int y, const GroupImpl** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, @@ -519,8 +519,8 @@ inline Result ViewImpl::Pick( // FUNCTION: LEGO1 0x100a30c0 // FUNCTION: BETA10 0x1016ee10 Result ViewImpl::Pick( - unsigned int x, - unsigned int y, + int x, + int y, const Group** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, diff --git a/LEGO1/tgl/tgl.h b/LEGO1/tgl/tgl.h index aabe6c96..2f8ab645 100644 --- a/LEGO1/tgl/tgl.h +++ b/LEGO1/tgl/tgl.h @@ -257,8 +257,8 @@ class View : public Object { // output parameter // size of rppPickedGroups virtual Result Pick( - unsigned int x, - unsigned int y, + int x, + int y, const Group** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, diff --git a/LEGO1/viewmanager/viewmanager.cpp b/LEGO1/viewmanager/viewmanager.cpp index 721ec247..9ec2da58 100644 --- a/LEGO1/viewmanager/viewmanager.cpp +++ b/LEGO1/viewmanager/viewmanager.cpp @@ -499,7 +499,7 @@ float ViewManager::ProjectedSize(const BoundingSphere& p_bounding_sphere) } // FUNCTION: LEGO1 0x100a6e00 -ViewROI* ViewManager::Pick(Tgl::View* p_view, unsigned int x, unsigned int y) +ViewROI* ViewManager::Pick(Tgl::View* p_view, int x, int y) { LPDIRECT3DRMPICKEDARRAY picked = NULL; ViewROI* result = NULL; diff --git a/LEGO1/viewmanager/viewmanager.h b/LEGO1/viewmanager/viewmanager.h index 2fdb9afb..ee068658 100644 --- a/LEGO1/viewmanager/viewmanager.h +++ b/LEGO1/viewmanager/viewmanager.h @@ -33,7 +33,7 @@ class ViewManager { void RemoveROIDetailFromScene(ViewROI* p_roi); void SetPOVSource(const OrientableROI* point_of_view); float ProjectedSize(const BoundingSphere& p_bounding_sphere); - ViewROI* Pick(Tgl::View* p_view, unsigned int x, unsigned int y); + ViewROI* Pick(Tgl::View* p_view, int x, int y); void SetResolution(int width, int height); void SetFrustrum(float fov, float front, float back); inline void ManageVisibilityAndDetailRecursively(ViewROI* p_from, int p_lodLevel); diff --git a/LEGO1/viewmanager/viewroi.cpp b/LEGO1/viewmanager/viewroi.cpp index 787e9078..05f636b6 100644 --- a/LEGO1/viewmanager/viewroi.cpp +++ b/LEGO1/viewmanager/viewroi.cpp @@ -16,65 +16,60 @@ float ViewROI::IntrinsicImportance() const } // for now // FUNCTION: LEGO1 0x100a9ec0 +// FUNCTION: BETA10 0x1018c740 Tgl::Group* ViewROI::GetGeometry() { return geometry; } // FUNCTION: LEGO1 0x100a9ed0 +// FUNCTION: BETA10 0x1018c760 const Tgl::Group* ViewROI::GetGeometry() const { return geometry; } // FUNCTION: LEGO1 0x100a9ee0 +// FUNCTION: BETA10 0x1018c780 void ViewROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& parent2world) { OrientableROI::UpdateWorldDataWithTransformAndChildren(parent2world); + SetGeometryTransformation(); +} +// FUNCTION: BETA10 0x1018c7b0 +inline void ViewROI::SetGeometryTransformation() +{ if (geometry) { Tgl::FloatMatrix4 matrix; Matrix4 in(matrix); SETMAT4(in, m_local2world); - Tgl::Result result = geometry->SetTransformation(matrix); - // assert(Tgl::Succeeded(result)); + geometry->SetTransformation(matrix); } } // FUNCTION: LEGO1 0x100a9fc0 +// FUNCTION: BETA10 0x1018cad0 void ViewROI::UpdateWorldDataWithTransform(const Matrix4& p_transform) { OrientableROI::UpdateWorldDataWithTransform(p_transform); - if (geometry) { - Tgl::FloatMatrix4 matrix; - Matrix4 in(matrix); - SETMAT4(in, m_local2world); - geometry->SetTransformation(matrix); - } + SetGeometryTransformation(); } // FUNCTION: LEGO1 0x100aa0a0 +// FUNCTION: BETA10 0x1018cb00 void ViewROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform) { OrientableROI::SetLocal2WorldWithWorldDataUpdate(p_transform); - if (geometry) { - Tgl::FloatMatrix4 matrix; - Matrix4 in(matrix); - SETMAT4(in, m_local2world); - geometry->SetTransformation(matrix); - } + SetGeometryTransformation(); } // FUNCTION: LEGO1 0x100aa180 +// FUNCTION: BETA10 0x1018cb30 void ViewROI::UpdateWorldData() { OrientableROI::UpdateWorldData(); - if (geometry) { - Tgl::FloatMatrix4 matrix; - Matrix4 in(matrix); - SETMAT4(in, m_local2world); - geometry->SetTransformation(matrix); - } + SetGeometryTransformation(); } // FUNCTION: LEGO1 0x100aa500 diff --git a/LEGO1/viewmanager/viewroi.h b/LEGO1/viewmanager/viewroi.h index 63e82154..b7ba9564 100644 --- a/LEGO1/viewmanager/viewroi.h +++ b/LEGO1/viewmanager/viewroi.h @@ -13,6 +13,7 @@ */ // VTABLE: LEGO1 0x100dbe70 +// VTABLE: BETA10 0x101c3908 // SIZE 0xe4 class ViewROI : public OrientableROI { public: @@ -21,6 +22,7 @@ class ViewROI : public OrientableROI { c_lodLevelInvisible = -2, }; + // FUNCTION: BETA10 0x1018c5e0 ViewROI(Tgl::Renderer* pRenderer, ViewLODList* lodList) { SetLODList(lodList); @@ -29,6 +31,7 @@ class ViewROI : public OrientableROI { } // FUNCTION: LEGO1 0x100a9e20 + // FUNCTION: BETA10 0x1018c680 ~ViewROI() override { // SetLODList() will decrease refCount of LODList @@ -36,6 +39,7 @@ class ViewROI : public OrientableROI { delete geometry; } + // FUNCTION: BETA10 0x1007b540 void SetLODList(ViewLODList* lodList) { // ??? inherently type unsafe - kind of... because, now, ROI @@ -69,6 +73,8 @@ class ViewROI : public OrientableROI { protected: void UpdateWorldDataWithTransformAndChildren(const Matrix4& parent2world) override; // vtable+0x28 + void SetGeometryTransformation(); + Tgl::Group* geometry; // 0xdc int m_lodLevel; // 0xe0 }; diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..0a041280 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md index 955853d0..33dbd232 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ Please note: this project is dedicated to achieving platform independence withou | macOS | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | | [Web](https://isle.pizza) | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) | +We are actively working to support more platforms. If you have experience with a particular platform, we encourage you to contribute to `isle-portable`. You can find a [list of ongoing efforts](https://github.com/isledecomp/isle-portable/wiki/Work%E2%80%90in%E2%80%90progress-ports) in our Wiki. + ### Library substitutions To achieve our goal of platform independence, we need to replace any Windows-only libraries with platform-independent alternatives. This ensures that our codebase remains versatile and compatible across various systems. The following table serves as an overview of major libraries / subsystems and their chosen replacements. For any significant changes or additions, it's recommended to discuss them with the team on the Matrix chat first to ensure consistency and alignment with our project's objectives. @@ -32,13 +34,19 @@ To achieve our goal of platform independence, we need to replace any Windows-onl | WinMM, DirectSound (Audio) | [SDL3](https://www.libsdl.org/), [miniaudio](https://miniaud.io/) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Aaudio%5D%22&type=code) | | DirectDraw (2D video) | [SDL3](https://www.libsdl.org/) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A2d%5D%22&type=code) | | [Smacker](https://github.com/isledecomp/isle/tree/master/3rdparty/smacker) | [libsmacker](https://github.com/foxtacles/libsmacker) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable%20%22%2F%2F%20%5Blibrary%3Alibsmacker%5D%22&type=code) | -| Direct3D (3D video) | [SDL3](https://www.libsdl.org/), D3D9, OpenGL, OpenGL ES, Software | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A3d%5D%22&type=code) | +| Direct3D (3D video) | [SDL3 (Vulkan, Metal, D3D12)](https://www.libsdl.org/), D3D9, OpenGL, OpenGL ES, Software | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A3d%5D%22&type=code) | | Direct3D Retained Mode | Custom re-implementation | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Aretained%5D%22&type=code) | | [SmartHeap](https://github.com/isledecomp/isle/tree/master/3rdparty/smartheap) | Default memory allocator | - | - | ## Building -This project uses the [CMake](https://cmake.org/) build system, which allows for a high degree of versatility regarding compilers and development environments. Please refer to the [GitHub action](/.github/workflows//build.yml) for guidance. +This project uses the [CMake](https://cmake.org/) build system, which allows for a high degree of versatility regarding compilers and development environments. Please refer to the [GitHub action](/.github/workflows//ci.yml) for guidance. + +## Usage + +**An existing copy of LEGO Island is required to use this project.** + +As it stands, the builds provided in the Releases tab are for developers; as such, they may not work properly for end-users. Work is currently ongoing to create workable release builds ready for gameplay and general use by end-users. If you are technically inclined, you may find it easiest to compile the project yourself to get it running at this current point in time. ## Contributing diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index 5017f456..a1939441 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -27,6 +27,10 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL src/d3drm/backends/software/renderer.cpp ) +target_compile_definitions(miniwin PRIVATE + $<$:DEBUG> +) + find_package(OpenGL) find_package(GLEW) if(OpenGL_FOUND AND GLEW_FOUND) diff --git a/miniwin/include/miniwin/d3drm.h b/miniwin/include/miniwin/d3drm.h index 365046a5..dea6e0f7 100644 --- a/miniwin/include/miniwin/d3drm.h +++ b/miniwin/include/miniwin/d3drm.h @@ -181,10 +181,10 @@ struct IDirect3DRMMesh : public IDirect3DRMVisual { virtual HRESULT Clone(int flags, GUID iid, void** object) = 0; virtual HRESULT GetBox(D3DRMBOX* box) = 0; virtual HRESULT AddGroup( - int vertexCount, - int faceCount, - int vertexPerFace, - DWORD* faceBuffer, + unsigned int vertexCount, + unsigned int faceCount, + unsigned int vertexPerFace, + unsigned int* faceBuffer, D3DRMGROUPINDEX* groupIndex ) = 0; virtual HRESULT GetGroup( diff --git a/miniwin/include/miniwin/ddraw.h b/miniwin/include/miniwin/ddraw.h index 55a95f8f..1e3fd17f 100644 --- a/miniwin/include/miniwin/ddraw.h +++ b/miniwin/include/miniwin/ddraw.h @@ -159,12 +159,15 @@ enum class DDBltFastFlags : uint32_t { }; ENABLE_BITMASK_OPERATORS(DDBltFastFlags) -#define DDLOCK_WAIT DDLockFlags::WAIT #define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR +#define DDLOCK_WAIT DDLockFlags::WAIT +#define DDLOCK_WRITEONLY DDLockFlags::WRITEONLY enum class DDLockFlags : uint32_t { - SURFACEMEMORYPTR, - WAIT, + SURFACEMEMORYPTR = 0, + WAIT = 1 << 0, + WRITEONLY = 1 << 5, }; +ENABLE_BITMASK_OPERATORS(DDLockFlags) #define DDSCL_FULLSCREEN DDSCLFlags::FULLSCREEN #define DDSCL_ALLOWREBOOT DDSCLFlags::ALLOWREBOOT diff --git a/miniwin/include/miniwin/windows.h b/miniwin/include/miniwin/windows.h index bd54249d..83726998 100644 --- a/miniwin/include/miniwin/windows.h +++ b/miniwin/include/miniwin/windows.h @@ -46,7 +46,6 @@ #define CLIP_DEFAULT_PRECIS 0 #define DEFAULT_QUALITY 0 #define ETO_OPAQUE 0x0002 -#define FF_DONTCARE 0x00000000 #define RASTERCAPS 0x00000000 #define RC_PALETTE 0x0100 #define SIZEPALETTE 104 diff --git a/miniwin/src/d3drm/backends/directx9/actual.cpp b/miniwin/src/d3drm/backends/directx9/actual.cpp index 30a3360c..33dc2864 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.cpp +++ b/miniwin/src/d3drm/backends/directx9/actual.cpp @@ -11,19 +11,22 @@ static LPDIRECT3D9 g_d3d; static LPDIRECT3DDEVICE9 g_device; static HWND g_hwnd; -static LPDIRECT3DTEXTURE9 g_renderTargetTex; -static LPDIRECT3DSURFACE9 g_renderTargetSurf; -static LPDIRECT3DSURFACE9 g_oldRenderTarget; -static int m_width; -static int m_height; -static std::vector m_lights; -static Matrix4x4 m_projection; +static int g_width; +static int g_height; +static int g_virtualWidth; +static int g_virtualHeight; +static bool g_hasScene = false; +static std::vector g_lights; +static Matrix4x4 g_projection; +static ViewportTransform g_viewportTransform; bool Actual_Initialize(void* hwnd, int width, int height) { g_hwnd = (HWND) hwnd; - m_width = width; - m_height = height; + g_width = width; + g_height = height; + g_virtualWidth = width; + g_virtualHeight = height; g_d3d = Direct3DCreate9(D3D_SDK_VERSION); if (!g_d3d) { return false; @@ -52,45 +55,17 @@ bool Actual_Initialize(void* hwnd, int width, int height) return false; } - hr = g_device->CreateTexture( - width, - height, - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &g_renderTargetTex, - nullptr - ); if (FAILED(hr)) { g_device->Release(); g_d3d->Release(); return false; } - hr = g_renderTargetTex->GetSurfaceLevel(0, &g_renderTargetSurf); - if (FAILED(hr)) { - g_renderTargetTex->Release(); - g_device->Release(); - g_d3d->Release(); - return false; - } - - g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1); - return true; } void Actual_Shutdown() { - if (g_renderTargetSurf) { - g_renderTargetSurf->Release(); - g_renderTargetSurf = nullptr; - } - if (g_renderTargetTex) { - g_renderTargetTex->Release(); - g_renderTargetTex = nullptr; - } if (g_device) { g_device->Release(); g_device = nullptr; @@ -103,12 +78,12 @@ void Actual_Shutdown() void Actual_PushLights(const BridgeSceneLight* lightsArray, size_t count) { - m_lights.assign(lightsArray, lightsArray + count); + g_lights.assign(lightsArray, lightsArray + count); } void Actual_SetProjection(const Matrix4x4* projection, float front, float back) { - memcpy(&m_projection, projection, sizeof(Matrix4x4)); + memcpy(&g_projection, projection, sizeof(Matrix4x4)); } IDirect3DTexture9* UploadSurfaceToD3DTexture(SDL_Surface* surface) @@ -188,18 +163,71 @@ void UploadMeshBuffers( cache.ibo->Unlock(); } -constexpr float PI = 3.14159265358979323846f; - -void SetupLights() +void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform) { + g_width = width; + g_height = height; + g_viewportTransform = viewportTransform; + + D3DPRESENT_PARAMETERS pp = {}; + pp.Windowed = TRUE; + pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + pp.hDeviceWindow = g_hwnd; + pp.BackBufferFormat = D3DFMT_A8R8G8B8; + pp.BackBufferWidth = width; + pp.BackBufferHeight = height; + pp.EnableAutoDepthStencil = TRUE; + pp.AutoDepthStencilFormat = D3DFMT_D24S8; + g_device->Reset(&pp); +} + +void StartScene() +{ + if (g_hasScene) { + return; + } + g_device->BeginScene(); + g_hasScene = true; +} + +void Actual_Clear(float r, float g, float b) +{ + StartScene(); + + g_device->Clear( + 0, + nullptr, + D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_ARGB(255, static_cast(r * 255), static_cast(g * 255), static_cast(b * 255)), + 1.0f, + 0 + ); +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +uint32_t Actual_BeginFrame() +{ + StartScene(); + g_device->SetRenderState(D3DRS_LIGHTING, TRUE); + g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + + g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + for (DWORD i = 0; i < 8; ++i) { g_device->LightEnable(i, FALSE); } DWORD lightIdx = 0; - for (const auto& l : m_lights) { + for (const auto& l : g_lights) { if (lightIdx >= 8) { break; } @@ -235,30 +263,16 @@ void SetupLights() } light.Falloff = 1.0f; - light.Phi = PI; - light.Theta = PI / 2; + light.Phi = M_PI; + light.Theta = M_PI / 2; if (SUCCEEDED(g_device->SetLight(lightIdx, &light))) { g_device->LightEnable(lightIdx, TRUE); } ++lightIdx; } -} -uint32_t Actual_BeginFrame() -{ - g_device->GetRenderTarget(0, &g_oldRenderTarget); - g_device->SetRenderTarget(0, g_renderTargetSurf); - - g_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0); - - g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); - g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - - g_device->BeginScene(); - - SetupLights(); + g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1); return D3D_OK; } @@ -286,15 +300,19 @@ D3DMATRIX ToD3DMATRIX(const Matrix4x4& in) void Actual_SubmitDraw( const D3D9MeshCacheEntry* mesh, const Matrix4x4* modelViewMatrix, + const Matrix4x4* worldMatrix, + const Matrix4x4* viewMatrix, const Matrix3x3* normalMatrix, const Appearance* appearance, IDirect3DTexture9* texture ) { - D3DMATRIX worldView = ToD3DMATRIX(*modelViewMatrix); - g_device->SetTransform(D3DTS_WORLD, &worldView); - D3DMATRIX proj = ToD3DMATRIX(m_projection); + D3DMATRIX proj = ToD3DMATRIX(g_projection); g_device->SetTransform(D3DTS_PROJECTION, &proj); + D3DMATRIX view = ToD3DMATRIX(*viewMatrix); + g_device->SetTransform(D3DTS_VIEW, &view); + D3DMATRIX world = ToD3DMATRIX(*worldMatrix); + g_device->SetTransform(D3DTS_WORLD, &world); D3DMATERIAL9 mat = {}; mat.Diffuse.r = appearance->color.r / 255.0f; @@ -342,44 +360,149 @@ void Actual_SubmitDraw( g_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mesh->vertexCount, 0, mesh->indexCount / 3); } -uint32_t Actual_FinalizeFrame(void* pixels, int pitch) +uint32_t Actual_Flip() { g_device->EndScene(); - - g_device->SetRenderTarget(0, g_oldRenderTarget); - g_oldRenderTarget->Release(); - - LPDIRECT3DSURFACE9 sysMemSurf; - HRESULT hr = - g_device - ->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysMemSurf, nullptr); - if (FAILED(hr)) { - return hr; - } - - hr = g_device->GetRenderTargetData(g_renderTargetSurf, sysMemSurf); - if (FAILED(hr)) { - sysMemSurf->Release(); - return hr; - } - - D3DLOCKED_RECT lockedRect; - hr = sysMemSurf->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY); - if (FAILED(hr)) { - sysMemSurf->Release(); - return hr; - } - - BYTE* src = static_cast(lockedRect.pBits); - BYTE* dst = static_cast(pixels); - int copyWidth = m_width * 4; - - for (int y = 0; y < m_height; y++) { - memcpy(dst + y * pitch, src + y * lockedRect.Pitch, copyWidth); - } - - sysMemSurf->UnlockRect(); - sysMemSurf->Release(); - - return hr; + g_hasScene = false; + return g_device->Present(nullptr, nullptr, nullptr, nullptr); +} + +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + StartScene(); + + float left = -g_viewportTransform.offsetX / g_viewportTransform.scale; + float right = (g_width - g_viewportTransform.offsetX) / g_viewportTransform.scale; + float top = -g_viewportTransform.offsetY / g_viewportTransform.scale; + float bottom = (g_height - g_viewportTransform.offsetY) / g_viewportTransform.scale; + + auto virtualToScreenX = [&](float x) { return ((x - left) / (right - left)) * g_width; }; + auto virtualToScreenY = [&](float y) { return ((y - top) / (bottom - top)) * g_height; }; + + float x1_virtual = static_cast(dstRect.x); + float y1_virtual = static_cast(dstRect.y); + float x2_virtual = x1_virtual + dstRect.w; + float y2_virtual = y1_virtual + dstRect.h; + + float x1 = virtualToScreenX(x1_virtual); + float y1 = virtualToScreenY(y1_virtual); + float x2 = virtualToScreenX(x2_virtual); + float y2 = virtualToScreenY(y2_virtual); + + D3DMATRIX identity = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + g_device->SetTransform(D3DTS_PROJECTION, &identity); + g_device->SetTransform(D3DTS_VIEW, &identity); + g_device->SetTransform(D3DTS_WORLD, &identity); + + g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + + g_device->SetRenderState(D3DRS_ZENABLE, FALSE); + g_device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + g_device->SetRenderState(D3DRS_LIGHTING, FALSE); + g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + g_device->SetTexture(0, texture); + g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + D3DSURFACE_DESC texDesc; + texture->GetLevelDesc(0, &texDesc); + float texW = static_cast(texDesc.Width); + float texH = static_cast(texDesc.Height); + + float u1 = static_cast(srcRect.x) / texW; + float v1 = static_cast(srcRect.y) / texH; + float u2 = static_cast(srcRect.x + srcRect.w) / texW; + float v2 = static_cast(srcRect.y + srcRect.h) / texH; + + struct Vertex { + float x, y, z, rhw; + float u, v; + }; + + Vertex quad[4] = { + {x1, y1, 0.0f, 1.0f, u1, v1}, + {x2, y1, 0.0f, 1.0f, u2, v1}, + {x2, y2, 0.0f, 1.0f, u2, v2}, + {x1, y2, 0.0f, 1.0f, u1, v2}, + }; + + g_device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + g_device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, sizeof(Vertex)); +} + +uint32_t Actual_Download(SDL_Surface* target) +{ + IDirect3DSurface9* backBuffer; + HRESULT hr = g_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); + if (FAILED(hr)) { + return hr; + } + + IDirect3DSurface9* sysMemSurface; + hr = g_device->CreateOffscreenPlainSurface( + g_width, + g_height, + D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM, + &sysMemSurface, + nullptr + ); + if (FAILED(hr)) { + backBuffer->Release(); + return hr; + } + + hr = g_device->GetRenderTargetData(backBuffer, sysMemSurface); + backBuffer->Release(); + if (FAILED(hr)) { + sysMemSurface->Release(); + return hr; + } + + D3DLOCKED_RECT locked; + hr = sysMemSurface->LockRect(&locked, nullptr, D3DLOCK_READONLY); + if (FAILED(hr)) { + sysMemSurface->Release(); + return hr; + } + + SDL_Surface* srcSurface = + SDL_CreateSurfaceFrom(g_width, g_height, SDL_PIXELFORMAT_ARGB8888, locked.pBits, locked.Pitch); + if (!srcSurface) { + sysMemSurface->UnlockRect(); + sysMemSurface->Release(); + return E_FAIL; + } + + float srcAspect = static_cast(g_width) / g_height; + float dstAspect = static_cast(target->w) / target->h; + + SDL_Rect srcRect; + if (srcAspect > dstAspect) { + int cropWidth = static_cast(g_height * dstAspect); + srcRect = {(g_width - cropWidth) / 2, 0, cropWidth, g_height}; + } + else { + int cropHeight = static_cast(g_width / dstAspect); + srcRect = {0, (g_height - cropHeight) / 2, g_width, cropHeight}; + } + + if (SDL_BlitSurfaceScaled(srcSurface, &srcRect, target, nullptr, SDL_SCALEMODE_NEAREST)) { + SDL_DestroySurface(srcSurface); + sysMemSurface->UnlockRect(); + sysMemSurface->Release(); + return E_FAIL; + } + + SDL_DestroySurface(srcSurface); + sysMemSurface->UnlockRect(); + sysMemSurface->Release(); + + return D3D_OK; } diff --git a/miniwin/src/d3drm/backends/directx9/actual.h b/miniwin/src/d3drm/backends/directx9/actual.h index 9080878d..e3369ec9 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.h +++ b/miniwin/src/d3drm/backends/directx9/actual.h @@ -69,8 +69,14 @@ void Actual_EnableTransparency(); void Actual_SubmitDraw( const D3D9MeshCacheEntry* mesh, const Matrix4x4* modelViewMatrix, + const Matrix4x4* worldMatrix, + const Matrix4x4* viewMatrix, const Matrix3x3* normalMatrix, const Appearance* appearance, IDirect3DTexture9* texture ); -uint32_t Actual_FinalizeFrame(void* pixels, int pitch); +void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform); +void Actual_Clear(float r, float g, float b); +uint32_t Actual_Flip(); +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect); +uint32_t Actual_Download(SDL_Surface* target); diff --git a/miniwin/src/d3drm/backends/directx9/renderer.cpp b/miniwin/src/d3drm/backends/directx9/renderer.cpp index f0207041..574939f5 100644 --- a/miniwin/src/d3drm/backends/directx9/renderer.cpp +++ b/miniwin/src/d3drm/backends/directx9/renderer.cpp @@ -20,14 +20,18 @@ Direct3DRMRenderer* DirectX9Renderer::Create(DWORD width, DWORD height) return new DirectX9Renderer(width, height); } -DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height) : m_width(width), m_height(height) +DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height) { + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; Actual_Initialize( SDL_GetPointerProperty(SDL_GetWindowProperties(DDWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL), width, height ); - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ARGB8888); + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); } DirectX9Renderer::~DirectX9Renderer() @@ -212,16 +216,6 @@ Uint32 DirectX9Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshG return static_cast(m_meshs.size() - 1); } -DWORD DirectX9Renderer::GetWidth() -{ - return m_width; -} - -DWORD DirectX9Renderer::GetHeight() -{ - return m_height; -} - void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -253,6 +247,8 @@ void DirectX9Renderer::EnableTransparency() void DirectX9Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -261,17 +257,46 @@ void DirectX9Renderer::SubmitDraw( if (appearance.textureId != NO_TEXTURE_ID) { texture = m_textures[appearance.textureId].dxTexture; } - Actual_SubmitDraw(&m_meshs[meshId], &modelViewMatrix, &normalMatrix, &appearance, texture); + Actual_SubmitDraw( + &m_meshs[meshId], + &modelViewMatrix, + &worldMatrix, + &viewMatrix, + &normalMatrix, + &appearance, + texture + ); } HRESULT DirectX9Renderer::FinalizeFrame() { - HRESULT hr = Actual_FinalizeFrame(m_renderedImage->pixels, m_renderedImage->pitch); - if (hr != DD_OK) { - return hr; - } - - // Composite onto SDL backbuffer - SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); - return hr; + return DD_OK; +} + +void DirectX9Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + Actual_Resize(width, height, viewportTransform); +} + +void DirectX9Renderer::Clear(float r, float g, float b) +{ + Actual_Clear(r, g, b); +} + +void DirectX9Renderer::Flip() +{ + Actual_Flip(); +} + +void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect); +} + +void DirectX9Renderer::Download(SDL_Surface* target) +{ + Actual_Download(target); } diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index 815d854b..cc415de8 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -15,17 +15,24 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_Window* window = DDWindow; bool testWindow = false; if (!window) { - window = SDL_CreateWindow("OpenGL 1.2 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + window = SDL_CreateWindow("OpenGL 1.1 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + if (!window) { + SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); + return nullptr; + } testWindow = true; } + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GLContext context = SDL_GL_CreateContext(window); if (!context) { + SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError()); if (testWindow) { SDL_DestroyWindow(window); } @@ -33,18 +40,16 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height) } if (!SDL_GL_MakeCurrent(window, context)) { - return nullptr; - } - - GLenum err = glewInit(); - if (err != GLEW_OK) { + SDL_Log("SDL_GL_MakeCurrent: %s", SDL_GetError()); if (testWindow) { SDL_DestroyWindow(window); } return nullptr; } - if (!GLEW_EXT_framebuffer_object) { + GLenum err = glewInit(); + if (err != GLEW_OK) { + SDL_Log("glewInit: %s", glewGetErrorString(err)); if (testWindow) { SDL_DestroyWindow(window); } @@ -53,65 +58,37 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height) glEnable(GL_CULL_FACE); glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - // Setup FBO - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // Create color texture - GLuint colorTex; - glGenTextures(1, &colorTex); - glBindTexture(GL_TEXTURE_2D, colorTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); - - // Create depth renderbuffer - GLuint depthRb; - glGenRenderbuffers(1, &depthRb); - glBindRenderbuffer(GL_RENDERBUFFER, depthRb); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - return nullptr; - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glFrontFace(GL_CW); if (testWindow) { SDL_DestroyWindow(window); } - return new OpenGL1Renderer(width, height, context, fbo, colorTex, depthRb); + return new OpenGL1Renderer(width, height, context); } -OpenGL1Renderer::OpenGL1Renderer( - DWORD width, - DWORD height, - SDL_GLContext context, - GLuint fbo, - GLuint colorTex, - GLuint depthRb -) - : m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb) +OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context) : m_context(context) { - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888); + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); m_useVBOs = GLEW_ARB_vertex_buffer_object; } OpenGL1Renderer::~OpenGL1Renderer() { SDL_DestroySurface(m_renderedImage); - glDeleteFramebuffers(1, &m_fbo); - glDeleteRenderbuffers(1, &m_depthRb); - glDeleteTextures(1, &m_colorTex); } void OpenGL1Renderer::PushLights(const SceneLight* lightsArray, size_t count) { + if (count > 8) { + SDL_Log("Unsupported number of lights (%d)", static_cast(count)); + count = 8; + } + m_lights.assign(lightsArray, lightsArray + count); } @@ -122,7 +99,6 @@ void OpenGL1Renderer::SetFrustumPlanes(const Plane* frustumPlanes) void OpenGL1Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) { memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); - m_projection[1][1] *= -1.0f; // OpenGL is upside down } struct TextureDestroyContextGL { @@ -161,14 +137,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) glGenTextures(1, &tex.glTextureId); glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); tex.version = texture->m_version; } @@ -180,14 +154,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; @@ -260,7 +232,7 @@ GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs) glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); glBufferData(GL_ARRAY_BUFFER, cache.normals.size() * sizeof(D3DVECTOR), cache.normals.data(), GL_STATIC_DRAW); - if (meshGroup.texture != nullptr) { + if (meshGroup.texture) { glGenBuffers(1, &cache.vboTexcoords); glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); glBufferData( @@ -337,16 +309,6 @@ Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGr return (Uint32) (m_meshs.size() - 1); } -DWORD OpenGL1Renderer::GetWidth() -{ - return m_width; -} - -DWORD OpenGL1Renderer::GetHeight() -{ - return m_height; -} - void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -362,14 +324,12 @@ void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) const char* OpenGL1Renderer::GetName() { - return "OpenGL 1.2 HAL"; + return "OpenGL 1.1 HAL"; } HRESULT OpenGL1Renderer::BeginFrame() { - SDL_GL_MakeCurrent(DDWindow, m_context); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glViewport(0, 0, m_width, m_height); + m_dirty = true; glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); @@ -378,16 +338,12 @@ HRESULT OpenGL1Renderer::BeginFrame() glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Disable all lights and reset global ambient for (int i = 0; i < 8; ++i) { glDisable(GL_LIGHT0 + i); } const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient); - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); // Setup lights @@ -462,15 +418,14 @@ void OpenGL1Renderer::EnableTransparency() void OpenGL1Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) { auto& mesh = m_meshs[meshId]; - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadMatrixf(&modelViewMatrix[0][0]); glEnable(GL_NORMALIZE); @@ -496,6 +451,8 @@ void OpenGL1Renderer::SubmitDraw( // Bind texture if present if (appearance.textureId != NO_TEXTURE_ID) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); auto& tex = m_textures[appearance.textureId]; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex.glTextureId); @@ -542,11 +499,130 @@ void OpenGL1Renderer::SubmitDraw( HRESULT OpenGL1Renderer::FinalizeFrame() { - glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Composite onto SDL backbuffer - SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); - return DD_OK; } + +void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + SDL_DestroySurface(m_renderedImage); + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + glViewport(0, 0, m_width, m_height); +} + +void OpenGL1Renderer::Clear(float r, float g, float b) +{ + m_dirty = true; + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(r, g, b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void OpenGL1Renderer::Flip() +{ + if (m_dirty) { + SDL_GL_SwapWindow(DDWindow); + m_dirty = false; + } +} + +void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + m_dirty = true; + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; + float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; + float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; + glOrtho(left, right, bottom, top, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_LIGHTING); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_textures[textureId].glTextureId); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + GLint boundTexture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); + + GLfloat texW, texH; + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW); + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH); + + float u1 = srcRect.x / texW; + float v1 = srcRect.y / texH; + float u2 = (srcRect.x + srcRect.w) / texW; + float v2 = (srcRect.y + srcRect.h) / texH; + + float x1 = (float) dstRect.x; + float y1 = (float) dstRect.y; + float x2 = x1 + dstRect.w; + float y2 = y1 + dstRect.h; + + glBegin(GL_QUADS); + glTexCoord2f(u1, v1); + glVertex2f(x1, y1); + glTexCoord2f(u2, v1); + glVertex2f(x2, y1); + glTexCoord2f(u2, v2); + glVertex2f(x2, y2); + glTexCoord2f(u1, v2); + glVertex2f(x1, y2); + glEnd(); + + // Restore state + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); +} + +void OpenGL1Renderer::Download(SDL_Surface* target) +{ + glFinish(); + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); + + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(target->w * m_viewportTransform.scale), + static_cast(target->h * m_viewportTransform.scale), + }; + + SDL_Surface* bufferClone = SDL_CreateSurface(target->w, target->h, SDL_PIXELFORMAT_RGBA32); + if (!bufferClone) { + SDL_Log("SDL_CreateSurface: %s", SDL_GetError()); + return; + } + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, bufferClone, nullptr, SDL_SCALEMODE_NEAREST); + + // Flip image vertically into target + SDL_Rect rowSrc = {0, 0, bufferClone->w, 1}; + SDL_Rect rowDst = {0, 0, bufferClone->w, 1}; + for (int y = 0; y < bufferClone->h; ++y) { + rowSrc.y = y; + rowDst.y = bufferClone->h - 1 - y; + SDL_BlitSurface(bufferClone, &rowSrc, target, &rowDst); + } + + SDL_DestroySurface(bufferClone); +} diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 94229cc7..3dbabda2 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -41,6 +41,8 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) testWindow = true; } + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GLContext context = SDL_GL_CreateContext(window); if (!context) { if (testWindow) { @@ -50,51 +52,16 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) } if (!SDL_GL_MakeCurrent(window, context)) { + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - // Setup FBO - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // Create color texture - GLuint colorTex; - glGenTextures(1, &colorTex); - glBindTexture(GL_TEXTURE_2D, colorTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); - - // Create depth renderbuffer - GLuint depthRb; - glGenRenderbuffers(1, &depthRb); - glBindRenderbuffer(GL_RENDERBUFFER, depthRb); - const char* extensions = (const char*) glGetString(GL_EXTENSIONS); - if (extensions) { - if (strstr(extensions, "GL_OES_depth24")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, width, height); - } - else if (strstr(extensions, "GL_OES_depth32")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32_OES, width, height); - } - } - else { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); - } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - return nullptr; - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glFrontFace(GL_CW); const char* vertexShaderSource = R"( attribute vec3 a_position; @@ -183,6 +150,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) if (u_useTexture != 0) { vec4 texel = texture2D(u_texture, v_texCoord); finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0); + finalColor.a = texel.a; } gl_FragColor = finalColor; @@ -206,31 +174,23 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) SDL_DestroyWindow(window); } - return new OpenGLES2Renderer(width, height, context, fbo, colorTex, depthRb, shaderProgram); + return new OpenGLES2Renderer(width, height, context, shaderProgram); } -OpenGLES2Renderer::OpenGLES2Renderer( - DWORD width, - DWORD height, - SDL_GLContext context, - GLuint fbo, - GLuint colorTex, - GLuint depthRb, - GLuint shaderProgram -) - : m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb), - m_shaderProgram(shaderProgram) +OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram) + : m_context(context), m_shaderProgram(shaderProgram) { - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888); + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); } OpenGLES2Renderer::~OpenGLES2Renderer() { SDL_DestroySurface(m_renderedImage); - glDeleteFramebuffers(1, &m_fbo); - glDeleteRenderbuffers(1, &m_depthRb); glDeleteProgram(m_shaderProgram); - glDeleteTextures(1, &m_colorTex); } void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count) @@ -250,7 +210,6 @@ void OpenGLES2Renderer::SetFrustumPlanes(const Plane* frustumPlanes) void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) { memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); - m_projection[1][1] *= -1.0f; // OpenGL is upside down } struct TextureDestroyContextGLS2 { @@ -289,14 +248,12 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) glGenTextures(1, &tex.glTextureId); glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); tex.version = texture->m_version; } @@ -308,14 +265,11 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; @@ -323,12 +277,15 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) tex.texture = texture; tex.version = texture->m_version; tex.glTextureId = texId; + tex.width = surf->w; + tex.height = surf->h; AddTextureDestroyCallback(i, texture); return i; } } - m_textures.push_back({texture, texture->m_version, texId}); + m_textures.push_back({texture, texture->m_version, texId, (uint16_t) surf->w, (uint16_t) surf->h}); + SDL_DestroySurface(surf); AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); return (Uint32) (m_textures.size() - 1); } @@ -366,7 +323,6 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup) return v.texCoord; }); } - std::vector positions(vertices.size()); std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { return v.position; @@ -451,16 +407,6 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh return (Uint32) (m_meshs.size() - 1); } -DWORD OpenGLES2Renderer::GetWidth() -{ - return m_width; -} - -DWORD OpenGLES2Renderer::GetHeight() -{ - return m_height; -} - void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -490,9 +436,7 @@ const char* OpenGLES2Renderer::GetName() HRESULT OpenGLES2Renderer::BeginFrame() { - SDL_GL_MakeCurrent(DDWindow, m_context); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glViewport(0, 0, m_width, m_height); + m_dirty = true; glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); @@ -500,9 +444,6 @@ HRESULT OpenGLES2Renderer::BeginFrame() glUseProgram(m_shaderProgram); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - SceneLightGLES2 lightData[3]; int lightCount = std::min(static_cast(m_lights.size()), 3); @@ -531,7 +472,6 @@ HRESULT OpenGLES2Renderer::BeginFrame() glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()), 1, lightData[i].direction); } glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), lightCount); - return DD_OK; } @@ -545,6 +485,8 @@ void OpenGLES2Renderer::EnableTransparency() void OpenGLES2Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -570,6 +512,8 @@ void OpenGLES2Renderer::SubmitDraw( glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId); glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 0); @@ -606,11 +550,168 @@ HRESULT OpenGLES2Renderer::FinalizeFrame() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glUseProgram(0); - glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Composite onto SDL backbuffer - SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); - return DD_OK; } + +void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + SDL_DestroySurface(m_renderedImage); + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + glViewport(0, 0, m_width, m_height); +} + +void OpenGLES2Renderer::Clear(float r, float g, float b) +{ + m_dirty = true; + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(r, g, b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void OpenGLES2Renderer::Flip() +{ + if (m_dirty) { + SDL_GL_SwapWindow(DDWindow); + m_dirty = false; + } +} + +void CreateOrthoMatrix(float left, float right, float bottom, float top, D3DRMMATRIX4D& outMatrix) +{ + float near = -1.0f; + float far = 1.0f; + float rl = right - left; + float tb = top - bottom; + float fn = far - near; + + outMatrix[0][0] = 2.0f / rl; + outMatrix[0][1] = 0.0f; + outMatrix[0][2] = 0.0f; + outMatrix[0][3] = 0.0f; + + outMatrix[1][0] = 0.0f; + outMatrix[1][1] = 2.0f / tb; + outMatrix[1][2] = 0.0f; + outMatrix[1][3] = 0.0f; + + outMatrix[2][0] = 0.0f; + outMatrix[2][1] = 0.0f; + outMatrix[2][2] = -2.0f / fn; + outMatrix[2][3] = 0.0f; + + outMatrix[3][0] = -(right + left) / rl; + outMatrix[3][1] = -(top + bottom) / tb; + outMatrix[3][2] = -(far + near) / fn; + outMatrix[3][3] = 1.0f; +} + +void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + m_dirty = true; + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glUseProgram(m_shaderProgram); + + float color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + float blank[] = {0.0f, 0.0f, 0.0f, 0.0f}; + glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].color"), 1, color); + glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].position"), 1, blank); + glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].direction"), 1, blank); + glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), 1); + + glUniform4f(glGetUniformLocation(m_shaderProgram, "u_color"), 1.0f, 1.0f, 1.0f, 1.0f); + glUniform1f(glGetUniformLocation(m_shaderProgram, "u_shininess"), 0.0f); + + float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; + float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; + float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; + + D3DRMMATRIX4D projection; + CreateOrthoMatrix(left, right, bottom, top, projection); + + D3DRMMATRIX4D identity = {{1.f, 0.f, 0.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}}; + glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_modelViewMatrix"), 1, GL_FALSE, &identity[0][0]); + glUniformMatrix3fv(glGetUniformLocation(m_shaderProgram, "u_normalMatrix"), 1, GL_FALSE, &identity[0][0]); + glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"), 1, GL_FALSE, &projection[0][0]); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glActiveTexture(GL_TEXTURE0); + glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 1); + const GLES2TextureCacheEntry& texture = m_textures[textureId]; + glBindTexture(GL_TEXTURE_2D, texture.glTextureId); + glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + float texW = texture.width; + float texH = texture.height; + + float u1 = srcRect.x / texW; + float v1 = srcRect.y / texH; + float u2 = (srcRect.x + srcRect.w) / texW; + float v2 = (srcRect.y + srcRect.h) / texH; + + float x1 = static_cast(dstRect.x); + float y1 = static_cast(dstRect.y); + float x2 = x1 + dstRect.w; + float y2 = y1 + dstRect.h; + + GLfloat vertices[] = {x1, y1, u1, v1, x2, y1, u2, v1, x1, y2, u1, v2, x2, y2, u2, v2}; + + GLint posLoc = glGetAttribLocation(m_shaderProgram, "a_position"); + GLint texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord"); + + glEnableVertexAttribArray(posLoc); + glEnableVertexAttribArray(texLoc); + + glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices); + glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices + 2); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableVertexAttribArray(posLoc); + glDisableVertexAttribArray(texLoc); + + glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); +} + +void OpenGLES2Renderer::Download(SDL_Surface* target) +{ + glFinish(); + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); + + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(target->w * m_viewportTransform.scale), + static_cast(target->h * m_viewportTransform.scale), + }; + + SDL_Surface* bufferClone = SDL_CreateSurface(target->w, target->h, SDL_PIXELFORMAT_RGBA32); + if (!bufferClone) { + SDL_Log("SDL_CreateSurface: %s", SDL_GetError()); + return; + } + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, bufferClone, nullptr, SDL_SCALEMODE_NEAREST); + + // Flip image vertically into target + SDL_Rect rowSrc = {0, 0, bufferClone->w, 1}; + SDL_Rect rowDst = {0, 0, bufferClone->w, 1}; + for (int y = 0; y < bufferClone->h; ++y) { + rowSrc.y = y; + rowDst.y = bufferClone->h - 1 - y; + SDL_BlitSurface(bufferClone, &rowSrc, target, &rowDst); + } + + SDL_DestroySurface(bufferClone); +} diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index ea182dc2..4ee5a35c 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -7,6 +7,7 @@ #include "miniwin.h" #include +#include #include struct ScopedSurface { @@ -91,7 +92,12 @@ struct ScopedShader { void release() { ptr = nullptr; } }; -static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device, bool depthWrite) +static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline( + SDL_GPUDevice* device, + SDL_Window* window, + bool depthTest, + bool depthWrite +) { const SDL_GPUShaderCreateInfo* vertexCreateInfo = GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device)); @@ -141,8 +147,8 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device vertexInputState.num_vertex_attributes = SDL_arraysize(vertexAttrs); SDL_GPUColorTargetDescription colorTargets = {}; - colorTargets.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - if (depthWrite) { + colorTargets.format = SDL_GetGPUSwapchainTextureFormat(device, window); + if (depthTest && depthWrite) { colorTargets.blend_state.enable_blend = false; } else { @@ -170,7 +176,7 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device pipelineCreateInfo.rasterizer_state = rasterizerState; pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_GREATER; pipelineCreateInfo.depth_stencil_state.write_mask = 0xff; - pipelineCreateInfo.depth_stencil_state.enable_depth_test = true; + pipelineCreateInfo.depth_stencil_state.enable_depth_test = depthTest; pipelineCreateInfo.depth_stencil_state.enable_depth_write = depthWrite; pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false; pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets; @@ -178,16 +184,18 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device pipelineCreateInfo.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; pipelineCreateInfo.target_info.has_depth_stencil_target = true; - SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo); - - return pipeline; + return SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo); } Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) { ScopedDevice device{SDL_CreateGPUDevice( SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, +#ifdef DEBUG true, +#else + false, +#endif nullptr )}; if (!device.ptr) { @@ -195,63 +203,63 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) return nullptr; } - ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, true)}; + SDL_Window* window = DDWindow; + bool testWindow = false; + if (!window) { + window = SDL_CreateWindow("SDL_GPU test", width, height, SDL_WINDOW_HIDDEN); + if (!window) { + SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); + return nullptr; + } + testWindow = true; + } + + if (!SDL_ClaimWindowForGPUDevice(device.ptr, window)) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ClaimWindowForGPUDevice: %s", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } + return nullptr; + } + + ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, true)}; if (!opaquePipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline"); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } - ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, false)}; + ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, false)}; if (!transparentPipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline"); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } - SDL_GPUTextureCreateInfo textureInfo = {}; - textureInfo.type = SDL_GPU_TEXTURETYPE_2D; - textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; - textureInfo.width = width; - textureInfo.height = height; - textureInfo.layer_count_or_depth = 1; - textureInfo.num_levels = 1; - textureInfo.sample_count = SDL_GPU_SAMPLECOUNT_1; - ScopedTexture transferTexture{device.ptr, SDL_CreateGPUTexture(device.ptr, &textureInfo)}; - if (!transferTexture.ptr) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError()); - return nullptr; - } - - SDL_GPUTextureCreateInfo depthTexInfo = textureInfo; - depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; - depthTexInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; - ScopedTexture depthTexture{device.ptr, SDL_CreateGPUTexture(device.ptr, &depthTexInfo)}; - if (!depthTexture.ptr) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError()); - return nullptr; - } - - // Setup texture GPU-to-CPU transfer - SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {}; - downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD; - downloadBufferInfo.size = width * height * 4; - ScopedTransferBuffer downloadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &downloadBufferInfo)}; - if (!downloadBuffer.ptr) { - SDL_LogError( - LOG_CATEGORY_MINIWIN, - "SDL_CreateGPUTransferBuffer filed for download buffer (%s)", - SDL_GetError() - ); + ScopedPipeline uiPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, false, false)}; + if (!uiPipeline.ptr) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for uiPipeline"); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } // Setup texture CPU-to-GPU transfer SDL_GPUTransferBufferCreateInfo uploadBufferInfo = {}; uploadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - uploadBufferInfo.size = 256 * 256 * 4; // Largest known game texture + int uploadBufferSize = 640 * 480 * 4; // Largest known game texture + uploadBufferInfo.size = uploadBufferSize; ScopedTransferBuffer uploadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &uploadBufferInfo)}; if (!uploadBuffer.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer filed for upload buffer (%s)", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } @@ -265,31 +273,54 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)}; if (!sampler.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } + SDL_GPUSamplerCreateInfo uiSamplerInfo = {}; + uiSamplerInfo.min_filter = SDL_GPU_FILTER_LINEAR; + uiSamplerInfo.mag_filter = SDL_GPU_FILTER_NEAREST; + uiSamplerInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + uiSamplerInfo.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + uiSamplerInfo.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + uiSamplerInfo.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + ScopedSampler uiSampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &uiSamplerInfo)}; + if (!uiSampler.ptr) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } + return nullptr; + } + + if (testWindow) { + SDL_ReleaseWindowFromGPUDevice(device.ptr, window); + SDL_DestroyWindow(window); + } + auto renderer = new Direct3DRMSDL3GPURenderer( width, height, device.ptr, opaquePipeline.ptr, transparentPipeline.ptr, - transferTexture.ptr, - depthTexture.ptr, + uiPipeline.ptr, sampler.ptr, + uiSampler.ptr, uploadBuffer.ptr, - downloadBuffer.ptr + uploadBufferSize ); // Release resources so they don't get cleaned up device.release(); opaquePipeline.release(); transparentPipeline.release(); - transferTexture.release(); - depthTexture.release(); + uiPipeline.release(); sampler.release(); + uiSampler.release(); uploadBuffer.release(); - downloadBuffer.release(); return renderer; } @@ -300,17 +331,21 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer( SDL_GPUDevice* device, SDL_GPUGraphicsPipeline* opaquePipeline, SDL_GPUGraphicsPipeline* transparentPipeline, - SDL_GPUTexture* transferTexture, - SDL_GPUTexture* depthTexture, + SDL_GPUGraphicsPipeline* uiPipeline, SDL_GPUSampler* sampler, + SDL_GPUSampler* uiSampler, SDL_GPUTransferBuffer* uploadBuffer, - SDL_GPUTransferBuffer* downloadBuffer + int uploadBufferSize ) - : m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline), - m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture), - m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer) + : m_device(device), m_opaquePipeline(opaquePipeline), m_transparentPipeline(transparentPipeline), + m_uiPipeline(uiPipeline), m_sampler(sampler), m_uiSampler(uiSampler), m_uploadBuffer(uploadBuffer), + m_uploadBufferSize(uploadBufferSize) { - SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ABGR8888); + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; + SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_RGBA32); if (!dummySurface) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError()); return; @@ -324,35 +359,67 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer( SDL_UnlockSurface(dummySurface); m_dummyTexture = CreateTextureFromSurface(dummySurface); + if (!m_dummyTexture) { + SDL_DestroySurface(dummySurface); + SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError()); + return; + } SDL_DestroySurface(dummySurface); + + ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; + Resize(m_width, m_height, viewportTransform); + + m_uiMesh.vertices = { + {{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}}, + {{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}}, + {{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}}, + {{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}} + }; + m_uiMesh.indices = {0, 1, 2, 0, 2, 3}; + m_uiMeshCache = UploadMesh(m_uiMesh); } Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer() { - SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer); + SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.vertexBuffer); + SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.indexBuffer); + if (DDWindow) { + SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow); + } + if (m_downloadBuffer) { + SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer); + } if (m_uploadBuffer) { SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer); } SDL_ReleaseGPUSampler(m_device, m_sampler); - SDL_ReleaseGPUTexture(m_device, m_dummyTexture); - SDL_ReleaseGPUTexture(m_device, m_depthTexture); - SDL_ReleaseGPUTexture(m_device, m_transferTexture); + SDL_ReleaseGPUSampler(m_device, m_uiSampler); + if (m_dummyTexture) { + SDL_ReleaseGPUTexture(m_device, m_dummyTexture); + } + if (m_depthTexture) { + SDL_ReleaseGPUTexture(m_device, m_depthTexture); + } + if (m_transferTexture) { + SDL_ReleaseGPUTexture(m_device, m_transferTexture); + } SDL_ReleaseGPUGraphicsPipeline(m_device, m_opaquePipeline); SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline); + SDL_ReleaseGPUGraphicsPipeline(m_device, m_uiPipeline); if (m_uploadFence) { SDL_ReleaseGPUFence(m_device, m_uploadFence); } SDL_DestroyGPUDevice(m_device); } -void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* vertices, size_t count) +void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* lights, size_t count) { if (count > 3) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Unsupported number of lights (%d)", static_cast(count)); count = 3; } int lightCount = std::min(static_cast(count), 3); - memcpy(&m_fragmentShadingData.lights, vertices, sizeof(SceneLight) * lightCount); + memcpy(&m_fragmentShadingData.lights, lights, sizeof(SceneLight) * lightCount); m_fragmentShadingData.lightCount = lightCount; } @@ -364,7 +431,7 @@ void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D { m_front = front; m_back = back; - memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D)); + memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); } void Direct3DRMSDL3GPURenderer::WaitForPendingUpload() @@ -405,7 +472,7 @@ void Direct3DRMSDL3GPURenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRM SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* surface) { - ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888)}; + ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32)}; if (!surf.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError()); return nullptr; @@ -607,6 +674,7 @@ void Direct3DRMSDL3GPURenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMes auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_meshs[ctx->id]; SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer); + SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.indexBuffer); cache.meshGroup = nullptr; delete ctx; }, @@ -621,6 +689,7 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro if (cache.meshGroup == meshGroup) { if (cache.version != meshGroup->version) { SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer); + SDL_ReleaseGPUBuffer(m_device, cache.indexBuffer); cache = std::move(UploadMesh(*meshGroup)); } return i; @@ -643,16 +712,6 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro return (Uint32) (m_meshs.size() - 1); } -DWORD Direct3DRMSDL3GPURenderer::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMSDL3GPURenderer::GetHeight() -{ - return m_height; -} - void Direct3DRMSDL3GPURenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -708,32 +767,45 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size) return m_uploadBuffer; } -HRESULT Direct3DRMSDL3GPURenderer::BeginFrame() +void Direct3DRMSDL3GPURenderer::StartRenderPass(float r, float g, float b, bool clear) { - if (!DDBackBuffer) { - return DDERR_GENERIC; + m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device); + if (!m_cmdbuf) { + SDL_LogError( + LOG_CATEGORY_MINIWIN, + "SDL_AcquireGPUCommandBuffer in StartRenderPass failed (%s)", + SDL_GetError() + ); + return; } // Clear color and depth targets SDL_GPUColorTargetInfo colorTargetInfo = {}; colorTargetInfo.texture = m_transferTexture; - colorTargetInfo.clear_color = {0, 0, 0, 0}; - colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; + colorTargetInfo.clear_color = {r, g, b, 1.0f}; + colorTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE; SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {}; depthStencilTargetInfo.texture = m_depthTexture; depthStencilTargetInfo.clear_depth = 0.0f; - depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; + depthStencilTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE; depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE; - m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device); - if (!m_cmdbuf) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in BeginFrame failed (%s)", SDL_GetError()); - return DDERR_GENERIC; - } - m_renderPass = SDL_BeginGPURenderPass(m_cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo); +} + +void Direct3DRMSDL3GPURenderer::Clear(float r, float g, float b) +{ + StartRenderPass(r, g, b, true); +} + +HRESULT Direct3DRMSDL3GPURenderer::BeginFrame() +{ + if (!m_renderPass) { + StartRenderPass(0, 0, 0, false); + } SDL_BindGPUGraphicsPipeline(m_renderPass, m_opaquePipeline); + memcpy(&m_uniforms.projection, m_projection, sizeof(D3DRMMATRIX4D)); return DD_OK; } @@ -746,6 +818,8 @@ void Direct3DRMSDL3GPURenderer::EnableTransparency() void Direct3DRMSDL3GPURenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -774,15 +848,210 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw( HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame() { - SDL_EndGPURenderPass(m_renderPass); - m_renderPass = nullptr; + return DD_OK; +} + +void Direct3DRMSDL3GPURenderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + + if (!DDWindow) { + return; + } + + if (m_transferTexture) { + SDL_ReleaseGPUTexture(m_device, m_transferTexture); + } + SDL_GPUTextureCreateInfo textureInfo = {}; + textureInfo.type = SDL_GPU_TEXTURETYPE_2D; + textureInfo.format = SDL_GetGPUSwapchainTextureFormat(m_device, DDWindow); + textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER; + textureInfo.width = m_width; + textureInfo.height = m_height; + textureInfo.layer_count_or_depth = 1; + textureInfo.num_levels = 1; + textureInfo.sample_count = SDL_GPU_SAMPLECOUNT_1; + m_transferTexture = SDL_CreateGPUTexture(m_device, &textureInfo); + if (!m_transferTexture) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError()); + return; + } + + if (m_depthTexture) { + SDL_ReleaseGPUTexture(m_device, m_depthTexture); + } + SDL_GPUTextureCreateInfo depthTexInfo = textureInfo; + depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; + depthTexInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; + m_depthTexture = SDL_CreateGPUTexture(m_device, &depthTexInfo); + if (!m_depthTexture) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError()); + return; + } + + // Setup texture GPU-to-CPU transfer + SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {}; + downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD; + downloadBufferInfo.size = + ((m_width - (m_viewportTransform.offsetX * 2)) * (m_height - (m_viewportTransform.offsetY * 2))) * 4; + m_downloadBuffer = SDL_CreateGPUTransferBuffer(m_device, &downloadBufferInfo); + if (!m_downloadBuffer) { + SDL_LogError( + LOG_CATEGORY_MINIWIN, + "SDL_CreateGPUTransferBuffer filed for download buffer (%s)", + SDL_GetError() + ); + return; + } +} + +void Direct3DRMSDL3GPURenderer::Flip() +{ + if (!m_cmdbuf) { + return; + } + if (m_renderPass) { + SDL_EndGPURenderPass(m_renderPass); + m_renderPass = nullptr; + } + + SDL_GPUTexture* swapchainTexture; + if (!SDL_WaitAndAcquireGPUSwapchainTexture(m_cmdbuf, DDWindow, &swapchainTexture, nullptr, nullptr) || + !swapchainTexture) { + SDL_Log("SDL_WaitAndAcquireGPUSwapchainTexture: %s", SDL_GetError()); + return; + } + + SDL_GPUBlitInfo blit = {}; + blit.source.texture = m_transferTexture; + blit.source.w = m_width; + blit.source.h = m_height; + blit.destination.texture = swapchainTexture; + blit.destination.w = m_width; + blit.destination.h = m_height; + blit.load_op = SDL_GPU_LOADOP_DONT_CARE; + blit.flip_mode = SDL_FLIP_NONE; + blit.filter = SDL_GPU_FILTER_NEAREST; + blit.cycle = false; + SDL_BlitGPUTexture(m_cmdbuf, &blit); + SDL_SubmitGPUCommandBuffer(m_cmdbuf); + m_cmdbuf = nullptr; +} + +// TODO use SDL_SetGPUScissor(SDL_GPURenderPass *render_pass, const SDL_Rect *scissor) when srcRect isn't 100% of +// texture + +void Create2DTransformMatrix( + const SDL_Rect& dstRect, + float scale, + float offsetX, + float offsetY, + D3DRMMATRIX4D& outMatrix +) +{ + float x = static_cast(dstRect.x) * scale + offsetX; + float y = static_cast(dstRect.y) * scale + offsetY; + float w = static_cast(dstRect.w) * scale; + float h = static_cast(dstRect.h) * scale; + + D3DVALUE tmp[4][4] = {{w, 0, 0, 0}, {0, h, 0, 0}, {0, 0, 1, 0}, {x, y, 0, 1}}; + memcpy(outMatrix, tmp, sizeof(tmp)); +} + +void CreateOrthographicProjection(float width, float height, D3DRMMATRIX4D& outProj) +{ + D3DVALUE tmp[4][4] = { + {2.0f / width, 0.0f, 0.0f, 0.0f}, + {0.0f, -2.0f / height, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f, 1.0f} + }; + memcpy(outProj, tmp, sizeof(tmp)); +} + +void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + if (!m_renderPass) { + StartRenderPass(0, 0, 0, false); + } + SDL_BindGPUGraphicsPipeline(m_renderPass, m_uiPipeline); + + const SDL3TextureCache& tex = m_textures[textureId]; + + auto surface = static_cast(tex.texture->m_surface); + float scaleX = static_cast(dstRect.w) / srcRect.w; + float scaleY = static_cast(dstRect.h) / srcRect.h; + SDL_Rect expandedDstRect = { + static_cast(std::round(dstRect.x - srcRect.x * scaleX)), + static_cast(std::round(dstRect.y - srcRect.y * scaleY)), + static_cast(std::round(static_cast(surface->m_surface->w) * scaleX)), + static_cast(std::round(static_cast(surface->m_surface->h) * scaleY)), + }; + + Create2DTransformMatrix( + expandedDstRect, + m_viewportTransform.scale, + m_viewportTransform.offsetX, + m_viewportTransform.offsetY, + m_uniforms.worldViewMatrix + ); + + CreateOrthographicProjection((float) m_width, (float) m_height, m_uniforms.projection); + + SceneLight fullBright = {{1, 1, 1, 1}, {0, 0, 0}, 0, {0, 0, 0}, 0}; + memcpy(&m_fragmentShadingData.lights, &fullBright, sizeof(SceneLight)); + m_fragmentShadingData.lightCount = 1; + m_fragmentShadingData.color = {0xff, 0xff, 0xff, 0xff}; + m_fragmentShadingData.shininess = 0.0f; + m_fragmentShadingData.useTexture = 1; + + SDL_GPUTextureSamplerBinding samplerBinding = {tex.gpuTexture, m_uiSampler}; + SDL_BindGPUFragmentSamplers(m_renderPass, 0, &samplerBinding, 1); + SDL_PushGPUVertexUniformData(m_cmdbuf, 0, &m_uniforms, sizeof(m_uniforms)); + SDL_PushGPUFragmentUniformData(m_cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData)); + SDL_GPUBufferBinding vertexBufferBinding = {m_uiMeshCache.vertexBuffer}; + SDL_BindGPUVertexBuffers(m_renderPass, 0, &vertexBufferBinding, 1); + SDL_GPUBufferBinding indexBufferBinding = {m_uiMeshCache.indexBuffer}; + SDL_BindGPUIndexBuffer(m_renderPass, &indexBufferBinding, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + SDL_Rect scissor; + scissor.x = static_cast(std::round(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX)); + scissor.y = static_cast(std::round(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY)); + scissor.w = static_cast(std::round(dstRect.w * m_viewportTransform.scale)); + scissor.h = static_cast(std::round(dstRect.h * m_viewportTransform.scale)); + SDL_SetGPUScissor(m_renderPass, &scissor); + + SDL_DrawGPUIndexedPrimitives(m_renderPass, m_uiMeshCache.indexCount, 1, 0, 0, 0); + + SDL_Rect fullViewport = {0, 0, m_width, m_height}; + SDL_SetGPUScissor(m_renderPass, &fullViewport); +} + +void Direct3DRMSDL3GPURenderer::Download(SDL_Surface* target) +{ + if (!m_cmdbuf) { + StartRenderPass(0, 0, 0, false); + } + if (m_renderPass) { + SDL_EndGPURenderPass(m_renderPass); + m_renderPass = nullptr; + } + + const int offsetX = static_cast(m_viewportTransform.offsetX); + const int offsetY = static_cast(m_viewportTransform.offsetY); + const int width = m_width - offsetX * 2; + const int height = m_height - offsetY * 2; - // Download rendered image SDL_GPUTextureRegion region = {}; region.texture = m_transferTexture; - region.w = m_width; - region.h = m_height; + region.x = offsetX; + region.y = offsetY; + region.w = width; + region.h = height; region.d = 1; + SDL_GPUTextureTransferInfo transferInfo = {}; transferInfo.transfer_buffer = m_downloadBuffer; @@ -792,27 +1061,24 @@ HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame() WaitForPendingUpload(); - // Render the frame SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf); m_cmdbuf = nullptr; - if (!fence) { - return DDERR_GENERIC; + + if (!fence || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) { + SDL_ReleaseGPUFence(m_device, fence); + return; } - bool success = SDL_WaitForGPUFences(m_device, true, &fence, 1); SDL_ReleaseGPUFence(m_device, fence); - if (!success) { - return DDERR_GENERIC; - } + void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false); if (!downloadedData) { - return DDERR_GENERIC; + return; } SDL_Surface* renderedImage = - SDL_CreateSurfaceFrom(m_width, m_height, SDL_PIXELFORMAT_ABGR8888, downloadedData, m_width * 4); - SDL_BlitSurface(renderedImage, nullptr, DDBackBuffer, nullptr); + SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_ARGB8888, downloadedData, width * 4); + + SDL_BlitSurfaceScaled(renderedImage, nullptr, target, nullptr, SDL_SCALEMODE_NEAREST); SDL_DestroySurface(renderedImage); SDL_UnmapGPUTransferBuffer(m_device, m_downloadBuffer); - - return DD_OK; } diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h index ae843a2b..ebdbe79d 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h @@ -10,9 +10,9 @@ // DXIL only makes sense on Windows platforms #if defined(SDL_PLATFORM_WINDOWS) -static const Uint8 SolidColor_frag_dxil[6640] = { - 0x44, 0x58, 0x42, 0x43, 0x91, 0x24, 0xbe, 0xd8, 0x43, 0x8d, 0x7f, 0xf4, 0x71, 0x2b, 0x59, 0x98, - 0x2d, 0x7f, 0x8d, 0xac, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, +static const Uint8 SolidColor_frag_dxil[6648] = { + 0x44, 0x58, 0x42, 0x43, 0xd8, 0xfe, 0x4c, 0xec, 0x17, 0x1b, 0x52, 0xee, 0xf7, 0xc8, 0x8d, 0xcf, + 0x47, 0x0e, 0xfe, 0xb7, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x94, 0x0c, 0x00, 0x00, 0xb0, 0x0c, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, @@ -52,7 +52,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x11, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xc8, 0x09, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, @@ -113,9 +113,9 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x18, 0x8a, 0xa0, 0x24, 0xca, 0xa0, 0x80, 0x05, 0x0a, 0xac, 0x1c, 0x4a, 0xa3, 0x10, 0x0a, 0xa4, 0x80, 0x0a, 0x54, 0xa0, 0x50, 0x05, 0x0a, 0x56, 0xa0, 0x14, 0x0a, 0x57, 0xa0, 0x20, 0xca, 0xa3, 0x06, 0xca, 0x34, 0xa0, - 0x24, 0x07, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, + 0x2c, 0x07, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, 0x1a, 0xa0, 0xad, 0x06, 0x48, 0x9c, 0x01, 0xa0, 0x71, 0x06, 0x80, 0xca, 0x19, 0x00, 0x32, 0x67, - 0x00, 0x08, 0x9d, 0x01, 0xa0, 0x74, 0x2c, 0x09, 0x22, 0x8e, 0xe3, 0x00, 0x8e, 0x03, 0x00, 0x8e, + 0x00, 0x08, 0x9d, 0x01, 0xa0, 0x74, 0x2c, 0x09, 0x22, 0x8e, 0xe3, 0x00, 0x9e, 0x07, 0x00, 0x8e, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb9, 0xc1, 0xc9, @@ -213,10 +213,10 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x04, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x06, 0x40, 0x30, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x63, 0x6a, 0xf1, 0xca, 0xdc, 0xf6, 0x75, 0x3d, 0x1e, 0x21, 0x9a, 0xb8, 0xa2, 0x91, 0xc3, - 0x44, 0x58, 0x49, 0x4c, 0x38, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4e, 0x03, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x0d, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x45, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, + 0xeb, 0x0f, 0x40, 0x5f, 0x0e, 0x75, 0xec, 0xd9, 0x61, 0x1b, 0x68, 0x81, 0x54, 0xd3, 0xf4, 0x48, + 0x44, 0x58, 0x49, 0x4c, 0x40, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x03, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x0d, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x47, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, @@ -272,7 +272,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x20, 0x8a, 0xa1, 0x08, 0x4a, 0xa2, 0x0c, 0x0a, 0x58, 0xa0, 0x1c, 0xca, 0xa3, 0x06, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, 0x1a, 0x20, 0x71, 0x06, 0x80, 0xcc, 0x19, 0x00, - 0x42, 0x67, 0x00, 0x28, 0x1d, 0x4b, 0x82, 0x88, 0xe3, 0x38, 0x80, 0xe3, 0x00, 0x80, 0xe3, 0x38, + 0x42, 0x67, 0x00, 0x28, 0x1d, 0x4b, 0x82, 0x88, 0xe3, 0x38, 0x80, 0xe7, 0x01, 0x80, 0xe3, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb9, 0xc1, 0xc9, @@ -336,7 +336,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x9b, 0x01, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x04, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x06, 0x40, - 0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x13, 0x04, 0x52, 0x2c, + 0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x13, 0x04, 0x52, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xb4, 0x8d, 0x00, 0x10, 0x51, 0x78, 0x05, 0x52, 0x30, 0xa5, 0x32, 0x03, 0x50, 0x76, 0x85, 0x50, 0x46, 0x85, 0x54, 0x6e, 0xa5, 0x50, 0x72, 0x25, 0x53, 0xfe, 0x03, 0xe5, 0x42, 0xc3, 0x0c, 0xc0, 0x18, 0x41, 0x48, 0x82, 0x21, 0xde, 0x8d, 0x11, @@ -413,25 +413,26 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0xc4, 0xe0, 0x00, 0x40, 0x10, 0x0c, 0x9c, 0xd8, 0x58, 0x8b, 0x21, 0x2c, 0x46, 0x13, 0xb8, 0x61, 0xb8, 0x21, 0x68, 0x0d, 0x30, 0x98, 0x65, 0x88, 0xa0, 0x60, 0xc4, 0xe0, 0x01, 0x40, 0x10, 0x0c, 0xa6, 0xd9, 0xb0, 0x0b, 0xb1, 0x08, 0x8b, 0x9d, 0xd0, 0x89, 0xb3, 0x38, 0x0b, 0xd7, 0x70, 0x0d, - 0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0xb0, 0x21, 0x91, - 0x8f, 0x0d, 0x89, 0x7c, 0x6c, 0x48, 0xe4, 0x33, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6e, - 0xd8, 0xc5, 0xa0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, - 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f, 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, - 0x00, 0x82, 0x60, 0xe0, 0xf8, 0x06, 0x5e, 0x0c, 0x6e, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, - 0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, - 0x0c, 0x70, 0x31, 0x4b, 0x10, 0x0d, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, - 0x64, 0xf0, 0x0c, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, - 0xe7, 0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb3, 0x31, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, - 0x1e, 0x7c, 0xe1, 0x1b, 0xbe, 0xd1, 0x1a, 0xc2, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe7, - 0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb2, 0x11, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x1e, - 0x7c, 0xe1, 0x1b, 0xbe, 0x11, 0x1b, 0x6a, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc8, 0x79, - 0xf0, 0xc5, 0x6f, 0xf8, 0xc6, 0x6c, 0x98, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0x18, 0x4d, 0x20, + 0x06, 0x23, 0x14, 0xf9, 0x18, 0xa1, 0xc8, 0xc7, 0x08, 0x45, 0x3e, 0x23, 0x06, 0x07, 0x00, 0x82, + 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f, + 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf8, 0x46, 0x5e, 0x0c, 0x6d, + 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07, + 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, 0x0c, 0x70, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, + 0x4e, 0x78, 0xec, 0xc5, 0x10, 0x17, 0xb3, 0x04, 0xd1, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c, + 0x54, 0x0c, 0x06, 0x64, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c, 0x54, 0x0c, 0x1a, + 0x64, 0x0b, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e, + 0xb5, 0x41, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0xf1, + 0x1a, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e, 0xb4, + 0x21, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0x31, 0x1b, + 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe1, 0x01, 0x1e, 0xb5, 0x81, + 0x16, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif // MSL only makes sense on Apple platforms #if defined(SDL_PLATFORM_APPLE) -static const Uint8 SolidColor_frag_msl[3333] = { +static const Uint8 SolidColor_frag_msl[3377] = { 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x3e, 0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x0a, @@ -620,32 +621,35 @@ static const Uint8 SolidColor_frag_msl[3333] = { 0x78, 0x79, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x5f, 0x36, 0x32, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, - 0x33, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x34, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x55, 0x73, 0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, - 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x28, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, - 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, - 0x31, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x66, - 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, - 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x5f, 0x31, - 0x35, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, - 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x30, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x5f, 0x31, - 0x36, 0x34, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, - 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, - 0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, - 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x31, 0x36, 0x31, 0x20, 0x3d, + 0x20, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28, + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, + 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x34, 0x28, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x6d, 0x70, + 0x28, 0x5f, 0x31, 0x36, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31, + 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, + 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x2c, 0x20, 0x5f, 0x31, 0x36, + 0x31, 0x2e, 0x77, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, + 0x28, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, + 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x30, 0x20, 0x3d, + 0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67, + 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x67, 0x6c, + 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, + 0x0a, }; #endif -static const Uint8 SolidColor_frag_spirv[4492] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xab, 0x00, 0x00, 0x00, +static const Uint8 SolidColor_frag_spirv[4616] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -902,28 +906,36 @@ static const Uint8 SolidColor_frag_spirv[4492] = { 0x16, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0xab, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, - 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, - 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, - 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x27, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, - 0xa9, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, - 0xaa, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, + 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, + 0x9c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, + 0x9e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xa6, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x12, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, + 0xa6, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x9d, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, + 0x27, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x9d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xb0, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, }; diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl index 7e9a0c6d..6a6608ba 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl @@ -72,8 +72,11 @@ FS_Output main(FS_Input input) if (UseTexture != 0) { float4 texel = Texture.Sample(Sampler, input.TexCoord); finalColor = saturate(texel.rgb * finalColor); + output.Color = float4(finalColor, texel.a); + } + else { + output.Color = float4(finalColor, Color.a); } - output.Color = float4(finalColor, Color.a); output.Depth = input.Position.w; return output; } diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index 563821b2..64adc93b 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -23,9 +23,22 @@ #include #endif -Direct3DRMSoftwareRenderer::Direct3DRMSoftwareRenderer(DWORD width, DWORD height) : m_width(width), m_height(height) +Direct3DRMSoftwareRenderer::Direct3DRMSoftwareRenderer(DWORD width, DWORD height) { - m_zBuffer.resize(m_width * m_height); + m_virtualWidth = width; + m_virtualHeight = height; + + m_renderer = SDL_CreateRenderer(DDWindow, NULL); + + ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; + Resize(width, height, viewportTransform); +} + +Direct3DRMSoftwareRenderer::~Direct3DRMSoftwareRenderer() +{ + SDL_DestroySurface(m_renderedImage); + SDL_DestroyTexture(m_uploadBuffer); + SDL_DestroyRenderer(m_renderer); } void Direct3DRMSoftwareRenderer::PushLights(const SceneLight* lights, size_t count) @@ -354,8 +367,8 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected( c2 = ApplyLighting(v2.position, v2.normal, appearance); } - Uint8* pixels = (Uint8*) DDBackBuffer->pixels; - int pitch = DDBackBuffer->pitch; + Uint8* pixels = (Uint8*) m_renderedImage->pixels; + int pitch = m_renderedImage->pitch; VertexXY verts[3] = { {p0.x, p0.y, p0.z, p0.w, c0, v0.texCoord.u, v0.texCoord.v}, @@ -553,7 +566,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture) if (texRef.version != texture->m_version) { // Update animated textures SDL_DestroySurface(texRef.cached); - texRef.cached = SDL_ConvertSurface(surface->m_surface, DDBackBuffer->format); + texRef.cached = SDL_ConvertSurface(surface->m_surface, m_renderedImage->format); SDL_LockSurface(texRef.cached); texRef.version = texture->m_version; } @@ -561,7 +574,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture) } } - SDL_Surface* convertedRender = SDL_ConvertSurface(surface->m_surface, DDBackBuffer->format); + SDL_Surface* convertedRender = SDL_ConvertSurface(surface->m_surface, m_renderedImage->format); SDL_LockSurface(convertedRender); // Reuse freed slot @@ -651,16 +664,6 @@ Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGr return (Uint32) (m_meshs.size() - 1); } -DWORD Direct3DRMSoftwareRenderer::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMSoftwareRenderer::GetHeight() -{ - return m_height; -} - void Direct3DRMSoftwareRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { memset(halDesc, 0, sizeof(D3DDEVICEDESC)); @@ -681,13 +684,13 @@ const char* Direct3DRMSoftwareRenderer::GetName() HRESULT Direct3DRMSoftwareRenderer::BeginFrame() { - if (!DDBackBuffer || !SDL_LockSurface(DDBackBuffer)) { + if (!m_renderedImage || !SDL_LockSurface(m_renderedImage)) { return DDERR_GENERIC; } ClearZBuffer(); - m_format = SDL_GetPixelFormatDetails(DDBackBuffer->format); - m_palette = SDL_GetSurfacePalette(DDBackBuffer); + m_format = SDL_GetPixelFormatDetails(m_renderedImage->format); + m_palette = SDL_GetSurfacePalette(m_renderedImage); m_bytesPerPixel = m_format->bits_per_pixel / 8; return DD_OK; @@ -700,6 +703,8 @@ void Direct3DRMSoftwareRenderer::EnableTransparency() void Direct3DRMSoftwareRenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -731,7 +736,84 @@ void Direct3DRMSoftwareRenderer::SubmitDraw( HRESULT Direct3DRMSoftwareRenderer::FinalizeFrame() { - SDL_UnlockSurface(DDBackBuffer); + SDL_UnlockSurface(m_renderedImage); return DD_OK; } + +void Direct3DRMSoftwareRenderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_viewportTransform = viewportTransform; + float aspect = static_cast(width) / height; + float virtualAspect = static_cast(m_virtualWidth) / m_virtualHeight; + + // Cap to virtual canvase for performance + if (aspect > virtualAspect) { + m_height = std::min(height, m_virtualHeight); + m_width = static_cast(m_height * aspect); + } + else { + m_width = std::min(width, m_virtualWidth); + m_height = static_cast(m_width / aspect); + } + + m_viewportTransform.scale = + std::min(static_cast(m_width) / m_virtualWidth, static_cast(m_height) / m_virtualHeight); + + m_viewportTransform.offsetX = (m_width - (m_virtualWidth * m_viewportTransform.scale)) / 2.0f; + m_viewportTransform.offsetY = (m_height - (m_virtualHeight * m_viewportTransform.scale)) / 2.0f; + + if (m_renderedImage) { + SDL_DestroySurface(m_renderedImage); + } + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + + if (m_uploadBuffer) { + SDL_DestroyTexture(m_uploadBuffer); + } + m_uploadBuffer = + SDL_CreateTexture(m_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, m_width, m_height); + + m_zBuffer.resize(m_width * m_height); +} + +void Direct3DRMSoftwareRenderer::Clear(float r, float g, float b) +{ + SDL_Rect rect = {0, 0, m_renderedImage->w, m_renderedImage->h}; + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_renderedImage->format); + Uint32 color = SDL_MapRGB(details, m_palette, r * 255, g * 255, b * 255); + SDL_FillSurfaceRect(m_renderedImage, &rect, color); +} + +void Direct3DRMSoftwareRenderer::Flip() +{ + SDL_UpdateTexture(m_uploadBuffer, nullptr, m_renderedImage->pixels, m_renderedImage->pitch); + SDL_RenderTexture(m_renderer, m_uploadBuffer, nullptr, nullptr); + SDL_RenderPresent(m_renderer); +} + +void Direct3DRMSoftwareRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + SDL_Surface* surface = m_textures[textureId].cached; + SDL_UnlockSurface(surface); + SDL_Rect centeredRect = { + static_cast(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX), + static_cast(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY), + static_cast(dstRect.w * m_viewportTransform.scale), + static_cast(dstRect.h * m_viewportTransform.scale), + }; + SDL_BlitSurfaceScaled(surface, &srcRect, m_renderedImage, ¢eredRect, SDL_SCALEMODE_LINEAR); + SDL_LockSurface(surface); +} + +void Direct3DRMSoftwareRenderer::Download(SDL_Surface* target) +{ + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(m_virtualWidth * m_viewportTransform.scale), + static_cast(m_virtualHeight * m_viewportTransform.scale), + }; + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, target, nullptr, SDL_SCALEMODE_LINEAR); +} diff --git a/miniwin/src/d3drm/d3drm.cpp b/miniwin/src/d3drm/d3drm.cpp index 01375d8c..e8df37b1 100644 --- a/miniwin/src/d3drm/d3drm.cpp +++ b/miniwin/src/d3drm/d3drm.cpp @@ -127,7 +127,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromD3D( { auto renderer = static_cast(d3dDevice); *outDevice = static_cast( - new Direct3DRMDevice2Impl(renderer->GetWidth(), renderer->GetHeight(), renderer) + new Direct3DRMDevice2Impl(renderer->GetVirtualWidth(), renderer->GetVirtualHeight(), renderer) ); return DD_OK; } @@ -143,26 +143,25 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( DDSDesc.dwSize = sizeof(DDSURFACEDESC); surface->GetSurfaceDesc(&DDSDesc); - Direct3DRMRenderer* renderer; if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { - renderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { - renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); } #ifdef USE_OPENGLES2 else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - renderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef USE_OPENGL1 else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { - renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef _WIN32 else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { - renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif else { @@ -170,7 +169,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( return E_NOINTERFACE; } *outDevice = - static_cast(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, renderer)); + static_cast(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, DDRenderer)); return DD_OK; } @@ -181,9 +180,8 @@ HRESULT Direct3DRMImpl::CreateTexture(D3DRMIMAGE* image, IDirect3DRMTexture2** o } HRESULT Direct3DRMImpl::CreateTextureFromSurface(LPDIRECTDRAWSURFACE surface, IDirect3DRMTexture2** outTexture) - { - *outTexture = static_cast(new Direct3DRMTextureImpl(surface)); + *outTexture = static_cast(new Direct3DRMTextureImpl(surface, true)); return DD_OK; } diff --git a/miniwin/src/d3drm/d3drmdevice.cpp b/miniwin/src/d3drm/d3drmdevice.cpp index be850823..f6b2f9f7 100644 --- a/miniwin/src/d3drm/d3drmdevice.cpp +++ b/miniwin/src/d3drm/d3drmdevice.cpp @@ -11,8 +11,9 @@ #include Direct3DRMDevice2Impl::Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer) - : m_width(width), m_height(height), m_renderer(renderer), m_viewports(new Direct3DRMViewportArrayImpl) + : m_virtualWidth(width), m_virtualHeight(height), m_renderer(renderer), m_viewports(new Direct3DRMViewportArrayImpl) { + Resize(); } Direct3DRMDevice2Impl::~Direct3DRMDevice2Impl() @@ -43,16 +44,6 @@ HRESULT Direct3DRMDevice2Impl::QueryInterface(const GUID& riid, void** ppvObject return E_NOINTERFACE; } -DWORD Direct3DRMDevice2Impl::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMDevice2Impl::GetHeight() -{ - return m_height; -} - HRESULT Direct3DRMDevice2Impl::SetBufferCount(int count) { MINIWIN_NOT_IMPLEMENTED(); @@ -133,7 +124,9 @@ HRESULT Direct3DRMDevice2Impl::Update() HRESULT Direct3DRMDevice2Impl::AddViewport(IDirect3DRMViewport* viewport) { - return m_viewports->AddElement(viewport); + HRESULT status = m_viewports->AddElement(viewport); + Resize(); + return status; } HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewportArray) @@ -143,7 +136,53 @@ HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewpor return DD_OK; } +ViewportTransform CalculateViewportTransform(int virtualW, int virtualH, int windowW, int windowH) +{ + float scaleX = (float) windowW / virtualW; + float scaleY = (float) windowH / virtualH; + float scale = (scaleX < scaleY) ? scaleX : scaleY; + + float viewportW = virtualW * scale; + float viewportH = virtualH * scale; + + float offsetX = (windowW - viewportW) * 0.5f; + float offsetY = (windowH - viewportH) * 0.5f; + + return {scale, offsetX, offsetY}; +} + +void Direct3DRMDevice2Impl::Resize() +{ + int width, height; + SDL_GetWindowSizeInPixels(DDWindow, &width, &height); + m_viewportTransform = CalculateViewportTransform(m_virtualWidth, m_virtualHeight, width, height); + m_renderer->Resize(width, height, m_viewportTransform); + for (int i = 0; i < m_viewports->GetSize(); i++) { + IDirect3DRMViewport* viewport; + m_viewports->GetElement(i, &viewport); + static_cast(viewport)->UpdateProjectionMatrix(); + } +} + bool Direct3DRMDevice2Impl::ConvertEventToRenderCoordinates(SDL_Event* event) { - return m_renderer->ConvertEventToRenderCoordinates(event); + switch (event->type) { + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: { + Resize(); + break; + } + case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: { + int rawX = event->motion.x; + int rawY = event->motion.y; + float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale; + event->motion.x = static_cast(x); + event->motion.y = static_cast(y); + break; + } break; + } + + return true; } diff --git a/miniwin/src/d3drm/d3drmmesh.cpp b/miniwin/src/d3drm/d3drmmesh.cpp index dc8c8686..4545036b 100644 --- a/miniwin/src/d3drm/d3drmmesh.cpp +++ b/miniwin/src/d3drm/d3drmmesh.cpp @@ -40,10 +40,10 @@ HRESULT Direct3DRMMeshImpl::Clone(int flags, GUID iid, void** object) } HRESULT Direct3DRMMeshImpl::AddGroup( - int vertexCount, - int faceCount, - int vertexPerFace, - DWORD* faceBuffer, + unsigned int vertexCount, + unsigned int faceCount, + unsigned int vertexPerFace, + unsigned int* faceBuffer, D3DRMGROUPINDEX* groupIndex ) { @@ -59,7 +59,7 @@ HRESULT Direct3DRMMeshImpl::AddGroup( MeshGroup group; group.vertexPerFace = vertexPerFace; - DWORD* src = faceBuffer; + unsigned int* src = faceBuffer; group.indices.assign(src, src + faceCount * vertexPerFace); m_groups.push_back(std::move(group)); diff --git a/miniwin/src/d3drm/d3drmtexture.cpp b/miniwin/src/d3drm/d3drmtexture.cpp index c0a2ad59..a5d63588 100644 --- a/miniwin/src/d3drm/d3drmtexture.cpp +++ b/miniwin/src/d3drm/d3drmtexture.cpp @@ -6,8 +6,19 @@ Direct3DRMTextureImpl::Direct3DRMTextureImpl(D3DRMIMAGE* image) MINIWIN_NOT_IMPLEMENTED(); } -Direct3DRMTextureImpl::Direct3DRMTextureImpl(IDirectDrawSurface* surface) : m_surface(surface) +Direct3DRMTextureImpl::Direct3DRMTextureImpl(IDirectDrawSurface* surface, bool holdsRef) + : m_surface(surface), m_holdsRef(holdsRef) { + if (holdsRef && m_surface) { + m_surface->AddRef(); + } +} + +Direct3DRMTextureImpl::~Direct3DRMTextureImpl() +{ + if (m_holdsRef && m_surface) { + m_surface->Release(); + } } HRESULT Direct3DRMTextureImpl::QueryInterface(const GUID& riid, void** ppvObject) diff --git a/miniwin/src/d3drm/d3drmviewport.cpp b/miniwin/src/d3drm/d3drmviewport.cpp index 933cbbcd..e3bb79d3 100644 --- a/miniwin/src/d3drm/d3drmviewport.cpp +++ b/miniwin/src/d3drm/d3drmviewport.cpp @@ -15,7 +15,7 @@ #include Direct3DRMViewportImpl::Direct3DRMViewportImpl(DWORD width, DWORD height, Direct3DRMRenderer* renderer) - : m_width(width), m_height(height), m_renderer(renderer) + : m_virtualWidth(width), m_virtualHeight(height), m_renderer(renderer) { } @@ -151,7 +151,7 @@ void Direct3DRMViewportImpl::CollectLightsFromFrame( void Direct3DRMViewportImpl::BuildViewFrustumPlanes() { - float aspect = (float) m_width / (float) m_height; + float aspect = (float) m_renderer->GetWidth() / (float) m_renderer->GetHeight(); float tanFovX = m_field; float tanFovY = m_field / aspect; @@ -268,18 +268,22 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3D if (appearance.color.a != 255) { m_deferredDraws.push_back( {m_renderer->GetMeshId(mesh, &meshGroup), + {}, {}, {}, appearance, CalculateDepth(m_viewProjectionwMatrix, worldMatrix)} ); memcpy(m_deferredDraws.back().modelViewMatrix, modelViewMatrix, sizeof(D3DRMMATRIX4D)); + memcpy(m_deferredDraws.back().worldMatrix, worldMatrix, sizeof(D3DRMMATRIX4D)); memcpy(m_deferredDraws.back().normalMatrix, worldMatrixInvert, sizeof(Matrix3x3)); } else { m_renderer->SubmitDraw( m_renderer->GetMeshId(mesh, &meshGroup), modelViewMatrix, + worldMatrix, + m_viewMatrix, worldMatrixInvert, appearance ); @@ -325,7 +329,14 @@ HRESULT Direct3DRMViewportImpl::RenderScene() ); m_renderer->EnableTransparency(); for (const DeferredDrawCommand& cmd : m_deferredDraws) { - m_renderer->SubmitDraw(cmd.meshId, cmd.modelViewMatrix, cmd.normalMatrix, cmd.appearance); + m_renderer->SubmitDraw( + cmd.meshId, + cmd.modelViewMatrix, + cmd.worldMatrix, + m_viewMatrix, + cmd.normalMatrix, + cmd.appearance + ); } m_deferredDraws.clear(); @@ -349,16 +360,14 @@ HRESULT Direct3DRMViewportImpl::ForceUpdate(int x, int y, int w, int h) HRESULT Direct3DRMViewportImpl::Clear() { - if (!DDBackBuffer) { + if (!m_renderer) { return DDERR_GENERIC; } uint8_t r = (m_backgroundColor >> 16) & 0xFF; uint8_t g = (m_backgroundColor >> 8) & 0xFF; uint8_t b = m_backgroundColor & 0xFF; - - Uint32 color = SDL_MapRGB(SDL_GetPixelFormatDetails(DDBackBuffer->format), nullptr, r, g, b); - SDL_FillSurfaceRect(DDBackBuffer, nullptr, color); + m_renderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f); return DD_OK; } @@ -427,13 +436,24 @@ HRESULT Direct3DRMViewportImpl::SetField(D3DVALUE field) void Direct3DRMViewportImpl::UpdateProjectionMatrix() { - float aspect = (float) m_width / (float) m_height; - float f = m_front / m_field; + float virtualAspect = (float) m_virtualWidth / (float) m_virtualHeight; + float windowAspect = (float) m_renderer->GetWidth() / (float) m_renderer->GetHeight(); + + float base_f = m_front / m_field; + float f_v = base_f * virtualAspect; + float f_h = base_f; + if (windowAspect >= virtualAspect) { + f_h *= virtualAspect / windowAspect; + } + else { + f_v *= windowAspect / virtualAspect; + } + float depth = m_back - m_front; D3DRMMATRIX4D projection = { - {f, 0, 0, 0}, - {0, f * aspect, 0, 0}, + {f_h, 0, 0, 0}, + {0, f_v, 0, 0}, {0, 0, m_back / depth, 1}, {0, 0, (-m_front * m_back) / depth, 0}, }; @@ -442,8 +462,8 @@ void Direct3DRMViewportImpl::UpdateProjectionMatrix() m_renderer->SetProjection(projection, m_front, m_back); D3DRMMATRIX4D inverseProjectionMatrix = { - {1.0f / f, 0, 0, 0}, - {0, 1.0f / (f * aspect), 0, 0}, + {1.0f / f_h, 0, 0, 0}, + {0, 1.0f / f_v, 0, 0}, {0, 0, 0, depth / (-m_front * m_back)}, {0, 0, 1, -(m_back / depth) * depth / (-m_front * m_back)}, }; @@ -455,16 +475,6 @@ D3DVALUE Direct3DRMViewportImpl::GetField() return m_field; } -DWORD Direct3DRMViewportImpl::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMViewportImpl::GetHeight() -{ - return m_height; -} - inline float FromNDC(float ndcCoord, float dim) { return (ndcCoord * 0.5f + 0.5f) * dim; @@ -492,8 +502,8 @@ HRESULT Direct3DRMViewportImpl::Transform(D3DRMVECTOR4D* screen, D3DVECTOR* worl float ndcX = projVec.x * invW; float ndcY = projVec.y * invW; - screen->x = FromNDC(ndcX, m_width); - screen->y = FromNDC(-ndcY, m_height); // Y-flip + screen->x = FromNDC(ndcX, m_virtualWidth); + screen->y = FromNDC(-ndcY, m_virtualHeight); // Y-flip // Undo perspective divide for screen-space coords screen->x *= projVec.z; @@ -509,8 +519,8 @@ HRESULT Direct3DRMViewportImpl::InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D float screenY = screen->y / screen->w; // Convert screen coordinates to NDC - float ndcX = screenX / m_width * 2.0f - 1.0f; - float ndcY = 1.0f - (screenY / m_height) * 2.0f; + float ndcX = screenX / m_virtualWidth * 2.0f - 1.0f; + float ndcY = 1.0f - (screenY / m_virtualHeight) * 2.0f; D3DRMVECTOR4D clipVec = {ndcX * screen->w, ndcY * screen->w, screen->z, screen->w}; @@ -753,13 +763,13 @@ HRESULT Direct3DRMViewportImpl::Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* Ray pickRay = BuildPickingRay( x, y, - m_width, - m_height, + m_virtualWidth, + m_virtualHeight, m_camera, m_front, m_back, m_field, - (float) m_width / (float) m_height + (float) m_virtualWidth / (float) m_virtualHeight ); std::function&)> recurse; diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index bd1541a3..2765a2a1 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -23,9 +23,7 @@ #include SDL_Window* DDWindow; -SDL_Surface* DDBackBuffer; -FrameBufferImpl* DDFrameBuffer; -SDL_Renderer* DDRenderer; +Direct3DRMRenderer* DDRenderer; HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject) { @@ -82,13 +80,13 @@ HRESULT DirectDrawImpl::CreateSurface( return DD_OK; } if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) == DDSCAPS_PRIMARYSURFACE) { - DDFrameBuffer = new FrameBufferImpl(); - *lplpDDSurface = static_cast(DDFrameBuffer); + m_frameBuffer = new FrameBufferImpl(m_virtualWidth, m_virtualHeight); + *lplpDDSurface = static_cast(m_frameBuffer); return DD_OK; } if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) == DDSCAPS_3DDEVICE) { - DDFrameBuffer->AddRef(); - *lplpDDSurface = static_cast(DDFrameBuffer); + m_frameBuffer->AddRef(); + *lplpDDSurface = static_cast(m_frameBuffer); return DD_OK; } if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_TEXTURE) == DDSCAPS_TEXTURE) { @@ -100,7 +98,7 @@ HRESULT DirectDrawImpl::CreateSurface( #ifdef MINIWIN_PIXELFORMAT format = MINIWIN_PIXELFORMAT; #else - format = SDL_PIXELFORMAT_RGBA8888; + format = SDL_PIXELFORMAT_RGBA32; #endif if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) == DDSD_PIXELFORMAT) { if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) == DDPF_RGB) { @@ -284,6 +282,12 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags) { SDL_Window* sdlWindow = reinterpret_cast(hWnd); + if (m_virtualWidth == 0 || m_virtualHeight == 0) { + if (!SDL_GetWindowSize(sdlWindow, &m_virtualWidth, &m_virtualHeight)) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_GetWindowSizeInPixels: %s", SDL_GetError()); + } + } + if (sdlWindow) { bool fullscreen; if ((dwFlags & DDSCL_NORMAL) == DDSCL_NORMAL) { @@ -302,15 +306,14 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags) #endif } DDWindow = sdlWindow; - DDRenderer = SDL_CreateRenderer(DDWindow, NULL); - SDL_PropertiesID prop = SDL_GetRendererProperties(DDRenderer); - SDL_SetRenderLogicalPresentation(DDRenderer, 640, 480, SDL_LOGICAL_PRESENTATION_LETTERBOX); } return DD_OK; } HRESULT DirectDrawImpl::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) { + m_virtualWidth = dwWidth; + m_virtualHeight = dwHeight; return DD_OK; } @@ -325,33 +328,32 @@ HRESULT DirectDrawImpl::CreateDevice( DDSDesc.dwSize = sizeof(DDSURFACEDESC); pBackBuffer->GetSurfaceDesc(&DDSDesc); - Direct3DRMRenderer* renderer; if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { - renderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #ifdef USE_OPENGLES2 else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - renderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef USE_OPENGL1 else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { - renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef _WIN32 else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { - renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { - renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); return E_NOINTERFACE; } - *ppDirect3DDevice = static_cast(renderer); + *ppDirect3DDevice = static_cast(DDRenderer); return DD_OK; } diff --git a/miniwin/src/ddraw/ddsurface.cpp b/miniwin/src/ddraw/ddsurface.cpp index 59c4569a..de250dea 100644 --- a/miniwin/src/ddraw/ddsurface.cpp +++ b/miniwin/src/ddraw/ddsurface.cpp @@ -1,3 +1,4 @@ +#include "d3drmtexture_impl.h" #include "ddpalette_impl.h" #include "ddraw_impl.h" #include "ddsurface_impl.h" @@ -19,6 +20,9 @@ DirectDrawSurfaceImpl::~DirectDrawSurfaceImpl() if (m_palette) { m_palette->Release(); } + if (m_texture) { + m_texture->Release(); + } } // IUnknown interface @@ -69,6 +73,9 @@ HRESULT DirectDrawSurfaceImpl::Blt( if (blitSource != other->m_surface) { SDL_DestroySurface(blitSource); } + if (m_texture) { + m_texture->Changed(TRUE, FALSE); + } return DD_OK; } @@ -203,6 +210,10 @@ HRESULT DirectDrawSurfaceImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) MINIWIN_NOT_IMPLEMENTED(); } + if (m_texture) { + m_texture->Changed(FALSE, TRUE); + } + if (m_palette) { m_palette->Release(); } @@ -216,5 +227,16 @@ HRESULT DirectDrawSurfaceImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) HRESULT DirectDrawSurfaceImpl::Unlock(LPVOID lpSurfaceData) { SDL_UnlockSurface(m_surface); + if (m_texture) { + m_texture->Changed(TRUE, FALSE); + } return DD_OK; } + +IDirect3DRMTexture2* DirectDrawSurfaceImpl::ToTexture() +{ + if (!m_texture) { + m_texture = new Direct3DRMTextureImpl(this, false); + } + return m_texture; +} diff --git a/miniwin/src/ddraw/framebuffer.cpp b/miniwin/src/ddraw/framebuffer.cpp index eee8b7cb..eb21abef 100644 --- a/miniwin/src/ddraw/framebuffer.cpp +++ b/miniwin/src/ddraw/framebuffer.cpp @@ -6,21 +6,15 @@ #include -FrameBufferImpl::FrameBufferImpl() +FrameBufferImpl::FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight) + : m_virtualWidth(virtualWidth), m_virtualHeight(virtualHeight) { - int width, height; - SDL_GetRenderOutputSize(DDRenderer, &width, &height); - DDBackBuffer = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA8888); - if (!DDBackBuffer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create surface: %s", SDL_GetError()); - } - m_uploadBuffer = - SDL_CreateTexture(DDRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height); + m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_RGBA32); } FrameBufferImpl::~FrameBufferImpl() { - SDL_DestroySurface(DDBackBuffer); + m_transferBuffer->Release(); if (m_palette) { m_palette->Release(); } @@ -51,44 +45,30 @@ HRESULT FrameBufferImpl::Blt( LPDDBLTFX lpDDBltFx ) { + if (!DDRenderer) { + return DDERR_GENERIC; + } if (dynamic_cast(lpDDSrcSurface) == this) { return Flip(nullptr, DDFLIP_WAIT); } if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) { - SDL_Rect rect = {0, 0, DDBackBuffer->w, DDBackBuffer->h}; - const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(DDBackBuffer->format); Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF; Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF; Uint8 b = lpDDBltFx->dwFillColor & 0xFF; - DirectDrawPaletteImpl* ddPal = static_cast(m_palette); - SDL_Palette* sdlPalette = ddPal ? ddPal->m_palette : nullptr; - Uint32 color = SDL_MapRGB(details, sdlPalette, r, g, b); - SDL_FillSurfaceRect(DDBackBuffer, &rect, color); + DDRenderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f); return DD_OK; } - auto other = static_cast(lpDDSrcSurface); - if (!other) { + auto surface = static_cast(lpDDSrcSurface); + if (!surface) { return DDERR_GENERIC; } - SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, other->m_surface->w, other->m_surface->h}; - SDL_Rect dstRect = lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, DDBackBuffer->w, DDBackBuffer->h}; + Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture()); + SDL_Rect srcRect = + lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, surface->m_surface->w, surface->m_surface->h}; + SDL_Rect dstRect = + lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, (int) m_virtualWidth, (int) m_virtualHeight}; + DDRenderer->Draw2DImage(textureId, srcRect, dstRect); - SDL_Surface* blitSource = other->m_surface; - - if (other->m_surface->format != DDBackBuffer->format) { - blitSource = SDL_ConvertSurface(other->m_surface, DDBackBuffer->format); - if (!blitSource) { - return DDERR_GENERIC; - } - } - - if (!SDL_BlitSurfaceScaled(blitSource, &srcRect, DDBackBuffer, &dstRect, SDL_SCALEMODE_NEAREST)) { - return DDERR_GENERIC; - } - - if (blitSource != other->m_surface) { - SDL_DestroySurface(blitSource); - } return DD_OK; } @@ -100,20 +80,20 @@ HRESULT FrameBufferImpl::BltFast( DDBltFastFlags dwTrans ) { - RECT destRect = { - (int) dwX, - (int) dwY, - (int) (lpSrcRect->right - lpSrcRect->left + dwX), - (int) (lpSrcRect->bottom - lpSrcRect->top + dwY) - }; + auto surface = static_cast(lpDDSrcSurface); + int width = lpSrcRect ? (lpSrcRect->right - lpSrcRect->left) : surface->m_surface->w; + int height = lpSrcRect ? (lpSrcRect->bottom - lpSrcRect->top) : surface->m_surface->h; + RECT destRect = {(int) dwX, (int) dwY, (int) (dwX + width), (int) (dwY + height)}; + return Blt(&destRect, lpDDSrcSurface, lpSrcRect, DDBLT_NONE, nullptr); } HRESULT FrameBufferImpl::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DDFlipFlags dwFlags) { - SDL_UpdateTexture(m_uploadBuffer, nullptr, DDBackBuffer->pixels, DDBackBuffer->pitch); - SDL_RenderTexture(DDRenderer, m_uploadBuffer, nullptr, nullptr); - SDL_RenderPresent(DDRenderer); + if (!DDRenderer) { + return DDERR_GENERIC; + } + DDRenderer->Flip(); return DD_OK; } @@ -146,7 +126,7 @@ HRESULT FrameBufferImpl::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) { memset(lpDDPixelFormat, 0, sizeof(*lpDDPixelFormat)); lpDDPixelFormat->dwFlags = DDPF_RGB; - const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(DDBackBuffer->format); + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format); if (details->bits_per_pixel == 8) { lpDDPixelFormat->dwFlags |= DDPF_PALETTEINDEXED8; } @@ -163,25 +143,28 @@ HRESULT FrameBufferImpl::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc) lpDDSurfaceDesc->dwFlags = DDSD_PIXELFORMAT; GetPixelFormat(&lpDDSurfaceDesc->ddpfPixelFormat); lpDDSurfaceDesc->dwFlags |= DDSD_WIDTH | DDSD_HEIGHT; - lpDDSurfaceDesc->dwWidth = DDBackBuffer->w; - lpDDSurfaceDesc->dwHeight = DDBackBuffer->h; - return DD_OK; -} - -HRESULT FrameBufferImpl::IsLost() -{ + lpDDSurfaceDesc->dwWidth = m_transferBuffer->m_surface->w; + lpDDSurfaceDesc->dwHeight = m_transferBuffer->m_surface->h; return DD_OK; } HRESULT FrameBufferImpl::Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent) { - if (!SDL_LockSurface(DDBackBuffer)) { + if (!DDRenderer) { return DDERR_GENERIC; } + if ((dwFlags & DDLOCK_WRITEONLY) == DDLOCK_WRITEONLY) { + SDL_Rect rect = {0, 0, m_transferBuffer->m_surface->w, m_transferBuffer->m_surface->h}; + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format); + SDL_Palette* palette = m_palette ? static_cast(m_palette)->m_palette : nullptr; + Uint32 color = SDL_MapRGBA(details, palette, 0, 0, 0, 0); + SDL_FillSurfaceRect(m_transferBuffer->m_surface, &rect, color); + } + else { + DDRenderer->Download(m_transferBuffer->m_surface); + } - GetSurfaceDesc(lpDDSurfaceDesc); - lpDDSurfaceDesc->lpSurface = DDBackBuffer->pixels; - lpDDSurfaceDesc->lPitch = DDBackBuffer->pitch; + m_transferBuffer->Lock(lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent); return DD_OK; } @@ -198,11 +181,6 @@ HRESULT FrameBufferImpl::Restore() return DD_OK; } -HRESULT FrameBufferImpl::SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper) -{ - return DD_OK; -} - HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey) { MINIWIN_NOT_IMPLEMENTED(); @@ -211,7 +189,7 @@ HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDC HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) { - if (DDBackBuffer->format != SDL_PIXELFORMAT_INDEX8) { + if (m_transferBuffer->m_surface->format != SDL_PIXELFORMAT_INDEX8) { MINIWIN_NOT_IMPLEMENTED(); } @@ -220,13 +198,15 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) } m_palette = lpDDPalette; - SDL_SetSurfacePalette(DDBackBuffer, ((DirectDrawPaletteImpl*) m_palette)->m_palette); + SDL_SetSurfacePalette(m_transferBuffer->m_surface, ((DirectDrawPaletteImpl*) m_palette)->m_palette); m_palette->AddRef(); return DD_OK; } HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData) { - SDL_UnlockSurface(DDBackBuffer); + m_transferBuffer->Unlock(lpSurfaceData); + BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT); + return DD_OK; } diff --git a/miniwin/src/internal/d3drmdevice_impl.h b/miniwin/src/internal/d3drmdevice_impl.h index ad30f75a..daab564a 100644 --- a/miniwin/src/internal/d3drmdevice_impl.h +++ b/miniwin/src/internal/d3drmdevice_impl.h @@ -11,8 +11,8 @@ struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl vertices; std::vector indices; @@ -67,8 +67,13 @@ struct MeshGroup { struct Direct3DRMMeshImpl : public Direct3DRMObjectBaseImpl { HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; HRESULT Clone(int flags, GUID iid, void** object) override; - HRESULT AddGroup(int vertexCount, int faceCount, int vertexPerFace, DWORD* faceBuffer, D3DRMGROUPINDEX* groupIndex) - override; + HRESULT AddGroup( + unsigned int vertexCount, + unsigned int faceCount, + unsigned int vertexPerFace, + unsigned int* faceBuffer, + D3DRMGROUPINDEX* groupIndex + ) override; HRESULT GetGroup( D3DRMGROUPINDEX groupIndex, unsigned int* vertexCount, diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index e1e7e558..e76f0759 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -26,8 +26,6 @@ struct Plane { float d; }; -extern SDL_Renderer* DDRenderer; - class Direct3DRMRenderer : public IDirect3DDevice2 { public: virtual void PushLights(const SceneLight* vertices, size_t count) = 0; @@ -35,8 +33,10 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { virtual void SetFrustumPlanes(const Plane* frustumPlanes) = 0; virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0; virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0; - virtual DWORD GetWidth() = 0; - virtual DWORD GetHeight() = 0; + int GetWidth() { return m_width; } + int GetHeight() { return m_height; } + int GetVirtualWidth() { return m_virtualWidth; } + int GetVirtualHeight() { return m_virtualHeight; } virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0; virtual const char* GetName() = 0; virtual HRESULT BeginFrame() = 0; @@ -44,13 +44,20 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { virtual void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) = 0; virtual HRESULT FinalizeFrame() = 0; + virtual void Resize(int width, int height, const ViewportTransform& viewportTransform) = 0; + virtual void Clear(float r, float g, float b) = 0; + virtual void Flip() = 0; + virtual void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) = 0; + virtual void Download(SDL_Surface* target) = 0; - bool ConvertEventToRenderCoordinates(SDL_Event* event) - { - return SDL_ConvertEventToRenderCoordinates(DDRenderer, event); - } +protected: + int m_width, m_height; + int m_virtualWidth, m_virtualHeight; + ViewportTransform m_viewportTransform; }; diff --git a/miniwin/src/internal/d3drmrenderer_directx9.h b/miniwin/src/internal/d3drmrenderer_directx9.h index 8df63424..b7badb03 100644 --- a/miniwin/src/internal/d3drmrenderer_directx9.h +++ b/miniwin/src/internal/d3drmrenderer_directx9.h @@ -20,8 +20,6 @@ class DirectX9Renderer : public Direct3DRMRenderer { void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -29,17 +27,23 @@ class DirectX9Renderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); SDL_Surface* m_renderedImage; - DWORD m_width, m_height; std::vector m_lights; std::vector m_meshs; std::vector m_textures; diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index 763509d8..71c0ea82 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -42,7 +42,7 @@ struct GLMeshCacheEntry { class OpenGL1Renderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); - OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint fbo, GLuint colorTex, GLuint depthRb); + OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context); ~OpenGL1Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; @@ -50,8 +50,6 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -59,10 +57,17 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); @@ -72,13 +77,11 @@ class OpenGL1Renderer : public Direct3DRMRenderer { std::vector m_meshs; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; - DWORD m_width, m_height; bool m_useVBOs; + bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context; - GLuint m_fbo; - GLuint m_colorTex; - GLuint m_depthRb; + ViewportTransform m_viewportTransform; }; inline static void OpenGL1Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) diff --git a/miniwin/src/internal/d3drmrenderer_opengles2.h b/miniwin/src/internal/d3drmrenderer_opengles2.h index 94ff70ee..7ea1ed9a 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles2.h +++ b/miniwin/src/internal/d3drmrenderer_opengles2.h @@ -14,6 +14,8 @@ struct GLES2TextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; GLuint glTextureId; + uint16_t width; + uint16_t height; }; struct GLES2MeshCacheEntry { @@ -31,15 +33,7 @@ struct GLES2MeshCacheEntry { class OpenGLES2Renderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); - OpenGLES2Renderer( - DWORD width, - DWORD height, - SDL_GLContext context, - GLuint fbo, - GLuint colorTex, - GLuint vertexBuffer, - GLuint shaderProgram - ); + OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram); ~OpenGLES2Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; @@ -47,8 +41,6 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -56,10 +48,17 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); @@ -69,13 +68,11 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { std::vector m_meshs; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; - DWORD m_width, m_height; + bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context; - GLuint m_fbo; - GLuint m_colorTex; - GLuint m_depthRb; GLuint m_shaderProgram; + ViewportTransform m_viewportTransform; }; inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index 3a20000e..25485b1f 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -51,8 +51,6 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -60,10 +58,17 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: Direct3DRMSDL3GPURenderer( @@ -72,12 +77,13 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { SDL_GPUDevice* device, SDL_GPUGraphicsPipeline* opaquePipeline, SDL_GPUGraphicsPipeline* transparentPipeline, - SDL_GPUTexture* transferTexture, - SDL_GPUTexture* depthTexture, + SDL_GPUGraphicsPipeline* uiPipeline, SDL_GPUSampler* sampler, + SDL_GPUSampler* uiSampler, SDL_GPUTransferBuffer* uploadBuffer, - SDL_GPUTransferBuffer* downloadBuffer + int uploadBufferSize ); + void StartRenderPass(float r, float g, float b, bool clear); void WaitForPendingUpload(); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); SDL_GPUTransferBuffer* GetUploadBuffer(size_t size); @@ -85,26 +91,29 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); SDL3MeshCache UploadMesh(const MeshGroup& meshGroup); - DWORD m_width; - DWORD m_height; + MeshGroup m_uiMesh; + SDL3MeshCache m_uiMeshCache; D3DVALUE m_front; D3DVALUE m_back; ViewportUniforms m_uniforms; FragmentShadingData m_fragmentShadingData; D3DDEVICEDESC m_desc; + D3DRMMATRIX4D m_projection; std::vector m_textures; std::vector m_meshs; SDL_GPUDevice* m_device; SDL_GPUGraphicsPipeline* m_opaquePipeline; SDL_GPUGraphicsPipeline* m_transparentPipeline; - SDL_GPUTexture* m_transferTexture; - SDL_GPUTexture* m_depthTexture; + SDL_GPUGraphicsPipeline* m_uiPipeline; + SDL_GPUTexture* m_transferTexture = nullptr; + SDL_GPUTexture* m_depthTexture = nullptr; SDL_GPUTexture* m_dummyTexture; int m_uploadBufferSize; SDL_GPUTransferBuffer* m_uploadBuffer; - SDL_GPUTransferBuffer* m_downloadBuffer; + SDL_GPUTransferBuffer* m_downloadBuffer = nullptr; SDL_GPUBuffer* m_vertexBuffer = nullptr; SDL_GPUSampler* m_sampler; + SDL_GPUSampler* m_uiSampler; SDL_GPUCommandBuffer* m_cmdbuf = nullptr; SDL_GPURenderPass* m_renderPass = nullptr; SDL_GPUFence* m_uploadFence = nullptr; diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 6df2b4a4..444a80a3 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -27,13 +27,12 @@ struct MeshCache { class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { public: Direct3DRMSoftwareRenderer(DWORD width, DWORD height); + ~Direct3DRMSoftwareRenderer() override; void PushLights(const SceneLight* vertices, size_t count) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -41,10 +40,17 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void ClearZBuffer(); @@ -61,9 +67,10 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); - DWORD m_width; - DWORD m_height; + SDL_Surface* m_renderedImage = nullptr; SDL_Palette* m_palette; + SDL_Texture* m_uploadBuffer = nullptr; + SDL_Renderer* m_renderer; const SDL_PixelFormatDetails* m_format; int m_bytesPerPixel; std::vector m_lights; diff --git a/miniwin/src/internal/d3drmtexture_impl.h b/miniwin/src/internal/d3drmtexture_impl.h index e81c3884..35ef7779 100644 --- a/miniwin/src/internal/d3drmtexture_impl.h +++ b/miniwin/src/internal/d3drmtexture_impl.h @@ -4,10 +4,12 @@ struct Direct3DRMTextureImpl : public Direct3DRMObjectBaseImpl { Direct3DRMTextureImpl(D3DRMIMAGE* image); - Direct3DRMTextureImpl(IDirectDrawSurface* surface); + Direct3DRMTextureImpl(IDirectDrawSurface* surface, bool holdsRef); + ~Direct3DRMTextureImpl() override; HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; HRESULT Changed(BOOL pixels, BOOL palette) override; IDirectDrawSurface* m_surface = nullptr; Uint8 m_version = 0; + bool m_holdsRef; }; diff --git a/miniwin/src/internal/d3drmviewport_impl.h b/miniwin/src/internal/d3drmviewport_impl.h index c27af586..b23652d0 100644 --- a/miniwin/src/internal/d3drmviewport_impl.h +++ b/miniwin/src/internal/d3drmviewport_impl.h @@ -10,6 +10,7 @@ struct DeferredDrawCommand { DWORD meshId; D3DRMMATRIX4D modelViewMatrix; + D3DRMMATRIX4D worldMatrix; Matrix3x3 normalMatrix; Appearance appearance; float depth; @@ -36,24 +37,24 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl& lights); void CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix); void BuildViewFrustumPlanes(); - void UpdateProjectionMatrix(); Direct3DRMRenderer* m_renderer; std::vector m_deferredDraws; D3DCOLOR m_backgroundColor = 0xFF000000; - DWORD m_width; - DWORD m_height; + DWORD m_virtualWidth; + DWORD m_virtualHeight; D3DRMMATRIX4D m_viewProjectionwMatrix; D3DRMMATRIX4D m_viewMatrix; D3DRMMATRIX4D m_projectionMatrix; diff --git a/miniwin/src/internal/ddraw_impl.h b/miniwin/src/internal/ddraw_impl.h index 7cefe2f6..f2604946 100644 --- a/miniwin/src/internal/ddraw_impl.h +++ b/miniwin/src/internal/ddraw_impl.h @@ -8,9 +8,7 @@ #include extern SDL_Window* DDWindow; -extern SDL_Surface* DDBackBuffer; -extern FrameBufferImpl* DDFrameBuffer; -extern SDL_Renderer* DDRenderer; +extern Direct3DRMRenderer* DDRenderer; inline static SDL_Rect ConvertRect(const RECT* r) { @@ -47,6 +45,11 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 { HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice) override; HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override; + +private: + FrameBufferImpl* m_frameBuffer; + int m_virtualWidth = 0; + int m_virtualHeight = 0; }; HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context); diff --git a/miniwin/src/internal/ddsurface_impl.h b/miniwin/src/internal/ddsurface_impl.h index 4218e157..62fab18a 100644 --- a/miniwin/src/internal/ddsurface_impl.h +++ b/miniwin/src/internal/ddsurface_impl.h @@ -35,8 +35,11 @@ struct DirectDrawSurfaceImpl : public IDirectDrawSurface3 { HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override; HRESULT Unlock(LPVOID lpSurfaceData) override; + IDirect3DRMTexture2* ToTexture(); + SDL_Surface* m_surface = nullptr; private: + IDirect3DRMTexture2* m_texture = nullptr; IDirectDrawPalette* m_palette = nullptr; }; diff --git a/miniwin/src/internal/framebuffer_impl.h b/miniwin/src/internal/framebuffer_impl.h index c2d9e3c8..5e40f7e8 100644 --- a/miniwin/src/internal/framebuffer_impl.h +++ b/miniwin/src/internal/framebuffer_impl.h @@ -5,7 +5,7 @@ #include struct FrameBufferImpl : public IDirectDrawSurface3 { - FrameBufferImpl(); + FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight); ~FrameBufferImpl() override; // IUnknown interface @@ -27,16 +27,18 @@ struct FrameBufferImpl : public IDirectDrawSurface3 { HRESULT GetPalette(LPDIRECTDRAWPALETTE* lplpDDPalette) override; HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) override; HRESULT GetSurfaceDesc(DDSURFACEDESC* lpDDSurfaceDesc) override; - HRESULT IsLost() override; + HRESULT IsLost() override { return DD_OK; } HRESULT Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent) override; HRESULT ReleaseDC(HDC hDC) override; HRESULT Restore() override; - HRESULT SetClipper(IDirectDrawClipper* lpDDClipper) override; + HRESULT SetClipper(IDirectDrawClipper* lpDDClipper) override { return DD_OK; } HRESULT SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey) override; HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override; HRESULT Unlock(LPVOID lpSurfaceData) override; private: - SDL_Texture* m_uploadBuffer; + uint32_t m_virtualWidth; + uint32_t m_virtualHeight; + DirectDrawSurfaceImpl* m_transferBuffer; IDirectDrawPalette* m_palette = nullptr; }; diff --git a/miniwin/src/internal/structs.h b/miniwin/src/internal/structs.h index 4f745098..43bda0ed 100644 --- a/miniwin/src/internal/structs.h +++ b/miniwin/src/internal/structs.h @@ -15,3 +15,9 @@ struct Appearance { uint32_t textureId; uint32_t flat; }; + +struct ViewportTransform { + float scale; + float offsetX; + float offsetY; +};