Merge pull request #3 from AJenbo/psp

This commit is contained in:
VoxelTek 2025-06-26 11:03:59 +10:00 committed by GitHub
commit 415d9bf2e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
89 changed files with 2226 additions and 1063 deletions

View File

@ -66,7 +66,8 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y \ sudo apt-get install -y \
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ 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) - name: Install macOS dependencies (brew)
if: ${{ matrix.brew }} if: ${{ matrix.brew }}

View File

@ -45,7 +45,8 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y \ sudo apt-get install -y \
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ 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) - name: Install macOS dependencies (brew)
if: ${{ matrix.brew }} if: ${{ matrix.brew }}

View File

@ -30,16 +30,6 @@ target_compile_definitions(miniaudio PUBLIC
MA_NO_RUNTIME_LINKING MA_NO_RUNTIME_LINKING
) )
if(PSP)
target_compile_definitions(miniaudio PUBLIC
MA_NO_RUNTIME_LINKING
)
endif()
if(DOWNLOAD_DEPENDENCIES) if(DOWNLOAD_DEPENDENCIES)
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(

View File

@ -26,7 +26,7 @@ else()
endif() endif()
find_program(SDL_SHADERCROSS_BIN NAMES "shadercross") 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_BUILD_APP "Build isle application" ON)
option(ISLE_ASAN "Enable Address Sanitizer" OFF) 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 "Isle debugging: ${ISLE_DEBUG}")
message(STATUS "Compile shaders: ${ISLE_COMPILE_SHADERS}") message(STATUS "Compile shaders: ${ISLE_COMPILE_SHADERS}")
add_library(Isle::iniparser INTERFACE IMPORTED)
if (DOWNLOAD_DEPENDENCIES) if (DOWNLOAD_DEPENDENCIES)
# FetchContent downloads and configures dependencies # FetchContent downloads and configures dependencies
include(FetchContent) include(FetchContent)
@ -77,6 +79,7 @@ if (DOWNLOAD_DEPENDENCIES)
set(BUILD_DOCS off) set(BUILD_DOCS off)
set(BUILD_SHARED_LIBS off) set(BUILD_SHARED_LIBS off)
FetchContent_MakeAvailable(iniparser) FetchContent_MakeAvailable(iniparser)
target_link_libraries(Isle::iniparser INTERFACE iniparser-static)
endblock() endblock()
else() else()
# find_package looks for already-installed system packages. # find_package looks for already-installed system packages.
@ -84,10 +87,8 @@ else()
# to add search paths. # to add search paths.
find_package(SDL3 CONFIG REQUIRED) find_package(SDL3 CONFIG REQUIRED)
find_package(iniparser CONFIG COMPONENTS static) find_package(iniparser REQUIRED CONFIG COMPONENTS shared)
if (NOT TARGET iniparser-static) target_link_libraries(Isle::iniparser INTERFACE iniparser-shared)
find_package(iniparser REQUIRED MODULE COMPONENTS static)
endif()
endif() endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@ -493,7 +494,7 @@ if (ISLE_BUILD_APP)
target_link_libraries(isle PRIVATE $<$<BOOL:${ISLE_USE_DX5}>:DirectX5::DirectX5>) target_link_libraries(isle PRIVATE $<$<BOOL:${ISLE_USE_DX5}>:DirectX5::DirectX5>)
# Link SDL and iniparser # 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 # Allow unconditional include of miniwin/miniwindevice.h
target_link_libraries(isle PRIVATE miniwin-headers) target_link_libraries(isle PRIVATE miniwin-headers)
@ -559,7 +560,7 @@ if (ISLE_BUILD_CONFIG)
target_link_libraries(config PRIVATE DirectX5::DirectX5) target_link_libraries(config PRIVATE DirectX5::DirectX5)
endif() endif()
target_compile_definitions(config PRIVATE DIRECT3D_VERSION=0x500) 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) if (NOT ISLE_MINIWIN)
target_link_libraries(config PRIVATE ddraw dxguid) target_link_libraries(config PRIVATE ddraw dxguid)
endif() endif()
@ -672,4 +673,3 @@ else()
set(CPACK_GENERATOR TGZ) set(CPACK_GENERATOR TGZ)
endif() endif()
include(CPack) include(CPack)

View File

@ -1,5 +1,5 @@
diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js 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 --- a/src/lib/libwasmfs_fetch.js
+++ b/src/lib/libwasmfs_fetch.js +++ b/src/lib/libwasmfs_fetch.js
@@ -38,36 +38,7 @@ addToLibrary({ @@ -38,36 +38,7 @@ addToLibrary({
@ -49,7 +49,7 @@ index e8c9f7e21..5c3a3dfbe 100644
allPresent = false; allPresent = false;
break; break;
} }
@@ -90,16 +61,36 @@ addToLibrary({ @@ -90,16 +61,37 @@ addToLibrary({
// one request for all the chunks we need, rather than one // one request for all the chunks we need, rather than one
// request per chunk. // request per chunk.
var start = firstChunk * chunkSize; var start = firstChunk * chunkSize;
@ -66,8 +66,10 @@ index e8c9f7e21..5c3a3dfbe 100644
if (!response.ok) { if (!response.ok) {
throw response; 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)) { + if (!(file in wasmFS$JSMemoryRanges)) {
+ var size = Math.max( + var size = Math.max(
+ parseInt(response.headers.get('Content-Range').split('/')[1], 10), + parseInt(response.headers.get('Content-Range').split('/')[1], 10),
@ -87,7 +89,7 @@ index e8c9f7e21..5c3a3dfbe 100644
return Promise.resolve(); return Promise.resolve();
} }
@@ -164,6 +155,21 @@ addToLibrary({ @@ -164,6 +156,21 @@ addToLibrary({
return wasmFS$JSMemoryRanges[file].size; return wasmFS$JSMemoryRanges[file].size;
}, },
}; };

View File

@ -109,7 +109,7 @@ IsleApp::IsleApp()
m_drawCursor = FALSE; m_drawCursor = FALSE;
m_use3dSound = TRUE; m_use3dSound = TRUE;
m_useMusic = TRUE; m_useMusic = TRUE;
m_useJoystick = FALSE; m_useJoystick = TRUE;
m_joystickIndex = 0; m_joystickIndex = 0;
m_wideViewAngle = TRUE; m_wideViewAngle = TRUE;
m_islandQuality = 2; m_islandQuality = 2;
@ -394,6 +394,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
#endif #endif
switch (event->type) { switch (event->type) {
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: 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; 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; break;
} }
@ -652,6 +659,7 @@ MxResult IsleApp::SetupWindow()
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE);
#ifdef MINIWIN #ifdef MINIWIN
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#endif #endif
window = SDL_CreateWindowWithProperties(props); window = SDL_CreateWindowWithProperties(props);
@ -788,6 +796,7 @@ bool IsleApp::LoadConfig()
return false; return false;
} }
char buf[32];
dict = iniparser_load(iniConfig); dict = iniparser_load(iniConfig);
iniparser_set(dict, "isle", NULL); 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:Music", m_useMusic ? "true" : "false");
iniparser_set(dict, "isle:UseJoystick", m_useJoystick ? "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:Draw Cursor", m_drawCursor ? "true" : "false");
iniparser_set(dict, "isle:Back Buffers in Video RAM", "-1"); 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 Quality", SDL_itoa(m_islandQuality, buf, 10));
iniparser_set(dict, "isle:Island Texture", SDL_itoa(m_islandTexture, buf, 10)); iniparser_set(dict, "isle:Island Texture", SDL_itoa(m_islandTexture, buf, 10));
SDL_snprintf(buf, sizeof(buf), "%f", m_maxLod); SDL_snprintf(buf, sizeof(buf), "%f", m_maxLod);
@ -1056,11 +1064,22 @@ MxResult IsleApp::VerifyFilesystem()
Emscripten_SetupFilesystem(); Emscripten_SetupFilesystem();
#else #else
for (const char* file : g_files) { for (const char* file : g_files) {
MxString path(&file[1]); const char* searchPaths[] = {".", m_hdPath, m_cdPath};
path.MapPathToFilesystem(); bool found = false;
if (!SDL_GetPathInfo(path.GetData(), NULL)) { for (const char* base : searchPaths) {
char buffer[512]; MxString path(base);
path += file;
path.MapPathToFilesystem();
if (SDL_GetPathInfo(path.GetData(), NULL)) {
found = true;
break;
}
}
if (!found) {
char buffer[1024];
SDL_snprintf( SDL_snprintf(
buffer, buffer,
sizeof(buffer), sizeof(buffer),

View File

@ -183,7 +183,11 @@ void IsleDebug_Init()
} }
g_videoPalette = g_videoPalette =
SDL_CreateTexture(g_debugRenderer, SDL_PIXELFORMAT_RGBX32, SDL_TEXTUREACCESS_STREAMING, 16, 16); 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)) { if (!ImGui_ImplSDLRenderer3_Init(g_debugRenderer)) {
g_debugEnabled = false; g_debugEnabled = false;
break; break;
@ -288,9 +292,9 @@ void IsleDebug_Render()
ImGui::Text("Actor Name: %s", gameState->GetActorName()); ImGui::Text("Actor Name: %s", gameState->GetActorName());
ImGui::Text("Current act: %d", gameState->GetCurrentAct()); ImGui::Text("Current act: %d", gameState->GetCurrentAct());
ImGui::Text("Loaded act: %d", gameState->GetLoadedAct()); ImGui::Text("Loaded act: %d", gameState->GetLoadedAct());
ImGui::Text("Previous area: %d", gameState->GetPreviousArea()); ImGui::Text("Previous area: %d", gameState->m_previousArea);
ImGui::Text("Unknown 0x42c: %d", gameState->GetUnknown0x42c()); ImGui::Text("Unknown 0x42c: %d", gameState->m_unk0x42c);
ImGui::Value("Player count", gameState->GetPlayerCount()); ImGui::Value("Player count", gameState->m_playerCount);
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Renderer")) { if (ImGui::TreeNode("Renderer")) {
@ -305,7 +309,7 @@ void IsleDebug_Render()
if (ImGui::TreeNode("Sound Manager")) { if (ImGui::TreeNode("Sound Manager")) {
LegoSoundManager* soundManager = lego->GetSoundManager(); LegoSoundManager* soundManager = lego->GetSoundManager();
Sint32 oldVolume = soundManager->GetVolume(); Sint32 oldVolume = soundManager->GetVolume();
int volume = oldVolume; Sint32 volume = oldVolume;
ImGui::SliderInt("volume", &volume, 0, 100); ImGui::SliderInt("volume", &volume, 0, 100);
if (volume != oldVolume) { if (volume != oldVolume) {
soundManager->SetVolume(volume); soundManager->SetVolume(volume);

View File

@ -157,7 +157,18 @@ class LegoGameState {
MxS16 m_totalScore; // 0x00 MxS16 m_totalScore; // 0x00
MxU8 m_scores[5][5]; // 0x02 MxU8 m_scores[5][5]; // 0x02
Username m_name; // 0x1c 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 // SIZE 0x372
@ -165,7 +176,7 @@ class LegoGameState {
History(); History();
void WriteScoreHistory(); void WriteScoreHistory();
MxResult Serialize(LegoStorage* p_storage); 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 // FUNCTION: BETA10 0x1002c2b0
MxS16 GetCount() { return m_count; } MxS16 GetCount() { return m_count; }
@ -174,9 +185,12 @@ class LegoGameState {
// FUNCTION: BETA10 0x1002c540 // FUNCTION: BETA10 0x1002c540
ScoreItem* GetScore(MxS32 p_index) { return p_index >= m_count ? NULL : &m_scores[p_index]; } ScoreItem* GetScore(MxS32 p_index) { return p_index >= m_count ? NULL : &m_scores[p_index]; }
MxS16 m_count; // 0x00 MxS16 m_count; // 0x00
ScoreItem m_scores[20]; // 0x02 #ifdef BETA10
MxS16 m_unk0x372; // 0x372 MxS16 m_indices[20]; // 0x02
#endif
ScoreItem m_scores[20]; // 0x02 (0x22 for BETA10)
MxS16 m_nextPlayerId; // 0x372 (0x392 for BETA10)
}; };
LEGO1_EXPORT LegoGameState(); LEGO1_EXPORT LegoGameState();
@ -216,14 +230,8 @@ class LegoGameState {
Act GetCurrentAct() { return m_currentAct; } Act GetCurrentAct() { return m_currentAct; }
Act GetLoadedAct() { return m_loadedAct; } 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; } 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; } LegoBackgroundColor* GetBackgroundColor() { return m_backgroundColor; }
void SetCurrentAct(Act p_currentAct); void SetCurrentAct(Act p_currentAct);
@ -249,14 +257,11 @@ class LegoGameState {
LegoBackgroundColor* m_tempBackgroundColor; // 0x1c LegoBackgroundColor* m_tempBackgroundColor; // 0x1c
LegoFullScreenMovie* m_fullScreenMovie; // 0x20 LegoFullScreenMovie* m_fullScreenMovie; // 0x20
// TODO: Most likely getters/setters are not used according to BETA for the following members:
public: public:
MxS16 m_unk0x24; // 0x24 MxS16 m_currentPlayerId; // 0x24
MxS16 m_playerCount; // 0x26 MxS16 m_playerCount; // 0x26
Username m_players[9]; // 0x28 Username m_players[9]; // 0x28
History m_history; // 0xa6 History m_history; // 0xa6
undefined2 m_unk0x41a; // 0x41a
JukeboxScript::Script m_jukeboxMusic; // 0x41c JukeboxScript::Script m_jukeboxMusic; // 0x41c
MxBool m_isDirty; // 0x420 MxBool m_isDirty; // 0x420
Area m_currentArea; // 0x424 Area m_currentArea; // 0x424

View File

@ -78,6 +78,9 @@ class LegoVideoManager : public MxVideoManager {
inline void DrawCursor(); 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 Tgl::Renderer* m_renderer; // 0x64
Lego3DManager* m_3dManager; // 0x68 Lego3DManager* m_3dManager; // 0x68
LegoROI* m_viewROI; // 0x6c LegoROI* m_viewROI; // 0x6c

View File

@ -579,10 +579,10 @@ void LegoCarBuildAnimPresenter::RotateAroundYAxis(MxFloat p_angle)
newRotation.EqualsHamiltonProduct(currentRotation, additionalRotation); newRotation.EqualsHamiltonProduct(currentRotation, additionalRotation);
if (newRotation[3] < 0.9999) { if (newRotation[3] < 0.9999) {
rotationKey->FUN_100739a0(TRUE); rotationKey->SetActive(TRUE);
} }
else { else {
rotationKey->FUN_100739a0(FALSE); rotationKey->SetActive(FALSE);
} }
m_platformAnimNodeData->GetRotationKey(0)->SetX(newRotation[0]); m_platformAnimNodeData->GetRotationKey(0)->SetX(newRotation[0]);

View File

@ -290,7 +290,7 @@ MxResult LegoGameState::Save(MxULong p_slot)
} }
storage.WriteS32(0x1000c); storage.WriteS32(0x1000c);
storage.WriteS16(m_unk0x24); storage.WriteS16(m_currentPlayerId);
storage.WriteU16(m_currentAct); storage.WriteU16(m_currentAct);
storage.WriteU8(m_actorId); storage.WriteU8(m_actorId);
@ -386,7 +386,7 @@ MxResult LegoGameState::Load(MxULong p_slot)
goto done; goto done;
} }
storage.ReadS16(m_unk0x24); storage.ReadS16(m_currentPlayerId);
storage.ReadS16(actArea); storage.ReadS16(actArea);
SetCurrentAct((Act) actArea); SetCurrentAct((Act) actArea);
@ -630,8 +630,8 @@ MxResult LegoGameState::AddPlayer(Username& p_player)
m_playerCount++; m_playerCount++;
m_players[0].Set(p_player); m_players[0].Set(p_player);
m_unk0x24 = m_history.m_unk0x372; m_currentPlayerId = m_history.m_nextPlayerId;
m_history.m_unk0x372 = m_unk0x24 + 1; m_history.m_nextPlayerId = m_currentPlayerId + 1;
m_history.WriteScoreHistory(); m_history.WriteScoreHistory();
SetCurrentAct(e_act1); SetCurrentAct(e_act1);
@ -1422,7 +1422,7 @@ MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage)
} }
m_name.Serialize(p_storage); m_name.Serialize(p_storage);
p_storage->ReadS16(m_unk0x2a); p_storage->ReadS16(m_playerId);
} }
else if (p_storage->IsWriteMode()) { else if (p_storage->IsWriteMode()) {
p_storage->WriteS16(m_totalScore); p_storage->WriteS16(m_totalScore);
@ -1434,7 +1434,7 @@ MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage)
} }
m_name.Serialize(p_storage); m_name.Serialize(p_storage);
p_storage->WriteS16(m_unk0x2a); p_storage->WriteS16(m_playerId);
} }
return SUCCESS; return SUCCESS;
@ -1445,7 +1445,7 @@ MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage)
LegoGameState::History::History() LegoGameState::History::History()
{ {
m_count = 0; m_count = 0;
m_unk0x372 = 0; m_nextPlayerId = 0;
} }
// FUNCTION: LEGO1 0x1003c870 // FUNCTION: LEGO1 0x1003c870
@ -1456,83 +1456,128 @@ void LegoGameState::History::WriteScoreHistory()
MxU8 scores[5][5]; MxU8 scores[5][5];
InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState"); 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++) { if (!state->m_letters[0]) {
scores[0][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0; return;
totalScore += scores[0][actor - 1]; }
scores[1][actor - 1] = jetskiRaceState ? jetskiRaceState->GetState(actor)->GetHighScore() : 0; JetskiRaceState* jetskiRaceState = (JetskiRaceState*) GameState()->GetState("JetskiRaceState");
totalScore += scores[1][actor - 1]; 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; for (MxS32 actor = 1; actor <= 5; actor++) {
totalScore += scores[2][actor - 1]; scores[0][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0;
totalScore += scores[0][actor - 1];
scores[3][actor - 1] = towTrackMissionState ? towTrackMissionState->GetHighScore(actor) : 0; #ifdef BETA10
totalScore += scores[3][actor - 1]; // 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; scores[2][actor - 1] = pizzaMissionState ? pizzaMissionState->GetHighScore(actor) : 0;
totalScore += scores[4][actor - 1]; totalScore += scores[2][actor - 1];
}
MxS32 unk0x2c; scores[3][actor - 1] = towTrackMissionState ? towTrackMissionState->GetHighScore(actor) : 0;
ScoreItem* p_scorehist = FUN_1003cc90(&GameState()->m_players[0], GameState()->m_unk0x24, unk0x2c); totalScore += scores[3][actor - 1];
if (p_scorehist != NULL) { scores[4][actor - 1] = ambulanceMissionState ? ambulanceMissionState->GetHighScore(actor) : 0;
p_scorehist->m_totalScore = totalScore; totalScore += scores[4][actor - 1];
memcpy(p_scorehist->m_scores, scores, sizeof(p_scorehist->m_scores)); }
}
else { MxS32 playerScoreHistoryIndex;
if (m_count < (MxS16) sizeOfArray(m_scores)) { ScoreItem* p_scorehist =
m_scores[m_count].m_totalScore = totalScore; FindPlayerInScoreHistory(GameState()->m_players, GameState()->m_currentPlayerId, playerScoreHistoryIndex);
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]; #ifdef BETA10
m_scores[m_count].m_unk0x2a = GameState()->m_unk0x24; if (!p_scorehist) {
m_count++; MxS32 playerScoreRank;
} // LINE: BETA10 0x100870ee
else if (m_scores[19].m_totalScore <= totalScore) { for (playerScoreRank = 0; playerScoreRank < m_count; playerScoreRank++) {
m_scores[19].m_totalScore = totalScore; if (totalScore > m_scores[m_indices[playerScoreRank]].m_totalScore) {
memcpy(m_scores[19].m_scores, scores, sizeof(m_scores[19].m_scores)); break;
m_scores[19].m_name = GameState()->m_players[0];
m_scores[19].m_unk0x2a = GameState()->m_unk0x24;
} }
} }
// LINE: BETA10 0x1008713f
if (playerScoreRank < m_count) {
if (m_count < 20) {
playerScoreHistoryIndex = m_count++;
}
else {
playerScoreHistoryIndex = m_indices[19];
}
MxU8 tmpScores[5][5]; MxS32 max = m_count - 1;
Username tmpPlayer; for (MxS32 j = max; playerScoreRank < j; j--) {
MxS16 tmpUnk0x2a; m_indices[j - 1] = m_indices[j - 2];
}
// TODO: Match bubble sort loops m_indices[playerScoreRank] = playerScoreHistoryIndex;
for (MxS32 i = m_count - 1; i > 0; i--) { p_scorehist = &m_scores[playerScoreHistoryIndex];
for (MxS32 j = 1; j <= i; j++) { }
if (m_scores[j - 1].m_totalScore < m_scores[j].m_totalScore) { else if (playerScoreRank < 20) {
memcpy(tmpScores, m_scores[j - 1].m_scores, sizeof(tmpScores)); m_indices[m_count] = m_count;
tmpPlayer = m_scores[j - 1].m_name; p_scorehist = &m_scores[m_count++];
tmpUnk0x2a = m_scores[j - 1].m_unk0x2a; }
}
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)); for (MxS32 i = playerScoreHistoryIndex; i > 0 && m_indices[i - 1] < m_indices[i]; i--) {
m_scores[j - 1].m_name = m_scores[j].m_name; MxU8 tmp = m_indices[i - 1];
m_scores[j - 1].m_unk0x2a = m_scores[j].m_unk0x2a; 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)); ScoreItem tmpItem;
m_scores[j].m_name = tmpPlayer;
m_scores[j].m_unk0x2a = tmpUnk0x2a; 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: LEGO1 0x1003cc90
// FUNCTION: BETA10 0x1008732a // FUNCTION: BETA10 0x1008732a
LegoGameState::ScoreItem* LegoGameState::History::FUN_1003cc90( LegoGameState::ScoreItem* LegoGameState::History::FindPlayerInScoreHistory(
LegoGameState::Username* p_player, LegoGameState::Username* p_player,
MxS16 p_unk0x24, MxS16 p_unk0x24,
MxS32& p_unk0x2c MxS32& p_unk0x2c
@ -1540,7 +1585,7 @@ LegoGameState::ScoreItem* LegoGameState::History::FUN_1003cc90(
{ {
MxS32 i = 0; MxS32 i = 0;
for (; i < m_count; i++) { 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; break;
} }
} }
@ -1559,7 +1604,7 @@ LegoGameState::ScoreItem* LegoGameState::History::FUN_1003cc90(
MxResult LegoGameState::History::Serialize(LegoStorage* p_storage) MxResult LegoGameState::History::Serialize(LegoStorage* p_storage)
{ {
if (p_storage->IsReadMode()) { if (p_storage->IsReadMode()) {
p_storage->ReadS16(m_unk0x372); p_storage->ReadS16(m_nextPlayerId);
p_storage->ReadS16(m_count); p_storage->ReadS16(m_count);
for (MxS16 i = 0; i < m_count; i++) { for (MxS16 i = 0; i < m_count; i++) {
@ -1569,7 +1614,7 @@ MxResult LegoGameState::History::Serialize(LegoStorage* p_storage)
} }
} }
else if (p_storage->IsWriteMode()) { else if (p_storage->IsWriteMode()) {
p_storage->WriteS16(m_unk0x372); p_storage->WriteS16(m_nextPlayerId);
p_storage->WriteS16(m_count); p_storage->WriteS16(m_count);
for (MxS16 i = 0; i < m_count; i++) { for (MxS16 i = 0; i < m_count; i++) {
@ -1599,6 +1644,7 @@ void LegoGameState::SerializeScoreHistory(MxS16 p_flags)
} }
// FUNCTION: LEGO1 0x1003cea0 // FUNCTION: LEGO1 0x1003cea0
// FUNCTION: BETA10 0x10017840
void LegoGameState::SetCurrentAct(Act p_currentAct) void LegoGameState::SetCurrentAct(Act p_currentAct)
{ {
m_currentAct = p_currentAct; m_currentAct = p_currentAct;

View File

@ -214,7 +214,7 @@ LegoEntity* LegoPlantManager::CreatePlant(MxS32 p_index, LegoWorld* p_world, Leg
{ {
LegoEntity* entity = NULL; 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; MxU32 world = 1 << (MxU8) p_worldId;
if (g_plantInfo[p_index].m_worlds & world && g_plantInfo[p_index].m_counter != 0) { if (g_plantInfo[p_index].m_worlds & world && g_plantInfo[p_index].m_counter != 0) {

View File

@ -83,7 +83,7 @@ LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_text
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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; goto done;
} }
@ -193,7 +193,7 @@ LegoResult LegoTextureInfo::LoadBits(const LegoU8* p_bits)
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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; MxU8* surface = (MxU8*) desc.lpSurface;
const LegoU8* bits = p_bits; const LegoU8* bits = p_bits;

View File

@ -708,7 +708,7 @@ void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name)
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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); LegoImage* image = new LegoImage(desc.dwWidth, desc.dwHeight);
if (image != NULL) { if (image != NULL) {

View File

@ -1,6 +1,7 @@
#include "legovariables.h" #include "legovariables.h"
#include "3dmanager/lego3dmanager.h" #include "3dmanager/lego3dmanager.h"
#include "legoactor.h"
#include "legogamestate.h" #include "legogamestate.h"
#include "legonavcontroller.h" #include "legonavcontroller.h"
#include "legovideomanager.h" #include "legovideomanager.h"
@ -159,18 +160,18 @@ void WhoAmIVariable::SetValue(const char* p_value)
MxVariable::SetValue(p_value); MxVariable::SetValue(p_value);
if (!SDL_strcasecmp(p_value, g_papa)) { if (!SDL_strcasecmp(p_value, g_papa)) {
GameState()->SetActorId(3); GameState()->SetActorId(LegoActor::c_papa);
} }
else if (!SDL_strcasecmp(p_value, g_mama)) { else if (!SDL_strcasecmp(p_value, g_mama)) {
GameState()->SetActorId(2); GameState()->SetActorId(LegoActor::c_mama);
} }
else if (!SDL_strcasecmp(p_value, g_pepper)) { else if (!SDL_strcasecmp(p_value, g_pepper)) {
GameState()->SetActorId(1); GameState()->SetActorId(LegoActor::c_pepper);
} }
else if (!SDL_strcasecmp(p_value, g_nick)) { else if (!SDL_strcasecmp(p_value, g_nick)) {
GameState()->SetActorId(4); GameState()->SetActorId(LegoActor::c_nick);
} }
else if (!SDL_strcasecmp(p_value, g_laura)) { else if (!SDL_strcasecmp(p_value, g_laura)) {
GameState()->SetActorId(5); GameState()->SetActorId(LegoActor::c_laura);
} }
} }

View File

@ -210,10 +210,10 @@ void MxTransitionManager::DissolveTransition()
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore(); 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) { if (res == DD_OK) {
@ -402,10 +402,10 @@ void MxTransitionManager::WipeDownTransition()
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore(); 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) { if (res == DD_OK) {
@ -439,10 +439,10 @@ void MxTransitionManager::WindowsTransition()
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore(); 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) { if (res == DD_OK) {
@ -483,10 +483,10 @@ void MxTransitionManager::BrokenTransition()
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore(); 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) { if (res == DD_OK) {

View File

@ -393,7 +393,7 @@ MxResult LegoWorldPresenter::LoadWorldModel(ModelDbModel& p_model, SDL_IOStream*
} }
modelPresenter.SetAction(&action); 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; delete[] buff;
return SUCCESS; return SUCCESS;

View File

@ -224,10 +224,10 @@ void LegoAnimPresenter::FUN_100692b0()
for (LegoU32 i = 0; i < numActors; i++) { for (LegoU32 i = 0; i < numActors; i++) {
LegoChar* str = GetVariableOrIdentity(m_anim->GetActorName(i), NULL); LegoChar* str = GetVariableOrIdentity(m_anim->GetActorName(i), NULL);
undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); LegoU32 actorType = m_anim->GetActorType(i);
LegoROI* roi = NULL; LegoROI* roi = NULL;
if (unk0x04 == 2) { if (actorType == LegoAnimActorEntry::e_actorType2) {
LegoChar* src; LegoChar* src;
if (str[0] == '*') { if (str[0] == '*') {
src = str + 1; src = str + 1;
@ -242,7 +242,7 @@ void LegoAnimPresenter::FUN_100692b0()
roi->SetVisibility(FALSE); roi->SetVisibility(FALSE);
} }
} }
else if (unk0x04 == 4) { else if (actorType == LegoAnimActorEntry::e_actorType4) {
LegoChar* baseName = new LegoChar[strlen(str)]; LegoChar* baseName = new LegoChar[strlen(str)];
strcpy(baseName, str + 1); strcpy(baseName, str + 1);
SDL_strlwr(baseName); SDL_strlwr(baseName);
@ -257,7 +257,7 @@ void LegoAnimPresenter::FUN_100692b0()
delete[] baseName; delete[] baseName;
delete[] und; delete[] und;
} }
else if (unk0x04 == 3) { else if (actorType == LegoAnimActorEntry::e_actorType3) {
LegoChar* lodName = new LegoChar[strlen(str)]; LegoChar* lodName = new LegoChar[strlen(str)];
strcpy(lodName, str + 1); strcpy(lodName, str + 1);
@ -303,9 +303,9 @@ void LegoAnimPresenter::FUN_100695c0()
for (LegoU32 i = 0; i < numActors; i++) { for (LegoU32 i = 0; i < numActors; i++) {
if (FUN_100698b0(rois, m_anim->GetActorName(i)) == FALSE) { 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]; LegoChar lodName[256];
const LegoChar* actorName = m_anim->GetActorName(i); const LegoChar* actorName = m_anim->GetActorName(i);

View File

@ -406,37 +406,14 @@ inline void LegoVideoManager::DrawCursor()
// FUNCTION: LEGO1 0x1007bbc0 // FUNCTION: LEGO1 0x1007bbc0
void LegoVideoManager::DrawFPS() void LegoVideoManager::DrawFPS()
{ {
char zeros[8] = "0000.00";
if (m_unk0x528 == NULL) { if (m_unk0x528 == NULL) {
m_arialFont = CreateFont( int width = 64; // Big enough for 9999.99
12, int height = 16;
0,
0,
0,
FW_NORMAL,
FALSE,
FALSE,
FALSE,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
FF_DONTCARE | VARIABLE_PITCH,
"Arial"
);
HDC dc = GetDC(NULL); m_unk0x528 = m_displaySurface->FUN_100bc8b0(width, height);
SelectObject(dc, m_arialFont); SetRect(&m_fpsRect, 0, 0, width, height);
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);
if (m_unk0x528 == NULL) { if (m_unk0x528 == NULL) {
DeleteObject(m_arialFont);
m_arialFont = NULL;
return; return;
} }
@ -450,9 +427,7 @@ void LegoVideoManager::DrawFPS()
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) != DD_OK) { if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) != DD_OK) {
m_unk0x528->Release(); m_unk0x528->Release();
DeleteObject(m_arialFont);
m_unk0x528 = NULL; m_unk0x528 = NULL;
m_arialFont = NULL;
} }
else { else {
DWORD i; DWORD i;
@ -472,8 +447,7 @@ void LegoVideoManager::DrawFPS()
if (Timer()->GetTime() > m_unk0x54c + 5000.f) { if (Timer()->GetTime() > m_unk0x54c + 5000.f) {
char buffer[32]; char buffer[32];
MxFloat time = (Timer()->GetTime() - m_unk0x54c) / 1000.0f; MxFloat time = (Timer()->GetTime() - m_unk0x54c) / 1000.0f;
MxS32 nb = sprintf(buffer, "%.02f", m_unk0x550 / time); sprintf(buffer, "%.02f", m_unk0x550 / time);
SDL_Log("%.02f", m_unk0x550 / time);
m_unk0x54c = Timer()->GetTime(); m_unk0x54c = Timer()->GetTime();
DDSURFACEDESC surfaceDesc; DDSURFACEDESC surfaceDesc;
@ -481,37 +455,13 @@ void LegoVideoManager::DrawFPS()
surfaceDesc.dwSize = sizeof(surfaceDesc); surfaceDesc.dwSize = sizeof(surfaceDesc);
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) { if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) {
DWORD i; memset(surfaceDesc.lpSurface, 0, surfaceDesc.lPitch * surfaceDesc.dwHeight);
char* ptr = (char*) surfaceDesc.lpSurface;
for (i = 0; i < surfaceDesc.dwHeight; i++) { DrawTextToSurface32((uint8_t*) surfaceDesc.lpSurface, surfaceDesc.lPitch, 0, 0, buffer, 0xFF0000FF);
memset(ptr, 0, surfaceDesc.lPitch);
ptr += surfaceDesc.lPitch;
}
m_unk0x528->Unlock(surfaceDesc.lpSurface); 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 { else {
m_unk0x550 += 1.f; m_unk0x550 += 1.f;
@ -826,3 +776,63 @@ MxResult LegoVideoManager::ConfigureD3DRM()
return SUCCESS; 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;
}
}

View File

@ -489,7 +489,7 @@ MxResult Act3::Create(MxDSAction& p_dsAction)
case LegoGameState::e_act1: case LegoGameState::e_act1:
case LegoGameState::e_actNotFound: case LegoGameState::e_actNotFound:
GameState()->StopArea(LegoGameState::e_undefined); GameState()->StopArea(LegoGameState::e_undefined);
if (GameState()->GetPreviousArea() == LegoGameState::e_infomain) { if (GameState()->m_previousArea == LegoGameState::e_infomain) {
GameState()->StopArea(LegoGameState::e_isle); GameState()->StopArea(LegoGameState::e_isle);
} }
} }
@ -506,7 +506,7 @@ MxResult Act3::Create(MxDSAction& p_dsAction)
GameState()->m_currentArea = LegoGameState::e_act3script; GameState()->m_currentArea = LegoGameState::e_act3script;
GameState()->SetCurrentAct(LegoGameState::e_act3); GameState()->SetCurrentAct(LegoGameState::e_act3);
GameState()->SetDirty(TRUE); GameState()->m_isDirty = TRUE;
} }
return result; return result;
@ -884,7 +884,7 @@ void Act3::Enable(MxBool p_enable)
FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
PlayMusic(JukeboxScript::c_Act3Music); PlayMusic(JukeboxScript::c_Act3Music);
GameState()->SetDirty(TRUE); GameState()->m_isDirty = TRUE;
if (m_time > 0) { if (m_time > 0) {
MxFloat delta = Timer()->GetTime() - m_time - 100.0f; MxFloat delta = Timer()->GetTime() - m_time - 100.0f;

View File

@ -219,7 +219,7 @@ MxResult Infocenter::Create(MxDSAction& p_dsAction)
if (m_infocenterState->m_unk0x74 == 4) { if (m_infocenterState->m_unk0x74 == 4) {
LegoGameState* state = GameState(); LegoGameState* state = GameState();
state->SetPreviousArea(GameState()->GetUnknown0x42c()); state->m_previousArea = GameState()->m_unk0x42c;
} }
InputManager()->Register(this); InputManager()->Register(this);
@ -1024,13 +1024,13 @@ MxU8 Infocenter::HandleControl(LegoControlManagerNotificationParam& p_param)
case InfomainScript::c_BigInfo_Ctl: case InfomainScript::c_BigInfo_Ctl:
switch (state->GetCurrentAct()) { switch (state->GetCurrentAct()) {
case LegoGameState::e_act1: case LegoGameState::e_act1:
if (state->GetPreviousArea()) { if (state->m_previousArea) {
switch (state->GetPreviousArea()) { switch (state->m_previousArea) {
case LegoGameState::e_infodoor: case LegoGameState::e_infodoor:
case LegoGameState::e_regbook: case LegoGameState::e_regbook:
case LegoGameState::e_infoscor: case LegoGameState::e_infoscor:
m_infocenterState->m_unk0x74 = 5; m_infocenterState->m_unk0x74 = 5;
m_destLocation = state->GetPreviousArea(); m_destLocation = state->m_previousArea;
actionToPlay = (InfomainScript::Script) m_infocenterState->GetNextLeaveDialogue(); actionToPlay = (InfomainScript::Script) m_infocenterState->GetNextLeaveDialogue();
m_radio.Stop(); m_radio.Stop();
InputManager()->DisableInputProcessing(); InputManager()->DisableInputProcessing();
@ -1085,7 +1085,7 @@ MxU8 Infocenter::HandleControl(LegoControlManagerNotificationParam& p_param)
actionToPlay = GameState()->GetCurrentAct() != LegoGameState::e_act1 ? InfomainScript::c_GoTo_RegBook_Red actionToPlay = GameState()->GetCurrentAct() != LegoGameState::e_act1 ? InfomainScript::c_GoTo_RegBook_Red
: InfomainScript::c_GoTo_RegBook; : InfomainScript::c_GoTo_RegBook;
m_radio.Stop(); m_radio.Stop();
GameState()->m_unk0x42c = GameState()->GetPreviousArea(); GameState()->m_unk0x42c = GameState()->m_previousArea;
InputManager()->DisableInputProcessing(); InputManager()->DisableInputProcessing();
break; break;
case InfomainScript::c_Mama_Ctl: case InfomainScript::c_Mama_Ctl:
@ -1394,7 +1394,7 @@ void Infocenter::Reset()
AnimationManager()->Reset(FALSE); AnimationManager()->Reset(FALSE);
CharacterManager()->ReleaseAllActors(); CharacterManager()->ReleaseAllActors();
GameState()->SetCurrentAct(LegoGameState::e_act1); GameState()->SetCurrentAct(LegoGameState::e_act1);
GameState()->SetPreviousArea(LegoGameState::e_undefined); GameState()->m_previousArea = LegoGameState::e_undefined;
GameState()->m_unk0x42c = LegoGameState::e_undefined; GameState()->m_unk0x42c = LegoGameState::e_undefined;
InitializeBitmaps(); InitializeBitmaps();

View File

@ -121,7 +121,7 @@ MxResult Isle::Create(MxDSAction& p_dsAction)
m_act1state = act1state; m_act1state = act1state;
EnableAnimations(TRUE); EnableAnimations(TRUE);
GameState()->SetDirty(TRUE); GameState()->m_isDirty = TRUE;
} }
return result; return result;

View File

@ -141,7 +141,7 @@ MxResult LegoAct2::Create(MxDSAction& p_dsAction)
case LegoGameState::e_act1: case LegoGameState::e_act1:
case LegoGameState::e_actNotFound: case LegoGameState::e_actNotFound:
GameState()->StopArea(LegoGameState::e_undefined); GameState()->StopArea(LegoGameState::e_undefined);
if (GameState()->GetPreviousArea() == LegoGameState::e_infomain) { if (GameState()->m_previousArea == LegoGameState::e_infomain) {
GameState()->StopArea(LegoGameState::e_isle); GameState()->StopArea(LegoGameState::e_isle);
} }
} }
@ -149,7 +149,7 @@ MxResult LegoAct2::Create(MxDSAction& p_dsAction)
GameState()->m_currentArea = LegoGameState::e_act2main; GameState()->m_currentArea = LegoGameState::e_act2main;
GameState()->SetCurrentAct(LegoGameState::e_act2); GameState()->SetCurrentAct(LegoGameState::e_act2);
InputManager()->Register(this); InputManager()->Register(this);
GameState()->SetDirty(TRUE); GameState()->m_isDirty = TRUE;
} }
return result; return result;
@ -536,7 +536,7 @@ void LegoAct2::Enable(MxBool p_enable)
((IslePathActor*) m_pepper->GetEntity())->VTable0xec(m_unk0x10dc, m_unk0x1124, TRUE); ((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); GameState()->StopArea(LegoGameState::e_infomain);
} }

View File

@ -254,7 +254,7 @@ void Score::Paint()
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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 (result == DD_OK) {
if (desc.lPitch != desc.dwWidth) { if (desc.lPitch != desc.dwWidth) {
cube->m_surface->Unlock(desc.lpSurface); cube->m_surface->Unlock(desc.lpSurface);

View File

@ -154,7 +154,7 @@ double Lego3DView::Render(double p_und)
} }
// FUNCTION: LEGO1 0x100ab2b0 // 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); return m_pViewManager->Pick(GetView(), x, y);
} }

View File

@ -27,7 +27,7 @@ class Lego3DView : public LegoView1 {
double Render(double p_und); double Render(double p_und);
ViewROI* Pick(unsigned int x, unsigned int y); ViewROI* Pick(int x, int y);
ViewROI* GetPointOfView(); ViewROI* GetPointOfView();
ViewManager* GetViewManager(); ViewManager* GetViewManager();

View File

@ -725,6 +725,7 @@ void LegoAnimNodeData::SetName(LegoChar* p_name)
} }
// FUNCTION: LEGO1 0x100a03c0 // FUNCTION: LEGO1 0x100a03c0
// FUNCTION: BETA10 0x1017f254
LegoResult LegoAnimNodeData::CreateLocalTransform(LegoFloat p_time, Matrix4& p_matrix) LegoResult LegoAnimNodeData::CreateLocalTransform(LegoFloat p_time, Matrix4& p_matrix)
{ {
LegoU32 index; LegoU32 index;
@ -1062,7 +1063,7 @@ LegoResult LegoAnim::Read(LegoStorage* p_storage, LegoS32 p_parseScene)
m_modelList[i].m_name[length] = '\0'; 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; goto done;
} }
} }
@ -1123,7 +1124,7 @@ LegoResult LegoAnim::Write(LegoStorage* p_storage)
goto done; 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; goto done;
} }
} }
@ -1158,10 +1159,10 @@ const LegoChar* LegoAnim::GetActorName(LegoU32 p_index)
// FUNCTION: LEGO1 0x100a0f40 // FUNCTION: LEGO1 0x100a0f40
// FUNCTION: BETA10 0x1018023c // FUNCTION: BETA10 0x1018023c
undefined4 LegoAnim::GetActorUnknown0x04(LegoU32 p_index) LegoU32 LegoAnim::GetActorType(LegoU32 p_index)
{ {
if (p_index < m_numActors) { if (p_index < m_numActors) {
return m_modelList[p_index].m_unk0x04; return m_modelList[p_index].m_type;
} }
return 0; return 0;

View File

@ -30,9 +30,9 @@ class LegoAnimKey {
LegoU32 ShouldSkipInterpolation() { return m_flags & c_skipInterpolation; } LegoU32 ShouldSkipInterpolation() { return m_flags & c_skipInterpolation; }
// FUNCTION: BETA10 0x100739a0 // FUNCTION: BETA10 0x100739a0
void FUN_100739a0(MxS32 p_param) void SetActive(MxS32 p_active)
{ {
if (p_param) { if (p_active) {
m_flags |= c_active; m_flags |= c_active;
} }
else { else {
@ -289,8 +289,16 @@ class LegoAnimNodeData : public LegoTreeNodeData {
// SIZE 0x08 // SIZE 0x08
struct LegoAnimActorEntry { struct LegoAnimActorEntry {
LegoChar* m_name; // 0x00 enum {
undefined4 m_unk0x04; // 0x04 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)`? // TODO: Possibly called `LegoCameraAnim(ation)`?
@ -338,7 +346,7 @@ class LegoAnim : public LegoTree {
virtual LegoResult Read(LegoStorage* p_storage, LegoS32 p_parseScene); // vtable+0x10 virtual LegoResult Read(LegoStorage* p_storage, LegoS32 p_parseScene); // vtable+0x10
const LegoChar* GetActorName(LegoU32 p_index); const LegoChar* GetActorName(LegoU32 p_index);
undefined4 GetActorUnknown0x04(LegoU32 p_index); LegoU32 GetActorType(LegoU32 p_index);
// FUNCTION: BETA10 0x1005abf0 // FUNCTION: BETA10 0x1005abf0
LegoAnimScene* GetCamAnim() { return m_camAnim; } LegoAnimScene* GetCamAnim() { return m_camAnim; }

View File

@ -22,7 +22,7 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo)
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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; width = desc.dwWidth;
height = desc.dwHeight; height = desc.dwHeight;
p_textureInfo->m_surface->Unlock(desc.lpSurface); p_textureInfo->m_surface->Unlock(desc.lpSurface);
@ -35,7 +35,7 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo)
memset(&newDesc, 0, sizeof(newDesc)); memset(&newDesc, 0, sizeof(newDesc));
newDesc.dwSize = 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; BOOL und = FALSE;
if (newDesc.dwWidth == width && newDesc.dwHeight == height) { if (newDesc.dwWidth == width && newDesc.dwHeight == height) {
und = TRUE; und = TRUE;

View File

@ -59,8 +59,12 @@ ColorOverride g_colorOverride = NULL;
TextureHandler g_textureHandler = NULL; TextureHandler g_textureHandler = NULL;
// FUNCTION: LEGO1 0x100a81b0 // 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 // FUNCTION: LEGO1 0x100a81c0
@ -70,6 +74,7 @@ void LegoROI::configureLegoROI(int p_roiConfig)
} }
// FUNCTION: LEGO1 0x100a81d0 // FUNCTION: LEGO1 0x100a81d0
// FUNCTION: BETA10 0x101898e8
LegoROI::LegoROI(Tgl::Renderer* p_renderer) : ViewROI(p_renderer, NULL) LegoROI::LegoROI(Tgl::Renderer* p_renderer) : ViewROI(p_renderer, NULL)
{ {
m_parentROI = NULL; m_parentROI = NULL;
@ -78,6 +83,7 @@ LegoROI::LegoROI(Tgl::Renderer* p_renderer) : ViewROI(p_renderer, NULL)
} }
// FUNCTION: LEGO1 0x100a82d0 // FUNCTION: LEGO1 0x100a82d0
// FUNCTION: BETA10 0x10189994
LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_renderer, p_lodList) LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_renderer, p_lodList)
{ {
m_parentROI = NULL; m_parentROI = NULL;
@ -86,6 +92,7 @@ LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_
} }
// FUNCTION: LEGO1 0x100a83c0 // FUNCTION: LEGO1 0x100a83c0
// FUNCTION: BETA10 0x10189a42
LegoROI::~LegoROI() LegoROI::~LegoROI()
{ {
if (comp) { if (comp) {
@ -106,6 +113,7 @@ LegoROI::~LegoROI()
} }
// FUNCTION: LEGO1 0x100a84a0 // FUNCTION: LEGO1 0x100a84a0
// FUNCTION: BETA10 0x10189b99
LegoResult LegoROI::Read( LegoResult LegoROI::Read(
OrientableROI* p_unk0xd4, OrientableROI* p_unk0xd4,
Tgl::Renderer* p_renderer, Tgl::Renderer* p_renderer,
@ -338,6 +346,7 @@ LegoResult LegoROI::Read(
} }
// FUNCTION: LEGO1 0x100a8cb0 // FUNCTION: LEGO1 0x100a8cb0
// FUNCTION: BETA10 0x1018a7e8
LegoResult LegoROI::CreateLocalTransform(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix) LegoResult LegoROI::CreateLocalTransform(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix)
{ {
p_matrix.SetIdentity(); p_matrix.SetIdentity();
@ -380,6 +389,7 @@ LegoROI* LegoROI::FindChildROI(const LegoChar* p_name, LegoROI* p_roi)
} }
// FUNCTION: LEGO1 0x100a8da0 // FUNCTION: LEGO1 0x100a8da0
// FUNCTION: BETA10 0x1018a9fb
LegoResult LegoROI::ApplyAnimationTransformation( LegoResult LegoROI::ApplyAnimationTransformation(
LegoTreeNode* p_node, LegoTreeNode* p_node,
const Matrix4& p_matrix, 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: LEGO1 0x100a90f0
// FUNCTION: BETA10 0x1018ada8
LegoResult LegoROI::SetFrame(LegoAnim* p_anim, LegoTime p_time) LegoResult LegoROI::SetFrame(LegoAnim* p_anim, LegoTime p_time)
{ {
LegoTreeNode* root = p_anim->GetRoot(); LegoTreeNode* root = p_anim->GetRoot();
@ -513,6 +524,7 @@ LegoResult LegoROI::SetLodColor(LegoFloat p_red, LegoFloat p_green, LegoFloat p_
} }
// FUNCTION: LEGO1 0x100a9210 // FUNCTION: LEGO1 0x100a9210
// FUNCTION: BETA10 0x1018af25
LegoResult LegoROI::SetTextureInfo(LegoTextureInfo* p_textureInfo) LegoResult LegoROI::SetTextureInfo(LegoTextureInfo* p_textureInfo)
{ {
LegoResult result = SUCCESS; LegoResult result = SUCCESS;
@ -736,6 +748,7 @@ LegoU32 LegoROI::FUN_100a9410(
} }
// FUNCTION: LEGO1 0x100a9a50 // FUNCTION: LEGO1 0x100a9a50
// FUNCTION: BETA10 0x1018bb6b
TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time) : LegoROI(p_renderer, p_lodList) TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time) : LegoROI(p_renderer, p_lodList)
{ {
m_time = p_time; m_time = p_time;
@ -761,6 +774,7 @@ void TimeROI::FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time)
} }
// FUNCTION: LEGO1 0x100a9bf0 // 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) LegoBool LegoROI::GetRGBAColor(const LegoChar* p_name, float& p_red, float& p_green, float& p_blue, float& p_alpha)
{ {
if (p_name == NULL) { if (p_name == NULL) {
@ -851,12 +865,14 @@ void LegoROI::SetDisplayBB(int p_displayBB)
} }
// FUNCTION: LEGO1 0x100aa340 // FUNCTION: LEGO1 0x100aa340
// FUNCTION: BETA10 0x1018cca0
float LegoROI::IntrinsicImportance() const float LegoROI::IntrinsicImportance() const
{ {
return .5; return .5;
} }
// FUNCTION: LEGO1 0x100aa350 // FUNCTION: LEGO1 0x100aa350
// FUNCTION: BETA10 0x1018ccc0
void LegoROI::UpdateWorldBoundingVolumes() void LegoROI::UpdateWorldBoundingVolumes()
{ {
CalcWorldBoundingVolumes(m_sphere, m_local2world, m_world_bounding_box, m_world_bounding_sphere); CalcWorldBoundingVolumes(m_sphere, m_local2world, m_world_bounding_box, m_world_bounding_sphere);

View File

@ -18,6 +18,7 @@ class LegoTreeNode;
struct LegoAnimActorEntry; struct LegoAnimActorEntry;
// VTABLE: LEGO1 0x100dbe38 // VTABLE: LEGO1 0x100dbe38
// VTABLE: BETA10 0x101c3898
// SIZE 0x108 // SIZE 0x108
class LegoROI : public ViewROI { class LegoROI : public ViewROI {
public: public:
@ -58,7 +59,7 @@ class LegoROI : public ViewROI {
void SetDisplayBB(int p_displayBB); void SetDisplayBB(int p_displayBB);
static LegoResult CreateLocalTransform(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix); 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); LEGO1_EXPORT static void configureLegoROI(int p_roi);
static void SetColorOverride(ColorOverride p_colorOverride); 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); 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; } void SetBoundingBox(const BoundingBox& p_box) { m_bounding_box = p_box; }
// SYNTHETIC: LEGO1 0x100a82b0 // SYNTHETIC: LEGO1 0x100a82b0
// SYNTHETIC: BETA10 0x1018c490
// LegoROI::`scalar deleting destructor' // LegoROI::`scalar deleting destructor'
private: private:
@ -99,15 +101,20 @@ class LegoROI : public ViewROI {
}; };
// VTABLE: LEGO1 0x100dbea8 // VTABLE: LEGO1 0x100dbea8
// VTABLE: BETA10 0x101c38d0
// SIZE 0x10c // SIZE 0x10c
class TimeROI : public LegoROI { class TimeROI : public LegoROI {
public: public:
TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time); TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time);
void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time);
// SYNTHETIC: LEGO1 0x100a9ad0 // SYNTHETIC: LEGO1 0x100a9ad0
// SYNTHETIC: BETA10 0x1018c540
// TimeROI::`scalar deleting destructor' // TimeROI::`scalar deleting destructor'
void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time); // SYNTHETIC: BETA10 0x1018c580
// TimeROI::~TimeROI
private: private:
LegoTime m_time; // 0x108 LegoTime m_time; // 0x108

View File

@ -52,7 +52,7 @@ MxResult ModelDbModel::Read(SDL_IOStream* p_file)
if (SDL_ReadIO(p_file, m_up, 3 * sizeof(float)) != 3 * sizeof(float)) { if (SDL_ReadIO(p_file, m_up, 3 * sizeof(float)) != 3 * sizeof(float)) {
return FAILURE; 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; return FAILURE;
} }

View File

@ -102,7 +102,7 @@ struct ModelDbModel {
float m_location[3]; // 0x10 float m_location[3]; // 0x10
float m_direction[3]; // 0x1c float m_direction[3]; // 0x1c
float m_up[3]; // 0x28 float m_up[3]; // 0x28
undefined m_unk0x34; // 0x34 MxU8 m_visible; // 0x34
}; };
// SIZE 0x18 // SIZE 0x18

View File

@ -174,7 +174,7 @@ BOOL MxDirect3D::D3DSetMode()
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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; unsigned char* surface = (unsigned char*) desc.lpSurface;
for (int i = 0; i < mode.height; i++) { for (int i = 0; i < mode.height; i++) {
@ -192,7 +192,7 @@ BOOL MxDirect3D::D3DSetMode()
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
desc.dwSize = 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; unsigned char* surface = (unsigned char*) desc.lpSurface;
for (int i = 0; i < mode.height; i++) { for (int i = 0; i < mode.height; i++) {

View File

@ -539,10 +539,10 @@ void MxDirectDraw::ClearBackBuffers()
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (result == DDERR_SURFACELOST) {
m_pBackBuffer->Restore(); 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) { if (result != DD_OK) {

View File

@ -24,7 +24,7 @@ class MxString : public MxCore {
const MxString& operator=(const char* p_str); const MxString& operator=(const char* p_str);
MxString operator+(const MxString& p_str) const; MxString operator+(const MxString& p_str) const;
MxString operator+(const char* 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); static void CharSwap(char* p_a, char* p_b);
LEGO1_EXPORT static void MapPathToFilesystem(char* p_path); LEGO1_EXPORT static void MapPathToFilesystem(char* p_path);

View File

@ -9,6 +9,8 @@
#include "mxticklethread.h" #include "mxticklethread.h"
#include "mxwavepresenter.h" #include "mxwavepresenter.h"
#include <SDL3/SDL_log.h>
DECOMP_SIZE_ASSERT(MxSoundManager, 0x3c); DECOMP_SIZE_ASSERT(MxSoundManager, 0x3c);
// GLOBAL LEGO1 0x10101420 // GLOBAL LEGO1 0x10101420
@ -98,12 +100,17 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
spec.format = SDL_AUDIO_F32; spec.format = SDL_AUDIO_F32;
spec.channels = ma_engine_get_channels(m_engine); 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) { 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) { if (p_createThread) {
m_thread = new MxTickleThread(this, p_frequencyMS); m_thread = new MxTickleThread(this, p_frequencyMS);

View File

@ -217,7 +217,6 @@ void MxString::MapPathToFilesystem(char* p_path)
} }
else if (j == 1) { else if (j == 1) {
SDL_strlcpy(&p_path[i - 1], file.GetData(), file.GetLength() + 1); SDL_strlcpy(&p_path[i - 1], file.GetData(), file.GetLength() + 1);
SDL_Log("Resolved file path to %s", p_path);
return true; return true;
} }
} }
@ -229,5 +228,14 @@ void MxString::MapPathToFilesystem(char* p_path)
if (!mapPath(MxOmni::GetHDFiles())) { if (!mapPath(MxOmni::GetHDFiles())) {
mapPath(MxOmni::GetCDFiles()); mapPath(MxOmni::GetCDFiles());
} }
#else
char* path = p_path;
while (*path) {
if (*path == '/') {
*path = '\\';
}
path++;
}
#endif #endif
} }

View File

@ -289,7 +289,7 @@ void DecodeBrun(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_da
while (--line >= 0) { while (--line >= 0) {
short column = 0; short column = 0;
data++; data++;
char count = 0; signed char count = 0;
while ((column += count) < width2) { while ((column += count) < width2) {
count = *data++; count = *data++;
@ -332,7 +332,7 @@ void DecodeLC(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data
while (packets > 0) { while (packets > 0) {
column += *data++; // skip byte column += *data++; // skip byte
char type = *((char*) data++); signed char type = *((signed char*) data++);
if (type < 0) { if (type < 0) {
type = -type; type = -type;
@ -418,7 +418,7 @@ void DecodeSS2(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_dat
// LINE: BETA10 0x1013e726 // LINE: BETA10 0x1013e726
column += *data.byte++; column += *data.byte++;
// LINE: BETA10 0x1013e73a // LINE: BETA10 0x1013e73a
short type = *(char*) data.byte++; short type = *(signed char*) data.byte++;
type += type; type += type;
if (type >= 0) { if (type >= 0) {

View File

@ -402,10 +402,10 @@ void MxDisplaySurface::VTable0x28(
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (hr == DDERR_SURFACELOST) {
m_ddSurface2->Restore(); 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) { if (hr != DD_OK) {
@ -514,10 +514,10 @@ void MxDisplaySurface::VTable0x30(
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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) { if (hr == DDERR_SURFACELOST) {
m_ddSurface2->Restore(); 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) { 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)); memset(&surfaceDesc, 0, sizeof(surfaceDesc));
surfaceDesc.dwSize = 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) { if (result == DDERR_SURFACELOST) {
m_ddSurface2->Restore(); 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) { if (result == DD_OK) {
@ -784,7 +784,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p
DDSURFACEDESC ddsd; DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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; MxU8* surface = (MxU8*) ddsd.lpSurface;
MxS32 height = m_videoParam.GetRect().GetHeight(); MxS32 height = m_videoParam.GetRect().GetHeight();
@ -891,7 +891,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44(
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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->Release();
surface = NULL; surface = NULL;
} }
@ -1067,7 +1067,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface()
memset(&ddsd, 0, sizeof(ddsd)); memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = 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; goto done;
} }
else { else {

View File

@ -108,6 +108,7 @@ void OrientableROI::SetLocal2World(const Matrix4& p_local2world)
} }
// FUNCTION: LEGO1 0x100a5910 // FUNCTION: LEGO1 0x100a5910
// FUNCTION: BETA10 0x10167bac
void OrientableROI::UpdateWorldData() void OrientableROI::UpdateWorldData()
{ {
UpdateWorldBoundingVolumes(); UpdateWorldBoundingVolumes();
@ -115,6 +116,7 @@ void OrientableROI::UpdateWorldData()
} }
// FUNCTION: LEGO1 0x100a5930 // FUNCTION: LEGO1 0x100a5930
// FUNCTION: BETA10 0x10167bd8
void OrientableROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform) void OrientableROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform)
{ {
m_local2world = p_transform; m_local2world = p_transform;
@ -123,6 +125,7 @@ void OrientableROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform
} }
// FUNCTION: LEGO1 0x100a5960 // FUNCTION: LEGO1 0x100a5960
// FUNCTION: BETA10 0x10167c19
void OrientableROI::UpdateWorldDataWithTransform(const Matrix4& p_transform) void OrientableROI::UpdateWorldDataWithTransform(const Matrix4& p_transform)
{ {
MxMatrix l_matrix(m_local2world); MxMatrix l_matrix(m_local2world);
@ -132,6 +135,7 @@ void OrientableROI::UpdateWorldDataWithTransform(const Matrix4& p_transform)
} }
// FUNCTION: LEGO1 0x100a59b0 // FUNCTION: LEGO1 0x100a59b0
// FUNCTION: BETA10 0x10167c6d
void OrientableROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& p_transform) void OrientableROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& p_transform)
{ {
MxMatrix l_matrix(m_local2world); MxMatrix l_matrix(m_local2world);
@ -155,11 +159,13 @@ void OrientableROI::SetWorldVelocity(const Vector3& p_world_velocity)
} }
// FUNCTION: LEGO1 0x100a5a50 // FUNCTION: LEGO1 0x100a5a50
// FUNCTION: BETA10 0x10167d65
void OrientableROI::UpdateWorldVelocity() void OrientableROI::UpdateWorldVelocity()
{ {
} }
// FUNCTION: LEGO1 0x100a5a60 // FUNCTION: LEGO1 0x100a5a60
// FUNCTION: BETA10 0x10167d7b
void CalcWorldBoundingVolumes( void CalcWorldBoundingVolumes(
const BoundingSphere& modelling_sphere, const BoundingSphere& modelling_sphere,
const Matrix4& local2world, const Matrix4& local2world,
@ -186,18 +192,21 @@ void CalcWorldBoundingVolumes(
} }
// FUNCTION: LEGO1 0x100a5d80 // FUNCTION: LEGO1 0x100a5d80
// FUNCTION: BETA10 0x10168760
const float* OrientableROI::GetWorldVelocity() const const float* OrientableROI::GetWorldVelocity() const
{ {
return m_world_velocity.GetData(); return m_world_velocity.GetData();
} }
// FUNCTION: LEGO1 0x100a5d90 // FUNCTION: LEGO1 0x100a5d90
// FUNCTION: BETA10 0x10168790
const BoundingBox& OrientableROI::GetWorldBoundingBox() const const BoundingBox& OrientableROI::GetWorldBoundingBox() const
{ {
return m_world_bounding_box; return m_world_bounding_box;
} }
// FUNCTION: LEGO1 0x100a5da0 // FUNCTION: LEGO1 0x100a5da0
// FUNCTION: BETA10 0x101687b0
const BoundingSphere& OrientableROI::GetWorldBoundingSphere() const const BoundingSphere& OrientableROI::GetWorldBoundingSphere() const
{ {
return m_world_bounding_sphere; return m_world_bounding_sphere;

View File

@ -27,6 +27,7 @@ class OrientableROI : public ROI {
const BoundingSphere& GetWorldBoundingSphere() const override; // vtable+0x10 const BoundingSphere& GetWorldBoundingSphere() const override; // vtable+0x10
// FUNCTION: LEGO1 0x100a5db0 // FUNCTION: LEGO1 0x100a5db0
// FUNCTION: BETA10 0x101687d0
virtual void WrappedUpdateWorldData() { UpdateWorldData(); } // vtable+0x14 virtual void WrappedUpdateWorldData() { UpdateWorldData(); } // vtable+0x14
virtual void UpdateWorldBoundingVolumes() = 0; // vtable+0x18 virtual void UpdateWorldBoundingVolumes() = 0; // vtable+0x18
@ -85,6 +86,7 @@ class OrientableROI : public ROI {
// OrientableROI::`scalar deleting destructor' // OrientableROI::`scalar deleting destructor'
// SYNTHETIC: LEGO1 0x100aa2f0 // SYNTHETIC: LEGO1 0x100aa2f0
// SYNTHETIC: BETA10 0x10168600
// OrientableROI::~OrientableROI // OrientableROI::~OrientableROI
#endif // ORIENTABLEROI_H #endif // ORIENTABLEROI_H

View File

@ -15,9 +15,16 @@
// SIZE 0x28 // SIZE 0x28
class BoundingBox { class BoundingBox {
public: public:
// The BETA10 matches may reference the wrong version
// FUNCTION: BETA10 0x1004a7a0
const Vector3& Min() const { return min; } const Vector3& Min() const { return min; }
Vector3& Min() { return min; } Vector3& Min() { return min; }
// FUNCTION: BETA10 0x1004a7c0
const Vector3& Max() const { return max; } const Vector3& Max() const { return max; }
Vector3& Max() { return max; } Vector3& Max() { return max; }
private: private:
@ -31,14 +38,26 @@ class BoundingBox {
// SIZE 0x18 // SIZE 0x18
class BoundingSphere { class BoundingSphere {
public: public:
// The BETA10 matches may reference the wrong version
// FUNCTION: BETA10 0x1001fac0
const Vector3& Center() const { return center; } const Vector3& Center() const { return center; }
// FUNCTION: BETA10 0x100d55a0
Vector3& Center() { return center; } Vector3& Center() { return center; }
// FUNCTION: BETA10 0x1001fd30
const float& Radius() const { return radius; } const float& Radius() const { return radius; }
// FUNCTION: BETA10 0x1001fae0
float& Radius() { return radius; } float& Radius() { return radius; }
// SYNTHETIC: BETA10 0x1001fb90 // SYNTHETIC: BETA10 0x1001fb90
// BoundingSphere::operator= // BoundingSphere::operator=
// SYNTHETIC: BETA10 0x1001fc50
// BoundingSphere::BoundingSphere
private: private:
Mx3DPointFloat center; // 0x00 Mx3DPointFloat center; // 0x00
float radius; // 0x14 float radius; // 0x14
@ -136,6 +155,7 @@ class ROI {
// list<ROI *,allocator<ROI *> >::~list<ROI *,allocator<ROI *> > // list<ROI *,allocator<ROI *> >::~list<ROI *,allocator<ROI *> >
// SYNTHETIC: LEGO1 0x100a5d50 // SYNTHETIC: LEGO1 0x100a5d50
// SYNTHETIC: BETA10 0x101686a0
// ROI::~ROI // ROI::~ROI
#endif // ROI_H #endif // ROI_H

View File

@ -252,8 +252,8 @@ class ViewImpl : public View {
Result TransformWorldToScreen(const float world[3], float screen[4]) override; Result TransformWorldToScreen(const float world[3], float screen[4]) override;
Result TransformScreenToWorld(const float screen[4], float world[3]) override; Result TransformScreenToWorld(const float screen[4], float world[3]) override;
Result Pick( Result Pick(
unsigned int x, int x,
unsigned int y, int y,
const Group** ppGroupsToPickFrom, const Group** ppGroupsToPickFrom,
int groupsToPickFromCount, int groupsToPickFromCount,
const Group**& rppPickedGroups, const Group**& rppPickedGroups,
@ -277,8 +277,8 @@ class ViewImpl : public View {
Result SetCamera(const CameraImpl& rCamera); Result SetCamera(const CameraImpl& rCamera);
Result Render(const GroupImpl& rScene); Result Render(const GroupImpl& rScene);
Result Pick( Result Pick(
unsigned int x, int x,
unsigned int y, int y,
const GroupImpl** ppGroupsToPickFrom, const GroupImpl** ppGroupsToPickFrom,
int groupsToPickFromCount, int groupsToPickFromCount,
const Group**& rppPickedGroups, const Group**& rppPickedGroups,
@ -867,4 +867,7 @@ inline D3DRMMATERIALMODE Translate(MaterialMode mode)
// GLOBAL: LEGO1 0x100dd1e0 // GLOBAL: LEGO1 0x100dd1e0
// IID_IDirect3DRMMeshBuilder // IID_IDirect3DRMMeshBuilder
// GLOBAL: LEGO1 0x100dd1f0
// IID_IDirect3DRMMesh
#endif #endif

View File

@ -17,7 +17,7 @@ void* MeshImpl::ImplementationDataPtr()
} }
// FUNCTION: BETA10 0x10170590 // 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) { if (a > 0) {
D3DCOLOR color = D3DRMCreateColorRGBA(r, g, b, a); 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: LEGO1 0x100a3ee0
// FUNCTION: BETA10 0x10170520 // 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); assert(m_data);
@ -38,14 +38,14 @@ Tgl::Result MeshImpl::SetColor(float r, float g, float b, float a)
} }
// FUNCTION: BETA10 0x10171320 // 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; return result;
} }
// FUNCTION: BETA10 0x10171260 // FUNCTION: BETA10 0x10171260
inline Tgl::Result MeshImpl::SetTexture(const TextureImpl* pTexture) inline Result MeshImpl::SetTexture(const TextureImpl* pTexture)
{ {
assert(m_data); assert(m_data);
assert(!pTexture || pTexture->ImplementationData()); assert(!pTexture || pTexture->ImplementationData());
@ -56,7 +56,7 @@ inline Tgl::Result MeshImpl::SetTexture(const TextureImpl* pTexture)
// FUNCTION: LEGO1 0x100a3f50 // FUNCTION: LEGO1 0x100a3f50
// FUNCTION: BETA10 0x10170630 // FUNCTION: BETA10 0x10170630
Tgl::Result MeshImpl::SetTexture(const Texture* pTexture) Result MeshImpl::SetTexture(const Texture* pTexture)
{ {
assert(m_data); assert(m_data);
@ -65,7 +65,7 @@ Tgl::Result MeshImpl::SetTexture(const Texture* pTexture)
// FUNCTION: LEGO1 0x100a3f80 // FUNCTION: LEGO1 0x100a3f80
// FUNCTION: BETA10 0x10170690 // FUNCTION: BETA10 0x10170690
Tgl::Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode) Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode)
{ {
assert(m_data); assert(m_data);
@ -73,7 +73,7 @@ Tgl::Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode)
} }
// FUNCTION: BETA10 0x10170750 // FUNCTION: BETA10 0x10170750
inline Tgl::Result MeshSetShadingModel(MeshImpl::MeshData* pMesh, ShadingModel model) inline Result MeshSetShadingModel(MeshImpl::MeshData* pMesh, ShadingModel model)
{ {
D3DRMRENDERQUALITY mode = Translate(model); D3DRMRENDERQUALITY mode = Translate(model);
return ResultVal(pMesh->groupMesh->SetGroupQuality(pMesh->groupIndex, mode)); 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: LEGO1 0x100a3fc0
// FUNCTION: BETA10 0x101706f0 // FUNCTION: BETA10 0x101706f0
Tgl::Result MeshImpl::SetShadingModel(ShadingModel model) Result MeshImpl::SetShadingModel(ShadingModel model)
{ {
assert(m_data); assert(m_data);
return MeshSetShadingModel(m_data, model); return MeshSetShadingModel(m_data, model);
} }
// FUNCTION: BETA10 0x101714e0 // 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 = new MeshImpl::MeshData();
rpTarget->groupMesh = pMesh; rpTarget->groupMesh = pMesh;
@ -97,13 +97,13 @@ inline Tgl::Result MeshDeepClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData
DWORD dataSize; DWORD dataSize;
unsigned int vcount, fcount, vperface; unsigned int vcount, fcount, vperface;
Tgl::Result result = Result result =
ResultVal(pSource->groupMesh->GetGroup(pSource->groupIndex, (unsigned int*)&vcount, (unsigned int*)&fcount, (unsigned int*)&vperface, &dataSize, NULL)); ResultVal(pSource->groupMesh->GetGroup(pSource->groupIndex, &vcount, &fcount, &vperface, &dataSize, NULL));
assert(Succeeded(result)); assert(Succeeded(result));
unsigned int* faceBuffer = new unsigned int[dataSize]; unsigned int* faceBuffer = new unsigned int[dataSize];
result = 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)); assert(Succeeded(result));
@ -122,7 +122,7 @@ inline Tgl::Result MeshDeepClone(MeshImpl::MeshData* pSource, MeshImpl::MeshData
// Push information to new group // Push information to new group
D3DRMGROUPINDEX index; 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)); assert(Succeeded(result));
rpTarget->groupIndex = index; rpTarget->groupIndex = index;
@ -180,9 +180,9 @@ Mesh* MeshImpl::DeepClone(MeshBuilder* pMesh)
return DeepClone(*static_cast<MeshBuilderImpl*>(pMesh)); return DeepClone(*static_cast<MeshBuilderImpl*>(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(); rpTarget = new MeshImpl::MeshData();
if (rpTarget) { if (rpTarget) {
@ -220,13 +220,13 @@ Mesh* MeshImpl::ShallowClone(MeshBuilder* pMeshBuilder)
} }
// FUNCTION: BETA10 0x10171ac0 // 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)); return ResultVal(pMesh->groupMesh->GetGroupTexture(pMesh->groupIndex, pD3DTexture));
} }
// FUNCTION: BETA10 0x10171980 // FUNCTION: BETA10 0x10171980
inline Tgl::Result MeshImpl::GetTexture(TextureImpl** ppTexture) inline Result MeshImpl::GetTexture(TextureImpl** ppTexture)
{ {
assert(m_data); assert(m_data);
assert(ppTexture); assert(ppTexture);
@ -236,7 +236,7 @@ inline Tgl::Result MeshImpl::GetTexture(TextureImpl** ppTexture)
// TODO: This helps retail match, but it adds to the stack // TODO: This helps retail match, but it adds to the stack
IDirect3DRMTexture* tex; IDirect3DRMTexture* tex;
Tgl::Result result = MeshGetTexture(m_data, &tex); Result result = MeshGetTexture(m_data, &tex);
#ifndef BETA10 #ifndef BETA10
if (Succeeded(result)) { if (Succeeded(result)) {
@ -251,7 +251,7 @@ inline Tgl::Result MeshImpl::GetTexture(TextureImpl** ppTexture)
// FUNCTION: LEGO1 0x100a4330 // FUNCTION: LEGO1 0x100a4330
// FUNCTION: BETA10 0x10170820 // FUNCTION: BETA10 0x10170820
Tgl::Result MeshImpl::GetTexture(Texture*& rpTexture) Result MeshImpl::GetTexture(Texture*& rpTexture)
{ {
assert(m_data); assert(m_data);

View File

@ -15,6 +15,7 @@ void* MeshBuilderImpl::ImplementationDataPtr()
} }
// FUNCTION: LEGO1 0x100a3840 // FUNCTION: LEGO1 0x100a3840
// FUNCTION: BETA10 0x1016ca40
Mesh* MeshBuilderImpl::CreateMesh( Mesh* MeshBuilderImpl::CreateMesh(
unsigned int faceCount, unsigned int faceCount,
unsigned int vertexCount, unsigned int vertexCount,
@ -26,6 +27,8 @@ Mesh* MeshBuilderImpl::CreateMesh(
ShadingModel shadingModel ShadingModel shadingModel
) )
{ {
assert(m_data);
MeshImpl* pMeshImpl = new MeshImpl; MeshImpl* pMeshImpl = new MeshImpl;
if (CreateMeshImpl( if (CreateMeshImpl(
pMeshImpl, pMeshImpl,
@ -45,63 +48,67 @@ Mesh* MeshBuilderImpl::CreateMesh(
return pMeshImpl; return pMeshImpl;
} }
inline Tgl::Result CreateMesh( // FUNCTION: BETA10 0x1016fef0
inline Result CreateMesh(
IDirect3DRMMesh* pD3DRM, IDirect3DRMMesh* pD3DRM,
unsigned int faceCount, unsigned int p_numFaces,
unsigned int vertexCount, unsigned int p_numVertices,
float (*pPositions)[3], float(*p_positions),
float (*pNormals)[3], float(*p_normals),
float (*pTextureCoordinates)[2], float(*p_textureCoordinates),
unsigned int (*pFaceIndices)[3], unsigned int (*p_faceIndices)[3],
unsigned int (*pTextureIndices)[3], unsigned int (*p_textureIndices)[3],
ShadingModel shadingModel, ShadingModel shadingModel,
MeshImpl::MeshDataType& rpMesh MeshImpl::MeshDataType& rpMesh
) )
{ {
unsigned int* faceIndices = (unsigned int*) pFaceIndices; unsigned short* faceIndices = (unsigned short*) p_faceIndices;
D3DRMGROUPINDEX groupIndex = 0; D3DRMGROUPINDEX groupIndex = 0;
int count = faceCount * 3; int faceCount = p_numFaces * 3;
int index = 0; int count = 0;
unsigned int* fData = new unsigned int[count]; unsigned int* fData = new unsigned int[faceCount];
D3DRMVERTEX* vertices = new D3DRMVERTEX[vertexCount]; D3DRMVERTEX* vertices = new D3DRMVERTEX[p_numVertices];
memset(vertices, 0, sizeof(*vertices) * vertexCount); memset(vertices, 0, sizeof(*vertices) * p_numVertices);
rpMesh = new MeshImpl::MeshData; rpMesh = new MeshImpl::MeshData;
rpMesh->groupMesh = pD3DRM; rpMesh->groupMesh = pD3DRM;
for (int i = 0; i < count; i++) { for (int i = 0; i < faceCount; i++) {
if ((*((unsigned short*) &faceIndices[i] + 1) >> 0x0f) & 0x01) { if (((faceIndices[2 * i + 1]) >> 0x0f) & 0x01) {
unsigned int j = *(unsigned short*) &faceIndices[i]; unsigned int j = 3 * faceIndices[2 * i];
vertices[index].position.x = pPositions[j][0]; vertices[count].position.x = p_positions[j];
vertices[index].position.y = pPositions[j][1]; vertices[count].position.y = p_positions[j + 1];
vertices[index].position.z = pPositions[j][2]; vertices[count].position.z = p_positions[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];
if (pTextureIndices != NULL && pTextureCoordinates != NULL) { int k = 3 * (faceIndices[2 * i + 1] & MAXSHORT);
j = ((unsigned int*) pTextureIndices)[i]; vertices[count].normal.x = p_normals[k];
vertices[index].tu = pTextureCoordinates[j][0]; vertices[count].normal.y = p_normals[k + 1];
vertices[index].tv = pTextureCoordinates[j][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; fData[i] = count;
index++; count++;
} }
else { else {
fData[i] = *(unsigned short*) &faceIndices[i]; fData[i] = faceIndices[2 * i];
} }
} }
Tgl::Result result; assert(count == (int) p_numVertices);
result = ResultVal(pD3DRM->AddGroup(vertexCount, faceCount, 3, (long unsigned int*)fData, &groupIndex));
Result result;
result = ResultVal(pD3DRM->AddGroup(p_numVertices, p_numFaces, 3, fData, &groupIndex));
if (Succeeded(result)) { if (Succeeded(result)) {
rpMesh->groupIndex = groupIndex; rpMesh->groupIndex = groupIndex;
result = ResultVal(pD3DRM->SetVertices(groupIndex, 0, vertexCount, vertices)); result = ResultVal(pD3DRM->SetVertices(groupIndex, 0, p_numVertices, vertices));
} }
if (!Succeeded(result)) { if (!Succeeded(result)) {
@ -112,6 +119,7 @@ inline Tgl::Result CreateMesh(
} }
else { else {
result = MeshSetTextureMappingMode(rpMesh, PerspectiveCorrect); result = MeshSetTextureMappingMode(rpMesh, PerspectiveCorrect);
assert(Succeeded(result));
} }
if (fData != NULL) { if (fData != NULL) {
@ -125,7 +133,8 @@ inline Tgl::Result CreateMesh(
return result; return result;
} }
inline Tgl::Result MeshBuilderImpl::CreateMeshImpl( // FUNCTION: BETA10 0x1016fe40
inline Result MeshBuilderImpl::CreateMeshImpl(
MeshImpl* pMeshImpl, MeshImpl* pMeshImpl,
unsigned int faceCount, unsigned int faceCount,
unsigned int vertexCount, unsigned int vertexCount,
@ -137,13 +146,16 @@ inline Tgl::Result MeshBuilderImpl::CreateMeshImpl(
ShadingModel shadingModel ShadingModel shadingModel
) )
{ {
assert(m_data);
assert(!pMeshImpl->ImplementationData());
return ::CreateMesh( return ::CreateMesh(
m_data, m_data,
faceCount, faceCount,
vertexCount, vertexCount,
pPositions, reinterpret_cast<float*>(pPositions),
pNormals, reinterpret_cast<float*>(pNormals),
pTextureCoordinates, reinterpret_cast<float*>(pTextureCoordinates),
pFaceIndices, pFaceIndices,
pTextureIndices, pTextureIndices,
shadingModel, shadingModel,
@ -152,10 +164,10 @@ inline Tgl::Result MeshBuilderImpl::CreateMeshImpl(
} }
// FUNCTION: BETA10 0x1016e060 // 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; D3DRMBOX box;
Tgl::Result result = ResultVal(pMesh->GetBox(&box)); Result result = ResultVal(pMesh->GetBox(&box));
if (Succeeded(result)) { if (Succeeded(result)) {
min[0] = box.min.x; min[0] = box.min.x;
min[1] = box.min.y; min[1] = box.min.y;
@ -169,7 +181,7 @@ inline Tgl::Result MeshBuilderGetBoundingBox(IDirect3DRMMesh* pMesh, float min[3
// FUNCTION: LEGO1 0x100a3ae0 // FUNCTION: LEGO1 0x100a3ae0
// FUNCTION: BETA10 0x1016ce00 // 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); assert(m_data);

View File

@ -495,8 +495,8 @@ Result ViewImpl::ForceUpdate(unsigned int x, unsigned int y, unsigned int width,
// FUNCTION: BETA10 0x101710f0 // FUNCTION: BETA10 0x101710f0
inline Result ViewImpl::Pick( inline Result ViewImpl::Pick(
unsigned int x, int x,
unsigned int y, int y,
const GroupImpl** ppGroupsToPickFrom, const GroupImpl** ppGroupsToPickFrom,
int groupsToPickFromCount, int groupsToPickFromCount,
const Group**& rppPickedGroups, const Group**& rppPickedGroups,
@ -519,8 +519,8 @@ inline Result ViewImpl::Pick(
// FUNCTION: LEGO1 0x100a30c0 // FUNCTION: LEGO1 0x100a30c0
// FUNCTION: BETA10 0x1016ee10 // FUNCTION: BETA10 0x1016ee10
Result ViewImpl::Pick( Result ViewImpl::Pick(
unsigned int x, int x,
unsigned int y, int y,
const Group** ppGroupsToPickFrom, const Group** ppGroupsToPickFrom,
int groupsToPickFromCount, int groupsToPickFromCount,
const Group**& rppPickedGroups, const Group**& rppPickedGroups,

View File

@ -257,8 +257,8 @@ class View : public Object {
// output parameter // output parameter
// size of rppPickedGroups // size of rppPickedGroups
virtual Result Pick( virtual Result Pick(
unsigned int x, int x,
unsigned int y, int y,
const Group** ppGroupsToPickFrom, const Group** ppGroupsToPickFrom,
int groupsToPickFromCount, int groupsToPickFromCount,
const Group**& rppPickedGroups, const Group**& rppPickedGroups,

View File

@ -499,7 +499,7 @@ float ViewManager::ProjectedSize(const BoundingSphere& p_bounding_sphere)
} }
// FUNCTION: LEGO1 0x100a6e00 // 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; LPDIRECT3DRMPICKEDARRAY picked = NULL;
ViewROI* result = NULL; ViewROI* result = NULL;

View File

@ -33,7 +33,7 @@ class ViewManager {
void RemoveROIDetailFromScene(ViewROI* p_roi); void RemoveROIDetailFromScene(ViewROI* p_roi);
void SetPOVSource(const OrientableROI* point_of_view); void SetPOVSource(const OrientableROI* point_of_view);
float ProjectedSize(const BoundingSphere& p_bounding_sphere); 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 SetResolution(int width, int height);
void SetFrustrum(float fov, float front, float back); void SetFrustrum(float fov, float front, float back);
inline void ManageVisibilityAndDetailRecursively(ViewROI* p_from, int p_lodLevel); inline void ManageVisibilityAndDetailRecursively(ViewROI* p_from, int p_lodLevel);

View File

@ -16,65 +16,60 @@ float ViewROI::IntrinsicImportance() const
} // for now } // for now
// FUNCTION: LEGO1 0x100a9ec0 // FUNCTION: LEGO1 0x100a9ec0
// FUNCTION: BETA10 0x1018c740
Tgl::Group* ViewROI::GetGeometry() Tgl::Group* ViewROI::GetGeometry()
{ {
return geometry; return geometry;
} }
// FUNCTION: LEGO1 0x100a9ed0 // FUNCTION: LEGO1 0x100a9ed0
// FUNCTION: BETA10 0x1018c760
const Tgl::Group* ViewROI::GetGeometry() const const Tgl::Group* ViewROI::GetGeometry() const
{ {
return geometry; return geometry;
} }
// FUNCTION: LEGO1 0x100a9ee0 // FUNCTION: LEGO1 0x100a9ee0
// FUNCTION: BETA10 0x1018c780
void ViewROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& parent2world) void ViewROI::UpdateWorldDataWithTransformAndChildren(const Matrix4& parent2world)
{ {
OrientableROI::UpdateWorldDataWithTransformAndChildren(parent2world); OrientableROI::UpdateWorldDataWithTransformAndChildren(parent2world);
SetGeometryTransformation();
}
// FUNCTION: BETA10 0x1018c7b0
inline void ViewROI::SetGeometryTransformation()
{
if (geometry) { if (geometry) {
Tgl::FloatMatrix4 matrix; Tgl::FloatMatrix4 matrix;
Matrix4 in(matrix); Matrix4 in(matrix);
SETMAT4(in, m_local2world); SETMAT4(in, m_local2world);
Tgl::Result result = geometry->SetTransformation(matrix); geometry->SetTransformation(matrix);
// assert(Tgl::Succeeded(result));
} }
} }
// FUNCTION: LEGO1 0x100a9fc0 // FUNCTION: LEGO1 0x100a9fc0
// FUNCTION: BETA10 0x1018cad0
void ViewROI::UpdateWorldDataWithTransform(const Matrix4& p_transform) void ViewROI::UpdateWorldDataWithTransform(const Matrix4& p_transform)
{ {
OrientableROI::UpdateWorldDataWithTransform(p_transform); OrientableROI::UpdateWorldDataWithTransform(p_transform);
if (geometry) { SetGeometryTransformation();
Tgl::FloatMatrix4 matrix;
Matrix4 in(matrix);
SETMAT4(in, m_local2world);
geometry->SetTransformation(matrix);
}
} }
// FUNCTION: LEGO1 0x100aa0a0 // FUNCTION: LEGO1 0x100aa0a0
// FUNCTION: BETA10 0x1018cb00
void ViewROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform) void ViewROI::SetLocal2WorldWithWorldDataUpdate(const Matrix4& p_transform)
{ {
OrientableROI::SetLocal2WorldWithWorldDataUpdate(p_transform); OrientableROI::SetLocal2WorldWithWorldDataUpdate(p_transform);
if (geometry) { SetGeometryTransformation();
Tgl::FloatMatrix4 matrix;
Matrix4 in(matrix);
SETMAT4(in, m_local2world);
geometry->SetTransformation(matrix);
}
} }
// FUNCTION: LEGO1 0x100aa180 // FUNCTION: LEGO1 0x100aa180
// FUNCTION: BETA10 0x1018cb30
void ViewROI::UpdateWorldData() void ViewROI::UpdateWorldData()
{ {
OrientableROI::UpdateWorldData(); OrientableROI::UpdateWorldData();
if (geometry) { SetGeometryTransformation();
Tgl::FloatMatrix4 matrix;
Matrix4 in(matrix);
SETMAT4(in, m_local2world);
geometry->SetTransformation(matrix);
}
} }
// FUNCTION: LEGO1 0x100aa500 // FUNCTION: LEGO1 0x100aa500

View File

@ -13,6 +13,7 @@
*/ */
// VTABLE: LEGO1 0x100dbe70 // VTABLE: LEGO1 0x100dbe70
// VTABLE: BETA10 0x101c3908
// SIZE 0xe4 // SIZE 0xe4
class ViewROI : public OrientableROI { class ViewROI : public OrientableROI {
public: public:
@ -21,6 +22,7 @@ class ViewROI : public OrientableROI {
c_lodLevelInvisible = -2, c_lodLevelInvisible = -2,
}; };
// FUNCTION: BETA10 0x1018c5e0
ViewROI(Tgl::Renderer* pRenderer, ViewLODList* lodList) ViewROI(Tgl::Renderer* pRenderer, ViewLODList* lodList)
{ {
SetLODList(lodList); SetLODList(lodList);
@ -29,6 +31,7 @@ class ViewROI : public OrientableROI {
} }
// FUNCTION: LEGO1 0x100a9e20 // FUNCTION: LEGO1 0x100a9e20
// FUNCTION: BETA10 0x1018c680
~ViewROI() override ~ViewROI() override
{ {
// SetLODList() will decrease refCount of LODList // SetLODList() will decrease refCount of LODList
@ -36,6 +39,7 @@ class ViewROI : public OrientableROI {
delete geometry; delete geometry;
} }
// FUNCTION: BETA10 0x1007b540
void SetLODList(ViewLODList* lodList) void SetLODList(ViewLODList* lodList)
{ {
// ??? inherently type unsafe - kind of... because, now, ROI // ??? inherently type unsafe - kind of... because, now, ROI
@ -69,6 +73,8 @@ class ViewROI : public OrientableROI {
protected: protected:
void UpdateWorldDataWithTransformAndChildren(const Matrix4& parent2world) override; // vtable+0x28 void UpdateWorldDataWithTransformAndChildren(const Matrix4& parent2world) override; // vtable+0x28
void SetGeometryTransformation();
Tgl::Group* geometry; // 0xdc Tgl::Group* geometry; // 0xdc
int m_lodLevel; // 0xe0 int m_lodLevel; // 0xe0
}; };

165
LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
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.

View File

@ -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) | | 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) | | [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 ### 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. 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) | | 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) | | 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) | | [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) | | 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 | - | - | | [SmartHeap](https://github.com/isledecomp/isle/tree/master/3rdparty/smartheap) | Default memory allocator | - | - |
## Building ## 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 ## Contributing

View File

@ -27,6 +27,10 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL
src/d3drm/backends/software/renderer.cpp src/d3drm/backends/software/renderer.cpp
) )
target_compile_definitions(miniwin PRIVATE
$<$<CONFIG:Debug>:DEBUG>
)
find_package(OpenGL) find_package(OpenGL)
find_package(GLEW) find_package(GLEW)
if(OpenGL_FOUND AND GLEW_FOUND) if(OpenGL_FOUND AND GLEW_FOUND)

View File

@ -181,10 +181,10 @@ struct IDirect3DRMMesh : public IDirect3DRMVisual {
virtual HRESULT Clone(int flags, GUID iid, void** object) = 0; virtual HRESULT Clone(int flags, GUID iid, void** object) = 0;
virtual HRESULT GetBox(D3DRMBOX* box) = 0; virtual HRESULT GetBox(D3DRMBOX* box) = 0;
virtual HRESULT AddGroup( virtual HRESULT AddGroup(
int vertexCount, unsigned int vertexCount,
int faceCount, unsigned int faceCount,
int vertexPerFace, unsigned int vertexPerFace,
DWORD* faceBuffer, unsigned int* faceBuffer,
D3DRMGROUPINDEX* groupIndex D3DRMGROUPINDEX* groupIndex
) = 0; ) = 0;
virtual HRESULT GetGroup( virtual HRESULT GetGroup(

View File

@ -159,12 +159,15 @@ enum class DDBltFastFlags : uint32_t {
}; };
ENABLE_BITMASK_OPERATORS(DDBltFastFlags) ENABLE_BITMASK_OPERATORS(DDBltFastFlags)
#define DDLOCK_WAIT DDLockFlags::WAIT
#define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR #define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR
#define DDLOCK_WAIT DDLockFlags::WAIT
#define DDLOCK_WRITEONLY DDLockFlags::WRITEONLY
enum class DDLockFlags : uint32_t { enum class DDLockFlags : uint32_t {
SURFACEMEMORYPTR, SURFACEMEMORYPTR = 0,
WAIT, WAIT = 1 << 0,
WRITEONLY = 1 << 5,
}; };
ENABLE_BITMASK_OPERATORS(DDLockFlags)
#define DDSCL_FULLSCREEN DDSCLFlags::FULLSCREEN #define DDSCL_FULLSCREEN DDSCLFlags::FULLSCREEN
#define DDSCL_ALLOWREBOOT DDSCLFlags::ALLOWREBOOT #define DDSCL_ALLOWREBOOT DDSCLFlags::ALLOWREBOOT

View File

@ -46,7 +46,6 @@
#define CLIP_DEFAULT_PRECIS 0 #define CLIP_DEFAULT_PRECIS 0
#define DEFAULT_QUALITY 0 #define DEFAULT_QUALITY 0
#define ETO_OPAQUE 0x0002 #define ETO_OPAQUE 0x0002
#define FF_DONTCARE 0x00000000
#define RASTERCAPS 0x00000000 #define RASTERCAPS 0x00000000
#define RC_PALETTE 0x0100 #define RC_PALETTE 0x0100
#define SIZEPALETTE 104 #define SIZEPALETTE 104

View File

@ -11,19 +11,22 @@
static LPDIRECT3D9 g_d3d; static LPDIRECT3D9 g_d3d;
static LPDIRECT3DDEVICE9 g_device; static LPDIRECT3DDEVICE9 g_device;
static HWND g_hwnd; static HWND g_hwnd;
static LPDIRECT3DTEXTURE9 g_renderTargetTex; static int g_width;
static LPDIRECT3DSURFACE9 g_renderTargetSurf; static int g_height;
static LPDIRECT3DSURFACE9 g_oldRenderTarget; static int g_virtualWidth;
static int m_width; static int g_virtualHeight;
static int m_height; static bool g_hasScene = false;
static std::vector<BridgeSceneLight> m_lights; static std::vector<BridgeSceneLight> g_lights;
static Matrix4x4 m_projection; static Matrix4x4 g_projection;
static ViewportTransform g_viewportTransform;
bool Actual_Initialize(void* hwnd, int width, int height) bool Actual_Initialize(void* hwnd, int width, int height)
{ {
g_hwnd = (HWND) hwnd; g_hwnd = (HWND) hwnd;
m_width = width; g_width = width;
m_height = height; g_height = height;
g_virtualWidth = width;
g_virtualHeight = height;
g_d3d = Direct3DCreate9(D3D_SDK_VERSION); g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (!g_d3d) { if (!g_d3d) {
return false; return false;
@ -52,45 +55,17 @@ bool Actual_Initialize(void* hwnd, int width, int height)
return false; return false;
} }
hr = g_device->CreateTexture(
width,
height,
1,
D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&g_renderTargetTex,
nullptr
);
if (FAILED(hr)) { if (FAILED(hr)) {
g_device->Release(); g_device->Release();
g_d3d->Release(); g_d3d->Release();
return false; 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; return true;
} }
void Actual_Shutdown() void Actual_Shutdown()
{ {
if (g_renderTargetSurf) {
g_renderTargetSurf->Release();
g_renderTargetSurf = nullptr;
}
if (g_renderTargetTex) {
g_renderTargetTex->Release();
g_renderTargetTex = nullptr;
}
if (g_device) { if (g_device) {
g_device->Release(); g_device->Release();
g_device = nullptr; g_device = nullptr;
@ -103,12 +78,12 @@ void Actual_Shutdown()
void Actual_PushLights(const BridgeSceneLight* lightsArray, size_t count) 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) 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) IDirect3DTexture9* UploadSurfaceToD3DTexture(SDL_Surface* surface)
@ -188,18 +163,71 @@ void UploadMeshBuffers(
cache.ibo->Unlock(); cache.ibo->Unlock();
} }
constexpr float PI = 3.14159265358979323846f; void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform)
void SetupLights()
{ {
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<int>(r * 255), static_cast<int>(g * 255), static_cast<int>(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_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) { for (DWORD i = 0; i < 8; ++i) {
g_device->LightEnable(i, FALSE); g_device->LightEnable(i, FALSE);
} }
DWORD lightIdx = 0; DWORD lightIdx = 0;
for (const auto& l : m_lights) { for (const auto& l : g_lights) {
if (lightIdx >= 8) { if (lightIdx >= 8) {
break; break;
} }
@ -235,30 +263,16 @@ void SetupLights()
} }
light.Falloff = 1.0f; light.Falloff = 1.0f;
light.Phi = PI; light.Phi = M_PI;
light.Theta = PI / 2; light.Theta = M_PI / 2;
if (SUCCEEDED(g_device->SetLight(lightIdx, &light))) { if (SUCCEEDED(g_device->SetLight(lightIdx, &light))) {
g_device->LightEnable(lightIdx, TRUE); g_device->LightEnable(lightIdx, TRUE);
} }
++lightIdx; ++lightIdx;
} }
}
uint32_t Actual_BeginFrame() g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
{
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();
return D3D_OK; return D3D_OK;
} }
@ -286,15 +300,19 @@ D3DMATRIX ToD3DMATRIX(const Matrix4x4& in)
void Actual_SubmitDraw( void Actual_SubmitDraw(
const D3D9MeshCacheEntry* mesh, const D3D9MeshCacheEntry* mesh,
const Matrix4x4* modelViewMatrix, const Matrix4x4* modelViewMatrix,
const Matrix4x4* worldMatrix,
const Matrix4x4* viewMatrix,
const Matrix3x3* normalMatrix, const Matrix3x3* normalMatrix,
const Appearance* appearance, const Appearance* appearance,
IDirect3DTexture9* texture IDirect3DTexture9* texture
) )
{ {
D3DMATRIX worldView = ToD3DMATRIX(*modelViewMatrix); D3DMATRIX proj = ToD3DMATRIX(g_projection);
g_device->SetTransform(D3DTS_WORLD, &worldView);
D3DMATRIX proj = ToD3DMATRIX(m_projection);
g_device->SetTransform(D3DTS_PROJECTION, &proj); 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 = {}; D3DMATERIAL9 mat = {};
mat.Diffuse.r = appearance->color.r / 255.0f; 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); 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->EndScene();
g_hasScene = false;
g_device->SetRenderTarget(0, g_oldRenderTarget); return g_device->Present(nullptr, nullptr, nullptr, nullptr);
g_oldRenderTarget->Release(); }
LPDIRECT3DSURFACE9 sysMemSurf; void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
HRESULT hr = {
g_device StartScene();
->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysMemSurf, nullptr);
if (FAILED(hr)) { float left = -g_viewportTransform.offsetX / g_viewportTransform.scale;
return hr; 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;
hr = g_device->GetRenderTargetData(g_renderTargetSurf, sysMemSurf);
if (FAILED(hr)) { auto virtualToScreenX = [&](float x) { return ((x - left) / (right - left)) * g_width; };
sysMemSurf->Release(); auto virtualToScreenY = [&](float y) { return ((y - top) / (bottom - top)) * g_height; };
return hr;
} float x1_virtual = static_cast<float>(dstRect.x);
float y1_virtual = static_cast<float>(dstRect.y);
D3DLOCKED_RECT lockedRect; float x2_virtual = x1_virtual + dstRect.w;
hr = sysMemSurf->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY); float y2_virtual = y1_virtual + dstRect.h;
if (FAILED(hr)) {
sysMemSurf->Release(); float x1 = virtualToScreenX(x1_virtual);
return hr; float y1 = virtualToScreenY(y1_virtual);
} float x2 = virtualToScreenX(x2_virtual);
float y2 = virtualToScreenY(y2_virtual);
BYTE* src = static_cast<BYTE*>(lockedRect.pBits);
BYTE* dst = static_cast<BYTE*>(pixels); D3DMATRIX identity =
int copyWidth = m_width * 4; {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);
for (int y = 0; y < m_height; y++) { g_device->SetTransform(D3DTS_VIEW, &identity);
memcpy(dst + y * pitch, src + y * lockedRect.Pitch, copyWidth); g_device->SetTransform(D3DTS_WORLD, &identity);
}
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
sysMemSurf->UnlockRect(); g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
sysMemSurf->Release();
g_device->SetRenderState(D3DRS_ZENABLE, FALSE);
return hr; 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<float>(texDesc.Width);
float texH = static_cast<float>(texDesc.Height);
float u1 = static_cast<float>(srcRect.x) / texW;
float v1 = static_cast<float>(srcRect.y) / texH;
float u2 = static_cast<float>(srcRect.x + srcRect.w) / texW;
float v2 = static_cast<float>(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<float>(g_width) / g_height;
float dstAspect = static_cast<float>(target->w) / target->h;
SDL_Rect srcRect;
if (srcAspect > dstAspect) {
int cropWidth = static_cast<int>(g_height * dstAspect);
srcRect = {(g_width - cropWidth) / 2, 0, cropWidth, g_height};
}
else {
int cropHeight = static_cast<int>(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;
} }

View File

@ -69,8 +69,14 @@ void Actual_EnableTransparency();
void Actual_SubmitDraw( void Actual_SubmitDraw(
const D3D9MeshCacheEntry* mesh, const D3D9MeshCacheEntry* mesh,
const Matrix4x4* modelViewMatrix, const Matrix4x4* modelViewMatrix,
const Matrix4x4* worldMatrix,
const Matrix4x4* viewMatrix,
const Matrix3x3* normalMatrix, const Matrix3x3* normalMatrix,
const Appearance* appearance, const Appearance* appearance,
IDirect3DTexture9* texture 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);

View File

@ -20,14 +20,18 @@ Direct3DRMRenderer* DirectX9Renderer::Create(DWORD width, DWORD height)
return new DirectX9Renderer(width, 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( Actual_Initialize(
SDL_GetPointerProperty(SDL_GetWindowProperties(DDWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL), SDL_GetPointerProperty(SDL_GetWindowProperties(DDWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL),
width, width,
height 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() DirectX9Renderer::~DirectX9Renderer()
@ -212,16 +216,6 @@ Uint32 DirectX9Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshG
return static_cast<Uint32>(m_meshs.size() - 1); return static_cast<Uint32>(m_meshs.size() - 1);
} }
DWORD DirectX9Renderer::GetWidth()
{
return m_width;
}
DWORD DirectX9Renderer::GetHeight()
{
return m_height;
}
void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{ {
halDesc->dcmColorModel = D3DCOLORMODEL::RGB; halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -253,6 +247,8 @@ void DirectX9Renderer::EnableTransparency()
void DirectX9Renderer::SubmitDraw( void DirectX9Renderer::SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) )
@ -261,17 +257,46 @@ void DirectX9Renderer::SubmitDraw(
if (appearance.textureId != NO_TEXTURE_ID) { if (appearance.textureId != NO_TEXTURE_ID) {
texture = m_textures[appearance.textureId].dxTexture; 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 DirectX9Renderer::FinalizeFrame()
{ {
HRESULT hr = Actual_FinalizeFrame(m_renderedImage->pixels, m_renderedImage->pitch); return DD_OK;
if (hr != DD_OK) { }
return hr;
} void DirectX9Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
// Composite onto SDL backbuffer m_width = width;
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); m_height = height;
return hr; 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);
} }

View File

@ -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_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); 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; SDL_Window* window = DDWindow;
bool testWindow = false; bool testWindow = false;
if (!window) { 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; testWindow = true;
} }
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GLContext context = SDL_GL_CreateContext(window); SDL_GLContext context = SDL_GL_CreateContext(window);
if (!context) { if (!context) {
SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError());
if (testWindow) { if (testWindow) {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
} }
@ -33,18 +40,16 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
} }
if (!SDL_GL_MakeCurrent(window, context)) { if (!SDL_GL_MakeCurrent(window, context)) {
return nullptr; SDL_Log("SDL_GL_MakeCurrent: %s", SDL_GetError());
}
GLenum err = glewInit();
if (err != GLEW_OK) {
if (testWindow) { if (testWindow) {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
} }
return nullptr; return nullptr;
} }
if (!GLEW_EXT_framebuffer_object) { GLenum err = glewInit();
if (err != GLEW_OK) {
SDL_Log("glewInit: %s", glewGetErrorString(err));
if (testWindow) { if (testWindow) {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
} }
@ -53,65 +58,37 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CCW); glFrontFace(GL_CW);
// 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);
if (testWindow) { if (testWindow) {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
} }
return new OpenGL1Renderer(width, height, context, fbo, colorTex, depthRb); return new OpenGL1Renderer(width, height, context);
} }
OpenGL1Renderer::OpenGL1Renderer( OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context) : m_context(context)
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)
{ {
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; m_useVBOs = GLEW_ARB_vertex_buffer_object;
} }
OpenGL1Renderer::~OpenGL1Renderer() OpenGL1Renderer::~OpenGL1Renderer()
{ {
SDL_DestroySurface(m_renderedImage); 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) void OpenGL1Renderer::PushLights(const SceneLight* lightsArray, size_t count)
{ {
if (count > 8) {
SDL_Log("Unsupported number of lights (%d)", static_cast<int>(count));
count = 8;
}
m_lights.assign(lightsArray, lightsArray + count); 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) void OpenGL1Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{ {
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
m_projection[1][1] *= -1.0f; // OpenGL is upside down
} }
struct TextureDestroyContextGL { struct TextureDestroyContextGL {
@ -161,14 +137,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &tex.glTextureId); glGenTextures(1, &tex.glTextureId);
glBindTexture(GL_TEXTURE_2D, 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) { if (!surf) {
return NO_TEXTURE_ID; 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); 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; tex.version = texture->m_version;
} }
@ -180,14 +154,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &texId); glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, 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) { if (!surf) {
return NO_TEXTURE_ID; 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); 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) { for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i]; auto& tex = m_textures[i];
@ -260,7 +232,7 @@ GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs)
glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals);
glBufferData(GL_ARRAY_BUFFER, cache.normals.size() * sizeof(D3DVECTOR), cache.normals.data(), GL_STATIC_DRAW); 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); glGenBuffers(1, &cache.vboTexcoords);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords);
glBufferData( glBufferData(
@ -337,16 +309,6 @@ Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGr
return (Uint32) (m_meshs.size() - 1); 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) void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{ {
halDesc->dcmColorModel = D3DCOLORMODEL::RGB; halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -362,14 +324,12 @@ void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
const char* OpenGL1Renderer::GetName() const char* OpenGL1Renderer::GetName()
{ {
return "OpenGL 1.2 HAL"; return "OpenGL 1.1 HAL";
} }
HRESULT OpenGL1Renderer::BeginFrame() HRESULT OpenGL1Renderer::BeginFrame()
{ {
SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true;
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(0, 0, m_width, m_height);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -378,16 +338,12 @@ HRESULT OpenGL1Renderer::BeginFrame()
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); 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 // Disable all lights and reset global ambient
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
glDisable(GL_LIGHT0 + i); glDisable(GL_LIGHT0 + i);
} }
const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient);
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
// Setup lights // Setup lights
@ -462,15 +418,14 @@ void OpenGL1Renderer::EnableTransparency()
void OpenGL1Renderer::SubmitDraw( void OpenGL1Renderer::SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) )
{ {
auto& mesh = m_meshs[meshId]; auto& mesh = m_meshs[meshId];
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf(&modelViewMatrix[0][0]); glLoadMatrixf(&modelViewMatrix[0][0]);
glEnable(GL_NORMALIZE); glEnable(GL_NORMALIZE);
@ -496,6 +451,8 @@ void OpenGL1Renderer::SubmitDraw(
// Bind texture if present // Bind texture if present
if (appearance.textureId != NO_TEXTURE_ID) { 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]; auto& tex = m_textures[appearance.textureId];
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId); glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
@ -542,11 +499,130 @@ void OpenGL1Renderer::SubmitDraw(
HRESULT OpenGL1Renderer::FinalizeFrame() 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; 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<int>(m_viewportTransform.offsetX),
static_cast<int>(m_viewportTransform.offsetY),
static_cast<int>(target->w * m_viewportTransform.scale),
static_cast<int>(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);
}

View File

@ -41,6 +41,8 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
testWindow = true; testWindow = true;
} }
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GLContext context = SDL_GL_CreateContext(window); SDL_GLContext context = SDL_GL_CreateContext(window);
if (!context) { if (!context) {
if (testWindow) { if (testWindow) {
@ -50,51 +52,16 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
} }
if (!SDL_GL_MakeCurrent(window, context)) { if (!SDL_GL_MakeCurrent(window, context)) {
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr; return nullptr;
} }
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CCW); glFrontFace(GL_CW);
// 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);
const char* vertexShaderSource = R"( const char* vertexShaderSource = R"(
attribute vec3 a_position; attribute vec3 a_position;
@ -183,6 +150,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
if (u_useTexture != 0) { if (u_useTexture != 0) {
vec4 texel = texture2D(u_texture, v_texCoord); vec4 texel = texture2D(u_texture, v_texCoord);
finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0); finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0);
finalColor.a = texel.a;
} }
gl_FragColor = finalColor; gl_FragColor = finalColor;
@ -206,31 +174,23 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
} }
return new OpenGLES2Renderer(width, height, context, fbo, colorTex, depthRb, shaderProgram); return new OpenGLES2Renderer(width, height, context, shaderProgram);
} }
OpenGLES2Renderer::OpenGLES2Renderer( OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram)
DWORD width, : m_context(context), m_shaderProgram(shaderProgram)
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)
{ {
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() OpenGLES2Renderer::~OpenGLES2Renderer()
{ {
SDL_DestroySurface(m_renderedImage); SDL_DestroySurface(m_renderedImage);
glDeleteFramebuffers(1, &m_fbo);
glDeleteRenderbuffers(1, &m_depthRb);
glDeleteProgram(m_shaderProgram); glDeleteProgram(m_shaderProgram);
glDeleteTextures(1, &m_colorTex);
} }
void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count) 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) void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{ {
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
m_projection[1][1] *= -1.0f; // OpenGL is upside down
} }
struct TextureDestroyContextGLS2 { struct TextureDestroyContextGLS2 {
@ -289,14 +248,12 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &tex.glTextureId); glGenTextures(1, &tex.glTextureId);
glBindTexture(GL_TEXTURE_2D, 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) { if (!surf) {
return NO_TEXTURE_ID; return NO_TEXTURE_ID;
} }
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 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); 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; tex.version = texture->m_version;
} }
@ -308,14 +265,11 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &texId); glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, 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) { if (!surf) {
return NO_TEXTURE_ID; return NO_TEXTURE_ID;
} }
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 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) { for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i]; auto& tex = m_textures[i];
@ -323,12 +277,15 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
tex.texture = texture; tex.texture = texture;
tex.version = texture->m_version; tex.version = texture->m_version;
tex.glTextureId = texId; tex.glTextureId = texId;
tex.width = surf->w;
tex.height = surf->h;
AddTextureDestroyCallback(i, texture); AddTextureDestroyCallback(i, texture);
return i; 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); AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture);
return (Uint32) (m_textures.size() - 1); return (Uint32) (m_textures.size() - 1);
} }
@ -366,7 +323,6 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup)
return v.texCoord; return v.texCoord;
}); });
} }
std::vector<D3DVECTOR> positions(vertices.size()); std::vector<D3DVECTOR> positions(vertices.size());
std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) {
return v.position; return v.position;
@ -451,16 +407,6 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh
return (Uint32) (m_meshs.size() - 1); 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) void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{ {
halDesc->dcmColorModel = D3DCOLORMODEL::RGB; halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -490,9 +436,7 @@ const char* OpenGLES2Renderer::GetName()
HRESULT OpenGLES2Renderer::BeginFrame() HRESULT OpenGLES2Renderer::BeginFrame()
{ {
SDL_GL_MakeCurrent(DDWindow, m_context); m_dirty = true;
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(0, 0, m_width, m_height);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -500,9 +444,6 @@ HRESULT OpenGLES2Renderer::BeginFrame()
glUseProgram(m_shaderProgram); glUseProgram(m_shaderProgram);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SceneLightGLES2 lightData[3]; SceneLightGLES2 lightData[3];
int lightCount = std::min(static_cast<int>(m_lights.size()), 3); int lightCount = std::min(static_cast<int>(m_lights.size()), 3);
@ -531,7 +472,6 @@ HRESULT OpenGLES2Renderer::BeginFrame()
glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()), 1, lightData[i].direction); glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()), 1, lightData[i].direction);
} }
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), lightCount); glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), lightCount);
return DD_OK; return DD_OK;
} }
@ -545,6 +485,8 @@ void OpenGLES2Renderer::EnableTransparency()
void OpenGLES2Renderer::SubmitDraw( void OpenGLES2Renderer::SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) )
@ -570,6 +512,8 @@ void OpenGLES2Renderer::SubmitDraw(
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId); glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId);
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); 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 { else {
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 0); glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 0);
@ -606,11 +550,168 @@ HRESULT OpenGLES2Renderer::FinalizeFrame()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(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; 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<float>(dstRect.x);
float y1 = static_cast<float>(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<int>(m_viewportTransform.offsetX),
static_cast<int>(m_viewportTransform.offsetY),
static_cast<int>(target->w * m_viewportTransform.scale),
static_cast<int>(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);
}

View File

@ -7,6 +7,7 @@
#include "miniwin.h" #include "miniwin.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <cmath>
#include <cstddef> #include <cstddef>
struct ScopedSurface { struct ScopedSurface {
@ -91,7 +92,12 @@ struct ScopedShader {
void release() { ptr = nullptr; } 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 = const SDL_GPUShaderCreateInfo* vertexCreateInfo =
GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device)); GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device));
@ -141,8 +147,8 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
vertexInputState.num_vertex_attributes = SDL_arraysize(vertexAttrs); vertexInputState.num_vertex_attributes = SDL_arraysize(vertexAttrs);
SDL_GPUColorTargetDescription colorTargets = {}; SDL_GPUColorTargetDescription colorTargets = {};
colorTargets.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; colorTargets.format = SDL_GetGPUSwapchainTextureFormat(device, window);
if (depthWrite) { if (depthTest && depthWrite) {
colorTargets.blend_state.enable_blend = false; colorTargets.blend_state.enable_blend = false;
} }
else { else {
@ -170,7 +176,7 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
pipelineCreateInfo.rasterizer_state = rasterizerState; pipelineCreateInfo.rasterizer_state = rasterizerState;
pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_GREATER; pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_GREATER;
pipelineCreateInfo.depth_stencil_state.write_mask = 0xff; 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_depth_write = depthWrite;
pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false; pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false;
pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets; 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.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT;
pipelineCreateInfo.target_info.has_depth_stencil_target = true; pipelineCreateInfo.target_info.has_depth_stencil_target = true;
SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo); return SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo);
return pipeline;
} }
Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
{ {
ScopedDevice device{SDL_CreateGPUDevice( ScopedDevice device{SDL_CreateGPUDevice(
SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL,
#ifdef DEBUG
true, true,
#else
false,
#endif
nullptr nullptr
)}; )};
if (!device.ptr) { if (!device.ptr) {
@ -195,63 +203,63 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
return nullptr; 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) { if (!opaquePipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline"); SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline");
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr; return nullptr;
} }
ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, false)}; ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, false)};
if (!transparentPipeline.ptr) { if (!transparentPipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline"); SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline");
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr; return nullptr;
} }
SDL_GPUTextureCreateInfo textureInfo = {}; ScopedPipeline uiPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, false, false)};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D; if (!uiPipeline.ptr) {
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for uiPipeline");
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; if (testWindow) {
textureInfo.width = width; SDL_DestroyWindow(window);
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()
);
return nullptr; return nullptr;
} }
// Setup texture CPU-to-GPU transfer // Setup texture CPU-to-GPU transfer
SDL_GPUTransferBufferCreateInfo uploadBufferInfo = {}; SDL_GPUTransferBufferCreateInfo uploadBufferInfo = {};
uploadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; 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)}; ScopedTransferBuffer uploadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &uploadBufferInfo)};
if (!uploadBuffer.ptr) { if (!uploadBuffer.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer filed for upload buffer (%s)", SDL_GetError()); SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer filed for upload buffer (%s)", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr; return nullptr;
} }
@ -265,31 +273,54 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)}; ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)};
if (!sampler.ptr) { if (!sampler.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr; 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( auto renderer = new Direct3DRMSDL3GPURenderer(
width, width,
height, height,
device.ptr, device.ptr,
opaquePipeline.ptr, opaquePipeline.ptr,
transparentPipeline.ptr, transparentPipeline.ptr,
transferTexture.ptr, uiPipeline.ptr,
depthTexture.ptr,
sampler.ptr, sampler.ptr,
uiSampler.ptr,
uploadBuffer.ptr, uploadBuffer.ptr,
downloadBuffer.ptr uploadBufferSize
); );
// Release resources so they don't get cleaned up // Release resources so they don't get cleaned up
device.release(); device.release();
opaquePipeline.release(); opaquePipeline.release();
transparentPipeline.release(); transparentPipeline.release();
transferTexture.release(); uiPipeline.release();
depthTexture.release();
sampler.release(); sampler.release();
uiSampler.release();
uploadBuffer.release(); uploadBuffer.release();
downloadBuffer.release();
return renderer; return renderer;
} }
@ -300,17 +331,21 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
SDL_GPUDevice* device, SDL_GPUDevice* device,
SDL_GPUGraphicsPipeline* opaquePipeline, SDL_GPUGraphicsPipeline* opaquePipeline,
SDL_GPUGraphicsPipeline* transparentPipeline, SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture, SDL_GPUGraphicsPipeline* uiPipeline,
SDL_GPUTexture* depthTexture,
SDL_GPUSampler* sampler, SDL_GPUSampler* sampler,
SDL_GPUSampler* uiSampler,
SDL_GPUTransferBuffer* uploadBuffer, SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer int uploadBufferSize
) )
: m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline), : m_device(device), m_opaquePipeline(opaquePipeline), m_transparentPipeline(transparentPipeline),
m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture), m_uiPipeline(uiPipeline), m_sampler(sampler), m_uiSampler(uiSampler), m_uploadBuffer(uploadBuffer),
m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer) 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) { if (!dummySurface) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError()); SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError());
return; return;
@ -324,35 +359,67 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
SDL_UnlockSurface(dummySurface); SDL_UnlockSurface(dummySurface);
m_dummyTexture = CreateTextureFromSurface(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); 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() 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) { if (m_uploadBuffer) {
SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer); SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer);
} }
SDL_ReleaseGPUSampler(m_device, m_sampler); SDL_ReleaseGPUSampler(m_device, m_sampler);
SDL_ReleaseGPUTexture(m_device, m_dummyTexture); SDL_ReleaseGPUSampler(m_device, m_uiSampler);
SDL_ReleaseGPUTexture(m_device, m_depthTexture); if (m_dummyTexture) {
SDL_ReleaseGPUTexture(m_device, m_transferTexture); 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_opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline); SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_uiPipeline);
if (m_uploadFence) { if (m_uploadFence) {
SDL_ReleaseGPUFence(m_device, m_uploadFence); SDL_ReleaseGPUFence(m_device, m_uploadFence);
} }
SDL_DestroyGPUDevice(m_device); 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) { if (count > 3) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Unsupported number of lights (%d)", static_cast<int>(count)); SDL_LogError(LOG_CATEGORY_MINIWIN, "Unsupported number of lights (%d)", static_cast<int>(count));
count = 3; count = 3;
} }
int lightCount = std::min(static_cast<int>(count), 3); int lightCount = std::min(static_cast<int>(count), 3);
memcpy(&m_fragmentShadingData.lights, vertices, sizeof(SceneLight) * lightCount); memcpy(&m_fragmentShadingData.lights, lights, sizeof(SceneLight) * lightCount);
m_fragmentShadingData.lightCount = lightCount; m_fragmentShadingData.lightCount = lightCount;
} }
@ -364,7 +431,7 @@ void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D
{ {
m_front = front; m_front = front;
m_back = back; m_back = back;
memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D)); memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
} }
void Direct3DRMSDL3GPURenderer::WaitForPendingUpload() void Direct3DRMSDL3GPURenderer::WaitForPendingUpload()
@ -405,7 +472,7 @@ void Direct3DRMSDL3GPURenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRM
SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* surface) 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) { if (!surf.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError()); SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError());
return nullptr; return nullptr;
@ -607,6 +674,7 @@ void Direct3DRMSDL3GPURenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMes
auto* ctx = static_cast<SDLMeshDestroyContext*>(arg); auto* ctx = static_cast<SDLMeshDestroyContext*>(arg);
auto& cache = ctx->renderer->m_meshs[ctx->id]; auto& cache = ctx->renderer->m_meshs[ctx->id];
SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer); SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer);
SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.indexBuffer);
cache.meshGroup = nullptr; cache.meshGroup = nullptr;
delete ctx; delete ctx;
}, },
@ -621,6 +689,7 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro
if (cache.meshGroup == meshGroup) { if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) { if (cache.version != meshGroup->version) {
SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer); SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer);
SDL_ReleaseGPUBuffer(m_device, cache.indexBuffer);
cache = std::move(UploadMesh(*meshGroup)); cache = std::move(UploadMesh(*meshGroup));
} }
return i; return i;
@ -643,16 +712,6 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro
return (Uint32) (m_meshs.size() - 1); 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) void Direct3DRMSDL3GPURenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{ {
halDesc->dcmColorModel = D3DCOLORMODEL::RGB; halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -708,32 +767,45 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
return m_uploadBuffer; return m_uploadBuffer;
} }
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame() void Direct3DRMSDL3GPURenderer::StartRenderPass(float r, float g, float b, bool clear)
{ {
if (!DDBackBuffer) { m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
return DDERR_GENERIC; if (!m_cmdbuf) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_AcquireGPUCommandBuffer in StartRenderPass failed (%s)",
SDL_GetError()
);
return;
} }
// Clear color and depth targets // Clear color and depth targets
SDL_GPUColorTargetInfo colorTargetInfo = {}; SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture; colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.clear_color = {0, 0, 0, 0}; colorTargetInfo.clear_color = {r, g, b, 1.0f};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; colorTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {}; SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture; depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.clear_depth = 0.0f; 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; 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); 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); SDL_BindGPUGraphicsPipeline(m_renderPass, m_opaquePipeline);
memcpy(&m_uniforms.projection, m_projection, sizeof(D3DRMMATRIX4D));
return DD_OK; return DD_OK;
} }
@ -746,6 +818,8 @@ void Direct3DRMSDL3GPURenderer::EnableTransparency()
void Direct3DRMSDL3GPURenderer::SubmitDraw( void Direct3DRMSDL3GPURenderer::SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) )
@ -774,15 +848,210 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw(
HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame() HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
{ {
SDL_EndGPURenderPass(m_renderPass); return DD_OK;
m_renderPass = nullptr; }
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<float>(dstRect.x) * scale + offsetX;
float y = static_cast<float>(dstRect.y) * scale + offsetY;
float w = static_cast<float>(dstRect.w) * scale;
float h = static_cast<float>(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<DirectDrawSurfaceImpl*>(tex.texture->m_surface);
float scaleX = static_cast<float>(dstRect.w) / srcRect.w;
float scaleY = static_cast<float>(dstRect.h) / srcRect.h;
SDL_Rect expandedDstRect = {
static_cast<int>(std::round(dstRect.x - srcRect.x * scaleX)),
static_cast<int>(std::round(dstRect.y - srcRect.y * scaleY)),
static_cast<int>(std::round(static_cast<float>(surface->m_surface->w) * scaleX)),
static_cast<int>(std::round(static_cast<float>(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<int>(std::round(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX));
scissor.y = static_cast<int>(std::round(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY));
scissor.w = static_cast<int>(std::round(dstRect.w * m_viewportTransform.scale));
scissor.h = static_cast<int>(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<int>(m_viewportTransform.offsetX);
const int offsetY = static_cast<int>(m_viewportTransform.offsetY);
const int width = m_width - offsetX * 2;
const int height = m_height - offsetY * 2;
// Download rendered image
SDL_GPUTextureRegion region = {}; SDL_GPUTextureRegion region = {};
region.texture = m_transferTexture; region.texture = m_transferTexture;
region.w = m_width; region.x = offsetX;
region.h = m_height; region.y = offsetY;
region.w = width;
region.h = height;
region.d = 1; region.d = 1;
SDL_GPUTextureTransferInfo transferInfo = {}; SDL_GPUTextureTransferInfo transferInfo = {};
transferInfo.transfer_buffer = m_downloadBuffer; transferInfo.transfer_buffer = m_downloadBuffer;
@ -792,27 +1061,24 @@ HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
WaitForPendingUpload(); WaitForPendingUpload();
// Render the frame
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf); SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf);
m_cmdbuf = nullptr; 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); SDL_ReleaseGPUFence(m_device, fence);
if (!success) {
return DDERR_GENERIC;
}
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false); void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false);
if (!downloadedData) { if (!downloadedData) {
return DDERR_GENERIC; return;
} }
SDL_Surface* renderedImage = SDL_Surface* renderedImage =
SDL_CreateSurfaceFrom(m_width, m_height, SDL_PIXELFORMAT_ABGR8888, downloadedData, m_width * 4); SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_ARGB8888, downloadedData, width * 4);
SDL_BlitSurface(renderedImage, nullptr, DDBackBuffer, nullptr);
SDL_BlitSurfaceScaled(renderedImage, nullptr, target, nullptr, SDL_SCALEMODE_NEAREST);
SDL_DestroySurface(renderedImage); SDL_DestroySurface(renderedImage);
SDL_UnmapGPUTransferBuffer(m_device, m_downloadBuffer); SDL_UnmapGPUTransferBuffer(m_device, m_downloadBuffer);
return DD_OK;
} }

View File

@ -10,9 +10,9 @@
// DXIL only makes sense on Windows platforms // DXIL only makes sense on Windows platforms
#if defined(SDL_PLATFORM_WINDOWS) #if defined(SDL_PLATFORM_WINDOWS)
static const Uint8 SolidColor_frag_dxil[6640] = { static const Uint8 SolidColor_frag_dxil[6648] = {
0x44, 0x58, 0x42, 0x43, 0x91, 0x24, 0xbe, 0xd8, 0x43, 0x8d, 0x7f, 0xf4, 0x71, 0x2b, 0x59, 0x98, 0x44, 0x58, 0x42, 0x43, 0xd8, 0xfe, 0x4c, 0xec, 0x17, 0x1b, 0x52, 0xee, 0xf7, 0xc8, 0x8d, 0xcf,
0x2d, 0x7f, 0x8d, 0xac, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0xeb, 0x0f, 0x40, 0x5f, 0x0e, 0x75, 0xec, 0xd9, 0x61, 0x1b, 0x68, 0x81, 0x54, 0xd3, 0xf4, 0x48,
0x44, 0x58, 0x49, 0x4c, 0x38, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4e, 0x03, 0x00, 0x00, 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, 0x20, 0x0d, 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, 0x45, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0x18, 0x4d, 0x20,
0x8f, 0x0d, 0x89, 0x7c, 0x6c, 0x48, 0xe4, 0x33, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6e, 0x06, 0x23, 0x14, 0xf9, 0x18, 0xa1, 0xc8, 0xc7, 0x08, 0x45, 0x3e, 0x23, 0x06, 0x07, 0x00, 0x82,
0xd8, 0xc5, 0xa0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f,
0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f, 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf8, 0x46, 0x5e, 0x0c, 0x6d,
0x00, 0x82, 0x60, 0xe0, 0xf8, 0x06, 0x5e, 0x0c, 0x6e, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07,
0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, 0x0c, 0x70, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06,
0x0c, 0x70, 0x31, 0x4b, 0x10, 0x0d, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, 0x4e, 0x78, 0xec, 0xc5, 0x10, 0x17, 0xb3, 0x04, 0xd1, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c,
0x64, 0xf0, 0x0c, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x54, 0x0c, 0x06, 0x64, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c, 0x54, 0x0c, 0x1a,
0xe7, 0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb3, 0x31, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x64, 0x0b, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e,
0x1e, 0x7c, 0xe1, 0x1b, 0xbe, 0xd1, 0x1a, 0xc2, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe7, 0xb5, 0x41, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0xf1,
0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb2, 0x11, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x1e, 0x1a, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e, 0xb4,
0x7c, 0xe1, 0x1b, 0xbe, 0x11, 0x1b, 0x6a, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc8, 0x79, 0x21, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0x31, 0x1b,
0xf0, 0xc5, 0x6f, 0xf8, 0xc6, 0x6c, 0x98, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 #endif
// MSL only makes sense on Apple platforms // MSL only makes sense on Apple platforms
#if defined(SDL_PLATFORM_APPLE) #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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x31, 0x36, 0x31, 0x20, 0x3d,
0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, 0x20, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28,
0x6d, 0x70, 0x6c, 0x65, 0x28, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76,
0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x29, 0x3b, 0x0a, 0x20,
0x31, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c,
0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x6d, 0x70,
0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x28, 0x5f, 0x31, 0x36, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x5f, 0x31, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x2c, 0x20, 0x5f, 0x31, 0x36,
0x35, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x31, 0x2e, 0x77, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x67, 0x65, 0x74, 0x30, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x5f, 0x31, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34,
0x36, 0x34, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x28, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20,
0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f,
0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77, 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x30, 0x20, 0x3d,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67,
0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 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 #endif
static const Uint8 SolidColor_frag_spirv[4492] = { static const Uint8 SolidColor_frag_spirv[4616] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xab, 0x00, 0x00, 0x00, 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, 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, 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, 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, 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, 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, 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, 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, 0x9d, 0x00, 0x00, 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, 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, 0x9f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x9f, 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, 0xa1, 0x00, 0x00, 0x00, 0xa0, 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, 0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00,
0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 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, 0xa2, 0x00, 0x00, 0x00, 0xa1, 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, 0xa3, 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, 0xa2, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00,
0x97, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00,
0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x9d, 0x00, 0x00, 0x00,
0xa7, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00,
0xa9, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00,
0xaa, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 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,
}; };

View File

@ -72,8 +72,11 @@ FS_Output main(FS_Input input)
if (UseTexture != 0) { if (UseTexture != 0) {
float4 texel = Texture.Sample(Sampler, input.TexCoord); float4 texel = Texture.Sample(Sampler, input.TexCoord);
finalColor = saturate(texel.rgb * finalColor); 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; output.Depth = input.Position.w;
return output; return output;
} }

View File

@ -23,9 +23,22 @@
#include <wasm_simd128.h> #include <wasm_simd128.h>
#endif #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) void Direct3DRMSoftwareRenderer::PushLights(const SceneLight* lights, size_t count)
@ -354,8 +367,8 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
c2 = ApplyLighting(v2.position, v2.normal, appearance); c2 = ApplyLighting(v2.position, v2.normal, appearance);
} }
Uint8* pixels = (Uint8*) DDBackBuffer->pixels; Uint8* pixels = (Uint8*) m_renderedImage->pixels;
int pitch = DDBackBuffer->pitch; int pitch = m_renderedImage->pitch;
VertexXY verts[3] = { VertexXY verts[3] = {
{p0.x, p0.y, p0.z, p0.w, c0, v0.texCoord.u, v0.texCoord.v}, {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) { if (texRef.version != texture->m_version) {
// Update animated textures // Update animated textures
SDL_DestroySurface(texRef.cached); 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); SDL_LockSurface(texRef.cached);
texRef.version = texture->m_version; 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); SDL_LockSurface(convertedRender);
// Reuse freed slot // Reuse freed slot
@ -651,16 +664,6 @@ Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGr
return (Uint32) (m_meshs.size() - 1); 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) void Direct3DRMSoftwareRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{ {
memset(halDesc, 0, sizeof(D3DDEVICEDESC)); memset(halDesc, 0, sizeof(D3DDEVICEDESC));
@ -681,13 +684,13 @@ const char* Direct3DRMSoftwareRenderer::GetName()
HRESULT Direct3DRMSoftwareRenderer::BeginFrame() HRESULT Direct3DRMSoftwareRenderer::BeginFrame()
{ {
if (!DDBackBuffer || !SDL_LockSurface(DDBackBuffer)) { if (!m_renderedImage || !SDL_LockSurface(m_renderedImage)) {
return DDERR_GENERIC; return DDERR_GENERIC;
} }
ClearZBuffer(); ClearZBuffer();
m_format = SDL_GetPixelFormatDetails(DDBackBuffer->format); m_format = SDL_GetPixelFormatDetails(m_renderedImage->format);
m_palette = SDL_GetSurfacePalette(DDBackBuffer); m_palette = SDL_GetSurfacePalette(m_renderedImage);
m_bytesPerPixel = m_format->bits_per_pixel / 8; m_bytesPerPixel = m_format->bits_per_pixel / 8;
return DD_OK; return DD_OK;
@ -700,6 +703,8 @@ void Direct3DRMSoftwareRenderer::EnableTransparency()
void Direct3DRMSoftwareRenderer::SubmitDraw( void Direct3DRMSoftwareRenderer::SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) )
@ -731,7 +736,84 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
HRESULT Direct3DRMSoftwareRenderer::FinalizeFrame() HRESULT Direct3DRMSoftwareRenderer::FinalizeFrame()
{ {
SDL_UnlockSurface(DDBackBuffer); SDL_UnlockSurface(m_renderedImage);
return DD_OK; return DD_OK;
} }
void Direct3DRMSoftwareRenderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
m_viewportTransform = viewportTransform;
float aspect = static_cast<float>(width) / height;
float virtualAspect = static_cast<float>(m_virtualWidth) / m_virtualHeight;
// Cap to virtual canvase for performance
if (aspect > virtualAspect) {
m_height = std::min(height, m_virtualHeight);
m_width = static_cast<int>(m_height * aspect);
}
else {
m_width = std::min(width, m_virtualWidth);
m_height = static_cast<int>(m_width / aspect);
}
m_viewportTransform.scale =
std::min(static_cast<float>(m_width) / m_virtualWidth, static_cast<float>(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<int>(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX),
static_cast<int>(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY),
static_cast<int>(dstRect.w * m_viewportTransform.scale),
static_cast<int>(dstRect.h * m_viewportTransform.scale),
};
SDL_BlitSurfaceScaled(surface, &srcRect, m_renderedImage, &centeredRect, SDL_SCALEMODE_LINEAR);
SDL_LockSurface(surface);
}
void Direct3DRMSoftwareRenderer::Download(SDL_Surface* target)
{
SDL_Rect srcRect = {
static_cast<int>(m_viewportTransform.offsetX),
static_cast<int>(m_viewportTransform.offsetY),
static_cast<int>(m_virtualWidth * m_viewportTransform.scale),
static_cast<int>(m_virtualHeight * m_viewportTransform.scale),
};
SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, target, nullptr, SDL_SCALEMODE_LINEAR);
}

View File

@ -127,7 +127,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromD3D(
{ {
auto renderer = static_cast<Direct3DRMRenderer*>(d3dDevice); auto renderer = static_cast<Direct3DRMRenderer*>(d3dDevice);
*outDevice = static_cast<IDirect3DRMDevice2*>( *outDevice = static_cast<IDirect3DRMDevice2*>(
new Direct3DRMDevice2Impl(renderer->GetWidth(), renderer->GetHeight(), renderer) new Direct3DRMDevice2Impl(renderer->GetVirtualWidth(), renderer->GetVirtualHeight(), renderer)
); );
return DD_OK; return DD_OK;
} }
@ -143,26 +143,25 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
DDSDesc.dwSize = sizeof(DDSURFACEDESC); DDSDesc.dwSize = sizeof(DDSURFACEDESC);
surface->GetSurfaceDesc(&DDSDesc); surface->GetSurfaceDesc(&DDSDesc);
Direct3DRMRenderer* renderer;
if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { 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) { 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 #ifdef USE_OPENGLES2
else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { 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 #endif
#ifdef USE_OPENGL1 #ifdef USE_OPENGL1
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { 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 #endif
#ifdef _WIN32 #ifdef _WIN32
else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { 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 #endif
else { else {
@ -170,7 +169,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
return E_NOINTERFACE; return E_NOINTERFACE;
} }
*outDevice = *outDevice =
static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, renderer)); static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, DDRenderer));
return DD_OK; return DD_OK;
} }
@ -181,9 +180,8 @@ HRESULT Direct3DRMImpl::CreateTexture(D3DRMIMAGE* image, IDirect3DRMTexture2** o
} }
HRESULT Direct3DRMImpl::CreateTextureFromSurface(LPDIRECTDRAWSURFACE surface, IDirect3DRMTexture2** outTexture) HRESULT Direct3DRMImpl::CreateTextureFromSurface(LPDIRECTDRAWSURFACE surface, IDirect3DRMTexture2** outTexture)
{ {
*outTexture = static_cast<IDirect3DRMTexture2*>(new Direct3DRMTextureImpl(surface)); *outTexture = static_cast<IDirect3DRMTexture2*>(new Direct3DRMTextureImpl(surface, true));
return DD_OK; return DD_OK;
} }

View File

@ -11,8 +11,9 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
Direct3DRMDevice2Impl::Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer) 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() Direct3DRMDevice2Impl::~Direct3DRMDevice2Impl()
@ -43,16 +44,6 @@ HRESULT Direct3DRMDevice2Impl::QueryInterface(const GUID& riid, void** ppvObject
return E_NOINTERFACE; return E_NOINTERFACE;
} }
DWORD Direct3DRMDevice2Impl::GetWidth()
{
return m_width;
}
DWORD Direct3DRMDevice2Impl::GetHeight()
{
return m_height;
}
HRESULT Direct3DRMDevice2Impl::SetBufferCount(int count) HRESULT Direct3DRMDevice2Impl::SetBufferCount(int count)
{ {
MINIWIN_NOT_IMPLEMENTED(); MINIWIN_NOT_IMPLEMENTED();
@ -133,7 +124,9 @@ HRESULT Direct3DRMDevice2Impl::Update()
HRESULT Direct3DRMDevice2Impl::AddViewport(IDirect3DRMViewport* viewport) HRESULT Direct3DRMDevice2Impl::AddViewport(IDirect3DRMViewport* viewport)
{ {
return m_viewports->AddElement(viewport); HRESULT status = m_viewports->AddElement(viewport);
Resize();
return status;
} }
HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewportArray) HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewportArray)
@ -143,7 +136,53 @@ HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewpor
return DD_OK; 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<Direct3DRMViewportImpl*>(viewport)->UpdateProjectionMatrix();
}
}
bool Direct3DRMDevice2Impl::ConvertEventToRenderCoordinates(SDL_Event* event) 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<Sint32>(x);
event->motion.y = static_cast<Sint32>(y);
break;
} break;
}
return true;
} }

View File

@ -40,10 +40,10 @@ HRESULT Direct3DRMMeshImpl::Clone(int flags, GUID iid, void** object)
} }
HRESULT Direct3DRMMeshImpl::AddGroup( HRESULT Direct3DRMMeshImpl::AddGroup(
int vertexCount, unsigned int vertexCount,
int faceCount, unsigned int faceCount,
int vertexPerFace, unsigned int vertexPerFace,
DWORD* faceBuffer, unsigned int* faceBuffer,
D3DRMGROUPINDEX* groupIndex D3DRMGROUPINDEX* groupIndex
) )
{ {
@ -59,7 +59,7 @@ HRESULT Direct3DRMMeshImpl::AddGroup(
MeshGroup group; MeshGroup group;
group.vertexPerFace = vertexPerFace; group.vertexPerFace = vertexPerFace;
DWORD* src = faceBuffer; unsigned int* src = faceBuffer;
group.indices.assign(src, src + faceCount * vertexPerFace); group.indices.assign(src, src + faceCount * vertexPerFace);
m_groups.push_back(std::move(group)); m_groups.push_back(std::move(group));

View File

@ -6,8 +6,19 @@ Direct3DRMTextureImpl::Direct3DRMTextureImpl(D3DRMIMAGE* image)
MINIWIN_NOT_IMPLEMENTED(); 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) HRESULT Direct3DRMTextureImpl::QueryInterface(const GUID& riid, void** ppvObject)

View File

@ -15,7 +15,7 @@
#include <math.h> #include <math.h>
Direct3DRMViewportImpl::Direct3DRMViewportImpl(DWORD width, DWORD height, Direct3DRMRenderer* renderer) 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() 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 tanFovX = m_field;
float tanFovY = m_field / aspect; float tanFovY = m_field / aspect;
@ -268,18 +268,22 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3D
if (appearance.color.a != 255) { if (appearance.color.a != 255) {
m_deferredDraws.push_back( m_deferredDraws.push_back(
{m_renderer->GetMeshId(mesh, &meshGroup), {m_renderer->GetMeshId(mesh, &meshGroup),
{},
{}, {},
{}, {},
appearance, appearance,
CalculateDepth(m_viewProjectionwMatrix, worldMatrix)} CalculateDepth(m_viewProjectionwMatrix, worldMatrix)}
); );
memcpy(m_deferredDraws.back().modelViewMatrix, modelViewMatrix, sizeof(D3DRMMATRIX4D)); memcpy(m_deferredDraws.back().modelViewMatrix, modelViewMatrix, sizeof(D3DRMMATRIX4D));
memcpy(m_deferredDraws.back().worldMatrix, worldMatrix, sizeof(D3DRMMATRIX4D));
memcpy(m_deferredDraws.back().normalMatrix, worldMatrixInvert, sizeof(Matrix3x3)); memcpy(m_deferredDraws.back().normalMatrix, worldMatrixInvert, sizeof(Matrix3x3));
} }
else { else {
m_renderer->SubmitDraw( m_renderer->SubmitDraw(
m_renderer->GetMeshId(mesh, &meshGroup), m_renderer->GetMeshId(mesh, &meshGroup),
modelViewMatrix, modelViewMatrix,
worldMatrix,
m_viewMatrix,
worldMatrixInvert, worldMatrixInvert,
appearance appearance
); );
@ -325,7 +329,14 @@ HRESULT Direct3DRMViewportImpl::RenderScene()
); );
m_renderer->EnableTransparency(); m_renderer->EnableTransparency();
for (const DeferredDrawCommand& cmd : m_deferredDraws) { 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(); m_deferredDraws.clear();
@ -349,16 +360,14 @@ HRESULT Direct3DRMViewportImpl::ForceUpdate(int x, int y, int w, int h)
HRESULT Direct3DRMViewportImpl::Clear() HRESULT Direct3DRMViewportImpl::Clear()
{ {
if (!DDBackBuffer) { if (!m_renderer) {
return DDERR_GENERIC; return DDERR_GENERIC;
} }
uint8_t r = (m_backgroundColor >> 16) & 0xFF; uint8_t r = (m_backgroundColor >> 16) & 0xFF;
uint8_t g = (m_backgroundColor >> 8) & 0xFF; uint8_t g = (m_backgroundColor >> 8) & 0xFF;
uint8_t b = m_backgroundColor & 0xFF; uint8_t b = m_backgroundColor & 0xFF;
m_renderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f);
Uint32 color = SDL_MapRGB(SDL_GetPixelFormatDetails(DDBackBuffer->format), nullptr, r, g, b);
SDL_FillSurfaceRect(DDBackBuffer, nullptr, color);
return DD_OK; return DD_OK;
} }
@ -427,13 +436,24 @@ HRESULT Direct3DRMViewportImpl::SetField(D3DVALUE field)
void Direct3DRMViewportImpl::UpdateProjectionMatrix() void Direct3DRMViewportImpl::UpdateProjectionMatrix()
{ {
float aspect = (float) m_width / (float) m_height; float virtualAspect = (float) m_virtualWidth / (float) m_virtualHeight;
float f = m_front / m_field; 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; float depth = m_back - m_front;
D3DRMMATRIX4D projection = { D3DRMMATRIX4D projection = {
{f, 0, 0, 0}, {f_h, 0, 0, 0},
{0, f * aspect, 0, 0}, {0, f_v, 0, 0},
{0, 0, m_back / depth, 1}, {0, 0, m_back / depth, 1},
{0, 0, (-m_front * m_back) / depth, 0}, {0, 0, (-m_front * m_back) / depth, 0},
}; };
@ -442,8 +462,8 @@ void Direct3DRMViewportImpl::UpdateProjectionMatrix()
m_renderer->SetProjection(projection, m_front, m_back); m_renderer->SetProjection(projection, m_front, m_back);
D3DRMMATRIX4D inverseProjectionMatrix = { D3DRMMATRIX4D inverseProjectionMatrix = {
{1.0f / f, 0, 0, 0}, {1.0f / f_h, 0, 0, 0},
{0, 1.0f / (f * aspect), 0, 0}, {0, 1.0f / f_v, 0, 0},
{0, 0, 0, depth / (-m_front * m_back)}, {0, 0, 0, depth / (-m_front * m_back)},
{0, 0, 1, -(m_back / depth) * 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; return m_field;
} }
DWORD Direct3DRMViewportImpl::GetWidth()
{
return m_width;
}
DWORD Direct3DRMViewportImpl::GetHeight()
{
return m_height;
}
inline float FromNDC(float ndcCoord, float dim) inline float FromNDC(float ndcCoord, float dim)
{ {
return (ndcCoord * 0.5f + 0.5f) * 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 ndcX = projVec.x * invW;
float ndcY = projVec.y * invW; float ndcY = projVec.y * invW;
screen->x = FromNDC(ndcX, m_width); screen->x = FromNDC(ndcX, m_virtualWidth);
screen->y = FromNDC(-ndcY, m_height); // Y-flip screen->y = FromNDC(-ndcY, m_virtualHeight); // Y-flip
// Undo perspective divide for screen-space coords // Undo perspective divide for screen-space coords
screen->x *= projVec.z; screen->x *= projVec.z;
@ -509,8 +519,8 @@ HRESULT Direct3DRMViewportImpl::InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D
float screenY = screen->y / screen->w; float screenY = screen->y / screen->w;
// Convert screen coordinates to NDC // Convert screen coordinates to NDC
float ndcX = screenX / m_width * 2.0f - 1.0f; float ndcX = screenX / m_virtualWidth * 2.0f - 1.0f;
float ndcY = 1.0f - (screenY / m_height) * 2.0f; float ndcY = 1.0f - (screenY / m_virtualHeight) * 2.0f;
D3DRMVECTOR4D clipVec = {ndcX * screen->w, ndcY * screen->w, screen->z, screen->w}; 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( Ray pickRay = BuildPickingRay(
x, x,
y, y,
m_width, m_virtualWidth,
m_height, m_virtualHeight,
m_camera, m_camera,
m_front, m_front,
m_back, m_back,
m_field, m_field,
(float) m_width / (float) m_height (float) m_virtualWidth / (float) m_virtualHeight
); );
std::function<void(IDirect3DRMFrame*, std::vector<IDirect3DRMFrame*>&)> recurse; std::function<void(IDirect3DRMFrame*, std::vector<IDirect3DRMFrame*>&)> recurse;

View File

@ -23,9 +23,7 @@
#include <cstring> #include <cstring>
SDL_Window* DDWindow; SDL_Window* DDWindow;
SDL_Surface* DDBackBuffer; Direct3DRMRenderer* DDRenderer;
FrameBufferImpl* DDFrameBuffer;
SDL_Renderer* DDRenderer;
HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject) HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject)
{ {
@ -82,13 +80,13 @@ HRESULT DirectDrawImpl::CreateSurface(
return DD_OK; return DD_OK;
} }
if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) == DDSCAPS_PRIMARYSURFACE) { if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) == DDSCAPS_PRIMARYSURFACE) {
DDFrameBuffer = new FrameBufferImpl(); m_frameBuffer = new FrameBufferImpl(m_virtualWidth, m_virtualHeight);
*lplpDDSurface = static_cast<IDirectDrawSurface*>(DDFrameBuffer); *lplpDDSurface = static_cast<IDirectDrawSurface*>(m_frameBuffer);
return DD_OK; return DD_OK;
} }
if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) == DDSCAPS_3DDEVICE) { if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) == DDSCAPS_3DDEVICE) {
DDFrameBuffer->AddRef(); m_frameBuffer->AddRef();
*lplpDDSurface = static_cast<IDirectDrawSurface*>(DDFrameBuffer); *lplpDDSurface = static_cast<IDirectDrawSurface*>(m_frameBuffer);
return DD_OK; return DD_OK;
} }
if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_TEXTURE) == DDSCAPS_TEXTURE) { if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_TEXTURE) == DDSCAPS_TEXTURE) {
@ -100,7 +98,7 @@ HRESULT DirectDrawImpl::CreateSurface(
#ifdef MINIWIN_PIXELFORMAT #ifdef MINIWIN_PIXELFORMAT
format = MINIWIN_PIXELFORMAT; format = MINIWIN_PIXELFORMAT;
#else #else
format = SDL_PIXELFORMAT_RGBA8888; format = SDL_PIXELFORMAT_RGBA32;
#endif #endif
if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) == DDSD_PIXELFORMAT) { if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) == DDSD_PIXELFORMAT) {
if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) == DDPF_RGB) { if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) == DDPF_RGB) {
@ -284,6 +282,12 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags)
{ {
SDL_Window* sdlWindow = reinterpret_cast<SDL_Window*>(hWnd); SDL_Window* sdlWindow = reinterpret_cast<SDL_Window*>(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) { if (sdlWindow) {
bool fullscreen; bool fullscreen;
if ((dwFlags & DDSCL_NORMAL) == DDSCL_NORMAL) { if ((dwFlags & DDSCL_NORMAL) == DDSCL_NORMAL) {
@ -302,15 +306,14 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags)
#endif #endif
} }
DDWindow = sdlWindow; 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; return DD_OK;
} }
HRESULT DirectDrawImpl::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) HRESULT DirectDrawImpl::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP)
{ {
m_virtualWidth = dwWidth;
m_virtualHeight = dwHeight;
return DD_OK; return DD_OK;
} }
@ -325,33 +328,32 @@ HRESULT DirectDrawImpl::CreateDevice(
DDSDesc.dwSize = sizeof(DDSURFACEDESC); DDSDesc.dwSize = sizeof(DDSURFACEDESC);
pBackBuffer->GetSurfaceDesc(&DDSDesc); pBackBuffer->GetSurfaceDesc(&DDSDesc);
Direct3DRMRenderer* renderer;
if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { 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 #ifdef USE_OPENGLES2
else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { 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 #endif
#ifdef USE_OPENGL1 #ifdef USE_OPENGL1
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { 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 #endif
#ifdef _WIN32 #ifdef _WIN32
else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { 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 #endif
else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { 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 { else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized");
return E_NOINTERFACE; return E_NOINTERFACE;
} }
*ppDirect3DDevice = static_cast<IDirect3DDevice2*>(renderer); *ppDirect3DDevice = static_cast<IDirect3DDevice2*>(DDRenderer);
return DD_OK; return DD_OK;
} }

View File

@ -1,3 +1,4 @@
#include "d3drmtexture_impl.h"
#include "ddpalette_impl.h" #include "ddpalette_impl.h"
#include "ddraw_impl.h" #include "ddraw_impl.h"
#include "ddsurface_impl.h" #include "ddsurface_impl.h"
@ -19,6 +20,9 @@ DirectDrawSurfaceImpl::~DirectDrawSurfaceImpl()
if (m_palette) { if (m_palette) {
m_palette->Release(); m_palette->Release();
} }
if (m_texture) {
m_texture->Release();
}
} }
// IUnknown interface // IUnknown interface
@ -69,6 +73,9 @@ HRESULT DirectDrawSurfaceImpl::Blt(
if (blitSource != other->m_surface) { if (blitSource != other->m_surface) {
SDL_DestroySurface(blitSource); SDL_DestroySurface(blitSource);
} }
if (m_texture) {
m_texture->Changed(TRUE, FALSE);
}
return DD_OK; return DD_OK;
} }
@ -203,6 +210,10 @@ HRESULT DirectDrawSurfaceImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
MINIWIN_NOT_IMPLEMENTED(); MINIWIN_NOT_IMPLEMENTED();
} }
if (m_texture) {
m_texture->Changed(FALSE, TRUE);
}
if (m_palette) { if (m_palette) {
m_palette->Release(); m_palette->Release();
} }
@ -216,5 +227,16 @@ HRESULT DirectDrawSurfaceImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
HRESULT DirectDrawSurfaceImpl::Unlock(LPVOID lpSurfaceData) HRESULT DirectDrawSurfaceImpl::Unlock(LPVOID lpSurfaceData)
{ {
SDL_UnlockSurface(m_surface); SDL_UnlockSurface(m_surface);
if (m_texture) {
m_texture->Changed(TRUE, FALSE);
}
return DD_OK; return DD_OK;
} }
IDirect3DRMTexture2* DirectDrawSurfaceImpl::ToTexture()
{
if (!m_texture) {
m_texture = new Direct3DRMTextureImpl(this, false);
}
return m_texture;
}

View File

@ -6,21 +6,15 @@
#include <assert.h> #include <assert.h>
FrameBufferImpl::FrameBufferImpl() FrameBufferImpl::FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight)
: m_virtualWidth(virtualWidth), m_virtualHeight(virtualHeight)
{ {
int width, height; m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_RGBA32);
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);
} }
FrameBufferImpl::~FrameBufferImpl() FrameBufferImpl::~FrameBufferImpl()
{ {
SDL_DestroySurface(DDBackBuffer); m_transferBuffer->Release();
if (m_palette) { if (m_palette) {
m_palette->Release(); m_palette->Release();
} }
@ -51,44 +45,30 @@ HRESULT FrameBufferImpl::Blt(
LPDDBLTFX lpDDBltFx LPDDBLTFX lpDDBltFx
) )
{ {
if (!DDRenderer) {
return DDERR_GENERIC;
}
if (dynamic_cast<FrameBufferImpl*>(lpDDSrcSurface) == this) { if (dynamic_cast<FrameBufferImpl*>(lpDDSrcSurface) == this) {
return Flip(nullptr, DDFLIP_WAIT); return Flip(nullptr, DDFLIP_WAIT);
} }
if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) { 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 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF;
Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF; Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF;
Uint8 b = lpDDBltFx->dwFillColor & 0xFF; Uint8 b = lpDDBltFx->dwFillColor & 0xFF;
DirectDrawPaletteImpl* ddPal = static_cast<DirectDrawPaletteImpl*>(m_palette); DDRenderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f);
SDL_Palette* sdlPalette = ddPal ? ddPal->m_palette : nullptr;
Uint32 color = SDL_MapRGB(details, sdlPalette, r, g, b);
SDL_FillSurfaceRect(DDBackBuffer, &rect, color);
return DD_OK; return DD_OK;
} }
auto other = static_cast<DirectDrawSurfaceImpl*>(lpDDSrcSurface); auto surface = static_cast<DirectDrawSurfaceImpl*>(lpDDSrcSurface);
if (!other) { if (!surface) {
return DDERR_GENERIC; return DDERR_GENERIC;
} }
SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, other->m_surface->w, other->m_surface->h}; Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture());
SDL_Rect dstRect = lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, DDBackBuffer->w, DDBackBuffer->h}; 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; return DD_OK;
} }
@ -100,20 +80,20 @@ HRESULT FrameBufferImpl::BltFast(
DDBltFastFlags dwTrans DDBltFastFlags dwTrans
) )
{ {
RECT destRect = { auto surface = static_cast<DirectDrawSurfaceImpl*>(lpDDSrcSurface);
(int) dwX, int width = lpSrcRect ? (lpSrcRect->right - lpSrcRect->left) : surface->m_surface->w;
(int) dwY, int height = lpSrcRect ? (lpSrcRect->bottom - lpSrcRect->top) : surface->m_surface->h;
(int) (lpSrcRect->right - lpSrcRect->left + dwX), RECT destRect = {(int) dwX, (int) dwY, (int) (dwX + width), (int) (dwY + height)};
(int) (lpSrcRect->bottom - lpSrcRect->top + dwY)
};
return Blt(&destRect, lpDDSrcSurface, lpSrcRect, DDBLT_NONE, nullptr); return Blt(&destRect, lpDDSrcSurface, lpSrcRect, DDBLT_NONE, nullptr);
} }
HRESULT FrameBufferImpl::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DDFlipFlags dwFlags) HRESULT FrameBufferImpl::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DDFlipFlags dwFlags)
{ {
SDL_UpdateTexture(m_uploadBuffer, nullptr, DDBackBuffer->pixels, DDBackBuffer->pitch); if (!DDRenderer) {
SDL_RenderTexture(DDRenderer, m_uploadBuffer, nullptr, nullptr); return DDERR_GENERIC;
SDL_RenderPresent(DDRenderer); }
DDRenderer->Flip();
return DD_OK; return DD_OK;
} }
@ -146,7 +126,7 @@ HRESULT FrameBufferImpl::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat)
{ {
memset(lpDDPixelFormat, 0, sizeof(*lpDDPixelFormat)); memset(lpDDPixelFormat, 0, sizeof(*lpDDPixelFormat));
lpDDPixelFormat->dwFlags = DDPF_RGB; 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) { if (details->bits_per_pixel == 8) {
lpDDPixelFormat->dwFlags |= DDPF_PALETTEINDEXED8; lpDDPixelFormat->dwFlags |= DDPF_PALETTEINDEXED8;
} }
@ -163,25 +143,28 @@ HRESULT FrameBufferImpl::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc)
lpDDSurfaceDesc->dwFlags = DDSD_PIXELFORMAT; lpDDSurfaceDesc->dwFlags = DDSD_PIXELFORMAT;
GetPixelFormat(&lpDDSurfaceDesc->ddpfPixelFormat); GetPixelFormat(&lpDDSurfaceDesc->ddpfPixelFormat);
lpDDSurfaceDesc->dwFlags |= DDSD_WIDTH | DDSD_HEIGHT; lpDDSurfaceDesc->dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
lpDDSurfaceDesc->dwWidth = DDBackBuffer->w; lpDDSurfaceDesc->dwWidth = m_transferBuffer->m_surface->w;
lpDDSurfaceDesc->dwHeight = DDBackBuffer->h; lpDDSurfaceDesc->dwHeight = m_transferBuffer->m_surface->h;
return DD_OK;
}
HRESULT FrameBufferImpl::IsLost()
{
return DD_OK; return DD_OK;
} }
HRESULT FrameBufferImpl::Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent) HRESULT FrameBufferImpl::Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent)
{ {
if (!SDL_LockSurface(DDBackBuffer)) { if (!DDRenderer) {
return DDERR_GENERIC; 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<DirectDrawPaletteImpl*>(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); m_transferBuffer->Lock(lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent);
lpDDSurfaceDesc->lpSurface = DDBackBuffer->pixels;
lpDDSurfaceDesc->lPitch = DDBackBuffer->pitch;
return DD_OK; return DD_OK;
} }
@ -198,11 +181,6 @@ HRESULT FrameBufferImpl::Restore()
return DD_OK; return DD_OK;
} }
HRESULT FrameBufferImpl::SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper)
{
return DD_OK;
}
HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey) HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey)
{ {
MINIWIN_NOT_IMPLEMENTED(); MINIWIN_NOT_IMPLEMENTED();
@ -211,7 +189,7 @@ HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDC
HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
{ {
if (DDBackBuffer->format != SDL_PIXELFORMAT_INDEX8) { if (m_transferBuffer->m_surface->format != SDL_PIXELFORMAT_INDEX8) {
MINIWIN_NOT_IMPLEMENTED(); MINIWIN_NOT_IMPLEMENTED();
} }
@ -220,13 +198,15 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
} }
m_palette = 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(); m_palette->AddRef();
return DD_OK; return DD_OK;
} }
HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData) HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData)
{ {
SDL_UnlockSurface(DDBackBuffer); m_transferBuffer->Unlock(lpSurfaceData);
BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT);
return DD_OK; return DD_OK;
} }

View File

@ -11,8 +11,8 @@ struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl<IDirect3DRMDevice
Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer); Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer);
~Direct3DRMDevice2Impl() override; ~Direct3DRMDevice2Impl() override;
HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; HRESULT QueryInterface(const GUID& riid, void** ppvObject) override;
DWORD GetWidth() override; DWORD GetWidth() override { return m_virtualWidth; }
DWORD GetHeight() override; DWORD GetHeight() override { return m_virtualHeight; }
HRESULT SetBufferCount(int count) override; HRESULT SetBufferCount(int count) override;
DWORD GetBufferCount() override; DWORD GetBufferCount() override;
HRESULT SetShades(DWORD shadeCount) override; HRESULT SetShades(DWORD shadeCount) override;
@ -38,7 +38,10 @@ struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl<IDirect3DRMDevice
Direct3DRMRenderer* m_renderer; Direct3DRMRenderer* m_renderer;
private: private:
DWORD m_width; void Resize();
DWORD m_height;
uint32_t m_virtualWidth;
uint32_t m_virtualHeight;
ViewportTransform m_viewportTransform;
IDirect3DRMViewportArray* m_viewports; IDirect3DRMViewportArray* m_viewports;
}; };

View File

@ -10,7 +10,7 @@ struct MeshGroup {
IDirect3DRMTexture* texture = nullptr; IDirect3DRMTexture* texture = nullptr;
IDirect3DRMMaterial* material = nullptr; IDirect3DRMMaterial* material = nullptr;
D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD; D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD;
int vertexPerFace = 0; int vertexPerFace = 3;
int version = 0; int version = 0;
std::vector<D3DRMVERTEX> vertices; std::vector<D3DRMVERTEX> vertices;
std::vector<DWORD> indices; std::vector<DWORD> indices;
@ -67,8 +67,13 @@ struct MeshGroup {
struct Direct3DRMMeshImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMMesh> { struct Direct3DRMMeshImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMMesh> {
HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; HRESULT QueryInterface(const GUID& riid, void** ppvObject) override;
HRESULT Clone(int flags, GUID iid, void** object) override; HRESULT Clone(int flags, GUID iid, void** object) override;
HRESULT AddGroup(int vertexCount, int faceCount, int vertexPerFace, DWORD* faceBuffer, D3DRMGROUPINDEX* groupIndex) HRESULT AddGroup(
override; unsigned int vertexCount,
unsigned int faceCount,
unsigned int vertexPerFace,
unsigned int* faceBuffer,
D3DRMGROUPINDEX* groupIndex
) override;
HRESULT GetGroup( HRESULT GetGroup(
D3DRMGROUPINDEX groupIndex, D3DRMGROUPINDEX groupIndex,
unsigned int* vertexCount, unsigned int* vertexCount,

View File

@ -26,8 +26,6 @@ struct Plane {
float d; float d;
}; };
extern SDL_Renderer* DDRenderer;
class Direct3DRMRenderer : public IDirect3DDevice2 { class Direct3DRMRenderer : public IDirect3DDevice2 {
public: public:
virtual void PushLights(const SceneLight* vertices, size_t count) = 0; 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 void SetFrustumPlanes(const Plane* frustumPlanes) = 0;
virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0; virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0;
virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0; virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0;
virtual DWORD GetWidth() = 0; int GetWidth() { return m_width; }
virtual DWORD GetHeight() = 0; int GetHeight() { return m_height; }
int GetVirtualWidth() { return m_virtualWidth; }
int GetVirtualHeight() { return m_virtualHeight; }
virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0; virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0;
virtual const char* GetName() = 0; virtual const char* GetName() = 0;
virtual HRESULT BeginFrame() = 0; virtual HRESULT BeginFrame() = 0;
@ -44,13 +44,20 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
virtual void SubmitDraw( virtual void SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) = 0; ) = 0;
virtual HRESULT FinalizeFrame() = 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) protected:
{ int m_width, m_height;
return SDL_ConvertEventToRenderCoordinates(DDRenderer, event); int m_virtualWidth, m_virtualHeight;
} ViewportTransform m_viewportTransform;
}; };

View File

@ -20,8 +20,6 @@ class DirectX9Renderer : public Direct3DRMRenderer {
void SetFrustumPlanes(const Plane* frustumPlanes) override; void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override; const char* GetName() override;
HRESULT BeginFrame() override; HRESULT BeginFrame() override;
@ -29,17 +27,23 @@ class DirectX9Renderer : public Direct3DRMRenderer {
void SubmitDraw( void SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) override; ) override;
HRESULT FinalizeFrame() 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: private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
SDL_Surface* m_renderedImage; SDL_Surface* m_renderedImage;
DWORD m_width, m_height;
std::vector<SceneLight> m_lights; std::vector<SceneLight> m_lights;
std::vector<D3D9MeshCacheEntry> m_meshs; std::vector<D3D9MeshCacheEntry> m_meshs;
std::vector<D3D9TextureCacheEntry> m_textures; std::vector<D3D9TextureCacheEntry> m_textures;

View File

@ -42,7 +42,7 @@ struct GLMeshCacheEntry {
class OpenGL1Renderer : public Direct3DRMRenderer { class OpenGL1Renderer : public Direct3DRMRenderer {
public: public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height); 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; ~OpenGL1Renderer() override;
void PushLights(const SceneLight* lightsArray, size_t count) override; void PushLights(const SceneLight* lightsArray, size_t count) override;
@ -50,8 +50,6 @@ class OpenGL1Renderer : public Direct3DRMRenderer {
void SetFrustumPlanes(const Plane* frustumPlanes) override; void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override; const char* GetName() override;
HRESULT BeginFrame() override; HRESULT BeginFrame() override;
@ -59,10 +57,17 @@ class OpenGL1Renderer : public Direct3DRMRenderer {
void SubmitDraw( void SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) override; ) override;
HRESULT FinalizeFrame() 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: private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
@ -72,13 +77,11 @@ class OpenGL1Renderer : public Direct3DRMRenderer {
std::vector<GLMeshCacheEntry> m_meshs; std::vector<GLMeshCacheEntry> m_meshs;
D3DRMMATRIX4D m_projection; D3DRMMATRIX4D m_projection;
SDL_Surface* m_renderedImage; SDL_Surface* m_renderedImage;
DWORD m_width, m_height;
bool m_useVBOs; bool m_useVBOs;
bool m_dirty = false;
std::vector<SceneLight> m_lights; std::vector<SceneLight> m_lights;
SDL_GLContext m_context; SDL_GLContext m_context;
GLuint m_fbo; ViewportTransform m_viewportTransform;
GLuint m_colorTex;
GLuint m_depthRb;
}; };
inline static void OpenGL1Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) inline static void OpenGL1Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)

View File

@ -14,6 +14,8 @@ struct GLES2TextureCacheEntry {
IDirect3DRMTexture* texture; IDirect3DRMTexture* texture;
Uint32 version; Uint32 version;
GLuint glTextureId; GLuint glTextureId;
uint16_t width;
uint16_t height;
}; };
struct GLES2MeshCacheEntry { struct GLES2MeshCacheEntry {
@ -31,15 +33,7 @@ struct GLES2MeshCacheEntry {
class OpenGLES2Renderer : public Direct3DRMRenderer { class OpenGLES2Renderer : public Direct3DRMRenderer {
public: public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height); static Direct3DRMRenderer* Create(DWORD width, DWORD height);
OpenGLES2Renderer( OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram);
DWORD width,
DWORD height,
SDL_GLContext context,
GLuint fbo,
GLuint colorTex,
GLuint vertexBuffer,
GLuint shaderProgram
);
~OpenGLES2Renderer() override; ~OpenGLES2Renderer() override;
void PushLights(const SceneLight* lightsArray, size_t count) override; void PushLights(const SceneLight* lightsArray, size_t count) override;
@ -47,8 +41,6 @@ class OpenGLES2Renderer : public Direct3DRMRenderer {
void SetFrustumPlanes(const Plane* frustumPlanes) override; void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override; const char* GetName() override;
HRESULT BeginFrame() override; HRESULT BeginFrame() override;
@ -56,10 +48,17 @@ class OpenGLES2Renderer : public Direct3DRMRenderer {
void SubmitDraw( void SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) override; ) override;
HRESULT FinalizeFrame() 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: private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
@ -69,13 +68,11 @@ class OpenGLES2Renderer : public Direct3DRMRenderer {
std::vector<GLES2MeshCacheEntry> m_meshs; std::vector<GLES2MeshCacheEntry> m_meshs;
D3DRMMATRIX4D m_projection; D3DRMMATRIX4D m_projection;
SDL_Surface* m_renderedImage; SDL_Surface* m_renderedImage;
DWORD m_width, m_height; bool m_dirty = false;
std::vector<SceneLight> m_lights; std::vector<SceneLight> m_lights;
SDL_GLContext m_context; SDL_GLContext m_context;
GLuint m_fbo;
GLuint m_colorTex;
GLuint m_depthRb;
GLuint m_shaderProgram; GLuint m_shaderProgram;
ViewportTransform m_viewportTransform;
}; };
inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)

View File

@ -51,8 +51,6 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
void SetFrustumPlanes(const Plane* frustumPlanes) override; void SetFrustumPlanes(const Plane* frustumPlanes) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override; const char* GetName() override;
HRESULT BeginFrame() override; HRESULT BeginFrame() override;
@ -60,10 +58,17 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
void SubmitDraw( void SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) override; ) override;
HRESULT FinalizeFrame() 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: private:
Direct3DRMSDL3GPURenderer( Direct3DRMSDL3GPURenderer(
@ -72,12 +77,13 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
SDL_GPUDevice* device, SDL_GPUDevice* device,
SDL_GPUGraphicsPipeline* opaquePipeline, SDL_GPUGraphicsPipeline* opaquePipeline,
SDL_GPUGraphicsPipeline* transparentPipeline, SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture, SDL_GPUGraphicsPipeline* uiPipeline,
SDL_GPUTexture* depthTexture,
SDL_GPUSampler* sampler, SDL_GPUSampler* sampler,
SDL_GPUSampler* uiSampler,
SDL_GPUTransferBuffer* uploadBuffer, SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer int uploadBufferSize
); );
void StartRenderPass(float r, float g, float b, bool clear);
void WaitForPendingUpload(); void WaitForPendingUpload();
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
SDL_GPUTransferBuffer* GetUploadBuffer(size_t size); SDL_GPUTransferBuffer* GetUploadBuffer(size_t size);
@ -85,26 +91,29 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
SDL3MeshCache UploadMesh(const MeshGroup& meshGroup); SDL3MeshCache UploadMesh(const MeshGroup& meshGroup);
DWORD m_width; MeshGroup m_uiMesh;
DWORD m_height; SDL3MeshCache m_uiMeshCache;
D3DVALUE m_front; D3DVALUE m_front;
D3DVALUE m_back; D3DVALUE m_back;
ViewportUniforms m_uniforms; ViewportUniforms m_uniforms;
FragmentShadingData m_fragmentShadingData; FragmentShadingData m_fragmentShadingData;
D3DDEVICEDESC m_desc; D3DDEVICEDESC m_desc;
D3DRMMATRIX4D m_projection;
std::vector<SDL3TextureCache> m_textures; std::vector<SDL3TextureCache> m_textures;
std::vector<SDL3MeshCache> m_meshs; std::vector<SDL3MeshCache> m_meshs;
SDL_GPUDevice* m_device; SDL_GPUDevice* m_device;
SDL_GPUGraphicsPipeline* m_opaquePipeline; SDL_GPUGraphicsPipeline* m_opaquePipeline;
SDL_GPUGraphicsPipeline* m_transparentPipeline; SDL_GPUGraphicsPipeline* m_transparentPipeline;
SDL_GPUTexture* m_transferTexture; SDL_GPUGraphicsPipeline* m_uiPipeline;
SDL_GPUTexture* m_depthTexture; SDL_GPUTexture* m_transferTexture = nullptr;
SDL_GPUTexture* m_depthTexture = nullptr;
SDL_GPUTexture* m_dummyTexture; SDL_GPUTexture* m_dummyTexture;
int m_uploadBufferSize; int m_uploadBufferSize;
SDL_GPUTransferBuffer* m_uploadBuffer; SDL_GPUTransferBuffer* m_uploadBuffer;
SDL_GPUTransferBuffer* m_downloadBuffer; SDL_GPUTransferBuffer* m_downloadBuffer = nullptr;
SDL_GPUBuffer* m_vertexBuffer = nullptr; SDL_GPUBuffer* m_vertexBuffer = nullptr;
SDL_GPUSampler* m_sampler; SDL_GPUSampler* m_sampler;
SDL_GPUSampler* m_uiSampler;
SDL_GPUCommandBuffer* m_cmdbuf = nullptr; SDL_GPUCommandBuffer* m_cmdbuf = nullptr;
SDL_GPURenderPass* m_renderPass = nullptr; SDL_GPURenderPass* m_renderPass = nullptr;
SDL_GPUFence* m_uploadFence = nullptr; SDL_GPUFence* m_uploadFence = nullptr;

View File

@ -27,13 +27,12 @@ struct MeshCache {
class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
public: public:
Direct3DRMSoftwareRenderer(DWORD width, DWORD height); Direct3DRMSoftwareRenderer(DWORD width, DWORD height);
~Direct3DRMSoftwareRenderer() override;
void PushLights(const SceneLight* vertices, size_t count) override; void PushLights(const SceneLight* vertices, size_t count) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
void SetFrustumPlanes(const Plane* frustumPlanes) override; void SetFrustumPlanes(const Plane* frustumPlanes) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override; const char* GetName() override;
HRESULT BeginFrame() override; HRESULT BeginFrame() override;
@ -41,10 +40,17 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
void SubmitDraw( void SubmitDraw(
DWORD meshId, DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
) override; ) override;
HRESULT FinalizeFrame() 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: private:
void ClearZBuffer(); void ClearZBuffer();
@ -61,9 +67,10 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
DWORD m_width; SDL_Surface* m_renderedImage = nullptr;
DWORD m_height;
SDL_Palette* m_palette; SDL_Palette* m_palette;
SDL_Texture* m_uploadBuffer = nullptr;
SDL_Renderer* m_renderer;
const SDL_PixelFormatDetails* m_format; const SDL_PixelFormatDetails* m_format;
int m_bytesPerPixel; int m_bytesPerPixel;
std::vector<SceneLight> m_lights; std::vector<SceneLight> m_lights;

View File

@ -4,10 +4,12 @@
struct Direct3DRMTextureImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMTexture2> { struct Direct3DRMTextureImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMTexture2> {
Direct3DRMTextureImpl(D3DRMIMAGE* image); Direct3DRMTextureImpl(D3DRMIMAGE* image);
Direct3DRMTextureImpl(IDirectDrawSurface* surface); Direct3DRMTextureImpl(IDirectDrawSurface* surface, bool holdsRef);
~Direct3DRMTextureImpl() override;
HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; HRESULT QueryInterface(const GUID& riid, void** ppvObject) override;
HRESULT Changed(BOOL pixels, BOOL palette) override; HRESULT Changed(BOOL pixels, BOOL palette) override;
IDirectDrawSurface* m_surface = nullptr; IDirectDrawSurface* m_surface = nullptr;
Uint8 m_version = 0; Uint8 m_version = 0;
bool m_holdsRef;
}; };

View File

@ -10,6 +10,7 @@
struct DeferredDrawCommand { struct DeferredDrawCommand {
DWORD meshId; DWORD meshId;
D3DRMMATRIX4D modelViewMatrix; D3DRMMATRIX4D modelViewMatrix;
D3DRMMATRIX4D worldMatrix;
Matrix3x3 normalMatrix; Matrix3x3 normalMatrix;
Appearance appearance; Appearance appearance;
float depth; float depth;
@ -36,24 +37,24 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMViewp
D3DVALUE GetBack() override; D3DVALUE GetBack() override;
HRESULT SetField(D3DVALUE field) override; HRESULT SetField(D3DVALUE field) override;
D3DVALUE GetField() override; D3DVALUE GetField() override;
DWORD GetWidth() override; DWORD GetWidth() override { return m_virtualWidth; }
DWORD GetHeight() override; DWORD GetHeight() override { return m_virtualHeight; }
HRESULT Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world) override; HRESULT Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world) override;
HRESULT InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen) override; HRESULT InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen) override;
HRESULT Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray) override; HRESULT Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray) override;
void CloseDevice(); void CloseDevice();
void UpdateProjectionMatrix();
private: private:
HRESULT RenderScene(); HRESULT RenderScene();
void CollectLightsFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix, std::vector<SceneLight>& lights); void CollectLightsFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix, std::vector<SceneLight>& lights);
void CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix); void CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix);
void BuildViewFrustumPlanes(); void BuildViewFrustumPlanes();
void UpdateProjectionMatrix();
Direct3DRMRenderer* m_renderer; Direct3DRMRenderer* m_renderer;
std::vector<DeferredDrawCommand> m_deferredDraws; std::vector<DeferredDrawCommand> m_deferredDraws;
D3DCOLOR m_backgroundColor = 0xFF000000; D3DCOLOR m_backgroundColor = 0xFF000000;
DWORD m_width; DWORD m_virtualWidth;
DWORD m_height; DWORD m_virtualHeight;
D3DRMMATRIX4D m_viewProjectionwMatrix; D3DRMMATRIX4D m_viewProjectionwMatrix;
D3DRMMATRIX4D m_viewMatrix; D3DRMMATRIX4D m_viewMatrix;
D3DRMMATRIX4D m_projectionMatrix; D3DRMMATRIX4D m_projectionMatrix;

View File

@ -8,9 +8,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
extern SDL_Window* DDWindow; extern SDL_Window* DDWindow;
extern SDL_Surface* DDBackBuffer; extern Direct3DRMRenderer* DDRenderer;
extern FrameBufferImpl* DDFrameBuffer;
extern SDL_Renderer* DDRenderer;
inline static SDL_Rect ConvertRect(const RECT* r) 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) HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice)
override; override;
HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) 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); HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context);

View File

@ -35,8 +35,11 @@ struct DirectDrawSurfaceImpl : public IDirectDrawSurface3 {
HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override; HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override;
HRESULT Unlock(LPVOID lpSurfaceData) override; HRESULT Unlock(LPVOID lpSurfaceData) override;
IDirect3DRMTexture2* ToTexture();
SDL_Surface* m_surface = nullptr; SDL_Surface* m_surface = nullptr;
private: private:
IDirect3DRMTexture2* m_texture = nullptr;
IDirectDrawPalette* m_palette = nullptr; IDirectDrawPalette* m_palette = nullptr;
}; };

View File

@ -5,7 +5,7 @@
#include <miniwin/ddraw.h> #include <miniwin/ddraw.h>
struct FrameBufferImpl : public IDirectDrawSurface3 { struct FrameBufferImpl : public IDirectDrawSurface3 {
FrameBufferImpl(); FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight);
~FrameBufferImpl() override; ~FrameBufferImpl() override;
// IUnknown interface // IUnknown interface
@ -27,16 +27,18 @@ struct FrameBufferImpl : public IDirectDrawSurface3 {
HRESULT GetPalette(LPDIRECTDRAWPALETTE* lplpDDPalette) override; HRESULT GetPalette(LPDIRECTDRAWPALETTE* lplpDDPalette) override;
HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) override; HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) override;
HRESULT GetSurfaceDesc(DDSURFACEDESC* lpDDSurfaceDesc) 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 Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent) override;
HRESULT ReleaseDC(HDC hDC) override; HRESULT ReleaseDC(HDC hDC) override;
HRESULT Restore() 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 SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey) override;
HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override; HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override;
HRESULT Unlock(LPVOID lpSurfaceData) override; HRESULT Unlock(LPVOID lpSurfaceData) override;
private: private:
SDL_Texture* m_uploadBuffer; uint32_t m_virtualWidth;
uint32_t m_virtualHeight;
DirectDrawSurfaceImpl* m_transferBuffer;
IDirectDrawPalette* m_palette = nullptr; IDirectDrawPalette* m_palette = nullptr;
}; };

View File

@ -15,3 +15,9 @@ struct Appearance {
uint32_t textureId; uint32_t textureId;
uint32_t flat; uint32_t flat;
}; };
struct ViewportTransform {
float scale;
float offsetX;
float offsetY;
};