Merge branch 'master' into emscripten

This commit is contained in:
Christian Semmler 2025-06-10 16:51:21 -07:00
commit 26424cfada
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
64 changed files with 3005 additions and 2136 deletions

View File

@ -101,9 +101,7 @@ if (ISLE_UBSAN)
add_link_options(-fsanitize=undefined)
endif()
if(ISLE_MINIWIN)
add_subdirectory(miniwin)
endif()
add_subdirectory(miniwin EXCLUDE_FROM_ALL)
set(isle_targets)
@ -485,6 +483,9 @@ if (ISLE_BUILD_APP)
# Link SDL and iniparser
target_link_libraries(isle PRIVATE SDL3::SDL3 iniparser-static)
# Allow unconditional include of miniwin/miniwindevice.h
target_link_libraries(isle PRIVATE miniwin-headers)
# Link DSOUND and WINMM
if (WIN32)
target_link_libraries(isle PRIVATE winmm)
@ -497,6 +498,14 @@ if (ISLE_BUILD_APP)
)
target_compile_definitions(isle PRIVATE ISLE_DEBUG)
target_link_libraries(isle PRIVATE imgui)
find_path(valgrind_INCLUDE_PATH NAMES valgrind/callgrind.h)
if(valgrind_INCLUDE_PATH)
# Run isle under valgrind to create a profile. Use e.g. kcachegrind to view the profile.
# > valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes \
# > --collect-atstart=no --instr-atstart=no ./isle --debug
target_compile_definitions(isle PRIVATE ISLE_VALGRIND)
target_include_directories(isle PRIVATE ${valgrind_INCLUDE_PATH})
endif()
endif()
if(EMSCRIPTEN)
target_sources(isle PRIVATE

View File

@ -1,3 +1,5 @@
#define INITGUID
#include "isleapp.h"
#include "3dmanager/lego3dmanager.h"
@ -29,8 +31,11 @@
#include "res/isle_bmp.h"
#include "res/resource.h"
#include "roi/legoroi.h"
#include "tgl/d3drm/impl.h"
#include "viewmanager/viewmanager.h"
#include <miniwin/miniwindevice.h>
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
@ -127,6 +132,8 @@ IsleApp::IsleApp()
LegoOmni::CreateInstance();
m_iniPath = NULL;
m_maxLod = RealtimeView::GetUserMaxLOD();
m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20;
}
// FUNCTION: ISLE 0x4011a0
@ -567,6 +574,8 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
IsleDebug_Quit();
if (appstate != NULL) {
SDL_DestroyWindow((SDL_Window*) appstate);
}
@ -688,12 +697,24 @@ MxResult IsleApp::SetupWindow()
LegoWorldPresenter::configureLegoWorldPresenter(m_islandQuality);
LegoBuildingManager::configureLegoBuildingManager(m_islandQuality);
LegoROI::configureLegoROI(iVar10);
LegoAnimationManager::configureLegoAnimationManager(m_islandQuality);
LegoAnimationManager::configureLegoAnimationManager(m_maxAllowedExtras);
RealtimeView::SetUserMaxLOD(m_maxLod);
if (LegoOmni::GetInstance()) {
if (LegoOmni::GetInstance()->GetInputManager()) {
LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick);
LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex);
}
MxDirect3D* d3d = LegoOmni::GetInstance()->GetVideoManager()->GetDirect3D();
if (d3d) {
SDL_Log(
"Direct3D driver name=\"%s\" description=\"%s\"",
d3d->GetDeviceName().c_str(),
d3d->GetDeviceDescription().c_str()
);
}
else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Failed to get D3D device name and description");
}
}
IsleDebug_Init();
@ -769,8 +790,12 @@ bool IsleApp::LoadConfig()
iniparser_set(dict, "isle:Back Buffers in Video RAM", "-1");
iniparser_set(dict, "isle:Island Quality", "2");
iniparser_set(dict, "isle:Island Texture", "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);
iniparser_set(dict, "isle:Max LOD", buf);
iniparser_set(dict, "isle:Max Allowed Extras", SDL_itoa(m_maxAllowedExtras, buf, 10));
iniparser_dump_ini(dict, iniFP);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "New config written at '%s'", iniConfig);
@ -823,8 +848,10 @@ bool IsleApp::LoadConfig()
}
}
m_islandQuality = iniparser_getint(dict, "isle:Island Quality", 2);
m_islandTexture = iniparser_getint(dict, "isle:Island Texture", 1);
m_islandQuality = iniparser_getint(dict, "isle:Island Quality", m_islandQuality);
m_islandTexture = iniparser_getint(dict, "isle:Island Texture", m_islandTexture);
m_maxLod = iniparser_getdouble(dict, "isle:Max LOD", m_maxLod);
m_maxAllowedExtras = iniparser_getint(dict, "isle:Max Allowed Extras", m_maxAllowedExtras);
const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL);
if (deviceId != NULL) {
@ -1003,3 +1030,32 @@ MxResult IsleApp::ParseArguments(int argc, char** argv)
return SUCCESS;
}
IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice()
{
LegoVideoManager* videoManager = LegoOmni::GetInstance()->GetVideoManager();
if (!videoManager) {
return nullptr;
}
Lego3DManager* lego3DManager = videoManager->Get3DManager();
if (!lego3DManager) {
return nullptr;
}
Lego3DView* lego3DView = lego3DManager->GetLego3DView();
if (!lego3DView) {
return nullptr;
}
TglImpl::DeviceImpl* tgl_device = (TglImpl::DeviceImpl*) lego3DView->GetDevice();
if (!tgl_device) {
return nullptr;
}
IDirect3DRMDevice2* d3drmdev = tgl_device->ImplementationData();
if (!d3drmdev) {
return nullptr;
}
IDirect3DRMMiniwinDevice* d3drmMiniwinDev = nullptr;
if (!SUCCEEDED(d3drmdev->QueryInterface(IID_IDirect3DRMMiniwinDevice, (void**) &d3drmMiniwinDev))) {
return nullptr;
}
return d3drmMiniwinDev;
}

View File

@ -12,6 +12,7 @@
#else
#include <windows.h>
#endif
#include "miniwin/miniwindevice.h"
// SIZE 0x8c
class IsleApp {
@ -86,8 +87,12 @@ class IsleApp {
char* m_mediaPath;
char* m_iniPath;
MxFloat m_maxLod;
MxU32 m_maxAllowedExtras;
};
extern IsleApp* g_isle;
extern IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice();
#endif // ISLEAPP_H

View File

@ -16,6 +16,10 @@
#include <backends/imgui_impl_sdlrenderer3.h>
#include <imgui.h>
#ifdef ISLE_VALGRIND
#include <valgrind/callgrind.h>
#endif
#define SCANCODE_KEY_PAUSE SDL_SCANCODE_KP_0
#define SCANCODE_KEY_RESUME SDL_SCANCODE_KP_PERIOD
@ -26,6 +30,11 @@ static SDL_Window* g_debugWindow;
static SDL_Renderer* g_debugRenderer;
static SDL_Texture* g_videoPalette;
static IDirect3DRMMiniwinDevice* g_d3drmMiniwinDevice;
#ifdef ISLE_VALGRIND
static bool g_instrumentationEnabled;
#endif
class DebugViewer {
public:
@ -179,6 +188,7 @@ void IsleDebug_Init()
g_debugEnabled = false;
break;
}
g_d3drmMiniwinDevice = GetD3DRMMiniwinDevice();
} while (0);
if (!g_debugEnabled) {
if (g_debugRenderer) {
@ -192,6 +202,15 @@ void IsleDebug_Init()
}
}
void IsleDebug_Quit()
{
SDL_DestroyRenderer(g_debugRenderer);
SDL_DestroyWindow(g_debugWindow);
if (g_d3drmMiniwinDevice) {
g_d3drmMiniwinDevice->Release();
}
}
bool IsleDebug_Event(SDL_Event* event)
{
if (!g_debugEnabled) {
@ -246,6 +265,19 @@ void IsleDebug_Render()
Lego()->Resume();
}
}
#ifdef ISLE_VALGRIND
if (ImGui::MenuItem(g_instrumentationEnabled ? "Disable instrumentation" : "Enable instrumentation")) {
g_instrumentationEnabled = !g_instrumentationEnabled;
if (g_instrumentationEnabled) {
CALLGRIND_START_INSTRUMENTATION;
CALLGRIND_TOGGLE_COLLECT;
}
else {
CALLGRIND_TOGGLE_COLLECT;
CALLGRIND_STOP_INSTRUMENTATION;
}
}
#endif
ImGui::EndMainMenuBar();
ImGui::ShowDemoWindow(nullptr);
LegoOmni* lego = Lego();
@ -261,6 +293,17 @@ void IsleDebug_Render()
ImGui::Value("Player count", gameState->GetPlayerCount());
ImGui::TreePop();
}
if (ImGui::TreeNode("Renderer")) {
if (g_d3drmMiniwinDevice) {
float shininess = g_d3drmMiniwinDevice->GetShininessFactor();
ImGui::SliderFloat("shininess", &shininess, 0.f, 10.f);
g_d3drmMiniwinDevice->SetShininessFactor(shininess);
}
else {
ImGui::Text("No miniwin driver");
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Sound Manager")) {
LegoSoundManager* soundManager = lego->GetSoundManager();
Sint32 oldVolume = soundManager->GetVolume();

View File

@ -11,6 +11,8 @@ extern void IsleDebug_SetEnabled(bool);
extern void IsleDebug_Init();
extern void IsleDebug_Quit();
extern bool IsleDebug_Event(SDL_Event* event);
extern void IsleDebug_Render();
@ -35,6 +37,10 @@ extern void IsleDebug_ResetStepMode();
do { \
} while (0)
#define IsleDebug_Quit() \
do { \
} while (0)
#define IsleDebug_Event(EVENT) (false)
#define IsleDebug_Render() \

View File

@ -16,6 +16,24 @@ class MxStillPresenter;
// SIZE 0x18
class HospitalState : public LegoState {
public:
enum {
e_exitToClose = 0,
e_newState = 1,
e_unknown3 = 3,
e_unknown4 = 4,
e_introduction = 5,
e_explainQuestShort = 6,
e_explainQuest = 7,
e_waitAcceptingQuest = 8,
e_beforeEnteringAmbulance = 9,
e_unknown10 = 10, // Can never be reached
e_unknown11 = 11, // Can only be reached via e_unknown10
e_afterAcceptingQuest = 12,
e_exitImmediately = 13,
e_exitToInfocenter = 14,
e_exitToFront = 15,
};
HospitalState();
~HospitalState() override {}
@ -40,13 +58,13 @@ class HospitalState : public LegoState {
// TODO: Most likely getters/setters are not used according to BETA.
undefined4 m_unk0x08; // 0x08
MxS16 m_unk0x0c; // 0x0c
MxS16 m_unk0x0e; // 0x0e
MxS16 m_unk0x10; // 0x10
MxS16 m_unk0x12; // 0x12
MxS16 m_unk0x14; // 0x14
MxS16 m_unk0x16; // 0x16
MxS32 m_state; // 0x08
MxS16 m_stateActor; // 0x0c
MxS16 m_statePepper; // 0x0e
MxS16 m_stateMama; // 0x10
MxS16 m_statePapa; // 0x12
MxS16 m_stateNick; // 0x14
MxS16 m_stateLaura; // 0x16
};
// VTABLE: LEGO1 0x100d9730
@ -95,13 +113,13 @@ class Hospital : public LegoWorld {
MxS16 m_currentActorId; // 0xf8
LegoGameState::Area m_destLocation; // 0xfc
undefined2 m_unk0x100; // 0x100
MxU16 m_interactionMode; // 0x100
HospitalState* m_hospitalState; // 0x104
undefined2 m_unk0x108; // 0x108
MxU16 m_setWithCurrentAction; // 0x108
HospitalScript::Script m_currentAction; // 0x10c
MxStillPresenter* m_copLedBitmap; // 0x110
MxStillPresenter* m_pizzaLedBitmap; // 0x114
undefined m_unk0x118; // 0x118
MxBool m_flashingLeds; // 0x118
MxLong m_copLedAnimTimer; // 0x11c
MxLong m_pizzaLedAnimTimer; // 0x120
MxLong m_time; // 0x124

View File

@ -285,7 +285,7 @@ class LegoAnimationManager : public MxCore {
MxLong m_unk0x410; // 0x410
MxU32 m_unk0x414; // 0x414
MxU32 m_numAllowedExtras; // 0x418
undefined4 m_unk0x41c; // 0x41c
MxU32 m_maxAllowedExtras; // 0x41c
AnimState* m_animState; // 0x420
LegoROIList* m_unk0x424; // 0x424
MxBool m_suspendedEnableCamAnims; // 0x428

View File

@ -39,7 +39,7 @@ class LegoPathBoundary : public LegoWEGEdge {
MxResult AddActor(LegoPathActor* p_actor);
MxResult RemoveActor(LegoPathActor* p_actor);
void FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor);
void CheckAndCallPathTriggers(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor);
void SwitchBoundary(
LegoPathActor* p_actor,
LegoPathBoundary*& p_boundary,
@ -47,8 +47,8 @@ class LegoPathBoundary : public LegoWEGEdge {
float& p_unk0xe4
);
MxU32 Intersect(float p_scale, Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, LegoOrientedEdge*& p_edge);
MxU32 FUN_10057fe0(LegoAnimPresenter* p_presenter);
MxU32 FUN_100586e0(LegoAnimPresenter* p_presenter);
MxU32 AddPresenterIfInRange(LegoAnimPresenter* p_presenter);
MxU32 RemovePresenter(LegoAnimPresenter* p_presenter);
// FUNCTION: BETA10 0x1001ffb0
LegoPathActorSet& GetActors() { return m_actors; }

View File

@ -110,7 +110,7 @@ class LegoPathController : public MxCore {
MxResult PlaceActor(LegoPathActor* p_actor);
MxResult RemoveActor(LegoPathActor* p_actor);
void FUN_100468f0(LegoAnimPresenter* p_presenter);
void FUN_10046930(LegoAnimPresenter* p_presenter);
void RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter);
MxResult FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL);
LegoPathBoundary* GetPathBoundary(const char* p_name);
void Enable(MxBool p_enable);
@ -194,12 +194,12 @@ class LegoPathController : public MxCore {
LegoPathBoundary* m_boundaries; // 0x08
LegoPathCtrlEdge* m_edges; // 0x0c
Mx3DPointFloat* m_unk0x10; // 0x10
Mx3DPointFloat* m_nodes; // 0x10
LegoPathStruct* m_structs; // 0x14
MxU16 m_numL; // 0x18
MxU16 m_numE; // 0x1a
MxU16 m_numN; // 0x1c
MxU16 m_numT; // 0x1e
MxU16 m_numL; // 0x18 Number of boundaries
MxU16 m_numE; // 0x1a Number of edges
MxU16 m_numN; // 0x1c Number of nodes
MxU16 m_numT; // 0x1e Number of structs
LegoPathCtrlEdgeSet m_pfsE; // 0x20
LegoPathActorSet m_actors; // 0x30

View File

@ -24,7 +24,7 @@ class LegoTextureInfo {
static BOOL SetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo* p_textureInfo);
static BOOL GetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo*& p_textureInfo);
LegoResult FUN_10066010(const LegoU8* p_bits);
LegoResult LoadBits(const LegoU8* p_bits);
// private:
char* m_name; // 0x00

View File

@ -245,7 +245,7 @@ void Act3Cop::ParseAction(char* p_extra)
}
}
Mx4DPointFloat* boundary0x14 = boundary->GetUnknown0x14();
Mx4DPointFloat* boundary0x14 = boundary->GetUp();
if (point.Dot(point, *boundary0x14) + boundary0x14->index_operator(3) <= 0.001 &&
point.Dot(point, *boundary0x14) + boundary0x14->index_operator(3) >= -0.001) {

View File

@ -337,7 +337,7 @@ void Act3Ammo::Animate(float p_time)
Vector3 local174(local104[2]);
if (IsPizza()) {
local184 = *m_boundary->GetUnknown0x14();
local184 = *m_boundary->GetUp();
local17c[0] = 1.0f;
local17c[1] = local17c[2] = 0.0f;
local174.EqualsCross(local17c, local184);
@ -345,7 +345,7 @@ void Act3Ammo::Animate(float p_time)
local17c.EqualsCross(local184, local174);
}
else {
local17c = *m_boundary->GetUnknown0x14();
local17c = *m_boundary->GetUp();
local184[0] = 1.0f;
local184[1] = local184[2] = 0.0f;
local174.EqualsCross(local17c, local184);

View File

@ -503,7 +503,7 @@ void LegoAnimationManager::Init()
m_unk0x1a = FALSE;
m_tranInfoList = NULL;
m_tranInfoList2 = NULL;
m_unk0x41c = g_legoAnimationManagerConfig <= 1 ? 10 : 20;
m_maxAllowedExtras = g_legoAnimationManagerConfig;
MxS32 i;
for (i = 0; i < (MxS32) sizeOfArray(m_unk0x28); i++) {
@ -1576,7 +1576,7 @@ MxResult LegoAnimationManager::Tickle()
if (elapsedSeconds > 0.2 && m_numAllowedExtras > 2) {
m_numAllowedExtras--;
}
else if (g_unk0x100f7500 < 0.16 && m_numAllowedExtras < m_unk0x41c) {
else if (g_unk0x100f7500 < 0.16 && m_numAllowedExtras < m_maxAllowedExtras) {
m_numAllowedExtras++;
}
}

View File

@ -827,7 +827,7 @@ MxResult LegoBuildingManager::FUN_10030630()
}
if (g_buildingInfo[i].m_boundary != NULL) {
Mx4DPointFloat& unk0x14 = *g_buildingInfo[i].m_boundary->GetUnknown0x14();
Mx4DPointFloat& unk0x14 = *g_buildingInfo[i].m_boundary->GetUp();
if (position.Dot(position, unk0x14) + unk0x14.index_operator(3) > 0.001 ||
position.Dot(position, unk0x14) + unk0x14.index_operator(3) < -0.001) {

View File

@ -160,7 +160,7 @@ MxResult LegoPlantManager::FUN_10026410()
}
if (g_plantInfo[i].m_boundary != NULL) {
Mx4DPointFloat& unk0x14 = *g_plantInfo[i].m_boundary->GetUnknown0x14();
Mx4DPointFloat& unk0x14 = *g_plantInfo[i].m_boundary->GetUp();
if (position.Dot(position, unk0x14) + unk0x14.index_operator(3) > 0.001 ||
position.Dot(position, unk0x14) + unk0x14.index_operator(3) < -0.001) {

View File

@ -186,7 +186,7 @@ BOOL LegoTextureInfo::GetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo*& p_text
}
// FUNCTION: LEGO1 0x10066010
LegoResult LegoTextureInfo::FUN_10066010(const LegoU8* p_bits)
LegoResult LegoTextureInfo::LoadBits(const LegoU8* p_bits)
{
if (m_surface != NULL && m_texture != NULL) {
DDSURFACEDESC desc;

View File

@ -779,6 +779,6 @@ void FUN_1003f930(LegoNamedTexture* p_namedTexture)
LegoTextureInfo* textureInfo = TextureContainer()->Get(p_namedTexture->GetName()->GetData());
if (textureInfo != NULL) {
textureInfo->FUN_10066010(p_namedTexture->GetTexture()->GetImage()->GetBits());
textureInfo->LoadBits(p_namedTexture->GetTexture()->GetImage()->GetBits());
}
}

View File

@ -371,7 +371,7 @@ void LegoWorld::FUN_1001fe90(LegoAnimPresenter* p_presenter)
LegoPathController* controller;
while (cursor.Next(controller)) {
controller->FUN_10046930(p_presenter);
controller->RemovePresenterFromBoundaries(p_presenter);
}
}

View File

@ -36,7 +36,7 @@ DECOMP_SIZE_ASSERT(LegoWorldPresenter, 0x54)
MxS32 g_legoWorldPresenterQuality = 1;
// GLOBAL: LEGO1 0x100f75d8
Sint64 g_wdbOffset = 0;
Sint64 g_wdbSkipGlobalPartsOffset = 0;
// FUNCTION: LEGO1 0x100665b0
void LegoWorldPresenter::configureLegoWorldPresenter(MxS32 p_legoWorldPresenterQuality)
@ -208,7 +208,7 @@ MxResult LegoWorldPresenter::LoadWorld(char* p_worldName, LegoWorld* p_world)
return FAILURE;
}
if (g_wdbOffset == 0) {
if (g_wdbSkipGlobalPartsOffset == 0) {
if (SDL_ReadIO(wdbFile, &size, sizeof(MxU32)) != sizeof(MxU32)) {
return FAILURE;
}
@ -248,10 +248,10 @@ MxResult LegoWorldPresenter::LoadWorld(char* p_worldName, LegoWorld* p_world)
delete[] buff;
g_wdbOffset = SDL_TellIO(wdbFile);
g_wdbSkipGlobalPartsOffset = SDL_TellIO(wdbFile);
}
else {
if (SDL_SeekIO(wdbFile, g_wdbOffset, SDL_IO_SEEK_SET) != g_wdbOffset) {
if (SDL_SeekIO(wdbFile, g_wdbSkipGlobalPartsOffset, SDL_IO_SEEK_SET) != g_wdbSkipGlobalPartsOffset) {
return FAILURE;
}
}

View File

@ -141,7 +141,7 @@ MxResult LegoPathActor::VTable0x88(
matrix.SetIdentity();
pos = p1;
dir = p4;
up = *m_boundary->GetUnknown0x14();
up = *m_boundary->GetUp();
if (!m_cameraFlag || !m_userNavFlag) {
dir *= -1.0f;
@ -151,7 +151,7 @@ MxResult LegoPathActor::VTable0x88(
m_roi->UpdateTransformationRelativeToParent(matrix);
if (!m_cameraFlag || !m_userNavFlag) {
p5.EqualsCross(*p_boundary->GetUnknown0x14(), p3);
p5.EqualsCross(*p_boundary->GetUp(), p3);
p5.Unitize();
if (VTable0x80(p1, p4, p2, p5) == SUCCESS) {
@ -212,7 +212,7 @@ MxResult LegoPathActor::VTable0x84(
matrix.SetIdentity();
pos = p_p1;
dir = p_p4;
up = *m_boundary->GetUnknown0x14();
up = *m_boundary->GetUp();
if (!m_cameraFlag || !m_userNavFlag) {
dir *= -1.0f;
@ -226,7 +226,7 @@ MxResult LegoPathActor::VTable0x84(
FUN_10010c30();
}
else {
p5.EqualsCross(*p_boundary->GetUnknown0x14(), p3);
p5.EqualsCross(*p_boundary->GetUp(), p3);
p5.Unitize();
if (VTable0x80(p_p1, p_p4, p2, p5) != SUCCESS) {
@ -257,7 +257,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
m_worldSpeed = nav->GetLinearVel();
if (nav->CalculateNewPosDir(p4, p5, p2, p1, m_boundary->GetUnknown0x14())) {
if (nav->CalculateNewPosDir(p4, p5, p2, p1, m_boundary->GetUp())) {
Mx3DPointFloat p6;
p6 = p2;
MxS32 result = 0;
@ -281,7 +281,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
result = 0;
}
else {
m_boundary->FUN_100575b0(p4, p2, this);
m_boundary->CheckAndCallPathTriggers(p4, p2, this);
}
LegoPathBoundary* oldBoundary = m_boundary;
@ -322,7 +322,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
Vector3 pos(p_transform[3]);
dir = p1;
up = *m_boundary->GetUnknown0x14();
up = *m_boundary->GetUp();
right.EqualsCross(up, dir);
MxS32 res = right.Unitize();
@ -355,10 +355,10 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
LegoResult r;
if (m_userNavFlag) {
r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUnknown0x14(), 0);
r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), 0);
}
else {
r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUnknown0x14(), 1);
r = m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUp(), 1);
}
assert(r == 0); // SUCCESS
@ -372,7 +372,7 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform)
return 1;
}
else {
m_boundary->FUN_100575b0(pos2, pos1, this);
m_boundary->CheckAndCallPathTriggers(pos2, pos1, this);
pos2 = pos1;
}
@ -663,7 +663,7 @@ MxResult LegoPathActor::VTable0x9c()
LERP3(local34, v1, v2, m_unk0xe4);
m_destEdge->GetFaceNormal(*m_boundary, local78);
local48.EqualsCross(*m_boundary->GetUnknown0x14(), local78);
local48.EqualsCross(*m_boundary->GetUp(), local78);
local48.Unitize();
}
@ -671,7 +671,7 @@ MxResult LegoPathActor::VTable0x9c()
Vector3 upRef(m_unk0xec[1]);
Vector3 dirRef(m_unk0xec[2]);
upRef = *m_boundary->GetUnknown0x14();
upRef = *m_boundary->GetUp();
rightRef.EqualsCross(upRef, dirRef);
rightRef.Unitize();

View File

@ -46,27 +46,27 @@ MxResult LegoPathBoundary::RemoveActor(LegoPathActor* p_actor)
// FUNCTION: LEGO1 0x100575b0
// FUNCTION: BETA10 0x100b1598
void LegoPathBoundary::FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor)
void LegoPathBoundary::CheckAndCallPathTriggers(Vector3& p_from, Vector3& p_to, LegoPathActor* p_actor)
{
Vector3* ccwV = NULL;
if (m_numTriggers > 0 && m_unk0x50 != NULL) {
if (m_numTriggers > 0 && m_direction != NULL) {
ccwV = m_edges[0]->CCWVertex(*this);
Mx3DPointFloat v;
v = p_point1;
v = p_from;
v -= *ccwV;
float dot1 = v.Dot(v, *m_unk0x50);
float dot1 = v.Dot(v, *m_direction);
v = p_point2;
v = p_to;
v -= *ccwV;
float dot2 = v.Dot(v, *m_unk0x50);
float dot2 = v.Dot(v, *m_direction);
if (dot2 > dot1) {
for (MxS32 i = 0; i < m_numTriggers; i++) {
LegoPathStruct* s = m_pathTrigger[i].m_pathStruct;
if (m_pathTrigger[i].m_unk0x08 >= dot1 && m_pathTrigger[i].m_unk0x08 < dot2) {
if (m_pathTrigger[i].m_triggerLength >= dot1 && m_pathTrigger[i].m_triggerLength < dot2) {
s->HandleTrigger(p_actor, TRUE, m_pathTrigger[i].m_data);
}
}
@ -75,7 +75,7 @@ void LegoPathBoundary::FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPa
for (MxS32 i = 0; i < m_numTriggers; i++) {
LegoPathStruct* s = m_pathTrigger[i].m_pathStruct;
if (m_pathTrigger[i].m_unk0x08 >= dot2 && m_pathTrigger[i].m_unk0x08 < dot1) {
if (m_pathTrigger[i].m_triggerLength >= dot2 && m_pathTrigger[i].m_triggerLength < dot1) {
s->HandleTrigger(p_actor, FALSE, m_pathTrigger[i].m_data);
}
}
@ -341,15 +341,15 @@ MxU32 LegoPathBoundary::Intersect(
// FUNCTION: LEGO1 0x10057fe0
// FUNCTION: BETA10 0x100b2220
MxU32 LegoPathBoundary::FUN_10057fe0(LegoAnimPresenter* p_presenter)
MxU32 LegoPathBoundary::AddPresenterIfInRange(LegoAnimPresenter* p_presenter)
{
Mx3DPointFloat unk0x30;
unk0x30 = m_unk0x30;
unk0x30 = m_centerPoint;
unk0x30 -= p_presenter->m_unk0xa8;
float len = unk0x30.LenSquared();
float local20 = p_presenter->m_unk0xa4 + m_unk0x44;
float local20 = p_presenter->m_unk0xa4 + m_boundingRadius;
if (len > 0.001 && len > local20 * local20) {
return 0;
@ -361,7 +361,7 @@ MxU32 LegoPathBoundary::FUN_10057fe0(LegoAnimPresenter* p_presenter)
// FUNCTION: LEGO1 0x100586e0
// FUNCTION: BETA10 0x100b22d1
MxU32 LegoPathBoundary::FUN_100586e0(LegoAnimPresenter* p_presenter)
MxU32 LegoPathBoundary::RemovePresenter(LegoAnimPresenter* p_presenter)
{
if (p_presenter != NULL) {
if (m_presenters.find(p_presenter) != m_presenters.end()) {

View File

@ -73,7 +73,7 @@ LegoPathController::LegoPathController()
{
m_boundaries = NULL;
m_edges = NULL;
m_unk0x10 = NULL;
m_nodes = NULL;
m_structs = NULL;
m_numL = 0;
m_numE = 0;
@ -101,7 +101,7 @@ MxResult LegoPathController::Create(
}
for (i = 0; i < m_numN; i++) {
m_unk0x10[i] += p_location;
m_nodes[i] += p_location;
}
for (i = 0; i < m_numL; i++) {
@ -151,10 +151,10 @@ void LegoPathController::Destroy()
m_boundaries = NULL;
m_numL = 0;
if (m_unk0x10 != NULL) {
delete[] m_unk0x10;
if (m_nodes != NULL) {
delete[] m_nodes;
}
m_unk0x10 = NULL;
m_nodes = NULL;
m_numN = 0;
if (m_structs != NULL) {
@ -354,17 +354,17 @@ void LegoPathController::FUN_100468f0(LegoAnimPresenter* p_presenter)
{
for (MxS32 i = 0; i < m_numL; i++) {
if (!(m_boundaries[i].m_flags & LegoWEGEdge::c_bit3)) {
m_boundaries[i].FUN_10057fe0(p_presenter);
m_boundaries[i].AddPresenterIfInRange(p_presenter);
}
}
}
// FUNCTION: LEGO1 0x10046930
// FUNCTION: BETA10 0x100b737b
void LegoPathController::FUN_10046930(LegoAnimPresenter* p_presenter)
void LegoPathController::RemovePresenterFromBoundaries(LegoAnimPresenter* p_presenter)
{
for (MxS32 i = 0; i < m_numL; i++) {
m_boundaries[i].FUN_100586e0(p_presenter);
m_boundaries[i].RemovePresenter(p_presenter);
}
}
@ -478,7 +478,7 @@ MxResult LegoPathController::Read(LegoStorage* p_storage)
return FAILURE;
}
if (m_numN > 0) {
m_unk0x10 = new Mx3DPointFloat[m_numN];
m_nodes = new Mx3DPointFloat[m_numN];
}
if (p_storage->Read(&m_numE, sizeof(MxU16)) != SUCCESS) {
@ -501,7 +501,7 @@ MxResult LegoPathController::Read(LegoStorage* p_storage)
if (m_numN > 0) {
for (MxS32 i = 0; i < m_numN; i++) {
if (ReadVector(p_storage, m_unk0x10[i]) != SUCCESS) {
if (ReadVector(p_storage, m_nodes[i]) != SUCCESS) {
return FAILURE;
}
}
@ -566,12 +566,12 @@ MxResult LegoPathController::ReadEdges(LegoStorage* p_storage)
if (p_storage->Read(&s, sizeof(MxU16)) != SUCCESS) {
return FAILURE;
}
edge.m_pointA = &m_unk0x10[s];
edge.m_pointA = &m_nodes[s];
if (p_storage->Read(&s, sizeof(MxU16)) != SUCCESS) {
return FAILURE;
}
edge.m_pointB = &m_unk0x10[s];
edge.m_pointB = &m_nodes[s];
if (edge.m_flags & LegoOrientedEdge::c_hasFaceA) {
if (p_storage->Read(&s, sizeof(MxU16)) != SUCCESS) {
@ -669,7 +669,7 @@ MxResult LegoPathController::ReadBoundaries(LegoStorage* p_storage)
boundary.m_name[length] = '\0';
}
if (ReadVector(p_storage, boundary.m_unk0x14) != SUCCESS) {
if (ReadVector(p_storage, boundary.m_up) != SUCCESS) {
return FAILURE;
}
@ -679,11 +679,11 @@ MxResult LegoPathController::ReadBoundaries(LegoStorage* p_storage)
}
}
if (ReadVector(p_storage, boundary.m_unk0x30) != SUCCESS) {
if (ReadVector(p_storage, boundary.m_centerPoint) != SUCCESS) {
return FAILURE;
}
if (p_storage->Read(&boundary.m_unk0x44, sizeof(boundary.m_unk0x44)) != SUCCESS) {
if (p_storage->Read(&boundary.m_boundingRadius, sizeof(boundary.m_boundingRadius)) != SUCCESS) {
return FAILURE;
}
@ -692,7 +692,7 @@ MxResult LegoPathController::ReadBoundaries(LegoStorage* p_storage)
}
if (boundary.m_numTriggers > 0) {
boundary.m_unk0x50 = new Mx3DPointFloat;
boundary.m_direction = new Mx3DPointFloat;
boundary.m_pathTrigger = new PathWithTrigger[boundary.m_numTriggers];
for (j = 0; j < boundary.m_numTriggers; j++) {
@ -708,14 +708,14 @@ MxResult LegoPathController::ReadBoundaries(LegoStorage* p_storage)
}
if (p_storage->Read(
&boundary.m_pathTrigger[j].m_unk0x08,
sizeof(boundary.m_pathTrigger[j].m_unk0x08)
&boundary.m_pathTrigger[j].m_triggerLength,
sizeof(boundary.m_pathTrigger[j].m_triggerLength)
) != SUCCESS) {
return FAILURE;
}
}
if (ReadVector(p_storage, *boundary.m_unk0x50) != SUCCESS) {
if (ReadVector(p_storage, *boundary.m_direction) != SUCCESS) {
return FAILURE;
}
}
@ -963,7 +963,7 @@ MxS32 LegoPathController::FUN_1004a240(
p_v1 *= p_f1;
p_v1 += *p_edge->CWVertex(*p_boundary);
p_edge->GetFaceNormal(*p_boundary, vec);
p_v2.EqualsCross(*p_boundary->GetUnknown0x14(), vec);
p_v2.EqualsCross(*p_boundary->GetUp(), vec);
return 0;
}
@ -987,7 +987,7 @@ MxResult LegoPathController::FUN_1004a380(
}
LegoPathBoundary* b = &m_boundaries[i];
Mx4DPointFloat* unk0x14 = b->GetUnknown0x14();
Mx4DPointFloat* unk0x14 = b->GetUp();
float local28 = p_param3[0].Dot(p_param3[0], *unk0x14);
if (local28 < 0.001 && local28 > -0.001) {

View File

@ -172,7 +172,7 @@ MxS32 LegoCarRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_edg
m_destEdge->GetFaceNormal(*m_boundary, destEdgeUnknownVector);
crossProduct.EqualsCross(*m_boundary->GetUnknown0x14(), destEdgeUnknownVector);
crossProduct.EqualsCross(*m_boundary->GetUp(), destEdgeUnknownVector);
crossProduct.Unitize();
Mx3DPointFloat worldDirection(Vector3(m_roi->GetWorldDirection()));
@ -266,8 +266,8 @@ MxResult LegoCarRaceActor::VTable0x9c()
d->GetFaceNormal(*b, point2);
m_destEdge->GetFaceNormal(*m_boundary, point3);
point4.EqualsCross(point2, *m_boundary->GetUnknown0x14());
point5.EqualsCross(*m_boundary->GetUnknown0x14(), point3);
point4.EqualsCross(point2, *m_boundary->GetUp());
point5.EqualsCross(*m_boundary->GetUp(), point3);
point4.Unitize();
point5.Unitize();
@ -366,7 +366,7 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_
LERP3(a, *v1, *v2, m_unk0xe4);
m_destEdge->GetFaceNormal(*m_boundary, bbb);
c.EqualsCross(bbb, *m_boundary->GetUnknown0x14());
c.EqualsCross(bbb, *m_boundary->GetUp());
c.Unitize();
Mx3DPointFloat worldDirection(m_roi->GetWorldDirection());

View File

@ -64,7 +64,7 @@ void LegoFlcTexturePresenter::LoadFrame(MxStreamChunk* p_chunk)
void LegoFlcTexturePresenter::PutFrame()
{
if (m_texture != NULL && m_rectCount != 0) {
m_texture->FUN_10066010(m_frameBitmap->GetImage());
m_texture->LoadBits(m_frameBitmap->GetImage());
m_rectCount = 0;
}
}

View File

@ -91,7 +91,7 @@ MxResult LegoPartPresenter::Read(MxDSChunk& p_chunk)
SDL_strlwr(textureName);
if (textureName[0] == '^') {
strcpy(textureName, textureName + 1);
memmove(textureName, textureName + 1, strlen(textureName));
if (g_partPresenterConfig1) {
texture = new LegoTexture();

View File

@ -114,7 +114,7 @@ void LegoPhonemePresenter::LoadFrame(MxStreamChunk* p_chunk)
void LegoPhonemePresenter::PutFrame()
{
if (m_textureInfo != NULL && m_rectCount != 0) {
m_textureInfo->FUN_10066010(m_frameBitmap->GetImage());
m_textureInfo->LoadBits(m_frameBitmap->GetImage());
m_rectCount = 0;
}
}

View File

@ -106,7 +106,7 @@ MxResult LegoTexturePresenter::Store()
}
}
else {
textureInfo->FUN_10066010(texture->GetImage()->GetBits());
textureInfo->LoadBits(texture->GetImage()->GetBits());
}
}

View File

@ -26,7 +26,7 @@ DECOMP_SIZE_ASSERT(Hospital, 0x12c)
DECOMP_SIZE_ASSERT(HospitalState, 0x18)
// GLOBAL: LEGO1 0x100f7918
undefined4 g_unk0x100f7918 = 3;
undefined4 g_animationSkipCounter = 3;
// GLOBAL: LEGO1 0x100f791c
MxBool g_copLedEnabled = FALSE;
@ -38,14 +38,14 @@ MxBool g_pizzaLedEnabled = FALSE;
Hospital::Hospital()
{
m_currentActorId = LegoActor::c_none;
m_unk0x100 = 0;
m_interactionMode = 0;
m_hospitalState = NULL;
m_unk0x108 = 0;
m_setWithCurrentAction = 0;
m_destLocation = LegoGameState::e_undefined;
m_currentAction = HospitalScript::c__StartUp;
m_copLedBitmap = NULL;
m_pizzaLedBitmap = NULL;
m_unk0x118 = 0;
m_flashingLeds = 0;
m_copLedAnimTimer = 0;
m_pizzaLedAnimTimer = 0;
m_unk0x128 = 0;
@ -63,10 +63,10 @@ Hospital::~Hospital()
ControlManager()->Unregister(this);
TickleManager()->UnregisterClient(this);
m_hospitalState->m_unk0x08 = 3;
m_hospitalState->m_state = HospitalState::e_unknown3;
NotificationManager()->Unregister(this);
g_unk0x100f7918 = 3;
g_animationSkipCounter = 3;
}
// FUNCTION: LEGO1 0x100748c0
@ -83,13 +83,13 @@ MxResult Hospital::Create(MxDSAction& p_dsAction)
m_hospitalState = (HospitalState*) GameState()->GetState("HospitalState");
if (!m_hospitalState) {
m_hospitalState = (HospitalState*) GameState()->CreateState("HospitalState");
m_hospitalState->m_unk0x08 = 1;
m_hospitalState->m_state = HospitalState::e_newState;
}
else if (m_hospitalState->m_unk0x08 == 4) {
m_hospitalState->m_unk0x08 = 4;
else if (m_hospitalState->m_state == HospitalState::e_unknown4) {
m_hospitalState->m_state = HospitalState::e_unknown4;
}
else {
m_hospitalState->m_unk0x08 = 3;
m_hospitalState->m_state = HospitalState::e_unknown3;
}
GameState()->m_currentArea = LegoGameState::e_hospital;
@ -151,69 +151,69 @@ void Hospital::ReadyWorld()
switch (m_currentActorId) {
case LegoActor::c_pepper:
m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x0e;
m_hospitalState->m_stateActor = m_hospitalState->m_statePepper;
if (m_hospitalState->m_unk0x0e < 5) {
m_hospitalState->m_unk0x0e += 1;
if (m_hospitalState->m_statePepper < 5) {
m_hospitalState->m_statePepper += 1;
}
break;
case LegoActor::c_mama:
m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x10;
m_hospitalState->m_stateActor = m_hospitalState->m_stateMama;
if (m_hospitalState->m_unk0x10 < 5) {
m_hospitalState->m_unk0x10 += 1;
if (m_hospitalState->m_stateMama < 5) {
m_hospitalState->m_stateMama += 1;
}
break;
case LegoActor::c_papa:
m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x12;
m_hospitalState->m_stateActor = m_hospitalState->m_statePapa;
if (m_hospitalState->m_unk0x12 < 5) {
m_hospitalState->m_unk0x12 += 1;
if (m_hospitalState->m_statePapa < 5) {
m_hospitalState->m_statePapa += 1;
}
break;
case LegoActor::c_nick:
m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x14;
m_hospitalState->m_stateActor = m_hospitalState->m_stateNick;
if (m_hospitalState->m_unk0x14 < 5) {
m_hospitalState->m_unk0x14 += 1;
if (m_hospitalState->m_stateNick < 5) {
m_hospitalState->m_stateNick += 1;
}
break;
case LegoActor::c_laura:
m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x16;
m_hospitalState->m_stateActor = m_hospitalState->m_stateLaura;
if (m_hospitalState->m_unk0x16 < 5) {
m_hospitalState->m_unk0x16 += 1;
if (m_hospitalState->m_stateLaura < 5) {
m_hospitalState->m_stateLaura += 1;
}
break;
}
if (m_hospitalState->m_unk0x0c < 3) {
if (m_hospitalState->m_stateActor < 3) {
HospitalScript::Script hospitalScript[] = {
HospitalScript::c_hho002cl_RunAnim,
HospitalScript::c_hho004jk_RunAnim,
HospitalScript::c_hho007p1_RunAnim
};
m_hospitalState->m_unk0x08 = 5;
m_hospitalState->m_state = HospitalState::e_introduction;
PlayAction(hospitalScript[m_hospitalState->m_unk0x0c]);
m_currentAction = hospitalScript[m_hospitalState->m_unk0x0c];
m_unk0x108 = 1;
PlayAction(hospitalScript[m_hospitalState->m_stateActor]);
m_currentAction = hospitalScript[m_hospitalState->m_stateActor];
m_setWithCurrentAction = 1;
}
else {
m_unk0x100 = 1;
m_interactionMode = 1;
m_time = Timer()->GetTime();
m_hospitalState->m_unk0x08 = 6;
m_hospitalState->m_state = HospitalState::e_explainQuestShort;
PlayAction(HospitalScript::c_hho003cl_RunAnim);
m_currentAction = HospitalScript::c_hho003cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
}
FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
@ -224,7 +224,7 @@ MxLong Hospital::HandleKeyPress(SDL_Keycode p_key)
{
MxLong result = 0;
if (p_key == SDLK_SPACE && g_unk0x100f7918 == 0) {
if (p_key == SDLK_SPACE && g_animationSkipCounter == 0) {
DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim);
result = 1;
}
@ -243,132 +243,132 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param)
return result;
}
m_unk0x108 = 0;
m_setWithCurrentAction = 0;
switch (m_hospitalState->m_unk0x08) {
case 5:
m_hospitalState->m_unk0x08 = 7;
switch (m_hospitalState->m_state) {
case HospitalState::e_introduction:
m_hospitalState->m_state = HospitalState::e_explainQuest;
PlayAction(HospitalScript::c_hho006cl_RunAnim);
m_currentAction = HospitalScript::c_hho006cl_RunAnim;
m_unk0x108 = 1;
m_unk0x118 = 1;
g_unk0x100f7918 = 0;
m_setWithCurrentAction = 1;
m_flashingLeds = 1;
g_animationSkipCounter = 0;
break;
case 6:
case HospitalState::e_explainQuestShort:
m_time = Timer()->GetTime();
m_unk0x100 = 1;
m_interactionMode = 1;
break;
case 7:
case 10:
m_hospitalState->m_unk0x08 = 8;
m_unk0x100 = 1;
case HospitalState::e_explainQuest:
case HospitalState::e_unknown10:
m_hospitalState->m_state = HospitalState::e_waitAcceptingQuest;
m_interactionMode = 1;
m_time = Timer()->GetTime();
break;
case 11:
case HospitalState::e_unknown11:
switch (m_currentActorId) {
case LegoActor::c_pepper:
switch (m_hospitalState->m_unk0x0e) {
switch (m_hospitalState->m_statePepper) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho017cl_RunAnim);
m_currentAction = HospitalScript::c_hho017cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho018cl_RunAnim);
m_currentAction = HospitalScript::c_hho018cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_mama:
switch (m_hospitalState->m_unk0x10) {
switch (m_hospitalState->m_stateMama) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho019cl_RunAnim);
m_currentAction = HospitalScript::c_hho019cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho020cl_RunAnim);
m_currentAction = HospitalScript::c_hho020cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_papa:
switch (m_hospitalState->m_unk0x12) {
switch (m_hospitalState->m_statePapa) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho023cl_RunAnim);
m_currentAction = HospitalScript::c_hho023cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho024cl_RunAnim);
m_currentAction = HospitalScript::c_hho024cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_nick:
switch (m_hospitalState->m_unk0x14) {
switch (m_hospitalState->m_stateNick) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho021cl_RunAnim);
m_currentAction = HospitalScript::c_hho021cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hhoa22cl_RunAnim);
m_currentAction = HospitalScript::c_hhoa22cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_laura:
switch (m_hospitalState->m_unk0x16) {
switch (m_hospitalState->m_stateLaura) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho025cl_RunAnim);
m_currentAction = HospitalScript::c_hho025cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho026cl_RunAnim);
m_currentAction = HospitalScript::c_hho026cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
}
break;
case 12:
m_hospitalState->m_unk0x08 = 9;
case HospitalState::e_afterAcceptingQuest:
m_hospitalState->m_state = HospitalState::e_beforeEnteringAmbulance;
act1State = (Act1State*) GameState()->GetState("Act1State");
act1State->SetUnknown18(9);
case 14:
case HospitalState::e_exitToFront:
if (m_unk0x128 == 0) {
m_unk0x128 = 1;
m_destLocation = LegoGameState::e_unk31;
@ -377,7 +377,7 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param)
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE);
}
break;
case 15:
case HospitalState::e_exitToInfocenter:
if (m_unk0x128 == 0) {
m_unk0x128 = 1;
m_destLocation = LegoGameState::e_infomain;
@ -397,7 +397,7 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param)
// FUNCTION: BETA10 0x1002d2b1
MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param)
{
if (m_unk0x100 == 1) {
if (m_interactionMode == 1) {
LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY());
if (roi != NULL) {
const LegoChar* roiName = roi->GetName();
@ -409,15 +409,15 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param)
if (!SDL_strcasecmp("actor_ha", roiName)) {
InputManager()->DisableInputProcessing();
m_unk0x100 = 3;
m_interactionMode = 3;
if (m_hospitalState->m_unk0x08 == 6) {
if (m_hospitalState->m_state == HospitalState::e_explainQuestShort) {
if (m_unk0x128 == 0) {
m_unk0x128 = 1;
TickleManager()->UnregisterClient(this);
m_hospitalState->m_unk0x08 = 9;
m_hospitalState->m_state = HospitalState::e_beforeEnteringAmbulance;
Act1State* act1State = (Act1State*) GameState()->GetState("Act1State");
assert(act1State);
@ -432,9 +432,9 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param)
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE);
}
}
else if (m_hospitalState->m_unk0x08 == 10 || m_hospitalState->m_unk0x08 == 8) {
if (m_hospitalState->m_unk0x08 == 10) {
m_hospitalState->m_unk0x08 = 11;
else if (m_hospitalState->m_state == HospitalState::e_unknown10 || m_hospitalState->m_state == HospitalState::e_waitAcceptingQuest) {
if (m_hospitalState->m_state == HospitalState::e_unknown10) {
m_hospitalState->m_state = HospitalState::e_unknown11;
BackgroundAudioManager()->RaiseVolume();
DeleteObjects(
@ -446,97 +446,97 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param)
else {
switch (m_currentActorId) {
case LegoActor::c_pepper:
switch (m_hospitalState->m_unk0x0e) {
switch (m_hospitalState->m_statePepper) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho017cl_RunAnim);
m_currentAction = HospitalScript::c_hho017cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho018cl_RunAnim);
m_currentAction = HospitalScript::c_hho018cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_mama:
switch (m_hospitalState->m_unk0x10) {
switch (m_hospitalState->m_stateMama) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho019cl_RunAnim);
m_currentAction = HospitalScript::c_hho019cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho020cl_RunAnim);
m_currentAction = HospitalScript::c_hho020cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_nick:
switch (m_hospitalState->m_unk0x14) {
switch (m_hospitalState->m_stateNick) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho021cl_RunAnim);
m_currentAction = HospitalScript::c_hho021cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hhoa22cl_RunAnim);
m_currentAction = HospitalScript::c_hhoa22cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_papa:
switch (m_hospitalState->m_unk0x12) {
switch (m_hospitalState->m_statePapa) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho023cl_RunAnim);
m_currentAction = HospitalScript::c_hho023cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho024cl_RunAnim);
m_currentAction = HospitalScript::c_hho024cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
case LegoActor::c_laura:
switch (m_hospitalState->m_unk0x16) {
switch (m_hospitalState->m_stateLaura) {
case 0:
case 1:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho025cl_RunAnim);
m_currentAction = HospitalScript::c_hho025cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
default:
m_hospitalState->m_unk0x08 = 12;
m_hospitalState->m_state = HospitalState::e_afterAcceptingQuest;
PlayAction(HospitalScript::c_hho026cl_RunAnim);
m_currentAction = HospitalScript::c_hho026cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
break;
}
break;
@ -561,16 +561,16 @@ MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param)
BackgroundAudioManager()->RaiseVolume();
DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim);
if (m_unk0x100 == 1) {
m_hospitalState->m_unk0x08 = 14;
if (m_interactionMode == 1) {
m_hospitalState->m_state = HospitalState::e_exitToInfocenter;
PlayAction(HospitalScript::c_hho016cl_RunAnim);
m_currentAction = HospitalScript::c_hho016cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
}
else if (m_unk0x128 == 0) {
m_unk0x128 = 1;
m_hospitalState->m_unk0x08 = 13;
m_hospitalState->m_state = HospitalState::e_exitImmediately;
m_destLocation = LegoGameState::e_infomain;
DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim);
@ -582,16 +582,16 @@ MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param)
case HospitalScript::c_Door_Ctl:
DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim);
if (m_unk0x100 == 1) {
m_hospitalState->m_unk0x08 = 15;
if (m_interactionMode == 1) {
m_hospitalState->m_state = HospitalState::e_exitToFront;
PlayAction(HospitalScript::c_hho016cl_RunAnim);
m_currentAction = HospitalScript::c_hho016cl_RunAnim;
m_unk0x108 = 1;
m_setWithCurrentAction = 1;
}
else if (m_unk0x128 == 0) {
m_unk0x128 = 1;
m_hospitalState->m_unk0x08 = 13;
m_hospitalState->m_state = HospitalState::e_exitImmediately;
m_destLocation = LegoGameState::e_unk31;
DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim);
@ -639,13 +639,13 @@ MxResult Hospital::Tickle()
return SUCCESS;
}
if (g_unk0x100f7918 != 0) {
g_unk0x100f7918 -= 1;
if (g_animationSkipCounter != 0) {
g_animationSkipCounter -= 1;
}
MxLong time = Timer()->GetTime();
if (m_unk0x118 != 0) {
if (m_flashingLeds != 0) {
if (time - m_copLedAnimTimer > 300) {
m_copLedAnimTimer = time;
g_copLedEnabled = !g_copLedEnabled;
@ -666,7 +666,7 @@ MxResult Hospital::Tickle()
MxBool Hospital::Escape()
{
DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, 999);
m_hospitalState->m_unk0x08 = 0;
m_hospitalState->m_state = HospitalState::e_exitToClose;
m_destLocation = LegoGameState::e_infomain;
@ -676,12 +676,12 @@ MxBool Hospital::Escape()
// FUNCTION: LEGO1 0x10076370
HospitalState::HospitalState()
{
m_unk0x0c = 0;
m_unk0x0e = 0;
m_unk0x10 = 0;
m_unk0x12 = 0;
m_unk0x14 = 0;
m_unk0x16 = 0;
m_stateActor = 0;
m_statePepper = 0;
m_stateMama = 0;
m_statePapa = 0;
m_stateNick = 0;
m_stateLaura = 0;
}
// FUNCTION: LEGO1 0x10076530
@ -691,20 +691,20 @@ MxResult HospitalState::Serialize(LegoStorage* p_storage)
LegoState::Serialize(p_storage);
if (p_storage->IsWriteMode()) {
p_storage->WriteS16(m_unk0x0c);
p_storage->WriteS16(m_unk0x0e);
p_storage->WriteS16(m_unk0x10);
p_storage->WriteS16(m_unk0x12);
p_storage->WriteS16(m_unk0x14);
p_storage->WriteS16(m_unk0x16);
p_storage->WriteS16(m_stateActor);
p_storage->WriteS16(m_statePepper);
p_storage->WriteS16(m_stateMama);
p_storage->WriteS16(m_statePapa);
p_storage->WriteS16(m_stateNick);
p_storage->WriteS16(m_stateLaura);
}
else if (p_storage->IsReadMode()) {
p_storage->ReadS16(m_unk0x0c);
p_storage->ReadS16(m_unk0x0e);
p_storage->ReadS16(m_unk0x10);
p_storage->ReadS16(m_unk0x12);
p_storage->ReadS16(m_unk0x14);
p_storage->ReadS16(m_unk0x16);
p_storage->ReadS16(m_stateActor);
p_storage->ReadS16(m_statePepper);
p_storage->ReadS16(m_stateMama);
p_storage->ReadS16(m_statePapa);
p_storage->ReadS16(m_stateNick);
p_storage->ReadS16(m_stateLaura);
}
return SUCCESS;

View File

@ -20,7 +20,7 @@ LegoWEEdge::~LegoWEEdge()
}
// FUNCTION: LEGO1 0x1009a5b0
LegoS32 LegoWEEdge::VTable0x04()
LegoS32 LegoWEEdge::LinkEdgesAndFaces()
{
for (LegoS32 i = 0; i < m_numEdges; i++) {
LegoOrientedEdge* e1 = m_edges[i];

View File

@ -14,7 +14,7 @@ class LegoWEEdge {
LegoWEEdge();
virtual ~LegoWEEdge(); // vtable+0x00
virtual LegoS32 VTable0x04(); // vtable+0x04
virtual LegoS32 LinkEdgesAndFaces(); // vtable+0x04
// FUNCTION: BETA10 0x1001c980
LegoU8 GetNumEdges() { return m_numEdges; }

View File

@ -13,12 +13,12 @@ LegoWEGEdge::LegoWEGEdge()
{
m_unk0x0d = 0;
m_name = NULL;
m_unk0x14.Clear();
m_up.Clear();
m_edgeNormals = NULL;
m_flags = 0;
m_numTriggers = 0;
m_pathTrigger = NULL;
m_unk0x50 = NULL;
m_direction = NULL;
}
// FUNCTION: LEGO1 0x1009a800
@ -37,18 +37,18 @@ LegoWEGEdge::~LegoWEGEdge()
if (m_pathTrigger) {
delete[] m_pathTrigger;
}
if (m_unk0x50) {
delete m_unk0x50;
if (m_direction) {
delete m_direction;
}
}
// FUNCTION: LEGO1 0x1009a8c0
// FUNCTION: BETA10 0x101832f7
LegoS32 LegoWEGEdge::VTable0x04()
LegoS32 LegoWEGEdge::LinkEdgesAndFaces()
{
LegoS32 result = 0;
m_unk0x30.Clear();
LegoWEEdge::VTable0x04();
m_centerPoint.Clear();
LegoWEEdge::LinkEdgesAndFaces();
assert(m_numEdges > 1);
@ -72,7 +72,7 @@ LegoS32 LegoWEGEdge::VTable0x04()
local14 = m_edges[1]->m_pointB;
}
result = FUN_1009aea0();
result = ValidateFacePlanarity();
if (result != 0) {
result = -2;
}
@ -86,35 +86,35 @@ LegoS32 LegoWEGEdge::VTable0x04()
for (i = 0; i < m_numEdges; i++) {
edge = m_edges[i];
m_unk0x30 += *edge->m_pointA;
m_unk0x30 += *edge->m_pointB;
m_centerPoint += *edge->m_pointA;
m_centerPoint += *edge->m_pointB;
}
m_unk0x30 /= m_numEdges * 2;
m_unk0x44 = 0.0f;
m_centerPoint /= m_numEdges * 2;
m_boundingRadius = 0.0f;
for (i = 0; i < m_numEdges; i++) {
Mx3DPointFloat local44;
edge = m_edges[i];
local44 = *edge->m_pointA;
local44 -= m_unk0x30;
local44 -= m_centerPoint;
float length = local44.LenSquared();
if (m_unk0x44 < length) {
m_unk0x44 = length;
if (m_boundingRadius < length) {
m_boundingRadius = length;
}
local44 = *edge->m_pointB;
local44 -= m_unk0x30;
local44 -= m_centerPoint;
length = local44.LenSquared();
if (m_unk0x44 < length) {
m_unk0x44 = length;
if (m_boundingRadius < length) {
m_boundingRadius = length;
}
}
m_unk0x44 = sqrt((double) m_unk0x44);
m_boundingRadius = sqrt((double) m_boundingRadius);
for (i = 0; i < m_numEdges; i++) {
edge = m_edges[i];
@ -139,10 +139,10 @@ LegoS32 LegoWEGEdge::VTable0x04()
Mx3DPointFloat local58;
Vector3 local64(&m_edgeNormals[i][0]);
edge->GetFaceNormal(*this, local58);
local64.EqualsCross(local58, m_unk0x14);
local64.EqualsCross(local58, m_up);
m_edgeNormals[i][3] = -local64.Dot(*m_edges[i]->m_pointA, local64);
if (m_edgeNormals[i][3] + m_unk0x30.Dot(m_unk0x30, local64) < 0.0f) {
if (m_edgeNormals[i][3] + m_centerPoint.Dot(m_centerPoint, local64) < 0.0f) {
m_edgeNormals[i] *= -1.0f;
}
@ -156,14 +156,14 @@ LegoS32 LegoWEGEdge::VTable0x04()
Vector3* vTrig2 = m_edges[1]->CCWVertex(*this);
assert(vTrig1 && vTrig2);
m_unk0x50 = new Mx3DPointFloat();
*m_unk0x50 = *vTrig2;
*m_unk0x50 -= *vTrig1;
m_direction = new Mx3DPointFloat();
*m_direction = *vTrig2;
*m_direction -= *vTrig1;
if (m_unk0x50->Unitize() < 0) {
if (m_direction->Unitize() < 0) {
assert(0);
delete m_unk0x50;
m_unk0x50 = NULL;
delete m_direction;
m_direction = NULL;
}
if (GetNumEdges() == 4) {
@ -178,12 +178,12 @@ LegoS32 LegoWEGEdge::VTable0x04()
localb8 -= *vTrig1;
local80 -= *vTrig1;
float locala4 = localb8.Dot(*m_unk0x50, localb8);
float locala4 = localb8.Dot(*m_direction, localb8);
if (local98 < locala4) {
local98 = locala4;
}
locala4 = local80.Dot(*m_unk0x50, local80);
locala4 = local80.Dot(*m_direction, local80);
if (locala4 < local9c) {
local9c = locala4;
}
@ -199,12 +199,12 @@ LegoS32 LegoWEGEdge::VTable0x04()
local9c -= 0.001;
for (LegoS32 j = 0; j < m_numTriggers; j++) {
if (m_pathTrigger[j].m_unk0x08 < local98) {
m_pathTrigger[j].m_unk0x08 = local98;
if (m_pathTrigger[j].m_triggerLength < local98) {
m_pathTrigger[j].m_triggerLength = local98;
}
if (m_pathTrigger[j].m_unk0x08 > local9c) {
m_pathTrigger[j].m_unk0x08 = local9c;
if (m_pathTrigger[j].m_triggerLength > local9c) {
m_pathTrigger[j].m_triggerLength = local9c;
}
}
}
@ -218,7 +218,7 @@ LegoS32 LegoWEGEdge::VTable0x04()
// FUNCTION: LEGO1 0x1009aea0
// FUNCTION: BETA10 0x10183e2a
LegoS32 LegoWEGEdge::FUN_1009aea0()
LegoS32 LegoWEGEdge::ValidateFacePlanarity()
{
LegoU32 localc = FALSE;
Mx3DPointFloat local24;
@ -255,17 +255,17 @@ LegoS32 LegoWEGEdge::FUN_1009aea0()
local24 /= local58;
if (localc) {
float local54 = local24.Dot(m_unk0x14, local24);
float local54 = local24.Dot(m_up, local24);
if (local54 < 0.98) {
delete[] local8;
return -2;
}
}
else {
m_unk0x14[0] = local24[0];
m_unk0x14[1] = local24[1];
m_unk0x14[2] = local24[2];
m_unk0x14[3] = -local8[i]->Dot(*local8[i], local24);
m_up[0] = local24[0];
m_up[1] = local24[1];
m_up[2] = local24[2];
m_up[3] = -local8[i]->Dot(*local8[i], local24);
localc = TRUE;
}
}

View File

@ -16,12 +16,12 @@ struct PathWithTrigger {
{
m_pathStruct = NULL;
m_data = 0;
m_unk0x08 = 0.0f;
m_triggerLength = 0.0f;
}
LegoPathStruct* m_pathStruct; // 0x00
unsigned int m_data; // 0x04
float m_unk0x08; // 0x08
float m_triggerLength; // 0x08
};
#include "mxgeometry/mxgeometry3d.h"
@ -42,7 +42,7 @@ class LegoWEGEdge : public LegoWEEdge {
LegoWEGEdge();
~LegoWEGEdge() override;
LegoS32 VTable0x04() override; // vtable+0x04
LegoS32 LinkEdgesAndFaces() override; // vtable+0x04
// FUNCTION: BETA10 0x100270c0
LegoU32 GetFlag0x10()
@ -57,7 +57,7 @@ class LegoWEGEdge : public LegoWEEdge {
// TODO: Other BETA10 reference at 0x1001c9e0, not sure what is going on
// FUNCTION: BETA10 0x1001ff80
Mx4DPointFloat* GetUnknown0x14() { return &m_unk0x14; }
Mx4DPointFloat* GetUp() { return &m_up; }
// FUNCTION: BETA10 0x1001ca10
Mx4DPointFloat* GetEdgeNormal(int index) { return &m_edgeNormals[index]; }
@ -85,18 +85,18 @@ class LegoWEGEdge : public LegoWEEdge {
friend class LegoPathController;
protected:
LegoS32 FUN_1009aea0();
LegoS32 ValidateFacePlanarity();
LegoU8 m_flags; // 0x0c
LegoU8 m_unk0x0d; // 0x0d
LegoChar* m_name; // 0x10
Mx4DPointFloat m_unk0x14; // 0x14
Mx4DPointFloat m_up; // 0x14
Mx4DPointFloat* m_edgeNormals; // 0x2c
Mx3DPointFloat m_unk0x30; // 0x30
float m_unk0x44; // 0x44
Mx3DPointFloat m_centerPoint; // 0x30
float m_boundingRadius; // 0x44
LegoU8 m_numTriggers; // 0x48
PathWithTrigger* m_pathTrigger; // 0x4c
Mx3DPointFloat* m_unk0x50; // 0x50
Mx3DPointFloat* m_direction; // 0x50
};
#endif // __LEGOWEGEDGE_H

View File

@ -312,6 +312,8 @@ BOOL MxDirect3D::SetDevice(MxDeviceEnumerate& p_deviceEnumerate, MxDriver* p_dri
d->m_desc = device.m_HELDesc;
}
m_deviceName = p_device->m_deviceName;
m_deviceDesc = p_device->m_deviceDesc;
m_currentDeviceInfo = d;
m_currentDevInfo = d->m_deviceInfo;
break;

View File

@ -6,6 +6,8 @@
#include "mxdirectxinfo.h"
#include "mxstl/stlcompat.h"
#include <string>
#ifdef MINIWIN
#include "miniwin/d3d.h"
#else
@ -44,6 +46,9 @@ class MxDirect3D : public MxDirectDraw {
BOOL SetDevice(MxDeviceEnumerate& p_deviceEnumerate, MxDriver* p_driver, Direct3DDeviceInfo* p_device);
const std::string& GetDeviceName() const { return m_deviceName; }
const std::string& GetDeviceDescription() const { return m_deviceDesc; }
protected:
BOOL D3DCreate();
BOOL D3DSetMode();
@ -60,6 +65,8 @@ class MxDirect3D : public MxDirectDraw {
IDirect3DDevice2* m_pDirect3dDevice; // 0x888
BOOL m_bTexturesDisabled; // 0x88c
undefined4 m_unk0x890; // 0x890
std::string m_deviceName;
std::string m_deviceDesc;
};
// GLOBAL: LEGO1 0x100dd1b0

View File

@ -49,7 +49,7 @@ class MxStopWatch {
inline MxStopWatch::MxStopWatch()
{
Reset();
m_ticksPerSeconds = SDL_GetPerformanceCounter();
m_ticksPerSeconds = SDL_GetPerformanceFrequency();
}
// FUNCTION: BETA10 0x100d8be0

View File

@ -1,6 +1,8 @@
#ifndef REALTIMEVIEW_H
#define REALTIMEVIEW_H
#include "lego1_export.h"
extern float g_userMaxLodPower;
class RealtimeView {
@ -9,10 +11,10 @@ class RealtimeView {
~RealtimeView();
static float GetPartsThreshold();
static float GetUserMaxLOD();
LEGO1_EXPORT static float GetUserMaxLOD();
static void SetPartsThreshold(float);
static void UpdateMaxLOD();
static void SetUserMaxLOD(float);
LEGO1_EXPORT static void SetUserMaxLOD(float);
static float GetUserMaxLodPower() { return g_userMaxLodPower; }
};

View File

@ -1,3 +1,6 @@
add_library(miniwin-headers INTERFACE)
target_include_directories(miniwin-headers INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
add_library(miniwin STATIC EXCLUDE_FROM_ALL
# Core
src/windows/windows.cpp
@ -15,6 +18,7 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL
src/d3drm/d3drmmesh.cpp
src/d3drm/d3drmtexture.cpp
src/d3drm/d3drmviewport.cpp
src/internal/meshutils.cpp
# D3DRM backends
src/d3drm/backends/software/renderer.cpp
@ -25,8 +29,8 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL
find_package(OpenGL)
find_package(GLEW)
if(OpenGL_FOUND AND GLEW_FOUND)
target_sources(miniwin PRIVATE src/d3drm/backends/opengl15/renderer.cpp)
target_compile_definitions(miniwin PRIVATE USE_OPENGL15)
target_sources(miniwin PRIVATE src/d3drm/backends/opengl1/renderer.cpp)
target_compile_definitions(miniwin PRIVATE USE_OPENGL1)
# Find and link OpenGL (1.5)
target_link_libraries(miniwin PRIVATE OpenGL::GL)
# Glew is used for getting a FBO for off screen rendering
@ -38,12 +42,11 @@ target_compile_definitions(miniwin PRIVATE MINIWIN_PIXELFORMAT=SDL_PIXELFORMAT_R
target_compile_definitions(miniwin PUBLIC MINIWIN)
target_include_directories(miniwin
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/internal
${CMAKE_CURRENT_SOURCE_DIR}/src/d3drm/backends/sdl3gpu/shaders/generated
)
target_link_libraries(miniwin PUBLIC miniwin-headers)
target_link_libraries(miniwin PRIVATE SDL3::SDL3)

View File

@ -100,6 +100,7 @@ typedef D3DRMPROJECTIONTYPE* LPD3DRMPROJECTIONTYPE;
// --- GUIDs ---
DEFINE_GUID(IID_IDirect3DRM2, 0x4516ecc8, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3);
DEFINE_GUID(IID_IDirect3DRMDevice2, 0x4516ec78, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3);
DEFINE_GUID(IID_IDirect3DRMWinDevice, 0xc5016cc0, 0xd273, 0x11ce, 0xac, 0x48, 0x00, 0x00, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMFrame, 0xeb16cb03, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1);
DEFINE_GUID(IID_IDirect3DRMMesh, 0xa3a80d01, 0x6e12, 0x11cf, 0xac, 0x4a, 0x00, 0x00, 0xc0, 0x38, 0x25, 0xa1);
@ -136,13 +137,22 @@ struct D3DRMBOX {
D3DVECTOR max;
};
struct TexCoord {
float u, v;
};
struct D3DRMVERTEX {
D3DVECTOR position;
D3DVECTOR normal;
D3DVALUE tu, tv;
union {
struct {
D3DVALUE tu, tv;
};
TexCoord texCoord;
};
};
struct IDirect3DRMObject : public IUnknown {
struct IDirect3DRMObject : virtual public IUnknown {
virtual HRESULT AddDestroyCallback(D3DRMOBJECTCALLBACK callback, void* arg) = 0;
virtual HRESULT DeleteDestroyCallback(D3DRMOBJECTCALLBACK callback, void* arg) = 0;
virtual HRESULT SetAppData(LPD3DRM_APPDATA appData) = 0;
@ -182,8 +192,8 @@ struct IDirect3DRMMesh : public IDirect3DRMVisual {
DWORD* vertexCount,
DWORD* faceCount,
DWORD* vertexPerFace,
DWORD* dataSize,
DWORD* data
DWORD* indexCount,
DWORD* indices
) = 0;
virtual DWORD GetGroupCount() = 0;
virtual HRESULT SetGroupColor(DWORD groupIndex, D3DCOLOR color) = 0;

View File

@ -0,0 +1,8 @@
#pragma once
DEFINE_GUID(IID_IDirect3DRMMiniwinDevice, 0x6eb09673, 0x8d30, 0x4d8a, 0x8d, 0x81, 0x34, 0xea, 0x69, 0x30, 0x12, 0x01);
struct IDirect3DRMMiniwinDevice : virtual public IUnknown {
virtual float GetShininessFactor() = 0;
virtual HRESULT SetShininessFactor(float factor) = 0;
};

View File

@ -1,22 +1,24 @@
#include "d3drmrenderer_opengl15.h"
#include "d3drmrenderer_opengl1.h"
#include "ddraw_impl.h"
#include "ddsurface_impl.h"
#include "mathutils.h"
#include "meshutils.h"
#include <GL/glew.h>
#include <algorithm>
#include <cstring>
#include <vector>
Direct3DRMRenderer* OpenGL15Renderer::Create(DWORD width, DWORD height)
Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_Window* window = DDWindow;
bool testWindow = false;
if (!window) {
window = SDL_CreateWindow("OpenGL 1.5 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
window = SDL_CreateWindow("OpenGL 1.2 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
testWindow = true;
}
@ -37,12 +39,16 @@ Direct3DRMRenderer* OpenGL15Renderer::Create(DWORD width, DWORD height)
return nullptr;
}
if (!GLEW_EXT_framebuffer_object) {
if (testWindow) {
SDL_DestroyWindow(window);
}
return nullptr;
}
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
// Setup FBO
GLuint fbo;
@ -74,10 +80,10 @@ Direct3DRMRenderer* OpenGL15Renderer::Create(DWORD width, DWORD height)
SDL_DestroyWindow(window);
}
return new OpenGL15Renderer(width, height, context, fbo, colorTex, depthRb);
return new OpenGL1Renderer(width, height, context, fbo, colorTex, depthRb);
}
OpenGL15Renderer::OpenGL15Renderer(
OpenGL1Renderer::OpenGL1Renderer(
int width,
int height,
SDL_GLContext context,
@ -88,32 +94,33 @@ OpenGL15Renderer::OpenGL15Renderer(
: m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb)
{
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888);
m_useVBOs = GLEW_ARB_vertex_buffer_object;
}
OpenGL15Renderer::~OpenGL15Renderer()
OpenGL1Renderer::~OpenGL1Renderer()
{
if (m_renderedImage) {
SDL_DestroySurface(m_renderedImage);
}
}
void OpenGL15Renderer::PushLights(const SceneLight* lightsArray, size_t count)
void OpenGL1Renderer::PushLights(const SceneLight* lightsArray, size_t count)
{
m_lights.assign(lightsArray, lightsArray + count);
}
void OpenGL15Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
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 {
OpenGL15Renderer* renderer;
OpenGL1Renderer* renderer;
Uint32 textureId;
};
void OpenGL15Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture)
void OpenGL1Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture)
{
auto* ctx = new TextureDestroyContextGL{this, id};
texture->AddDestroyCallback(
@ -131,7 +138,7 @@ void OpenGL15Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture*
);
}
Uint32 OpenGL15Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
{
auto texture = static_cast<Direct3DRMTextureImpl*>(iTexture);
auto surface = static_cast<DirectDrawSurfaceImpl*>(texture->m_surface);
@ -176,7 +183,7 @@ Uint32 OpenGL15Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i];
if (tex.texture == nullptr) {
if (!tex.texture) {
tex.texture = texture;
tex.version = texture->m_version;
tex.glTextureId = texId;
@ -190,17 +197,146 @@ Uint32 OpenGL15Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
return (Uint32) (m_textures.size() - 1);
}
DWORD OpenGL15Renderer::GetWidth()
GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs)
{
GLMeshCacheEntry cache{&meshGroup, meshGroup.version};
cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT;
std::vector<D3DRMVERTEX> vertices;
if (cache.flat) {
FlattenSurfaces(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
meshGroup.texture != nullptr,
vertices,
cache.indices
);
}
else {
vertices = meshGroup.vertices;
cache.indices = meshGroup.indices;
}
if (meshGroup.texture != nullptr) {
cache.texcoords.resize(vertices.size());
std::transform(vertices.begin(), vertices.end(), cache.texcoords.begin(), [](const D3DRMVERTEX& v) {
return v.texCoord;
});
}
cache.positions.resize(vertices.size());
std::transform(vertices.begin(), vertices.end(), cache.positions.begin(), [](const D3DRMVERTEX& v) {
return v.position;
});
cache.normals.resize(vertices.size());
std::transform(vertices.begin(), vertices.end(), cache.normals.begin(), [](const D3DRMVERTEX& v) {
return v.normal;
});
if (useVBOs) {
glGenBuffers(1, &cache.vboPositions);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions);
glBufferData(
GL_ARRAY_BUFFER,
cache.positions.size() * sizeof(D3DVECTOR),
cache.positions.data(),
GL_STATIC_DRAW
);
glGenBuffers(1, &cache.vboNormals);
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) {
glGenBuffers(1, &cache.vboTexcoords);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords);
glBufferData(
GL_ARRAY_BUFFER,
cache.texcoords.size() * sizeof(TexCoord),
cache.texcoords.data(),
GL_STATIC_DRAW
);
}
glGenBuffers(1, &cache.ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache.ibo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
cache.indices.size() * sizeof(Uint32),
cache.indices.data(),
GL_STATIC_DRAW
);
}
return cache;
}
struct GLMeshDestroyContext {
OpenGL1Renderer* renderer;
Uint32 id;
};
void OpenGL1Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new GLMeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<GLMeshDestroyContext*>(arg);
auto& cache = ctx->renderer->m_meshs[ctx->id];
cache.meshGroup = nullptr;
if (ctx->renderer->m_useVBOs) {
glDeleteBuffers(1, &cache.vboPositions);
glDeleteBuffers(1, &cache.vboNormals);
glDeleteBuffers(1, &cache.vboTexcoords);
glDeleteBuffers(1, &cache.ibo);
}
delete ctx;
},
ctx
);
}
Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
{
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
cache = std::move(GLUploadMesh(*meshGroup, m_useVBOs));
}
return i;
}
}
auto newCache = GLUploadMesh(*meshGroup, m_useVBOs);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (!cache.meshGroup) {
cache = std::move(newCache);
AddMeshDestroyCallback(i, mesh);
return i;
}
}
m_meshs.push_back(std::move(newCache));
AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh);
return (Uint32) (m_meshs.size() - 1);
}
DWORD OpenGL1Renderer::GetWidth()
{
return m_width;
}
DWORD OpenGL15Renderer::GetHeight()
DWORD OpenGL1Renderer::GetHeight()
{
return m_height;
}
void OpenGL15Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
{
halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
@ -213,12 +349,12 @@ void OpenGL15Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
memset(helDesc, 0, sizeof(D3DDEVICEDESC));
}
const char* OpenGL15Renderer::GetName()
const char* OpenGL1Renderer::GetName()
{
return "OpenGL 1.5 HAL";
return "OpenGL 1.2 HAL";
}
HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
HRESULT OpenGL1Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
if (!DDBackBuffer) {
return DDERR_GENERIC;
@ -303,9 +439,8 @@ HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
return DD_OK;
}
void OpenGL15Renderer::SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
void OpenGL1Renderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -321,19 +456,7 @@ void OpenGL15Renderer::SubmitDraw(
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
// Bind texture if present
if (appearance.textureId != NO_TEXTURE_ID) {
auto& tex = m_textures[appearance.textureId];
if (tex.glTextureId) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
}
}
else {
glDisable(GL_TEXTURE_2D);
}
float shininess = appearance.shininess;
float shininess = appearance.shininess * m_shininessFactor;
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
if (shininess != 0.0f) {
GLfloat whiteSpec[] = {shininess, shininess, shininess, shininess};
@ -344,19 +467,62 @@ void OpenGL15Renderer::SubmitDraw(
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
}
glBegin(GL_TRIANGLES);
for (size_t i = 0; i < count; i++) {
const GeometryVertex& v = vertices[i];
glNormal3f(v.normals.x, v.normals.y, v.normals.z);
glTexCoord2f(v.texCoord.u, v.texCoord.v);
glVertex3f(v.position.x, v.position.y, v.position.z);
auto& mesh = m_meshs[meshId];
if (mesh.flat) {
glShadeModel(GL_FLAT);
}
else {
glShadeModel(GL_SMOOTH);
}
// Bind texture if present
if (appearance.textureId != NO_TEXTURE_ID) {
auto& tex = m_textures[appearance.textureId];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
else {
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
if (m_useVBOs) {
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions);
glVertexPointer(3, GL_FLOAT, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals);
glNormalPointer(GL_FLOAT, 0, nullptr);
if (appearance.textureId != NO_TEXTURE_ID) {
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords);
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
else {
glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data());
glNormalPointer(GL_FLOAT, 0, mesh.normals.data());
if (appearance.textureId != NO_TEXTURE_ID) {
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data());
}
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, mesh.indices.data());
}
glEnd();
glPopMatrix();
}
HRESULT OpenGL15Renderer::FinalizeFrame()
HRESULT OpenGL1Renderer::FinalizeFrame()
{
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

View File

@ -3,11 +3,94 @@
#include "d3drmrenderer_sdl3gpu.h"
#include "ddraw_impl.h"
#include "mathutils.h"
#include "meshutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
#include <cstddef>
struct ScopedSurface {
SDL_Surface* ptr = nullptr;
~ScopedSurface()
{
if (ptr) {
SDL_DestroySurface(ptr);
}
}
void release() { ptr = nullptr; }
};
struct ScopedTexture {
SDL_GPUDevice* dev;
SDL_GPUTexture* ptr = nullptr;
~ScopedTexture()
{
if (ptr) {
SDL_ReleaseGPUTexture(dev, ptr);
}
}
void release() { ptr = nullptr; }
};
struct ScopedTransferBuffer {
SDL_GPUDevice* dev;
SDL_GPUTransferBuffer* ptr = nullptr;
~ScopedTransferBuffer()
{
if (ptr) {
SDL_ReleaseGPUTransferBuffer(dev, ptr);
}
}
void release() { ptr = nullptr; }
};
struct ScopedDevice {
SDL_GPUDevice* ptr = nullptr;
~ScopedDevice()
{
if (ptr) {
SDL_DestroyGPUDevice(ptr);
}
}
void release() { ptr = nullptr; }
};
struct ScopedPipeline {
SDL_GPUDevice* dev;
SDL_GPUGraphicsPipeline* ptr = nullptr;
~ScopedPipeline()
{
if (ptr) {
SDL_ReleaseGPUGraphicsPipeline(dev, ptr);
}
}
void release() { ptr = nullptr; }
};
struct ScopedSampler {
SDL_GPUDevice* dev;
SDL_GPUSampler* ptr = nullptr;
~ScopedSampler()
{
if (ptr) {
SDL_ReleaseGPUSampler(dev, ptr);
}
}
void release() { ptr = nullptr; }
};
struct ScopedShader {
SDL_GPUDevice* dev;
SDL_GPUShader* ptr = nullptr;
~ScopedShader()
{
if (ptr) {
SDL_ReleaseGPUShader(dev, ptr);
}
}
void release() { ptr = nullptr; }
};
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device, bool depthWrite)
{
const SDL_GPUShaderCreateInfo* vertexCreateInfo =
@ -15,8 +98,8 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
if (!vertexCreateInfo) {
return nullptr;
}
SDL_GPUShader* vertexShader = SDL_CreateGPUShader(device, vertexCreateInfo);
if (!vertexShader) {
ScopedShader vertexShader{device, SDL_CreateGPUShader(device, vertexCreateInfo)};
if (!vertexShader.ptr) {
return nullptr;
}
@ -25,32 +108,31 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
if (!fragmentCreateInfo) {
return nullptr;
}
SDL_GPUShader* fragmentShader = SDL_CreateGPUShader(device, fragmentCreateInfo);
if (!fragmentShader) {
ScopedShader fragmentShader{device, SDL_CreateGPUShader(device, fragmentCreateInfo)};
if (!fragmentShader.ptr) {
return nullptr;
}
SDL_GPUVertexBufferDescription vertexBufferDescs[1] = {};
vertexBufferDescs[0].slot = 0;
vertexBufferDescs[0].pitch = sizeof(GeometryVertex);
vertexBufferDescs[0].pitch = sizeof(D3DRMVERTEX);
vertexBufferDescs[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
vertexBufferDescs[0].instance_step_rate = 0;
SDL_GPUVertexAttribute vertexAttrs[3] = {};
vertexAttrs[0].location = 0;
vertexAttrs[0].buffer_slot = 0;
vertexAttrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
vertexAttrs[0].offset = offsetof(GeometryVertex, position);
vertexAttrs[0].offset = offsetof(D3DRMVERTEX, position);
vertexAttrs[1].location = 1;
vertexAttrs[1].buffer_slot = 0;
vertexAttrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
vertexAttrs[1].offset = offsetof(GeometryVertex, normals);
vertexAttrs[1].offset = offsetof(D3DRMVERTEX, normal);
vertexAttrs[2].location = 2;
vertexAttrs[2].buffer_slot = 0;
vertexAttrs[2].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
vertexAttrs[2].offset = offsetof(GeometryVertex, texCoord);
vertexAttrs[2].offset = offsetof(D3DRMVERTEX, texCoord);
SDL_GPUVertexInputState vertexInputState = {};
vertexInputState.vertex_buffer_descriptions = vertexBufferDescs;
@ -81,107 +163,135 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
rasterizerState.enable_depth_clip = true;
SDL_GPUGraphicsPipelineCreateInfo pipelineCreateInfo = {};
pipelineCreateInfo.rasterizer_state = rasterizerState;
pipelineCreateInfo.vertex_shader = vertexShader;
pipelineCreateInfo.fragment_shader = fragmentShader;
pipelineCreateInfo.vertex_shader = vertexShader.ptr;
pipelineCreateInfo.fragment_shader = fragmentShader.ptr;
pipelineCreateInfo.vertex_input_state = vertexInputState;
pipelineCreateInfo.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets;
pipelineCreateInfo.target_info.num_color_targets = 1;
pipelineCreateInfo.target_info.has_depth_stencil_target = true;
pipelineCreateInfo.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
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_write = depthWrite;
pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false;
pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS;
pipelineCreateInfo.depth_stencil_state.write_mask = 0xff;
pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets;
pipelineCreateInfo.target_info.num_color_targets = 1;
pipelineCreateInfo.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
pipelineCreateInfo.target_info.has_depth_stencil_target = true;
SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo);
// Clean up shader resources
SDL_ReleaseGPUShader(device, vertexShader);
SDL_ReleaseGPUShader(device, fragmentShader);
return pipeline;
}
Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
{
SDL_GPUDevice* device = SDL_CreateGPUDevice(
ScopedDevice device{SDL_CreateGPUDevice(
SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL,
true,
NULL
);
if (device == NULL) {
nullptr
)};
if (!device.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUDevice failed (%s)", SDL_GetError());
return nullptr;
}
SDL_GPUGraphicsPipeline* opaquePipeline = InitializeGraphicsPipeline(device, true);
if (!opaquePipeline) {
ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, true)};
if (!opaquePipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline");
return nullptr;
}
SDL_GPUGraphicsPipeline* transparentPipeline = InitializeGraphicsPipeline(device, false);
if (!transparentPipeline) {
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, false)};
if (!transparentPipeline.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline");
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.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
SDL_GPUTexture* transferTexture = SDL_CreateGPUTexture(device, &textureInfo);
if (!transferTexture) {
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(device, transparentPipeline);
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 depthTextureInfo = {};
depthTextureInfo.type = SDL_GPU_TEXTURETYPE_2D;
depthTextureInfo.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
depthTextureInfo.width = width;
depthTextureInfo.height = height;
depthTextureInfo.layer_count_or_depth = 1;
depthTextureInfo.num_levels = 1;
depthTextureInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET;
SDL_GPUTexture* depthTexture = SDL_CreateGPUTexture(device, &depthTextureInfo);
if (!depthTexture) {
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(device, transparentPipeline);
SDL_ReleaseGPUTexture(device, transferTexture);
SDL_GPUTextureCreateInfo depthTexInfo = textureInfo;
depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
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 downloadTransferInfo = {};
downloadTransferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
downloadTransferInfo.size = static_cast<Uint32>(width * height * 4);
SDL_GPUTransferBuffer* downloadTransferBuffer = SDL_CreateGPUTransferBuffer(device, &downloadTransferInfo);
if (!downloadTransferBuffer) {
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(device, transparentPipeline);
SDL_ReleaseGPUTexture(device, depthTexture);
SDL_ReleaseGPUTexture(device, transferTexture);
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer failed (%s)", SDL_GetError());
SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {};
downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
downloadBufferInfo.size = width * height * 4;
ScopedTransferBuffer downloadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &downloadBufferInfo)};
if (!downloadBuffer.ptr) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer filed for download buffer (%s)",
SDL_GetError()
);
return nullptr;
}
return new Direct3DRMSDL3GPURenderer(
// Setup texture CPU-to-GPU transfer
SDL_GPUTransferBufferCreateInfo uploadBufferInfo = {};
uploadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
uploadBufferInfo.size = 256 * 256 * 4; // Largest known game texture
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());
return nullptr;
}
SDL_GPUSamplerCreateInfo samplerInfo = {};
samplerInfo.min_filter = SDL_GPU_FILTER_LINEAR;
samplerInfo.mag_filter = SDL_GPU_FILTER_LINEAR;
samplerInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR;
samplerInfo.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
samplerInfo.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
samplerInfo.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)};
if (!sampler.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError());
return nullptr;
}
auto renderer = new Direct3DRMSDL3GPURenderer(
width,
height,
device,
opaquePipeline,
transparentPipeline,
transferTexture,
depthTexture,
downloadTransferBuffer
device.ptr,
opaquePipeline.ptr,
transparentPipeline.ptr,
transferTexture.ptr,
depthTexture.ptr,
sampler.ptr,
uploadBuffer.ptr,
downloadBuffer.ptr
);
// Release resources so they don't get cleaned up
device.release();
opaquePipeline.release();
transparentPipeline.release();
transferTexture.release();
depthTexture.release();
sampler.release();
uploadBuffer.release();
downloadBuffer.release();
return renderer;
}
Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
@ -192,22 +302,46 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUTransferBuffer* downloadTransferBuffer
SDL_GPUSampler* sampler,
SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer
)
: m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline),
m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture),
m_downloadTransferBuffer(downloadTransferBuffer)
m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer)
{
SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ABGR8888);
if (!dummySurface) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError());
return;
}
if (!SDL_LockSurface(dummySurface)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to lock surface: %s", SDL_GetError());
SDL_DestroySurface(dummySurface);
return;
}
((Uint32*) dummySurface->pixels)[0] = 0xFFFFFFFF;
SDL_UnlockSurface(dummySurface);
m_dummyTexture = CreateTextureFromSurface(dummySurface);
SDL_DestroySurface(dummySurface);
}
Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer()
{
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
SDL_ReleaseGPUTransferBuffer(m_device, m_downloadTransferBuffer);
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_ReleaseGPUGraphicsPipeline(m_device, m_opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline);
if (m_uploadFence) {
SDL_ReleaseGPUFence(m_device, m_uploadFence);
}
SDL_DestroyGPUDevice(m_device);
}
@ -228,9 +362,280 @@ void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D
memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D));
}
Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* texture)
void Direct3DRMSDL3GPURenderer::WaitForPendingUpload()
{
return NO_TEXTURE_ID;
if (!m_uploadFence) {
return;
}
bool success = SDL_WaitForGPUFences(m_device, true, &m_uploadFence, 1);
SDL_ReleaseGPUFence(m_device, m_uploadFence);
m_uploadFence = nullptr;
if (!success) {
return;
}
}
struct SDLTextureDestroyContext {
Direct3DRMSDL3GPURenderer* renderer;
Uint32 id;
};
void Direct3DRMSDL3GPURenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture)
{
auto* ctx = new SDLTextureDestroyContext{this, id};
texture->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<SDLTextureDestroyContext*>(arg);
auto& cache = ctx->renderer->m_textures[ctx->id];
if (cache.gpuTexture) {
SDL_ReleaseGPUTexture(ctx->renderer->m_device, cache.gpuTexture);
cache.gpuTexture = nullptr;
cache.texture = nullptr;
}
delete ctx;
},
ctx
);
}
SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* surface)
{
ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888)};
if (!surf.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError());
return nullptr;
}
const Uint32 dataSize = surf.ptr->pitch * surf.ptr->h;
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
textureInfo.width = surf.ptr->w;
textureInfo.height = surf.ptr->h;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
ScopedTexture texture{m_device, SDL_CreateGPUTexture(m_device, &textureInfo)};
if (!texture.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture (%s)", SDL_GetError());
return nullptr;
}
SDL_GPUTransferBuffer* transferBuffer = GetUploadBuffer(dataSize);
void* transferData = SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer (%s)", SDL_GetError());
return nullptr;
}
memcpy(transferData, surf.ptr->pixels, dataSize);
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
SDL_GPUTextureTransferInfo transferRegionInfo = {};
transferRegionInfo.transfer_buffer = transferBuffer;
SDL_GPUTextureRegion textureRegion = {};
textureRegion.texture = texture.ptr;
textureRegion.w = surf.ptr->w;
textureRegion.h = surf.ptr->h;
textureRegion.d = 1;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_AcquireGPUCommandBuffer in CreateTextureFromSurface failed (%s)",
SDL_GetError()
);
return nullptr;
}
SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_UploadToGPUTexture(pass, &transferRegionInfo, &textureRegion, false);
SDL_EndGPUCopyPass(pass);
m_uploadFence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
auto texptr = texture.ptr;
// Release texture ownership so caller can manage it safely
texture.release();
return texptr;
}
Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture)
{
auto texture = static_cast<Direct3DRMTextureImpl*>(iTexture);
auto surface = static_cast<DirectDrawSurfaceImpl*>(texture->m_surface);
SDL_Surface* surf = surface->m_surface;
for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i];
if (tex.texture == texture) {
if (tex.version != texture->m_version) {
SDL_ReleaseGPUTexture(m_device, tex.gpuTexture);
tex.gpuTexture = CreateTextureFromSurface(surf);
if (!tex.gpuTexture) {
return NO_TEXTURE_ID;
}
tex.version = texture->m_version;
}
return i;
}
}
SDL_GPUTexture* newTex = CreateTextureFromSurface(surf);
if (!newTex) {
return NO_TEXTURE_ID;
}
for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& tex = m_textures[i];
if (!tex.texture) {
tex = {texture, texture->m_version, newTex};
AddTextureDestroyCallback(i, texture);
return i;
}
}
m_textures.push_back({texture, texture->m_version, newTex});
AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture);
return (Uint32) (m_textures.size() - 1);
}
SDL3MeshCache Direct3DRMSDL3GPURenderer::UploadMesh(const MeshGroup& meshGroup)
{
std::vector<D3DRMVERTEX> finalVertices;
std::vector<Uint16> finalIndices;
if (meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT) {
std::vector<DWORD> newIndices;
FlattenSurfaces(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
meshGroup.texture != nullptr,
finalVertices,
newIndices
);
finalIndices.assign(newIndices.begin(), newIndices.end());
}
else {
finalVertices = meshGroup.vertices;
finalIndices.assign(meshGroup.indices.begin(), meshGroup.indices.end());
}
SDL_GPUBufferCreateInfo vertexBufferCreateInfo = {};
vertexBufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
vertexBufferCreateInfo.size = sizeof(D3DRMVERTEX) * finalVertices.size();
SDL_GPUBuffer* vertexBuffer = SDL_CreateGPUBuffer(m_device, &vertexBufferCreateInfo);
if (!vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer failed (%s)", SDL_GetError());
return {};
}
SDL_GPUBufferCreateInfo indexBufferCreateInfo = {};
indexBufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_INDEX;
indexBufferCreateInfo.size = sizeof(Uint16) * finalIndices.size();
SDL_GPUBuffer* indexBuffer = SDL_CreateGPUBuffer(m_device, &indexBufferCreateInfo);
if (!indexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create index buffer (%s)", SDL_GetError());
return {};
}
size_t verticesSize = sizeof(D3DRMVERTEX) * finalVertices.size();
size_t indicesSize = sizeof(Uint16) * finalIndices.size();
SDL_GPUTransferBuffer* uploadBuffer = GetUploadBuffer(verticesSize + indicesSize);
if (!uploadBuffer) {
return {};
}
auto* transferData = static_cast<Uint8*>(SDL_MapGPUTransferBuffer(m_device, uploadBuffer, false));
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Transfer buffer mapping failed (%s)", SDL_GetError());
return {};
}
memcpy(transferData, finalVertices.data(), verticesSize);
memcpy(transferData + verticesSize, finalIndices.data(), indicesSize);
SDL_UnmapGPUTransferBuffer(m_device, uploadBuffer);
SDL_GPUTransferBufferLocation transferLocation = {uploadBuffer};
// Upload vertex + index data to GPU
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
return {};
}
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUBufferRegion vertexRegion = {};
vertexRegion.buffer = vertexBuffer;
vertexRegion.size = verticesSize;
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &vertexRegion, false);
SDL_GPUTransferBufferLocation indexTransferLocation = {};
indexTransferLocation.transfer_buffer = uploadBuffer;
indexTransferLocation.offset = verticesSize;
SDL_GPUBufferRegion indexRegion = {};
indexRegion.buffer = indexBuffer;
indexRegion.size = indicesSize;
SDL_UploadToGPUBuffer(copyPass, &indexTransferLocation, &indexRegion, false);
SDL_EndGPUCopyPass(copyPass);
m_uploadFence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
return {&meshGroup, meshGroup.version, vertexBuffer, indexBuffer, finalIndices.size()};
}
struct SDLMeshDestroyContext {
Direct3DRMSDL3GPURenderer* renderer;
Uint32 id;
};
void Direct3DRMSDL3GPURenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new SDLMeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<SDLMeshDestroyContext*>(arg);
auto& cache = ctx->renderer->m_meshs[ctx->id];
SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer);
cache.meshGroup = nullptr;
delete ctx;
},
ctx
);
}
Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
{
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer);
cache = std::move(UploadMesh(*meshGroup));
}
return i;
}
}
auto newCache = UploadMesh(*meshGroup);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (!cache.meshGroup) {
cache = std::move(newCache);
AddMeshDestroyCallback(i, mesh);
return i;
}
}
m_meshs.push_back(std::move(newCache));
AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh);
return (Uint32) (m_meshs.size() - 1);
}
DWORD Direct3DRMSDL3GPURenderer::GetWidth()
@ -261,6 +666,43 @@ const char* Direct3DRMSDL3GPURenderer::GetName()
return "SDL3 GPU HAL";
}
void PackNormalMatrix(const Matrix3x3& normalMatrix3x3, D3DRMMATRIX4D& packedNormalMatrix4x4)
{
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
packedNormalMatrix4x4[col][row] = normalMatrix3x3[row][col];
}
packedNormalMatrix4x4[3][row] = 0.0f;
}
for (int col = 0; col < 4; ++col) {
packedNormalMatrix4x4[col][3] = 0.0f;
}
}
SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
{
WaitForPendingUpload();
if (m_uploadBufferSize < size) {
SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer);
SDL_GPUTransferBufferCreateInfo transferCreateInfo = {};
transferCreateInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
transferCreateInfo.size = size;
m_uploadBuffer = SDL_CreateGPUTransferBuffer(m_device, &transferCreateInfo);
if (!m_uploadBuffer) {
m_uploadBufferSize = 0;
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer failed for updating upload buffer (%s)",
SDL_GetError()
);
}
m_uploadBufferSize = size;
}
return m_uploadBuffer;
}
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
if (!DDBackBuffer) {
@ -277,171 +719,97 @@ HRESULT Direct3DRMSDL3GPURenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.clear_depth = 1.f;
depthStencilTargetInfo.clear_depth = 0.0f;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
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;
}
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_EndGPURenderPass(renderPass);
if (!SDL_SubmitGPUCommandBuffer(cmdbuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
m_renderPass = SDL_BeginGPURenderPass(m_cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_BindGPUGraphicsPipeline(m_renderPass, m_opaquePipeline);
return DD_OK;
}
void Direct3DRMSDL3GPURenderer::SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
{
// TODO only switch piplinen after all opaque's have been rendered
SDL_BindGPUGraphicsPipeline(m_renderPass, appearance.color.a == 255 ? m_opaquePipeline : m_transparentPipeline);
D3DRMMATRIX4D worldViewMatrix;
MultiplyMatrix(worldViewMatrix, worldMatrix, m_viewMatrix);
memcpy(&m_uniforms.worldViewMatrix, worldViewMatrix, sizeof(D3DRMMATRIX4D));
PackNormalMatrix(normalMatrix, m_uniforms.normalMatrix);
m_fragmentShadingData.color = appearance.color;
m_fragmentShadingData.shininess = appearance.shininess;
m_fragmentShadingData.shininess = appearance.shininess * m_shininessFactor;
bool useTexture = appearance.textureId != NO_TEXTURE_ID;
m_fragmentShadingData.useTexture = appearance.textureId != NO_TEXTURE_ID;
if (count > m_vertexBufferCount) {
if (m_vertexBuffer) {
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
}
SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
bufferCreateInfo.size = static_cast<Uint32>(sizeof(GeometryVertex) * count);
m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!m_vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer returned NULL buffer (%s)", SDL_GetError());
}
m_vertexBufferCount = count;
}
m_vertexCount = count;
if (!count) {
return;
}
SDL_GPUTransferBufferCreateInfo transferCreateInfo = {};
transferCreateInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
transferCreateInfo.size = static_cast<Uint32>(sizeof(GeometryVertex) * m_vertexCount);
SDL_GPUTransferBuffer* transferBuffer = SDL_CreateGPUTransferBuffer(m_device, &transferCreateInfo);
if (!transferBuffer) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer returned NULL transfer buffer (%s)",
SDL_GetError()
);
}
GeometryVertex* transferData = (GeometryVertex*) SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer returned NULL buffer (%s)", SDL_GetError());
}
memcpy(transferData, vertices, m_vertexCount * sizeof(GeometryVertex));
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
return;
}
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTransferBufferLocation transferLocation = {};
transferLocation.transfer_buffer = transferBuffer;
transferLocation.offset = 0;
SDL_GPUBufferRegion bufferRegion = {};
bufferRegion.buffer = m_vertexBuffer;
bufferRegion.offset = 0;
bufferRegion.size = static_cast<Uint32>(sizeof(GeometryVertex) * m_vertexCount);
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
SDL_ReleaseGPUTransferBuffer(m_device, transferBuffer);
auto& mesh = m_meshs[meshId];
// Render the graphics
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.load_op = SDL_GPU_LOADOP_LOAD;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_LOAD;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_BindGPUGraphicsPipeline(renderPass, appearance.color.a == 255 ? m_opaquePipeline : m_transparentPipeline);
SDL_PushGPUVertexUniformData(cmdbuf, 0, &m_uniforms, sizeof(m_uniforms));
SDL_PushGPUFragmentUniformData(cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData));
if (m_vertexCount) {
SDL_GPUBufferBinding vertexBufferBinding = {};
vertexBufferBinding.buffer = m_vertexBuffer;
vertexBufferBinding.offset = 0;
SDL_BindGPUVertexBuffers(renderPass, 0, &vertexBufferBinding, 1);
SDL_DrawGPUPrimitives(renderPass, m_vertexCount, 1, 0, 0);
}
SDL_EndGPURenderPass(renderPass);
if (!SDL_SubmitGPUCommandBuffer(cmdbuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer failes (%s)", SDL_GetError());
}
SDL_GPUTexture* texture = useTexture ? m_textures[appearance.textureId].gpuTexture : m_dummyTexture;
SDL_GPUTextureSamplerBinding samplerBinding = {texture, m_sampler};
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 = {mesh.vertexBuffer};
SDL_BindGPUVertexBuffers(m_renderPass, 0, &vertexBufferBinding, 1);
SDL_GPUBufferBinding indexBufferBinding = {mesh.indexBuffer};
SDL_BindGPUIndexBuffer(m_renderPass, &indexBufferBinding, SDL_GPU_INDEXELEMENTSIZE_16BIT);
SDL_DrawGPUIndexedPrimitives(m_renderPass, mesh.indexCount, 1, 0, 0, 0);
}
HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
{
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (cmdbuf == NULL) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
SDL_EndGPURenderPass(m_renderPass);
m_renderPass = nullptr;
// Download rendered image
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTextureRegion region = {};
region.texture = m_transferTexture;
region.w = m_width;
region.h = m_height;
region.d = 1;
SDL_GPUTextureTransferInfo transferInfo = {};
transferInfo.transfer_buffer = m_downloadTransferBuffer;
transferInfo.offset = 0;
transferInfo.transfer_buffer = m_downloadBuffer;
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(m_cmdbuf);
SDL_DownloadFromGPUTexture(copyPass, &region, &transferInfo);
SDL_EndGPUCopyPass(copyPass);
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
if (!SDL_WaitForGPUFences(m_device, true, &fence, 1)) {
WaitForPendingUpload();
// Render the frame
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf);
m_cmdbuf = nullptr;
if (!fence) {
return DDERR_GENERIC;
}
bool success = SDL_WaitForGPUFences(m_device, true, &fence, 1);
SDL_ReleaseGPUFence(m_device, fence);
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadTransferBuffer, false);
if (!success) {
return DDERR_GENERIC;
}
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false);
if (!downloadedData) {
return DDERR_GENERIC;
}
SDL_DestroySurface(m_renderedImage);
m_renderedImage = SDL_CreateSurfaceFrom(m_width, m_height, SDL_PIXELFORMAT_ABGR8888, downloadedData, m_width * 4);
SDL_Surface* convertedRender = SDL_ConvertSurface(m_renderedImage, SDL_PIXELFORMAT_RGBA8888);
SDL_DestroySurface(m_renderedImage);
SDL_UnmapGPUTransferBuffer(m_device, m_downloadTransferBuffer);
m_renderedImage = convertedRender;
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr);
SDL_Surface* renderedImage =
SDL_CreateSurfaceFrom(m_width, m_height, SDL_PIXELFORMAT_ABGR8888, downloadedData, m_width * 4);
SDL_BlitSurface(renderedImage, nullptr, DDBackBuffer, nullptr);
SDL_DestroySurface(renderedImage);
SDL_UnmapGPUTransferBuffer(m_device, m_downloadBuffer);
return DD_OK;
}

View File

@ -10,11 +10,11 @@
// DXIL only makes sense on Windows platforms
#if defined(SDL_PLATFORM_WINDOWS)
static const Uint8 PositionColor_vert_dxil[4724] = {
0x44, 0x58, 0x42, 0x43, 0x90, 0xb8, 0x23, 0x65, 0xe9, 0x7d, 0x7d, 0xb6, 0xd3, 0x7b, 0x28, 0xc6,
0x2f, 0x0e, 0x0b, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x74, 0x12, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
static const Uint8 PositionColor_vert_dxil[5132] = {
0x44, 0x58, 0x42, 0x43, 0x4a, 0x28, 0x54, 0x85, 0x4b, 0xb0, 0x04, 0x11, 0x56, 0x33, 0x94, 0x85,
0x05, 0x1a, 0xb4, 0x05, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x14, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00,
0xc4, 0x02, 0x00, 0x00, 0x9c, 0x09, 0x00, 0x00, 0xb8, 0x09, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30,
0xc4, 0x02, 0x00, 0x00, 0x18, 0x0a, 0x00, 0x00, 0x34, 0x0a, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31,
0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
@ -53,11 +53,11 @@ static const Uint8 PositionColor_vert_dxil[4724] = {
0x03, 0x02, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x43, 0x00,
0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x44, 0x03,
0x03, 0x04, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xd0, 0x06, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00,
0xb4, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0xb8, 0x06, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x4c, 0x07, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00,
0xd3, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x34, 0x07, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xca, 0x01, 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, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14,
@ -67,78 +67,84 @@ static const Uint8 PositionColor_vert_dxil[4724] = {
0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff,
0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00,
0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06,
0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09,
0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09,
0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14,
0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x68, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66,
0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66,
0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, 0x42, 0xa6, 0x18, 0x80,
0x10, 0x52, 0x06, 0xa1, 0xa3, 0x86, 0xcb, 0x9f, 0xb0, 0x87, 0x90, 0x7c, 0x6e, 0xa3, 0x8a, 0x95,
0x98, 0xfc, 0xe2, 0xb6, 0x11, 0x31, 0xc6, 0x18, 0x54, 0xee, 0x19, 0x2e, 0x7f, 0xc2, 0x1e, 0x42,
0xf2, 0x43, 0xa0, 0x19, 0x16, 0x02, 0x05, 0xab, 0x10, 0x8a, 0x30, 0x42, 0xad, 0x14, 0x83, 0x8c,
0x31, 0xe8, 0xcd, 0x11, 0x04, 0xc5, 0x60, 0xa4, 0x10, 0x12, 0x49, 0x0e, 0x04, 0x0c, 0x23, 0x10,
0x43, 0x12, 0xd4, 0x03, 0x83, 0xc3, 0x91, 0xa6, 0x05, 0xc0, 0x1c, 0x6a, 0xf2, 0x27, 0xec, 0x21,
0xfe, 0x17, 0x21, 0xac, 0xc7, 0x89, 0x26, 0xb7, 0x41, 0x0a, 0x27, 0x62, 0x24, 0x24, 0x58, 0x4b,
0x37, 0x19, 0x08, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79,
0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d,
0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0,
0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e,
0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73,
0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10,
0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07,
0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78,
0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0xe4, 0x79, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0xc8, 0x23, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00,
0x15, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47,
0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50, 0x0c, 0x05, 0x28, 0x50, 0x04, 0x85, 0x50, 0x06,
0xe5, 0x50, 0x12, 0x05, 0x18, 0x50, 0x1e, 0xc5, 0x51, 0xac, 0x01, 0x05, 0x51, 0x18, 0x54, 0x4a,
0x62, 0x04, 0xa0, 0x0c, 0x8a, 0xa0, 0x10, 0x28, 0xd6, 0x00, 0xdd, 0x19, 0x00, 0xc2, 0x33, 0x00,
0x94, 0xc7, 0x62, 0x14, 0x08, 0xc4, 0xfb, 0x00, 0xc4, 0xfb, 0x00, 0xc4, 0xfb, 0x00, 0x08, 0x04,
0x02, 0x80, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00,
0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x8f, 0x0c, 0x6f, 0x0c, 0x05, 0x4e, 0x2e, 0xcd,
0x2e, 0x8c, 0xae, 0x2c, 0x05, 0x24, 0xc6, 0x05, 0xc7, 0x05, 0xc6, 0x25, 0x06, 0x04, 0x05, 0x46,
0xac, 0x2c, 0x2c, 0xec, 0xc6, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x08, 0x63, 0x82, 0x40,
0x1c, 0x1b, 0x84, 0x81, 0xd8, 0x20, 0x10, 0x04, 0x05, 0xbb, 0xb9, 0x09, 0x02, 0x81, 0x6c, 0x18,
0x0e, 0x84, 0x98, 0x20, 0x60, 0x1c, 0x2b, 0xba, 0x3c, 0xb8, 0xb2, 0x2f, 0xab, 0xb4, 0xb2, 0x3b,
0xb8, 0x37, 0x39, 0xba, 0x2a, 0xb7, 0x34, 0xb3, 0x37, 0xb9, 0xb6, 0xb9, 0x09, 0x02, 0x91, 0x6c,
0x40, 0x08, 0x65, 0x19, 0x88, 0x81, 0x01, 0x36, 0x04, 0xcd, 0x06, 0x02, 0x00, 0x1c, 0x60, 0x82,
0x70, 0x6d, 0xdc, 0xac, 0xd2, 0xca, 0xee, 0xe0, 0xde, 0xe4, 0xe8, 0xaa, 0xdc, 0xd2, 0xcc, 0xde,
0xe4, 0xda, 0xe6, 0xbe, 0xe0, 0xe4, 0xde, 0xd4, 0xca, 0xc6, 0xe8, 0xd2, 0xde, 0xdc, 0x26, 0x08,
0x84, 0x32, 0x41, 0x20, 0x96, 0x0d, 0xc3, 0x34, 0x49, 0x13, 0x04, 0x82, 0x99, 0x20, 0x10, 0xcd,
0x04, 0x81, 0x70, 0x26, 0x08, 0x91, 0xb6, 0x41, 0x41, 0x22, 0x89, 0xaa, 0x08, 0xeb, 0xba, 0x30,
0x6e, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x13, 0x04, 0xe2, 0xd9,
0xa0, 0x20, 0x9a, 0x44, 0x55, 0x9b, 0x75, 0x5d, 0xd8, 0x86, 0x81, 0xc9, 0xb8, 0x0d, 0x03, 0x01,
0x75, 0x13, 0x04, 0x01, 0xd8, 0x00, 0x6c, 0x18, 0x08, 0x30, 0x00, 0x83, 0x0d, 0x41, 0x18, 0x6c,
0x18, 0x86, 0x4f, 0x0c, 0x26, 0x08, 0x59, 0xb7, 0x21, 0x20, 0x03, 0x12, 0x6d, 0x61, 0x69, 0x6e,
0x44, 0xa8, 0x8a, 0xb0, 0x86, 0x9e, 0x9e, 0xa4, 0x88, 0x26, 0x08, 0x45, 0x35, 0x41, 0x28, 0xac,
0x0d, 0x01, 0x31, 0x41, 0x28, 0xae, 0x0d, 0x42, 0x65, 0x6d, 0x58, 0x88, 0x33, 0x40, 0x83, 0x34,
0x50, 0x83, 0x34, 0x18, 0xd6, 0x80, 0x48, 0x03, 0x36, 0xd8, 0x10, 0x0c, 0x1b, 0x96, 0xe1, 0x0c,
0xd0, 0x20, 0x0d, 0xdc, 0x20, 0x0d, 0x86, 0x35, 0x18, 0xd2, 0x80, 0x0d, 0x36, 0x04, 0xd2, 0x04,
0xa1, 0xc0, 0x36, 0x08, 0x55, 0xb5, 0x61, 0x91, 0xce, 0x00, 0x0d, 0xd2, 0x00, 0x0e, 0xd2, 0x60,
0x88, 0x03, 0x29, 0x0d, 0xe4, 0x60, 0xc3, 0xd0, 0x06, 0x6f, 0x30, 0x07, 0x1b, 0x16, 0xe2, 0x0c,
0xd0, 0x20, 0x0d, 0xd4, 0x20, 0x0e, 0x86, 0x35, 0x20, 0xd2, 0x80, 0x0d, 0x36, 0x2c, 0xc3, 0x19,
0xa0, 0x41, 0x1a, 0xb8, 0x41, 0x1c, 0x0c, 0x71, 0x30, 0xa4, 0x81, 0x1c, 0x6c, 0x58, 0xa4, 0x33,
0x40, 0x83, 0x34, 0x80, 0x83, 0x38, 0x18, 0xd6, 0x40, 0x4a, 0x03, 0x36, 0xe0, 0x32, 0x65, 0xf5,
0x05, 0xf5, 0x36, 0x97, 0x46, 0x97, 0xf6, 0xe6, 0x36, 0x41, 0x28, 0xb2, 0x09, 0x02, 0x01, 0x6d,
0x10, 0x2a, 0x3d, 0xd8, 0xb0, 0x54, 0x78, 0x80, 0x06, 0x6b, 0xa0, 0x06, 0x79, 0x30, 0xe4, 0x41,
0x95, 0x06, 0x7b, 0xb0, 0x81, 0xa8, 0x03, 0x3b, 0xb8, 0x03, 0x3e, 0xd8, 0x30, 0xd0, 0x41, 0x1f,
0x00, 0x1b, 0x8a, 0xcf, 0x0c, 0xfc, 0xe0, 0x01, 0x68, 0x98, 0xb1, 0xbd, 0x85, 0xd1, 0xcd, 0x4d,
0x10, 0x88, 0x88, 0x45, 0x9a, 0xdb, 0x1c, 0xdd, 0xdc, 0x04, 0x81, 0x90, 0x68, 0xcc, 0xa5, 0x9d,
0x7d, 0xb1, 0x91, 0x4d, 0x10, 0x88, 0x89, 0xc6, 0x5c, 0xda, 0xd9, 0xd7, 0x1c, 0xdd, 0x04, 0x81,
0xa0, 0x36, 0x20, 0xa0, 0x10, 0x0a, 0xa2, 0x30, 0x0a, 0xa4, 0x50, 0x0a, 0xa6, 0x70, 0x0a, 0x55,
0xd8, 0xd8, 0xec, 0xda, 0x5c, 0xd2, 0xc8, 0xca, 0xdc, 0xe8, 0xa6, 0x04, 0x41, 0x15, 0x32, 0x3c,
0x17, 0xbb, 0x32, 0xb9, 0xb9, 0xb4, 0x37, 0xb7, 0x29, 0x01, 0xd1, 0x84, 0x0c, 0xcf, 0xc5, 0x2e,
0x8c, 0xcd, 0xae, 0x4c, 0x6e, 0x4a, 0x50, 0xd4, 0x21, 0xc3, 0x73, 0x99, 0x43, 0x0b, 0x23, 0x2b,
0x93, 0x6b, 0x7a, 0x23, 0x2b, 0x63, 0x9b, 0x12, 0x20, 0x65, 0xc8, 0xf0, 0x5c, 0xe4, 0xca, 0xe6,
0xde, 0xea, 0xe4, 0xc6, 0xca, 0xe6, 0xa6, 0x04, 0x4e, 0x25, 0x32, 0x3c, 0x17, 0xba, 0x3c, 0xb8,
0xb2, 0x20, 0x37, 0xb7, 0x37, 0xba, 0x30, 0xba, 0xb4, 0x37, 0xb7, 0xb9, 0x29, 0x42, 0x27, 0x06,
0x75, 0xc8, 0xf0, 0x5c, 0xec, 0xd2, 0xca, 0xee, 0x92, 0xc8, 0xa6, 0xe8, 0xc2, 0xe8, 0xca, 0xa6,
0x04, 0x64, 0x50, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, 0xcd, 0x8d,
0x6e, 0x6e, 0x4a, 0xe0, 0x07, 0x5d, 0xc8, 0xf0, 0x5c, 0xc6, 0xde, 0xea, 0xdc, 0xe8, 0xca, 0xe4,
0xe6, 0xa6, 0x04, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
0x10, 0x52, 0x06, 0xa1, 0x82, 0x0c, 0x32, 0xc6, 0x18, 0x63, 0x90, 0x2a, 0xc3, 0x20, 0x83, 0xd8,
0x51, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x3e, 0xb7, 0x51, 0xc5, 0x4a, 0x4c, 0x7e, 0x71, 0xdb,
0x88, 0x18, 0x63, 0x0c, 0x2a, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c,
0x0b, 0x81, 0x82, 0x57, 0x08, 0x47, 0x20, 0xa1, 0x58, 0x8a, 0x41, 0xc6, 0x18, 0x34, 0xe7, 0x08,
0x82, 0x62, 0x40, 0x52, 0x08, 0xa9, 0x64, 0x07, 0x02, 0x86, 0x11, 0x88, 0x21, 0x09, 0xf2, 0x81,
0xc1, 0xe1, 0x48, 0xd3, 0x02, 0x60, 0x0e, 0x35, 0xf9, 0x13, 0xf6, 0x10, 0xff, 0x8b, 0x10, 0xd6,
0xe3, 0x44, 0x93, 0xdb, 0x20, 0x85, 0x13, 0x31, 0x12, 0x1a, 0xb4, 0xd6, 0xb4, 0x93, 0x81, 0x00,
0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0,
0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30,
0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07,
0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a,
0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90,
0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07,
0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6,
0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60,
0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0xf2, 0x28, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4,
0x61, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x13, 0x01, 0x01,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x67, 0x02, 0x02, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0x8f, 0x05, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x59, 0x20, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x18,
0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50,
0x0c, 0x05, 0x38, 0x50, 0x04, 0x85, 0x50, 0x06, 0xe5, 0x50, 0x12, 0x05, 0x18, 0x50, 0x80, 0x02,
0xe5, 0x51, 0x2c, 0x05, 0x1e, 0x50, 0x10, 0x85, 0x41, 0xa5, 0x24, 0x46, 0x00, 0xca, 0xa0, 0x08,
0x0a, 0x81, 0x6a, 0x0d, 0xd0, 0x9e, 0x01, 0x20, 0x3e, 0x03, 0x40, 0x7d, 0x2c, 0x46, 0x81, 0x40,
0xbc, 0x0f, 0x40, 0xbc, 0x0f, 0x40, 0xbc, 0x0f, 0x80, 0xe3, 0x38, 0x00, 0x08, 0x0c, 0x00, 0x00,
0x79, 0x18, 0x00, 0x00, 0xb4, 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, 0x01, 0x41, 0x11, 0xa3, 0xb9, 0x89, 0x89, 0xc1,
0x99, 0xc9, 0x29, 0x4b, 0xd9, 0x10, 0x04, 0x13, 0x04, 0x02, 0x99, 0x20, 0x10, 0xc9, 0x06, 0x61,
0x20, 0x36, 0x08, 0x04, 0x41, 0xc1, 0x6e, 0x6e, 0x82, 0x40, 0x28, 0x1b, 0x86, 0x03, 0x21, 0x26,
0x08, 0xdc, 0xc7, 0x8a, 0x2e, 0x0f, 0xae, 0xec, 0xcb, 0x2a, 0xad, 0xec, 0x0e, 0xee, 0x4d, 0x8e,
0xae, 0xca, 0x2d, 0xcd, 0xec, 0x4d, 0xae, 0x6d, 0x6e, 0x82, 0x40, 0x2c, 0x1b, 0x10, 0x42, 0x59,
0x06, 0x62, 0x60, 0x80, 0x0d, 0x41, 0xb3, 0x81, 0x00, 0x00, 0x07, 0x98, 0x20, 0x6c, 0x1e, 0x37,
0xab, 0xb4, 0xb2, 0x3b, 0xb8, 0x37, 0x39, 0xba, 0x2a, 0xb7, 0x34, 0xb3, 0x37, 0xb9, 0xb6, 0xb9,
0x2f, 0x38, 0xb9, 0x37, 0xb5, 0xb2, 0x31, 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x02, 0xc1, 0x4c, 0x10,
0x88, 0x66, 0xc3, 0x30, 0x4d, 0xd2, 0x04, 0x81, 0x70, 0x26, 0x08, 0xc4, 0x33, 0x41, 0x20, 0xa0,
0x09, 0x42, 0xd5, 0x6d, 0x50, 0x90, 0x48, 0xa2, 0x2a, 0xc2, 0xba, 0x2e, 0x8c, 0x60, 0x60, 0x95,
0x56, 0x76, 0x07, 0xf7, 0x26, 0x47, 0x57, 0xe5, 0x96, 0x66, 0xf6, 0x26, 0xd7, 0x36, 0xf7, 0x75,
0xf7, 0x26, 0xc7, 0x46, 0x66, 0x95, 0x56, 0x76, 0xd7, 0x14, 0x46, 0x27, 0x97, 0x86, 0x37, 0x41,
0x20, 0xa2, 0x0d, 0x0a, 0xa2, 0x49, 0x54, 0xb5, 0x59, 0xd7, 0x85, 0xb1, 0xb3, 0x4a, 0x2b, 0xbb,
0x83, 0x7b, 0x93, 0xa3, 0xab, 0x72, 0x4b, 0x33, 0x7b, 0x93, 0x6b, 0x9b, 0xfb, 0x72, 0x7b, 0x93,
0x6b, 0x0b, 0x63, 0x6b, 0x0a, 0xa3, 0x93, 0x4b, 0xc3, 0x9b, 0x20, 0x10, 0xd2, 0x06, 0x05, 0xe9,
0x24, 0xaa, 0xf2, 0xac, 0xeb, 0xc2, 0x36, 0x10, 0x4c, 0xc6, 0x7d, 0x1b, 0x06, 0x02, 0x02, 0x83,
0x09, 0x82, 0x00, 0x6c, 0x00, 0x36, 0x0c, 0xc4, 0x18, 0x8c, 0xc1, 0x86, 0x80, 0x0c, 0x36, 0x0c,
0x83, 0x18, 0x94, 0xc1, 0x04, 0xa1, 0x03, 0x83, 0x0d, 0xc1, 0x19, 0x90, 0x68, 0x0b, 0x4b, 0x73,
0x23, 0x42, 0x55, 0x84, 0x35, 0xf4, 0xf4, 0x24, 0x45, 0x34, 0x41, 0x28, 0xb0, 0x09, 0x42, 0x91,
0x6d, 0x08, 0x88, 0x09, 0x42, 0xa1, 0x6d, 0x10, 0x2a, 0x6b, 0xc3, 0x42, 0xa8, 0xc1, 0x1a, 0xb0,
0x41, 0x1b, 0xb0, 0xc1, 0xe0, 0x06, 0x04, 0x1b, 0xbc, 0xc1, 0x86, 0x60, 0xd8, 0xb0, 0x0c, 0x6a,
0xb0, 0x06, 0x6c, 0x10, 0x07, 0x6c, 0x30, 0xb8, 0xc1, 0xc0, 0x06, 0x6f, 0xb0, 0x21, 0x90, 0x26,
0x08, 0xc5, 0xb6, 0x41, 0xa8, 0xaa, 0x0d, 0x8b, 0xa4, 0x06, 0x6b, 0xc0, 0x06, 0x73, 0xc0, 0x06,
0x03, 0x1d, 0x48, 0x6c, 0x50, 0x07, 0x1b, 0x06, 0x38, 0x90, 0x03, 0x3b, 0xd8, 0xb0, 0x10, 0x6a,
0xb0, 0x06, 0x6c, 0xd0, 0x06, 0x74, 0x30, 0xb8, 0x01, 0xc1, 0x06, 0x6f, 0xb0, 0x61, 0x19, 0xd4,
0x60, 0x0d, 0xd8, 0x20, 0x0e, 0xe8, 0x60, 0xa0, 0x83, 0x81, 0x0d, 0xea, 0x60, 0xc3, 0x22, 0xa9,
0xc1, 0x1a, 0xb0, 0xc1, 0x1c, 0xd0, 0xc1, 0xe0, 0x06, 0x12, 0x1b, 0xbc, 0x01, 0x97, 0x29, 0xab,
0x2f, 0xa8, 0xb7, 0xb9, 0x34, 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x42, 0xc1, 0x4d, 0x10, 0x88, 0x69,
0x83, 0x50, 0xf5, 0xc1, 0x86, 0xa5, 0xda, 0x83, 0x35, 0x70, 0x83, 0x36, 0xe0, 0x83, 0x81, 0x0f,
0x2a, 0x36, 0xf0, 0x83, 0x0d, 0x04, 0x1e, 0xe4, 0x81, 0x1e, 0xfc, 0xc1, 0x86, 0xe1, 0x0e, 0x40,
0x01, 0xd8, 0x50, 0x88, 0x41, 0x1a, 0x84, 0xc2, 0x03, 0xd0, 0x30, 0x63, 0x7b, 0x0b, 0xa3, 0x9b,
0x9b, 0x20, 0x10, 0x14, 0x8b, 0x34, 0xb7, 0x39, 0xba, 0xb9, 0x09, 0x02, 0x51, 0xd1, 0x98, 0x4b,
0x3b, 0xfb, 0x62, 0x23, 0x9b, 0x20, 0x10, 0x16, 0x8d, 0xb9, 0xb4, 0xb3, 0xaf, 0x39, 0xba, 0x09,
0x02, 0x71, 0x6d, 0x40, 0x46, 0x81, 0x14, 0x4a, 0xc1, 0x14, 0x4e, 0x01, 0x15, 0x52, 0x41, 0x15,
0xaa, 0xb0, 0xb1, 0xd9, 0xb5, 0xb9, 0xa4, 0x91, 0x95, 0xb9, 0xd1, 0x4d, 0x09, 0x82, 0x2a, 0x64,
0x78, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x02, 0xa2, 0x09, 0x19, 0x9e, 0x8b,
0x5d, 0x18, 0x9b, 0x5d, 0x99, 0xdc, 0x94, 0xa0, 0xa8, 0x43, 0x86, 0xe7, 0x32, 0x87, 0x16, 0x46,
0x56, 0x26, 0xd7, 0xf4, 0x46, 0x56, 0xc6, 0x36, 0x25, 0x40, 0xca, 0x90, 0xe1, 0xb9, 0xc8, 0x95,
0xcd, 0xbd, 0xd5, 0xc9, 0x8d, 0x95, 0xcd, 0x4d, 0x09, 0x9c, 0x4a, 0x64, 0x78, 0x2e, 0x74, 0x79,
0x70, 0x65, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x04, 0x30,
0x28, 0x83, 0x3a, 0x64, 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74,
0x65, 0x53, 0x82, 0x33, 0xa8, 0x43, 0x86, 0xe7, 0x52, 0xe6, 0x46, 0x27, 0x97, 0x07, 0xf5, 0x96,
0xe6, 0x46, 0x37, 0x37, 0x25, 0x08, 0x85, 0x2e, 0x64, 0x78, 0x2e, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x65, 0x72, 0x73, 0x53, 0x02, 0x55, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3,
0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10,
0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30,
@ -158,161 +164,180 @@ static const Uint8 PositionColor_vert_dxil[4724] = {
0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87,
0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a,
0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00,
0x71, 0x20, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x36, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10,
0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x05,
0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x58, 0xc0,
0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x8b, 0x03, 0x0c, 0x62, 0xf3, 0x50, 0x93, 0x5f, 0xdc, 0xb6, 0x09,
0x54, 0xc3, 0xe5, 0x3b, 0x8f, 0x2f, 0x4d, 0x4e, 0x44, 0xa0, 0xd4, 0xf4, 0x50, 0x93, 0x5f, 0xdc,
0xb6, 0x11, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x11, 0xd1, 0x84, 0x00, 0x11, 0xe6, 0x17, 0xb7,
0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48,
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xf8, 0xd8, 0x30, 0xc0, 0xc0, 0x66, 0x9f,
0xb9, 0xf5, 0x62, 0xf4, 0xcf, 0x36, 0xe2, 0x37, 0x44, 0x58, 0x49, 0x4c, 0xb4, 0x08, 0x00, 0x00,
0x60, 0x00, 0x01, 0x00, 0x2d, 0x02, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x9c, 0x08, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00,
0x24, 0x02, 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, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42,
0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20,
0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50,
0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d,
0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f,
0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42,
0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3,
0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x68, 0x23, 0x00,
0x25, 0x00, 0x14, 0x66, 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14,
0x42, 0xa6, 0x18, 0x80, 0x10, 0x52, 0x06, 0xa1, 0xa3, 0x86, 0xcb, 0x9f, 0xb0, 0x87, 0x90, 0x7c,
0x6e, 0xa3, 0x8a, 0x95, 0x98, 0xfc, 0xe2, 0xb6, 0x11, 0x31, 0xc6, 0x18, 0x54, 0xee, 0x19, 0x2e,
0x7f, 0xc2, 0x1e, 0x42, 0xf2, 0x43, 0xa0, 0x19, 0x16, 0x02, 0x05, 0xab, 0x10, 0x8a, 0x30, 0x42,
0xad, 0x14, 0x83, 0x8c, 0x31, 0xe8, 0xcd, 0x11, 0x04, 0xc5, 0x60, 0xa4, 0x10, 0x12, 0x49, 0x0e,
0x04, 0x0c, 0x23, 0x10, 0x43, 0x12, 0xd4, 0x03, 0x83, 0xc3, 0x91, 0xa6, 0x05, 0xc0, 0x1c, 0x6a,
0xf2, 0x27, 0xec, 0x21, 0xfe, 0x17, 0x21, 0xac, 0xc7, 0x89, 0x26, 0xb7, 0x41, 0x0a, 0x27, 0x62,
0x24, 0x24, 0x58, 0x4b, 0x37, 0x19, 0x08, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87,
0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e,
0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d,
0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20,
0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07,
0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74,
0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20,
0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07,
0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76,
0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86,
0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x79, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0xc8, 0x23, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x16, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90,
0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50, 0x12, 0xc5, 0x50, 0x80,
0x02, 0x65, 0x50, 0x0e, 0x45, 0x50, 0x1e, 0x54, 0x4a, 0x62, 0x04, 0xa0, 0x0c, 0x8a, 0xa0, 0x10,
0x08, 0xcf, 0x00, 0x50, 0x1e, 0x8b, 0x51, 0x20, 0x10, 0xef, 0x03, 0x10, 0xef, 0x03, 0x10, 0xef,
0x03, 0x20, 0x10, 0x08, 0x00, 0x02, 0x03, 0x00, 0x79, 0x18, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x8f, 0x0c, 0x6f, 0x0c, 0x05, 0x4e, 0x2e, 0xcd,
0x2e, 0x8c, 0xae, 0x2c, 0x05, 0x24, 0xc6, 0x05, 0xc7, 0x05, 0xc6, 0x25, 0x06, 0x04, 0x05, 0x46,
0xac, 0x2c, 0x2c, 0xec, 0xc6, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x08, 0x63, 0x82, 0x40,
0x1c, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc8, 0x06, 0x61, 0x30, 0x28, 0xd8, 0xcd, 0x4d, 0x10,
0x88, 0x64, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x01, 0xa3, 0x08, 0x4c, 0x10, 0x08, 0x65, 0x03, 0x42,
0x2c, 0xcc, 0x40, 0x0c, 0x0d, 0xb0, 0x21, 0x70, 0x36, 0x10, 0x00, 0xf0, 0x00, 0x13, 0x84, 0xac,
0xda, 0x10, 0x44, 0x13, 0x04, 0x01, 0x20, 0xd1, 0x16, 0x96, 0xe6, 0x46, 0x84, 0xaa, 0x08, 0x6b,
0xe8, 0xe9, 0x49, 0x8a, 0x68, 0x82, 0x50, 0x3c, 0x13, 0x84, 0x02, 0xda, 0x10, 0x10, 0x13, 0x84,
0x22, 0x9a, 0x20, 0x10, 0xcb, 0x04, 0x81, 0x60, 0x36, 0x08, 0xda, 0xb6, 0x61, 0x21, 0x2a, 0xeb,
0xc2, 0xae, 0x21, 0x23, 0x2e, 0x6e, 0x43, 0x30, 0x6c, 0x58, 0x86, 0xca, 0xba, 0xbc, 0x6b, 0xc8,
0x86, 0x8b, 0x9b, 0x20, 0x10, 0xcd, 0x86, 0x00, 0x0c, 0x26, 0x08, 0x85, 0xb4, 0x41, 0xd0, 0xb4,
0x0d, 0x0b, 0x18, 0x54, 0xd6, 0x15, 0x06, 0xd7, 0x20, 0x06, 0x60, 0x70, 0x8d, 0xc1, 0x86, 0xa1,
0xfb, 0xc8, 0x60, 0xc3, 0x42, 0x54, 0xd6, 0x85, 0x89, 0xc1, 0x90, 0x11, 0x17, 0xb7, 0x61, 0x19,
0x2a, 0xeb, 0xf2, 0xc4, 0x60, 0x10, 0x83, 0xe1, 0x1a, 0x83, 0x0d, 0x0b, 0x18, 0x54, 0xd6, 0x15,
0x06, 0x62, 0x30, 0x64, 0x60, 0x70, 0x71, 0x5c, 0xa6, 0xac, 0xbe, 0xa0, 0xde, 0xe6, 0xd2, 0xe8,
0xd2, 0xde, 0xdc, 0x26, 0x08, 0xc5, 0x34, 0x41, 0x20, 0x9c, 0x0d, 0x82, 0xb6, 0x06, 0x1b, 0x16,
0x2d, 0x0d, 0xac, 0x0c, 0x53, 0x83, 0x41, 0x0d, 0xb4, 0x8b, 0x0d, 0x36, 0x10, 0x66, 0x70, 0x06,
0x68, 0xd0, 0x06, 0x1b, 0x86, 0x32, 0x70, 0x03, 0x60, 0x43, 0x31, 0x51, 0x6f, 0x00, 0x01, 0x55,
0xd8, 0xd8, 0xec, 0xda, 0x5c, 0xd2, 0xc8, 0xca, 0xdc, 0xe8, 0xa6, 0x04, 0x41, 0x15, 0x32, 0x3c,
0x17, 0xbb, 0x32, 0xb9, 0xb9, 0xb4, 0x37, 0xb7, 0x29, 0x01, 0xd1, 0x84, 0x0c, 0xcf, 0xc5, 0x2e,
0x8c, 0xcd, 0xae, 0x4c, 0x6e, 0x4a, 0x60, 0xd4, 0x21, 0xc3, 0x73, 0x99, 0x43, 0x0b, 0x23, 0x2b,
0x93, 0x6b, 0x7a, 0x23, 0x2b, 0x63, 0x9b, 0x12, 0x24, 0x65, 0xc8, 0xf0, 0x5c, 0xe4, 0xca, 0xe6,
0xde, 0xea, 0xe4, 0xc6, 0xca, 0xe6, 0xa6, 0x04, 0x4f, 0x1d, 0x32, 0x3c, 0x17, 0xbb, 0xb4, 0xb2,
0xbb, 0x24, 0xb2, 0x29, 0xba, 0x30, 0xba, 0xb2, 0x29, 0x41, 0x54, 0x87, 0x0c, 0xcf, 0xa5, 0xcc,
0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0xf0, 0x06, 0x00, 0x00, 0x00,
0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66,
0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73,
0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e,
0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b,
0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b,
0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20,
0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0,
0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61,
0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83,
0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87,
0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76,
0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98,
0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30,
0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61,
0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43,
0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b,
0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8,
0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60,
0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40,
0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x36, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25,
0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x05, 0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01,
0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x58, 0xc0, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x8b, 0x03, 0x0c,
0x62, 0xf3, 0x50, 0x93, 0x5f, 0xdc, 0xb6, 0x09, 0x54, 0xc3, 0xe5, 0x3b, 0x8f, 0x2f, 0x4d, 0x4e,
0x44, 0xa0, 0xd4, 0xf4, 0x50, 0x93, 0x5f, 0xdc, 0xb6, 0x11, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f,
0x11, 0xd1, 0x84, 0x00, 0x11, 0xe6, 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00,
0x61, 0x20, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x44, 0x8a, 0xab, 0x14, 0x0a, 0x61, 0x06, 0xa0, 0xec, 0x4a, 0x8e, 0x4a,
0x09, 0x50, 0x1c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x20, 0x65,
0x03, 0x73, 0x5d, 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0xde, 0x21, 0x61, 0x8f, 0x31,
0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc6, 0x87, 0x4c, 0x19, 0x71, 0x8c, 0x18, 0x24, 0x00, 0x08,
0x82, 0x81, 0x01, 0x06, 0xc9, 0xa6, 0x45, 0xc8, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x61,
0xa0, 0x70, 0x9b, 0x91, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x21, 0x06, 0x4b, 0xc7, 0x45,
0xca, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x63, 0xc0, 0x74, 0x1d, 0xb5, 0x8c, 0x18, 0x24,
0x00, 0x08, 0x82, 0x81, 0x41, 0x06, 0x8d, 0xe7, 0x25, 0xcc, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18,
0x18, 0x65, 0xe0, 0x7c, 0x1f, 0xd5, 0x8c, 0x18, 0x1c, 0x00, 0x08, 0x82, 0x41, 0x43, 0x06, 0x4d,
0xf2, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82, 0x10, 0x8c, 0x26, 0x0c, 0xc2, 0x88, 0xc1, 0x01, 0x80,
0x20, 0x18, 0x34, 0x68, 0x10, 0x35, 0xd4, 0x68, 0x42, 0x00, 0x8c, 0x26, 0x08, 0xc1, 0x68, 0xc2,
0x20, 0x8c, 0x18, 0x1c, 0x00, 0x08, 0x82, 0x41, 0xc3, 0x06, 0x55, 0x64, 0x06, 0xa3, 0x09, 0x01,
0x30, 0x9a, 0x20, 0x04, 0xa3, 0x09, 0x83, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x0d, 0x1c,
0x64, 0xd5, 0x19, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82, 0x10, 0x8c, 0x26, 0x0c, 0x82, 0x3d, 0x93,
0x7c, 0x46, 0x0c, 0x10, 0x00, 0x04, 0xc1, 0xe0, 0xa1, 0x03, 0x31, 0x60, 0xa6, 0x60, 0xc4, 0x00,
0x01, 0x40, 0x10, 0x0c, 0x9e, 0x3a, 0x18, 0x83, 0x64, 0x0a, 0x2c, 0x30, 0xa0, 0x63, 0xd2, 0x25,
0x9f, 0x11, 0x03, 0x04, 0x00, 0x41, 0x30, 0x78, 0xf0, 0xc0, 0x0c, 0x9e, 0x2b, 0x18, 0x31, 0x40,
0x00, 0x10, 0x04, 0x83, 0x27, 0x0f, 0xce, 0x80, 0xb9, 0x02, 0x0b, 0x12, 0xe8, 0x58, 0xb5, 0xc9,
0x67, 0xc4, 0x00, 0x01, 0x40, 0x10, 0x0c, 0x1e, 0x3e, 0x50, 0x03, 0x69, 0x0b, 0x46, 0x0c, 0x10,
0x00, 0x04, 0xc1, 0xe0, 0xe9, 0x83, 0x35, 0x78, 0xb6, 0xc0, 0x02, 0x06, 0x3a, 0x23, 0x06, 0x07,
0x00, 0x82, 0x60, 0xd0, 0x80, 0x42, 0x1a, 0x94, 0x01, 0x1f, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82,
0x10, 0x8c, 0x26, 0x0c, 0xc2, 0x68, 0x02, 0x31, 0x8c, 0x18, 0x1c, 0x00, 0x08, 0x82, 0x41, 0x53,
0x0a, 0x6e, 0xa0, 0x06, 0xa2, 0x30, 0x9a, 0x10, 0x00, 0xa3, 0x09, 0x42, 0x30, 0x9a, 0x30, 0x08,
0xa3, 0x09, 0xc4, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x8d, 0x2a, 0xcc, 0xc1, 0x1b, 0x80,
0xc2, 0x68, 0x42, 0x00, 0x8c, 0x26, 0x08, 0xc1, 0x68, 0xc2, 0x20, 0x8c, 0x26, 0x10, 0xc3, 0x88,
0xc1, 0x01, 0x80, 0x20, 0x18, 0x34, 0xaf, 0x80, 0x07, 0x74, 0x70, 0x0a, 0xa3, 0x09, 0x01, 0x30,
0x9a, 0x20, 0x04, 0xa3, 0x09, 0x83, 0x30, 0x9a, 0x40, 0x0c, 0x36, 0x75, 0xf2, 0x19, 0x31, 0x40,
0x00, 0x10, 0x04, 0x83, 0x87, 0x16, 0x44, 0xe1, 0xd1, 0x82, 0x11, 0x03, 0x04, 0x00, 0x41, 0x30,
0x78, 0x6a, 0x61, 0x14, 0x96, 0x2b, 0xb0, 0xe0, 0x80, 0x8e, 0x59, 0x61, 0x20, 0x9f, 0x11, 0x03,
0x04, 0x00, 0x41, 0x30, 0x78, 0x70, 0xc1, 0x14, 0x24, 0x2f, 0x18, 0x31, 0x40, 0x00, 0x10, 0x04,
0x83, 0x27, 0x17, 0x4e, 0xc1, 0xd9, 0x02, 0x0b, 0x14, 0xe8, 0x58, 0x56, 0x06, 0xf2, 0x19, 0x31,
0x40, 0x00, 0x10, 0x04, 0x83, 0x87, 0x17, 0x54, 0xa1, 0x12, 0x83, 0x60, 0xc4, 0x00, 0x01, 0x40,
0x10, 0x0c, 0x9e, 0x5e, 0x58, 0x85, 0xe8, 0x0b, 0x2c, 0x68, 0xa0, 0x63, 0x5c, 0x1a, 0xc8, 0x67,
0xc4, 0x00, 0x01, 0x40, 0x10, 0x0c, 0x1e, 0x70, 0x70, 0x05, 0xcc, 0x0c, 0x82, 0x11, 0x03, 0x04,
0x00, 0x41, 0x30, 0x78, 0xc2, 0xe1, 0x15, 0xa8, 0x31, 0x08, 0x2c, 0x80, 0xa0, 0x33, 0x62, 0x90,
0x00, 0x20, 0x08, 0x06, 0x48, 0x39, 0xc0, 0x02, 0x38, 0x80, 0xc3, 0x2d, 0x98, 0xc2, 0x88, 0x41,
0x02, 0x80, 0x20, 0x18, 0x20, 0xe5, 0x00, 0x0b, 0xe0, 0x00, 0x0e, 0xab, 0x50, 0x0a, 0x23, 0x06,
0x09, 0x00, 0x82, 0x60, 0x80, 0x94, 0x03, 0x2c, 0x80, 0x03, 0x38, 0xd4, 0x02, 0x29, 0x8c, 0x18,
0x24, 0x00, 0x08, 0x82, 0x01, 0x52, 0x0e, 0xb0, 0x10, 0x0e, 0xe0, 0x70, 0x0b, 0xa8, 0x30, 0x62,
0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x39, 0xc0, 0x42, 0x38, 0x80, 0xc3, 0x2a, 0x9c, 0xc2, 0x88,
0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe5, 0x00, 0x0b, 0xba, 0x00, 0x0e, 0xb7, 0xd0, 0x06, 0x23,
0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x94, 0x03, 0x2c, 0xe8, 0x02, 0x38, 0xac, 0x42, 0x1a, 0x8c,
0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x52, 0x0e, 0xb0, 0xa0, 0x0b, 0xe0, 0x50, 0x0b, 0x65, 0x30,
0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x39, 0xc0, 0x02, 0x2f, 0x80, 0xc3, 0x2d, 0x34, 0x23,
0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x94, 0x03, 0x2c, 0xf0, 0x02, 0x38, 0xac, 0x42, 0x32, 0x62,
0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x39, 0xc0, 0x02, 0x2f, 0x80, 0x43, 0x2d, 0x14, 0x23, 0x06,
0x09, 0x00, 0x82, 0x60, 0x80, 0x94, 0x03, 0x2c, 0xf0, 0x02, 0x38, 0xd8, 0x42, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x71, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x56, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10,
0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x07,
0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0xd8, 0x80,
0x33, 0x5c, 0xbe, 0xf3, 0xf8, 0x83, 0x33, 0xdd, 0x7e, 0x71, 0xdb, 0x16, 0x30, 0x0d, 0x97, 0xef,
0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9,
0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x06, 0xd2,
0x70, 0xf9, 0xce, 0xe3, 0x4f, 0x44, 0x34, 0x21, 0x40, 0x84, 0xf9, 0xc5, 0x6d, 0x1b, 0xc1, 0x33,
0x5c, 0xbe, 0xf3, 0xf8, 0x54, 0x03, 0x44, 0x98, 0x5f, 0xdc, 0xb6, 0x01, 0x10, 0x0c, 0x80, 0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x83, 0xb6, 0x50, 0xbb, 0x0d, 0xbf, 0x5b, 0x40, 0x75, 0x62, 0x54, 0x58,
0xb1, 0xa1, 0x1b, 0x04, 0x44, 0x58, 0x49, 0x4c, 0xd0, 0x09, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00,
0x74, 0x02, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0xb8, 0x09, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x6b, 0x02, 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, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14,
0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5,
0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c,
0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff,
0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00,
0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06,
0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09,
0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14,
0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66,
0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, 0x42, 0xa6, 0x18, 0x80,
0x10, 0x52, 0x06, 0xa1, 0x82, 0x0c, 0x32, 0xc6, 0x18, 0x63, 0x90, 0x2a, 0xc3, 0x20, 0x83, 0xd8,
0x51, 0xc3, 0xe5, 0x4f, 0xd8, 0x43, 0x48, 0x3e, 0xb7, 0x51, 0xc5, 0x4a, 0x4c, 0x7e, 0x71, 0xdb,
0x88, 0x18, 0x63, 0x0c, 0x2a, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c,
0x0b, 0x81, 0x82, 0x57, 0x08, 0x47, 0x20, 0xa1, 0x58, 0x8a, 0x41, 0xc6, 0x18, 0x34, 0xe7, 0x08,
0x82, 0x62, 0x40, 0x52, 0x08, 0xa9, 0x64, 0x07, 0x02, 0x86, 0x11, 0x88, 0x21, 0x09, 0xf2, 0x81,
0xc1, 0xe1, 0x48, 0xd3, 0x02, 0x60, 0x0e, 0x35, 0xf9, 0x13, 0xf6, 0x10, 0xff, 0x8b, 0x10, 0xd6,
0xe3, 0x44, 0x93, 0xdb, 0x20, 0x85, 0x13, 0x31, 0x12, 0x1a, 0xb4, 0xd6, 0xb4, 0x93, 0x81, 0x00,
0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0,
0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30,
0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07,
0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a,
0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90,
0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07,
0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6,
0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60,
0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0xf2, 0x28, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4,
0x61, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x13, 0x01, 0x01,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x67, 0x02, 0x02, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0x8f, 0x05, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x59, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14,
0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50,
0x10, 0xc5, 0x50, 0x80, 0x03, 0x65, 0x50, 0x0e, 0x45, 0x50, 0x1e, 0x54, 0x4a, 0x62, 0x04, 0xa0,
0x0c, 0x8a, 0xa0, 0x10, 0x88, 0xcf, 0x00, 0x50, 0x1f, 0x8b, 0x51, 0x20, 0x10, 0xef, 0x03, 0x10,
0xef, 0x03, 0x10, 0xef, 0x03, 0xe0, 0x38, 0x0e, 0x00, 0x02, 0x03, 0x00, 0x79, 0x18, 0x00, 0x00,
0x65, 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, 0x01, 0x41, 0x11, 0xa3, 0xb9, 0x89, 0x89, 0xc1, 0x99, 0xc9, 0x29, 0x4b,
0xd9, 0x10, 0x04, 0x13, 0x04, 0x02, 0x99, 0x20, 0x10, 0xc9, 0x06, 0x61, 0x20, 0x26, 0x08, 0x84,
0xb2, 0x41, 0x18, 0x0c, 0x0a, 0x76, 0x73, 0x13, 0x04, 0x62, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41,
0xe0, 0x2c, 0x02, 0x13, 0x04, 0x82, 0xd9, 0x80, 0x10, 0x0b, 0x33, 0x10, 0x43, 0x03, 0x6c, 0x08,
0x9c, 0x0d, 0x04, 0x00, 0x3c, 0xc0, 0x04, 0xa1, 0xbb, 0x36, 0x04, 0xd1, 0x04, 0x41, 0x00, 0x48,
0xb4, 0x85, 0xa5, 0xb9, 0x11, 0xa1, 0x2a, 0xc2, 0x1a, 0x7a, 0x7a, 0x92, 0x22, 0x9a, 0x20, 0x14,
0xd1, 0x04, 0xa1, 0x90, 0x36, 0x04, 0xc4, 0x04, 0xa1, 0x98, 0x26, 0x08, 0x44, 0x33, 0x41, 0x20,
0x9c, 0x0d, 0x82, 0xb6, 0x6d, 0x58, 0x88, 0xca, 0xba, 0xb0, 0x6b, 0xc8, 0x88, 0x8b, 0xdb, 0x10,
0x0c, 0x1b, 0x96, 0xa1, 0xb2, 0x2e, 0xef, 0x1a, 0xb2, 0xe1, 0xe2, 0x26, 0x08, 0xc4, 0xb3, 0x21,
0x00, 0x83, 0x09, 0x42, 0x41, 0x6d, 0x10, 0x34, 0x6d, 0xc3, 0x02, 0x06, 0x95, 0x75, 0x85, 0xc1,
0x35, 0x88, 0x01, 0x18, 0x5c, 0x63, 0xb0, 0x61, 0xe8, 0x3e, 0x32, 0xd8, 0xb0, 0x10, 0x95, 0x75,
0x61, 0x62, 0x30, 0x64, 0xc4, 0xc5, 0x6d, 0x58, 0x86, 0xca, 0xba, 0x3c, 0x31, 0x18, 0xc4, 0x60,
0xb8, 0xc6, 0x60, 0xc3, 0x02, 0x06, 0x95, 0x75, 0x85, 0x81, 0x18, 0x0c, 0x19, 0x18, 0x5c, 0x1c,
0x97, 0x29, 0xab, 0x2f, 0xa8, 0xb7, 0xb9, 0x34, 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x42, 0x51, 0x4d,
0x10, 0x08, 0x68, 0x83, 0xa0, 0xad, 0xc1, 0x86, 0x45, 0x4b, 0x03, 0x2b, 0xc3, 0xd4, 0x60, 0x50,
0x03, 0xed, 0x62, 0x83, 0x0d, 0x84, 0x19, 0x9c, 0x01, 0x1a, 0xb4, 0xc1, 0x86, 0xa1, 0x0c, 0xdc,
0x00, 0xd8, 0x50, 0x4c, 0xd4, 0x1b, 0x40, 0x40, 0x15, 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2,
0x32, 0x37, 0xba, 0x29, 0x41, 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd,
0x6d, 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, 0x93, 0x9b, 0x12, 0x18,
0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6,
0x04, 0x49, 0x19, 0x32, 0x3c, 0x17, 0xb9, 0xb2, 0xb9, 0xb7, 0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29,
0xc1, 0x53, 0x87, 0x0c, 0xcf, 0xc5, 0x2e, 0xad, 0xec, 0x2e, 0x89, 0x6c, 0x8a, 0x2e, 0x8c, 0xae,
0x6c, 0x4a, 0x10, 0xd5, 0x21, 0xc3, 0x73, 0x29, 0x73, 0xa3, 0x93, 0xcb, 0x83, 0x7a, 0x4b, 0x73,
0xa3, 0x9b, 0x9b, 0x12, 0xbc, 0x01, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3,
0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10,
0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30,
0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03,
0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07,
0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e,
0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d,
0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b,
0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76,
0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90,
0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87,
0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e,
0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c,
0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca,
0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8,
0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82,
0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87,
0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a,
0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00,
0x71, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x56, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10,
0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x07,
0xd2, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0xd8, 0x80,
0x33, 0x5c, 0xbe, 0xf3, 0xf8, 0x83, 0x33, 0xdd, 0x7e, 0x71, 0xdb, 0x16, 0x30, 0x0d, 0x97, 0xef,
0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9,
0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x06, 0xd2,
0x70, 0xf9, 0xce, 0xe3, 0x4f, 0x44, 0x34, 0x21, 0x40, 0x84, 0xf9, 0xc5, 0x6d, 0x1b, 0xc1, 0x33,
0x5c, 0xbe, 0xf3, 0xf8, 0x54, 0x03, 0x44, 0x98, 0x5f, 0xdc, 0xb6, 0x01, 0x10, 0x0c, 0x80, 0x34,
0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c,
0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x8a, 0xab, 0x14, 0xca, 0xae, 0x10, 0x66,
0x00, 0x4a, 0xae, 0x24, 0x8a, 0xa2, 0xdc, 0x4a, 0x86, 0x4a, 0x09, 0x50, 0x1d, 0x01, 0x00, 0x00,
0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x75, 0x07, 0xb4, 0x6d, 0xc1, 0x88, 0x41, 0x02, 0x80,
0x20, 0x18, 0x18, 0x64, 0xa0, 0x58, 0xdc, 0x94, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x51,
0x06, 0xcb, 0xd5, 0x11, 0xca, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x66, 0xc0, 0x7c, 0x5e,
0xb5, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x71, 0x06, 0x0d, 0x18, 0x7c, 0x06, 0x33, 0x62,
0x90, 0x00, 0x20, 0x08, 0x06, 0x06, 0x1a, 0x38, 0x61, 0x00, 0x06, 0x55, 0x33, 0x62, 0x90, 0x00,
0x20, 0x08, 0x06, 0x46, 0x1a, 0x3c, 0x61, 0x10, 0x06, 0x98, 0x33, 0x62, 0x90, 0x00, 0x20, 0x08,
0x06, 0x86, 0x1a, 0x40, 0x62, 0x20, 0x06, 0xc9, 0x33, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc6,
0x1a, 0x44, 0x63, 0x30, 0x06, 0x18, 0x34, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x11, 0x1a, 0x4c,
0x89, 0x34, 0x9a, 0x10, 0x00, 0xa3, 0x09, 0x42, 0x30, 0x9a, 0x30, 0x08, 0x23, 0x06, 0x07, 0x00,
0x82, 0x60, 0x10, 0xb1, 0xc1, 0xd5, 0x60, 0xa3, 0x09, 0x01, 0x30, 0x9a, 0x20, 0x04, 0xa3, 0x09,
0x83, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x11, 0x1c, 0x6c, 0x91, 0x1a, 0x8c, 0x26, 0x04,
0xc0, 0x68, 0x82, 0x10, 0x8c, 0x26, 0x0c, 0xc2, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x44, 0x74,
0xf0, 0x55, 0x6b, 0x30, 0x9a, 0x10, 0x00, 0xa3, 0x09, 0x42, 0x30, 0x9a, 0x30, 0x08, 0xf6, 0x4c,
0xf2, 0x19, 0x31, 0x40, 0x00, 0x10, 0x04, 0x83, 0x09, 0x0f, 0xcc, 0x80, 0x99, 0x82, 0x11, 0x03,
0x04, 0x00, 0x41, 0x30, 0x98, 0xf2, 0xe0, 0x0c, 0x92, 0x29, 0xb0, 0xc0, 0x80, 0x8e, 0x49, 0x97,
0x7c, 0x46, 0x0c, 0x10, 0x00, 0x04, 0xc1, 0x60, 0xe2, 0x03, 0x35, 0x78, 0xae, 0x60, 0xc4, 0x00,
0x01, 0x40, 0x10, 0x0c, 0xa6, 0x3e, 0x58, 0x03, 0xe6, 0x0a, 0x2c, 0x48, 0xa0, 0x63, 0xd5, 0x26,
0x9f, 0x11, 0x03, 0x04, 0x00, 0x41, 0x30, 0x98, 0x40, 0xc1, 0x0d, 0xa4, 0x2d, 0x18, 0x31, 0x40,
0x00, 0x10, 0x04, 0x83, 0x29, 0x14, 0xde, 0xe0, 0xd9, 0x02, 0x0b, 0x18, 0xe8, 0x8c, 0x18, 0x1c,
0x00, 0x08, 0x82, 0x41, 0x44, 0x0a, 0x6f, 0x50, 0x06, 0xa0, 0x30, 0x9a, 0x10, 0x00, 0xa3, 0x09,
0x42, 0x30, 0x9a, 0x30, 0x08, 0xa3, 0x09, 0xc4, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x51,
0x2a, 0xd0, 0x81, 0x1a, 0x98, 0xc2, 0x68, 0x42, 0x00, 0x8c, 0x26, 0x08, 0xc1, 0x68, 0xc2, 0x20,
0x8c, 0x26, 0x10, 0xc3, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x44, 0xae, 0x90, 0x07, 0x6f, 0x40,
0x0a, 0xa3, 0x09, 0x01, 0x30, 0x9a, 0x20, 0x04, 0xa3, 0x09, 0x83, 0x30, 0x9a, 0x40, 0x0c, 0x23,
0x06, 0x07, 0x00, 0x82, 0x60, 0x10, 0xcd, 0x82, 0x1f, 0xd0, 0xc1, 0x2a, 0x8c, 0x26, 0x04, 0xc0,
0x68, 0x82, 0x10, 0x8c, 0x26, 0x0c, 0xc2, 0x68, 0x02, 0x31, 0xd8, 0xd4, 0xc9, 0x67, 0xc4, 0x00,
0x01, 0x40, 0x10, 0x0c, 0x26, 0x5c, 0x30, 0x85, 0x47, 0x0b, 0x46, 0x0c, 0x10, 0x00, 0x04, 0xc1,
0x60, 0xca, 0x85, 0x53, 0x58, 0xae, 0xc0, 0x82, 0x03, 0x3a, 0x66, 0x85, 0x81, 0x7c, 0x46, 0x0c,
0x10, 0x00, 0x04, 0xc1, 0x60, 0xe2, 0x05, 0x55, 0x90, 0xbc, 0x60, 0xc4, 0x00, 0x01, 0x40, 0x10,
0x0c, 0xa6, 0x5e, 0x58, 0x05, 0x67, 0x0b, 0x2c, 0x50, 0xa0, 0x63, 0x59, 0x19, 0xc8, 0x67, 0xc4,
0x00, 0x01, 0x40, 0x10, 0x0c, 0x26, 0x70, 0x70, 0x85, 0x4a, 0x0c, 0x82, 0x11, 0x03, 0x04, 0x00,
0x41, 0x30, 0x98, 0xc2, 0xe1, 0x15, 0xa2, 0x2f, 0xb0, 0xa0, 0x81, 0x8e, 0x71, 0x69, 0x20, 0x9f,
0x11, 0x03, 0x04, 0x00, 0x41, 0x30, 0x98, 0xc8, 0x41, 0x16, 0x30, 0x33, 0x08, 0x46, 0x0c, 0x10,
0x00, 0x04, 0xc1, 0x60, 0x2a, 0x87, 0x59, 0xa0, 0xc6, 0x20, 0xb0, 0x00, 0x82, 0xce, 0x88, 0xc1,
0x01, 0x80, 0x20, 0x18, 0x44, 0xe8, 0x30, 0x0b, 0xa9, 0x30, 0x0e, 0xa3, 0x09, 0x01, 0x30, 0x62,
0x70, 0x00, 0x20, 0x08, 0x06, 0x91, 0x3a, 0xd4, 0xc2, 0x2a, 0xc4, 0xc2, 0x68, 0x42, 0x00, 0x8c,
0x18, 0x1c, 0x00, 0x08, 0x82, 0x41, 0xc4, 0x0e, 0xb7, 0xd0, 0x0a, 0xb2, 0x30, 0x9a, 0x10, 0x00,
0xa3, 0x09, 0x46, 0x30, 0x9a, 0x50, 0x04, 0xa3, 0x09, 0x44, 0x30, 0x9a, 0x90, 0x08, 0xa3, 0x09,
0x88, 0x30, 0x9a, 0x70, 0x08, 0xb6, 0xc8, 0x82, 0x7c, 0x46, 0x0c, 0x10, 0x00, 0x04, 0xc1, 0x60,
0xa2, 0x07, 0x71, 0x90, 0x85, 0x23, 0x18, 0x31, 0x40, 0x00, 0x10, 0x04, 0x83, 0xa9, 0x1e, 0xc6,
0x41, 0x16, 0x8a, 0xc0, 0x98, 0x5a, 0x90, 0xcf, 0x88, 0x01, 0x02, 0x80, 0x20, 0x18, 0x4c, 0xf7,
0x50, 0x0e, 0xb5, 0x90, 0x04, 0x23, 0x06, 0x08, 0x00, 0x82, 0x60, 0x30, 0xe1, 0x83, 0x39, 0xd4,
0xc2, 0x11, 0x58, 0x83, 0x0b, 0xf2, 0x19, 0x31, 0x40, 0x00, 0x10, 0x04, 0x83, 0x49, 0x1f, 0xd0,
0x01, 0x17, 0x96, 0x60, 0xc4, 0x00, 0x01, 0x40, 0x10, 0x0c, 0xa6, 0x7d, 0x48, 0x07, 0x5c, 0x48,
0x82, 0x11, 0x83, 0x05, 0x00, 0x41, 0x30, 0x50, 0xfe, 0x41, 0x1c, 0x0e, 0x22, 0x38, 0x88, 0x60,
0xc4, 0xc0, 0x00, 0x40, 0x10, 0x0c, 0x98, 0x7f, 0x10, 0x87, 0xc0, 0x82, 0x44, 0x3e, 0x26, 0x1c,
0xf2, 0xb1, 0xa1, 0x90, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x25, 0xe1, 0x0e, 0xfe,
0xe0, 0x0f, 0xf5, 0x30, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x52, 0x12, 0xee, 0xe0, 0x0f,
0xfe, 0x50, 0x0e, 0xc2, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x25, 0xe1, 0x0e, 0xfe, 0xe0,
0x0f, 0xf3, 0x10, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x52, 0x12, 0xee, 0xf0, 0x0f, 0xfe,
0x50, 0x0f, 0xe2, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x49, 0xb8, 0xc3, 0x3f, 0xf8,
0x43, 0x39, 0x84, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x25, 0xe1, 0x0e, 0xf8, 0xe0,
0x0f, 0xf5, 0x70, 0x0a, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x94, 0x84, 0x3b, 0xe0, 0x83,
0x3f, 0x94, 0xc3, 0x28, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x52, 0x12, 0xee, 0x80, 0x0f,
0xfe, 0x30, 0x0f, 0x7f, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x49, 0xb8, 0x83, 0x3e,
0xf8, 0x43, 0x3d, 0x9c, 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x25, 0xe1, 0x0e, 0xfa,
0xe0, 0x0f, 0xe5, 0x30, 0x06, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x94, 0x84, 0x3b, 0xe8,
0x83, 0x3f, 0xcc, 0xc3, 0x37, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x49, 0xb8, 0x83, 0x3e,
0xf8, 0x03, 0x3d, 0x6c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif
// MSL only makes sense on Apple platforms
#if defined(SDL_PLATFORM_APPLE)
static const Uint8 PositionColor_vert_msl[1558] = {
static const Uint8 PositionColor_vert_msl[1498] = {
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,
@ -321,20 +346,10 @@ static const Uint8 PositionColor_vert_msl[1558] = {
0x79, 0x70, 0x65, 0x5f, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66,
0x6f, 0x72, 0x6d, 0x73, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x34, 0x78, 0x34, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x78, 0x34, 0x20, 0x76, 0x69, 0x65,
0x77, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72,
0x75, 0x63, 0x74, 0x20, 0x56, 0x53, 0x5f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x0a, 0x7b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x4e,
0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x32, 0x20, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a,
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x46, 0x53, 0x5f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x0a,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x50, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x33, 0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c,
0x6f, 0x61, 0x74, 0x32, 0x20, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x50,
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72,
0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x78, 0x34, 0x20, 0x77, 0x6f, 0x72,
0x6c, 0x64, 0x56, 0x69, 0x65, 0x77, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x78, 0x34, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61,
0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x72,
0x75, 0x63, 0x74, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x5f, 0x6f, 0x75, 0x74, 0x0a, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x6f, 0x75, 0x74, 0x5f, 0x76,
0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x20, 0x5b, 0x5b, 0x75, 0x73, 0x65,
@ -366,198 +381,180 @@ static const Uint8 PositionColor_vert_msl[1558] = {
0x5b, 0x5b, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, 0x0a, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x6f,
0x75, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
0x61, 0x74, 0x33, 0x20, 0x5f, 0x34, 0x32, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f,
0x76, 0x61, 0x72, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x5f, 0x34, 0x31, 0x20, 0x3d, 0x20, 0x69,
0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x5f, 0x34, 0x30,
0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58,
0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x34, 0x20, 0x5f, 0x36, 0x32, 0x20, 0x3d, 0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72,
0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x4d, 0x61,
0x74, 0x72, 0x69, 0x78, 0x20, 0x2a, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x69, 0x6e,
0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e,
0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x33, 0x20, 0x5f, 0x36, 0x33, 0x20, 0x3d, 0x20, 0x5f, 0x36, 0x32, 0x2e, 0x78, 0x79, 0x7a,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x5f, 0x35, 0x31,
0x20, 0x3d, 0x20, 0x5f, 0x36, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x33, 0x20, 0x5f, 0x34, 0x37, 0x20, 0x3d, 0x20, 0x5f, 0x36, 0x33, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x37, 0x30, 0x20, 0x3d, 0x20, 0x56,
0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x2a, 0x20, 0x66, 0x6c, 0x6f,
0x61, 0x74, 0x34, 0x28, 0x5f, 0x36, 0x32, 0x2e, 0x78, 0x79, 0x7a, 0x2c, 0x20, 0x31, 0x2e, 0x30,
0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x35,
0x30, 0x20, 0x3d, 0x20, 0x5f, 0x37, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
0x61, 0x74, 0x33, 0x20, 0x5f, 0x34, 0x39, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f,
0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x5f, 0x34, 0x38, 0x20, 0x3d, 0x20, 0x69, 0x6e,
0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44,
0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x34,
0x36, 0x20, 0x3d, 0x20, 0x5f, 0x37, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
0x61, 0x74, 0x33, 0x20, 0x5f, 0x34, 0x35, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f,
0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x5f, 0x34, 0x34, 0x20, 0x3d, 0x20, 0x69, 0x6e,
0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44,
0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x5f, 0x34,
0x33, 0x20, 0x3d, 0x20, 0x5f, 0x36, 0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74,
0x2e, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x5f,
0x37, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f,
0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x20, 0x3d, 0x20, 0x69, 0x6e,
0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x3b,
0x61, 0x74, 0x34, 0x20, 0x5f, 0x34, 0x32, 0x20, 0x3d, 0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f,
0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x77, 0x6f, 0x72, 0x6c, 0x64,
0x56, 0x69, 0x65, 0x77, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x2a, 0x20, 0x66, 0x6c, 0x6f,
0x61, 0x74, 0x34, 0x28, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x50, 0x4f,
0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x3d, 0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66,
0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x2a, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x5f, 0x34, 0x32, 0x2e, 0x78, 0x79, 0x7a,
0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e,
0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x20,
0x3d, 0x20, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a,
0x65, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x78, 0x33, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x34, 0x28, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72,
0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b,
0x30, 0x5d, 0x5b, 0x30, 0x5d, 0x2c, 0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55,
0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61,
0x74, 0x72, 0x69, 0x78, 0x5b, 0x31, 0x5d, 0x5b, 0x30, 0x5d, 0x2c, 0x20, 0x56, 0x69, 0x65, 0x77,
0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72,
0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b, 0x32, 0x5d, 0x5b, 0x30, 0x5d, 0x2c,
0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b, 0x33,
0x5d, 0x5b, 0x30, 0x5d, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x34, 0x28, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72,
0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b,
0x30, 0x5d, 0x5b, 0x31, 0x5d, 0x2c, 0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55,
0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61,
0x74, 0x72, 0x69, 0x78, 0x5b, 0x31, 0x5d, 0x5b, 0x31, 0x5d, 0x2c, 0x20, 0x56, 0x69, 0x65, 0x77,
0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72,
0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b, 0x32, 0x5d, 0x5b, 0x31, 0x5d, 0x2c,
0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b, 0x33,
0x5d, 0x5b, 0x31, 0x5d, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
0x34, 0x28, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72,
0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b,
0x30, 0x5d, 0x5b, 0x32, 0x5d, 0x2c, 0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55,
0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61,
0x74, 0x72, 0x69, 0x78, 0x5b, 0x31, 0x5d, 0x5b, 0x32, 0x5d, 0x2c, 0x20, 0x56, 0x69, 0x65, 0x77,
0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6e, 0x6f, 0x72,
0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b, 0x32, 0x5d, 0x5b, 0x32, 0x5d, 0x2c,
0x20, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d,
0x73, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x5b, 0x33,
0x5d, 0x5b, 0x32, 0x5d, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x29, 0x20, 0x2a, 0x20, 0x69, 0x6e, 0x2e,
0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x29, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72,
0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x2e,
0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61,
0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x33, 0x20, 0x3d, 0x20, 0x5f, 0x36,
0x33, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75,
0x74, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a,
0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x33, 0x20, 0x3d, 0x20, 0x5f, 0x34,
0x32, 0x2e, 0x78, 0x79, 0x7a, 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 PositionColor_vert_spirv[2316] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x48, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0xdf, 0x13, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x53, 0x50, 0x56, 0x5f, 0x4b, 0x48, 0x52, 0x5f,
0x71, 0x75, 0x61, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
0x05, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00,
0x74, 0x79, 0x70, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69,
0x66, 0x6f, 0x72, 0x6d, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,
0x06, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0x69, 0x65, 0x77,
0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x2e, 0x76,
0x61, 0x72, 0x2e, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x05, 0x00, 0x06, 0x00,
0x03, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x4e, 0x4f, 0x52, 0x4d, 0x41,
0x4c, 0x30, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x2e, 0x76,
0x61, 0x72, 0x2e, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x2e, 0x76, 0x61, 0x72, 0x2e,
0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x00, 0x05, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
static const Uint8 PositionColor_vert_spirv[1924] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x3e, 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,
0x0f, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72,
0x74, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x77, 0x6f, 0x72, 0x6c, 0x64, 0x56, 0x69, 0x65, 0x77, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x00,
0x06, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x72, 0x6d,
0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x56, 0x69, 0x65, 0x77, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x6e, 0x69, 0x66,
0x6f, 0x72, 0x6d, 0x73, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00,
0x69, 0x6e, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00,
0x05, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x4e,
0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00,
0x69, 0x6e, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x2e,
0x76, 0x61, 0x72, 0x2e, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x30, 0x00, 0x05, 0x00, 0x07, 0x00,
0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x54, 0x45, 0x58, 0x43,
0x4f, 0x4f, 0x52, 0x44, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, 0x00, 0x00,
0x6f, 0x75, 0x74, 0x2e, 0x76, 0x61, 0x72, 0x2e, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44,
0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x2e,
0x76, 0x61, 0x72, 0x2e, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x33, 0x00, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x56, 0x53, 0x5f, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x00, 0x00,
0x06, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x65, 0x78, 0x43,
0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x46, 0x53, 0x5f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x57, 0x6f, 0x72, 0x6c,
0x64, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00,
0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x21, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x50, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x29, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x24, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00,
0x17, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x33, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x00,
0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x90, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x32, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x30, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x00,
0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x07, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
0x3f, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
0x33, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x00,
0x21, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x16, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x19, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x1a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x1b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x1a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
0xf8, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x12, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00, 0x15, 0x00, 0x00, 0x00,
0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x2a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x12, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x12, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4f, 0x00, 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00, 0x15, 0x00, 0x00, 0x00,
0x3a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x06, 0x00, 0x1f, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00,
0x91, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
0x38, 0x00, 0x01, 0x00,
};

View File

@ -65,7 +65,7 @@ static const SDL_GPUShaderCreateInfo FragmentShaderDXILCodes[] = {
/* entrypoint */ "main",
/* format */ SDL_GPU_SHADERFORMAT_DXIL,
/* stage */ SDL_GPU_SHADERSTAGE_FRAGMENT,
/* num_samplers */ 0,
/* num_samplers */ 1,
/* num_storage_textures */ 0,
/* num_storage_buffers */ 0,
/* num_uniform_buffers */ 1,
@ -81,7 +81,7 @@ static const SDL_GPUShaderCreateInfo FragmentShaderMSLCodes[] = {
/* entrypoint */ "main0",
/* format */ SDL_GPU_SHADERFORMAT_MSL,
/* stage */ SDL_GPU_SHADERSTAGE_FRAGMENT,
/* num_samplers */ 0,
/* num_samplers */ 1,
/* num_storage_textures */ 0,
/* num_storage_buffers */ 0,
/* num_uniform_buffers */ 1,
@ -96,7 +96,7 @@ static const SDL_GPUShaderCreateInfo FragmentShaderSPIRVCodes[] = {
/* entrypoint */ "main",
/* format */ SDL_GPU_SHADERFORMAT_SPIRV,
/* stage */ SDL_GPU_SHADERSTAGE_FRAGMENT,
/* num_samplers */ 0,
/* num_samplers */ 1,
/* num_storage_textures */ 0,
/* num_storage_buffers */ 0,
/* num_uniform_buffers */ 1,

View File

@ -13,12 +13,6 @@ struct FS_Input
float3 WorldPosition : TEXCOORD3;
};
struct FS_Output
{
float4 Color : SV_Target0;
float Depth : SV_Depth;
};
struct SceneLight {
float4 color;
float4 position;

View File

@ -3,16 +3,17 @@
cbuffer ViewportUniforms : register(b0, space1)
{
float4x4 projection;
float4x4 viewMatrix;
float4x4 worldViewMatrix;
float4x4 normalMatrix;
}
FS_Input main(VS_Input input)
{
FS_Input output;
float3 viewPos = mul(viewMatrix, float4(input.Position, 1.0)).xyz;
float3 viewPos = mul(worldViewMatrix, float4(input.Position, 1.0)).xyz;
output.WorldPosition = viewPos;
output.Position = mul(projection, float4(viewPos, 1.0));
output.Normal = input.Normal;
output.Normal = normalize(mul(input.Normal, (float3x3) normalMatrix));
output.TexCoord = input.TexCoord;
return output;

View File

@ -1,11 +1,17 @@
#include "Common.hlsl"
struct FS_Output {
float4 Color : SV_Target0;
float Depth : SV_Depth;
};
cbuffer FragmentShadingData : register(b0, space3)
{
SceneLight lights[3];
int lightCount;
float Shininess;
uint ColorRaw;
int UseTexture;
}
float4 unpackColor(uint packed)
@ -18,6 +24,9 @@ float4 unpackColor(uint packed)
return color;
}
Texture2D<float4> Texture : register(t0, space2);
SamplerState Sampler : register(s0, space2);
FS_Output main(FS_Input input)
{
FS_Output output;
@ -63,6 +72,10 @@ FS_Output main(FS_Input input)
float4 Color = unpackColor(ColorRaw);
float3 finalColor = saturate(diffuse * Color.rgb + specular);
if (UseTexture != 0) {
float4 texel = Texture.Sample(Sampler, input.TexCoord);
finalColor = saturate(texel.rgb * finalColor);
}
output.Color = float4(finalColor, Color.a);
output.Depth = input.Position.w;
return output;

View File

@ -1,5 +1,5 @@
{
"num_samplers": 0,
"num_samplers": 1,
"num_storage_textures": 0,
"num_storage_buffers": 0,
"num_uniform_buffers": 1

View File

@ -2,6 +2,7 @@
#include "d3drmrenderer_software.h"
#include "ddsurface_impl.h"
#include "mathutils.h"
#include "meshutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
@ -32,7 +33,7 @@ void Direct3DRMSoftwareRenderer::ClearZBuffer()
std::fill(m_zBuffer.begin(), m_zBuffer.end(), std::numeric_limits<float>::infinity());
}
void Direct3DRMSoftwareRenderer::ProjectVertex(const GeometryVertex& v, D3DRMVECTOR4D& p) const
void Direct3DRMSoftwareRenderer::ProjectVertex(const D3DRMVERTEX& v, D3DRMVECTOR4D& p) const
{
float px = m_projection[0][0] * v.position.x + m_projection[1][0] * v.position.y +
m_projection[2][0] * v.position.z + m_projection[3][0];
@ -47,9 +48,10 @@ void Direct3DRMSoftwareRenderer::ProjectVertex(const GeometryVertex& v, D3DRMVEC
// Perspective divide
if (pw != 0.0f) {
px /= pw;
py /= pw;
pz /= pw;
float invW = 1.0f / pw;
px *= invW;
py *= invW;
pz *= invW;
}
// Map from NDC [-1,1] to screen coordinates
@ -58,31 +60,26 @@ void Direct3DRMSoftwareRenderer::ProjectVertex(const GeometryVertex& v, D3DRMVEC
p.z = pz;
}
GeometryVertex SplitEdge(GeometryVertex a, const GeometryVertex& b, float plane)
D3DRMVERTEX SplitEdge(D3DRMVERTEX a, const D3DRMVERTEX& b, float plane)
{
float t = (plane - a.position.z) / (b.position.z - a.position.z);
a.position.x = a.position.x + t * (b.position.x - a.position.x);
a.position.y = a.position.y + t * (b.position.y - a.position.y);
a.position.x += t * (b.position.x - a.position.x);
a.position.y += t * (b.position.y - a.position.y);
a.position.z = plane;
a.texCoord.u = a.texCoord.u + t * (b.texCoord.u - a.texCoord.u);
a.texCoord.v = a.texCoord.v + t * (b.texCoord.v - a.texCoord.v);
a.texCoord.u += t * (b.texCoord.u - a.texCoord.u);
a.texCoord.v += t * (b.texCoord.v - a.texCoord.v);
a.normals.x = a.normals.x + t * (b.normals.x - a.normals.x);
a.normals.y = a.normals.y + t * (b.normals.y - a.normals.y);
a.normals.z = a.normals.z + t * (b.normals.z - a.normals.z);
a.normal.x += t * (b.normal.x - a.normal.x);
a.normal.y += t * (b.normal.y - a.normal.y);
a.normal.z += t * (b.normal.z - a.normal.z);
float len = std::sqrt(a.normals.x * a.normals.x + a.normals.y * a.normals.y + a.normals.z * a.normals.z);
if (len > 0.0001f) {
a.normals.x /= len;
a.normals.y /= len;
a.normals.z /= len;
}
a.normal = Normalize(a.normal);
return a;
}
void Direct3DRMSoftwareRenderer::DrawTriangleClipped(const GeometryVertex (&v)[3], const Appearance& appearance)
void Direct3DRMSoftwareRenderer::DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance)
{
bool in0 = v[0].position.z >= m_front;
bool in1 = v[1].position.z >= m_front;
@ -98,7 +95,7 @@ void Direct3DRMSoftwareRenderer::DrawTriangleClipped(const GeometryVertex (&v)[3
DrawTriangleProjected(v[0], v[1], v[2], appearance);
}
else if (insideCount == 2) {
GeometryVertex split;
D3DRMVERTEX split;
if (!in0) {
split = SplitEdge(v[2], v[0], m_front);
DrawTriangleProjected(v[1], v[2], split, appearance);
@ -149,23 +146,15 @@ void Direct3DRMSoftwareRenderer::BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g,
memcpy(pixelAddr, &blended, m_bytesPerPixel);
}
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const GeometryVertex& vertex, const Appearance& appearance)
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(
const D3DVECTOR& position,
const D3DVECTOR& normal,
const Appearance& appearance
)
{
FColor specular = {0, 0, 0, 0};
FColor diffuse = {0, 0, 0, 0};
// Position and normal
D3DVECTOR position = vertex.position;
D3DVECTOR normal = vertex.normals;
float normLen = std::sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
if (normLen == 0.0f) {
return appearance.color;
}
normal.x /= normLen;
normal.y /= normLen;
normal.z /= normLen;
for (const auto& light : m_lights) {
FColor lightColor = light.color;
@ -185,14 +174,7 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const GeometryVertex& vertex
else if (light.positional == 1.0f) {
lightVec = {light.position.x - position.x, light.position.y - position.y, light.position.z - position.z};
}
float len = std::sqrt(lightVec.x * lightVec.x + lightVec.y * lightVec.y + lightVec.z * lightVec.z);
if (len == 0.0f) {
continue;
}
lightVec.x /= len;
lightVec.y /= len;
lightVec.z /= len;
lightVec = Normalize(lightVec);
float dotNL = normal.x * lightVec.x + normal.y * lightVec.y + normal.z * lightVec.z;
if (dotNL > 0.0f) {
@ -203,7 +185,7 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const GeometryVertex& vertex
if (appearance.shininess != 0.0f) {
// Using dotNL ignores view angle, but this matches DirectX 5 behavior.
float spec = std::pow(dotNL, appearance.shininess);
float spec = std::pow(dotNL, appearance.shininess * m_shininessFactor);
specular.r += spec * lightColor.r;
specular.g += spec * lightColor.g;
specular.b += spec * lightColor.b;
@ -219,15 +201,24 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const GeometryVertex& vertex
};
}
inline float EdgeFloat(float x0, float y0, float x1, float y1, float x, float y)
{
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
}
inline float EdgeDouble(double x0, double y0, double x1, double y1, double x, double y)
{
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
}
void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
const GeometryVertex& v0,
const GeometryVertex& v1,
const GeometryVertex& v2,
const D3DRMVERTEX& v0,
const D3DRMVERTEX& v1,
const D3DRMVERTEX& v2,
const Appearance& appearance
)
{
D3DRMVECTOR4D p0, p1, p2;
ProjectVertex(v0, p0);
ProjectVertex(v1, p1);
ProjectVertex(v2, p2);
@ -243,27 +234,31 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
return;
}
int minX = std::max(0, (int) std::floor(std::min({p0.x, p1.x, p2.x})));
int maxX = std::min((int) m_width - 1, (int) std::ceil(std::max({p0.x, p1.x, p2.x})));
int minY = std::max(0, (int) std::floor(std::min({p0.y, p1.y, p2.y})));
int maxY = std::min((int) m_height - 1, (int) std::ceil(std::max({p0.y, p1.y, p2.y})));
if (minX > maxX || minY > maxY) {
int minX = std::clamp((int) std::floor(std::min({p0.x, p1.x, p2.x})), 0, (int) m_width - 1);
int maxX = std::clamp((int) std::ceil(std::max({p0.x, p1.x, p2.x})), 0, (int) m_width - 1);
if (minX > maxX) {
return;
}
int minY = std::clamp((int) std::floor(std::min({p0.y, p1.y, p2.y})), 0, (int) m_height - 1);
int maxY = std::clamp((int) std::ceil(std::max({p0.y, p1.y, p2.y})), 0, (int) m_height - 1);
if (minY > maxY) {
return;
}
auto edge = [](double x0, double y0, double x1, double y1, double x, double y) {
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
};
float area = edge(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
// Cull backfaces
float area = EdgeFloat(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
if (area >= 0) {
return;
}
float invArea = 1.0f / area;
// Per-vertex lighting using vertex normals
SDL_Color c0 = ApplyLighting(v0, appearance);
SDL_Color c1 = ApplyLighting(v1, appearance);
SDL_Color c2 = ApplyLighting(v2, appearance);
Uint8 r, g, b;
SDL_Color c0 = ApplyLighting(v0.position, v0.normal, appearance);
SDL_Color c1, c2;
if (!appearance.flat) {
c1 = ApplyLighting(v1.position, v1.normal, appearance);
c2 = ApplyLighting(v2.position, v2.normal, appearance);
}
Uint32 textureId = appearance.textureId;
int texturePitch;
@ -287,12 +282,12 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
for (int x = minX; x <= maxX; ++x) {
float px = x + 0.5f;
float py = y + 0.5f;
float w0 = edge(p1.x, p1.y, p2.x, p2.y, px, py) * invArea;
float w0 = EdgeDouble(p1.x, p1.y, p2.x, p2.y, px, py) * invArea;
if (w0 < 0.0f || w0 > 1.0f) {
continue;
}
float w1 = edge(p2.x, p2.y, p0.x, p0.y, px, py) * invArea;
float w1 = EdgeDouble(p2.x, p2.y, p0.x, p0.y, px, py) * invArea;
if (w1 < 0.0f || w1 > 1.0f - w0) {
continue;
}
@ -306,10 +301,16 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
continue;
}
// Interpolate color
Uint8 r = static_cast<Uint8>(w0 * c0.r + w1 * c1.r + w2 * c2.r);
Uint8 g = static_cast<Uint8>(w0 * c0.g + w1 * c1.g + w2 * c2.g);
Uint8 b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
if (appearance.flat) {
r = c0.r;
g = c0.g;
b = c0.b;
}
else {
r = static_cast<Uint8>(w0 * c0.r + w1 * c1.r + w2 * c2.r);
g = static_cast<Uint8>(w0 * c0.g + w1 * c1.g + w2 * c2.g);
b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
}
Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel;
if (appearance.color.a == 255) {
@ -338,8 +339,22 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
Uint8* texelAddr = texels + texY * texturePitch + texX * m_bytesPerPixel;
Uint32 texelColor = 0;
memcpy(&texelColor, texelAddr, m_bytesPerPixel);
Uint32 texelColor;
switch (m_bytesPerPixel) {
case 1:
texelColor = *texelAddr;
break;
case 2:
texelColor = *(Uint16*) texelAddr;
break;
case 3:
// Manually build the 24-bit color (assuming byte order)
texelColor = texelAddr[0] | (texelAddr[1] << 8) | (texelAddr[2] << 16);
break;
case 4:
texelColor = *(Uint32*) texelAddr;
break;
}
Uint8 tr, tg, tb, ta;
SDL_GetRGBA(texelColor, m_format, m_palette, &tr, &tg, &tb, &ta);
@ -411,10 +426,8 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture)
// Reuse freed slot
for (Uint32 i = 0; i < m_textures.size(); ++i) {
auto& texRef = m_textures[i];
if (texRef.texture == nullptr) {
texRef.texture = texture;
texRef.cached = convertedRender;
texRef.version = texture->m_version;
if (!texRef.texture) {
texRef = {texture, texture->m_version, convertedRender};
AddTextureDestroyCallback(i, texture);
return i;
}
@ -426,6 +439,78 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture)
return static_cast<Uint32>(m_textures.size() - 1);
}
MeshCache UploadMesh(const MeshGroup& meshGroup)
{
MeshCache cache{&meshGroup, meshGroup.version};
cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT;
std::vector<D3DRMVERTEX> vertices;
if (cache.flat) {
FlattenSurfaces(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
meshGroup.texture != nullptr,
cache.vertices,
cache.indices
);
}
else {
cache.vertices.assign(meshGroup.vertices.begin(), meshGroup.vertices.end());
cache.indices.assign(meshGroup.indices.begin(), meshGroup.indices.end());
}
return cache;
}
struct MeshDestroyContext {
Direct3DRMSoftwareRenderer* renderer;
Uint32 id;
};
void Direct3DRMSoftwareRenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new MeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<MeshDestroyContext*>(arg);
ctx->renderer->m_meshs[ctx->id].meshGroup = nullptr;
delete ctx;
},
ctx
);
}
Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
{
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
cache = std::move(UploadMesh(*meshGroup));
}
return i;
}
}
auto newCache = UploadMesh(*meshGroup);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (!cache.meshGroup) {
cache = std::move(newCache);
AddMeshDestroyCallback(i, mesh);
return i;
}
}
m_meshs.push_back(std::move(newCache));
AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh);
return (Uint32) (m_meshs.size() - 1);
}
DWORD Direct3DRMSoftwareRenderer::GetWidth()
{
return m_width;
@ -470,8 +555,7 @@ HRESULT Direct3DRMSoftwareRenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
}
void Direct3DRMSoftwareRenderer::SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -480,15 +564,27 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
D3DRMMATRIX4D mvMatrix;
MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix);
for (size_t i = 0; i + 2 < count; i += 3) {
GeometryVertex vrts[3];
for (size_t j = 0; j < 3; ++j) {
const GeometryVertex& src = vertices[i + j];
vrts[j].position = TransformPoint(src.position, mvMatrix);
vrts[j].normals = Normalize(TransformNormal(src.normals, normalMatrix));
vrts[j].texCoord = src.texCoord;
}
DrawTriangleClipped(vrts, appearance);
auto& mesh = m_meshs[meshId];
// Pre-transform all vertex positions and normals
std::vector<D3DRMVERTEX> transformedVerts(mesh.vertices.size());
for (size_t i = 0; i < mesh.vertices.size(); ++i) {
const D3DRMVERTEX& src = mesh.vertices[i];
D3DRMVERTEX& dst = transformedVerts[i];
dst.position = TransformPoint(src.position, mvMatrix);
// TODO defer normal transformation til lighting to allow culling first
dst.normal = Normalize(TransformNormal(src.normal, normalMatrix));
dst.texCoord = src.texCoord;
}
// Assemble triangles using index buffer
for (size_t i = 0; i + 2 < mesh.indices.size(); i += 3) {
DrawTriangleClipped(
{transformedVerts[mesh.indices[i]],
transformedVerts[mesh.indices[i + 1]],
transformedVerts[mesh.indices[i + 2]]},
appearance
);
}
}

View File

@ -7,8 +7,8 @@
#include "d3drmmesh_impl.h"
#include "d3drmobject_impl.h"
#include "d3drmrenderer.h"
#ifdef USE_OPENGL15
#include "d3drmrenderer_opengl15.h"
#ifdef USE_OPENGL1
#include "d3drmrenderer_opengl1.h"
#endif
#include "d3drmrenderer_sdl3gpu.h"
#include "d3drmrenderer_software.h"
@ -144,9 +144,9 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) {
renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#ifdef USE_OPENGL15
else if (SDL_memcmp(&guid, &OPENGL15_GUID, sizeof(GUID)) == 0) {
renderer = OpenGL15Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
#ifdef USE_OPENGL1
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) {
renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
else {

View File

@ -6,6 +6,7 @@
#include "ddraw_impl.h"
#include "miniwin.h"
#include "miniwin/d3drm.h"
#include "miniwin/miniwindevice.h"
#include <SDL3/SDL.h>
@ -26,6 +27,22 @@ Direct3DRMDevice2Impl::~Direct3DRMDevice2Impl()
delete m_renderer;
}
HRESULT Direct3DRMDevice2Impl::QueryInterface(const GUID& riid, void** ppvObject)
{
if (SDL_memcmp(&riid, &IID_IDirect3DRMDevice2, sizeof(riid)) == 0) {
this->IUnknown::AddRef();
*ppvObject = static_cast<IDirect3DRMDevice2*>(this);
return DD_OK;
}
else if (SDL_memcmp(&riid, &IID_IDirect3DRMMiniwinDevice, sizeof(riid)) == 0) {
this->IUnknown::AddRef();
*ppvObject = static_cast<IDirect3DRMMiniwinDevice*>(this);
return DD_OK;
}
MINIWIN_NOT_IMPLEMENTED();
return E_NOINTERFACE;
}
DWORD Direct3DRMDevice2Impl::GetWidth()
{
return m_width;
@ -121,3 +138,13 @@ HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewpor
*ppViewportArray = m_viewports;
return DD_OK;
}
float Direct3DRMDevice2Impl::GetShininessFactor()
{
return m_renderer->GetShininessFactor();
}
HRESULT Direct3DRMDevice2Impl::SetShininessFactor(float factor)
{
return m_renderer->SetShininessFactor(factor);
}

View File

@ -60,7 +60,7 @@ HRESULT Direct3DRMMeshImpl::AddGroup(
group.vertexPerFace = vertexPerFace;
DWORD* src = faceBuffer;
group.faces.assign(src, src + faceCount * vertexPerFace);
group.indices.assign(src, src + faceCount * vertexPerFace);
m_groups.push_back(std::move(group));
@ -72,8 +72,8 @@ HRESULT Direct3DRMMeshImpl::GetGroup(
DWORD* vertexCount,
DWORD* faceCount,
DWORD* vertexPerFace,
DWORD* dataSize,
DWORD* data
DWORD* indexCount,
DWORD* indices
)
{
if (groupIndex >= m_groups.size()) {
@ -86,21 +86,26 @@ HRESULT Direct3DRMMeshImpl::GetGroup(
*vertexCount = static_cast<DWORD>(group.vertices.size());
}
if (faceCount) {
*faceCount = static_cast<DWORD>(group.faces.size() / group.vertexPerFace);
*faceCount = static_cast<DWORD>(group.indices.size() / group.vertexPerFace);
}
if (vertexPerFace) {
*vertexPerFace = static_cast<DWORD>(group.vertexPerFace);
}
if (dataSize) {
*dataSize = static_cast<DWORD>(group.faces.size());
if (indexCount) {
*indexCount = static_cast<DWORD>(group.indices.size());
}
if (data) {
std::copy(group.faces.begin(), group.faces.end(), reinterpret_cast<unsigned int*>(data));
if (indices) {
std::copy(group.indices.begin(), group.indices.end(), reinterpret_cast<unsigned int*>(indices));
}
return DD_OK;
}
const MeshGroup& Direct3DRMMeshImpl::GetGroup(DWORD groupIndex)
{
return m_groups[groupIndex];
}
DWORD Direct3DRMMeshImpl::GetGroupCount()
{
return m_groups.size();
@ -112,7 +117,12 @@ HRESULT Direct3DRMMeshImpl::SetGroupColor(DWORD groupIndex, D3DCOLOR color)
return DDERR_INVALIDPARAMS;
}
m_groups[groupIndex].color = color;
m_groups[groupIndex].color = {
static_cast<Uint8>((color >> 16) & 0xFF),
static_cast<Uint8>((color >> 8) & 0xFF),
static_cast<Uint8>((color >> 0) & 0xFF),
static_cast<Uint8>((color >> 24) & 0xFF)
};
return DD_OK;
}
@ -122,10 +132,9 @@ HRESULT Direct3DRMMeshImpl::SetGroupColorRGB(DWORD groupIndex, float r, float g,
return DDERR_INVALIDPARAMS;
}
D3DCOLOR color = (0xFF << 24) | (static_cast<BYTE>(r * 255.0f) << 16) | (static_cast<BYTE>(g * 255.0f) << 8) |
(static_cast<BYTE>(b * 255.0f));
m_groups[groupIndex]
.color = {static_cast<Uint8>(r * 255.0f), static_cast<Uint8>(g * 255.0f), static_cast<Uint8>(b * 255.0f), 255};
m_groups[groupIndex].color = color;
return DD_OK;
}
@ -134,7 +143,9 @@ D3DCOLOR Direct3DRMMeshImpl::GetGroupColor(D3DRMGROUPINDEX index)
if (index < 0 || index >= static_cast<int>(m_groups.size())) {
return 0xFFFFFFFF;
}
return m_groups[index].color;
const SDL_Color& color = m_groups[index].color;
return (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
}
HRESULT Direct3DRMMeshImpl::SetGroupMaterial(DWORD groupIndex, IDirect3DRMMaterial* material)
@ -166,6 +177,7 @@ HRESULT Direct3DRMMeshImpl::SetGroupTexture(DWORD groupIndex, IDirect3DRMTexture
texture->AddRef();
group.texture = texture;
group.version++;
return DD_OK;
}
@ -224,7 +236,10 @@ HRESULT Direct3DRMMeshImpl::SetGroupQuality(DWORD groupIndex, D3DRMRENDERQUALITY
break;
}
m_groups[groupIndex].quality = quality;
auto& group = m_groups[groupIndex];
group.quality = quality;
group.version++;
return DD_OK;
}
@ -243,7 +258,8 @@ HRESULT Direct3DRMMeshImpl::SetVertices(DWORD groupIndex, int offset, int count,
return DDERR_INVALIDPARAMS;
}
auto& vertList = m_groups[groupIndex].vertices;
auto& group = m_groups[groupIndex];
auto& vertList = group.vertices;
if (offset + count > static_cast<int>(vertList.size())) {
vertList.resize(offset + count);
@ -253,6 +269,8 @@ HRESULT Direct3DRMMeshImpl::SetVertices(DWORD groupIndex, int offset, int count,
UpdateBox();
group.version++;
return DD_OK;
}

View File

@ -1,5 +1,6 @@
#include "d3drm_impl.h"
#include "d3drmframe_impl.h"
#include "d3drmmesh_impl.h"
#include "d3drmrenderer.h"
#include "d3drmviewport_impl.h"
#include "ddraw_impl.h"
@ -95,21 +96,6 @@ static void ComputeFrameWorldMatrix(IDirect3DRMFrame* frame, D3DRMMATRIX4D out)
memcpy(out, acc, sizeof(acc));
}
inline D3DVECTOR CrossProduct(const D3DVECTOR& a, const D3DVECTOR& b)
{
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
D3DVECTOR ComputeTriangleNormal(const D3DVECTOR& v0, const D3DVECTOR& v1, const D3DVECTOR& v2)
{
D3DVECTOR u = {v1.x - v0.x, v1.y - v0.y, v1.z - v0.z};
D3DVECTOR v = {v2.x - v0.x, v2.y - v0.y, v2.z - v0.z};
D3DVECTOR normal = CrossProduct(u, v);
normal = Normalize(normal);
return normal;
}
void Direct3DRMViewportImpl::CollectLightsFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentToWorld,
@ -194,13 +180,31 @@ void ExtractFrustumPlanes(const D3DRMMATRIX4D& m)
}
}
bool IsBoxInFrustum(const D3DVECTOR corners[8], const Plane planes[6])
bool IsMeshInFrustum(Direct3DRMMeshImpl* mesh, const D3DRMMATRIX4D& worldMatrix)
{
D3DRMBOX box;
mesh->GetBox(&box);
D3DVECTOR boxCorners[8] = {
{box.min.x, box.min.y, box.min.z},
{box.min.x, box.min.y, box.max.z},
{box.min.x, box.max.y, box.min.z},
{box.min.x, box.max.y, box.max.z},
{box.max.x, box.min.y, box.min.z},
{box.max.x, box.min.y, box.max.z},
{box.max.x, box.max.y, box.min.z},
{box.max.x, box.max.y, box.max.z},
};
for (D3DVECTOR& corner : boxCorners) {
corner = TransformPoint(corner, worldMatrix);
}
for (int i = 0; i < 6; ++i) {
int out = 0;
for (int j = 0; j < 8; ++j) {
float dist = planes[i].normal.x * corners[j].x + planes[i].normal.y * corners[j].y +
planes[i].normal.z * corners[j].z + planes[i].d;
float dist = frustumPlanes[i].normal.x * boxCorners[j].x + frustumPlanes[i].normal.y * boxCorners[j].y +
frustumPlanes[i].normal.z * boxCorners[j].z + frustumPlanes[i].d;
if (dist < 0.0f) {
++out;
}
@ -212,13 +216,7 @@ bool IsBoxInFrustum(const D3DVECTOR corners[8], const Plane planes[6])
return true;
}
void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix,
std::vector<GeometryVertex>& verts,
std::vector<D3DRMVERTEX>& d3dVerts,
std::vector<DWORD>& faces
)
void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix)
{
Direct3DRMFrameImpl* frameImpl = static_cast<Direct3DRMFrameImpl*>(frame);
D3DRMMATRIX4D localMatrix;
@ -240,104 +238,32 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* childFrame = nullptr;
visual->QueryInterface(IID_IDirect3DRMFrame, (void**) &childFrame);
if (childFrame) {
CollectMeshesFromFrame(childFrame, worldMatrix, verts, d3dVerts, faces);
CollectMeshesFromFrame(childFrame, worldMatrix);
childFrame->Release();
visual->Release();
continue;
}
IDirect3DRMMesh* mesh = nullptr;
Direct3DRMMeshImpl* mesh = nullptr;
visual->QueryInterface(IID_IDirect3DRMMesh, (void**) &mesh);
if (!mesh) {
visual->Release();
continue;
}
D3DRMBOX box;
mesh->GetBox(&box);
D3DVECTOR boxCorners[8] = {
{box.min.x, box.min.y, box.min.z},
{box.min.x, box.min.y, box.max.z},
{box.min.x, box.max.y, box.min.z},
{box.min.x, box.max.y, box.max.z},
{box.max.x, box.min.y, box.min.z},
{box.max.x, box.min.y, box.max.z},
{box.max.x, box.max.y, box.min.z},
{box.max.x, box.max.y, box.max.z},
};
for (D3DVECTOR& boxCorner : boxCorners) {
boxCorner = TransformPoint(boxCorner, worldMatrix);
}
if (!IsBoxInFrustum(boxCorners, frustumPlanes)) {
if (mesh) {
if (IsMeshInFrustum(mesh, worldMatrix)) {
DWORD groupCount = mesh->GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) {
const MeshGroup& meshGroup = mesh->GetGroup(gi);
m_renderer->SubmitDraw(
m_renderer->GetMeshId(mesh, &meshGroup),
worldMatrix,
worldMatrixInvert,
{meshGroup.color,
meshGroup.material ? meshGroup.material->GetPower() : 0.0f,
meshGroup.texture ? m_renderer->GetTextureId(meshGroup.texture) : NO_TEXTURE_ID,
meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT}
);
}
}
mesh->Release();
visual->Release();
continue;
}
DWORD groupCount = mesh->GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) {
DWORD vtxCount, faceCount, vpf, dataSize;
mesh->GetGroup(gi, &vtxCount, &faceCount, &vpf, &dataSize, nullptr);
verts.reserve(dataSize);
verts.clear();
d3dVerts.resize(vtxCount);
faces.resize(dataSize);
mesh->GetVertices(gi, 0, vtxCount, d3dVerts.data());
mesh->GetGroup(gi, nullptr, nullptr, nullptr, nullptr, faces.data());
D3DCOLOR color = mesh->GetGroupColor(gi);
D3DRMRENDERQUALITY quality = mesh->GetGroupQuality(gi);
IDirect3DRMTexture* texture = nullptr;
mesh->GetGroupTexture(gi, &texture);
Uint32 textureId = NO_TEXTURE_ID;
if (texture) {
textureId = m_renderer->GetTextureId(texture);
texture->Release();
}
IDirect3DRMMaterial* material = nullptr;
mesh->GetGroupMaterial(gi, &material);
float shininess = 0.0f;
if (material) {
shininess = material->GetPower();
material->Release();
}
for (DWORD fi = 0; fi < faceCount; ++fi) {
D3DVECTOR norm;
if (quality == D3DRMRENDER_FLAT || quality == D3DRMRENDER_UNLITFLAT) {
D3DRMVERTEX& v0 = d3dVerts[faces[fi * vpf + 0]];
D3DRMVERTEX& v1 = d3dVerts[faces[fi * vpf + 1]];
D3DRMVERTEX& v2 = d3dVerts[faces[fi * vpf + 2]];
norm = ComputeTriangleNormal(v0.position, v1.position, v2.position);
}
for (DWORD idx = 0; idx < vpf; ++idx) {
D3DRMVERTEX& dv = d3dVerts[faces[fi * vpf + idx]];
D3DVECTOR pos = dv.position;
if (quality == D3DRMRENDER_GOURAUD || quality == D3DRMRENDER_PHONG) {
norm = dv.normal;
}
verts.push_back({pos, norm, {dv.tu, dv.tv}});
}
}
m_renderer->SubmitDraw(
verts.data(),
verts.size(),
worldMatrix,
worldMatrixInvert,
{{static_cast<Uint8>((color >> 16) & 0xFF),
static_cast<Uint8>((color >> 8) & 0xFF),
static_cast<Uint8>((color >> 0) & 0xFF),
static_cast<Uint8>((color >> 24) & 0xFF)},
shininess,
textureId}
);
}
mesh->Release();
visual->Release();
}
visuals->Release();
@ -363,11 +289,8 @@ HRESULT Direct3DRMViewportImpl::RenderScene()
return status;
}
std::vector<GeometryVertex> verts;
std::vector<D3DRMVERTEX> d3dVerts;
std::vector<DWORD> faces;
ExtractFrustumPlanes(viewProj);
CollectMeshesFromFrame(m_rootFrame, identity, verts, d3dVerts, faces);
CollectMeshesFromFrame(m_rootFrame, identity);
return m_renderer->FinalizeFrame();
}
@ -715,35 +638,25 @@ bool RayIntersectsTriangle(
bool RayIntersectsMeshTriangles(
const Ray& ray,
IDirect3DRMMesh* mesh,
Direct3DRMMeshImpl& mesh,
const D3DRMMATRIX4D& worldMatrix,
float& outDistance
)
{
DWORD groupCount = mesh->GetGroupCount();
for (DWORD g = 0; g < groupCount; ++g) {
DWORD vtxCount = 0, faceCount = 0, vpf = 0, dataSize = 0;
mesh->GetGroup(g, &vtxCount, &faceCount, &vpf, &dataSize, nullptr);
std::vector<D3DRMVERTEX> vertices(vtxCount);
mesh->GetVertices(g, 0, vtxCount, vertices.data());
std::vector<DWORD> faces(faceCount * vpf);
mesh->GetGroup(g, nullptr, nullptr, nullptr, nullptr, faces.data());
DWORD groupCount = mesh.GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) {
const MeshGroup& meshGroup = mesh.GetGroup(gi);
// Iterate over each face and do ray-triangle tests
for (DWORD fi = 0; fi < faceCount; ++fi) {
DWORD i0 = faces[fi * vpf + 0];
DWORD i1 = faces[fi * vpf + 1];
DWORD i2 = faces[fi * vpf + 2];
if (i0 >= vtxCount || i1 >= vtxCount || i2 >= vtxCount) {
continue;
}
for (DWORD fi = 0; fi < meshGroup.indices.size(); fi += 3) {
DWORD i0 = meshGroup.indices[fi + 0];
DWORD i1 = meshGroup.indices[fi + 1];
DWORD i2 = meshGroup.indices[fi + 2];
// Transform vertices to world space
D3DVECTOR tri[3];
for (int j = 0; j < 3; ++j) {
const D3DVECTOR& v = vertices[(j == 0 ? i0 : (j == 1 ? i1 : i2))].position;
const D3DVECTOR& v = meshGroup.vertices[(j == 0 ? i0 : (j == 1 ? i1 : i2))].position;
tri[j] = TransformPoint(v, worldMatrix);
}
@ -836,7 +749,7 @@ HRESULT Direct3DRMViewportImpl::Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY*
continue;
}
IDirect3DRMMesh* mesh = nullptr;
Direct3DRMMeshImpl* mesh = nullptr;
visual->QueryInterface(IID_IDirect3DRMMesh, (void**) &mesh);
if (mesh) {
D3DRMBOX box;
@ -848,7 +761,7 @@ HRESULT Direct3DRMViewportImpl::Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY*
float distance = FLT_MAX;
if (RayIntersectsBox(pickRay, worldBox, distance) &&
RayIntersectsMeshTriangles(pickRay, mesh, worldMatrix, distance)) {
RayIntersectsMeshTriangles(pickRay, *mesh, worldMatrix, distance)) {
auto* arr = new Direct3DRMFrameArrayImpl();
for (IDirect3DRMFrame* f : path) {
arr->AddElement(f);

View File

@ -1,5 +1,5 @@
#ifdef USE_OPENGL15
#include "d3drmrenderer_opengl15.h"
#ifdef USE_OPENGL1
#include "d3drmrenderer_opengl1.h"
#endif
#include "d3drmrenderer_sdl3gpu.h"
#include "d3drmrenderer_software.h"
@ -227,8 +227,8 @@ void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMRenderer* devi
HRESULT DirectDrawImpl::EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
Direct3DRMSDL3GPU_EnumDevice(cb, ctx);
#ifdef USE_OPENGL15
OpenGL15Renderer_EnumDevice(cb, ctx);
#ifdef USE_OPENGL1
OpenGL1Renderer_EnumDevice(cb, ctx);
#endif
Direct3DRMSoftware_EnumDevice(cb, ctx);
@ -327,9 +327,9 @@ HRESULT DirectDrawImpl::CreateDevice(
if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) {
renderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#ifdef USE_OPENGL15
else if (SDL_memcmp(&guid, &OPENGL15_GUID, sizeof(GUID)) == 0) {
renderer = OpenGL15Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
#ifdef USE_OPENGL1
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) {
renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) {

View File

@ -3,12 +3,14 @@
#include "d3drmobject_impl.h"
#include "d3drmrenderer.h"
#include "miniwin/d3drm.h"
#include "miniwin/miniwindevice.h"
#include <SDL3/SDL.h>
struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl<IDirect3DRMDevice2> {
struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl<IDirect3DRMDevice2>, public IDirect3DRMMiniwinDevice {
Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer);
~Direct3DRMDevice2Impl() override;
HRESULT QueryInterface(const GUID& riid, void** ppvObject) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
HRESULT SetBufferCount(int count) override;
@ -30,6 +32,10 @@ struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl<IDirect3DRMDevice
HRESULT AddViewport(IDirect3DRMViewport* viewport) override;
HRESULT GetViewports(IDirect3DRMViewportArray** ppViewportArray) override;
// IDirect3DRMMiniwinDevice interface
float GetShininessFactor() override;
HRESULT SetShininessFactor(float factor) override;
Direct3DRMRenderer* m_renderer;
private:

View File

@ -6,19 +6,20 @@
#include <vector>
struct MeshGroup {
D3DCOLOR color = 0xFFFFFFFF;
SDL_Color color = {0xFF, 0xFF, 0xFF, 0xFF};
IDirect3DRMTexture* texture = nullptr;
IDirect3DRMMaterial* material = nullptr;
D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD;
int vertexPerFace = 0;
int version = 0;
std::vector<D3DRMVERTEX> vertices;
std::vector<unsigned int> faces;
std::vector<unsigned int> indices;
MeshGroup() = default;
MeshGroup(const MeshGroup& other)
: color(other.color), texture(other.texture), material(other.material), quality(other.quality),
vertexPerFace(other.vertexPerFace), vertices(std::move(other.vertices)), faces(std::move(other.faces))
vertexPerFace(other.vertexPerFace), vertices(std::move(other.vertices)), indices(std::move(other.indices))
{
if (texture) {
texture->AddRef();
@ -31,7 +32,7 @@ struct MeshGroup {
// Move constructor
MeshGroup(MeshGroup&& other) noexcept
: color(other.color), texture(other.texture), material(other.material), quality(other.quality),
vertexPerFace(other.vertexPerFace), vertices(other.vertices), faces(other.faces)
vertexPerFace(other.vertexPerFace), vertices(other.vertices), indices(other.indices)
{
other.texture = nullptr;
other.material = nullptr;
@ -46,7 +47,7 @@ struct MeshGroup {
quality = other.quality;
vertexPerFace = other.vertexPerFace;
vertices = std::move(other.vertices);
faces = std::move(other.faces);
indices = std::move(other.indices);
other.texture = nullptr;
other.material = nullptr;
return *this;
@ -73,9 +74,10 @@ struct Direct3DRMMeshImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMMesh> {
DWORD* vertexCount,
DWORD* faceCount,
DWORD* vertexPerFace,
DWORD* dataSize,
DWORD* data
DWORD* indexCount,
DWORD* indices
) override;
const MeshGroup& GetGroup(DWORD groupIndex);
DWORD GetGroupCount() override;
HRESULT SetGroupColor(DWORD groupIndex, D3DCOLOR color) override;
HRESULT SetGroupColorRGB(DWORD groupIndex, float r, float g, float b) override;

View File

@ -1,27 +1,21 @@
#pragma once
#include "d3drmmesh_impl.h"
#include "mathutils.h"
#include "miniwin/d3drm.h"
#include "miniwin/miniwindevice.h"
#include <SDL3/SDL.h>
#define NO_TEXTURE_ID 0xffffffff
struct TexCoord {
float u, v;
};
struct GeometryVertex {
D3DVECTOR position;
D3DVECTOR normals;
TexCoord texCoord;
};
static_assert(sizeof(GeometryVertex) == 32);
static_assert(sizeof(D3DRMVERTEX) == 32);
struct Appearance {
SDL_Color color;
float shininess;
Uint32 textureId;
Uint32 flat;
};
struct FColor {
@ -42,17 +36,30 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
virtual void PushLights(const SceneLight* vertices, size_t count) = 0;
virtual void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) = 0;
virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0;
virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0;
virtual DWORD GetWidth() = 0;
virtual DWORD GetHeight() = 0;
virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0;
virtual const char* GetName() = 0;
virtual HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) = 0;
virtual void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) = 0;
virtual HRESULT FinalizeFrame() = 0;
float GetShininessFactor() { return m_shininessFactor; }
HRESULT SetShininessFactor(float factor)
{
if (factor < 0.f) {
return DDERR_GENERIC;
}
m_shininessFactor = factor;
return DD_OK;
}
protected:
float m_shininessFactor = 1.f;
};

View File

@ -8,7 +8,7 @@
#include <SDL3/SDL.h>
#include <vector>
DEFINE_GUID(OPENGL15_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03);
DEFINE_GUID(OpenGL1_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03);
struct GLTextureCacheEntry {
IDirect3DRMTexture* texture;
@ -16,22 +16,40 @@ struct GLTextureCacheEntry {
GLuint glTextureId;
};
class OpenGL15Renderer : public Direct3DRMRenderer {
struct GLMeshCacheEntry {
const MeshGroup* meshGroup;
int version;
bool flat;
// non-VBO cache
std::vector<D3DVECTOR> positions;
std::vector<D3DVECTOR> normals;
std::vector<TexCoord> texcoords;
std::vector<DWORD> indices;
// VBO cache
GLuint vboPositions;
GLuint vboNormals;
GLuint vboTexcoords;
GLuint ibo;
};
class OpenGL1Renderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
OpenGL15Renderer(int width, int height, SDL_GLContext context, GLuint fbo, GLuint colorTex, GLuint depthRb);
~OpenGL15Renderer() override;
OpenGL1Renderer(int width, int height, SDL_GLContext context, GLuint fbo, GLuint colorTex, GLuint depthRb);
~OpenGL1Renderer() override;
void PushLights(const SceneLight* lightsArray, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) 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(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -40,11 +58,14 @@ class OpenGL15Renderer : public Direct3DRMRenderer {
private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
std::vector<GLTextureCacheEntry> m_textures;
std::vector<GLMeshCacheEntry> m_meshs;
D3DRMMATRIX4D m_viewMatrix;
D3DRMMATRIX4D m_projection;
SDL_Surface* m_renderedImage;
int m_width, m_height;
bool m_useVBOs;
std::vector<SceneLight> m_lights;
SDL_GLContext m_context;
GLuint m_fbo = 0;
@ -52,11 +73,11 @@ class OpenGL15Renderer : public Direct3DRMRenderer {
GLuint m_depthRb = 0;
};
inline static void OpenGL15Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
inline static void OpenGL1Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
Direct3DRMRenderer* device = OpenGL15Renderer::Create(640, 480);
Direct3DRMRenderer* device = OpenGL1Renderer::Create(640, 480);
if (device) {
EnumDevice(cb, ctx, device, OPENGL15_GUID);
EnumDevice(cb, ctx, device, OpenGL1_GUID);
delete device;
}
}

View File

@ -1,35 +1,54 @@
#pragma once
#include "d3drmrenderer.h"
#include "d3drmtexture_impl.h"
#include "ddraw_impl.h"
#include "ddsurface_impl.h"
#include <SDL3/SDL.h>
#include <vector>
DEFINE_GUID(SDL3_GPU_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
typedef struct {
D3DRMMATRIX4D projection;
D3DRMMATRIX4D worldViewMatrix;
D3DRMMATRIX4D normalMatrix;
} ViewportUniforms;
static_assert(sizeof(ViewportUniforms) % 16 == 0);
static_assert(sizeof(ViewportUniforms) == 128);
static_assert(sizeof(ViewportUniforms) == 192);
struct FragmentShadingData {
SceneLight lights[3];
int lightCount;
float shininess;
SDL_Color color;
int padding1[1];
int useTexture;
};
static_assert(sizeof(FragmentShadingData) % 16 == 0);
static_assert(sizeof(FragmentShadingData) == 160);
struct SDL3TextureCache {
Direct3DRMTextureImpl* texture;
Uint32 version;
SDL_GPUTexture* gpuTexture;
};
struct SDL3MeshCache {
const MeshGroup* meshGroup;
int version;
SDL_GPUBuffer* vertexBuffer;
SDL_GPUBuffer* indexBuffer;
size_t indexCount;
};
class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
~Direct3DRMSDL3GPURenderer() 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;
DWORD GetWidth() override;
DWORD GetHeight() override;
@ -37,8 +56,7 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
const char* GetName() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -54,28 +72,41 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUTransferBuffer* downloadTransferBuffer
SDL_GPUSampler* sampler,
SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer
);
HRESULT Blit();
void WaitForPendingUpload();
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
SDL_GPUTransferBuffer* GetUploadBuffer(size_t size);
SDL_GPUTexture* CreateTextureFromSurface(SDL_Surface* surface);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
SDL3MeshCache UploadMesh(const MeshGroup& meshGroup);
DWORD m_width;
DWORD m_height;
D3DVALUE m_front;
D3DVALUE m_back;
int m_vertexCount;
int m_vertexBufferCount = 0;
ViewportUniforms m_uniforms;
FragmentShadingData m_fragmentShadingData;
D3DDEVICEDESC m_desc;
D3DRMMATRIX4D m_viewMatrix;
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_GPUTransferBuffer* m_downloadTransferBuffer;
SDL_GPUTexture* m_dummyTexture;
int m_uploadBufferSize;
SDL_GPUTransferBuffer* m_uploadBuffer;
SDL_GPUTransferBuffer* m_downloadBuffer;
SDL_GPUBuffer* m_vertexBuffer = nullptr;
SDL_Surface* m_renderedImage = nullptr;
SDL_GPUSampler* m_sampler;
SDL_GPUCommandBuffer* m_cmdbuf = nullptr;
SDL_GPURenderPass* m_renderPass = nullptr;
SDL_GPUFence* m_uploadFence = nullptr;
};
inline static void Direct3DRMSDL3GPU_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)

View File

@ -16,11 +16,20 @@ struct TextureCache {
SDL_Surface* cached;
};
struct MeshCache {
const MeshGroup* meshGroup;
int version;
bool flat;
std::vector<D3DRMVERTEX> vertices;
std::vector<DWORD> indices;
};
class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
public:
Direct3DRMSoftwareRenderer(DWORD width, DWORD height);
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;
DWORD GetWidth() override;
DWORD GetHeight() override;
@ -28,8 +37,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
const char* GetName() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -39,16 +47,17 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
private:
void ClearZBuffer();
void DrawTriangleProjected(
const GeometryVertex& v0,
const GeometryVertex& v1,
const GeometryVertex& v2,
const D3DRMVERTEX& v0,
const D3DRMVERTEX& v1,
const D3DRMVERTEX& v2,
const Appearance& appearance
);
void DrawTriangleClipped(const GeometryVertex (&v)[3], const Appearance& appearance);
void ProjectVertex(const GeometryVertex& v, D3DRMVECTOR4D& p) const;
void DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance);
void ProjectVertex(const D3DRMVERTEX& v, D3DRMVECTOR4D& p) const;
void BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
SDL_Color ApplyLighting(const GeometryVertex& vertex, const Appearance& appearance);
SDL_Color ApplyLighting(const D3DVECTOR& position, const D3DVECTOR& normal, const Appearance& appearance);
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
DWORD m_width;
DWORD m_height;
@ -57,6 +66,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
int m_bytesPerPixel;
std::vector<SceneLight> m_lights;
std::vector<TextureCache> m_textures;
std::vector<MeshCache> m_meshs;
D3DVALUE m_front;
D3DVALUE m_back;
D3DRMMATRIX4D m_viewMatrix;

View File

@ -37,13 +37,7 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMViewp
private:
HRESULT RenderScene();
void CollectLightsFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix, std::vector<SceneLight>& lights);
void CollectMeshesFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix,
std::vector<GeometryVertex>& verts,
std::vector<D3DRMVERTEX>& d3dVerts,
std::vector<DWORD>& faces
);
void CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix);
void UpdateProjectionMatrix();
Direct3DRMRenderer* m_renderer;
D3DCOLOR m_backgroundColor = 0xFF000000;

View File

@ -25,6 +25,11 @@ inline D3DVECTOR Normalize(const D3DVECTOR& v)
return {0, 0, 0};
}
inline D3DVECTOR CrossProduct(const D3DVECTOR& a, const D3DVECTOR& b)
{
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
inline D3DVECTOR TransformPoint(const D3DVECTOR& p, const D3DRMMATRIX4D& m)
{
return {

View File

@ -0,0 +1,77 @@
#include "meshutils.h"
#include "mathutils.h"
#include <tuple>
#include <unordered_map>
bool operator==(const D3DRMVERTEX& a, const D3DRMVERTEX& b)
{
return memcmp(&a, &b, sizeof(D3DRMVERTEX)) == 0;
}
namespace std
{
template <>
struct hash<D3DRMVERTEX> {
size_t operator()(const D3DRMVERTEX& v) const
{
const float* f = reinterpret_cast<const float*>(&v);
size_t h = 0;
for (int i = 0; i < sizeof(D3DRMVERTEX) / sizeof(float); ++i) {
h ^= std::hash<float>()(f[i]) + 0x9e3779b9 + (h << 6) + (h >> 2);
}
return h;
}
};
} // namespace std
D3DVECTOR ComputeTriangleNormal(const D3DVECTOR& v0, const D3DVECTOR& v1, const D3DVECTOR& v2)
{
D3DVECTOR u = {v1.x - v0.x, v1.y - v0.y, v1.z - v0.z};
D3DVECTOR v = {v2.x - v0.x, v2.y - v0.y, v2.z - v0.z};
D3DVECTOR normal = CrossProduct(u, v);
normal = Normalize(normal);
return normal;
}
void FlattenSurfaces(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
bool hasTexture,
std::vector<D3DRMVERTEX>& dedupedVertices,
std::vector<DWORD>& newIndices
)
{
std::unordered_map<D3DRMVERTEX, DWORD> uniqueVertexMap;
dedupedVertices.reserve(vertexCount);
newIndices.reserve(indexCount);
for (size_t i = 0; i < indexCount; i += 3) {
D3DRMVERTEX v0 = vertices[indices[i + 0]];
D3DRMVERTEX v1 = vertices[indices[i + 1]];
D3DRMVERTEX v2 = vertices[indices[i + 2]];
v0.normal = v1.normal = v2.normal = ComputeTriangleNormal(v0.position, v1.position, v2.position);
if (!hasTexture) {
v0.texCoord = v1.texCoord = v2.texCoord = {0.0f, 0.0f};
}
// Deduplicate vertecies
for (const D3DRMVERTEX& v : {v0, v1, v2}) {
auto it = uniqueVertexMap.find(v);
if (it != uniqueVertexMap.end()) {
newIndices.push_back(it->second);
}
else {
DWORD newIndex = static_cast<DWORD>(dedupedVertices.size());
uniqueVertexMap[v] = newIndex;
dedupedVertices.push_back(v);
newIndices.push_back(newIndex);
}
}
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "miniwin/d3drm.h"
#include <vector>
void FlattenSurfaces(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
bool hasTexture,
std::vector<D3DRMVERTEX>& dedupedVertices,
std::vector<DWORD>& newIndices
);