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 install -y \
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \
libasound2-dev
- name: Install macOS dependencies (brew)
if: ${{ matrix.brew }}

View File

@ -45,7 +45,8 @@ jobs:
sudo apt-get update
sudo apt-get install -y \
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \
libasound2-dev
- name: Install macOS dependencies (brew)
if: ${{ matrix.brew }}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -157,7 +157,18 @@ class LegoGameState {
MxS16 m_totalScore; // 0x00
MxU8 m_scores[5][5]; // 0x02
Username m_name; // 0x1c
MxS16 m_unk0x2a; // 0x2a
MxS16 m_playerId; // 0x2a
ScoreItem& operator=(const ScoreItem& p_other)
{
// MSVC auto-generates an operator=, but LegoGameState::WriteScoreHistory() has a much better match
// with a manual implementation.
m_totalScore = p_other.m_totalScore;
memcpy(m_scores, p_other.m_scores, sizeof(m_scores));
m_name = p_other.m_name;
m_playerId = p_other.m_playerId;
return *this;
}
};
// SIZE 0x372
@ -165,7 +176,7 @@ class LegoGameState {
History();
void WriteScoreHistory();
MxResult Serialize(LegoStorage* p_storage);
ScoreItem* FUN_1003cc90(Username* p_player, MxS16 p_unk0x24, MxS32& p_unk0x2c);
ScoreItem* FindPlayerInScoreHistory(Username* p_player, MxS16 p_unk0x24, MxS32& p_unk0x2c);
// FUNCTION: BETA10 0x1002c2b0
MxS16 GetCount() { return m_count; }
@ -174,9 +185,12 @@ class LegoGameState {
// FUNCTION: BETA10 0x1002c540
ScoreItem* GetScore(MxS32 p_index) { return p_index >= m_count ? NULL : &m_scores[p_index]; }
MxS16 m_count; // 0x00
ScoreItem m_scores[20]; // 0x02
MxS16 m_unk0x372; // 0x372
MxS16 m_count; // 0x00
#ifdef BETA10
MxS16 m_indices[20]; // 0x02
#endif
ScoreItem m_scores[20]; // 0x02 (0x22 for BETA10)
MxS16 m_nextPlayerId; // 0x372 (0x392 for BETA10)
};
LEGO1_EXPORT LegoGameState();
@ -216,14 +230,8 @@ class LegoGameState {
Act GetCurrentAct() { return m_currentAct; }
Act GetLoadedAct() { return m_loadedAct; }
Area GetPreviousArea() { return m_previousArea; }
Area GetUnknown0x42c() { return m_unk0x42c; }
void SetDirty(MxBool p_isDirty) { m_isDirty = p_isDirty; }
void SetPreviousArea(Area p_previousArea) { m_previousArea = p_previousArea; }
void SetActorId(MxU8 p_actorId) { m_actorId = p_actorId; }
Username* GetPlayersIndex(MxS32 p_index) { return &m_players[p_index]; }
MxS16 GetPlayerCount() { return m_playerCount; }
LegoBackgroundColor* GetBackgroundColor() { return m_backgroundColor; }
void SetCurrentAct(Act p_currentAct);
@ -249,14 +257,11 @@ class LegoGameState {
LegoBackgroundColor* m_tempBackgroundColor; // 0x1c
LegoFullScreenMovie* m_fullScreenMovie; // 0x20
// TODO: Most likely getters/setters are not used according to BETA for the following members:
public:
MxS16 m_unk0x24; // 0x24
MxS16 m_currentPlayerId; // 0x24
MxS16 m_playerCount; // 0x26
Username m_players[9]; // 0x28
History m_history; // 0xa6
undefined2 m_unk0x41a; // 0x41a
JukeboxScript::Script m_jukeboxMusic; // 0x41c
MxBool m_isDirty; // 0x420
Area m_currentArea; // 0x424

View File

@ -78,6 +78,9 @@ class LegoVideoManager : public MxVideoManager {
inline void DrawCursor();
void DrawDigitToBuffer32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, int p_digit, uint32_t p_color);
void DrawTextToSurface32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, const char* p_text, uint32_t p_color);
Tgl::Renderer* m_renderer; // 0x64
Lego3DManager* m_3dManager; // 0x68
LegoROI* m_viewROI; // 0x6c

View File

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

View File

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

View File

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

View File

@ -83,7 +83,7 @@ LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_text
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) != DD_OK) {
if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) != DD_OK) {
goto done;
}
@ -193,7 +193,7 @@ LegoResult LegoTextureInfo::LoadBits(const LegoU8* p_bits)
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
if (m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) {
if (m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) {
MxU8* surface = (MxU8*) desc.lpSurface;
const LegoU8* bits = p_bits;

View File

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

View File

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

View File

@ -210,10 +210,10 @@ void MxTransitionManager::DissolveTransition()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (res == DD_OK) {
@ -402,10 +402,10 @@ void MxTransitionManager::WipeDownTransition()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (res == DD_OK) {
@ -439,10 +439,10 @@ void MxTransitionManager::WindowsTransition()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (res == DD_OK) {
@ -483,10 +483,10 @@ void MxTransitionManager::BrokenTransition()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (res == DDERR_SURFACELOST) {
m_ddSurface->Restore();
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (res == DD_OK) {

View File

@ -393,7 +393,7 @@ MxResult LegoWorldPresenter::LoadWorldModel(ModelDbModel& p_model, SDL_IOStream*
}
modelPresenter.SetAction(&action);
modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_unk0x34, p_world);
modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_visible, p_world);
delete[] buff;
return SUCCESS;

View File

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

View File

@ -406,37 +406,14 @@ inline void LegoVideoManager::DrawCursor()
// FUNCTION: LEGO1 0x1007bbc0
void LegoVideoManager::DrawFPS()
{
char zeros[8] = "0000.00";
if (m_unk0x528 == NULL) {
m_arialFont = CreateFont(
12,
0,
0,
0,
FW_NORMAL,
FALSE,
FALSE,
FALSE,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
FF_DONTCARE | VARIABLE_PITCH,
"Arial"
);
int width = 64; // Big enough for 9999.99
int height = 16;
HDC dc = GetDC(NULL);
SelectObject(dc, m_arialFont);
GetTextExtentPoint(dc, zeros, strlen(zeros), &m_fpsSize);
ReleaseDC(NULL, dc);
m_unk0x528 = m_displaySurface->FUN_100bc8b0(m_fpsSize.cx, m_fpsSize.cy);
SetRect(&m_fpsRect, 0, 0, m_fpsSize.cx, m_fpsSize.cy);
m_unk0x528 = m_displaySurface->FUN_100bc8b0(width, height);
SetRect(&m_fpsRect, 0, 0, width, height);
if (m_unk0x528 == NULL) {
DeleteObject(m_arialFont);
m_arialFont = NULL;
return;
}
@ -450,9 +427,7 @@ void LegoVideoManager::DrawFPS()
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) != DD_OK) {
m_unk0x528->Release();
DeleteObject(m_arialFont);
m_unk0x528 = NULL;
m_arialFont = NULL;
}
else {
DWORD i;
@ -472,8 +447,7 @@ void LegoVideoManager::DrawFPS()
if (Timer()->GetTime() > m_unk0x54c + 5000.f) {
char buffer[32];
MxFloat time = (Timer()->GetTime() - m_unk0x54c) / 1000.0f;
MxS32 nb = sprintf(buffer, "%.02f", m_unk0x550 / time);
SDL_Log("%.02f", m_unk0x550 / time);
sprintf(buffer, "%.02f", m_unk0x550 / time);
m_unk0x54c = Timer()->GetTime();
DDSURFACEDESC surfaceDesc;
@ -481,37 +455,13 @@ void LegoVideoManager::DrawFPS()
surfaceDesc.dwSize = sizeof(surfaceDesc);
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) {
DWORD i;
char* ptr = (char*) surfaceDesc.lpSurface;
memset(surfaceDesc.lpSurface, 0, surfaceDesc.lPitch * surfaceDesc.dwHeight);
for (i = 0; i < surfaceDesc.dwHeight; i++) {
memset(ptr, 0, surfaceDesc.lPitch);
ptr += surfaceDesc.lPitch;
}
DrawTextToSurface32((uint8_t*) surfaceDesc.lpSurface, surfaceDesc.lPitch, 0, 0, buffer, 0xFF0000FF);
m_unk0x528->Unlock(surfaceDesc.lpSurface);
m_unk0x550 = 1.f;
}
HDC dc;
if (m_unk0x528->GetDC(&dc) != DD_OK) {
m_unk0x528->Release();
m_unk0x528 = NULL;
DeleteObject(m_arialFont);
m_arialFont = NULL;
return;
}
SelectObject(dc, m_arialFont);
SetTextColor(dc, RGB(255, 255, 0));
SetBkColor(dc, RGB(0, 0, 0));
SetBkMode(dc, OPAQUE);
GetTextExtentPoint32(dc, buffer, nb, &m_fpsSize);
RECT rect;
SetRect(&rect, 0, 0, m_fpsSize.cx, m_fpsSize.cy);
ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, buffer, nb, NULL);
m_unk0x528->ReleaseDC(dc);
m_unk0x550 = 1.f;
}
else {
m_unk0x550 += 1.f;
@ -826,3 +776,63 @@ MxResult LegoVideoManager::ConfigureD3DRM()
return SUCCESS;
}
void LegoVideoManager::DrawDigitToBuffer32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, int p_digit, uint32_t p_color)
{
if (p_digit < 0 || p_digit > 9) {
return;
}
uint32_t* pixels = (uint32_t*) p_dst;
int rowStride = p_pitch / 4;
// 4x5 bitmap font
const uint8_t digitFont[5][10] = {
{0b1111, 0b0001, 0b1111, 0b1111, 0b1001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111},
{0b1001, 0b0001, 0b0001, 0b0001, 0b1001, 0b1000, 0b1000, 0b0001, 0b1001, 0b1001},
{0b1001, 0b0001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111, 0b0010, 0b1111, 0b1111},
{0b1001, 0b0001, 0b1000, 0b0001, 0b0001, 0b0001, 0b1001, 0b0010, 0b1001, 0b0001},
{0b1111, 0b0001, 0b1111, 0b1111, 0b0001, 0b1111, 0b1111, 0b0100, 0b1111, 0b1111},
};
for (int row = 0; row < 5; ++row) {
uint8_t bits = digitFont[row][p_digit];
for (int col = 0; col < 5; ++col) {
if (bits & (1 << (4 - col))) {
for (int dy = 0; dy < 2; ++dy) {
for (int dx = 0; dx < 2; ++dx) {
pixels[(p_y + row * 2 + dy) * rowStride + (p_x + col * 2 + dx)] = p_color;
}
}
}
}
}
}
void LegoVideoManager::DrawTextToSurface32(
uint8_t* p_dst,
int p_pitch,
int p_x,
int p_y,
const char* p_text,
uint32_t p_color
)
{
while (*p_text) {
if (*p_text >= '0' && *p_text <= '9') {
DrawDigitToBuffer32(p_dst, p_pitch, p_x, p_y, *p_text - '0', p_color);
p_x += 10;
}
else if (*p_text == '.') {
uint32_t* pixels = (uint32_t*) p_dst;
int rowStride = p_pitch / 4;
for (int dy = 0; dy < 2; ++dy) {
for (int dx = 0; dx < 2; ++dx) {
pixels[(p_y + 10 + dy) * rowStride + (p_x + 2 + dx)] = p_color;
}
}
p_x += 4;
}
++p_text;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -254,7 +254,7 @@ void Score::Paint()
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
HRESULT result = cube->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL);
HRESULT result = cube->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL);
if (result == DD_OK) {
if (desc.lPitch != desc.dwWidth) {
cube->m_surface->Unlock(desc.lpSurface);

View File

@ -154,7 +154,7 @@ double Lego3DView::Render(double p_und)
}
// FUNCTION: LEGO1 0x100ab2b0
ViewROI* Lego3DView::Pick(unsigned int x, unsigned int y)
ViewROI* Lego3DView::Pick(int x, int y)
{
return m_pViewManager->Pick(GetView(), x, y);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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)) {
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;
}

View File

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

View File

@ -174,7 +174,7 @@ BOOL MxDirect3D::D3DSetMode()
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) {
if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) {
unsigned char* surface = (unsigned char*) desc.lpSurface;
for (int i = 0; i < mode.height; i++) {
@ -192,7 +192,7 @@ BOOL MxDirect3D::D3DSetMode()
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) {
if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) {
unsigned char* surface = (unsigned char*) desc.lpSurface;
for (int i = 0; i < mode.height; i++) {

View File

@ -539,10 +539,10 @@ void MxDirectDraw::ClearBackBuffers()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (result == DDERR_SURFACELOST) {
m_pBackBuffer->Restore();
result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (result != DD_OK) {

View File

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

View File

@ -9,6 +9,8 @@
#include "mxticklethread.h"
#include "mxwavepresenter.h"
#include <SDL3/SDL_log.h>
DECOMP_SIZE_ASSERT(MxSoundManager, 0x3c);
// GLOBAL LEGO1 0x10101420
@ -98,12 +100,17 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread)
spec.format = SDL_AUDIO_F32;
spec.channels = ma_engine_get_channels(m_engine);
if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) ==
if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) !=
NULL) {
goto done;
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
}
else {
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"Failed to open default audio device for playback: %s",
SDL_GetError()
);
}
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
if (p_createThread) {
m_thread = new MxTickleThread(this, p_frequencyMS);

View File

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

View File

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

View File

@ -402,10 +402,10 @@ void MxDisplaySurface::VTable0x28(
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (hr == DDERR_SURFACELOST) {
m_ddSurface2->Restore();
hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (hr != DD_OK) {
@ -514,10 +514,10 @@ void MxDisplaySurface::VTable0x30(
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (hr == DDERR_SURFACELOST) {
m_ddSurface2->Restore();
hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (hr != DD_OK) {
@ -726,11 +726,11 @@ void MxDisplaySurface::VTable0x34(MxU8* p_pixels, MxS32 p_bpp, MxS32 p_width, Mx
memset(&surfaceDesc, 0, sizeof(surfaceDesc));
surfaceDesc.dwSize = sizeof(surfaceDesc);
HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL);
HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (result == DDERR_SURFACELOST) {
m_ddSurface2->Restore();
result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL);
result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
}
if (result == DD_OK) {
@ -784,7 +784,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) {
if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) {
MxU8* surface = (MxU8*) ddsd.lpSurface;
MxS32 height = m_videoParam.GetRect().GetHeight();
@ -891,7 +891,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44(
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT, 0) != DD_OK) {
if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0) != DD_OK) {
surface->Release();
surface = NULL;
}
@ -1067,7 +1067,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) {
if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) {
goto done;
}
else {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -499,7 +499,7 @@ float ViewManager::ProjectedSize(const BoundingSphere& p_bounding_sphere)
}
// FUNCTION: LEGO1 0x100a6e00
ViewROI* ViewManager::Pick(Tgl::View* p_view, unsigned int x, unsigned int y)
ViewROI* ViewManager::Pick(Tgl::View* p_view, int x, int y)
{
LPDIRECT3DRMPICKEDARRAY picked = NULL;
ViewROI* result = NULL;

View File

@ -33,7 +33,7 @@ class ViewManager {
void RemoveROIDetailFromScene(ViewROI* p_roi);
void SetPOVSource(const OrientableROI* point_of_view);
float ProjectedSize(const BoundingSphere& p_bounding_sphere);
ViewROI* Pick(Tgl::View* p_view, unsigned int x, unsigned int y);
ViewROI* Pick(Tgl::View* p_view, int x, int y);
void SetResolution(int width, int height);
void SetFrustrum(float fov, float front, float back);
inline void ManageVisibilityAndDetailRecursively(ViewROI* p_from, int p_lodLevel);

View File

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

View File

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

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) |
| [Web](https://isle.pizza) | [![CI](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml/badge.svg)](https://github.com/isledecomp/isle-portable/actions/workflows/ci.yml) |
We are actively working to support more platforms. If you have experience with a particular platform, we encourage you to contribute to `isle-portable`. You can find a [list of ongoing efforts](https://github.com/isledecomp/isle-portable/wiki/Work%E2%80%90in%E2%80%90progress-ports) in our Wiki.
### Library substitutions
To achieve our goal of platform independence, we need to replace any Windows-only libraries with platform-independent alternatives. This ensures that our codebase remains versatile and compatible across various systems. The following table serves as an overview of major libraries / subsystems and their chosen replacements. For any significant changes or additions, it's recommended to discuss them with the team on the Matrix chat first to ensure consistency and alignment with our project's objectives.
@ -32,13 +34,19 @@ To achieve our goal of platform independence, we need to replace any Windows-onl
| WinMM, DirectSound (Audio) | [SDL3](https://www.libsdl.org/), [miniaudio](https://miniaud.io/) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Aaudio%5D%22&type=code) |
| DirectDraw (2D video) | [SDL3](https://www.libsdl.org/) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A2d%5D%22&type=code) |
| [Smacker](https://github.com/isledecomp/isle/tree/master/3rdparty/smacker) | [libsmacker](https://github.com/foxtacles/libsmacker) | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable%20%22%2F%2F%20%5Blibrary%3Alibsmacker%5D%22&type=code) |
| Direct3D (3D video) | [SDL3](https://www.libsdl.org/), D3D9, OpenGL, OpenGL ES, Software | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A3d%5D%22&type=code) |
| Direct3D (3D video) | [SDL3 (Vulkan, Metal, D3D12)](https://www.libsdl.org/), D3D9, OpenGL, OpenGL ES, Software | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3A3d%5D%22&type=code) |
| Direct3D Retained Mode | Custom re-implementation | ✅ | [Remarks](https://github.com/search?q=repo%3Aisledecomp%2Fisle-portable+%22%2F%2F+%5Blibrary%3Aretained%5D%22&type=code) |
| [SmartHeap](https://github.com/isledecomp/isle/tree/master/3rdparty/smartheap) | Default memory allocator | - | - |
## Building
This project uses the [CMake](https://cmake.org/) build system, which allows for a high degree of versatility regarding compilers and development environments. Please refer to the [GitHub action](/.github/workflows//build.yml) for guidance.
This project uses the [CMake](https://cmake.org/) build system, which allows for a high degree of versatility regarding compilers and development environments. Please refer to the [GitHub action](/.github/workflows//ci.yml) for guidance.
## Usage
**An existing copy of LEGO Island is required to use this project.**
As it stands, the builds provided in the Releases tab are for developers; as such, they may not work properly for end-users. Work is currently ongoing to create workable release builds ready for gameplay and general use by end-users. If you are technically inclined, you may find it easiest to compile the project yourself to get it running at this current point in time.
## Contributing

View File

@ -27,6 +27,10 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL
src/d3drm/backends/software/renderer.cpp
)
target_compile_definitions(miniwin PRIVATE
$<$<CONFIG:Debug>:DEBUG>
)
find_package(OpenGL)
find_package(GLEW)
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 GetBox(D3DRMBOX* box) = 0;
virtual HRESULT AddGroup(
int vertexCount,
int faceCount,
int vertexPerFace,
DWORD* faceBuffer,
unsigned int vertexCount,
unsigned int faceCount,
unsigned int vertexPerFace,
unsigned int* faceBuffer,
D3DRMGROUPINDEX* groupIndex
) = 0;
virtual HRESULT GetGroup(

View File

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

View File

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

View File

@ -11,19 +11,22 @@
static LPDIRECT3D9 g_d3d;
static LPDIRECT3DDEVICE9 g_device;
static HWND g_hwnd;
static LPDIRECT3DTEXTURE9 g_renderTargetTex;
static LPDIRECT3DSURFACE9 g_renderTargetSurf;
static LPDIRECT3DSURFACE9 g_oldRenderTarget;
static int m_width;
static int m_height;
static std::vector<BridgeSceneLight> m_lights;
static Matrix4x4 m_projection;
static int g_width;
static int g_height;
static int g_virtualWidth;
static int g_virtualHeight;
static bool g_hasScene = false;
static std::vector<BridgeSceneLight> g_lights;
static Matrix4x4 g_projection;
static ViewportTransform g_viewportTransform;
bool Actual_Initialize(void* hwnd, int width, int height)
{
g_hwnd = (HWND) hwnd;
m_width = width;
m_height = height;
g_width = width;
g_height = height;
g_virtualWidth = width;
g_virtualHeight = height;
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (!g_d3d) {
return false;
@ -52,45 +55,17 @@ bool Actual_Initialize(void* hwnd, int width, int height)
return false;
}
hr = g_device->CreateTexture(
width,
height,
1,
D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&g_renderTargetTex,
nullptr
);
if (FAILED(hr)) {
g_device->Release();
g_d3d->Release();
return false;
}
hr = g_renderTargetTex->GetSurfaceLevel(0, &g_renderTargetSurf);
if (FAILED(hr)) {
g_renderTargetTex->Release();
g_device->Release();
g_d3d->Release();
return false;
}
g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
return true;
}
void Actual_Shutdown()
{
if (g_renderTargetSurf) {
g_renderTargetSurf->Release();
g_renderTargetSurf = nullptr;
}
if (g_renderTargetTex) {
g_renderTargetTex->Release();
g_renderTargetTex = nullptr;
}
if (g_device) {
g_device->Release();
g_device = nullptr;
@ -103,12 +78,12 @@ void Actual_Shutdown()
void Actual_PushLights(const BridgeSceneLight* lightsArray, size_t count)
{
m_lights.assign(lightsArray, lightsArray + count);
g_lights.assign(lightsArray, lightsArray + count);
}
void Actual_SetProjection(const Matrix4x4* projection, float front, float back)
{
memcpy(&m_projection, projection, sizeof(Matrix4x4));
memcpy(&g_projection, projection, sizeof(Matrix4x4));
}
IDirect3DTexture9* UploadSurfaceToD3DTexture(SDL_Surface* surface)
@ -188,18 +163,71 @@ void UploadMeshBuffers(
cache.ibo->Unlock();
}
constexpr float PI = 3.14159265358979323846f;
void SetupLights()
void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform)
{
g_width = width;
g_height = height;
g_viewportTransform = viewportTransform;
D3DPRESENT_PARAMETERS pp = {};
pp.Windowed = TRUE;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = g_hwnd;
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
pp.BackBufferWidth = width;
pp.BackBufferHeight = height;
pp.EnableAutoDepthStencil = TRUE;
pp.AutoDepthStencilFormat = D3DFMT_D24S8;
g_device->Reset(&pp);
}
void StartScene()
{
if (g_hasScene) {
return;
}
g_device->BeginScene();
g_hasScene = true;
}
void Actual_Clear(float r, float g, float b)
{
StartScene();
g_device->Clear(
0,
nullptr,
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_ARGB(255, static_cast<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_ZENABLE, D3DZB_TRUE);
g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
for (DWORD i = 0; i < 8; ++i) {
g_device->LightEnable(i, FALSE);
}
DWORD lightIdx = 0;
for (const auto& l : m_lights) {
for (const auto& l : g_lights) {
if (lightIdx >= 8) {
break;
}
@ -235,30 +263,16 @@ void SetupLights()
}
light.Falloff = 1.0f;
light.Phi = PI;
light.Theta = PI / 2;
light.Phi = M_PI;
light.Theta = M_PI / 2;
if (SUCCEEDED(g_device->SetLight(lightIdx, &light))) {
g_device->LightEnable(lightIdx, TRUE);
}
++lightIdx;
}
}
uint32_t Actual_BeginFrame()
{
g_device->GetRenderTarget(0, &g_oldRenderTarget);
g_device->SetRenderTarget(0, g_renderTargetSurf);
g_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0);
g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
g_device->BeginScene();
SetupLights();
g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
return D3D_OK;
}
@ -286,15 +300,19 @@ D3DMATRIX ToD3DMATRIX(const Matrix4x4& in)
void Actual_SubmitDraw(
const D3D9MeshCacheEntry* mesh,
const Matrix4x4* modelViewMatrix,
const Matrix4x4* worldMatrix,
const Matrix4x4* viewMatrix,
const Matrix3x3* normalMatrix,
const Appearance* appearance,
IDirect3DTexture9* texture
)
{
D3DMATRIX worldView = ToD3DMATRIX(*modelViewMatrix);
g_device->SetTransform(D3DTS_WORLD, &worldView);
D3DMATRIX proj = ToD3DMATRIX(m_projection);
D3DMATRIX proj = ToD3DMATRIX(g_projection);
g_device->SetTransform(D3DTS_PROJECTION, &proj);
D3DMATRIX view = ToD3DMATRIX(*viewMatrix);
g_device->SetTransform(D3DTS_VIEW, &view);
D3DMATRIX world = ToD3DMATRIX(*worldMatrix);
g_device->SetTransform(D3DTS_WORLD, &world);
D3DMATERIAL9 mat = {};
mat.Diffuse.r = appearance->color.r / 255.0f;
@ -342,44 +360,149 @@ void Actual_SubmitDraw(
g_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mesh->vertexCount, 0, mesh->indexCount / 3);
}
uint32_t Actual_FinalizeFrame(void* pixels, int pitch)
uint32_t Actual_Flip()
{
g_device->EndScene();
g_device->SetRenderTarget(0, g_oldRenderTarget);
g_oldRenderTarget->Release();
LPDIRECT3DSURFACE9 sysMemSurf;
HRESULT hr =
g_device
->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysMemSurf, nullptr);
if (FAILED(hr)) {
return hr;
}
hr = g_device->GetRenderTargetData(g_renderTargetSurf, sysMemSurf);
if (FAILED(hr)) {
sysMemSurf->Release();
return hr;
}
D3DLOCKED_RECT lockedRect;
hr = sysMemSurf->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY);
if (FAILED(hr)) {
sysMemSurf->Release();
return hr;
}
BYTE* src = static_cast<BYTE*>(lockedRect.pBits);
BYTE* dst = static_cast<BYTE*>(pixels);
int copyWidth = m_width * 4;
for (int y = 0; y < m_height; y++) {
memcpy(dst + y * pitch, src + y * lockedRect.Pitch, copyWidth);
}
sysMemSurf->UnlockRect();
sysMemSurf->Release();
return hr;
g_hasScene = false;
return g_device->Present(nullptr, nullptr, nullptr, nullptr);
}
void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
{
StartScene();
float left = -g_viewportTransform.offsetX / g_viewportTransform.scale;
float right = (g_width - g_viewportTransform.offsetX) / g_viewportTransform.scale;
float top = -g_viewportTransform.offsetY / g_viewportTransform.scale;
float bottom = (g_height - g_viewportTransform.offsetY) / g_viewportTransform.scale;
auto virtualToScreenX = [&](float x) { return ((x - left) / (right - left)) * g_width; };
auto virtualToScreenY = [&](float y) { return ((y - top) / (bottom - top)) * g_height; };
float x1_virtual = static_cast<float>(dstRect.x);
float y1_virtual = static_cast<float>(dstRect.y);
float x2_virtual = x1_virtual + dstRect.w;
float y2_virtual = y1_virtual + dstRect.h;
float x1 = virtualToScreenX(x1_virtual);
float y1 = virtualToScreenY(y1_virtual);
float x2 = virtualToScreenX(x2_virtual);
float y2 = virtualToScreenY(y2_virtual);
D3DMATRIX identity =
{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
g_device->SetTransform(D3DTS_PROJECTION, &identity);
g_device->SetTransform(D3DTS_VIEW, &identity);
g_device->SetTransform(D3DTS_WORLD, &identity);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
g_device->SetRenderState(D3DRS_ZENABLE, FALSE);
g_device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
g_device->SetRenderState(D3DRS_LIGHTING, FALSE);
g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_device->SetTexture(0, texture);
g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
D3DSURFACE_DESC texDesc;
texture->GetLevelDesc(0, &texDesc);
float texW = static_cast<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(
const D3D9MeshCacheEntry* mesh,
const Matrix4x4* modelViewMatrix,
const Matrix4x4* worldMatrix,
const Matrix4x4* viewMatrix,
const Matrix3x3* normalMatrix,
const Appearance* appearance,
IDirect3DTexture9* texture
);
uint32_t Actual_FinalizeFrame(void* pixels, int pitch);
void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform);
void Actual_Clear(float r, float g, float b);
uint32_t Actual_Flip();
void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect);
uint32_t Actual_Download(SDL_Surface* target);

View File

@ -20,14 +20,18 @@ Direct3DRMRenderer* DirectX9Renderer::Create(DWORD width, DWORD height)
return new DirectX9Renderer(width, height);
}
DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height) : m_width(width), m_height(height)
DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height)
{
m_width = width;
m_height = height;
m_virtualWidth = width;
m_virtualHeight = height;
Actual_Initialize(
SDL_GetPointerProperty(SDL_GetWindowProperties(DDWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL),
width,
height
);
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ARGB8888);
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
}
DirectX9Renderer::~DirectX9Renderer()
@ -212,16 +216,6 @@ Uint32 DirectX9Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshG
return static_cast<Uint32>(m_meshs.size() - 1);
}
DWORD DirectX9Renderer::GetWidth()
{
return m_width;
}
DWORD DirectX9Renderer::GetHeight()
{
return m_height;
}
void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{
halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -253,6 +247,8 @@ void DirectX9Renderer::EnableTransparency()
void DirectX9Renderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
@ -261,17 +257,46 @@ void DirectX9Renderer::SubmitDraw(
if (appearance.textureId != NO_TEXTURE_ID) {
texture = m_textures[appearance.textureId].dxTexture;
}
Actual_SubmitDraw(&m_meshs[meshId], &modelViewMatrix, &normalMatrix, &appearance, texture);
Actual_SubmitDraw(
&m_meshs[meshId],
&modelViewMatrix,
&worldMatrix,
&viewMatrix,
&normalMatrix,
&appearance,
texture
);
}
HRESULT DirectX9Renderer::FinalizeFrame()
{
HRESULT hr = Actual_FinalizeFrame(m_renderedImage->pixels, m_renderedImage->pitch);
if (hr != DD_OK) {
return hr;
}
// Composite onto SDL backbuffer
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr);
return hr;
return DD_OK;
}
void DirectX9Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
m_width = width;
m_height = height;
m_viewportTransform = viewportTransform;
Actual_Resize(width, height, viewportTransform);
}
void DirectX9Renderer::Clear(float r, float g, float b)
{
Actual_Clear(r, g, b);
}
void DirectX9Renderer::Flip()
{
Actual_Flip();
}
void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
{
Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect);
}
void DirectX9Renderer::Download(SDL_Surface* target)
{
Actual_Download(target);
}

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_MAJOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_Window* window = DDWindow;
bool testWindow = false;
if (!window) {
window = SDL_CreateWindow("OpenGL 1.2 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
window = SDL_CreateWindow("OpenGL 1.1 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
if (!window) {
SDL_Log("SDL_CreateWindow: %s", SDL_GetError());
return nullptr;
}
testWindow = true;
}
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GLContext context = SDL_GL_CreateContext(window);
if (!context) {
SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
@ -33,18 +40,16 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
}
if (!SDL_GL_MakeCurrent(window, context)) {
return nullptr;
}
GLenum err = glewInit();
if (err != GLEW_OK) {
SDL_Log("SDL_GL_MakeCurrent: %s", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
if (!GLEW_EXT_framebuffer_object) {
GLenum err = glewInit();
if (err != GLEW_OK) {
SDL_Log("glewInit: %s", glewGetErrorString(err));
if (testWindow) {
SDL_DestroyWindow(window);
}
@ -53,65 +58,37 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
// Setup FBO
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create color texture
GLuint colorTex;
glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
// Create depth renderbuffer
GLuint depthRb;
glGenRenderbuffers(1, &depthRb);
glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return nullptr;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glFrontFace(GL_CW);
if (testWindow) {
SDL_DestroyWindow(window);
}
return new OpenGL1Renderer(width, height, context, fbo, colorTex, depthRb);
return new OpenGL1Renderer(width, height, context);
}
OpenGL1Renderer::OpenGL1Renderer(
DWORD width,
DWORD height,
SDL_GLContext context,
GLuint fbo,
GLuint colorTex,
GLuint depthRb
)
: m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb)
OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context) : m_context(context)
{
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888);
m_width = width;
m_height = height;
m_virtualWidth = width;
m_virtualHeight = height;
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
m_useVBOs = GLEW_ARB_vertex_buffer_object;
}
OpenGL1Renderer::~OpenGL1Renderer()
{
SDL_DestroySurface(m_renderedImage);
glDeleteFramebuffers(1, &m_fbo);
glDeleteRenderbuffers(1, &m_depthRb);
glDeleteTextures(1, &m_colorTex);
}
void OpenGL1Renderer::PushLights(const SceneLight* lightsArray, size_t count)
{
if (count > 8) {
SDL_Log("Unsupported number of lights (%d)", static_cast<int>(count));
count = 8;
}
m_lights.assign(lightsArray, lightsArray + count);
}
@ -122,7 +99,6 @@ void OpenGL1Renderer::SetFrustumPlanes(const Plane* frustumPlanes)
void OpenGL1Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
m_projection[1][1] *= -1.0f; // OpenGL is upside down
}
struct TextureDestroyContextGL {
@ -161,14 +137,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &tex.glTextureId);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
if (!surf) {
return NO_TEXTURE_ID;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
SDL_DestroySurface(surf);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
tex.version = texture->m_version;
}
@ -180,14 +154,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
if (!surf) {
return NO_TEXTURE_ID;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
SDL_DestroySurface(surf);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i];
@ -260,7 +232,7 @@ GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs)
glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals);
glBufferData(GL_ARRAY_BUFFER, cache.normals.size() * sizeof(D3DVECTOR), cache.normals.data(), GL_STATIC_DRAW);
if (meshGroup.texture != nullptr) {
if (meshGroup.texture) {
glGenBuffers(1, &cache.vboTexcoords);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords);
glBufferData(
@ -337,16 +309,6 @@ Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGr
return (Uint32) (m_meshs.size() - 1);
}
DWORD OpenGL1Renderer::GetWidth()
{
return m_width;
}
DWORD OpenGL1Renderer::GetHeight()
{
return m_height;
}
void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{
halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -362,14 +324,12 @@ void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
const char* OpenGL1Renderer::GetName()
{
return "OpenGL 1.2 HAL";
return "OpenGL 1.1 HAL";
}
HRESULT OpenGL1Renderer::BeginFrame()
{
SDL_GL_MakeCurrent(DDWindow, m_context);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(0, 0, m_width, m_height);
m_dirty = true;
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
@ -378,16 +338,12 @@ HRESULT OpenGL1Renderer::BeginFrame()
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Disable all lights and reset global ambient
for (int i = 0; i < 8; ++i) {
glDisable(GL_LIGHT0 + i);
}
const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient);
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
// Setup lights
@ -462,15 +418,14 @@ void OpenGL1Renderer::EnableTransparency()
void OpenGL1Renderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
{
auto& mesh = m_meshs[meshId];
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf(&modelViewMatrix[0][0]);
glEnable(GL_NORMALIZE);
@ -496,6 +451,8 @@ void OpenGL1Renderer::SubmitDraw(
// Bind texture if present
if (appearance.textureId != NO_TEXTURE_ID) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
auto& tex = m_textures[appearance.textureId];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
@ -542,11 +499,130 @@ void OpenGL1Renderer::SubmitDraw(
HRESULT OpenGL1Renderer::FinalizeFrame()
{
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Composite onto SDL backbuffer
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr);
return DD_OK;
}
void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
m_width = width;
m_height = height;
m_viewportTransform = viewportTransform;
SDL_DestroySurface(m_renderedImage);
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
glViewport(0, 0, m_width, m_height);
}
void OpenGL1Renderer::Clear(float r, float g, float b)
{
m_dirty = true;
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glClearColor(r, g, b, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void OpenGL1Renderer::Flip()
{
if (m_dirty) {
SDL_GL_SwapWindow(DDWindow);
m_dirty = false;
}
}
void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
{
m_dirty = true;
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
float left = -m_viewportTransform.offsetX / m_viewportTransform.scale;
float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale;
float top = -m_viewportTransform.offsetY / m_viewportTransform.scale;
float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale;
glOrtho(left, right, bottom, top, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_LIGHTING);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textures[textureId].glTextureId);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLint boundTexture = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture);
GLfloat texW, texH;
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW);
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH);
float u1 = srcRect.x / texW;
float v1 = srcRect.y / texH;
float u2 = (srcRect.x + srcRect.w) / texW;
float v2 = (srcRect.y + srcRect.h) / texH;
float x1 = (float) dstRect.x;
float y1 = (float) dstRect.y;
float x2 = x1 + dstRect.w;
float y2 = y1 + dstRect.h;
glBegin(GL_QUADS);
glTexCoord2f(u1, v1);
glVertex2f(x1, y1);
glTexCoord2f(u2, v1);
glVertex2f(x2, y1);
glTexCoord2f(u2, v2);
glVertex2f(x2, y2);
glTexCoord2f(u1, v2);
glVertex2f(x1, y2);
glEnd();
// Restore state
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void OpenGL1Renderer::Download(SDL_Surface* target)
{
glFinish();
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
SDL_Rect srcRect = {
static_cast<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;
}
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GLContext context = SDL_GL_CreateContext(window);
if (!context) {
if (testWindow) {
@ -50,51 +52,16 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
}
if (!SDL_GL_MakeCurrent(window, context)) {
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
// Setup FBO
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Create color texture
GLuint colorTex;
glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
// Create depth renderbuffer
GLuint depthRb;
glGenRenderbuffers(1, &depthRb);
glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
const char* extensions = (const char*) glGetString(GL_EXTENSIONS);
if (extensions) {
if (strstr(extensions, "GL_OES_depth24")) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, width, height);
}
else if (strstr(extensions, "GL_OES_depth32")) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32_OES, width, height);
}
}
else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return nullptr;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glFrontFace(GL_CW);
const char* vertexShaderSource = R"(
attribute vec3 a_position;
@ -183,6 +150,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
if (u_useTexture != 0) {
vec4 texel = texture2D(u_texture, v_texCoord);
finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0);
finalColor.a = texel.a;
}
gl_FragColor = finalColor;
@ -206,31 +174,23 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
SDL_DestroyWindow(window);
}
return new OpenGLES2Renderer(width, height, context, fbo, colorTex, depthRb, shaderProgram);
return new OpenGLES2Renderer(width, height, context, shaderProgram);
}
OpenGLES2Renderer::OpenGLES2Renderer(
DWORD width,
DWORD height,
SDL_GLContext context,
GLuint fbo,
GLuint colorTex,
GLuint depthRb,
GLuint shaderProgram
)
: m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb),
m_shaderProgram(shaderProgram)
OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram)
: m_context(context), m_shaderProgram(shaderProgram)
{
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888);
m_width = width;
m_height = height;
m_virtualWidth = width;
m_virtualHeight = height;
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
}
OpenGLES2Renderer::~OpenGLES2Renderer()
{
SDL_DestroySurface(m_renderedImage);
glDeleteFramebuffers(1, &m_fbo);
glDeleteRenderbuffers(1, &m_depthRb);
glDeleteProgram(m_shaderProgram);
glDeleteTextures(1, &m_colorTex);
}
void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count)
@ -250,7 +210,6 @@ void OpenGLES2Renderer::SetFrustumPlanes(const Plane* frustumPlanes)
void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
m_projection[1][1] *= -1.0f; // OpenGL is upside down
}
struct TextureDestroyContextGLS2 {
@ -289,14 +248,12 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &tex.glTextureId);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
if (!surf) {
return NO_TEXTURE_ID;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
SDL_DestroySurface(surf);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
tex.version = texture->m_version;
}
@ -308,14 +265,11 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888);
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
if (!surf) {
return NO_TEXTURE_ID;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
SDL_DestroySurface(surf);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i];
@ -323,12 +277,15 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
tex.texture = texture;
tex.version = texture->m_version;
tex.glTextureId = texId;
tex.width = surf->w;
tex.height = surf->h;
AddTextureDestroyCallback(i, texture);
return i;
}
}
m_textures.push_back({texture, texture->m_version, texId});
m_textures.push_back({texture, texture->m_version, texId, (uint16_t) surf->w, (uint16_t) surf->h});
SDL_DestroySurface(surf);
AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture);
return (Uint32) (m_textures.size() - 1);
}
@ -366,7 +323,6 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup)
return v.texCoord;
});
}
std::vector<D3DVECTOR> positions(vertices.size());
std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) {
return v.position;
@ -451,16 +407,6 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh
return (Uint32) (m_meshs.size() - 1);
}
DWORD OpenGLES2Renderer::GetWidth()
{
return m_width;
}
DWORD OpenGLES2Renderer::GetHeight()
{
return m_height;
}
void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{
halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -490,9 +436,7 @@ const char* OpenGLES2Renderer::GetName()
HRESULT OpenGLES2Renderer::BeginFrame()
{
SDL_GL_MakeCurrent(DDWindow, m_context);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(0, 0, m_width, m_height);
m_dirty = true;
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
@ -500,9 +444,6 @@ HRESULT OpenGLES2Renderer::BeginFrame()
glUseProgram(m_shaderProgram);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SceneLightGLES2 lightData[3];
int lightCount = std::min(static_cast<int>(m_lights.size()), 3);
@ -531,7 +472,6 @@ HRESULT OpenGLES2Renderer::BeginFrame()
glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()), 1, lightData[i].direction);
}
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), lightCount);
return DD_OK;
}
@ -545,6 +485,8 @@ void OpenGLES2Renderer::EnableTransparency()
void OpenGLES2Renderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
@ -570,6 +512,8 @@ void OpenGLES2Renderer::SubmitDraw(
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId);
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else {
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 0);
@ -606,11 +550,168 @@ HRESULT OpenGLES2Renderer::FinalizeFrame()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0);
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Composite onto SDL backbuffer
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr);
return DD_OK;
}
void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
m_width = width;
m_height = height;
m_viewportTransform = viewportTransform;
SDL_DestroySurface(m_renderedImage);
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
glViewport(0, 0, m_width, m_height);
}
void OpenGLES2Renderer::Clear(float r, float g, float b)
{
m_dirty = true;
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glClearColor(r, g, b, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void OpenGLES2Renderer::Flip()
{
if (m_dirty) {
SDL_GL_SwapWindow(DDWindow);
m_dirty = false;
}
}
void CreateOrthoMatrix(float left, float right, float bottom, float top, D3DRMMATRIX4D& outMatrix)
{
float near = -1.0f;
float far = 1.0f;
float rl = right - left;
float tb = top - bottom;
float fn = far - near;
outMatrix[0][0] = 2.0f / rl;
outMatrix[0][1] = 0.0f;
outMatrix[0][2] = 0.0f;
outMatrix[0][3] = 0.0f;
outMatrix[1][0] = 0.0f;
outMatrix[1][1] = 2.0f / tb;
outMatrix[1][2] = 0.0f;
outMatrix[1][3] = 0.0f;
outMatrix[2][0] = 0.0f;
outMatrix[2][1] = 0.0f;
outMatrix[2][2] = -2.0f / fn;
outMatrix[2][3] = 0.0f;
outMatrix[3][0] = -(right + left) / rl;
outMatrix[3][1] = -(top + bottom) / tb;
outMatrix[3][2] = -(far + near) / fn;
outMatrix[3][3] = 1.0f;
}
void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
{
m_dirty = true;
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glUseProgram(m_shaderProgram);
float color[] = {1.0f, 1.0f, 1.0f, 1.0f};
float blank[] = {0.0f, 0.0f, 0.0f, 0.0f};
glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].color"), 1, color);
glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].position"), 1, blank);
glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].direction"), 1, blank);
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), 1);
glUniform4f(glGetUniformLocation(m_shaderProgram, "u_color"), 1.0f, 1.0f, 1.0f, 1.0f);
glUniform1f(glGetUniformLocation(m_shaderProgram, "u_shininess"), 0.0f);
float left = -m_viewportTransform.offsetX / m_viewportTransform.scale;
float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale;
float top = -m_viewportTransform.offsetY / m_viewportTransform.scale;
float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale;
D3DRMMATRIX4D projection;
CreateOrthoMatrix(left, right, bottom, top, projection);
D3DRMMATRIX4D identity = {{1.f, 0.f, 0.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}};
glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_modelViewMatrix"), 1, GL_FALSE, &identity[0][0]);
glUniformMatrix3fv(glGetUniformLocation(m_shaderProgram, "u_normalMatrix"), 1, GL_FALSE, &identity[0][0]);
glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"), 1, GL_FALSE, &projection[0][0]);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 1);
const GLES2TextureCacheEntry& texture = m_textures[textureId];
glBindTexture(GL_TEXTURE_2D, texture.glTextureId);
glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
float texW = texture.width;
float texH = texture.height;
float u1 = srcRect.x / texW;
float v1 = srcRect.y / texH;
float u2 = (srcRect.x + srcRect.w) / texW;
float v2 = (srcRect.y + srcRect.h) / texH;
float x1 = static_cast<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 <SDL3/SDL.h>
#include <cmath>
#include <cstddef>
struct ScopedSurface {
@ -91,7 +92,12 @@ struct ScopedShader {
void release() { ptr = nullptr; }
};
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device, bool depthWrite)
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(
SDL_GPUDevice* device,
SDL_Window* window,
bool depthTest,
bool depthWrite
)
{
const SDL_GPUShaderCreateInfo* vertexCreateInfo =
GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device));
@ -141,8 +147,8 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
vertexInputState.num_vertex_attributes = SDL_arraysize(vertexAttrs);
SDL_GPUColorTargetDescription colorTargets = {};
colorTargets.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
if (depthWrite) {
colorTargets.format = SDL_GetGPUSwapchainTextureFormat(device, window);
if (depthTest && depthWrite) {
colorTargets.blend_state.enable_blend = false;
}
else {
@ -170,7 +176,7 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
pipelineCreateInfo.rasterizer_state = rasterizerState;
pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_GREATER;
pipelineCreateInfo.depth_stencil_state.write_mask = 0xff;
pipelineCreateInfo.depth_stencil_state.enable_depth_test = true;
pipelineCreateInfo.depth_stencil_state.enable_depth_test = depthTest;
pipelineCreateInfo.depth_stencil_state.enable_depth_write = depthWrite;
pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false;
pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets;
@ -178,16 +184,18 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
pipelineCreateInfo.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT;
pipelineCreateInfo.target_info.has_depth_stencil_target = true;
SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo);
return pipeline;
return SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo);
}
Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
{
ScopedDevice device{SDL_CreateGPUDevice(
SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL,
#ifdef DEBUG
true,
#else
false,
#endif
nullptr
)};
if (!device.ptr) {
@ -195,63 +203,63 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
return nullptr;
}
ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, true)};
SDL_Window* window = DDWindow;
bool testWindow = false;
if (!window) {
window = SDL_CreateWindow("SDL_GPU test", width, height, SDL_WINDOW_HIDDEN);
if (!window) {
SDL_Log("SDL_CreateWindow: %s", SDL_GetError());
return nullptr;
}
testWindow = true;
}
if (!SDL_ClaimWindowForGPUDevice(device.ptr, window)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ClaimWindowForGPUDevice: %s", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, true)};
if (!opaquePipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline");
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, false)};
ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, false)};
if (!transparentPipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline");
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
textureInfo.width = width;
textureInfo.height = height;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
textureInfo.sample_count = SDL_GPU_SAMPLECOUNT_1;
ScopedTexture transferTexture{device.ptr, SDL_CreateGPUTexture(device.ptr, &textureInfo)};
if (!transferTexture.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError());
return nullptr;
}
SDL_GPUTextureCreateInfo depthTexInfo = textureInfo;
depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT;
depthTexInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET;
ScopedTexture depthTexture{device.ptr, SDL_CreateGPUTexture(device.ptr, &depthTexInfo)};
if (!depthTexture.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError());
return nullptr;
}
// Setup texture GPU-to-CPU transfer
SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {};
downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
downloadBufferInfo.size = width * height * 4;
ScopedTransferBuffer downloadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &downloadBufferInfo)};
if (!downloadBuffer.ptr) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer filed for download buffer (%s)",
SDL_GetError()
);
ScopedPipeline uiPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, false, false)};
if (!uiPipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for uiPipeline");
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
// Setup texture CPU-to-GPU transfer
SDL_GPUTransferBufferCreateInfo uploadBufferInfo = {};
uploadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
uploadBufferInfo.size = 256 * 256 * 4; // Largest known game texture
int uploadBufferSize = 640 * 480 * 4; // Largest known game texture
uploadBufferInfo.size = uploadBufferSize;
ScopedTransferBuffer uploadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &uploadBufferInfo)};
if (!uploadBuffer.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer filed for upload buffer (%s)", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
@ -265,31 +273,54 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)};
if (!sampler.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
SDL_GPUSamplerCreateInfo uiSamplerInfo = {};
uiSamplerInfo.min_filter = SDL_GPU_FILTER_LINEAR;
uiSamplerInfo.mag_filter = SDL_GPU_FILTER_NEAREST;
uiSamplerInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR;
uiSamplerInfo.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
uiSamplerInfo.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
uiSamplerInfo.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
ScopedSampler uiSampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &uiSamplerInfo)};
if (!uiSampler.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError());
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
if (testWindow) {
SDL_ReleaseWindowFromGPUDevice(device.ptr, window);
SDL_DestroyWindow(window);
}
auto renderer = new Direct3DRMSDL3GPURenderer(
width,
height,
device.ptr,
opaquePipeline.ptr,
transparentPipeline.ptr,
transferTexture.ptr,
depthTexture.ptr,
uiPipeline.ptr,
sampler.ptr,
uiSampler.ptr,
uploadBuffer.ptr,
downloadBuffer.ptr
uploadBufferSize
);
// Release resources so they don't get cleaned up
device.release();
opaquePipeline.release();
transparentPipeline.release();
transferTexture.release();
depthTexture.release();
uiPipeline.release();
sampler.release();
uiSampler.release();
uploadBuffer.release();
downloadBuffer.release();
return renderer;
}
@ -300,17 +331,21 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
SDL_GPUDevice* device,
SDL_GPUGraphicsPipeline* opaquePipeline,
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUGraphicsPipeline* uiPipeline,
SDL_GPUSampler* sampler,
SDL_GPUSampler* uiSampler,
SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer
int uploadBufferSize
)
: m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline),
m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture),
m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer)
: m_device(device), m_opaquePipeline(opaquePipeline), m_transparentPipeline(transparentPipeline),
m_uiPipeline(uiPipeline), m_sampler(sampler), m_uiSampler(uiSampler), m_uploadBuffer(uploadBuffer),
m_uploadBufferSize(uploadBufferSize)
{
SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ABGR8888);
m_width = width;
m_height = height;
m_virtualWidth = width;
m_virtualHeight = height;
SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_RGBA32);
if (!dummySurface) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError());
return;
@ -324,35 +359,67 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
SDL_UnlockSurface(dummySurface);
m_dummyTexture = CreateTextureFromSurface(dummySurface);
if (!m_dummyTexture) {
SDL_DestroySurface(dummySurface);
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError());
return;
}
SDL_DestroySurface(dummySurface);
ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f};
Resize(m_width, m_height, viewportTransform);
m_uiMesh.vertices = {
{{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}},
{{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}},
{{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}},
{{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}}
};
m_uiMesh.indices = {0, 1, 2, 0, 2, 3};
m_uiMeshCache = UploadMesh(m_uiMesh);
}
Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer()
{
SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer);
SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.vertexBuffer);
SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.indexBuffer);
if (DDWindow) {
SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow);
}
if (m_downloadBuffer) {
SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer);
}
if (m_uploadBuffer) {
SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer);
}
SDL_ReleaseGPUSampler(m_device, m_sampler);
SDL_ReleaseGPUTexture(m_device, m_dummyTexture);
SDL_ReleaseGPUTexture(m_device, m_depthTexture);
SDL_ReleaseGPUTexture(m_device, m_transferTexture);
SDL_ReleaseGPUSampler(m_device, m_uiSampler);
if (m_dummyTexture) {
SDL_ReleaseGPUTexture(m_device, m_dummyTexture);
}
if (m_depthTexture) {
SDL_ReleaseGPUTexture(m_device, m_depthTexture);
}
if (m_transferTexture) {
SDL_ReleaseGPUTexture(m_device, m_transferTexture);
}
SDL_ReleaseGPUGraphicsPipeline(m_device, m_opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_uiPipeline);
if (m_uploadFence) {
SDL_ReleaseGPUFence(m_device, m_uploadFence);
}
SDL_DestroyGPUDevice(m_device);
}
void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* vertices, size_t count)
void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* lights, size_t count)
{
if (count > 3) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Unsupported number of lights (%d)", static_cast<int>(count));
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;
}
@ -364,7 +431,7 @@ void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D
{
m_front = front;
m_back = back;
memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D));
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
}
void Direct3DRMSDL3GPURenderer::WaitForPendingUpload()
@ -405,7 +472,7 @@ void Direct3DRMSDL3GPURenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRM
SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* surface)
{
ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888)};
ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32)};
if (!surf.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError());
return nullptr;
@ -607,6 +674,7 @@ void Direct3DRMSDL3GPURenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMes
auto* ctx = static_cast<SDLMeshDestroyContext*>(arg);
auto& cache = ctx->renderer->m_meshs[ctx->id];
SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer);
SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.indexBuffer);
cache.meshGroup = nullptr;
delete ctx;
},
@ -621,6 +689,7 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer);
SDL_ReleaseGPUBuffer(m_device, cache.indexBuffer);
cache = std::move(UploadMesh(*meshGroup));
}
return i;
@ -643,16 +712,6 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro
return (Uint32) (m_meshs.size() - 1);
}
DWORD Direct3DRMSDL3GPURenderer::GetWidth()
{
return m_width;
}
DWORD Direct3DRMSDL3GPURenderer::GetHeight()
{
return m_height;
}
void Direct3DRMSDL3GPURenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{
halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
@ -708,32 +767,45 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
return m_uploadBuffer;
}
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame()
void Direct3DRMSDL3GPURenderer::StartRenderPass(float r, float g, float b, bool clear)
{
if (!DDBackBuffer) {
return DDERR_GENERIC;
m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!m_cmdbuf) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_AcquireGPUCommandBuffer in StartRenderPass failed (%s)",
SDL_GetError()
);
return;
}
// Clear color and depth targets
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.clear_color = {0, 0, 0, 0};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
colorTargetInfo.clear_color = {r, g, b, 1.0f};
colorTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.clear_depth = 0.0f;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
depthStencilTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!m_cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in BeginFrame failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
m_renderPass = SDL_BeginGPURenderPass(m_cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
}
void Direct3DRMSDL3GPURenderer::Clear(float r, float g, float b)
{
StartRenderPass(r, g, b, true);
}
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame()
{
if (!m_renderPass) {
StartRenderPass(0, 0, 0, false);
}
SDL_BindGPUGraphicsPipeline(m_renderPass, m_opaquePipeline);
memcpy(&m_uniforms.projection, m_projection, sizeof(D3DRMMATRIX4D));
return DD_OK;
}
@ -746,6 +818,8 @@ void Direct3DRMSDL3GPURenderer::EnableTransparency()
void Direct3DRMSDL3GPURenderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
@ -774,15 +848,210 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw(
HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
{
SDL_EndGPURenderPass(m_renderPass);
m_renderPass = nullptr;
return DD_OK;
}
void Direct3DRMSDL3GPURenderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
m_width = width;
m_height = height;
m_viewportTransform = viewportTransform;
if (!DDWindow) {
return;
}
if (m_transferTexture) {
SDL_ReleaseGPUTexture(m_device, m_transferTexture);
}
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GetGPUSwapchainTextureFormat(m_device, DDWindow);
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER;
textureInfo.width = m_width;
textureInfo.height = m_height;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
textureInfo.sample_count = SDL_GPU_SAMPLECOUNT_1;
m_transferTexture = SDL_CreateGPUTexture(m_device, &textureInfo);
if (!m_transferTexture) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError());
return;
}
if (m_depthTexture) {
SDL_ReleaseGPUTexture(m_device, m_depthTexture);
}
SDL_GPUTextureCreateInfo depthTexInfo = textureInfo;
depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT;
depthTexInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET;
m_depthTexture = SDL_CreateGPUTexture(m_device, &depthTexInfo);
if (!m_depthTexture) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError());
return;
}
// Setup texture GPU-to-CPU transfer
SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {};
downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
downloadBufferInfo.size =
((m_width - (m_viewportTransform.offsetX * 2)) * (m_height - (m_viewportTransform.offsetY * 2))) * 4;
m_downloadBuffer = SDL_CreateGPUTransferBuffer(m_device, &downloadBufferInfo);
if (!m_downloadBuffer) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer filed for download buffer (%s)",
SDL_GetError()
);
return;
}
}
void Direct3DRMSDL3GPURenderer::Flip()
{
if (!m_cmdbuf) {
return;
}
if (m_renderPass) {
SDL_EndGPURenderPass(m_renderPass);
m_renderPass = nullptr;
}
SDL_GPUTexture* swapchainTexture;
if (!SDL_WaitAndAcquireGPUSwapchainTexture(m_cmdbuf, DDWindow, &swapchainTexture, nullptr, nullptr) ||
!swapchainTexture) {
SDL_Log("SDL_WaitAndAcquireGPUSwapchainTexture: %s", SDL_GetError());
return;
}
SDL_GPUBlitInfo blit = {};
blit.source.texture = m_transferTexture;
blit.source.w = m_width;
blit.source.h = m_height;
blit.destination.texture = swapchainTexture;
blit.destination.w = m_width;
blit.destination.h = m_height;
blit.load_op = SDL_GPU_LOADOP_DONT_CARE;
blit.flip_mode = SDL_FLIP_NONE;
blit.filter = SDL_GPU_FILTER_NEAREST;
blit.cycle = false;
SDL_BlitGPUTexture(m_cmdbuf, &blit);
SDL_SubmitGPUCommandBuffer(m_cmdbuf);
m_cmdbuf = nullptr;
}
// TODO use SDL_SetGPUScissor(SDL_GPURenderPass *render_pass, const SDL_Rect *scissor) when srcRect isn't 100% of
// texture
void Create2DTransformMatrix(
const SDL_Rect& dstRect,
float scale,
float offsetX,
float offsetY,
D3DRMMATRIX4D& outMatrix
)
{
float x = static_cast<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 = {};
region.texture = m_transferTexture;
region.w = m_width;
region.h = m_height;
region.x = offsetX;
region.y = offsetY;
region.w = width;
region.h = height;
region.d = 1;
SDL_GPUTextureTransferInfo transferInfo = {};
transferInfo.transfer_buffer = m_downloadBuffer;
@ -792,27 +1061,24 @@ HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
WaitForPendingUpload();
// Render the frame
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf);
m_cmdbuf = nullptr;
if (!fence) {
return DDERR_GENERIC;
if (!fence || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) {
SDL_ReleaseGPUFence(m_device, fence);
return;
}
bool success = SDL_WaitForGPUFences(m_device, true, &fence, 1);
SDL_ReleaseGPUFence(m_device, fence);
if (!success) {
return DDERR_GENERIC;
}
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false);
if (!downloadedData) {
return DDERR_GENERIC;
return;
}
SDL_Surface* renderedImage =
SDL_CreateSurfaceFrom(m_width, m_height, SDL_PIXELFORMAT_ABGR8888, downloadedData, m_width * 4);
SDL_BlitSurface(renderedImage, nullptr, DDBackBuffer, nullptr);
SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_ARGB8888, downloadedData, width * 4);
SDL_BlitSurfaceScaled(renderedImage, nullptr, target, nullptr, SDL_SCALEMODE_NEAREST);
SDL_DestroySurface(renderedImage);
SDL_UnmapGPUTransferBuffer(m_device, m_downloadBuffer);
return DD_OK;
}

View File

@ -10,9 +10,9 @@
// DXIL only makes sense on Windows platforms
#if defined(SDL_PLATFORM_WINDOWS)
static const Uint8 SolidColor_frag_dxil[6640] = {
0x44, 0x58, 0x42, 0x43, 0x91, 0x24, 0xbe, 0xd8, 0x43, 0x8d, 0x7f, 0xf4, 0x71, 0x2b, 0x59, 0x98,
0x2d, 0x7f, 0x8d, 0xac, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
static const Uint8 SolidColor_frag_dxil[6648] = {
0x44, 0x58, 0x42, 0x43, 0xd8, 0xfe, 0x4c, 0xec, 0x17, 0x1b, 0x52, 0xee, 0xf7, 0xc8, 0x8d, 0xcf,
0x47, 0x0e, 0xfe, 0xb7, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00,
0xc4, 0x02, 0x00, 0x00, 0x94, 0x0c, 0x00, 0x00, 0xb0, 0x0c, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31,
@ -52,7 +52,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = {
0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x10,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x11,
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xc8, 0x09, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
@ -113,9 +113,9 @@ static const Uint8 SolidColor_frag_dxil[6640] = {
0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x18, 0x8a, 0xa0, 0x24,
0xca, 0xa0, 0x80, 0x05, 0x0a, 0xac, 0x1c, 0x4a, 0xa3, 0x10, 0x0a, 0xa4, 0x80, 0x0a, 0x54, 0xa0,
0x50, 0x05, 0x0a, 0x56, 0xa0, 0x14, 0x0a, 0x57, 0xa0, 0x20, 0xca, 0xa3, 0x06, 0xca, 0x34, 0xa0,
0x24, 0x07, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81,
0x2c, 0x07, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81,
0x1a, 0xa0, 0xad, 0x06, 0x48, 0x9c, 0x01, 0xa0, 0x71, 0x06, 0x80, 0xca, 0x19, 0x00, 0x32, 0x67,
0x00, 0x08, 0x9d, 0x01, 0xa0, 0x74, 0x2c, 0x09, 0x22, 0x8e, 0xe3, 0x00, 0x8e, 0x03, 0x00, 0x8e,
0x00, 0x08, 0x9d, 0x01, 0xa0, 0x74, 0x2c, 0x09, 0x22, 0x8e, 0xe3, 0x00, 0x9e, 0x07, 0x00, 0x8e,
0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b,
0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb9, 0xc1, 0xc9,
@ -213,10 +213,10 @@ static const Uint8 SolidColor_frag_dxil[6640] = {
0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x04, 0xcf, 0x70,
0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x06, 0x40, 0x30, 0x00, 0xd2, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x63, 0x6a, 0xf1, 0xca, 0xdc, 0xf6, 0x75, 0x3d, 0x1e, 0x21, 0x9a, 0xb8, 0xa2, 0x91, 0xc3,
0x44, 0x58, 0x49, 0x4c, 0x38, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4e, 0x03, 0x00, 0x00,
0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x0d, 0x00, 0x00,
0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x45, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00,
0xeb, 0x0f, 0x40, 0x5f, 0x0e, 0x75, 0xec, 0xd9, 0x61, 0x1b, 0x68, 0x81, 0x54, 0xd3, 0xf4, 0x48,
0x44, 0x58, 0x49, 0x4c, 0x40, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x03, 0x00, 0x00,
0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x0d, 0x00, 0x00,
0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x47, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00,
0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49,
0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62,
0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b,
@ -272,7 +272,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = {
0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x20, 0x8a, 0xa1, 0x08,
0x4a, 0xa2, 0x0c, 0x0a, 0x58, 0xa0, 0x1c, 0xca, 0xa3, 0x06, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22,
0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, 0x1a, 0x20, 0x71, 0x06, 0x80, 0xcc, 0x19, 0x00,
0x42, 0x67, 0x00, 0x28, 0x1d, 0x4b, 0x82, 0x88, 0xe3, 0x38, 0x80, 0xe3, 0x00, 0x80, 0xe3, 0x38,
0x42, 0x67, 0x00, 0x28, 0x1d, 0x4b, 0x82, 0x88, 0xe3, 0x38, 0x80, 0xe7, 0x01, 0x80, 0xe3, 0x38,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00,
0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b,
0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb9, 0xc1, 0xc9,
@ -336,7 +336,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = {
0x9b, 0x01, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02,
0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7,
0x6d, 0x04, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x06, 0x40,
0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x13, 0x04, 0x52, 0x2c,
0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x13, 0x04, 0x52, 0x2c,
0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xb4, 0x8d, 0x00, 0x10, 0x51, 0x78, 0x05, 0x52,
0x30, 0xa5, 0x32, 0x03, 0x50, 0x76, 0x85, 0x50, 0x46, 0x85, 0x54, 0x6e, 0xa5, 0x50, 0x72, 0x25,
0x53, 0xfe, 0x03, 0xe5, 0x42, 0xc3, 0x0c, 0xc0, 0x18, 0x41, 0x48, 0x82, 0x21, 0xde, 0x8d, 0x11,
@ -413,25 +413,26 @@ static const Uint8 SolidColor_frag_dxil[6640] = {
0xc4, 0xe0, 0x00, 0x40, 0x10, 0x0c, 0x9c, 0xd8, 0x58, 0x8b, 0x21, 0x2c, 0x46, 0x13, 0xb8, 0x61,
0xb8, 0x21, 0x68, 0x0d, 0x30, 0x98, 0x65, 0x88, 0xa0, 0x60, 0xc4, 0xe0, 0x01, 0x40, 0x10, 0x0c,
0xa6, 0xd9, 0xb0, 0x0b, 0xb1, 0x08, 0x8b, 0x9d, 0xd0, 0x89, 0xb3, 0x38, 0x0b, 0xd7, 0x70, 0x0d,
0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0xb0, 0x21, 0x91,
0x8f, 0x0d, 0x89, 0x7c, 0x6c, 0x48, 0xe4, 0x33, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6e,
0xd8, 0xc5, 0xa0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b,
0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f, 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07,
0x00, 0x82, 0x60, 0xe0, 0xf8, 0x06, 0x5e, 0x0c, 0x6e, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06,
0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e,
0x0c, 0x70, 0x31, 0x4b, 0x10, 0x0d, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40,
0x64, 0xf0, 0x0c, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20,
0xe7, 0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb3, 0x31, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72,
0x1e, 0x7c, 0xe1, 0x1b, 0xbe, 0xd1, 0x1a, 0xc2, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe7,
0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb2, 0x11, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x1e,
0x7c, 0xe1, 0x1b, 0xbe, 0x11, 0x1b, 0x6a, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc8, 0x79,
0xf0, 0xc5, 0x6f, 0xf8, 0xc6, 0x6c, 0x98, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0x18, 0x4d, 0x20,
0x06, 0x23, 0x14, 0xf9, 0x18, 0xa1, 0xc8, 0xc7, 0x08, 0x45, 0x3e, 0x23, 0x06, 0x07, 0x00, 0x82,
0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f,
0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf8, 0x46, 0x5e, 0x0c, 0x6d,
0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07,
0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, 0x0c, 0x70, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06,
0x4e, 0x78, 0xec, 0xc5, 0x10, 0x17, 0xb3, 0x04, 0xd1, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c,
0x54, 0x0c, 0x06, 0x64, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c, 0x54, 0x0c, 0x1a,
0x64, 0x0b, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e,
0xb5, 0x41, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0xf1,
0x1a, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e, 0xb4,
0x21, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0x31, 0x1b,
0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe1, 0x01, 0x1e, 0xb5, 0x81,
0x16, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif
// MSL only makes sense on Apple platforms
#if defined(SDL_PLATFORM_APPLE)
static const Uint8 SolidColor_frag_msl[3333] = {
static const Uint8 SolidColor_frag_msl[3377] = {
0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x5f,
0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x3e, 0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x0a,
@ -620,32 +621,35 @@ static const Uint8 SolidColor_frag_msl[3333] = {
0x78, 0x79, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x5f, 0x36, 0x32, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28,
0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x33, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28,
0x34, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28,
0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44,
0x61, 0x74, 0x61, 0x2e, 0x55, 0x73, 0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x21,
0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a,
0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61,
0x6d, 0x70, 0x6c, 0x65, 0x28, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e,
0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44,
0x31, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x66,
0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x5f, 0x31,
0x35, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75,
0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72,
0x67, 0x65, 0x74, 0x30, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x5f, 0x31,
0x36, 0x34, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f,
0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20,
0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74,
0x3b, 0x0a, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x31, 0x36, 0x31, 0x20, 0x3d,
0x20, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28,
0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76,
0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x29, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c,
0x6f, 0x61, 0x74, 0x34, 0x28, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x6d, 0x70,
0x28, 0x5f, 0x31, 0x36, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31,
0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66,
0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x2c, 0x20, 0x5f, 0x31, 0x36,
0x31, 0x2e, 0x77, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34,
0x28, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f,
0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x30, 0x20, 0x3d,
0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67,
0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x67, 0x6c,
0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a,
0x0a,
};
#endif
static const Uint8 SolidColor_frag_spirv[4492] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xab, 0x00, 0x00, 0x00,
static const Uint8 SolidColor_frag_spirv[4616] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xb1, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
@ -902,28 +906,36 @@ static const Uint8 SolidColor_frag_spirv[4492] = {
0x16, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0xab, 0x00, 0x05, 0x00,
0x1a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x03, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00,
0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
0x9c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00,
0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00,
0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x85, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00,
0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
0x97, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00,
0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00,
0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00,
0x27, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00,
0xa7, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00,
0xa9, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x07, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
0xaa, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
0x9c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
0x9e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00,
0xa1, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00,
0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x85, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00,
0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
0xa1, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00,
0xa6, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x12, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00,
0xa6, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x9d, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00,
0x97, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00,
0xac, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00,
0x27, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00,
0xac, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00,
0xf8, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00,
0xae, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00,
0x9d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
0xb0, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00,
0xae, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00,
0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};

View File

@ -72,8 +72,11 @@ FS_Output main(FS_Input input)
if (UseTexture != 0) {
float4 texel = Texture.Sample(Sampler, input.TexCoord);
finalColor = saturate(texel.rgb * finalColor);
output.Color = float4(finalColor, texel.a);
}
else {
output.Color = float4(finalColor, Color.a);
}
output.Color = float4(finalColor, Color.a);
output.Depth = input.Position.w;
return output;
}

View File

@ -23,9 +23,22 @@
#include <wasm_simd128.h>
#endif
Direct3DRMSoftwareRenderer::Direct3DRMSoftwareRenderer(DWORD width, DWORD height) : m_width(width), m_height(height)
Direct3DRMSoftwareRenderer::Direct3DRMSoftwareRenderer(DWORD width, DWORD height)
{
m_zBuffer.resize(m_width * m_height);
m_virtualWidth = width;
m_virtualHeight = height;
m_renderer = SDL_CreateRenderer(DDWindow, NULL);
ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f};
Resize(width, height, viewportTransform);
}
Direct3DRMSoftwareRenderer::~Direct3DRMSoftwareRenderer()
{
SDL_DestroySurface(m_renderedImage);
SDL_DestroyTexture(m_uploadBuffer);
SDL_DestroyRenderer(m_renderer);
}
void Direct3DRMSoftwareRenderer::PushLights(const SceneLight* lights, size_t count)
@ -354,8 +367,8 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
c2 = ApplyLighting(v2.position, v2.normal, appearance);
}
Uint8* pixels = (Uint8*) DDBackBuffer->pixels;
int pitch = DDBackBuffer->pitch;
Uint8* pixels = (Uint8*) m_renderedImage->pixels;
int pitch = m_renderedImage->pitch;
VertexXY verts[3] = {
{p0.x, p0.y, p0.z, p0.w, c0, v0.texCoord.u, v0.texCoord.v},
@ -553,7 +566,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture)
if (texRef.version != texture->m_version) {
// Update animated textures
SDL_DestroySurface(texRef.cached);
texRef.cached = SDL_ConvertSurface(surface->m_surface, DDBackBuffer->format);
texRef.cached = SDL_ConvertSurface(surface->m_surface, m_renderedImage->format);
SDL_LockSurface(texRef.cached);
texRef.version = texture->m_version;
}
@ -561,7 +574,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture)
}
}
SDL_Surface* convertedRender = SDL_ConvertSurface(surface->m_surface, DDBackBuffer->format);
SDL_Surface* convertedRender = SDL_ConvertSurface(surface->m_surface, m_renderedImage->format);
SDL_LockSurface(convertedRender);
// Reuse freed slot
@ -651,16 +664,6 @@ Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGr
return (Uint32) (m_meshs.size() - 1);
}
DWORD Direct3DRMSoftwareRenderer::GetWidth()
{
return m_width;
}
DWORD Direct3DRMSoftwareRenderer::GetHeight()
{
return m_height;
}
void Direct3DRMSoftwareRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{
memset(halDesc, 0, sizeof(D3DDEVICEDESC));
@ -681,13 +684,13 @@ const char* Direct3DRMSoftwareRenderer::GetName()
HRESULT Direct3DRMSoftwareRenderer::BeginFrame()
{
if (!DDBackBuffer || !SDL_LockSurface(DDBackBuffer)) {
if (!m_renderedImage || !SDL_LockSurface(m_renderedImage)) {
return DDERR_GENERIC;
}
ClearZBuffer();
m_format = SDL_GetPixelFormatDetails(DDBackBuffer->format);
m_palette = SDL_GetSurfacePalette(DDBackBuffer);
m_format = SDL_GetPixelFormatDetails(m_renderedImage->format);
m_palette = SDL_GetSurfacePalette(m_renderedImage);
m_bytesPerPixel = m_format->bits_per_pixel / 8;
return DD_OK;
@ -700,6 +703,8 @@ void Direct3DRMSoftwareRenderer::EnableTransparency()
void Direct3DRMSoftwareRenderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
@ -731,7 +736,84 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
HRESULT Direct3DRMSoftwareRenderer::FinalizeFrame()
{
SDL_UnlockSurface(DDBackBuffer);
SDL_UnlockSurface(m_renderedImage);
return DD_OK;
}
void Direct3DRMSoftwareRenderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
m_viewportTransform = viewportTransform;
float aspect = static_cast<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);
*outDevice = static_cast<IDirect3DRMDevice2*>(
new Direct3DRMDevice2Impl(renderer->GetWidth(), renderer->GetHeight(), renderer)
new Direct3DRMDevice2Impl(renderer->GetVirtualWidth(), renderer->GetVirtualHeight(), renderer)
);
return DD_OK;
}
@ -143,26 +143,25 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
DDSDesc.dwSize = sizeof(DDSURFACEDESC);
surface->GetSurfaceDesc(&DDSDesc);
Direct3DRMRenderer* renderer;
if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) {
renderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) {
renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#ifdef USE_OPENGLES2
else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) {
renderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
#ifdef USE_OPENGL1
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) {
renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
#ifdef _WIN32
else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) {
renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
else {
@ -170,7 +169,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
return E_NOINTERFACE;
}
*outDevice =
static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, renderer));
static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, DDRenderer));
return DD_OK;
}
@ -181,9 +180,8 @@ HRESULT Direct3DRMImpl::CreateTexture(D3DRMIMAGE* image, IDirect3DRMTexture2** o
}
HRESULT Direct3DRMImpl::CreateTextureFromSurface(LPDIRECTDRAWSURFACE surface, IDirect3DRMTexture2** outTexture)
{
*outTexture = static_cast<IDirect3DRMTexture2*>(new Direct3DRMTextureImpl(surface));
*outTexture = static_cast<IDirect3DRMTexture2*>(new Direct3DRMTextureImpl(surface, true));
return DD_OK;
}

View File

@ -11,8 +11,9 @@
#include <SDL3/SDL.h>
Direct3DRMDevice2Impl::Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer)
: m_width(width), m_height(height), m_renderer(renderer), m_viewports(new Direct3DRMViewportArrayImpl)
: m_virtualWidth(width), m_virtualHeight(height), m_renderer(renderer), m_viewports(new Direct3DRMViewportArrayImpl)
{
Resize();
}
Direct3DRMDevice2Impl::~Direct3DRMDevice2Impl()
@ -43,16 +44,6 @@ HRESULT Direct3DRMDevice2Impl::QueryInterface(const GUID& riid, void** ppvObject
return E_NOINTERFACE;
}
DWORD Direct3DRMDevice2Impl::GetWidth()
{
return m_width;
}
DWORD Direct3DRMDevice2Impl::GetHeight()
{
return m_height;
}
HRESULT Direct3DRMDevice2Impl::SetBufferCount(int count)
{
MINIWIN_NOT_IMPLEMENTED();
@ -133,7 +124,9 @@ HRESULT Direct3DRMDevice2Impl::Update()
HRESULT Direct3DRMDevice2Impl::AddViewport(IDirect3DRMViewport* viewport)
{
return m_viewports->AddElement(viewport);
HRESULT status = m_viewports->AddElement(viewport);
Resize();
return status;
}
HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewportArray)
@ -143,7 +136,53 @@ HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewpor
return DD_OK;
}
ViewportTransform CalculateViewportTransform(int virtualW, int virtualH, int windowW, int windowH)
{
float scaleX = (float) windowW / virtualW;
float scaleY = (float) windowH / virtualH;
float scale = (scaleX < scaleY) ? scaleX : scaleY;
float viewportW = virtualW * scale;
float viewportH = virtualH * scale;
float offsetX = (windowW - viewportW) * 0.5f;
float offsetY = (windowH - viewportH) * 0.5f;
return {scale, offsetX, offsetY};
}
void Direct3DRMDevice2Impl::Resize()
{
int width, height;
SDL_GetWindowSizeInPixels(DDWindow, &width, &height);
m_viewportTransform = CalculateViewportTransform(m_virtualWidth, m_virtualHeight, width, height);
m_renderer->Resize(width, height, m_viewportTransform);
for (int i = 0; i < m_viewports->GetSize(); i++) {
IDirect3DRMViewport* viewport;
m_viewports->GetElement(i, &viewport);
static_cast<Direct3DRMViewportImpl*>(viewport)->UpdateProjectionMatrix();
}
}
bool Direct3DRMDevice2Impl::ConvertEventToRenderCoordinates(SDL_Event* event)
{
return m_renderer->ConvertEventToRenderCoordinates(event);
switch (event->type) {
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: {
Resize();
break;
}
case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: {
int rawX = event->motion.x;
int rawY = event->motion.y;
float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale;
float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale;
event->motion.x = static_cast<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(
int vertexCount,
int faceCount,
int vertexPerFace,
DWORD* faceBuffer,
unsigned int vertexCount,
unsigned int faceCount,
unsigned int vertexPerFace,
unsigned int* faceBuffer,
D3DRMGROUPINDEX* groupIndex
)
{
@ -59,7 +59,7 @@ HRESULT Direct3DRMMeshImpl::AddGroup(
MeshGroup group;
group.vertexPerFace = vertexPerFace;
DWORD* src = faceBuffer;
unsigned int* src = faceBuffer;
group.indices.assign(src, src + faceCount * vertexPerFace);
m_groups.push_back(std::move(group));

View File

@ -6,8 +6,19 @@ Direct3DRMTextureImpl::Direct3DRMTextureImpl(D3DRMIMAGE* image)
MINIWIN_NOT_IMPLEMENTED();
}
Direct3DRMTextureImpl::Direct3DRMTextureImpl(IDirectDrawSurface* surface) : m_surface(surface)
Direct3DRMTextureImpl::Direct3DRMTextureImpl(IDirectDrawSurface* surface, bool holdsRef)
: m_surface(surface), m_holdsRef(holdsRef)
{
if (holdsRef && m_surface) {
m_surface->AddRef();
}
}
Direct3DRMTextureImpl::~Direct3DRMTextureImpl()
{
if (m_holdsRef && m_surface) {
m_surface->Release();
}
}
HRESULT Direct3DRMTextureImpl::QueryInterface(const GUID& riid, void** ppvObject)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,8 +26,6 @@ struct Plane {
float d;
};
extern SDL_Renderer* DDRenderer;
class Direct3DRMRenderer : public IDirect3DDevice2 {
public:
virtual void PushLights(const SceneLight* vertices, size_t count) = 0;
@ -35,8 +33,10 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
virtual void SetFrustumPlanes(const Plane* frustumPlanes) = 0;
virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0;
virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0;
virtual DWORD GetWidth() = 0;
virtual DWORD GetHeight() = 0;
int GetWidth() { return m_width; }
int GetHeight() { return m_height; }
int GetVirtualWidth() { return m_virtualWidth; }
int GetVirtualHeight() { return m_virtualHeight; }
virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0;
virtual const char* GetName() = 0;
virtual HRESULT BeginFrame() = 0;
@ -44,13 +44,20 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
virtual void SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) = 0;
virtual HRESULT FinalizeFrame() = 0;
virtual void Resize(int width, int height, const ViewportTransform& viewportTransform) = 0;
virtual void Clear(float r, float g, float b) = 0;
virtual void Flip() = 0;
virtual void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) = 0;
virtual void Download(SDL_Surface* target) = 0;
bool ConvertEventToRenderCoordinates(SDL_Event* event)
{
return SDL_ConvertEventToRenderCoordinates(DDRenderer, event);
}
protected:
int m_width, m_height;
int m_virtualWidth, m_virtualHeight;
ViewportTransform m_viewportTransform;
};

View File

@ -20,8 +20,6 @@ class DirectX9Renderer : public Direct3DRMRenderer {
void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override;
HRESULT BeginFrame() override;
@ -29,17 +27,23 @@ class DirectX9Renderer : public Direct3DRMRenderer {
void SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
void Resize(int width, int height, const ViewportTransform& viewportTransform) override;
void Clear(float r, float g, float b) override;
void Flip() override;
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override;
void Download(SDL_Surface* target) override;
private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
SDL_Surface* m_renderedImage;
DWORD m_width, m_height;
std::vector<SceneLight> m_lights;
std::vector<D3D9MeshCacheEntry> m_meshs;
std::vector<D3D9TextureCacheEntry> m_textures;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,9 +8,7 @@
#include <SDL3/SDL.h>
extern SDL_Window* DDWindow;
extern SDL_Surface* DDBackBuffer;
extern FrameBufferImpl* DDFrameBuffer;
extern SDL_Renderer* DDRenderer;
extern Direct3DRMRenderer* DDRenderer;
inline static SDL_Rect ConvertRect(const RECT* r)
{
@ -47,6 +45,11 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 {
HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice)
override;
HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override;
private:
FrameBufferImpl* m_frameBuffer;
int m_virtualWidth = 0;
int m_virtualHeight = 0;
};
HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context);

View File

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

View File

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

View File

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