diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1187683e..aabbf0fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,7 @@ jobs: matrix: case: - { name: 'Windows (DirectX 9)', os: 'windows-latest', platform: 'D3D9' } + - { name: 'Windows (DirectX 11)', os: 'windows-latest', platform: 'D3D11' } - { name: 'Windows (GL3, glfw)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'GLFW' } - { name: 'Windows (GL3, SDL2)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'SDL2', sdl-version: '2-latest' } - { name: 'Windows (GL3, SDL3)', os: 'windows-latest', platform: 'GL3', gl3_gfxlib: 'SDL3', sdl-version: '3-latest' } diff --git a/.gitignore b/.gitignore index de870ed2..9f4a632c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,47 @@ -/bin -/build -/obj -/lib -/output -/.vs -librw.vcxproj.user -librw.VC.db -librw.VC.VC.opendb +/bin +/build +/build-*/ +/obj +/lib +/output +/.vs + +# CMake generated files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +install_manifest.txt +CTestTestfile.cmake +Testing/ +_deps/ + +# Visual Studio and MSVC build artifacts +*.obj +*.o +*.pch +*.pdb +*.ipch +*.ilk +*.idb +*.tlog +*.recipe +*.lastbuildstate +*.suo +*.user +*.VC.db +*.VC.opendb +*.vsidx + +# Compiled binaries and shader output +*.bin +*.cso +*.exe +*.dll +*.lib +*.exp + +librw.vcxproj.user +librw.VC.db +librw.VC.VC.opendb imgui.ini +/glfw diff --git a/CMakeLists.txt b/CMakeLists.txt index 92e57960..6ec2e687 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set(librw_AUTHOR aap) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") if(WIN32) - set(LIBRW_PLATFORMS "NULL" "GL3" "D3D9") + set(LIBRW_PLATFORMS "NULL" "GL3" "D3D9" "D3D11") set(LIBRW_PLATFORM_GL3_REQUIRES_OPENGL ON) elseif(NINTENDO_SWITCH) set(LIBRW_PLATFORMS "NULL" "GL3") @@ -134,6 +134,8 @@ if(LIBRW_INSTALL) endif() elseif(LIBRW_PLATFORM_D3D9) set(platform "-d3d9") + elseif(LIBRW_PLATFORM_D3D11) + set(platform "-d3d11") endif() if(NOT LIBRW_PLATFORM_PS2) if(WIN32) diff --git a/cmake/ShaderSource.h.in b/cmake/ShaderSource.h.in new file mode 100644 index 00000000..64eff4b9 --- /dev/null +++ b/cmake/ShaderSource.h.in @@ -0,0 +1,3 @@ +static const char @SHADER_VARIABLE@[] = R"librw_shader( +@SHADER_SOURCE@ +)librw_shader"; diff --git a/premake5.lua b/premake5.lua index 0cb4afa2..4e5bbc4a 100755 --- a/premake5.lua +++ b/premake5.lua @@ -38,6 +38,42 @@ newoption { default = "../SDL3-3.2.22", } +local d3d11Shaders = { + "clear_VS_d11", + "clear_PS_d11", + "im2d_VS_d11", + "im2d_PS_d11", + "im3d_VS_d11", + "im3d_PS_d11", + "im3d_tex_PS_d11", + "default_VS_d11", + "default_PS_d11", + "skin_VS_d11", + "matfx_env_VS_d11", + "matfx_env_PS_d11", +} + +local d3d11GeneratedDir = path.join(_SCRIPT_DIR, "build/generated") + +local function generateD3D11ShaderHeaders() + os.mkdir(d3d11GeneratedDir) + for _, shaderName in ipairs(d3d11Shaders) do + local input = assert(io.open(path.join( + _SCRIPT_DIR, "src/d3d/shaders", shaderName .. ".hlsl"), "rb")) + local source = input:read("*all") + input:close() + + local output = assert(io.open(path.join( + d3d11GeneratedDir, shaderName .. ".h"), "wb")) + output:write("static const char ", shaderName, + "_source[] = R\"librw_shader(\n", source, + "\n)librw_shader\";\n") + output:close() + end +end + +generateD3D11ShaderHeaders() + workspace "librw" location "build" language "C++" @@ -45,8 +81,8 @@ workspace "librw" configurations { "Release", "Debug" } filter { "system:windows" } configurations { "ReleaseStatic" } - platforms { "win-x86-null", "win-x86-gl3", "win-x86-d3d9", - "win-amd64-null", "win-amd64-gl3", "win-amd64-d3d9" } + platforms { "win-x86-null", "win-x86-gl3", "win-x86-d3d9", "win-x86-d3d11", + "win-amd64-null", "win-amd64-gl3", "win-amd64-d3d9", "win-amd64-d3d11" } filter { "system:linux" } platforms { "linux-x86-null", "linux-x86-gl3", "linux-amd64-null", "linux-amd64-gl3", @@ -79,6 +115,8 @@ workspace "librw" end filter { "platforms:*d3d9" } defines { "RW_D3D9" } + filter { "platforms:*d3d11" } + defines { "RW_D3D11" } filter { "platforms:ps2" } defines { "RW_PS2" } toolset "gcc" @@ -128,11 +166,17 @@ project "librw" files { "src/*/*.*" } filter { "platforms:*gl3" } files { "src/gl/glad/*.*" } + filter { "platforms:*d3d11" } + includedirs { d3d11GeneratedDir } + files { "src/d3d/shaders/*_d11.hlsl" } + filter { "files:**.hlsl" } + buildaction "None" + filter {} project "dumprwtree" kind "ConsoleApp" targetdir (Bindir) - removeplatforms { "*gl3", "*d3d9", "ps2" } + removeplatforms { "*gl3", "*d3d9", "*d3d11", "ps2" } files { "tools/dumprwtree/*" } includedirs { "." } libdirs { Libdir } @@ -169,6 +213,10 @@ function findlibs() links { "gdi32", "d3d9" } filter { "platforms:*d3d9", "action:vs*" } links { "Xinput9_1_0" } + filter { "platforms:*d3d11" } + links { "gdi32", "d3d11", "dxgi", "d3dcompiler" } + filter { "platforms:*d3d11", "action:vs*" } + links { "Xinput9_1_0" } filter {} end @@ -270,13 +318,13 @@ project "ska2anm" libdirs { Libdir } links { "librw" } findlibs() - removeplatforms { "*gl3", "*d3d9", "*ps2" } + removeplatforms { "*gl3", "*d3d9", "*d3d11", "*ps2" } project "ps2test" kind "ConsoleApp" targetdir (Bindir) vucode() - removeplatforms { "*gl3", "*d3d9", "*null" } + removeplatforms { "*gl3", "*d3d9", "*d3d11", "*null" } targetextension '.elf' includedirs { "." } files { "tools/ps2test/*.cpp", diff --git a/rw.h b/rw.h index fb9829f4..06d94061 100644 --- a/rw.h +++ b/rw.h @@ -19,6 +19,7 @@ #include "src/d3d/rwd3d.h" #include "src/d3d/rwd3d8.h" #include "src/d3d/rwd3d9.h" +#include "src/d3d/rwd3d11.h" #include "src/gl/rwwdgl.h" #include "src/gl/rwgl3.h" #include "src/gl/rwgl3shader.h" diff --git a/skeleton/win.cpp b/skeleton/win.cpp index a2b50ed9..069ba967 100644 --- a/skeleton/win.cpp +++ b/skeleton/win.cpp @@ -6,7 +6,7 @@ using namespace sk; using namespace rw; -#ifdef RW_D3D9 +#if defined(RW_D3D9) || defined(RW_D3D11) #ifndef VK_OEM_NEC_EQUAL #define VK_OEM_NEC_EQUAL 0x92 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9143b71..f3689c78 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,12 @@ add_library(librw d3d/d3ddevice.cpp d3d/d3dimmed.cpp d3d/d3drender.cpp + d3d/d3d11.cpp + d3d/d3d11device.cpp + d3d/d3d11matfx.cpp + d3d/d3d11skin.cpp + d3d/d3d11render.cpp + d3d/rwd3d11.h d3d/rwd3d8.h d3d/rwd3d9.h d3d/rwd3d.h @@ -97,6 +103,48 @@ add_library(librw ) add_library(librw::librw ALIAS librw) +if(LIBRW_PLATFORM_D3D11) + set(D3D11_SHADER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/d3d/shaders") + set(D3D11_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") + file(MAKE_DIRECTORY "${D3D11_GENERATED_DIR}") + + set(D3D11_SHADERS + clear_VS_d11 + clear_PS_d11 + im2d_VS_d11 + im2d_PS_d11 + im3d_VS_d11 + im3d_PS_d11 + im3d_tex_PS_d11 + default_VS_d11 + default_PS_d11 + skin_VS_d11 + matfx_env_VS_d11 + matfx_env_PS_d11 + ) + + foreach(SHADER_NAME IN LISTS D3D11_SHADERS) + set(SHADER_PATH "${D3D11_SHADER_DIR}/${SHADER_NAME}.hlsl") + list(APPEND D3D11_SHADER_SOURCES "${SHADER_PATH}") + file(READ "${SHADER_PATH}" SHADER_SOURCE) + set(SHADER_VARIABLE "${SHADER_NAME}_source") + configure_file( + "${PROJECT_SOURCE_DIR}/cmake/ShaderSource.h.in" + "${D3D11_GENERATED_DIR}/${SHADER_NAME}.h" + @ONLY + ) + endforeach() + + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS + ${D3D11_SHADER_SOURCES} + ) + target_sources(librw PRIVATE ${D3D11_SHADER_SOURCES}) + set_source_files_properties(${D3D11_SHADER_SOURCES} + PROPERTIES HEADER_FILE_ONLY TRUE + ) + target_include_directories(librw PRIVATE "${D3D11_GENERATED_DIR}") +endif() + target_include_directories(librw INTERFACE $ @@ -205,6 +253,14 @@ elseif(LIBRW_PLATFORM_D3D9) d3d9 xinput ) +elseif(LIBRW_PLATFORM_D3D11) + target_link_libraries(librw + PRIVATE + d3d11 + dxgi + d3dcompiler + xinput + ) endif() if(LIBRW_INSTALL) @@ -236,6 +292,7 @@ if(LIBRW_INSTALL) d3d/rwd3d.h d3d/rwd3d8.h d3d/rwd3d9.h + d3d/rwd3d11.h DESTINATION "${LIBRW_INSTALL_INCLUDEDIR}/src/d3d" ) install( diff --git a/src/base.cpp b/src/base.cpp index 3c3ca08c..982b1abd 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -31,6 +31,8 @@ int32 build = 0xFFFF; int32 platform = PLATFORM_WDGL; #elif RW_GL3 int32 platform = PLATFORM_GL3; +#elif RW_D3D11 + int32 platform = PLATFORM_D3D11; #elif RW_D3D9 int32 platform = PLATFORM_D3D9; #else diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp index f1f5f49e..e72761ba 100644 --- a/src/d3d/d3d.cpp +++ b/src/d3d/d3d.cpp @@ -11,1077 +11,1302 @@ #include "../rwobjects.h" #include "../rwengine.h" #include "rwd3d.h" +#include "rwd3d11.h" #include "rwd3dimpl.h" #define PLUGIN_ID ID_DRIVER -namespace rw { -namespace d3d { - -bool32 isP8supported = 1; // set to 0 when actual d3d device is used - -// stolen from d3d8to9 -static uint32 -calculateTextureSize(uint32 width, uint32 height, uint32 depth, uint32 format) -{ -#define D3DFMT_W11V11U10 65 - switch(format){ - default: - case D3DFMT_UNKNOWN: - return 0; - case D3DFMT_R3G3B2: - case D3DFMT_A8: - case D3DFMT_P8: - case D3DFMT_L8: - case D3DFMT_A4L4: - return width * height * depth; - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: - case D3DFMT_A1R5G5B5: - case D3DFMT_A4R4G4B4: - case D3DFMT_A8R3G3B2: - case D3DFMT_X4R4G4B4: - case D3DFMT_A8P8: - case D3DFMT_A8L8: - case D3DFMT_V8U8: - case D3DFMT_L6V5U5: - case D3DFMT_D16_LOCKABLE: - case D3DFMT_D15S1: - case D3DFMT_D16: - case D3DFMT_UYVY: - case D3DFMT_YUY2: - return width * 2 * height * depth; - case D3DFMT_R8G8B8: - return width * 3 * height * depth; - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: - case D3DFMT_A2B10G10R10: - case D3DFMT_A8B8G8R8: - case D3DFMT_X8B8G8R8: - case D3DFMT_G16R16: - case D3DFMT_X8L8V8U8: - case D3DFMT_Q8W8V8U8: - case D3DFMT_V16U16: - case D3DFMT_W11V11U10: - case D3DFMT_A2W10V10U10: - case D3DFMT_D32: - case D3DFMT_D24S8: - case D3DFMT_D24X8: - case D3DFMT_D24X4S4: - return width * 4 * height * depth; - case D3DFMT_DXT1: - assert(depth <= 1); - return ((width + 3) >> 2) * ((height + 3) >> 2) * 8; - case D3DFMT_DXT2: - case D3DFMT_DXT3: - case D3DFMT_DXT4: - case D3DFMT_DXT5: - assert(depth <= 1); - return ((width + 3) >> 2) * ((height + 3) >> 2) * 16; - } -} - -int vertFormatMap[] = { - -1, VERT_FLOAT2, VERT_FLOAT3, VERT_FLOAT4, VERT_ARGB, VERT_RGBA /* blend indices */ -}; - -void* -createIndexBuffer(uint32 length, bool dynamic) -{ -#ifdef RW_D3D9 - IDirect3DIndexBuffer9 *ibuf; - if(dynamic) - d3ddevice->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &ibuf, 0); - else - d3ddevice->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ibuf, 0); - if(ibuf) - d3d9Globals.numIndexBuffers++; - return ibuf; -#else - return rwNewT(uint8, length, MEMDUR_EVENT | ID_DRIVER); -#endif -} - -void -destroyIndexBuffer(void *indexBuffer) -{ -#ifdef RW_D3D9 - if(indexBuffer){ - if(((IUnknown*)indexBuffer)->Release() != 0) - printf("indexBuffer wasn't destroyed\n"); - d3d9Globals.numIndexBuffers--; - } -#else - rwFree(indexBuffer); -#endif -} - -uint16* -lockIndices(void *indexBuffer, uint32 offset, uint32 size, uint32 flags) -{ - if(indexBuffer == nil) - return nil; -#ifdef RW_D3D9 - uint16 *indices; - IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9*)indexBuffer; - ibuf->Lock(offset, size, (void**)&indices, flags); - return indices; -#else - (void)offset; - (void)size; - (void)flags; - return (uint16*)indexBuffer; -#endif -} - -void -unlockIndices(void *indexBuffer) -{ - if(indexBuffer == nil) - return; -#ifdef RW_D3D9 - IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9*)indexBuffer; - ibuf->Unlock(); -#endif -} - -void* -createVertexBuffer(uint32 length, uint32 fvf, bool dynamic) +namespace rw { -#ifdef RW_D3D9 - IDirect3DVertexBuffer9 *vbuf; - if(dynamic) - d3ddevice->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC, fvf, D3DPOOL_DEFAULT, &vbuf, 0); - else - d3ddevice->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY, fvf, D3DPOOL_MANAGED, &vbuf, 0); - if(vbuf) - d3d9Globals.numVertexBuffers++; - return vbuf; -#else - (void)fvf; - return rwNewT(uint8, length, MEMDUR_EVENT | ID_DRIVER); -#endif -} - -void -destroyVertexBuffer(void *vertexBuffer) -{ -#ifdef RW_D3D9 - if(vertexBuffer){ - if(((IUnknown*)vertexBuffer)->Release() != 0) - printf("vertexBuffer wasn't destroyed\n"); - d3d9Globals.numVertexBuffers--; - } -#else - rwFree(vertexBuffer); -#endif -} - -uint8* -lockVertices(void *vertexBuffer, uint32 offset, uint32 size, uint32 flags) -{ - if(vertexBuffer == nil) - return nil; -#ifdef RW_D3D9 - uint8 *verts; - IDirect3DVertexBuffer9 *vertbuf = (IDirect3DVertexBuffer9*)vertexBuffer; - vertbuf->Lock(offset, size, (void**)&verts, flags); - return verts; -#else - (void)offset; - (void)size; - (void)flags; - return (uint8*)vertexBuffer; -#endif -} - -void -unlockVertices(void *vertexBuffer) -{ - if(vertexBuffer == nil) - return; -#ifdef RW_D3D9 - IDirect3DVertexBuffer9 *vertbuf = (IDirect3DVertexBuffer9*)vertexBuffer; - vertbuf->Unlock(); -#endif -} + namespace d3d + { + + bool32 isP8supported = 1; // set to 0 when actual d3d device is used + + // stolen from d3d8to9 + static uint32 + calculateTextureSize( uint32 width, uint32 height, uint32 depth, uint32 format ) + { + #define D3DFMT_W11V11U10 65 + switch( format ) + { + default: + case D3DFMT_UNKNOWN: + return 0; + case D3DFMT_R3G3B2: + case D3DFMT_A8: + case D3DFMT_P8: + case D3DFMT_L8: + case D3DFMT_A4L4: + return width * height * depth; + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: + case D3DFMT_A8R3G3B2: + case D3DFMT_X4R4G4B4: + case D3DFMT_A8P8: + case D3DFMT_A8L8: + case D3DFMT_V8U8: + case D3DFMT_L6V5U5: + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D15S1: + case D3DFMT_D16: + case D3DFMT_UYVY: + case D3DFMT_YUY2: + return width * 2 * height * depth; + case D3DFMT_R8G8B8: + return width * 3 * height * depth; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A2B10G10R10: + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: + case D3DFMT_G16R16: + case D3DFMT_X8L8V8U8: + case D3DFMT_Q8W8V8U8: + case D3DFMT_V16U16: + case D3DFMT_W11V11U10: + case D3DFMT_A2W10V10U10: + case D3DFMT_D32: + case D3DFMT_D24S8: + case D3DFMT_D24X8: + case D3DFMT_D24X4S4: + return width * 4 * height * depth; + case D3DFMT_DXT1: + assert( depth <= 1 ); + return ((width + 3) >> 2) * ((height + 3) >> 2) * 8; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + assert( depth <= 1 ); + return ((width + 3) >> 2) * ((height + 3) >> 2) * 16; + } + } -void* -createTexture(int32 width, int32 height, int32 numlevels, uint32 usage, uint32 format) -{ -#ifdef RW_D3D9 - IDirect3DTexture9 *tex; - d3ddevice->CreateTexture(width, height, numlevels, usage, - (D3DFORMAT)format, D3DPOOL_MANAGED, &tex, nil); - if(tex) - d3d9Globals.numTextures++; - return tex; -#else - int32 w = width; - int32 h = height; - int32 size = 0; - for(int32 i = 0; i < numlevels; i++){ - size += calculateTextureSize(w, h, 1, format); - w /= 2; - if(w == 0) w = 1; - h /= 2; - if(h == 0) h = 1; - } - uint8 *data = (uint8*)rwNew(sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1)+size, - MEMDUR_EVENT | ID_DRIVER); - RasterLevels *levels = (RasterLevels*)data; - data += sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1); - levels->numlevels = numlevels; - levels->format = format; - w = width; - h = height; - for(int32 i = 0; i < numlevels; i++){ - levels->levels[i].width = w; - levels->levels[i].height = h; - levels->levels[i].data = data; - levels->levels[i].size = calculateTextureSize(w, h, 1, format); - data += levels->levels[i].size; - w /= 2; - if(w == 0) w = 1; - h /= 2; - if(h == 0) h = 1; - } - return levels; -#endif -} + int vertFormatMap[] = { + -1, VERT_FLOAT2, VERT_FLOAT3, VERT_FLOAT4, VERT_ARGB, VERT_RGBA /* blend indices */ + }; + + #ifdef RW_D3D11 + //This type contains the old D3D9 index buffer behaviour without dynamic buffers. It has a CPU shadow and uploads to the GPU buffer on unlock. + struct D3d11IndexBuffer + { + ID3D11Buffer* gpuBuffer; + uint8* cpuData; + uint32 length; + bool dynamic; + }; + + struct D3d11VertexBuffer + { + ID3D11Buffer* gpuBuffer; + uint8* cpuData; + uint32 length; + bool dynamic; + }; + #endif + + void* + createIndexBuffer( uint32 length, bool dynamic ) + { + #ifdef RW_D3D9 + IDirect3DIndexBuffer9* ibuf; + if( dynamic ) + d3ddevice->CreateIndexBuffer( length, D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &ibuf, 0 ); + else + d3ddevice->CreateIndexBuffer( length, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ibuf, 0 ); + if( ibuf ) + d3d9Globals.numIndexBuffers++; + return ibuf; + #elif defined(RW_D3D11) + if( length == 0 ) + return nil; + + D3d11IndexBuffer* indexBuffer = rwNewT( D3d11IndexBuffer, 1, + MEMDUR_EVENT | ID_DRIVER ); + memset( indexBuffer, 0, sizeof( *indexBuffer ) ); + indexBuffer->length = length; + indexBuffer->dynamic = dynamic; + + D3D11_BUFFER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = length; + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + if( dynamic ) + { + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } + else + { + // D3D11 has no D3DPOOL_MANAGED. Keep its CPU shadow ourselves and + // upload it from unlockIndices() to a normal GPU buffer. + desc.Usage = D3D11_USAGE_DEFAULT; + indexBuffer->cpuData = rwNewT( uint8, length, MEMDUR_EVENT | ID_DRIVER ); + } + + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &indexBuffer->gpuBuffer ) ) ) + { + rwFree( indexBuffer->cpuData ); + rwFree( indexBuffer ); + return nil; + } + d3d11Globals.numIndexBuffers++; + return indexBuffer; + #else + return rwNewT( uint8, length, MEMDUR_EVENT | ID_DRIVER ); + #endif + } -void -destroyTexture(void *texture) -{ -#ifdef RW_D3D9 - if(texture){ - if(((IUnknown*)texture)->Release() != 0) - printf("texture wasn't destroyed\n"); - d3d9Globals.numTextures--; - } -#else - rwFree(texture); -#endif -} + void + destroyIndexBuffer( void* indexBuffer ) + { + #ifdef RW_D3D9 + if( indexBuffer ) + { + if( (( IUnknown* )indexBuffer)->Release() != 0 ) + printf( "indexBuffer wasn't destroyed\n" ); + d3d9Globals.numIndexBuffers--; + } + #elif defined(RW_D3D11) + if( indexBuffer ) + { + D3d11IndexBuffer* ibuf = ( D3d11IndexBuffer* )indexBuffer; + d3d11::clearIndices( ibuf->gpuBuffer ); + if( ibuf->gpuBuffer->Release() != 0 ) + printf( "indexBuffer wasn't destroyed\n" ); + rwFree( ibuf->cpuData ); + rwFree( ibuf ); + d3d11Globals.numIndexBuffers--; + } + #else + rwFree( indexBuffer ); + #endif + } -// Native Raster + uint16* + lockIndices( void* indexBuffer, uint32 offset, uint32 size, uint32 flags ) + { + if( indexBuffer == nil ) + return nil; + #ifdef RW_D3D9 + uint16* indices; + IDirect3DIndexBuffer9* ibuf = ( IDirect3DIndexBuffer9* )indexBuffer; + ibuf->Lock( offset, size, ( void** )&indices, flags ); + return indices; + #elif defined(RW_D3D11) + D3d11IndexBuffer* ibuf = ( D3d11IndexBuffer* )indexBuffer; + assert( offset <= ibuf->length ); + assert( size == 0 || size <= ibuf->length - offset ); + ( void )flags; + if( !ibuf->dynamic ) + return ( uint16* )(ibuf->cpuData + offset); + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( ibuf->gpuBuffer, 0, + D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return nil; + return ( uint16* )(( uint8* )mapped.pData + offset); + #else + ( void )offset; + ( void )size; + ( void )flags; + return ( uint16* )indexBuffer; + #endif + } -int32 nativeRasterOffset; + void + unlockIndices( void* indexBuffer ) + { + if( indexBuffer == nil ) + return; + #ifdef RW_D3D9 + IDirect3DIndexBuffer9* ibuf = ( IDirect3DIndexBuffer9* )indexBuffer; + ibuf->Unlock(); + #elif defined(RW_D3D11) + D3d11IndexBuffer* ibuf = ( D3d11IndexBuffer* )indexBuffer; + if( ibuf->dynamic ) + d3d11Globals.context->Unmap( ibuf->gpuBuffer, 0 ); + else + d3d11Globals.context->UpdateSubresource( ibuf->gpuBuffer, 0, nil, + ibuf->cpuData, 0, 0 ); + #endif + } -struct RasterFormatInfo -{ - uint32 d3dformat; - int32 depth; - bool32 hasAlpha; - uint32 rwFormat; -}; - -// indexed directly by RW format -static RasterFormatInfo formatInfoRW[16] = { - { 0, 0, 0, 0}, - { D3DFMT_A1R5G5B5, 16, 1, Raster::C1555 }, - { D3DFMT_R5G6B5, 16, 0, Raster::C565 }, - { D3DFMT_A4R4G4B4, 16, 1, Raster::C4444 }, - { D3DFMT_L8, 8, 0, Raster::LUM8 }, - { D3DFMT_A8R8G8B8, 32, 1, Raster::C8888 }, - { D3DFMT_X8R8G8B8, 32, 0, Raster::C888 }, - { D3DFMT_D16, 16, 0, Raster::D16 }, - { D3DFMT_D24X8, 32, 0, Raster::D24 }, - { D3DFMT_D32, 32, 0, Raster::D32 }, - { D3DFMT_X1R5G5B5, 16, 0, Raster::C555 }, -}; - -static RasterFormatInfo formatInfoFull[] = { - { D3DFMT_R8G8B8, 0, 24, 0 }, - { D3DFMT_A8R8G8B8, 1, 32, Raster::C8888 }, - { D3DFMT_X8R8G8B8, 0, 32, Raster::C888 }, - { D3DFMT_R5G6B5, 0, 16, Raster::C565 }, - { D3DFMT_X1R5G5B5, 0, 16, Raster::C555 }, - { D3DFMT_A1R5G5B5, 1, 16, Raster::C1555 }, - { D3DFMT_A4R4G4B4, 1, 16, Raster::C4444 }, - { D3DFMT_R3G3B2, 0, 8, 0 }, - { D3DFMT_A8, 1, 8, 0 }, - { D3DFMT_A8R3G3B2, 1, 16, 0 }, - { D3DFMT_X4R4G4B4, 0, 16, 0 }, - { D3DFMT_A2B10G10R10, 1, 32, 0 }, - { D3DFMT_A8B8G8R8, 1, 32, 0 }, - { D3DFMT_X8B8G8R8, 0, 32, 0 }, - { D3DFMT_G16R16, 0, 32, 0 }, - { D3DFMT_A2R10G10B10, 1, 32, 0 }, - { D3DFMT_A16B16G16R16, 1, 64, 0 }, - { D3DFMT_A8P8, 1, 16, 0 }, -// { D3DFMT_P8, 0, 8, ... }, -// { D3DFMT_L8, 0, 8, ... }, - { D3DFMT_A8L8, 1, 16, 0 }, - { D3DFMT_A4L4, 1, 8, 0 }, - { D3DFMT_V8U8, 0, 16, 0 }, - { D3DFMT_L6V5U5, 0, 16, 0 }, - { D3DFMT_X8L8V8U8, 0, 32, 0 }, - { D3DFMT_Q8W8V8U8, 0, 32, 0 }, - { D3DFMT_V16U16, 0, 32, 0 }, - { D3DFMT_A2W10V10U10, 1, 32, 0 }, - { D3DFMT_D16_LOCKABLE, 0, 16, Raster::D16 }, - { D3DFMT_D32, 0, 32, Raster::D32 }, - { D3DFMT_D15S1, 0, 16, Raster::D16 }, - { D3DFMT_D24S8, 0, 32, Raster::D32 }, - { D3DFMT_D24X8, 0, 32, Raster::D32 }, - { D3DFMT_D24X4S4, 0, 32, Raster::D32 }, - { D3DFMT_D16, 0, 16, Raster::D16 }, - { D3DFMT_D32F_LOCKABLE, 0, 32, Raster::D32 }, - { D3DFMT_D24FS8, 0, 32, Raster::D32 }, - { D3DFMT_L16, 0, 16, 0 }, - { D3DFMT_Q16W16V16U16, 0, 64, 0 }, - { D3DFMT_R16F, 0, 16, 0 }, - { D3DFMT_G16R16F, 0, 32, 0 }, - { D3DFMT_A16B16G16R16F, 1, 64, 0 }, - { D3DFMT_R32F, 0, 32, 0 }, - { D3DFMT_G32R32F, 0, 64, 0 }, - { D3DFMT_A32B32G32R32F, 1, 128, 0 }, - { D3DFMT_CxV8U8, 0, 16, 0 }, -}; - -RasterFormatInfo* -findFormatInfoD3D(uint32 d3dformat) -{ - static RasterFormatInfo fake = { 0, 0, 0, 0 }; - int i; - for(i = 0; i < (int)nelem(formatInfoFull); i++) - if(formatInfoFull[i].d3dformat == d3dformat) - return &formatInfoFull[i]; - return &fake; -} + #ifdef RW_D3D11 + void* + getD3D11IndexBuffer( void* indexBuffer ) + { + if( indexBuffer == nil ) + return nil; + return (( D3d11IndexBuffer* )indexBuffer)->gpuBuffer; + } + #endif + + void* + createVertexBuffer( uint32 length, uint32 fvf, bool dynamic ) + { + #ifdef RW_D3D9 + IDirect3DVertexBuffer9* vbuf; + if( dynamic ) + d3ddevice->CreateVertexBuffer( length, D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, fvf, D3DPOOL_DEFAULT, &vbuf, 0 ); + else + d3ddevice->CreateVertexBuffer( length, D3DUSAGE_WRITEONLY, fvf, D3DPOOL_MANAGED, &vbuf, 0 ); + if( vbuf ) + d3d9Globals.numVertexBuffers++; + return vbuf; + #elif defined(RW_D3D11) + ( void )fvf; + if( length == 0 ) + return nil; + + D3d11VertexBuffer* vertexBuffer = rwNewT( D3d11VertexBuffer, 1, + MEMDUR_EVENT | ID_DRIVER ); + memset( vertexBuffer, 0, sizeof( *vertexBuffer ) ); + vertexBuffer->length = length; + vertexBuffer->dynamic = dynamic; + + D3D11_BUFFER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = length; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + if( dynamic ) + { + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } + else + { + desc.Usage = D3D11_USAGE_DEFAULT; + vertexBuffer->cpuData = rwNewT( uint8, length, MEMDUR_EVENT | ID_DRIVER ); + } + + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &vertexBuffer->gpuBuffer ) ) ) + { + rwFree( vertexBuffer->cpuData ); + rwFree( vertexBuffer ); + return nil; + } + d3d11Globals.numVertexBuffers++; + return vertexBuffer; + #else + ( void )fvf; + return rwNewT( uint8, length, MEMDUR_EVENT | ID_DRIVER ); + #endif + } + void + destroyVertexBuffer( void* vertexBuffer ) + { + #ifdef RW_D3D9 + if( vertexBuffer ) + { + if( (( IUnknown* )vertexBuffer)->Release() != 0 ) + printf( "vertexBuffer wasn't destroyed\n" ); + d3d9Globals.numVertexBuffers--; + } + #elif defined(RW_D3D11) + if( vertexBuffer ) + { + D3d11VertexBuffer* vbuf = ( D3d11VertexBuffer* )vertexBuffer; + d3d11::clearStreamSource( vbuf->gpuBuffer ); + if( vbuf->gpuBuffer->Release() != 0 ) + printf( "vertexBuffer wasn't destroyed\n" ); + rwFree( vbuf->cpuData ); + rwFree( vbuf ); + d3d11Globals.numVertexBuffers--; + } + #else + rwFree( vertexBuffer ); + #endif + } -static void -rasterSetFormat(Raster *raster) -{ - if(raster->format == 0){ - // have to find a format first - // this could perhaps be a bit more intelligent - - switch(raster->type){ - case Raster::NORMAL: - case Raster::TEXTURE: - raster->format = Raster::C8888; - break; - -#ifdef RW_D3D9 - case Raster::ZBUFFER: - // TODO: allow other formats - raster->format = findFormatInfoD3D(d3d9Globals.present.AutoDepthStencilFormat)->rwFormat; - // can this even happen? just do something... - if(raster->format == 0) - raster->format = Raster::D32; - break; - - case Raster::CAMERATEXTURE: -// let's not use this because we apparently don't want alpha -// raster->format = findFormatInfoD3D(d3d9Globals.present.BackBufferFormat)->rwFormat; - raster->format = findFormatInfoD3D(d3d9Globals.startMode.mode.Format)->rwFormat; - // can this even happen? just do something... - if(raster->format == 0) - raster->format = Raster::C888; - break; - case Raster::CAMERA: - raster->format = findFormatInfoD3D(d3d9Globals.present.BackBufferFormat)->rwFormat; - // can this even happen? just do something... - if(raster->format == 0) - raster->format = Raster::C8888; - break; -#endif + uint8* + lockVertices( void* vertexBuffer, uint32 offset, uint32 size, uint32 flags ) + { + if( vertexBuffer == nil ) + return nil; + #ifdef RW_D3D9 + uint8* verts; + IDirect3DVertexBuffer9* vertbuf = ( IDirect3DVertexBuffer9* )vertexBuffer; + vertbuf->Lock( offset, size, ( void** )&verts, flags ); + return verts; + #elif defined(RW_D3D11) + D3d11VertexBuffer* vbuf = ( D3d11VertexBuffer* )vertexBuffer; + assert( offset <= vbuf->length ); + assert( size == 0 || size <= vbuf->length - offset ); + ( void )flags; + if( !vbuf->dynamic ) + return vbuf->cpuData + offset; + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( vbuf->gpuBuffer, 0, + D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return nil; + return ( uint8* )mapped.pData + offset; + #else + ( void )offset; + ( void )size; + ( void )flags; + return ( uint8* )vertexBuffer; + #endif } - } + void + unlockVertices( void* vertexBuffer ) + { + if( vertexBuffer == nil ) + return; + #ifdef RW_D3D9 + IDirect3DVertexBuffer9* vertbuf = ( IDirect3DVertexBuffer9* )vertexBuffer; + vertbuf->Unlock(); + #elif defined(RW_D3D11) + D3d11VertexBuffer* vbuf = ( D3d11VertexBuffer* )vertexBuffer; + if( vbuf->dynamic ) + d3d11Globals.context->Unmap( vbuf->gpuBuffer, 0 ); + else + d3d11Globals.context->UpdateSubresource( vbuf->gpuBuffer, 0, nil, + vbuf->cpuData, 0, 0 ); + #endif + } - D3dRaster *natras = GETD3DRASTEREXT(raster); - if(raster->format & (Raster::PAL4 | Raster::PAL8)){ - // TODO: do we even allow PAL4? - natras->format = D3DFMT_P8; - raster->depth = 8; - }else{ - natras->format = formatInfoRW[(raster->format >> 8) & 0xF].d3dformat; - raster->depth = formatInfoRW[(raster->format >> 8) & 0xF].depth; - } - natras->bpp = raster->depth/8; - natras->hasAlpha = formatInfoRW[(raster->format >> 8) & 0xF].hasAlpha; - raster->stride = raster->width*natras->bpp; + #ifdef RW_D3D11 + void* + getD3D11VertexBuffer( void* vertexBuffer ) + { + if( vertexBuffer == nil ) + return nil; + return (( D3d11VertexBuffer* )vertexBuffer)->gpuBuffer; + } + #endif + + void* + createTexture( int32 width, int32 height, int32 numlevels, uint32 usage, uint32 format ) + { + #ifdef RW_D3D9 + IDirect3DTexture9* tex; + d3ddevice->CreateTexture( width, height, numlevels, usage, + ( D3DFORMAT )format, D3DPOOL_MANAGED, &tex, nil ); + if( tex ) + d3d9Globals.numTextures++; + return tex; + #else + int32 w = width; + int32 h = height; + int32 size = 0; + for( int32 i = 0; i < numlevels; i++ ) + { + size += calculateTextureSize( w, h, 1, format ); + w /= 2; + if( w == 0 ) w = 1; + h /= 2; + if( h == 0 ) h = 1; + } + uint8* data = ( uint8* )rwNew( sizeof( RasterLevels ) + sizeof( RasterLevels::Level ) * (numlevels - 1) + size, + MEMDUR_EVENT | ID_DRIVER ); + RasterLevels* levels = ( RasterLevels* )data; + data += sizeof( RasterLevels ) + sizeof( RasterLevels::Level ) * (numlevels - 1); + levels->numlevels = numlevels; + levels->format = format; + w = width; + h = height; + for( int32 i = 0; i < numlevels; i++ ) + { + levels->levels[ i ].width = w; + levels->levels[ i ].height = h; + levels->levels[ i ].data = data; + levels->levels[ i ].size = calculateTextureSize( w, h, 1, format ); + data += levels->levels[ i ].size; + w /= 2; + if( w == 0 ) w = 1; + h /= 2; + if( h == 0 ) h = 1; + } + return levels; + #endif + } - natras->autogenMipmap = (raster->format & (Raster::MIPMAP|Raster::AUTOMIPMAP)) == (Raster::MIPMAP|Raster::AUTOMIPMAP); -} + void + destroyTexture( void* texture ) + { + #ifdef RW_D3D9 + if( texture ) + { + if( (( IUnknown* )texture)->Release() != 0 ) + printf( "texture wasn't destroyed\n" ); + d3d9Globals.numTextures--; + } + #else + rwFree( texture ); + #endif + } -static Raster* -rasterCreateTexture(Raster *raster) -{ - int32 levels; - D3dRaster *natras = GETD3DRASTEREXT(raster); - - if(natras->format == D3DFMT_P8) - natras->palette = (uint8*)rwNew(4*256, MEMDUR_EVENT | ID_DRIVER); - if(natras->autogenMipmap) - levels = 0; - else if(raster->format & Raster::MIPMAP) - levels = Raster::calculateNumLevels(raster->width, raster->height); - else - levels = 1; - - assert(natras->texture == nil); - natras->texture = createTexture(raster->width, raster->height, - levels, - natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0, - natras->format); - if(natras->texture == nil){ - RWERROR((ERR_NOTEXTURE)); - return nil; - } - return raster; -} + // Native Raster + + int32 nativeRasterOffset; + + struct RasterFormatInfo + { + uint32 d3dformat; + int32 depth; + bool32 hasAlpha; + uint32 rwFormat; + }; + + // indexed directly by RW format + static RasterFormatInfo formatInfoRW[ 16 ] = { + { 0, 0, 0, 0}, + { D3DFMT_A1R5G5B5, 16, 1, Raster::C1555 }, + { D3DFMT_R5G6B5, 16, 0, Raster::C565 }, + { D3DFMT_A4R4G4B4, 16, 1, Raster::C4444 }, + { D3DFMT_L8, 8, 0, Raster::LUM8 }, + { D3DFMT_A8R8G8B8, 32, 1, Raster::C8888 }, + { D3DFMT_X8R8G8B8, 32, 0, Raster::C888 }, + { D3DFMT_D16, 16, 0, Raster::D16 }, + { D3DFMT_D24X8, 32, 0, Raster::D24 }, + { D3DFMT_D32, 32, 0, Raster::D32 }, + { D3DFMT_X1R5G5B5, 16, 0, Raster::C555 }, + }; + + static RasterFormatInfo formatInfoFull[] = { + { D3DFMT_R8G8B8, 0, 24, 0 }, + { D3DFMT_A8R8G8B8, 1, 32, Raster::C8888 }, + { D3DFMT_X8R8G8B8, 0, 32, Raster::C888 }, + { D3DFMT_R5G6B5, 0, 16, Raster::C565 }, + { D3DFMT_X1R5G5B5, 0, 16, Raster::C555 }, + { D3DFMT_A1R5G5B5, 1, 16, Raster::C1555 }, + { D3DFMT_A4R4G4B4, 1, 16, Raster::C4444 }, + { D3DFMT_R3G3B2, 0, 8, 0 }, + { D3DFMT_A8, 1, 8, 0 }, + { D3DFMT_A8R3G3B2, 1, 16, 0 }, + { D3DFMT_X4R4G4B4, 0, 16, 0 }, + { D3DFMT_A2B10G10R10, 1, 32, 0 }, + { D3DFMT_A8B8G8R8, 1, 32, 0 }, + { D3DFMT_X8B8G8R8, 0, 32, 0 }, + { D3DFMT_G16R16, 0, 32, 0 }, + { D3DFMT_A2R10G10B10, 1, 32, 0 }, + { D3DFMT_A16B16G16R16, 1, 64, 0 }, + { D3DFMT_A8P8, 1, 16, 0 }, + // { D3DFMT_P8, 0, 8, ... }, + // { D3DFMT_L8, 0, 8, ... }, + { D3DFMT_A8L8, 1, 16, 0 }, + { D3DFMT_A4L4, 1, 8, 0 }, + { D3DFMT_V8U8, 0, 16, 0 }, + { D3DFMT_L6V5U5, 0, 16, 0 }, + { D3DFMT_X8L8V8U8, 0, 32, 0 }, + { D3DFMT_Q8W8V8U8, 0, 32, 0 }, + { D3DFMT_V16U16, 0, 32, 0 }, + { D3DFMT_A2W10V10U10, 1, 32, 0 }, + { D3DFMT_D16_LOCKABLE, 0, 16, Raster::D16 }, + { D3DFMT_D32, 0, 32, Raster::D32 }, + { D3DFMT_D15S1, 0, 16, Raster::D16 }, + { D3DFMT_D24S8, 0, 32, Raster::D32 }, + { D3DFMT_D24X8, 0, 32, Raster::D32 }, + { D3DFMT_D24X4S4, 0, 32, Raster::D32 }, + { D3DFMT_D16, 0, 16, Raster::D16 }, + { D3DFMT_D32F_LOCKABLE, 0, 32, Raster::D32 }, + { D3DFMT_D24FS8, 0, 32, Raster::D32 }, + { D3DFMT_L16, 0, 16, 0 }, + { D3DFMT_Q16W16V16U16, 0, 64, 0 }, + { D3DFMT_R16F, 0, 16, 0 }, + { D3DFMT_G16R16F, 0, 32, 0 }, + { D3DFMT_A16B16G16R16F, 1, 64, 0 }, + { D3DFMT_R32F, 0, 32, 0 }, + { D3DFMT_G32R32F, 0, 64, 0 }, + { D3DFMT_A32B32G32R32F, 1, 128, 0 }, + { D3DFMT_CxV8U8, 0, 16, 0 }, + }; + + RasterFormatInfo* + findFormatInfoD3D( uint32 d3dformat ) + { + static RasterFormatInfo fake = { 0, 0, 0, 0 }; + int i; + for( i = 0; i < ( int )nelem( formatInfoFull ); i++ ) + if( formatInfoFull[ i ].d3dformat == d3dformat ) + return &formatInfoFull[ i ]; + return &fake; + } -#ifdef RW_D3D9 -static Raster* -rasterCreateCameraTexture(Raster *raster) -{ - if(raster->format & (Raster::PAL4 | Raster::PAL8)){ - RWERROR((ERR_NOTEXTURE)); - return nil; - } + static void + rasterSetFormat( Raster* raster ) + { + if( raster->format == 0 ) + { + // have to find a format first + // this could perhaps be a bit more intelligent + + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + raster->format = Raster::C8888; + break; + + #ifdef RW_D3D9 + case Raster::ZBUFFER: + // TODO: allow other formats + raster->format = findFormatInfoD3D( d3d9Globals.present.AutoDepthStencilFormat )->rwFormat; + // can this even happen? just do something... + if( raster->format == 0 ) + raster->format = Raster::D32; + break; + + case Raster::CAMERATEXTURE: + // let's not use this because we apparently don't want alpha + // raster->format = findFormatInfoD3D(d3d9Globals.present.BackBufferFormat)->rwFormat; + raster->format = findFormatInfoD3D( d3d9Globals.startMode.mode.Format )->rwFormat; + // can this even happen? just do something... + if( raster->format == 0 ) + raster->format = Raster::C888; + break; + case Raster::CAMERA: + raster->format = findFormatInfoD3D( d3d9Globals.present.BackBufferFormat )->rwFormat; + // can this even happen? just do something... + if( raster->format == 0 ) + raster->format = Raster::C8888; + break; + #endif + } + } + + + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( raster->format & (Raster::PAL4 | Raster::PAL8) ) + { + // TODO: do we even allow PAL4? + natras->format = D3DFMT_P8; + raster->depth = 8; + } + else + { + natras->format = formatInfoRW[ (raster->format >> 8) & 0xF ].d3dformat; + raster->depth = formatInfoRW[ (raster->format >> 8) & 0xF ].depth; + } + natras->bpp = raster->depth / 8; + natras->hasAlpha = formatInfoRW[ (raster->format >> 8) & 0xF ].hasAlpha; + raster->stride = raster->width * natras->bpp; + + natras->autogenMipmap = (raster->format & (Raster::MIPMAP | Raster::AUTOMIPMAP)) == (Raster::MIPMAP | Raster::AUTOMIPMAP); + } - int32 levels; - D3dRaster *natras = GETD3DRASTEREXT(raster); - if(natras->autogenMipmap) - levels = 0; - else if(raster->format & Raster::MIPMAP) - levels = Raster::calculateNumLevels(raster->width, raster->height); - else - levels = 1; - - IDirect3DTexture9 *tex; - d3ddevice->CreateTexture(raster->width, raster->height, - levels, - (natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0) | D3DUSAGE_RENDERTARGET, - (D3DFORMAT)natras->format, D3DPOOL_DEFAULT, &tex, nil); - assert(natras->texture == nil); - natras->texture = tex; - if(natras->texture == nil){ - RWERROR((ERR_NOTEXTURE)); - return nil; - } - d3d9Globals.numTextures++; - addVidmemRaster(raster); - return raster; -} + static Raster* + rasterCreateTexture( Raster* raster ) + { + int32 levels; + D3dRaster* natras = GETD3DRASTEREXT( raster ); + + if( natras->format == D3DFMT_P8 ) + natras->palette = ( uint8* )rwNew( 4 * 256, MEMDUR_EVENT | ID_DRIVER ); + if( natras->autogenMipmap ) + levels = 0; + else if( raster->format & Raster::MIPMAP ) + levels = Raster::calculateNumLevels( raster->width, raster->height ); + else + levels = 1; + + assert( natras->texture == nil ); + natras->texture = createTexture( raster->width, raster->height, + levels, + natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0, + natras->format ); + if( natras->texture == nil ) + { + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + return raster; + } -static Raster* -rasterCreateCamera(Raster *raster) -{ - D3dRaster *natras = GETD3DRASTEREXT(raster); + #ifdef RW_D3D9 + + static Raster* + rasterCreateCameraTexture( Raster* raster ) + { + if( raster->format & (Raster::PAL4 | Raster::PAL8) ) + { + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + + int32 levels; + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( natras->autogenMipmap ) + levels = 0; + else if( raster->format & Raster::MIPMAP ) + levels = Raster::calculateNumLevels( raster->width, raster->height ); + else + levels = 1; + + IDirect3DTexture9* tex; + d3ddevice->CreateTexture( raster->width, raster->height, + levels, + (natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0) | D3DUSAGE_RENDERTARGET, + ( D3DFORMAT )natras->format, D3DPOOL_DEFAULT, &tex, nil ); + assert( natras->texture == nil ); + natras->texture = tex; + if( natras->texture == nil ) + { + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + d3d9Globals.numTextures++; + addVidmemRaster( raster ); + return raster; + } - natras->autogenMipmap = 0; + static Raster* + rasterCreateCamera( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); - natras->format = d3d9Globals.present.BackBufferFormat; - raster->depth = findFormatDepth(natras->format); + natras->autogenMipmap = 0; - natras->texture = nil; // global default render target - return raster; -} + natras->format = d3d9Globals.present.BackBufferFormat; + raster->depth = findFormatDepth( natras->format ); -static Raster* -rasterCreateZbuffer(Raster *raster) -{ - D3dRaster *natras = GETD3DRASTEREXT(raster); - - natras->autogenMipmap = 0; - - // TODO: allow other formats - natras->format = d3d9Globals.present.AutoDepthStencilFormat; - raster->depth = findFormatDepth(natras->format); - - RECT rect; - GetClientRect(d3d9Globals.window, &rect); - // This check is done by RW but it's rather strange... - if(rect.right == raster->width && rect.bottom == raster->height) - natras->texture = d3d9Globals.defaultDepthSurf; - else{ - IDirect3DSurface9 *surf = nil; - d3ddevice->CreateDepthStencilSurface(raster->width, raster->height, (D3DFORMAT)natras->format, - d3d9Globals.present.MultiSampleType, d3d9Globals.present.MultiSampleQuality, - FALSE, &surf, nil); - assert(natras->texture == nil); - natras->texture = surf; - if(natras->texture == nil){ - RWERROR((ERR_NOTEXTURE)); - return nil; + natras->texture = nil; // global default render target + return raster; } - } - addVidmemRaster(raster); - return raster; -} -#endif + static Raster* + rasterCreateZbuffer( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); -Raster* -rasterCreate(Raster *raster) -{ - rasterSetFormat(raster); - - Raster *ret = raster; + natras->autogenMipmap = 0; - if(raster->width == 0 || raster->height == 0){ - raster->flags |= Raster::DONTALLOCATE; - raster->stride = 0; - goto ret; - } - if(raster->flags & Raster::DONTALLOCATE) - goto ret; - - switch(raster->type){ - case Raster::NORMAL: - case Raster::TEXTURE: - ret = rasterCreateTexture(raster); - break; - -#ifdef RW_D3D9 - case Raster::CAMERATEXTURE: - ret = rasterCreateCameraTexture(raster); - break; - case Raster::ZBUFFER: - ret = rasterCreateZbuffer(raster); - break; - case Raster::CAMERA: - ret = rasterCreateCamera(raster); - break; -#endif - - default: - RWERROR((ERR_INVRASTER)); - return nil; - } + // TODO: allow other formats + natras->format = d3d9Globals.present.AutoDepthStencilFormat; + raster->depth = findFormatDepth( natras->format ); + + RECT rect; + GetClientRect( d3d9Globals.window, &rect ); + // This check is done by RW but it's rather strange... + if( rect.right == raster->width && rect.bottom == raster->height ) + natras->texture = d3d9Globals.defaultDepthSurf; + else + { + IDirect3DSurface9* surf = nil; + d3ddevice->CreateDepthStencilSurface( raster->width, raster->height, ( D3DFORMAT )natras->format, + d3d9Globals.present.MultiSampleType, d3d9Globals.present.MultiSampleQuality, + FALSE, &surf, nil ); + assert( natras->texture == nil ); + natras->texture = surf; + if( natras->texture == nil ) + { + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + } + addVidmemRaster( raster ); + + return raster; + } + #endif + + Raster* + rasterCreate( Raster* raster ) + { + rasterSetFormat( raster ); + + Raster* ret = raster; + + if( raster->width == 0 || raster->height == 0 ) + { + raster->flags |= Raster::DONTALLOCATE; + raster->stride = 0; + goto ret; + } + if( raster->flags & Raster::DONTALLOCATE ) + goto ret; + + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + ret = rasterCreateTexture( raster ); + break; + + #ifdef RW_D3D9 + case Raster::CAMERATEXTURE: + ret = rasterCreateCameraTexture( raster ); + break; + case Raster::ZBUFFER: + ret = rasterCreateZbuffer( raster ); + break; + case Raster::CAMERA: + ret = rasterCreateCamera( raster ); + break; + #endif + + default: + RWERROR( (ERR_INVRASTER) ); + return nil; + } ret: - raster->originalWidth = raster->width; - raster->originalHeight = raster->height; - raster->originalStride = raster->stride; - raster->originalPixels = raster->pixels; - return ret; -} - -uint8* -rasterLock(Raster *raster, int32 level, int32 lockMode) -{ - D3dRaster *natras = GETD3DRASTEREXT(raster); - - // check if already locked - if(raster->privateFlags & (Raster::PRIVATELOCK_READ|Raster::PRIVATELOCK_WRITE)) - return nil; - -#ifdef RW_D3D9 - DWORD flags = D3DLOCK_NOSYSLOCK; - if(lockMode & Raster::LOCKREAD) - flags |= D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE; - IDirect3DTexture9 *tex = (IDirect3DTexture9*)natras->texture; - IDirect3DSurface9 *surf, *rt; - D3DLOCKED_RECT lr; - - switch(raster->type){ - case Raster::NORMAL: - case Raster::TEXTURE: { - tex->GetSurfaceLevel(level, &surf); - natras->lockedSurf = surf; - HRESULT res = surf->LockRect(&lr, 0, flags); - assert(res == D3D_OK); - break; + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalStride = raster->stride; + raster->originalPixels = raster->pixels; + return ret; } - case Raster::CAMERATEXTURE: - case Raster::CAMERA: { - if(lockMode & Raster::PRIVATELOCK_WRITE) - assert(0 && "can't lock framebuffer for writing"); - if(raster->type == Raster::CAMERA) - rt = d3d9Globals.defaultRenderTarget; - else - tex->GetSurfaceLevel(level, &rt); - D3DSURFACE_DESC desc; - rt->GetDesc(&desc); - HRESULT res = d3ddevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, nil); - if(res != D3D_OK) - return nil; - d3ddevice->GetRenderTargetData(rt, surf); - natras->lockedSurf = surf; - res = surf->LockRect(&lr, 0, flags); - assert(res == D3D_OK); - break; + uint8* + rasterLock( Raster* raster, int32 level, int32 lockMode ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + + // check if already locked + if( raster->privateFlags & (Raster::PRIVATELOCK_READ | Raster::PRIVATELOCK_WRITE) ) + return nil; + + #ifdef RW_D3D9 + DWORD flags = D3DLOCK_NOSYSLOCK; + if( lockMode & Raster::LOCKREAD ) + flags |= D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE; + IDirect3DTexture9* tex = ( IDirect3DTexture9* )natras->texture; + IDirect3DSurface9* surf, * rt; + D3DLOCKED_RECT lr; + + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + { + tex->GetSurfaceLevel( level, &surf ); + natras->lockedSurf = surf; + HRESULT res = surf->LockRect( &lr, 0, flags ); + assert( res == D3D_OK ); + break; + } + + case Raster::CAMERATEXTURE: + case Raster::CAMERA: + { + if( lockMode & Raster::PRIVATELOCK_WRITE ) + assert( 0 && "can't lock framebuffer for writing" ); + if( raster->type == Raster::CAMERA ) + rt = d3d9Globals.defaultRenderTarget; + else + tex->GetSurfaceLevel( level, &rt ); + D3DSURFACE_DESC desc; + rt->GetDesc( &desc ); + HRESULT res = d3ddevice->CreateOffscreenPlainSurface( desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, nil ); + if( res != D3D_OK ) + return nil; + d3ddevice->GetRenderTargetData( rt, surf ); + natras->lockedSurf = surf; + res = surf->LockRect( &lr, 0, flags ); + assert( res == D3D_OK ); + break; + } + + default: + assert( 0 && "can't lock this raster type (yet)" ); + } + + raster->pixels = ( uint8* )lr.pBits; + raster->width >>= level; + raster->height >>= level; + raster->stride = lr.Pitch; + if( raster->width == 0 ) raster->width = 1; + if( raster->height == 0 ) raster->height = 1; + #else + RasterLevels* levels = ( RasterLevels* )natras->texture; + raster->pixels = levels->levels[ level ].data; + raster->width = levels->levels[ level ].width; + raster->height = levels->levels[ level ].height; + raster->stride = raster->width * natras->bpp; + #endif + if( lockMode & Raster::LOCKREAD ) raster->privateFlags |= Raster::PRIVATELOCK_READ; + if( lockMode & Raster::LOCKWRITE ) raster->privateFlags |= Raster::PRIVATELOCK_WRITE; + + return raster->pixels; } - default: - assert(0 && "can't lock this raster type (yet)"); - } - - raster->pixels = (uint8*)lr.pBits; - raster->width >>= level; - raster->height >>= level; - raster->stride = lr.Pitch; - if(raster->width == 0) raster->width = 1; - if(raster->height == 0) raster->height = 1; -#else - RasterLevels *levels = (RasterLevels*)natras->texture; - raster->pixels = levels->levels[level].data; - raster->width = levels->levels[level].width; - raster->height = levels->levels[level].height; - raster->stride = raster->width*natras->bpp; -#endif - if(lockMode & Raster::LOCKREAD) raster->privateFlags |= Raster::PRIVATELOCK_READ; - if(lockMode & Raster::LOCKWRITE) raster->privateFlags |= Raster::PRIVATELOCK_WRITE; - - return raster->pixels; -} - -void -rasterUnlock(Raster *raster, int32 level) -{ -#if RW_D3D9 - D3dRaster *natras = GETD3DRASTEREXT(raster); - IDirect3DSurface9 *surf = (IDirect3DSurface9*)natras->lockedSurf; - surf->UnlockRect(); - surf->Release(); - natras->lockedSurf = nil; -#endif - raster->width = raster->originalWidth; - raster->height = raster->originalHeight; - raster->stride = raster->originalStride; - raster->pixels = raster->originalPixels; - - raster->privateFlags &= ~(Raster::PRIVATELOCK_READ|Raster::PRIVATELOCK_WRITE); -} - -int32 -rasterNumLevels(Raster *raster) -{ - D3dRaster *natras = GETD3DRASTEREXT(raster); -#ifdef RW_D3D9 - IDirect3DTexture9 *tex = (IDirect3DTexture9*)natras->texture; - return tex->GetLevelCount(); -#else - RasterLevels *levels = (RasterLevels*)natras->texture; - return levels->numlevels; -#endif -} - -// Almost the same as ps2 and gl3 function -bool32 -imageFindRasterFormat(Image *img, int32 type, - int32 *pWidth, int32 *pHeight, int32 *pDepth, int32 *pFormat) -{ - int32 width, height, depth, format; - - assert((type&0xF) == Raster::TEXTURE); - -// for(width = 1; width < img->width; width <<= 1); -// for(height = 1; height < img->height; height <<= 1); - // Perhaps non-power-of-2 textures are acceptable? - width = img->width; - height = img->height; - - depth = img->depth; - - if(depth <= 8 && !isP8supported) - depth = 32; - - switch(depth){ - case 32: - if(img->hasAlpha()) - format = Raster::C8888; - else{ - format = Raster::C888; - depth = 24; + void + rasterUnlock( Raster* raster, int32 level ) + { + #if RW_D3D9 + D3dRaster* natras = GETD3DRASTEREXT( raster ); + IDirect3DSurface9* surf = ( IDirect3DSurface9* )natras->lockedSurf; + surf->UnlockRect(); + surf->Release(); + natras->lockedSurf = nil; + #endif + raster->width = raster->originalWidth; + raster->height = raster->originalHeight; + raster->stride = raster->originalStride; + raster->pixels = raster->originalPixels; + + raster->privateFlags &= ~(Raster::PRIVATELOCK_READ | Raster::PRIVATELOCK_WRITE); } - break; - case 24: - format = Raster::C888; - break; - case 16: - format = Raster::C1555; - break; - case 8: - format = Raster::PAL8 | Raster::C8888; - break; - case 4: - format = Raster::PAL4 | Raster::C8888; - break; - default: - RWERROR((ERR_INVRASTER)); - return 0; - } - - format |= type; - - *pWidth = width; - *pHeight = height; - *pDepth = depth; - *pFormat = format; - - return 1; -} -bool32 -rasterFromImage(Raster *raster, Image *image) -{ - if((raster->type&0xF) != Raster::TEXTURE) - return 0; - - void (*conv)(uint8 *out, uint8 *in) = nil; - - // Unpalettize image if necessary but don't change original - Image *truecolimg = nil; - if(image->depth <= 8 && !isP8supported){ - truecolimg = Image::create(image->width, image->height, image->depth); - truecolimg->pixels = image->pixels; - truecolimg->stride = image->stride; - truecolimg->palette = image->palette; - truecolimg->unpalettize(); - image = truecolimg; - } - - D3dRaster *natras = GETD3DRASTEREXT(raster); - int32 format = raster->format&(Raster::PAL8 | Raster::PAL4 | 0xF00); - switch(image->depth){ - case 32: - if(format == Raster::C8888) - conv = conv_BGRA8888_from_RGBA8888; - else if(format == Raster::C888) - conv = conv_BGR888_from_RGB888; - else - goto err; - break; - case 24: - if(format == Raster::C8888) - conv = conv_BGRA8888_from_RGB888; - else if(format == Raster::C888) - conv = conv_BGR888_from_RGB888; - else - goto err; - break; - case 16: - if(format == Raster::C1555) - conv = conv_ARGB1555_from_ARGB1555; - else - goto err; - break; - case 8: - if(format == (Raster::PAL8 | Raster::C8888)) - conv = conv_8_from_8; - else - goto err; - break; - case 4: - if(format == (Raster::PAL4 | Raster::C8888) || - format == (Raster::PAL8 | Raster::C8888)) - conv = conv_8_from_8; - else - goto err; - break; - default: - err: -fprintf(stderr, "%d %x\n", image->depth, format); fflush(stdout); - RWERROR((ERR_INVRASTER)); - return 0; - } - - uint8 *in, *out; - int pallength = 0; - if(raster->format & Raster::PAL4) - pallength = 16; - else if(raster->format & Raster::PAL8) - pallength = 256; - if(pallength){ - in = image->palette; - out = (uint8*)natras->palette; - for(int32 i = 0; i < pallength; i++){ - conv_RGBA8888_from_RGBA8888(out, in); - in += 4; - out += 4; + int32 + rasterNumLevels( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + #ifdef RW_D3D9 + IDirect3DTexture9* tex = ( IDirect3DTexture9* )natras->texture; + return tex->GetLevelCount(); + #else + RasterLevels* levels = ( RasterLevels* )natras->texture; + return levels->numlevels; + #endif } - } - bool unlock = false; - if(raster->pixels == nil){ - raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); - unlock = true; - } - - uint8 *pixels = raster->pixels; - assert(pixels); - uint8 *imgpixels = image->pixels; - - int x, y; - assert(image->width == raster->width); - assert(image->height == raster->height); - for(y = 0; y < image->height; y++){ - uint8 *imgrow = imgpixels; - uint8 *rasrow = pixels; - for(x = 0; x < image->width; x++){ - conv(rasrow, imgrow); - imgrow += image->bpp; - rasrow += natras->bpp; + // Almost the same as ps2 and gl3 function + bool32 + imageFindRasterFormat( Image* img, int32 type, + int32* pWidth, int32* pHeight, int32* pDepth, int32* pFormat ) + { + int32 width, height, depth, format; + + assert( (type & 0xF) == Raster::TEXTURE ); + + // for(width = 1; width < img->width; width <<= 1); + // for(height = 1; height < img->height; height <<= 1); + // Perhaps non-power-of-2 textures are acceptable? + width = img->width; + height = img->height; + + depth = img->depth; + + if( depth <= 8 && !isP8supported ) + depth = 32; + + switch( depth ) + { + case 32: + if( img->hasAlpha() ) + format = Raster::C8888; + else + { + format = Raster::C888; + depth = 24; + } + break; + case 24: + format = Raster::C888; + break; + case 16: + format = Raster::C1555; + break; + case 8: + format = Raster::PAL8 | Raster::C8888; + break; + case 4: + format = Raster::PAL4 | Raster::C8888; + break; + default: + RWERROR( (ERR_INVRASTER) ); + return 0; + } + + format |= type; + + *pWidth = width; + *pHeight = height; + *pDepth = depth; + *pFormat = format; + + return 1; } - imgpixels += image->stride; - pixels += raster->stride; - } - if(unlock) - raster->unlock(0); - if(truecolimg) - truecolimg->destroy(); - - return 1; -} - -Image* -rasterToImage(Raster *raster) -{ - int32 depth; - Image *image; - - bool unlock = false; - if(raster->pixels == nil){ - raster->lock(0, Raster::LOCKREAD); - unlock = true; - } - - D3dRaster *natras = GETD3DRASTEREXT(raster); - if(natras->customFormat){ - int w = raster->width; - int h = raster->height; - // pixels are in the upper right corner - if(w < 4) w = 4; - if(h < 4) h = 4; - image = Image::create(w, h, 32); - image->allocate(); - uint8 *pix = raster->pixels; - switch(natras->format){ - case D3DFMT_DXT1: - image->setPixelsDXT(1, pix); - if((raster->format & 0xF00) == Raster::C565) - image->removeMask(); - break; - case D3DFMT_DXT3: - image->setPixelsDXT(3, pix); - break; - case D3DFMT_DXT5: - image->setPixelsDXT(5, pix); - break; - default: - image->destroy(); - if(unlock) - raster->unlock(0); - return nil; + bool32 + rasterFromImage( Raster* raster, Image* image ) + { + if( (raster->type & 0xF) != Raster::TEXTURE ) + return 0; + + void (*conv)(uint8 * out, uint8 * in) = nil; + + // Unpalettize image if necessary but don't change original + Image* truecolimg = nil; + if( image->depth <= 8 && !isP8supported ) + { + truecolimg = Image::create( image->width, image->height, image->depth ); + truecolimg->pixels = image->pixels; + truecolimg->stride = image->stride; + truecolimg->palette = image->palette; + truecolimg->unpalettize(); + image = truecolimg; + } + + D3dRaster* natras = GETD3DRASTEREXT( raster ); + int32 format = raster->format & (Raster::PAL8 | Raster::PAL4 | 0xF00); + switch( image->depth ) + { + case 32: + if( format == Raster::C8888 ) + conv = conv_BGRA8888_from_RGBA8888; + else if( format == Raster::C888 ) + conv = conv_BGR888_from_RGB888; + else + goto err; + break; + case 24: + if( format == Raster::C8888 ) + conv = conv_BGRA8888_from_RGB888; + else if( format == Raster::C888 ) + conv = conv_BGR888_from_RGB888; + else + goto err; + break; + case 16: + if( format == Raster::C1555 ) + conv = conv_ARGB1555_from_ARGB1555; + else + goto err; + break; + case 8: + if( format == (Raster::PAL8 | Raster::C8888) ) + conv = conv_8_from_8; + else + goto err; + break; + case 4: + if( format == (Raster::PAL4 | Raster::C8888) || + format == (Raster::PAL8 | Raster::C8888) ) + conv = conv_8_from_8; + else + goto err; + break; + default: +err: + fprintf( stderr, "%d %x\n", image->depth, format ); fflush( stdout ); + RWERROR( (ERR_INVRASTER) ); + return 0; + } + + uint8* in, * out; + int pallength = 0; + if( raster->format & Raster::PAL4 ) + pallength = 16; + else if( raster->format & Raster::PAL8 ) + pallength = 256; + if( pallength ) + { + in = image->palette; + out = ( uint8* )natras->palette; + for( int32 i = 0; i < pallength; i++ ) + { + conv_RGBA8888_from_RGBA8888( out, in ); + in += 4; + out += 4; + } + } + + bool unlock = false; + if( raster->pixels == nil ) + { + raster->lock( 0, Raster::LOCKWRITE | Raster::LOCKNOFETCH ); + unlock = true; + } + + uint8* pixels = raster->pixels; + assert( pixels ); + uint8* imgpixels = image->pixels; + + int x, y; + assert( image->width == raster->width ); + assert( image->height == raster->height ); + for( y = 0; y < image->height; y++ ) + { + uint8* imgrow = imgpixels; + uint8* rasrow = pixels; + for( x = 0; x < image->width; x++ ) + { + conv( rasrow, imgrow ); + imgrow += image->bpp; + rasrow += natras->bpp; + } + imgpixels += image->stride; + pixels += raster->stride; + } + if( unlock ) + raster->unlock( 0 ); + + if( truecolimg ) + truecolimg->destroy(); + + return 1; } - // fix it up again - image->width = raster->width; - image->height = raster->height; - - if(unlock) - raster->unlock(0); - return image; - } - void (*conv)(uint8 *out, uint8 *in) = nil; - switch(raster->format & 0xF00){ - case Raster::C1555: - depth = 16; - conv = conv_ARGB1555_from_ARGB1555; - break; - case Raster::C8888: - depth = 32; - conv = conv_RGBA8888_from_BGRA8888; - break; - case Raster::C888: - depth = 24; - conv = conv_RGB888_from_BGR888; - break; - case Raster::C555: - depth = 16; - conv = conv_ARGB1555_from_RGB555; - break; - - default: - case Raster::C565: - case Raster::C4444: - case Raster::LUM8: - RWERROR((ERR_INVRASTER)); - return nil; - } - int32 pallength = 0; - if((raster->format & Raster::PAL4) == Raster::PAL4){ - depth = 4; - pallength = 16; - }else if((raster->format & Raster::PAL8) == Raster::PAL8){ - depth = 8; - pallength = 256; - } - - uint8 *in, *out; - image = Image::create(raster->width, raster->height, depth); - image->allocate(); - - if(pallength){ - out = image->palette; - in = (uint8*)natras->palette; - for(int32 i = 0; i < pallength; i++){ - conv_RGBA8888_from_RGBA8888(out, in); - in += 4; - out += 4; + Image* + rasterToImage( Raster* raster ) + { + int32 depth; + Image* image; + + bool unlock = false; + if( raster->pixels == nil ) + { + raster->lock( 0, Raster::LOCKREAD ); + unlock = true; + } + + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( natras->customFormat ) + { + int w = raster->width; + int h = raster->height; + // pixels are in the upper right corner + if( w < 4 ) w = 4; + if( h < 4 ) h = 4; + image = Image::create( w, h, 32 ); + image->allocate(); + uint8* pix = raster->pixels; + switch( natras->format ) + { + case D3DFMT_DXT1: + image->setPixelsDXT( 1, pix ); + if( (raster->format & 0xF00) == Raster::C565 ) + image->removeMask(); + break; + case D3DFMT_DXT3: + image->setPixelsDXT( 3, pix ); + break; + case D3DFMT_DXT5: + image->setPixelsDXT( 5, pix ); + break; + default: + image->destroy(); + if( unlock ) + raster->unlock( 0 ); + return nil; + } + // fix it up again + image->width = raster->width; + image->height = raster->height; + + if( unlock ) + raster->unlock( 0 ); + return image; + } + + void (*conv)(uint8 * out, uint8 * in) = nil; + switch( raster->format & 0xF00 ) + { + case Raster::C1555: + depth = 16; + conv = conv_ARGB1555_from_ARGB1555; + break; + case Raster::C8888: + depth = 32; + conv = conv_RGBA8888_from_BGRA8888; + break; + case Raster::C888: + depth = 24; + conv = conv_RGB888_from_BGR888; + break; + case Raster::C555: + depth = 16; + conv = conv_ARGB1555_from_RGB555; + break; + + default: + case Raster::C565: + case Raster::C4444: + case Raster::LUM8: + RWERROR( (ERR_INVRASTER) ); + return nil; + } + int32 pallength = 0; + if( (raster->format & Raster::PAL4) == Raster::PAL4 ) + { + depth = 4; + pallength = 16; + } + else if( (raster->format & Raster::PAL8) == Raster::PAL8 ) + { + depth = 8; + pallength = 256; + } + + uint8* in, * out; + image = Image::create( raster->width, raster->height, depth ); + image->allocate(); + + if( pallength ) + { + out = image->palette; + in = ( uint8* )natras->palette; + for( int32 i = 0; i < pallength; i++ ) + { + conv_RGBA8888_from_RGBA8888( out, in ); + in += 4; + out += 4; + } + } + + uint8* imgpixels = image->pixels; + uint8* pixels = raster->pixels; + + int x, y; + assert( image->width == raster->width ); + assert( image->height == raster->height ); + for( y = 0; y < image->height; y++ ) + { + uint8* imgrow = imgpixels; + uint8* rasrow = pixels; + for( x = 0; x < image->width; x++ ) + { + conv( imgrow, rasrow ); + imgrow += image->bpp; + rasrow += natras->bpp; + } + imgpixels += image->stride; + pixels += raster->stride; + } + image->compressPalette(); + + if( unlock ) + raster->unlock( 0 ); + + return image; } - } - uint8 *imgpixels = image->pixels; - uint8 *pixels = raster->pixels; - - int x, y; - assert(image->width == raster->width); - assert(image->height == raster->height); - for(y = 0; y < image->height; y++){ - uint8 *imgrow = imgpixels; - uint8 *rasrow = pixels; - for(x = 0; x < image->width; x++){ - conv(imgrow, rasrow); - imgrow += image->bpp; - rasrow += natras->bpp; + int32 + getLevelSize( Raster* raster, int32 level ) + { + D3dRaster* ras = GETD3DRASTEREXT( raster ); + #ifdef RW_D3D9 + IDirect3DTexture9* tex = ( IDirect3DTexture9* )ras->texture; + D3DSURFACE_DESC desc; + tex->GetLevelDesc( level, &desc ); + return calculateTextureSize( desc.Width, desc.Height, 1, desc.Format ); + #elif defined(RW_D3D11) + RasterLevels* levels = ( RasterLevels* )ras->lockedSurf; + return levels->levels[ level ].size; + #else + RasterLevels* levels = ( RasterLevels* )ras->texture; + return levels->levels[ level ].size; + #endif } - imgpixels += image->stride; - pixels += raster->stride; - } - image->compressPalette(); - if(unlock) - raster->unlock(0); + void + allocateDXT( Raster* raster, int32 dxt, int32 numLevels, bool32 hasAlpha ) + { + static uint32 dxtMap[] = { + 0x31545844, // DXT1 + 0x32545844, // DXT2 + 0x33545844, // DXT3 + 0x34545844, // DXT4 + 0x35545844, // DXT5 + }; + D3dRaster* ras = GETD3DRASTEREXT( raster ); + ras->format = dxtMap[ dxt - 1 ]; + ras->hasAlpha = hasAlpha; + ras->customFormat = 1; + if( ras->autogenMipmap ) + numLevels = 0; + else if( raster->format & Raster::MIPMAP ) + {} + else + numLevels = 1; + ras->texture = createTexture( raster->width, raster->height, + numLevels, + ras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0, + ras->format ); + raster->flags &= ~Raster::DONTALLOCATE; + } - return image; -} + void + setPalette( Raster* raster, void* palette, int32 size ) + { + D3dRaster* ras = GETD3DRASTEREXT( raster ); + memcpy( ras->palette, palette, 4 * size ); + } -int32 -getLevelSize(Raster *raster, int32 level) -{ - D3dRaster *ras = GETD3DRASTEREXT(raster); -#ifdef RW_D3D9 - IDirect3DTexture9 *tex = (IDirect3DTexture9*)ras->texture; - D3DSURFACE_DESC desc; - tex->GetLevelDesc(level, &desc); - return calculateTextureSize(desc.Width, desc.Height, 1, desc.Format); -#else - RasterLevels *levels = (RasterLevels*)ras->texture; - return levels->levels[level].size; -#endif -} + void + setTexels( Raster* raster, void* texels, int32 level ) + { + uint8* dst = raster->lock( level, Raster::LOCKWRITE | Raster::LOCKNOFETCH ); + memcpy( dst, texels, getLevelSize( raster, level ) ); + raster->unlock( level ); + } -void -allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha) -{ - static uint32 dxtMap[] = { - 0x31545844, // DXT1 - 0x32545844, // DXT2 - 0x33545844, // DXT3 - 0x34545844, // DXT4 - 0x35545844, // DXT5 - }; - D3dRaster *ras = GETD3DRASTEREXT(raster); - ras->format = dxtMap[dxt-1]; - ras->hasAlpha = hasAlpha; - ras->customFormat = 1; - if(ras->autogenMipmap) - numLevels = 0; - else if(raster->format & Raster::MIPMAP) - {} - else - numLevels = 1; - ras->texture = createTexture(raster->width, raster->height, - numLevels, - ras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0, - ras->format); - raster->flags &= ~Raster::DONTALLOCATE; -} + static void* + createNativeRaster( void* object, int32 offset, int32 ) + { + D3dRaster* raster = PLUGINOFFSET( D3dRaster, object, offset ); + raster->texture = nil; + raster->palette = nil; + raster->lockedSurf = nil; + raster->format = 0; + raster->hasAlpha = 0; + raster->customFormat = 0; + return object; + } -void -setPalette(Raster *raster, void *palette, int32 size) -{ - D3dRaster *ras = GETD3DRASTEREXT(raster); - memcpy(ras->palette, palette, 4*size); -} + static void* + destroyNativeRaster( void* object, int32 offset, int32 ) + { + Raster* raster = ( Raster* )object; + D3dRaster* natras = PLUGINOFFSET( D3dRaster, raster, offset ); + #ifdef RW_D3D11 + if( raster->platform == PLATFORM_D3D11 ) + { + d3d11::destroyRaster( raster ); + return object; + } + #endif + #ifdef RW_D3D9 + removeVidmemRaster( raster ); + evictD3D9Raster( raster ); + #endif + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + case Raster::CAMERATEXTURE: + destroyTexture( natras->texture ); + break; + + case Raster::ZBUFFER: + #ifdef RW_D3D9 + if( raster->flags & Raster::DONTALLOCATE ) + break; + if( natras->texture != d3d9Globals.defaultDepthSurf ) + (( IDirect3DSurface9* )natras->texture)->Release(); + natras->texture = nil; + #endif + break; + case Raster::CAMERA: + break; + } + rwFree( natras->palette ); + return object; + } -void -setTexels(Raster *raster, void *texels, int32 level) -{ - uint8 *dst = raster->lock(level, Raster::LOCKWRITE|Raster::LOCKNOFETCH); - memcpy(dst, texels, getLevelSize(raster, level)); - raster->unlock(level); -} + static void* + copyNativeRaster( void* dst, void*, int32 offset, int32 ) + { + D3dRaster* raster = PLUGINOFFSET( D3dRaster, dst, offset ); + raster->texture = nil; + raster->palette = nil; + raster->lockedSurf = nil; + raster->format = 0; + raster->hasAlpha = 0; + raster->customFormat = 0; + return dst; + } -static void* -createNativeRaster(void *object, int32 offset, int32) -{ - D3dRaster *raster = PLUGINOFFSET(D3dRaster, object, offset); - raster->texture = nil; - raster->palette = nil; - raster->lockedSurf = nil; - raster->format = 0; - raster->hasAlpha = 0; - raster->customFormat = 0; - return object; -} + void + registerNativeRaster( void ) + { + nativeRasterOffset = Raster::registerPlugin( sizeof( D3dRaster ), + ID_RASTERD3D9, + createNativeRaster, + destroyNativeRaster, + copyNativeRaster ); + } -static void* -destroyNativeRaster(void *object, int32 offset, int32) -{ - Raster *raster = (Raster*)object; - D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, offset); -#ifdef RW_D3D9 - removeVidmemRaster(raster); - evictD3D9Raster(raster); -#endif - switch(raster->type){ - case Raster::NORMAL: - case Raster::TEXTURE: - case Raster::CAMERATEXTURE: - destroyTexture(natras->texture); - break; - - case Raster::ZBUFFER: -#ifdef RW_D3D9 - if(raster->flags & Raster::DONTALLOCATE) - break; - if(natras->texture != d3d9Globals.defaultDepthSurf) - ((IDirect3DSurface9*)natras->texture)->Release(); - natras->texture = nil; -#endif - break; - case Raster::CAMERA: - break; } - rwFree(natras->palette); - return object; -} - -static void* -copyNativeRaster(void *dst, void *, int32 offset, int32) -{ - D3dRaster *raster = PLUGINOFFSET(D3dRaster, dst, offset); - raster->texture = nil; - raster->palette = nil; - raster->lockedSurf = nil; - raster->format = 0; - raster->hasAlpha = 0; - raster->customFormat = 0; - return dst; -} - -void -registerNativeRaster(void) -{ - nativeRasterOffset = Raster::registerPlugin(sizeof(D3dRaster), - ID_RASTERD3D9, - createNativeRaster, - destroyNativeRaster, - copyNativeRaster); -} - -} } diff --git a/src/d3d/d3d11.cpp b/src/d3d/d3d11.cpp new file mode 100644 index 00000000..ce7c3cc1 --- /dev/null +++ b/src/d3d/d3d11.cpp @@ -0,0 +1,851 @@ +#include +#include +#include +#include + +#define WITH_D3D +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "rwd3d.h" +#include "rwd3d11.h" + +#include "rwd3dimpl.h" + +#define PLUGIN_ID 2 + +namespace rw +{ + namespace d3d11 + { + using namespace d3d; + + // TODO: move to header, but not as #define + #ifndef RW_D3D11 + static VertexElement _d3ddec_end = { 0xFF,0,0,0,0,0 }; + #define D3DDECL_END() _d3ddec_end + #endif + + #define NUMDECLELT 12 + + static void* + driverOpen( void* o, int32, int32 ) + { + #ifdef RW_D3D11 + // createDefaultShaders(); + #endif + engine->driver[ PLATFORM_D3D11 ]->defaultPipeline = makeDefaultPipeline(); + + engine->driver[ PLATFORM_D3D11 ]->rasterNativeOffset = nativeRasterOffset; + engine->driver[ PLATFORM_D3D11 ]->rasterCreate = d3d11::rasterCreate; + engine->driver[ PLATFORM_D3D11 ]->rasterLock = d3d11::rasterLock; + engine->driver[ PLATFORM_D3D11 ]->rasterUnlock = d3d11::rasterUnlock; + engine->driver[ PLATFORM_D3D11 ]->rasterNumLevels = d3d11::rasterNumLevels; + engine->driver[ PLATFORM_D3D11 ]->imageFindRasterFormat = d3d11::imageFindRasterFormat; + engine->driver[ PLATFORM_D3D11 ]->rasterFromImage = d3d11::rasterFromImage; + engine->driver[ PLATFORM_D3D11 ]->rasterToImage = d3d11::rasterToImage; + return o; + } + + static void* + driverClose( void* o, int32, int32 ) + { + #ifdef RW_D3D11 + // destroyDefaultShaders(); + #endif + return o; + } + + void + registerPlatformPlugins( void ) + { + Driver::registerPlugin( PLATFORM_D3D11, 0, PLATFORM_D3D11, + driverOpen, driverClose ); + // shared between D3D8, 9 and 11 + if( nativeRasterOffset == 0 ) + registerNativeRaster(); + } + + void* + createVertexDeclaration( VertexElement* elements ) + { + #ifdef RW_D3D11 + // TODO: Implement D3D11 vertex declaration creation + return nil; + #else + int n = 0; + VertexElement* e = ( VertexElement* )elements; + while( e[ n++ ].stream != 0xFF ) + ; + e = rwNewT( VertexElement, n, MEMDUR_EVENT | ID_DRIVER ); + memcpy( e, elements, n * sizeof( VertexElement ) ); + return e; + #endif + } + + void + destroyVertexDeclaration( void* declaration ) + { + #ifdef RW_D3D11 + // TODO: Implement D3D11 vertex declaration destruction + #else + rwFree( declaration ); + #endif + } + + uint32 + getDeclaration( void* declaration, VertexElement* elements ) + { + #ifdef RW_D3D11 + // TODO: Implement D3D11 vertex declaration retrieval + return 0; + #else + int n = 0; + VertexElement* e = ( VertexElement* )declaration; + while( e[ n++ ].stream != 0xFF ) + ; + if( elements ) + memcpy( elements, declaration, n * sizeof( VertexElement ) ); + return n; + #endif + } + + void + freeInstanceData( Geometry* geometry ) + { + if( geometry->instData == nil || + geometry->instData->platform != PLATFORM_D3D11 ) + return; + InstanceDataHeader* header = + ( InstanceDataHeader* )geometry->instData; + geometry->instData = nil; + destroyVertexDeclaration( header->vertexDeclaration ); + destroyIndexBuffer( header->indexBuffer ); + destroyVertexBuffer( header->vertexStream[ 0 ].vertexBuffer ); + destroyVertexBuffer( header->vertexStream[ 1 ].vertexBuffer ); + rwFree( header->inst ); + rwFree( header ); + return; + } + + + void* + destroyNativeData( void* object, int32, int32 ) + { + freeInstanceData( ( Geometry* )object ); + return object; + } + + Stream* + readNativeData( Stream* stream, int32, void* object, int32, int32 ) + { + ASSERTLITTLE; + Geometry* geometry = ( Geometry* )object; + if( !findChunk( stream, ID_STRUCT, nil, nil ) ) + { + RWERROR( (ERR_CHUNK, "STRUCT") ); + return nil; + } + + uint32 platform = stream->readU32(); + if( platform != PLATFORM_D3D11 ) + { + RWERROR( (ERR_PLATFORM, platform) ); + return nil; + } + + InstanceDataHeader* header = rwNewT( InstanceDataHeader, 1, + MEMDUR_EVENT | ID_GEOMETRY ); + memset( header, 0, sizeof( *header ) ); + geometry->instData = header; + header->platform = PLATFORM_D3D11; + uint8* data = nil; + + { + int32 size = stream->readI32(); + if( size < 64 ) + goto fail; + data = rwNewT( uint8, size, + MEMDUR_FUNCTION | ID_GEOMETRY ); + if( stream->read8( data, size ) != ( uint32 )size ) + goto fail; + + uint8* p = data; + header->serialNumber = *( uint32* )p; p += 4; + header->numMeshes = *( uint32* )p; p += 4; + if( header->numMeshes > + ( uint32 )(size - 64) / 36 ) + goto fail; + p += 4; // index buffer + header->primType = *( uint32* )p; p += 4; + p += 16 * 2; + header->useOffsets = *( bool32* )p; p += 4; + p += 4; // vertex declaration + header->totalNumIndex = *( uint32* )p; p += 4; + header->totalNumVertex = *( uint32* )p; p += 4; + if( geometry->meshHeader == nil || + header->numMeshes != geometry->meshHeader->numMeshes || + header->totalNumIndex != geometry->meshHeader->totalIndices || + header->totalNumVertex != ( uint32 )geometry->numVertices ) + goto fail; + header->inst = rwNewT( InstanceData, header->numMeshes, + MEMDUR_EVENT | ID_GEOMETRY ); + + InstanceData* inst = header->inst; + for( uint32 i = 0; i < header->numMeshes; i++, inst++ ) + { + inst->numIndex = *( uint32* )p; p += 4; + inst->minVert = *( uint32* )p; p += 4; + uint32 matid = *( uint32* )p; p += 4; + if( matid >= ( uint32 )geometry->matList.numMaterials ) + goto fail; + inst->material = geometry->matList.materials[ matid ]; + inst->vertexAlpha = *( bool32* )p; p += 4; + inst->vertexShader = nil; p += 4; + inst->baseIndex = *( uint32* )p; p += 4; + inst->numVertices = *( uint32* )p; p += 4; + inst->startIndex = *( uint32* )p; p += 4; + inst->numPrimitives = *( uint32* )p; p += 4; + if( inst->startIndex > header->totalNumIndex || + inst->numIndex > + header->totalNumIndex - inst->startIndex || + inst->minVert > header->totalNumVertex || + inst->numVertices > + header->totalNumVertex - inst->minVert ) + goto fail; + } + rwFree( data ); + data = nil; + } + + { + uint32 numDeclarations = stream->readU32(); + if( numDeclarations != 0 ) + goto fail; + + header->indexBuffer = createIndexBuffer( + header->totalNumIndex * sizeof( uint16 ), false ); + uint16* indices = lockIndices( header->indexBuffer, 0, 0, 0 ); + if( indices == nil ) + goto fail; + uint32 indexDataSize = + header->totalNumIndex * sizeof( uint16 ); + if( stream->read8( indices, indexDataSize ) != indexDataSize ) + { + unlockIndices( header->indexBuffer ); + goto fail; + } + unlockIndices( header->indexBuffer ); + + for( int32 i = 0; i < 2; i++ ) + { + uint8 streamData[ 16 ]; + if( stream->read8( streamData, sizeof( streamData ) ) != + sizeof( streamData ) ) + goto fail; + uint8* p = streamData; + + bool32 hasVertexBuffer = *( uint32* )p != 0; p += 4; + VertexStream* vertexStream = &header->vertexStream[ i ]; + vertexStream->offset = *( uint32* )p; p += 4; + vertexStream->stride = *( uint32* )p; p += 4; + vertexStream->geometryFlags = *( uint16* )p; p += 2; + vertexStream->managed = *p++; + vertexStream->dynamicLock = *p++; + + if( !hasVertexBuffer ) + continue; + + if( vertexStream->stride == 0 || + header->totalNumVertex > + 0xFFFFFFFFu / vertexStream->stride ) + goto fail; + uint32 vertexDataSize = + vertexStream->stride * header->totalNumVertex; + vertexStream->vertexBuffer = createVertexBuffer( + vertexDataSize, 0, false ); + uint8* vertices = lockVertices( + vertexStream->vertexBuffer, 0, 0, 0 ); + if( vertices == nil ) + goto fail; + if( stream->read8( vertices, vertexDataSize ) != + vertexDataSize ) + { + unlockVertices( vertexStream->vertexBuffer ); + goto fail; + } + unlockVertices( vertexStream->vertexBuffer ); + } + } + + return stream; + +fail: + if( data ) + rwFree( data ); + freeInstanceData( geometry ); + return nil; + } + + Stream* + writeNativeData( Stream* stream, int32 len, void* object, int32, int32 ) + { + ASSERTLITTLE; + Geometry* geometry = ( Geometry* )object; + writeChunkHeader( stream, ID_STRUCT, len - 12 ); + if( geometry->instData == nil || + geometry->instData->platform != PLATFORM_D3D11 ) + return stream; + + stream->writeU32( PLATFORM_D3D11 ); + + InstanceDataHeader* header = ( InstanceDataHeader* )geometry->instData; + int32 size = 64 + header->numMeshes * 36; + uint8* data = rwNewT( uint8, size, + MEMDUR_FUNCTION | ID_GEOMETRY ); + stream->writeI32( size ); + memset( data, 0, size ); + + uint8* p = data; + *( uint32* )p = header->serialNumber; p += 4; + *( uint32* )p = header->numMeshes; p += 4; + p += 4; // index buffer + *( uint32* )p = header->primType; p += 4; + p += 16 * 2; + *( bool32* )p = header->useOffsets; p += 4; + p += 4; // vertex declaration + *( uint32* )p = header->totalNumIndex; p += 4; + *( uint32* )p = header->totalNumVertex; p += 4; + + InstanceData* inst = header->inst; + for( uint32 i = 0; i < header->numMeshes; i++ ) + { + *( uint32* )p = inst->numIndex; p += 4; + *( uint32* )p = inst->minVert; p += 4; + int32 matid = geometry->matList.findIndex( inst->material ); + *( int32* )p = matid; p += 4; + *( bool32* )p = inst->vertexAlpha; p += 4; + p += 4; // vertex shader + *( uint32* )p = inst->baseIndex; p += 4; + *( uint32* )p = inst->numVertices; p += 4; + *( uint32* )p = inst->startIndex; p += 4; + *( uint32* )p = inst->numPrimitives; p += 4; + inst++; + } + stream->write8( data, size ); + + // The standard D3D11 pipeline uses the fixed default input layout. + stream->writeU32( 0 ); + + uint16* indices = lockIndices( header->indexBuffer, 0, 0, 0 ); + stream->write8( indices, + header->totalNumIndex * sizeof( uint16 ) ); + unlockIndices( header->indexBuffer ); + + for( int32 i = 0; i < 2; i++ ) + { + VertexStream* vertexStream = &header->vertexStream[ i ]; + p = data; + *( uint32* )p = + vertexStream->vertexBuffer ? 0xBADEAFFE : 0; p += 4; + *( uint32* )p = vertexStream->offset; p += 4; + *( uint32* )p = vertexStream->stride; p += 4; + *( uint16* )p = vertexStream->geometryFlags; p += 2; + *p++ = vertexStream->managed; + *p++ = vertexStream->dynamicLock; + stream->write8( data, 16 ); + + if( vertexStream->vertexBuffer == nil ) + continue; + + uint32 vertexDataSize = + vertexStream->stride * header->totalNumVertex; + uint8* vertices = lockVertices( + vertexStream->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK ); + stream->write8( vertices, vertexDataSize ); + unlockVertices( vertexStream->vertexBuffer ); + } + + rwFree( data ); + return stream; + } + + int32 + getSizeNativeData( void* object, int32, int32 ) + { + Geometry* geometry = ( Geometry* )object; + if( geometry->instData == nil || + geometry->instData->platform != PLATFORM_D3D11 ) + return 0; + + InstanceDataHeader* header = + ( InstanceDataHeader* )geometry->instData; + int32 size = 12 + 4 + 4 + 64 + header->numMeshes * 36; + size += 4; + size += header->totalNumIndex * sizeof( uint16 ); + for( int32 i = 0; i < 2; i++ ) + { + VertexStream* stream = &header->vertexStream[ i ]; + size += 16; + if( stream->vertexBuffer ) + size += stream->stride * header->totalNumVertex; + } + return size; + } + + void + registerNativeDataPlugin( void ) + { + Geometry::registerPlugin( 0, ID_NATIVEDATA, + nil, destroyNativeData, nil ); + Geometry::registerPluginStream( ID_NATIVEDATA, + readNativeData, + writeNativeData, + getSizeNativeData ); + } + + static InstanceDataHeader* + instanceMesh( rw::ObjPipeline* rwpipe, Geometry* geo ) + { + ( void )rwpipe; + + #ifdef RW_D3D11 + InstanceDataHeader* header = rwNewT( InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY ); + MeshHeader* meshh = geo->meshHeader; + header->platform = PLATFORM_D3D11; + + header->serialNumber = meshh->serialNum; + header->numMeshes = meshh->numMeshes; + header->primType = meshh->flags == 1 ? + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP : + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + header->useOffsets = 0; + header->vertexDeclaration = nil; + header->totalNumVertex = geo->numVertices; + header->totalNumIndex = meshh->totalIndices; + header->inst = rwNewT( InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY ); + + header->indexBuffer = createIndexBuffer( header->totalNumIndex * 2, false ); + uint16* indices = lockIndices( header->indexBuffer, 0, 0, 0 ); + if( indices == nil ) + { + destroyIndexBuffer( header->indexBuffer ); + rwFree( header->inst ); + rwFree( header ); + return nil; + } + + InstanceData* inst = header->inst; + Mesh* mesh = meshh->getMeshes(); + uint32 startindex = 0; + for( uint32 i = 0; i < header->numMeshes; i++ ) + { + findMinVertAndNumVertices( mesh->indices, mesh->numIndices, + &inst->minVert, ( int32* )&inst->numVertices ); + inst->numIndex = mesh->numIndices; + inst->material = mesh->material; + inst->vertexAlpha = 0; + inst->vertexShader = nil; + inst->baseIndex = inst->minVert; + inst->startIndex = startindex; + inst->numPrimitives = header->primType == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ? + inst->numIndex - 2 : inst->numIndex / 3; + if( inst->minVert == 0 ) + memcpy( &indices[ inst->startIndex ], mesh->indices, + inst->numIndex * sizeof( uint16 ) ); + else + for( uint32 j = 0; j < inst->numIndex; j++ ) + indices[ inst->startIndex + j ] = mesh->indices[ j ] - inst->minVert; + startindex += inst->numIndex; + mesh++; + inst++; + } + unlockIndices( header->indexBuffer ); + + memset( &header->vertexStream, 0, sizeof( header->vertexStream ) ); + return header; + #else + ( void )geo; + return nil; + #endif + } + + static void + instance( rw::ObjPipeline* rwpipe, Atomic* atomic ) + { + ObjPipeline* pipe = ( ObjPipeline* )rwpipe; + Geometry* geo = atomic->geometry; + // Native geometry already contains D3D11-ready vertex and index data. + if( geo->flags & Geometry::NATIVE ) + return; + + InstanceDataHeader* header = ( InstanceDataHeader* )geo->instData; + if( header ) + { + assert( header->platform == PLATFORM_D3D11 ); + if( header->serialNumber != geo->meshHeader->serialNum ) + freeInstanceData( geo ); + } + + if( geo->instData == nil ) + { + geo->instData = instanceMesh( rwpipe, geo ); + if( geo->instData && pipe->instanceCB ) + pipe->instanceCB( geo, ( InstanceDataHeader* )geo->instData, 0 ); + } + else if( geo->lockedSinceInst && pipe->instanceCB ) + pipe->instanceCB( geo, ( InstanceDataHeader* )geo->instData, 1 ); + + geo->lockedSinceInst = 0; + } + + static void + uninstance( rw::ObjPipeline* rwpipe, Atomic* atomic ) + { + ObjPipeline* pipe = ( ObjPipeline* )rwpipe; + Geometry* geo = atomic->geometry; + if( (geo->flags & Geometry::NATIVE) == 0 ) + return; + + assert( geo->instData != nil ); + if( geo->instData == nil ) + return; + assert( geo->instData->platform == PLATFORM_D3D11 ); + if( geo->instData->platform != PLATFORM_D3D11 ) + return; + + geo->numTriangles = geo->meshHeader->guessNumTriangles(); + geo->allocateData(); + geo->allocateMeshes( geo->meshHeader->numMeshes, + geo->meshHeader->totalIndices, 0 ); + + InstanceDataHeader* header = + ( InstanceDataHeader* )geo->instData; + uint16* indices = lockIndices( header->indexBuffer, 0, 0, 0 ); + if( indices == nil ) + return; + + InstanceData* inst = header->inst; + Mesh* mesh = geo->meshHeader->getMeshes(); + for( uint32 i = 0; i < header->numMeshes; i++ ) + { + if( inst->minVert == 0 ) + memcpy( mesh->indices, &indices[ inst->startIndex ], + inst->numIndex * sizeof( uint16 ) ); + else + for( uint32 j = 0; j < inst->numIndex; j++ ) + mesh->indices[ j ] = + indices[ inst->startIndex + j ] + inst->minVert; + mesh++; + inst++; + } + unlockIndices( header->indexBuffer ); + + assert( pipe->uninstanceCB != nil ); + if( pipe->uninstanceCB == nil ) + return; + pipe->uninstanceCB( geo, header ); + geo->generateTriangles(); + geo->flags &= ~Geometry::NATIVE; + destroyNativeData( geo, 0, 0 ); + } + + static void + render( rw::ObjPipeline* rwpipe, Atomic* atomic ) + { + ObjPipeline* pipe = ( ObjPipeline* )rwpipe; + Geometry* geo = atomic->geometry; + pipe->instance( atomic ); + if( geo->instData == nil ) + return; + assert( geo->instData->platform == PLATFORM_D3D11 ); + if( pipe->renderCB ) + pipe->renderCB( atomic, ( InstanceDataHeader* )geo->instData ); + } + + void + ObjPipeline::init( void ) + { + this->rw::ObjPipeline::init( PLATFORM_D3D11 ); + this->impl.instance = d3d11::instance; + this->impl.uninstance = d3d11::uninstance; + this->impl.render = d3d11::render; + this->instanceCB = nil; + this->uninstanceCB = nil; + this->renderCB = nil; + } + + ObjPipeline* + ObjPipeline::create( void ) + { + ObjPipeline* pipe = rwNewT( ObjPipeline, 1, MEMDUR_GLOBAL ); + pipe->init(); + return pipe; + } + + void + defaultInstanceCB( Geometry* geo, InstanceDataHeader* header, bool32 reinstance ) + { + VertexStream* stream = &header->vertexStream[ 0 ]; + if( geo->numVertices <= 0 || geo->morphTargets == nil || + geo->morphTargets[ 0 ].vertices == nil ) + return; + + if( !reinstance ) + { + stream->offset = 0; + stream->stride = sizeof( DefaultVertex ); + stream->managed = 1; + stream->geometryFlags = 0; + stream->dynamicLock = 0; + stream->vertexBuffer = createVertexBuffer( + header->totalNumVertex * stream->stride, 0, false ); + } + if( stream->vertexBuffer == nil ) + return; + + DefaultVertex* vertices = ( DefaultVertex* )lockVertices( stream->vertexBuffer, + 0, 0, 0 ); + if( vertices == nil ) + return; + + bool isPrelit = (geo->flags & Geometry::PRELIT) != 0 && geo->colors; + bool hasNormals = (geo->flags & Geometry::NORMALS) != 0 && + geo->morphTargets[ 0 ].normals; + bool hasTexCoords = geo->numTexCoordSets > 0 && geo->texCoords[ 0 ]; + V3d defaultNormal = { 0.0f, 0.0f, 1.0f }; + RGBA black = { 0, 0, 0, 255 }; + TexCoords zeroTexCoord = { 0.0f, 0.0f }; + for( uint32 i = 0; i < header->totalNumVertex; i++ ) + { + vertices[ i ].position = geo->morphTargets[ 0 ].vertices[ i ]; + vertices[ i ].normal = hasNormals ? geo->morphTargets[ 0 ].normals[ i ] : defaultNormal; + vertices[ i ].color = isPrelit ? geo->colors[ i ] : black; + vertices[ i ].texcoord = hasTexCoords ? geo->texCoords[ 0 ][ i ] : zeroTexCoord; + } + unlockVertices( stream->vertexBuffer ); + + InstanceData* inst = header->inst; + for( uint32 i = 0; i < header->numMeshes; i++, inst++ ) + { + inst->vertexAlpha = 0; + if( isPrelit ) + for( uint32 j = 0; j < inst->numVertices; j++ ) + if( geo->colors[ inst->minVert + j ].alpha != 255 ) + { + inst->vertexAlpha = 1; + break; + } + } + } + + void + defaultUninstanceCB( Geometry* geo, InstanceDataHeader* header ) + { + VertexStream* stream = &header->vertexStream[ 0 ]; + if( stream->vertexBuffer == nil || + stream->stride < sizeof( DefaultVertex ) ) + return; + + uint8* vertices = lockVertices( stream->vertexBuffer, 0, 0, + D3DLOCK_NOSYSLOCK ); + if( vertices == nil ) + return; + + bool hasNormals = (geo->flags & Geometry::NORMALS) != 0 && + geo->morphTargets[ 0 ].normals; + bool isPrelit = (geo->flags & Geometry::PRELIT) != 0 && + geo->colors; + bool hasTexCoords = geo->numTexCoordSets > 0 && + geo->texCoords[ 0 ]; + + for( uint32 i = 0; i < header->totalNumVertex; i++ ) + { + DefaultVertex* vertex = ( DefaultVertex* )( + vertices + stream->offset + i * stream->stride); + geo->morphTargets[ 0 ].vertices[ i ] = vertex->position; + if( hasNormals ) + geo->morphTargets[ 0 ].normals[ i ] = vertex->normal; + if( isPrelit ) + geo->colors[ i ] = vertex->color; + if( hasTexCoords ) + geo->texCoords[ 0 ][ i ] = vertex->texcoord; + } + + unlockVertices( stream->vertexBuffer ); + } + + ObjPipeline* + makeDefaultPipeline( void ) + { + ObjPipeline* pipe = ObjPipeline::create(); + pipe->instanceCB = defaultInstanceCB; + pipe->uninstanceCB = defaultUninstanceCB; + pipe->renderCB = defaultRenderCB_Shader; + return pipe; + } + + void + defaultRenderCB_Fix( Atomic* atomic, InstanceDataHeader* header ) + { + // TODO: Implement D3D11 default render callback (fixed function) + } + + // Native Texture and Raster + + enum NativeTextureFlags + { + NATIVE_TEXTURE_HAS_ALPHA = 1, + NATIVE_TEXTURE_IS_CUBE = 2, + NATIVE_TEXTURE_AUTOMIPMAP = 4, + NATIVE_TEXTURE_COMPRESSED = 8 + }; + + Texture* + readNativeTexture( Stream* stream ) + { + if( !findChunk( stream, ID_STRUCT, nil, nil ) ) + { + RWERROR( (ERR_CHUNK, "STRUCT") ); + return nil; + } + + uint32 platform = stream->readU32(); + if( platform != PLATFORM_D3D11 ) + { + RWERROR( (ERR_PLATFORM, platform) ); + return nil; + } + + Texture* tex = Texture::create( nil ); + if( tex == nil ) + return nil; + + // Texture + tex->filterAddressing = stream->readU32(); + stream->read8( tex->name, 32 ); + stream->read8( tex->mask, 32 ); + + // Raster + int32 format = stream->readI32(); + uint32 nativeFormat = stream->readU32(); + int32 width = stream->readU16(); + int32 height = stream->readU16(); + int32 depth = stream->readU8(); + int32 numLevels = stream->readU8(); + int32 type = stream->readU8(); + uint32 flags = stream->readU8(); + + if( flags & (NATIVE_TEXTURE_IS_CUBE | NATIVE_TEXTURE_COMPRESSED) || + format & (Raster::PAL4 | Raster::PAL8) ) + { + RWERROR( (ERR_INVRASTER) ); + tex->destroy(); + return nil; + } + + Raster* raster = Raster::create( width, height, depth, + format | type, PLATFORM_D3D11 ); + if( raster == nil ) + { + tex->destroy(); + return nil; + } + tex->raster = raster; + + D3dRaster* ext = GETD3DRASTEREXT( raster ); + if( nativeFormat != ext->format ) + { + RWERROR( (ERR_INVRASTER) ); + tex->destroy(); + return nil; + } + ext->hasAlpha = (flags & NATIVE_TEXTURE_HAS_ALPHA) != 0; + ext->autogenMipmap = (flags & NATIVE_TEXTURE_AUTOMIPMAP) != 0; + + for( int32 i = 0; i < numLevels; i++ ) + { + uint32 size = stream->readU32(); + if( i >= raster->getNumLevels() ) + { + stream->seek( size ); + continue; + } + if( size != (uint32)getLevelSize( raster, i ) ) + { + RWERROR( (ERR_INVRASTER) ); + tex->destroy(); + return nil; + } + + uint8* data = raster->lock( i, Raster::LOCKWRITE | Raster::LOCKNOFETCH ); + if( data == nil ) + { + tex->destroy(); + return nil; + } + stream->read8( data, size ); + raster->unlock( i ); + } + return tex; + } + + void + writeNativeTexture( Texture* tex, Stream* stream ) + { + int32 chunksize = getSizeNativeTexture( tex ); + writeChunkHeader( stream, ID_STRUCT, chunksize - 12 ); + stream->writeU32( PLATFORM_D3D11 ); + + // Texture + stream->writeU32( tex->filterAddressing ); + stream->write8( tex->name, 32 ); + stream->write8( tex->mask, 32 ); + + // Raster + Raster* raster = tex->raster; + D3dRaster* ext = GETD3DRASTEREXT( raster ); + int32 numLevels = raster->getNumLevels(); + assert( (raster->format & (Raster::PAL4 | Raster::PAL8)) == 0 ); + assert( ext->customFormat == 0 ); + + stream->writeI32( raster->format ); + stream->writeU32( ext->format ); + stream->writeU16( raster->width ); + stream->writeU16( raster->height ); + stream->writeU8( raster->depth ); + stream->writeU8( numLevels ); + stream->writeU8( raster->type ); + + uint8 flags = 0; + if( ext->hasAlpha ) + flags |= NATIVE_TEXTURE_HAS_ALPHA; + if( ext->autogenMipmap ) + flags |= NATIVE_TEXTURE_AUTOMIPMAP; + stream->writeU8( flags ); + + for( int32 i = 0; i < numLevels; i++ ) + { + uint32 size = getLevelSize( raster, i ); + stream->writeU32( size ); + uint8* data = raster->lock( i, Raster::LOCKREAD ); + stream->write8( data, size ); + raster->unlock( i ); + } + } + + uint32 + getSizeNativeTexture( Texture* tex ) + { + uint32 size = 12 + 72 + 16; + int32 numLevels = tex->raster->getNumLevels(); + for( int32 i = 0; i < numLevels; i++ ) + size += 4 + getLevelSize( tex->raster, i ); + return size; + } + + } +} diff --git a/src/d3d/d3d11device.cpp b/src/d3d/d3d11device.cpp new file mode 100644 index 00000000..7c7cefaa --- /dev/null +++ b/src/d3d/d3d11device.cpp @@ -0,0 +1,2781 @@ +#include +#include +#include +#include + +#define WITH_D3D +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwrender.h" +#include "../rwengine.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" + +#ifdef RW_D3D11 + +#include +#include + +#include "rwd3d.h" +#include "rwd3d11.h" +#include "rwd3dimpl.h" +#include "clear_VS_d11.h" +#include "clear_PS_d11.h" +#include "im2d_VS_d11.h" +#include "im2d_PS_d11.h" +#include "im3d_VS_d11.h" +#include "im3d_PS_d11.h" +#include "im3d_tex_PS_d11.h" + +#define PLUGIN_ID 0 + +namespace rw +{ + namespace d3d + { + D3d11Globals d3d11Globals; + } + + namespace d3d11 + { + using namespace d3d; + + template static void + safeRelease( T*& p ) + { + if( p ) + { + p->Release(); + p = nil; + } + } + + struct DynamicVB + { + uint32 length; + uint32 stride; + ID3D11Buffer** buf; + DynamicVB* next; + }; + + struct DynamicIB + { + uint32 length; + ID3D11Buffer** buf; + DynamicIB* next; + }; + + #define MAXNUMSTREAMS (3) + #define MAXNUMSTAGES (2) + + struct D3dDeviceCache + { + ID3D11VertexShader* vertexShader; + ID3D11PixelShader* pixelShader; + ID3D11InputLayout* vertexDeclaration; + ID3D11Buffer* indices; + struct + { + ID3D11Buffer* buffer; + uint32 offset; + uint32 stride; + } vertexStreams[ MAXNUMSTREAMS ]; + }; + + static D3dDeviceCache deviceCache; + + struct RwRasterStateCache + { + Raster* raster; + Texture::Addressing addressingU; + Texture::Addressing addressingV; + Texture::FilterMode filter; + }; + + struct RwStateCache + { + bool32 vertexAlpha; + bool32 textureAlpha; + uint32 alphaFunc; + uint32 alphaRef; + uint32 srcblend; + uint32 destblend; + uint32 zwrite; + uint32 ztest; + uint32 cullmode; + uint32 fogenable; + RGBA fogcolor; + RwRasterStateCache texstage[ MAXNUMSTAGES ]; + }; + + struct Im2DConstants + { + float xform[ 4 ]; + }; + + struct Im3DConstants + { + float combined[ 16 ]; + float world[ 16 ]; + float normal[ 16 ]; + float viewportOffset[ 4 ]; + }; + + struct AlphaTestConstants + { + // D3D11 has no fixed-function alpha test, unlike D3D9. + uint32 enabled; + uint32 function; + float reference; + float padding; + }; + + struct ClearConstants + { + float color[ 4 ]; + }; + + static DynamicVB* dynamicVBs; + static DynamicIB* dynamicIBs; + static RwStateCache rwStateCache; + + static ID3D11BlendState* blendState; + static ID3D11DepthStencilState* depthStencilState; + static ID3D11RasterizerState* rasterizerState; + static ID3D11SamplerState* samplerState[ MAXNUMSTAGES ]; + static ID3D11Buffer* alphaTestConstantBuffer; + + static ID3D11VertexShader* clearVS; + static ID3D11PixelShader* clearPS; + static ID3D11Buffer* clearConstantBuffer; + static ID3D11BlendState* clearBlendState[ 2 ]; + static ID3D11DepthStencilState* clearDepthStencilState[ 4 ]; + static ID3D11RasterizerState* clearRasterizerState; + + static ID3D11VertexShader* im2dVS; + static ID3D11PixelShader* im2dPS; + static ID3D11InputLayout* im2dLayout; + static ID3D11Buffer* im2dConstantBuffer; + static ID3D11Buffer* im2dVertexBuffer; + static ID3D11Buffer* im2dIndexBuffer; + static uint32 im2dVertexBufferSize; + static uint32 im2dIndexBufferSize; + + static ID3D11VertexShader* im3dVS; + static ID3D11PixelShader* im3dPS; + static ID3D11PixelShader* im3dTexPS; + static ID3D11InputLayout* im3dLayout; + static ID3D11Buffer* im3dConstantBuffer; + static ID3D11Buffer* im3dVertexBuffer; + static ID3D11Buffer* im3dIndexBuffer; + static const uint32 im3dMaxVertices = 10000; + static const uint32 im3dMaxIndices = 10000; + static int32 num3DVertices; + + static ID3D11Texture2D* whiteTexture; + static ID3D11ShaderResourceView* whiteSRV; + + static bool32 blendDirty; + static bool32 depthDirty; + static bool32 rasterizerDirty; + static bool32 samplerDirty[ MAXNUMSTAGES ]; + static bool32 alphaTestDirty; + + static int findFormatDepth11( DXGI_FORMAT format ); + static void initDefaultMode( void ); + static void updateDefaultMode( void ); + static bool32 createFactory( void ); + static void releaseDefaultViews( void ); + static bool32 createDefaultViews( void ); + static bool32 resizeSwapChain( uint32 width, uint32 height ); + static void ensureSwapChainSize( void ); + static bool32 openD3D11( EngineOpenParams* params ); + static int closeD3D11( void ); + static bool32 startD3D11( void ); + static bool32 initD3D11( void ); + static int termD3D11( void ); + static int finalizeD3D11( void ); + static void resetRenderState( void ); + static void setRenderSurfaces( Camera* cam ); + static void setViewport( Raster* fb ); + static void beginUpdate( Camera* cam ); + static void endUpdate( Camera* cam ); + static void clearCamera( Camera* cam, RGBA* col, uint32 mode ); + static void showRaster( Raster* raster, uint32 flags ); + static bool32 rasterRenderFast( Raster* raster, int32 x, int32 y ); + static void setRwRenderState( int32 state, void* value ); + static void* getRwRenderState( int32 state ); + static bool32 openClear( void ); + static void closeClear( void ); + static void clearRect( RGBA* color, uint32 mode, bool32 hasDepth ); + static bool32 openIm2D( void ); + static void closeIm2D( void ); + static bool32 openIm3D( void ); + static void closeIm3D( void ); + static void uploadMatrices( void ); + static void uploadMatrices( Matrix* world ); + static void im3DTransform( void* vertices, int32 numVertices, Matrix* world, uint32 flags ); + static void im3DRenderPrimitive( PrimitiveType primType ); + static void im3DRenderIndexedPrimitive( PrimitiveType primType, void* indices, int32 numIndices ); + static void im3DEnd( void ); + static void im2DRenderLine( void* vertices, int32 numVertices, int32 vert1, int32 vert2 ); + static void im2DRenderTriangle( void* vertices, int32 numVertices, int32 vert1, int32 vert2, int32 vert3 ); + static void im2DRenderPrimitive( PrimitiveType primType, void* vertices, int32 numVertices ); + static void im2DRenderIndexedPrimitive( PrimitiveType primType, void* vertices, int32 numVertices, void* indices, int32 numIndices ); + + void + addDynamicVB( uint32 length, uint32 stride, ID3D11Buffer** buf ) + { + DynamicVB* dvb = rwNewT( DynamicVB, 1, ID_DRIVER | MEMDUR_EVENT ); + dvb->length = length; + dvb->stride = stride; + dvb->buf = buf; + dvb->next = dynamicVBs; + dynamicVBs = dvb; + } + + void + removeDynamicVB( ID3D11Buffer** buf ) + { + DynamicVB** p, * dvb; + for( p = &dynamicVBs; *p; p = &(*p)->next ) + if( (*p)->buf == buf ) + goto found; + return; +found: + dvb = *p; + *p = dvb->next; + rwFree( dvb ); + } + + void + addDynamicIB( uint32 length, ID3D11Buffer** buf ) + { + DynamicIB* dib = rwNewT( DynamicIB, 1, ID_DRIVER | MEMDUR_EVENT ); + dib->length = length; + dib->buf = buf; + dib->next = dynamicIBs; + dynamicIBs = dib; + } + + void + removeDynamicIB( ID3D11Buffer** buf ) + { + DynamicIB** p, * dib; + for( p = &dynamicIBs; *p; p = &(*p)->next ) + if( (*p)->buf == buf ) + goto found; + return; +found: + dib = *p; + *p = dib->next; + rwFree( dib ); + } + + static int + getClientWidth( void ) + { + RECT rect = { 0, 0, 0, 0 }; + if( d3d11Globals.window ) + GetClientRect( d3d11Globals.window, &rect ); + return rect.right - rect.left; + } + + static int + getClientHeight( void ) + { + RECT rect = { 0, 0, 0, 0 }; + if( d3d11Globals.window ) + GetClientRect( d3d11Globals.window, &rect ); + return rect.bottom - rect.top; + } + + static int + findFormatDepth11( DXGI_FORMAT format ) + { + switch( format ) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return 32; + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_D16_UNORM: + return 16; + default: + return 32; + } + } + + static DXGI_FORMAT + getColorFormat( void ) + { + return DXGI_FORMAT_R8G8B8A8_UNORM; + } + + static DXGI_FORMAT + getDepthFormat( void ) + { + return DXGI_FORMAT_D24_UNORM_S8_UINT; + } + + static void + initDefaultMode( void ) + { + memset( &d3d11Globals.startMode, 0, sizeof( d3d11Globals.startMode ) ); + d3d11Globals.startMode.mode.Width = getClientWidth(); + d3d11Globals.startMode.mode.Height = getClientHeight(); + d3d11Globals.startMode.mode.Format = getColorFormat(); + d3d11Globals.startMode.mode.RefreshRate.Numerator = 60; + d3d11Globals.startMode.mode.RefreshRate.Denominator = 1; + d3d11Globals.startMode.flags = 0; + } + + static void + updateDefaultMode( void ) + { + if( d3d11Globals.modes == nil ) + return; + d3d11Globals.modes[ 0 ] = d3d11Globals.startMode; + } + + static void + addVideoMode( DXGI_MODE_DESC* mode ) + { + for( int32 i = 1; i < d3d11Globals.numModes; i++ ) + { + DXGI_MODE_DESC* current = &d3d11Globals.modes[ i ].mode; + if( current->Width == mode->Width && + current->Height == mode->Height && + current->Format == mode->Format ) + { + uint64 currentRefresh = + (uint64)current->RefreshRate.Numerator * mode->RefreshRate.Denominator; + uint64 newRefresh = + (uint64)mode->RefreshRate.Numerator * current->RefreshRate.Denominator; + if( newRefresh > currentRefresh ) + *current = *mode; + return; + } + } + + d3d11Globals.modes[ d3d11Globals.numModes ].mode = *mode; + d3d11Globals.modes[ d3d11Globals.numModes ].flags = VIDEOMODEEXCLUSIVE; + d3d11Globals.numModes++; + } + + static bool32 + makeVideoModeList( void ) + { + UINT modeCount = 0; + if( d3d11Globals.output &&FAILED( d3d11Globals.output->GetDisplayModeList(getColorFormat(), 0, &modeCount, nil ) ) ) + return 0; + + DXGI_MODE_DESC* modes = nil; + if( modeCount ) + { + modes = rwNewT( DXGI_MODE_DESC, modeCount,ID_DRIVER | MEMDUR_FUNCTION ); + if( FAILED( d3d11Globals.output->GetDisplayModeList(getColorFormat(), 0, &modeCount, modes ) ) ) + { + rwFree( modes ); + return 0; + } + } + + rwFree( d3d11Globals.modes ); + d3d11Globals.modes = rwNewT( DisplayMode, modeCount + 1,ID_DRIVER | MEMDUR_EVENT ); + d3d11Globals.numModes = 1; + d3d11Globals.currentMode = 0; + initDefaultMode(); + updateDefaultMode(); + + for( UINT i = 0; i < modeCount; i++ ) + addVideoMode( &modes[ i ] ); + rwFree( modes ); + return 1; + } + + static bool32 + createFactory( void ) + { + if( d3d11Globals.factory ) + return 1; + HRESULT hr = CreateDXGIFactory( __uuidof(IDXGIFactory), ( void** )&d3d11Globals.factory ); + return SUCCEEDED( hr ); + } + + static int + closeD3D11( void ) + { + termD3D11(); + rwFree( d3d11Globals.modes ); + d3d11Globals.modes = nil; + d3d11Globals.numModes = 0; + d3d11Globals.currentMode = 0; + safeRelease( d3d11Globals.output ); + for( int i = 0; i < d3d11Globals.numAdapters; i++ ) + safeRelease( d3d11Globals.adapters[ i ] ); + d3d11Globals.numAdapters = 0; + safeRelease( d3d11Globals.factory ); + d3d11Globals.window = nil; + return 1; + } + + static void + releaseDefaultViews( void ) + { + safeRelease( d3d11Globals.defaultRenderTarget ); + safeRelease( d3d11Globals.defaultDepthStencilView ); + } + + static bool32 + createDefaultViews( void ) + { + ID3D11Texture2D* backBuffer = nil; + ID3D11Texture2D* depthTex = nil; + HRESULT hr; + + hr = d3d11Globals.swapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D), ( void** )&backBuffer ); + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "IDXGISwapChain::GetBuffer() failed") ); + return 0; + } + hr = d3d11Globals.d3ddevice->CreateRenderTargetView( backBuffer, nil, &d3d11Globals.defaultRenderTarget ); + safeRelease( backBuffer ); + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "ID3D11Device::CreateRenderTargetView() failed") ); + return 0; + } + + D3D11_TEXTURE2D_DESC depthDesc; + memset( &depthDesc, 0, sizeof( depthDesc ) ); + depthDesc.Width = d3d11Globals.present.BufferDesc.Width; + depthDesc.Height = d3d11Globals.present.BufferDesc.Height; + depthDesc.MipLevels = 1; + depthDesc.ArraySize = 1; + depthDesc.Format = getDepthFormat(); + depthDesc.SampleDesc = d3d11Globals.present.SampleDesc; + depthDesc.Usage = D3D11_USAGE_DEFAULT; + depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + hr = d3d11Globals.d3ddevice->CreateTexture2D( &depthDesc, nil, &depthTex ); + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "ID3D11Device::CreateTexture2D() failed for depth") ); + return 0; + } + hr = d3d11Globals.d3ddevice->CreateDepthStencilView( depthTex, nil, &d3d11Globals.defaultDepthStencilView ); + safeRelease( depthTex ); + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "ID3D11Device::CreateDepthStencilView() failed") ); + return 0; + } + + d3d11Globals.context->OMSetRenderTargets( 1, &d3d11Globals.defaultRenderTarget, d3d11Globals.defaultDepthStencilView ); + return 1; + } + + static bool32 + resizeSwapChain( uint32 width, uint32 height ) + { + if( d3d11Globals.swapChain == nil ) + return 0; + if( width == 0 || height == 0 ) + return 1; + + d3d11Globals.context->OMSetRenderTargets( 0, nil, nil ); + releaseDefaultViews(); + + HRESULT hr = d3d11Globals.swapChain->ResizeBuffers( 1, width, height, d3d11Globals.present.BufferDesc.Format, d3d11Globals.present.Flags ); + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "IDXGISwapChain::ResizeBuffers() failed") ); + return 0; + } + d3d11Globals.present.BufferDesc.Width = width; + d3d11Globals.present.BufferDesc.Height = height; + initDefaultMode(); + updateDefaultMode(); + return createDefaultViews(); + } + + static void + ensureSwapChainSize( void ) + { + if( d3d11Globals.swapChain == nil ) + return; + uint32 width = getClientWidth(); + uint32 height = getClientHeight(); + if( width == 0 || height == 0 ) + return; + if( width != d3d11Globals.present.BufferDesc.Width || + height != d3d11Globals.present.BufferDesc.Height ) + resizeSwapChain( width, height ); + } + + static bool32 + openD3D11( EngineOpenParams* params ) + { + memset( &d3d11Globals, 0, sizeof( d3d11Globals ) ); + d3d11Globals.window = params->window; + d3d11Globals.msLevel = 1; + + if( !createFactory() ) + { + RWERROR( (ERR_GENERAL, "CreateDXGIFactory() failed") ); + return 0; + } + + for( int i = 0; i < MAX_D3D11_ADAPTERS; i++ ) + { + IDXGIAdapter* adapter = nil; + if( d3d11Globals.factory->EnumAdapters( i, &adapter ) == DXGI_ERROR_NOT_FOUND ) + break; + if( adapter == nil ) + break; + d3d11Globals.adapters[ d3d11Globals.numAdapters ] = adapter; + adapter->GetDesc( &d3d11Globals.adapterDescs[ d3d11Globals.numAdapters ] ); + d3d11Globals.numAdapters++; + } + if( d3d11Globals.numAdapters == 0 ) + { + RWERROR( (ERR_GENERAL, "No DXGI adapters found") ); + return 0; + } + + d3d11Globals.adapter = 0; + d3d11Globals.adapters[ d3d11Globals.adapter ]->EnumOutputs( 0, &d3d11Globals.output ); + + if( !makeVideoModeList() ) + { + RWERROR( (ERR_GENERAL, "IDXGIOutput::GetDisplayModeList() failed") ); + return 0; + } + + memset( &d3d11Globals.present, 0, sizeof( d3d11Globals.present ) ); + d3d11Globals.present.BufferDesc.Width = d3d11Globals.startMode.mode.Width; + d3d11Globals.present.BufferDesc.Height = d3d11Globals.startMode.mode.Height; + d3d11Globals.present.BufferDesc.RefreshRate = d3d11Globals.startMode.mode.RefreshRate; + d3d11Globals.present.BufferDesc.Format = getColorFormat(); + d3d11Globals.present.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + d3d11Globals.present.BufferCount = 1; + d3d11Globals.present.OutputWindow = d3d11Globals.window; + d3d11Globals.present.Windowed = TRUE; + d3d11Globals.present.SampleDesc.Count = 1; + d3d11Globals.present.SampleDesc.Quality = 0; + d3d11Globals.present.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + d3d11Globals.present.Flags = 0; + + return 1; + } + + static bool32 + startD3D11( void ) + { + HRESULT hr; + D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + + DXGI_MODE_DESC mode = d3d11Globals.modes[ d3d11Globals.currentMode ].mode; + bool32 windowed = !(d3d11Globals.modes[ d3d11Globals.currentMode ].flags & VIDEOMODEEXCLUSIVE); + uint32 width = windowed ? getClientWidth() : mode.Width; + uint32 height = windowed ? getClientHeight() : mode.Height; + if( width == 0 ) width = 1; + if( height == 0 ) height = 1; + + hr = D3D11CreateDevice( d3d11Globals.adapters[ d3d11Globals.adapter ], + D3D_DRIVER_TYPE_UNKNOWN, nil, flags, + levels, nelem( levels ), D3D11_SDK_VERSION, + &d3d11Globals.d3ddevice, &d3d11Globals.featureLevel, &d3d11Globals.context ); + if( FAILED( hr ) ) + { + hr = D3D11CreateDevice( nil, D3D_DRIVER_TYPE_HARDWARE, nil, flags, + levels, nelem( levels ), D3D11_SDK_VERSION, + &d3d11Globals.d3ddevice, &d3d11Globals.featureLevel, &d3d11Globals.context ); + } + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "D3D11CreateDevice() failed") ); + return 0; + } + + d3d11Globals.present.BufferDesc.Width = width; + d3d11Globals.present.BufferDesc.Height = height; + d3d11Globals.present.BufferDesc.Format = getColorFormat(); + d3d11Globals.present.BufferDesc.RefreshRate = mode.RefreshRate; + d3d11Globals.present.OutputWindow = d3d11Globals.window; + d3d11Globals.present.Windowed = windowed; + + uint32 requestedSamples = d3d11Globals.msLevel > 1 ? d3d11Globals.msLevel : 1; + uint32 quality = 0; + if( requestedSamples > 1 && + FAILED( d3d11Globals.d3ddevice->CheckMultisampleQualityLevels( getColorFormat(), requestedSamples, &quality ) ) ) + requestedSamples = 1; + if( requestedSamples > 1 && quality == 0 ) + requestedSamples = 1; + d3d11Globals.present.SampleDesc.Count = requestedSamples; + d3d11Globals.present.SampleDesc.Quality = requestedSamples > 1 ? quality - 1 : 0; + d3d11Globals.msLevel = requestedSamples; + + hr = d3d11Globals.factory->CreateSwapChain( d3d11Globals.d3ddevice, &d3d11Globals.present, &d3d11Globals.swapChain ); + if( FAILED( hr ) ) + { + RWERROR( (ERR_GENERAL, "IDXGIFactory::CreateSwapChain() failed") ); + return 0; + } + d3d11Globals.factory->MakeWindowAssociation( d3d11Globals.window, DXGI_MWA_NO_ALT_ENTER ); + return 1; + } + + static bool32 + initD3D11( void ) + { + memset( &deviceCache, 0, sizeof( deviceCache ) ); + d3d11Globals.numTextures = 0; + d3d11Globals.numVertexShaders = 0; + d3d11Globals.numPixelShaders = 0; + d3d11Globals.numVertexBuffers = 0; + d3d11Globals.numIndexBuffers = 0; + d3d11Globals.numInputLayouts = 0; + + if( !createDefaultViews() ) + return 0; + resetRenderState(); + if( !openClear() ) + return 0; + if( !openIm2D() ) + { + closeClear(); + return 0; + } + if( !openIm3D() ) + { + closeIm2D(); + closeClear(); + return 0; + } + if( !openDefaultRenderPipeline() ) + { + closeIm3D(); + closeIm2D(); + closeClear(); + return 0; + } + return 1; + } + + static int + termD3D11( void ) + { + closeDefaultRenderPipeline(); + closeIm3D(); + closeIm2D(); + closeClear(); + releaseDefaultViews(); + if( d3d11Globals.context ) + { + d3d11Globals.context->ClearState(); + d3d11Globals.context->Flush(); + } + safeRelease( d3d11Globals.swapChain ); + safeRelease( d3d11Globals.context ); + safeRelease( d3d11Globals.d3ddevice ); + return 1; + } + + static int + finalizeD3D11( void ) + { + return 1; + } + + static RasterLevels* + allocateLevels( int32 width, int32 height, int32 numlevels ) + { + if( numlevels <= 0 ) + numlevels = 1; + size_t size = sizeof( RasterLevels ) + sizeof( RasterLevels::Level ) * (numlevels - 1); + RasterLevels* levels = ( RasterLevels* )rwNew( size, MEMDUR_EVENT | ID_DRIVER ); + memset( levels, 0, size ); + levels->numlevels = numlevels; + levels->format = Raster::C8888; + for( int32 i = 0; i < numlevels; i++ ) + { + int32 w = width >> i; + int32 h = height >> i; + if( w < 1 ) w = 1; + if( h < 1 ) h = 1; + levels->levels[ i ].width = w; + levels->levels[ i ].height = h; + levels->levels[ i ].size = w * h * 4; + levels->levels[ i ].data = rwNewT( uint8, levels->levels[ i ].size, MEMDUR_EVENT | ID_DRIVER ); + memset( levels->levels[ i ].data, 0, levels->levels[ i ].size ); + } + return levels; + } + + static void + freeLevels( RasterLevels* levels ) + { + if( levels == nil ) + return; + for( int32 i = 0; i < levels->numlevels; i++ ) + rwFree( levels->levels[ i ].data ); + rwFree( levels ); + } + + static bool32 + createTextureResources( Raster* raster, bool32 renderTarget, int32 numLevels ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( numLevels < 1 ) + numLevels = 1; + D3D11_TEXTURE2D_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.Width = raster->width; + desc.Height = raster->height; + desc.MipLevels = numLevels; + desc.ArraySize = 1; + desc.Format = getColorFormat(); + desc.SampleDesc.Count = renderTarget ? 1 : 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | (renderTarget ? D3D11_BIND_RENDER_TARGET : 0); + + ID3D11Texture2D* texture = nil; + HRESULT hr = d3d11Globals.d3ddevice->CreateTexture2D( &desc, nil, &texture ); + if( FAILED( hr ) ) + return 0; + + ID3D11ShaderResourceView* srv = nil; + hr = d3d11Globals.d3ddevice->CreateShaderResourceView( texture, nil, &srv ); + if( FAILED( hr ) ) + { + safeRelease( texture ); + return 0; + } + + natras->texture = texture; + natras->srv = srv; + natras->format = desc.Format; + natras->bpp = 4; + natras->customFormat = 0; + natras->autogenMipmap = 0; + d3d11Globals.numTextures++; + + if( renderTarget ) + { + ID3D11RenderTargetView* rtv = nil; + hr = d3d11Globals.d3ddevice->CreateRenderTargetView( texture, nil, &rtv ); + if( FAILED( hr ) ) + { + safeRelease( ( ID3D11ShaderResourceView*& )natras->srv ); + safeRelease( ( ID3D11Texture2D*& )natras->texture ); + d3d11Globals.numTextures--; + return 0; + } + natras->rtv = rtv; + } + return 1; + } + + static bool32 + createDepthResources( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + D3D11_TEXTURE2D_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.Width = raster->width; + desc.Height = raster->height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = getDepthFormat(); + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + ID3D11Texture2D* texture = nil; + HRESULT hr = d3d11Globals.d3ddevice->CreateTexture2D( &desc, nil, &texture ); + if( FAILED( hr ) ) + return 0; + + ID3D11DepthStencilView* dsv = nil; + hr = d3d11Globals.d3ddevice->CreateDepthStencilView( texture, nil, &dsv ); + if( FAILED( hr ) ) + { + safeRelease( texture ); + return 0; + } + + natras->texture = texture; + natras->dsv = dsv; + return 1; + } + + static void + uploadRasterLevel( Raster* raster, int32 level ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + RasterLevels* levels = ( RasterLevels* )natras->lockedSurf; + if( levels == nil || natras->texture == nil ) + return; + if( level < 0 || level >= levels->numlevels ) + return; + d3d11Globals.context->UpdateSubresource( ( ID3D11Texture2D* )natras->texture, level, + nil, levels->levels[ level ].data, levels->levels[ level ].width * 4, 0 ); + } + + Raster* + rasterCreate( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + memset( natras, 0, sizeof( *natras ) ); + + if( raster->format == 0 ) + { + switch( raster->type ) + { + case Raster::ZBUFFER: + raster->format = Raster::D24; + break; + default: + raster->format = Raster::C8888; + break; + } + } + + if( raster->width == 0 || raster->height == 0 ) + { + raster->flags |= Raster::DONTALLOCATE; + raster->stride = 0; + goto done; + } + if( raster->flags & Raster::DONTALLOCATE ) + goto done; + + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + { + int32 numLevels = raster->format & Raster::MIPMAP ? + Raster::calculateNumLevels( raster->width, raster->height ) : 1; + raster->depth = 32; + raster->stride = raster->width * 4; + natras->hasAlpha = Raster::formatHasAlpha( raster->format ); + natras->bpp = 4; + natras->lockedSurf = allocateLevels( raster->width, raster->height, numLevels ); + if( !createTextureResources( raster, 0, numLevels ) ) + { + freeLevels( ( RasterLevels* )natras->lockedSurf ); + natras->lockedSurf = nil; + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + break; + } + case Raster::CAMERATEXTURE: + raster->depth = 32; + raster->stride = raster->width * 4; + natras->hasAlpha = 1; + if( !createTextureResources( raster, 1, 1 ) ) + { + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + break; + case Raster::CAMERA: + raster->depth = findFormatDepth11( getColorFormat() ); + raster->stride = raster->width * 4; + natras->bpp = 4; + natras->hasAlpha = 1; + natras->format = getColorFormat(); + break; + case Raster::ZBUFFER: + raster->depth = findFormatDepth11( getDepthFormat() ); + raster->stride = 0; + natras->format = getDepthFormat(); + if( raster->width != ( int32 )getClientWidth() || + raster->height != ( int32 )getClientHeight() ) + { + if( !createDepthResources( raster ) ) + { + RWERROR( (ERR_NOTEXTURE) ); + return nil; + } + } + break; + default: + RWERROR( (ERR_INVRASTER) ); + return nil; + } + +done: + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalStride = raster->stride; + raster->originalPixels = raster->pixels; + return raster; + } + + void + destroyRaster( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + for( uint32 i = 0; i < MAXNUMSTAGES; i++ ) + if( rwStateCache.texstage[ i ].raster == raster ) + rwStateCache.texstage[ i ].raster = nil; + + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + freeLevels( ( RasterLevels* )natras->lockedSurf ); + natras->lockedSurf = nil; + safeRelease( ( ID3D11ShaderResourceView*& )natras->srv ); + safeRelease( ( ID3D11Texture2D*& )natras->texture ); + break; + case Raster::CAMERATEXTURE: + safeRelease( ( ID3D11RenderTargetView*& )natras->rtv ); + safeRelease( ( ID3D11ShaderResourceView*& )natras->srv ); + safeRelease( ( ID3D11Texture2D*& )natras->texture ); + break; + case Raster::ZBUFFER: + safeRelease( ( ID3D11DepthStencilView*& )natras->dsv ); + safeRelease( ( ID3D11Texture2D*& )natras->texture ); + break; + case Raster::CAMERA: + default: + break; + } + natras->texture = nil; + natras->srv = nil; + natras->rtv = nil; + natras->dsv = nil; + natras->lockedSurf = nil; + } + + static ID3D11Texture2D* + getRasterTextureForReadback( Raster* raster ) + { + ID3D11Texture2D* texture = nil; + if( raster->type == Raster::CAMERA ) + { + if( d3d11Globals.defaultRenderTarget == nil ) + return nil; + ID3D11Resource* resource = nil; + d3d11Globals.defaultRenderTarget->GetResource( &resource ); + if( resource ) + { + resource->QueryInterface( + __uuidof(ID3D11Texture2D), (void**)&texture ); + resource->Release(); + } + } + else if( raster->type == Raster::CAMERATEXTURE ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster->parent ); + texture = (ID3D11Texture2D*)natras->texture; + if( texture ) + texture->AddRef(); + } + return texture; + } + + static ID3D11Texture2D* + createReadbackTexture( ID3D11Texture2D* source ) + { + D3D11_TEXTURE2D_DESC desc; + source->GetDesc( &desc ); + + ID3D11Texture2D* resolved = nil; + ID3D11Texture2D* copySource = source; + if( desc.SampleDesc.Count > 1 ) + { + D3D11_TEXTURE2D_DESC resolveDesc = desc; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + if( FAILED( d3d11Globals.d3ddevice->CreateTexture2D( + &resolveDesc, nil, &resolved ) ) ) + return nil; + d3d11Globals.context->ResolveSubresource( + resolved, 0, source, 0, desc.Format ); + copySource = resolved; + desc = resolveDesc; + } + + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + + ID3D11Texture2D* staging = nil; + if( SUCCEEDED( d3d11Globals.d3ddevice->CreateTexture2D( + &desc, nil, &staging ) ) ) + d3d11Globals.context->CopyResource( staging, copySource ); + if( resolved ) + resolved->Release(); + return staging; + } + + uint8* + rasterLock( Raster* raster, int32 level, int32 lockMode ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( raster->privateFlags & (Raster::PRIVATELOCK_READ | Raster::PRIVATELOCK_WRITE) ) + return nil; + + switch( raster->type ) + { + case Raster::NORMAL: + case Raster::TEXTURE: + { + RasterLevels* levels = ( RasterLevels* )natras->lockedSurf; + if( levels == nil || level >= levels->numlevels ) + return nil; + raster->pixels = levels->levels[ level ].data; + raster->width = levels->levels[ level ].width; + raster->height = levels->levels[ level ].height; + raster->stride = levels->levels[ level ].width * 4; + break; + } + case Raster::CAMERA: + case Raster::CAMERATEXTURE: + { + if( level != 0 || (lockMode & Raster::LOCKWRITE) ) + return nil; + ID3D11Texture2D* source = + getRasterTextureForReadback( raster ); + if( source == nil ) + return nil; + ID3D11Texture2D* staging = + createReadbackTexture( source ); + source->Release(); + if( staging == nil ) + return nil; + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( + staging, 0, D3D11_MAP_READ, 0, &mapped ) ) ) + { + staging->Release(); + return nil; + } + natras->lockedSurf = staging; + raster->pixels = (uint8*)mapped.pData + + raster->offsetY * mapped.RowPitch + + raster->offsetX * 4; + raster->stride = mapped.RowPitch; + break; + } + default: + return nil; + } + if( lockMode & Raster::LOCKREAD ) raster->privateFlags |= Raster::PRIVATELOCK_READ; + if( lockMode & Raster::LOCKWRITE ) raster->privateFlags |= Raster::PRIVATELOCK_WRITE; + return raster->pixels; + } + + void + rasterUnlock( Raster* raster, int32 level ) + { + if( raster->type == Raster::CAMERA || + raster->type == Raster::CAMERATEXTURE ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + ID3D11Texture2D* staging = + (ID3D11Texture2D*)natras->lockedSurf; + if( staging ) + { + d3d11Globals.context->Unmap( staging, 0 ); + staging->Release(); + natras->lockedSurf = nil; + } + } + else if( raster->privateFlags & Raster::PRIVATELOCK_WRITE ) + uploadRasterLevel( raster, level ); + + raster->width = raster->originalWidth; + raster->height = raster->originalHeight; + raster->stride = raster->originalStride; + raster->pixels = raster->originalPixels; + raster->privateFlags &= ~(Raster::PRIVATELOCK_READ | Raster::PRIVATELOCK_WRITE); + } + + int32 + rasterNumLevels( Raster* raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( raster->type == Raster::NORMAL || raster->type == Raster::TEXTURE ) + { + RasterLevels* levels = ( RasterLevels* )natras->lockedSurf; + return levels ? levels->numlevels : 1; + } + return 1; + } + + bool32 + imageFindRasterFormat( Image* img, int32 type, + int32* pWidth, int32* pHeight, int32* pDepth, int32* pFormat ) + { + int32 width = img->width; + int32 height = img->height; + int32 depth = img->depth; + int32 format; + + if( depth <= 8 ) + depth = 32; + + switch( depth ) + { + case 32: + format = img->hasAlpha() ? Raster::C8888 : Raster::C888; + depth = img->hasAlpha() ? 32 : 24; + break; + case 24: + format = Raster::C888; + break; + case 16: + format = Raster::C1555; + break; + default: + RWERROR( (ERR_INVRASTER) ); + return 0; + } + + *pWidth = width; + *pHeight = height; + *pDepth = depth; + *pFormat = format | type; + return 1; + } + + bool32 + rasterFromImage( Raster* raster, Image* image ) + { + if( (raster->type & 0xF) != Raster::TEXTURE ) + return 0; + + Image* truecolimg = nil; + if( image->depth <= 8 ) + { + truecolimg = Image::create( image->width, image->height, image->depth ); + truecolimg->pixels = image->pixels; + truecolimg->stride = image->stride; + truecolimg->palette = image->palette; + truecolimg->unpalettize(); + image = truecolimg; + } + + void (*conv)(uint8 * out, uint8 * in) = nil; + switch( image->depth ) + { + case 32: conv = conv_RGBA8888_from_RGBA8888; break; + case 24: conv = conv_RGBA8888_from_RGB888; break; + case 16: conv = conv_RGBA8888_from_ARGB1555; break; + default: + if( truecolimg ) + truecolimg->destroy(); + RWERROR( (ERR_INVRASTER) ); + return 0; + } + + D3dRaster* natras = GETD3DRASTEREXT( raster ); + natras->hasAlpha = image->hasAlpha(); + + bool unlock = false; + if( raster->pixels == nil ) + { + raster->lock( 0, Raster::LOCKWRITE | Raster::LOCKNOFETCH ); + unlock = true; + } + uint8* pixels = raster->pixels; + uint8* imgpixels = image->pixels; + for( int y = 0; y < image->height; y++ ) + { + uint8* imgrow = imgpixels; + uint8* rasrow = pixels; + for( int x = 0; x < image->width; x++ ) + { + conv( rasrow, imgrow ); + imgrow += image->bpp; + rasrow += 4; + } + imgpixels += image->stride; + pixels += raster->stride; + } + if( unlock ) + raster->unlock( 0 ); + if( truecolimg ) + truecolimg->destroy(); + return 1; + } + + Image* + rasterToImage( Raster* raster ) + { + bool unlock = false; + if( raster->pixels == nil ) + { + if( raster->lock( 0, Raster::LOCKREAD ) == nil ) + return nil; + unlock = true; + } + + Image* image = Image::create( raster->width, raster->height, 32 ); + image->allocate(); + for( int y = 0; y < raster->height; y++ ) + memcpy( image->pixels + y * image->stride, raster->pixels + y * raster->stride, raster->width * 4 ); + + if( unlock ) + raster->unlock( 0 ); + return image; + } + + static int + deviceSystem( DeviceReq req, void* arg, int32 n ) + { + VideoMode* rwmode; + switch( req ) + { + case DEVICEOPEN: + return openD3D11( ( EngineOpenParams* )arg ); + case DEVICECLOSE: + return closeD3D11(); + case DEVICEINIT: + return startD3D11() && initD3D11(); + case DEVICETERM: + return termD3D11(); + case DEVICEFINALIZE: + return finalizeD3D11(); + case DEVICEGETNUMSUBSYSTEMS: + return d3d11Globals.numAdapters; + case DEVICEGETCURRENTSUBSYSTEM: + return d3d11Globals.adapter; + case DEVICESETSUBSYSTEM: + if( n < 0 || n >= d3d11Globals.numAdapters ) + return 0; + d3d11Globals.adapter = n; + safeRelease( d3d11Globals.output ); + d3d11Globals.adapters[ n ]->EnumOutputs( 0, &d3d11Globals.output ); + return makeVideoModeList(); + case DEVICEGETSUBSSYSTEMINFO: + if( n < 0 || n >= d3d11Globals.numAdapters ) + return 0; + WideCharToMultiByte( CP_ACP, 0, d3d11Globals.adapterDescs[ n ].Description, -1, + (( SubSystemInfo* )arg)->name, sizeof( SubSystemInfo::name ), nil, nil ); + return 1; + case DEVICEGETNUMVIDEOMODES: + return d3d11Globals.numModes; + case DEVICEGETCURRENTVIDEOMODE: + return d3d11Globals.currentMode; + case DEVICESETVIDEOMODE: + if( n < 0 || n >= d3d11Globals.numModes ) + return 0; + d3d11Globals.currentMode = n; + return 1; + case DEVICEGETVIDEOMODEINFO: + if( d3d11Globals.modes == nil || n < 0 || n >= d3d11Globals.numModes ) + return 0; + rwmode = ( VideoMode* )arg; + rwmode->width = d3d11Globals.modes[ n ].mode.Width; + rwmode->height = d3d11Globals.modes[ n ].mode.Height; + rwmode->depth = findFormatDepth11( d3d11Globals.modes[ n ].mode.Format ); + rwmode->flags = d3d11Globals.modes[ n ].flags; + return 1; + case DEVICEGETMAXMULTISAMPLINGLEVELS: + return 8; + case DEVICEGETMULTISAMPLINGLEVELS: + return d3d11Globals.msLevel ? d3d11Globals.msLevel : 1; + case DEVICESETMULTISAMPLINGLEVELS: + d3d11Globals.msLevel = ( uint32 )n; + return 1; + default: + break; + } + return 1; + } + + static D3D11_BLEND blendMap[] = { + D3D11_BLEND_ZERO, + D3D11_BLEND_ZERO, + D3D11_BLEND_ONE, + D3D11_BLEND_SRC_COLOR, + D3D11_BLEND_INV_SRC_COLOR, + D3D11_BLEND_SRC_ALPHA, + D3D11_BLEND_INV_SRC_ALPHA, + D3D11_BLEND_DEST_ALPHA, + D3D11_BLEND_INV_DEST_ALPHA, + D3D11_BLEND_DEST_COLOR, + D3D11_BLEND_INV_DEST_COLOR, + D3D11_BLEND_SRC_ALPHA_SAT + }; + + static D3D11_TEXTURE_ADDRESS_MODE addressMap[] = { + D3D11_TEXTURE_ADDRESS_WRAP, + D3D11_TEXTURE_ADDRESS_WRAP, + D3D11_TEXTURE_ADDRESS_MIRROR, + D3D11_TEXTURE_ADDRESS_CLAMP, + D3D11_TEXTURE_ADDRESS_BORDER + }; + + static D3D11_FILTER + filterToD3D11( uint32 filter ) + { + switch( filter ) + { + case Texture::NEAREST: return D3D11_FILTER_MIN_MAG_MIP_POINT; + case Texture::LINEAR: return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + case Texture::MIPNEAREST: return D3D11_FILTER_MIN_MAG_MIP_POINT; + case Texture::MIPLINEAR: return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + case Texture::LINEARMIPNEAREST: return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + case Texture::LINEARMIPLINEAR: return D3D11_FILTER_MIN_MAG_MIP_LINEAR; + default: return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + } + } + + static void + setRasterStage( uint32 stage, Raster* raster ) + { + assert( stage < MAXNUMSTAGES ); + bool32 alpha = 0; + rwStateCache.texstage[ stage ].raster = raster; + if( raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + alpha = natras->hasAlpha; + } + if( stage == 0 && rwStateCache.textureAlpha != alpha ) + { + rwStateCache.textureAlpha = alpha; + blendDirty = 1; + alphaTestDirty = 1; + } + } + + static void + setVertexAlpha( bool32 enable ) + { + if( rwStateCache.vertexAlpha != enable ) + { + rwStateCache.vertexAlpha = enable; + blendDirty = 1; + alphaTestDirty = 1; + } + } + + static void + setDepthTest( bool32 enable ) + { + if( rwStateCache.ztest != enable ) + { + rwStateCache.ztest = enable; + depthDirty = 1; + } + } + + static void + setDepthWrite( bool32 enable ) + { + if( rwStateCache.zwrite != enable ) + { + rwStateCache.zwrite = enable; + depthDirty = 1; + } + } + + static void + setFilterMode( uint32 stage, uint32 filter ) + { + assert( stage < MAXNUMSTAGES ); + if( rwStateCache.texstage[ stage ].filter != ( Texture::FilterMode )filter ) + { + rwStateCache.texstage[ stage ].filter = ( Texture::FilterMode )filter; + samplerDirty[ stage ] = 1; + } + } + + static void + setAddressU( uint32 stage, uint32 addressing ) + { + assert( stage < MAXNUMSTAGES ); + if( rwStateCache.texstage[ stage ].addressingU != ( Texture::Addressing )addressing ) + { + rwStateCache.texstage[ stage ].addressingU = ( Texture::Addressing )addressing; + samplerDirty[ stage ] = 1; + } + } + + static void + setAddressV( uint32 stage, uint32 addressing ) + { + assert( stage < MAXNUMSTAGES ); + if( rwStateCache.texstage[ stage ].addressingV != ( Texture::Addressing )addressing ) + { + rwStateCache.texstage[ stage ].addressingV = ( Texture::Addressing )addressing; + samplerDirty[ stage ] = 1; + } + } + + void + setTexture( uint32 stage, Texture* texture ) + { + assert( stage < MAXNUMSTAGES ); + if( texture == nil ) + { + setRasterStage( stage, nil ); + return; + } + if( texture->raster ) + { + setFilterMode( stage, texture->getFilter() ); + setAddressU( stage, texture->getAddressU() ); + setAddressV( stage, texture->getAddressV() ); + } + setRasterStage( stage, texture->raster ); + } + + static void + resetRenderState( void ) + { + memset( &rwStateCache, 0, sizeof( rwStateCache ) ); + rwStateCache.srcblend = BLENDSRCALPHA; + rwStateCache.destblend = BLENDINVSRCALPHA; + rwStateCache.alphaFunc = ALPHAGREATEREQUAL; + rwStateCache.alphaRef = 10; + rwStateCache.zwrite = 1; + rwStateCache.ztest = 1; + rwStateCache.cullmode = CULLNONE; + for( uint32 i = 0; i < MAXNUMSTAGES; i++ ) + { + rwStateCache.texstage[ i ].addressingU = Texture::WRAP; + rwStateCache.texstage[ i ].addressingV = Texture::WRAP; + rwStateCache.texstage[ i ].filter = Texture::NEAREST; + samplerDirty[ i ] = 1; + } + rwStateCache.fogcolor = makeRGBA( 0, 0, 0, 255 ); + blendDirty = 1; + depthDirty = 1; + rasterizerDirty = 1; + alphaTestDirty = 1; + } + + static void + applyBlendState( void ) + { + if( !blendDirty ) + return; + safeRelease( blendState ); + D3D11_BLEND_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.RenderTarget[ 0 ].BlendEnable = rwStateCache.vertexAlpha || rwStateCache.textureAlpha; + desc.RenderTarget[ 0 ].SrcBlend = blendMap[ rwStateCache.srcblend ]; + desc.RenderTarget[ 0 ].DestBlend = blendMap[ rwStateCache.destblend ]; + desc.RenderTarget[ 0 ].BlendOp = D3D11_BLEND_OP_ADD; + desc.RenderTarget[ 0 ].SrcBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[ 0 ].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + desc.RenderTarget[ 0 ].BlendOpAlpha = D3D11_BLEND_OP_ADD; + desc.RenderTarget[ 0 ].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + if( SUCCEEDED( d3d11Globals.d3ddevice->CreateBlendState( &desc, &blendState ) ) ) + { + float blendFactor[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; + d3d11Globals.context->OMSetBlendState( blendState, blendFactor, 0xFFFFFFFF ); + } + blendDirty = 0; + } + + static void + applyDepthState( void ) + { + if( !depthDirty ) + return; + safeRelease( depthStencilState ); + D3D11_DEPTH_STENCIL_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.DepthEnable = rwStateCache.ztest || rwStateCache.zwrite; + desc.DepthWriteMask = rwStateCache.zwrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + desc.DepthFunc = rwStateCache.ztest ? D3D11_COMPARISON_LESS_EQUAL : D3D11_COMPARISON_ALWAYS; + desc.StencilEnable = FALSE; + if( SUCCEEDED( d3d11Globals.d3ddevice->CreateDepthStencilState( &desc, &depthStencilState ) ) ) + d3d11Globals.context->OMSetDepthStencilState( depthStencilState, 0 ); + depthDirty = 0; + } + + static void + applyRasterizerState( void ) + { + if( !rasterizerDirty ) + return; + safeRelease( rasterizerState ); + D3D11_RASTERIZER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.FillMode = D3D11_FILL_SOLID; + desc.FrontCounterClockwise = TRUE; + switch( rwStateCache.cullmode ) + { + case CULLBACK: desc.CullMode = D3D11_CULL_BACK; break; + case CULLFRONT: desc.CullMode = D3D11_CULL_FRONT; break; + case CULLNONE: + default: desc.CullMode = D3D11_CULL_NONE; break; + } + desc.DepthClipEnable = TRUE; + desc.MultisampleEnable = d3d11Globals.present.SampleDesc.Count > 1; + if( SUCCEEDED( d3d11Globals.d3ddevice->CreateRasterizerState( &desc, &rasterizerState ) ) ) + d3d11Globals.context->RSSetState( rasterizerState ); + rasterizerDirty = 0; + } + + static void + applySamplerState( void ) + { + for( uint32 i = 0; i < MAXNUMSTAGES; i++ ) + { + if( !samplerDirty[ i ] ) + continue; + safeRelease( samplerState[ i ] ); + D3D11_SAMPLER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.Filter = filterToD3D11( rwStateCache.texstage[ i ].filter ); + desc.AddressU = addressMap[ rwStateCache.texstage[ i ].addressingU ]; + desc.AddressV = addressMap[ rwStateCache.texstage[ i ].addressingV ]; + desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + desc.MaxLOD = D3D11_FLOAT32_MAX; + desc.MaxAnisotropy = 1; + desc.ComparisonFunc = D3D11_COMPARISON_NEVER; + if( SUCCEEDED( d3d11Globals.d3ddevice->CreateSamplerState( + &desc, &samplerState[ i ] ) ) ) + d3d11Globals.context->PSSetSamplers( + i, 1, &samplerState[ i ] ); + samplerDirty[ i ] = 0; + } + } + + static void + applyAlphaTestState( void ) + { + if( alphaTestConstantBuffer == nil ) + return; + if( alphaTestDirty ) + { + AlphaTestConstants constants; + constants.enabled = rwStateCache.vertexAlpha || rwStateCache.textureAlpha; + constants.function = rwStateCache.alphaFunc; + constants.reference = rwStateCache.alphaRef / 255.0f; + constants.padding = 0.0f; + d3d11Globals.context->UpdateSubresource( alphaTestConstantBuffer, 0, nil, + &constants, 0, 0 ); + alphaTestDirty = 0; + } + d3d11Globals.context->PSSetConstantBuffers( PSSlotD3D9States, 1, + &alphaTestConstantBuffer ); + } + + void + applyDrawState( void ) + { + applyBlendState(); + applyDepthState(); + applyRasterizerState(); + applySamplerState(); + applyAlphaTestState(); + + ID3D11ShaderResourceView* srvs[ MAXNUMSTAGES ] = { + whiteSRV, nil + }; + for( uint32 i = 0; i < MAXNUMSTAGES; i++ ) + { + Raster* raster = rwStateCache.texstage[ i ].raster; + if( raster ) + { + D3dRaster* natras = GETD3DRASTEREXT( raster ); + if( natras->srv ) + srvs[ i ] = ( ID3D11ShaderResourceView* )natras->srv; + } + } + d3d11Globals.context->PSSetShaderResources( + 0, MAXNUMSTAGES, srvs ); + } + + static bool32 + setIndicesNative( ID3D11Buffer* buffer ) + { + if( buffer == nil || d3d11Globals.context == nil ) + return 0; + + if( deviceCache.indices != buffer ) + { + deviceCache.indices = buffer; + d3d11Globals.context->IASetIndexBuffer( deviceCache.indices, + DXGI_FORMAT_R16_UINT, 0 ); + } + return 1; + } + + bool32 + setIndices( void* indexBuffer ) + { + return setIndicesNative( + ( ID3D11Buffer* )getD3D11IndexBuffer( indexBuffer ) ); + } + + void + clearIndices( void* buffer ) + { + if( buffer == nil || deviceCache.indices != buffer ) + return; + + deviceCache.indices = nil; + if( d3d11Globals.context ) + d3d11Globals.context->IASetIndexBuffer( nil, DXGI_FORMAT_R16_UINT, 0 ); + } + + static bool32 + setStreamSourceNative( int n, ID3D11Buffer* buffer, uint32 offset, uint32 stride ) + { + if( n < 0 || n >= MAXNUMSTREAMS || buffer == nil || + d3d11Globals.context == nil ) + return 0; + + if( deviceCache.vertexStreams[ n ].buffer != buffer || + deviceCache.vertexStreams[ n ].offset != offset || + deviceCache.vertexStreams[ n ].stride != stride ) + { + deviceCache.vertexStreams[ n ].buffer = ( ID3D11Buffer* )buffer; + deviceCache.vertexStreams[ n ].offset = offset; + deviceCache.vertexStreams[ n ].stride = stride; + UINT d3dStride = stride; + UINT d3dOffset = offset; + d3d11Globals.context->IASetVertexBuffers( n, 1, + &deviceCache.vertexStreams[ n ].buffer, + &d3dStride, &d3dOffset ); + } + return 1; + } + + bool32 + setStreamSource( int n, void* buffer, uint32 offset, uint32 stride ) + { + return setStreamSourceNative( n, + ( ID3D11Buffer* )getD3D11VertexBuffer( buffer ), offset, stride ); + } + + void + clearStreamSource( void* buffer ) + { + if( buffer == nil ) + return; + + for( int n = 0; n < MAXNUMSTREAMS; n++ ) + { + if( deviceCache.vertexStreams[ n ].buffer != buffer ) + continue; + + deviceCache.vertexStreams[ n ].buffer = nil; + deviceCache.vertexStreams[ n ].offset = 0; + deviceCache.vertexStreams[ n ].stride = 0; + if( d3d11Globals.context ) + { + ID3D11Buffer* nilBuffer = nil; + UINT zero = 0; + d3d11Globals.context->IASetVertexBuffers( n, 1, &nilBuffer, + &zero, &zero ); + } + } + } + + bool32 + setVertexDeclaration( void* declaration ) + { + ID3D11InputLayout* vertexDeclaration = + ( ID3D11InputLayout* )declaration; + if( vertexDeclaration == nil || d3d11Globals.context == nil ) + return 0; + + if( deviceCache.vertexDeclaration != vertexDeclaration ) + { + deviceCache.vertexDeclaration = vertexDeclaration; + d3d11Globals.context->IASetInputLayout( + deviceCache.vertexDeclaration ); + } + return 1; + } + + void + clearVertexDeclaration( void* declaration ) + { + if( declaration == nil || deviceCache.vertexDeclaration != declaration ) + return; + + deviceCache.vertexDeclaration = nil; + if( d3d11Globals.context ) + d3d11Globals.context->IASetInputLayout( nil ); + } + + bool32 + setVertexShader( void* shader ) + { + ID3D11VertexShader* vertexShader = ( ID3D11VertexShader* )shader; + if( vertexShader == nil || d3d11Globals.context == nil ) + return 0; + + if( deviceCache.vertexShader != vertexShader ) + { + deviceCache.vertexShader = vertexShader; + d3d11Globals.context->VSSetShader( deviceCache.vertexShader, nil, 0 ); + } + return 1; + } + + void + clearVertexShader( void* shader ) + { + if( shader == nil || deviceCache.vertexShader != shader ) + return; + + deviceCache.vertexShader = nil; + if( d3d11Globals.context ) + d3d11Globals.context->VSSetShader( nil, nil, 0 ); + } + + bool32 + setPixelShader( void* shader ) + { + ID3D11PixelShader* pixelShader = ( ID3D11PixelShader* )shader; + if( pixelShader == nil || d3d11Globals.context == nil ) + return 0; + + if( deviceCache.pixelShader != pixelShader ) + { + deviceCache.pixelShader = pixelShader; + d3d11Globals.context->PSSetShader( deviceCache.pixelShader, nil, 0 ); + } + return 1; + } + + void + clearPixelShader( void* shader ) + { + if( shader == nil || deviceCache.pixelShader != shader ) + return; + + deviceCache.pixelShader = nil; + if( d3d11Globals.context ) + d3d11Globals.context->PSSetShader( nil, nil, 0 ); + } + + static void + setRwRenderState( int32 state, void* pvalue ) + { + uint32 value = ( uint32 )( uintptr )pvalue; + switch( state ) + { + case TEXTURERASTER: setRasterStage( 0, ( Raster* )pvalue ); break; + case TEXTUREADDRESS: + setAddressU( 0, value ); + setAddressV( 0, value ); + break; + case TEXTUREADDRESSU: setAddressU( 0, value ); break; + case TEXTUREADDRESSV: setAddressV( 0, value ); break; + case TEXTUREFILTER: setFilterMode( 0, value ); break; + case VERTEXALPHA: setVertexAlpha( value != 0 ); break; + case SRCBLEND: + rwStateCache.srcblend = value; + blendDirty = 1; + break; + case DESTBLEND: + rwStateCache.destblend = value; + blendDirty = 1; + break; + case ZTESTENABLE: setDepthTest( value != 0 ); break; + case ZWRITEENABLE: setDepthWrite( value != 0 ); break; + case ALPHATESTFUNC: + if( rwStateCache.alphaFunc != value ) + { + rwStateCache.alphaFunc = value; + alphaTestDirty = 1; + } + break; + case ALPHATESTREF: + if( rwStateCache.alphaRef != value ) + { + rwStateCache.alphaRef = value; + alphaTestDirty = 1; + } + break; + case CULLMODE: + rwStateCache.cullmode = value; + rasterizerDirty = 1; + break; + case FOGENABLE: + rwStateCache.fogenable = value != 0; + break; + case FOGCOLOR: + rwStateCache.fogcolor.red = value; + rwStateCache.fogcolor.green = value >> 8; + rwStateCache.fogcolor.blue = value >> 16; + rwStateCache.fogcolor.alpha = value >> 24; + break; + default: + break; + } + } + + static void* + getRwRenderState( int32 state ) + { + uint32 val = 0; + switch( state ) + { + case TEXTURERASTER: + return rwStateCache.texstage[ 0 ].raster; + case TEXTUREADDRESS: + if( rwStateCache.texstage[ 0 ].addressingU == rwStateCache.texstage[ 0 ].addressingV ) + val = rwStateCache.texstage[ 0 ].addressingU; + break; + case TEXTUREADDRESSU: val = rwStateCache.texstage[ 0 ].addressingU; break; + case TEXTUREADDRESSV: val = rwStateCache.texstage[ 0 ].addressingV; break; + case TEXTUREFILTER: val = rwStateCache.texstage[ 0 ].filter; break; + case VERTEXALPHA: val = rwStateCache.vertexAlpha; break; + case SRCBLEND: val = rwStateCache.srcblend; break; + case DESTBLEND: val = rwStateCache.destblend; break; + case ZTESTENABLE: val = rwStateCache.ztest; break; + case ZWRITEENABLE: val = rwStateCache.zwrite; break; + case ALPHATESTFUNC: val = rwStateCache.alphaFunc; break; + case ALPHATESTREF: val = rwStateCache.alphaRef; break; + case CULLMODE: val = rwStateCache.cullmode; break; + case FOGENABLE: val = rwStateCache.fogenable; break; + case FOGCOLOR: + val = RWRGBAINT( rwStateCache.fogcolor.red, rwStateCache.fogcolor.green, + rwStateCache.fogcolor.blue, rwStateCache.fogcolor.alpha ); + break; + default: + break; + } + return ( void* )( uintptr )val; + } + + static void + getRenderSurfaces( Camera* cam, ID3D11RenderTargetView** rtv, + ID3D11DepthStencilView** dsv ) + { + *rtv = d3d11Globals.defaultRenderTarget; + *dsv = nil; + + Raster* fbuf = cam->frameBuffer; + assert( fbuf ); + if( fbuf && fbuf->parent ) + fbuf = fbuf->parent; + if( fbuf && fbuf->type == Raster::CAMERATEXTURE ) + { + D3dRaster* natras = GETD3DRASTEREXT( fbuf ); + if( natras->rtv ) + *rtv = ( ID3D11RenderTargetView* )natras->rtv; + } + + Raster* zbuf = cam->zBuffer; + if( zbuf ) + { + if( zbuf->parent ) + zbuf = zbuf->parent; + assert( zbuf->type == Raster::ZBUFFER ); + D3dRaster* natras = GETD3DRASTEREXT( zbuf ); + if( natras->dsv ) + *dsv = ( ID3D11DepthStencilView* )natras->dsv; + else + *dsv = d3d11Globals.defaultDepthStencilView; + } + } + + static void + setRenderSurfaces( Camera* cam ) + { + ID3D11RenderTargetView* rtv; + ID3D11DepthStencilView* dsv; + getRenderSurfaces( cam, &rtv, &dsv ); + + ID3D11ShaderResourceView* nullSRVs[ MAXNUMSTAGES ] = {}; + d3d11Globals.context->PSSetShaderResources( + 0, MAXNUMSTAGES, nullSRVs ); + d3d11Globals.context->OMSetRenderTargets( 1, &rtv, dsv ); + } + + static void + setViewport( Raster* fb ) + { + D3D11_VIEWPORT vp; + memset( &vp, 0, sizeof( vp ) ); + vp.TopLeftX = ( FLOAT )fb->offsetX; + vp.TopLeftY = ( FLOAT )fb->offsetY; + vp.Width = ( FLOAT )fb->width; + vp.Height = ( FLOAT )fb->height; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + d3d11Globals.context->RSSetViewports( 1, &vp ); + } + + static void + beginUpdate( Camera* cam ) + { + float view[ 16 ], proj[ 16 ]; + Matrix inv; + Matrix::invert( &inv, cam->getFrame()->getLTM() ); + + view[ 0 ] = -inv.right.x; + view[ 1 ] = inv.right.y; + view[ 2 ] = inv.right.z; + view[ 3 ] = 0.0f; + view[ 4 ] = -inv.up.x; + view[ 5 ] = inv.up.y; + view[ 6 ] = inv.up.z; + view[ 7 ] = 0.0f; + view[ 8 ] = -inv.at.x; + view[ 9 ] = inv.at.y; + view[ 10 ] = inv.at.z; + view[ 11 ] = 0.0f; + view[ 12 ] = -inv.pos.x; + view[ 13 ] = inv.pos.y; + view[ 14 ] = inv.pos.z; + view[ 15 ] = 1.0f; + memcpy( &cam->devView, view, sizeof( RawMatrix ) ); + + float32 invwx = 1.0f / cam->viewWindow.x; + float32 invwy = 1.0f / cam->viewWindow.y; + float32 invz = 1.0f / (cam->farPlane - cam->nearPlane); + memset( proj, 0, sizeof( proj ) ); + proj[ 0 ] = invwx; + proj[ 5 ] = invwy; + proj[ 8 ] = cam->viewOffset.x * invwx; + proj[ 9 ] = cam->viewOffset.y * invwy; + proj[ 12 ] = -proj[ 8 ]; + proj[ 13 ] = -proj[ 9 ]; + if( cam->projection == Camera::PERSPECTIVE ) + { + proj[ 10 ] = cam->farPlane * invz; + proj[ 11 ] = 1.0f; + proj[ 15 ] = 0.0f; + } + else + { + proj[ 10 ] = invz; + proj[ 11 ] = 0.0f; + proj[ 15 ] = 1.0f; + } + proj[ 14 ] = -cam->nearPlane * proj[ 10 ]; + memcpy( &cam->devProj, proj, sizeof( RawMatrix ) ); + + ensureSwapChainSize(); + setRenderSurfaces( cam ); + setViewport( cam->frameBuffer ); + } + + static void + endUpdate( Camera* cam ) + { + ( void )cam; + } + + static void + clearCamera( Camera* cam, RGBA* col, uint32 mode ) + { + ensureSwapChainSize(); + setRenderSurfaces( cam ); + setViewport( cam->frameBuffer ); + + ID3D11RenderTargetView* rtv; + ID3D11DepthStencilView* dsv; + getRenderSurfaces( cam, &rtv, &dsv ); + + Raster* targetRaster = cam->frameBuffer; + if( targetRaster && (targetRaster->flags & Raster::DONTALLOCATE) ) + { + clearRect( col, mode, dsv != nil ); + return; + } + + if( mode & Camera::CLEARIMAGE ) + { + float color[ 4 ]; + color[ 0 ] = col->red / 255.0f; + color[ 1 ] = col->green / 255.0f; + color[ 2 ] = col->blue / 255.0f; + color[ 3 ] = col->alpha / 255.0f; + d3d11Globals.context->ClearRenderTargetView( rtv, color ); + } + if( (mode & (Camera::CLEARZ | Camera::CLEARSTENCIL)) && dsv ) + { + UINT flags = 0; + if( mode & Camera::CLEARZ ) flags |= D3D11_CLEAR_DEPTH; + if( mode & Camera::CLEARSTENCIL ) flags |= D3D11_CLEAR_STENCIL; + d3d11Globals.context->ClearDepthStencilView( dsv, flags, 1.0f, 0 ); + } + } + + static void + showRaster( Raster* raster, uint32 flags ) + { + ( void )raster; + UINT interval = (flags & Raster::FLIPWAITVSYNCH) ? 1 : 0; + if( d3d11Globals.swapChain ) + d3d11Globals.swapChain->Present( interval, 0 ); + } + + static bool32 + rasterRenderFast( Raster* raster, int32 x, int32 y ) + { + ( void )raster; + ( void )x; + ( void )y; + return 0; + } + + static ID3DBlob* + compileShader( const char* src, const char* entry, const char* target ) + { + ID3DBlob* shader = nil; + ID3DBlob* errors = nil; + HRESULT hr = D3DCompile( src, strlen( src ), nil, nil, nil, entry, target, 0, 0, &shader, &errors ); + if( errors ) + { + fprintf( stderr, "%s\n", ( const char* )errors->GetBufferPointer() ); + errors->Release(); + } + if( FAILED( hr ) ) + return nil; + return shader; + } + + static bool32 + openClear( void ) + { + ID3DBlob* vsBlob = compileShader( clear_VS_d11_source, "main", "vs_4_0" ); + ID3DBlob* psBlob = compileShader( clear_PS_d11_source, "main", "ps_4_0" ); + if( vsBlob == nil || psBlob == nil ) + goto fail; + + if( FAILED( d3d11Globals.d3ddevice->CreateVertexShader( + vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nil, &clearVS ) ) ) + goto fail; + if( FAILED( d3d11Globals.d3ddevice->CreatePixelShader( + psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nil, &clearPS ) ) ) + goto fail; + d3d11Globals.numVertexShaders++; + d3d11Globals.numPixelShaders++; + + D3D11_BUFFER_DESC bufferDesc; + memset( &bufferDesc, 0, sizeof( bufferDesc ) ); + bufferDesc.ByteWidth = sizeof( ClearConstants ); + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( + &bufferDesc, nil, &clearConstantBuffer ) ) ) + goto fail; + + for( int32 i = 0; i < 2; i++ ) + { + D3D11_BLEND_DESC blendDesc; + memset( &blendDesc, 0, sizeof( blendDesc ) ); + blendDesc.RenderTarget[ 0 ].RenderTargetWriteMask = + i ? D3D11_COLOR_WRITE_ENABLE_ALL : 0; + if( FAILED( d3d11Globals.d3ddevice->CreateBlendState( + &blendDesc, &clearBlendState[ i ] ) ) ) + goto fail; + } + + for( int32 i = 0; i < 4; i++ ) + { + D3D11_DEPTH_STENCIL_DESC depthDesc; + memset( &depthDesc, 0, sizeof( depthDesc ) ); + depthDesc.DepthEnable = (i & 1) != 0; + depthDesc.DepthWriteMask = (i & 1) ? + D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + depthDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthDesc.StencilEnable = (i & 2) != 0; + depthDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + depthDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthDesc.BackFace = depthDesc.FrontFace; + if( FAILED( d3d11Globals.d3ddevice->CreateDepthStencilState( + &depthDesc, &clearDepthStencilState[ i ] ) ) ) + goto fail; + } + + D3D11_RASTERIZER_DESC rasterizerDesc; + memset( &rasterizerDesc, 0, sizeof( rasterizerDesc ) ); + rasterizerDesc.FillMode = D3D11_FILL_SOLID; + rasterizerDesc.CullMode = D3D11_CULL_NONE; + rasterizerDesc.DepthClipEnable = TRUE; + rasterizerDesc.MultisampleEnable = + d3d11Globals.present.SampleDesc.Count > 1; + if( FAILED( d3d11Globals.d3ddevice->CreateRasterizerState( + &rasterizerDesc, &clearRasterizerState ) ) ) + goto fail; + + vsBlob->Release(); + psBlob->Release(); + return 1; + +fail: + if( vsBlob ) vsBlob->Release(); + if( psBlob ) psBlob->Release(); + closeClear(); + return 0; + } + + static void + closeClear( void ) + { + safeRelease( clearRasterizerState ); + for( int32 i = 0; i < 4; i++ ) + safeRelease( clearDepthStencilState[ i ] ); + for( int32 i = 0; i < 2; i++ ) + safeRelease( clearBlendState[ i ] ); + safeRelease( clearConstantBuffer ); + safeRelease( clearPS ); + safeRelease( clearVS ); + } + + static void + clearRect( RGBA* color, uint32 mode, bool32 hasDepth ) + { + uint32 depthState = 0; + if( hasDepth && (mode & Camera::CLEARZ) ) + depthState |= 1; + if( hasDepth && (mode & Camera::CLEARSTENCIL) ) + depthState |= 2; + bool32 clearImage = (mode & Camera::CLEARIMAGE) != 0; + if( !clearImage && depthState == 0 ) + return; + + ClearConstants constants; + constants.color[ 0 ] = color->red / 255.0f; + constants.color[ 1 ] = color->green / 255.0f; + constants.color[ 2 ] = color->blue / 255.0f; + constants.color[ 3 ] = color->alpha / 255.0f; + d3d11Globals.context->UpdateSubresource( clearConstantBuffer, 0, nil, + &constants, 0, 0 ); + + float blendFactor[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; + d3d11Globals.context->OMSetBlendState( clearBlendState[ clearImage ], + blendFactor, 0xFFFFFFFF ); + d3d11Globals.context->OMSetDepthStencilState( + clearDepthStencilState[ depthState ], 0 ); + d3d11Globals.context->RSSetState( clearRasterizerState ); + d3d11Globals.context->IASetInputLayout( nil ); + d3d11Globals.context->IASetPrimitiveTopology( + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); + d3d11Globals.context->VSSetShader( clearVS, nil, 0 ); + d3d11Globals.context->PSSetShader( clearPS, nil, 0 ); + d3d11Globals.context->PSSetConstantBuffers( 0, 1, + &clearConstantBuffer ); + d3d11Globals.context->Draw( 3, 0 ); + + memset( &deviceCache, 0, sizeof( deviceCache ) ); + blendDirty = 1; + depthDirty = 1; + rasterizerDirty = 1; + } + + static bool32 + ensureDynamicVertexBuffer( uint32 bytes ) + { + if( im2dVertexBuffer && im2dVertexBufferSize >= bytes ) + return 1; + clearStreamSource( im2dVertexBuffer ); + safeRelease( im2dVertexBuffer ); + im2dVertexBufferSize = im2dVertexBufferSize ? im2dVertexBufferSize : 4096 * sizeof( Im2DVertex ); + while( im2dVertexBufferSize < bytes ) + im2dVertexBufferSize *= 2; + + D3D11_BUFFER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = im2dVertexBufferSize; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &im2dVertexBuffer ) ) ) + return 0; + return 1; + } + + static bool32 + ensureDynamicIndexBuffer( uint32 bytes ) + { + if( im2dIndexBuffer && im2dIndexBufferSize >= bytes ) + return 1; + clearIndices( im2dIndexBuffer ); + safeRelease( im2dIndexBuffer ); + im2dIndexBufferSize = im2dIndexBufferSize ? im2dIndexBufferSize : 8192 * sizeof( uint16 ); + while( im2dIndexBufferSize < bytes ) + im2dIndexBufferSize *= 2; + + D3D11_BUFFER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = im2dIndexBufferSize; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &im2dIndexBuffer ) ) ) + return 0; + return 1; + } + + static void + updateIm2DConstants( void ) + { + Camera* cam = engine->currentCamera; + if( cam == nil || cam->frameBuffer == nil ) + return; + Im2DConstants constants; + constants.xform[ 0 ] = 2.0f / cam->frameBuffer->width; + constants.xform[ 1 ] = -2.0f / cam->frameBuffer->height; + constants.xform[ 2 ] = -1.0f; + constants.xform[ 3 ] = 1.0f; + d3d11Globals.context->UpdateSubresource( im2dConstantBuffer, 0, nil, &constants, 0, 0 ); + d3d11Globals.context->VSSetConstantBuffers( VSlotObjects, 1, + &im2dConstantBuffer ); + } + + static D3D11_PRIMITIVE_TOPOLOGY + primitiveTypeToTopology( PrimitiveType primType ) + { + switch( primType ) + { + case PRIMTYPELINELIST: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + case PRIMTYPEPOLYLINE: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; + case PRIMTYPETRILIST: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + case PRIMTYPETRISTRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + case PRIMTYPEPOINTLIST: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + default: return D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + } + } + + static bool32 + prepareIm2DCommon( void ) + { + applyDrawState(); + updateIm2DConstants(); + if( !setVertexShader( im2dVS ) || !setPixelShader( im2dPS ) ) + return 0; + return setVertexDeclaration( im2dLayout ); + } + + static bool32 + openIm2D( void ) + { + ID3DBlob* vsBlob = compileShader( im2d_VS_d11_source, "main", "vs_4_0" ); + ID3DBlob* psBlob = compileShader( im2d_PS_d11_source, "main", "ps_4_0" ); + if( vsBlob == nil || psBlob == nil ) + { + if( vsBlob ) vsBlob->Release(); + if( psBlob ) psBlob->Release(); + return 0; + } + + if( FAILED( d3d11Globals.d3ddevice->CreateVertexShader( vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nil, &im2dVS ) ) ) + { + vsBlob->Release(); + psBlob->Release(); + return 0; + } + if( FAILED( d3d11Globals.d3ddevice->CreatePixelShader( psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nil, &im2dPS ) ) ) + { + vsBlob->Release(); + psBlob->Release(); + return 0; + } + d3d11Globals.numVertexShaders++; + d3d11Globals.numPixelShaders++; + + D3D11_INPUT_ELEMENT_DESC elements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof( Im2DVertex, color ), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof( Im2DVertex, u ), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + if( FAILED( d3d11Globals.d3ddevice->CreateInputLayout( elements, nelem( elements ), + vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &im2dLayout ) ) ) + { + vsBlob->Release(); + psBlob->Release(); + return 0; + } + d3d11Globals.numInputLayouts++; + vsBlob->Release(); + psBlob->Release(); + + D3D11_BUFFER_DESC cbd; + memset( &cbd, 0, sizeof( cbd ) ); + cbd.ByteWidth = sizeof( Im2DConstants ); + cbd.Usage = D3D11_USAGE_DEFAULT; + cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &cbd, nil, &im2dConstantBuffer ) ) ) + return 0; + cbd.ByteWidth = sizeof( AlphaTestConstants ); + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &cbd, nil, &alphaTestConstantBuffer ) ) ) + return 0; + + uint8 defaultPixelColor[ 4 ] = { 255, 255, 255, 255 }; + D3D11_TEXTURE2D_DESC td; + memset( &td, 0, sizeof( td ) ); + td.Width = 1; + td.Height = 1; + td.MipLevels = 1; + td.ArraySize = 1; + td.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + td.SampleDesc.Count = 1; + td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = D3D11_BIND_SHADER_RESOURCE; + D3D11_SUBRESOURCE_DATA initData = { defaultPixelColor, 4, 0 }; + if( FAILED( d3d11Globals.d3ddevice->CreateTexture2D( &td, &initData, &whiteTexture ) ) ) + return 0; + if( FAILED( d3d11Globals.d3ddevice->CreateShaderResourceView( whiteTexture, nil, &whiteSRV ) ) ) + return 0; + return 1; + } + + static void + closeIm2D( void ) + { + safeRelease( whiteSRV ); + safeRelease( whiteTexture ); + clearIndices( im2dIndexBuffer ); + safeRelease( im2dIndexBuffer ); + clearStreamSource( im2dVertexBuffer ); + safeRelease( im2dVertexBuffer ); + safeRelease( im2dConstantBuffer ); + safeRelease( alphaTestConstantBuffer ); + clearVertexDeclaration( im2dLayout ); + safeRelease( im2dLayout ); + clearPixelShader( im2dPS ); + safeRelease( im2dPS ); + clearVertexShader( im2dVS ); + safeRelease( im2dVS ); + im2dVertexBufferSize = 0; + im2dIndexBufferSize = 0; + } + + static bool32 + openIm3D( void ) + { + D3D11_INPUT_ELEMENT_DESC elements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof( Im3DVertex, position ), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof( Im3DVertex, normal ), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof( Im3DVertex, color ), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof( Im3DVertex, u ), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + D3D11_BUFFER_DESC desc; + + ID3DBlob* vsBlob = compileShader( im3d_VS_d11_source, "main", "vs_4_0" ); + ID3DBlob* psBlob = compileShader( im3d_PS_d11_source, "main", "ps_4_0" ); + ID3DBlob* texPsBlob = compileShader( im3d_tex_PS_d11_source, "main", "ps_4_0" ); + if( vsBlob == nil || psBlob == nil || texPsBlob == nil ) + goto fail; + + if( FAILED( d3d11Globals.d3ddevice->CreateVertexShader( vsBlob->GetBufferPointer(), + vsBlob->GetBufferSize(), nil, &im3dVS ) ) ) + goto fail; + if( FAILED( d3d11Globals.d3ddevice->CreatePixelShader( psBlob->GetBufferPointer(), + psBlob->GetBufferSize(), nil, &im3dPS ) ) ) + goto fail; + if( FAILED( d3d11Globals.d3ddevice->CreatePixelShader( texPsBlob->GetBufferPointer(), + texPsBlob->GetBufferSize(), nil, &im3dTexPS ) ) ) + goto fail; + d3d11Globals.numVertexShaders++; + d3d11Globals.numPixelShaders += 2; + + if( FAILED( d3d11Globals.d3ddevice->CreateInputLayout( elements, nelem( elements ), + vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &im3dLayout ) ) ) + goto fail; + d3d11Globals.numInputLayouts++; + + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = sizeof( Im3DConstants ); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &im3dConstantBuffer ) ) ) + goto fail; + + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = im3dMaxVertices * sizeof( Im3DVertex ); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &im3dVertexBuffer ) ) ) + goto fail; + + desc.ByteWidth = im3dMaxIndices * sizeof( uint16 ); + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( &desc, nil, &im3dIndexBuffer ) ) ) + goto fail; + + vsBlob->Release(); + psBlob->Release(); + texPsBlob->Release(); + return 1; + +fail: + if( vsBlob ) vsBlob->Release(); + if( psBlob ) psBlob->Release(); + if( texPsBlob ) texPsBlob->Release(); + closeIm3D(); + return 0; + } + + static void + closeIm3D( void ) + { + clearIndices( im3dIndexBuffer ); + safeRelease( im3dIndexBuffer ); + clearStreamSource( im3dVertexBuffer ); + safeRelease( im3dVertexBuffer ); + safeRelease( im3dConstantBuffer ); + clearVertexDeclaration( im3dLayout ); + safeRelease( im3dLayout ); + clearPixelShader( im3dTexPS ); + safeRelease( im3dTexPS ); + clearPixelShader( im3dPS ); + safeRelease( im3dPS ); + clearVertexShader( im3dVS ); + safeRelease( im3dVS ); + num3DVertices = 0; + } + + static void + uploadMatrices( void ) + { + RawMatrix combined, identity; + Camera* cam = engine->currentCamera; + RawMatrix::setIdentity( &identity ); + RawMatrix::mult( &combined, &cam->devView, &cam->devProj ); + + Im3DConstants constants; + memcpy( constants.combined, &combined, sizeof( combined ) ); + memcpy( constants.world, &identity, sizeof( identity ) ); + memcpy( constants.normal, &identity, sizeof( identity ) ); + constants.viewportOffset[ 0 ] = 1.0f / cam->frameBuffer->width; + constants.viewportOffset[ 1 ] = 1.0f / cam->frameBuffer->height; + constants.viewportOffset[ 2 ] = 0.0f; + constants.viewportOffset[ 3 ] = 0.0f; + d3d11Globals.context->UpdateSubresource( im3dConstantBuffer, 0, nil, + &constants, 0, 0 ); + d3d11Globals.context->VSSetConstantBuffers( VSlotObjects, 1, + &im3dConstantBuffer ); + } + + static void + uploadMatrices( Matrix* world ) + { + RawMatrix combined, worldMatrix, worldView; + Camera* cam = engine->currentCamera; + convMatrix( &worldMatrix, world ); + RawMatrix::mult( &worldView, &worldMatrix, &cam->devView ); + RawMatrix::mult( &combined, &worldView, &cam->devProj ); + + Im3DConstants constants; + memcpy( constants.combined, &combined, sizeof( combined ) ); + memcpy( constants.world, &worldMatrix, sizeof( worldMatrix ) ); + // TODO: use the inverse transpose of worldMatrix for normals. + memcpy( constants.normal, &worldMatrix, sizeof( worldMatrix ) ); + constants.viewportOffset[ 0 ] = 1.0f / cam->frameBuffer->width; + constants.viewportOffset[ 1 ] = 1.0f / cam->frameBuffer->height; + constants.viewportOffset[ 2 ] = 0.0f; + constants.viewportOffset[ 3 ] = 0.0f; + d3d11Globals.context->UpdateSubresource( im3dConstantBuffer, 0, nil, + &constants, 0, 0 ); + d3d11Globals.context->VSSetConstantBuffers( VSlotObjects, 1, + &im3dConstantBuffer ); + } + + static void + im3DTransform( void* vertices, int32 numVertices, Matrix* world, uint32 flags ) + { + Camera* cam = engine->currentCamera; + if( cam == nil || vertices == nil || numVertices <= 0 || + ( uint32 )numVertices > im3dMaxVertices ) + return; + + if( world == nil ) + uploadMatrices(); + else + uploadMatrices( world ); + + if( (flags & im3d::VERTEXUV) == 0 ) + SetRenderStatePtr( TEXTURERASTER, nil ); + + ID3D11VertexShader* shader = im3dVS; + if( flags & im3d::LIGHTING ) + { + // TODO: follow D3D9 and select dedicated Im3D lighting variants. + } + else + { + // TODO: upload the unlit material constants. + } + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( im3dVertexBuffer, 0, + D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return; + memcpy( mapped.pData, vertices, numVertices * sizeof( Im3DVertex ) ); + d3d11Globals.context->Unmap( im3dVertexBuffer, 0 ); + + if( !setStreamSourceNative( 0, im3dVertexBuffer, 0, sizeof( Im3DVertex ) ) ) + return; + if( !setVertexDeclaration( im3dLayout ) ) + return; + if( !setVertexShader( shader ) ) + return; + + num3DVertices = numVertices; + } + + static void + im3DRenderPrimitive( PrimitiveType primType ) + { + if( num3DVertices <= 0 ) + return; + if( primType == PRIMTYPETRIFAN ) + { + if( num3DVertices < 3 ) + return; + int32 numIndices = (num3DVertices - 2) * 3; + if( ( uint32 )numIndices > im3dMaxIndices ) + return; + uint16* indices = rwNewT( uint16, numIndices, MEMDUR_FUNCTION | ID_DRIVER ); + for( int32 i = 0; i < num3DVertices - 2; i++ ) + { + indices[ i * 3 + 0 ] = 0; + indices[ i * 3 + 1 ] = i + 1; + indices[ i * 3 + 2 ] = i + 2; + } + d3d11::im3DRenderIndexedPrimitive( PRIMTYPETRILIST, indices, numIndices ); + rwFree( indices ); + return; + } + + D3D11_PRIMITIVE_TOPOLOGY topology = primitiveTypeToTopology( primType ); + if( topology == D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED ) + return; + + ID3D11PixelShader* shader; + if( engine->device.getRenderState( TEXTURERASTER ) ) + shader = im3dTexPS; + else + shader = im3dPS; + + applyDrawState(); + if( !setPixelShader( shader ) ) + return; + d3d11Globals.context->IASetPrimitiveTopology( topology ); + d3d11Globals.context->Draw( num3DVertices, 0 ); + } + + static void + im3DRenderIndexedPrimitive( PrimitiveType primType, void* indices, int32 numIndices ) + { + if( num3DVertices <= 0 || indices == nil || numIndices <= 0 ) + return; + if( primType == PRIMTYPETRIFAN ) + { + if( numIndices < 3 ) + return; + int32 outCount = (numIndices - 2) * 3; + if( ( uint32 )outCount > im3dMaxIndices ) + return; + uint16* out = rwNewT( uint16, outCount, MEMDUR_FUNCTION | ID_DRIVER ); + uint16* in = ( uint16* )indices; + for( int32 i = 0; i < numIndices - 2; i++ ) + { + out[ i * 3 + 0 ] = in[ 0 ]; + out[ i * 3 + 1 ] = in[ i + 1 ]; + out[ i * 3 + 2 ] = in[ i + 2 ]; + } + d3d11::im3DRenderIndexedPrimitive( PRIMTYPETRILIST, out, outCount ); + rwFree( out ); + return; + } + if( ( uint32 )numIndices > im3dMaxIndices ) + return; + + D3D11_PRIMITIVE_TOPOLOGY topology = primitiveTypeToTopology( primType ); + if( topology == D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED ) + return; + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( im3dIndexBuffer, 0, + D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return; + memcpy( mapped.pData, indices, numIndices * sizeof( uint16 ) ); + d3d11Globals.context->Unmap( im3dIndexBuffer, 0 ); + + ID3D11PixelShader* shader; + if( engine->device.getRenderState( TEXTURERASTER ) ) + shader = im3dTexPS; + else + shader = im3dPS; + + applyDrawState(); + if( !setPixelShader( shader ) ) + return; + d3d11Globals.context->IASetPrimitiveTopology( topology ); + if( !setIndicesNative( im3dIndexBuffer ) ) + return; + d3d11Globals.context->DrawIndexed( numIndices, 0, 0 ); + } + + static void + im3DEnd( void ) + {} + + static void + im2DRenderLine( void* vertices, int32 numVertices, int32 vert1, int32 vert2 ) + { + Im2DVertex tmp[ 2 ]; + Im2DVertex* verts = ( Im2DVertex* )vertices; + tmp[ 0 ] = verts[ vert1 ]; + tmp[ 1 ] = verts[ vert2 ]; + d3d11::im2DRenderPrimitive( PRIMTYPELINELIST, tmp, 2 ); + } + + static void + im2DRenderTriangle( void* vertices, int32 numVertices, int32 vert1, int32 vert2, int32 vert3 ) + { + Im2DVertex tmp[ 3 ]; + Im2DVertex* verts = ( Im2DVertex* )vertices; + tmp[ 0 ] = verts[ vert1 ]; + tmp[ 1 ] = verts[ vert2 ]; + tmp[ 2 ] = verts[ vert3 ]; + d3d11::im2DRenderPrimitive( PRIMTYPETRILIST, tmp, 3 ); + } + + static void + im2DRenderPrimitive( PrimitiveType primType, void* vertices, int32 numVertices ) + { + if( primType == PRIMTYPETRIFAN ) + { + if( numVertices < 3 ) + return; + int32 numIndices = (numVertices - 2) * 3; + uint16* indices = rwNewT( uint16, numIndices, MEMDUR_FUNCTION | ID_DRIVER ); + for( int32 i = 0; i < numVertices - 2; i++ ) + { + indices[ i * 3 + 0 ] = 0; + indices[ i * 3 + 1 ] = i + 1; + indices[ i * 3 + 2 ] = i + 2; + } + d3d11::im2DRenderIndexedPrimitive( PRIMTYPETRILIST, vertices, numVertices, indices, numIndices ); + rwFree( indices ); + return; + } + + D3D11_PRIMITIVE_TOPOLOGY topology = primitiveTypeToTopology( primType ); + if( topology == D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED ) + return; + uint32 bytes = numVertices * sizeof( Im2DVertex ); + if( !ensureDynamicVertexBuffer( bytes ) ) + return; + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( im2dVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return; + memcpy( mapped.pData, vertices, bytes ); + d3d11Globals.context->Unmap( im2dVertexBuffer, 0 ); + + if( !prepareIm2DCommon() ) + return; + d3d11Globals.context->IASetPrimitiveTopology( topology ); + if( !setStreamSourceNative( 0, im2dVertexBuffer, 0, sizeof( Im2DVertex ) ) ) + return; + d3d11Globals.context->Draw( numVertices, 0 ); + } + + static void + im2DRenderIndexedPrimitive( PrimitiveType primType, void* vertices, int32 numVertices, void* indices, int32 numIndices ) + { + if( primType == PRIMTYPETRIFAN ) + { + if( numIndices < 3 ) + return; + int32 outCount = (numIndices - 2) * 3; + uint16* out = rwNewT( uint16, outCount, MEMDUR_FUNCTION | ID_DRIVER ); + uint16* in = ( uint16* )indices; + for( int32 i = 0; i < numIndices - 2; i++ ) + { + out[ i * 3 + 0 ] = in[ 0 ]; + out[ i * 3 + 1 ] = in[ i + 1 ]; + out[ i * 3 + 2 ] = in[ i + 2 ]; + } + d3d11::im2DRenderIndexedPrimitive( PRIMTYPETRILIST, vertices, numVertices, out, outCount ); + rwFree( out ); + return; + } + + D3D11_PRIMITIVE_TOPOLOGY topology = primitiveTypeToTopology( primType ); + if( topology == D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED ) + return; + uint32 vbytes = numVertices * sizeof( Im2DVertex ); + uint32 ibytes = numIndices * sizeof( uint16 ); + if( !ensureDynamicVertexBuffer( vbytes ) || !ensureDynamicIndexBuffer( ibytes ) ) + return; + + D3D11_MAPPED_SUBRESOURCE mapped; + if( FAILED( d3d11Globals.context->Map( im2dVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return; + memcpy( mapped.pData, vertices, vbytes ); + d3d11Globals.context->Unmap( im2dVertexBuffer, 0 ); + if( FAILED( d3d11Globals.context->Map( im2dIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped ) ) ) + return; + memcpy( mapped.pData, indices, ibytes ); + d3d11Globals.context->Unmap( im2dIndexBuffer, 0 ); + + if( !prepareIm2DCommon() ) + return; + d3d11Globals.context->IASetPrimitiveTopology( topology ); + if( !setStreamSourceNative( 0, im2dVertexBuffer, 0, sizeof( Im2DVertex ) ) ) + return; + if( !setIndicesNative( im2dIndexBuffer ) ) + return; + d3d11Globals.context->DrawIndexed( numIndices, 0, 0 ); + } + + Device renderdevice = { + 0.0f, 1.0f, + d3d11::beginUpdate, + d3d11::endUpdate, + d3d11::clearCamera, + d3d11::showRaster, + d3d11::rasterRenderFast, + d3d11::setRwRenderState, + d3d11::getRwRenderState, + d3d11::im2DRenderLine, + d3d11::im2DRenderTriangle, + d3d11::im2DRenderPrimitive, + d3d11::im2DRenderIndexedPrimitive, + d3d11::im3DTransform, + d3d11::im3DRenderPrimitive, + d3d11::im3DRenderIndexedPrimitive, + d3d11::im3DEnd, + d3d11::deviceSystem + }; + + } +} + +#endif diff --git a/src/d3d/d3d11matfx.cpp b/src/d3d/d3d11matfx.cpp new file mode 100644 index 00000000..4c16f53f --- /dev/null +++ b/src/d3d/d3d11matfx.cpp @@ -0,0 +1,453 @@ +#include +#include +#include +#include + +#define WITH_D3D +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwanim.h" +#include "../rwengine.h" +#include "../rwrender.h" +#include "../rwplugins.h" +#include "rwd3d.h" +#include "rwd3d11.h" + +#ifdef RW_D3D11 +#include + +#include "rwd3dimpl.h" +#include "matfx_env_VS_d11.h" +#include "matfx_env_PS_d11.h" +#endif + +namespace rw +{ + namespace d3d11 + { + using namespace d3d; + + #ifndef RW_D3D11 + void matfxRenderCB_Shader( Atomic* atomic, InstanceDataHeader* header ) {} + #else + + static ID3D11VertexShader* matfx_env_amb_VS; + static ID3D11VertexShader* matfx_env_amb_dir_VS; + static ID3D11VertexShader* matfx_env_all_VS; + static ID3D11PixelShader* matfx_env_PS; + static ID3D11PixelShader* matfx_env_tex_PS; + static ID3D11Buffer* matfxVSConstantBuffer; + static ID3D11Buffer* matfxPSConstantBuffer; + + struct MatFXVSConstants + { + float texMat[ 16 ]; + float colorClamp[ 4 ]; + float envColor[ 4 ]; + }; + + struct MatFXPSConstants + { + float shininess; + float disableFBA; + float unused[ 2 ]; + }; + + static MatFXVSConstants matfxVSConstants; + void destroyMatFXShaders( void ); + void destroyMatFXConstantBuffers( void ); + + enum + { + VSLOC_texMat = VSLOC_afterLights, + VSLOC_colorClamp = VSLOC_texMat + 4, + VSLOC_envColor, + + PSLOC_shininess = 1, + }; + + void + matfxRender_Default( InstanceDataHeader* header, InstanceData* inst, int32 lightBits ) + { + Material* m = inst->material; + + setDefaultVertexShader( lightBits ); + SetRenderState( VERTEXALPHA, + inst->vertexAlpha || m->color.alpha != 255 ); + setTexture( 0, m->texture ); + setDefaultPixelShader(); + drawInst( header, inst ); + } + + static Frame* lastEnvFrame; + + static RawMatrix normal2texcoord = { + { 0.5f, 0.0f, 0.0f }, 0.0f, + { 0.0f, -0.5f, 0.0f }, 0.0f, + { 0.0f, 0.0f, 1.0f }, 0.0f, + { 0.5f, 0.5f, 0.0f }, 1.0f + }; + + void + uploadEnvMatrix( Frame* frame ) + { + Matrix invMat; + if( frame == nil ) + frame = engine->currentCamera->getFrame(); + + RawMatrix envMtx, invMtx; + Matrix::invert( &invMat, frame->getLTM() ); + convMatrix( &invMtx, &invMat ); + invMtx.pos.set( 0.0f, 0.0f, 0.0f ); + float uscale = fabs( normal2texcoord.right.x ); + normal2texcoord.right.x = MatFX::envMapFlipU ? -uscale : uscale; + RawMatrix::mult( &envMtx, &invMtx, &normal2texcoord ); + + memcpy( matfxVSConstants.texMat, &envMtx, sizeof( envMtx ) ); + d3d11Globals.context->UpdateSubresource( matfxVSConstantBuffer, 0, nil, &matfxVSConstants, 0, 0 ); + d3d11Globals.context->VSSetConstantBuffers( VSlotMatFX, 1, &matfxVSConstantBuffer ); + } + + void + matfxRender_EnvMap( InstanceDataHeader* header, InstanceData* inst, int32 lightBits, MatFX::Env* env ) + { + Material* m = inst->material; + + if( env->tex == nil || env->coefficient == 0.0f ) + { + matfxRender_Default( header, inst, lightBits ); + return; + } + + setTexture( 1, env->tex ); + uploadEnvMatrix( env->frame ); + + SetRenderState( SRCBLEND, BLENDONE ); + + MatFXPSConstants fxparams; + fxparams.shininess = env->coefficient; + fxparams.disableFBA = env->fbAlpha ? 0.0f : 1.0f; + fxparams.unused[ 0 ] = 0.0f; + fxparams.unused[ 1 ] = 0.0f; + d3d11Globals.context->UpdateSubresource( + matfxPSConstantBuffer, 0, nil, &fxparams, 0, 0 ); + d3d11Globals.context->PSSetConstantBuffers( + PSSlotMatFX, 1, &matfxPSConstantBuffer ); + + float clamp = MatFX::envMapApplyLight ? 0.0f : 1.0f; + for( int32 i = 0; i < 4; i++ ) + matfxVSConstants.colorClamp[ i ] = clamp; + + RGBAf envColor; + if( MatFX::envMapUseMatColor ) + convColor( &envColor, &m->color ); + else + convColor( &envColor, &MatFX::envMapColor ); + memcpy( matfxVSConstants.envColor, &envColor, + sizeof( envColor ) ); + d3d11Globals.context->UpdateSubresource( + matfxVSConstantBuffer, 0, nil, &matfxVSConstants, 0, 0 ); + d3d11Globals.context->VSSetConstantBuffers( + VSlotMatFX, 1, &matfxVSConstantBuffer ); + + if( (lightBits & VSLIGHT_MASK) == 0 ) + setVertexShader( matfx_env_amb_VS ); + else if( (lightBits & VSLIGHT_MASK) == VSLIGHT_DIRECT ) + setVertexShader( matfx_env_amb_dir_VS ); + else + setVertexShader( matfx_env_all_VS ); + + bool32 texAlpha = GETD3DRASTEREXT( env->tex->raster )->hasAlpha; + setTexture( 0, m->texture ); + if( m->texture ) + setPixelShader( matfx_env_tex_PS ); + else + setPixelShader( matfx_env_PS ); + + SetRenderState( VERTEXALPHA, + texAlpha || inst->vertexAlpha || m->color.alpha != 255 ); + drawInst( header, inst ); + + SetRenderState( SRCBLEND, BLENDSRCALPHA ); + } + + void + matfxRenderCB_Shader( Atomic* atomic, InstanceDataHeader* header ) + { + if( !setStreamSource( 0, + header->vertexStream[ 0 ].vertexBuffer, 0, + header->vertexStream[ 0 ].stride ) ) + return; + if( !setIndices( header->indexBuffer ) ) + return; + if( !setDefaultVertexDeclaration() ) + return; + + d3d11Globals.context->IASetPrimitiveTopology( + (D3D11_PRIMITIVE_TOPOLOGY)header->primType ); + + lastEnvFrame = nil; + + int32 lightBits = lightingCB_Shader( atomic ); + if( !uploadDefaultMatrices( atomic->getFrame()->getLTM() ) ) + return; + + uint32 flags = atomic->geometry->flags; + bool32 normals = (flags & Geometry::NORMALS) != 0; + static const RGBA white = { 255, 255, 255, 255 }; + + InstanceData* inst = header->inst; + for( uint32 i = 0; i < header->numMeshes; i++, inst++ ) + { + Material* m = inst->material; + uploadDefaultMaterial( + (flags & Geometry::MODULATE) ? m->color : white, + m->surfaceProps ); + + MatFX* matfx = MatFX::get( m ); + if( matfx == nil ) + matfxRender_Default( header, inst, lightBits ); + else switch( matfx->type ) + { + case MatFX::ENVMAP: + if( normals ) + matfxRender_EnvMap( + header, inst, lightBits, &matfx->fx[ 0 ].env ); + else + matfxRender_Default( header, inst, lightBits ); + break; + case MatFX::NOTHING: + case MatFX::BUMPMAP: + case MatFX::BUMPENVMAP: + case MatFX::DUAL: + case MatFX::UVTRANSFORM: + case MatFX::DUALUVTRANSFORM: + matfxRender_Default( header, inst, lightBits ); + break; + } + } + setTexture( 1, nil ); + } + + static ID3DBlob* + compileMatFXShader( const char* source, const char* target, + const D3D_SHADER_MACRO* defines = nil ) + { + ID3DBlob* shader = nil; + ID3DBlob* errors = nil; + HRESULT hr = D3DCompile( source, strlen( source ), nil, defines, nil, + "main", target, 0, 0, &shader, &errors ); + if( errors ) + { + fprintf( stderr, "%s\n", ( const char* )errors->GetBufferPointer() ); + errors->Release(); + } + if( FAILED( hr ) ) + return nil; + return shader; + } + + void + createMatFXShaders( void ) + { + static const D3D_SHADER_MACRO ambDirDefines[] = { + { "DIRECTIONALS", "1" }, + { nil, nil } + }; + static const D3D_SHADER_MACRO allDefines[] = { + { "DIRECTIONALS", "1" }, + { "POINTLIGHTS", "1" }, + { "SPOTLIGHTS", "1" }, + { nil, nil } + }; + static const D3D_SHADER_MACRO texDefines[] = { + { "TEX", "1" }, + { nil, nil } + }; + ID3DBlob* ambBlob = compileMatFXShader( + matfx_env_VS_d11_source, "vs_4_0" ); + ID3DBlob* ambDirBlob = compileMatFXShader( + matfx_env_VS_d11_source, "vs_4_0", ambDirDefines ); + ID3DBlob* allBlob = compileMatFXShader( + matfx_env_VS_d11_source, "vs_4_0", allDefines ); + ID3DBlob* psBlob = compileMatFXShader( + matfx_env_PS_d11_source, "ps_4_0" ); + ID3DBlob* texPSBlob = compileMatFXShader( + matfx_env_PS_d11_source, "ps_4_0", texDefines ); + if( ambBlob == nil || ambDirBlob == nil || allBlob == nil || + psBlob == nil || texPSBlob == nil ) + goto fail; + + if( FAILED( d3d11Globals.d3ddevice->CreateVertexShader( + ambBlob->GetBufferPointer(), ambBlob->GetBufferSize(), nil, + &matfx_env_amb_VS ) ) ) + goto fail; + d3d11Globals.numVertexShaders++; + if( FAILED( d3d11Globals.d3ddevice->CreateVertexShader( + ambDirBlob->GetBufferPointer(), ambDirBlob->GetBufferSize(), nil, + &matfx_env_amb_dir_VS ) ) ) + goto fail; + d3d11Globals.numVertexShaders++; + if( FAILED( d3d11Globals.d3ddevice->CreateVertexShader( + allBlob->GetBufferPointer(), allBlob->GetBufferSize(), nil, + &matfx_env_all_VS ) ) ) + goto fail; + d3d11Globals.numVertexShaders++; + if( FAILED( d3d11Globals.d3ddevice->CreatePixelShader( + psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nil, + &matfx_env_PS ) ) ) + goto fail; + d3d11Globals.numPixelShaders++; + if( FAILED( d3d11Globals.d3ddevice->CreatePixelShader( + texPSBlob->GetBufferPointer(), texPSBlob->GetBufferSize(), nil, + &matfx_env_tex_PS ) ) ) + goto fail; + d3d11Globals.numPixelShaders++; + + ambBlob->Release(); + ambDirBlob->Release(); + allBlob->Release(); + psBlob->Release(); + texPSBlob->Release(); + return; + +fail: + if( ambBlob ) ambBlob->Release(); + if( ambDirBlob ) ambDirBlob->Release(); + if( allBlob ) allBlob->Release(); + if( psBlob ) psBlob->Release(); + if( texPSBlob ) texPSBlob->Release(); + destroyMatFXShaders(); + assert( !"Failed to create D3D11 MatFX shaders" ); + } + + void + destroyMatFXShaders( void ) + { + if( matfx_env_tex_PS ) + { + clearPixelShader( matfx_env_tex_PS ); + matfx_env_tex_PS->Release(); + matfx_env_tex_PS = nil; + d3d11Globals.numPixelShaders--; + } + if( matfx_env_PS ) + { + clearPixelShader( matfx_env_PS ); + matfx_env_PS->Release(); + matfx_env_PS = nil; + d3d11Globals.numPixelShaders--; + } + if( matfx_env_all_VS ) + { + clearVertexShader( matfx_env_all_VS ); + matfx_env_all_VS->Release(); + matfx_env_all_VS = nil; + d3d11Globals.numVertexShaders--; + } + if( matfx_env_amb_dir_VS ) + { + clearVertexShader( matfx_env_amb_dir_VS ); + matfx_env_amb_dir_VS->Release(); + matfx_env_amb_dir_VS = nil; + d3d11Globals.numVertexShaders--; + } + if( matfx_env_amb_VS ) + { + clearVertexShader( matfx_env_amb_VS ); + matfx_env_amb_VS->Release(); + matfx_env_amb_VS = nil; + d3d11Globals.numVertexShaders--; + } + } + + void + createMatFXConstantBuffers( void ) + { + memset( &matfxVSConstants, 0, sizeof( matfxVSConstants ) ); + matfxVSConstants.envColor[ 0 ] = 1.0f; + matfxVSConstants.envColor[ 1 ] = 1.0f; + matfxVSConstants.envColor[ 2 ] = 1.0f; + matfxVSConstants.envColor[ 3 ] = 1.0f; + + D3D11_BUFFER_DESC desc; + memset( &desc, 0, sizeof( desc ) ); + desc.ByteWidth = sizeof( MatFXVSConstants ); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( + &desc, nil, &matfxVSConstantBuffer ) ) ) + assert( !"Failed to create D3D11 MatFX constant buffers" ); + + desc.ByteWidth = sizeof( MatFXPSConstants ); + if( FAILED( d3d11Globals.d3ddevice->CreateBuffer( + &desc, nil, &matfxPSConstantBuffer ) ) ) + assert( !"Failed to create D3D11 MatFX constant buffers" ); + } + + void + destroyMatFXConstantBuffers( void ) + { + ID3D11Buffer* buffer = nil; + d3d11Globals.context->PSSetConstantBuffers( + PSSlotMatFX, 1, &buffer ); + matfxPSConstantBuffer->Release(); + matfxPSConstantBuffer = nil; + + d3d11Globals.context->VSSetConstantBuffers( + VSlotMatFX, 1, &buffer ); + matfxVSConstantBuffer->Release(); + matfxVSConstantBuffer = nil; + } + + #endif + + static void* + matfxOpen( void* o, int32, int32 ) + { + #ifdef RW_D3D11 + createMatFXShaders(); + createMatFXConstantBuffers(); + #endif + + matFXGlobals.pipelines[ PLATFORM_D3D11 ] = makeMatFXPipeline(); + return o; + } + + static void* + matfxClose( void* o, int32, int32 ) + { + #ifdef RW_D3D11 + destroyMatFXConstantBuffers(); + destroyMatFXShaders(); + #endif + + (( ObjPipeline* )matFXGlobals.pipelines[ PLATFORM_D3D11 ])->destroy(); + matFXGlobals.pipelines[ PLATFORM_D3D11 ] = nil; + return o; + } + + void + initMatFX( void ) + { + Driver::registerPlugin( PLATFORM_D3D11, 0, ID_MATFX, + matfxOpen, matfxClose ); + } + + ObjPipeline* + makeMatFXPipeline( void ) + { + ObjPipeline* pipe = ObjPipeline::create(); + pipe->instanceCB = defaultInstanceCB; + pipe->uninstanceCB = defaultUninstanceCB; + pipe->renderCB = matfxRenderCB_Shader; + pipe->pluginID = ID_MATFX; + pipe->pluginData = 0; + return pipe; + } + + } +} diff --git a/src/d3d/d3d11render.cpp b/src/d3d/d3d11render.cpp new file mode 100644 index 00000000..e303ed4e --- /dev/null +++ b/src/d3d/d3d11render.cpp @@ -0,0 +1,507 @@ +#include +#include +#include +#include + +#define WITH_D3D +#include "../rwbase.h" +#include "../rwplg.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "../rwrender.h" +#include "rwd3d.h" +#include "rwd3d11.h" + +#ifdef RW_D3D11 +#include + +#include "rwd3dimpl.h" +#include "default_VS_d11.h" +#include "default_PS_d11.h" +#endif + +namespace rw { +namespace d3d11 { +using namespace d3d; + +#ifndef RW_D3D11 +void defaultRenderCB(Atomic*, InstanceDataHeader*) {} +void defaultRenderCB_Shader(Atomic *atomic, InstanceDataHeader *header) {} +#else + +struct StandardConstants +{ + float combinedMat[16]; + float worldMat[16]; + float normalMat[16]; + float matCol[4]; + float surfProps[4]; + float fogData[4]; + float ambientLight[4]; +}; + +struct LightVS +{ + V3d color; float param0; + V3d position; float param1; + V3d direction; float param2; +}; + +#define MAX_LIGHTS 8 + +struct LightConstants +{ + int32 numLights[4]; + int32 firstLight[4]; + LightVS lights[MAX_LIGHTS]; +}; + +static ID3D11VertexShader *default_amb_VS; +static ID3D11VertexShader *default_amb_dir_VS; +static ID3D11VertexShader *default_all_VS; +static ID3D11PixelShader *default_PS; +static ID3D11InputLayout *defaultLayout; +static ID3D11Buffer *standardConstantBuffer; +static ID3D11Buffer *lightConstantBuffer; +static StandardConstants standardConstants; +static LightConstants lightConstants; + +template static void +safeRelease(T *&p) +{ + if(p){ + p->Release(); + p = nil; + } +} + +static ID3DBlob* +compileShader(const char *src, const char *entry, const char *target, + const D3D_SHADER_MACRO *defines = nil) +{ + ID3DBlob *shader = nil; + ID3DBlob *errors = nil; + HRESULT hr = D3DCompile(src, strlen(src), nil, defines, nil, + entry, target, 0, 0, &shader, &errors); + if(errors){ + fprintf(stderr, "%s\n", (const char*)errors->GetBufferPointer()); + errors->Release(); + } + if(FAILED(hr)) + return nil; + return shader; +} + +bool32 +openDefaultRenderPipeline(void) +{ + static const D3D_SHADER_MACRO ambDirDefines[] = { + { "DIRECTIONALS", "1" }, + { nil, nil } + }; + static const D3D_SHADER_MACRO allDefines[] = { + { "DIRECTIONALS", "1" }, + { "POINTLIGHTS", "1" }, + { "SPOTLIGHTS", "1" }, + { nil, nil } + }; + D3D11_INPUT_ELEMENT_DESC elements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(DefaultVertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(DefaultVertex, normal), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(DefaultVertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(DefaultVertex, texcoord), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + D3D11_BUFFER_DESC desc; + ID3DBlob *ambBlob = compileShader(default_VS_d11_source, "main", "vs_4_0"); + ID3DBlob *ambDirBlob = compileShader(default_VS_d11_source, "main", "vs_4_0", + ambDirDefines); + ID3DBlob *allBlob = compileShader(default_VS_d11_source, "main", "vs_4_0", + allDefines); + ID3DBlob *psBlob = compileShader(default_PS_d11_source, "main", "ps_4_0"); + if(ambBlob == nil || ambDirBlob == nil || allBlob == nil || psBlob == nil) + goto fail; + + if(FAILED(d3d11Globals.d3ddevice->CreateVertexShader(ambBlob->GetBufferPointer(), + ambBlob->GetBufferSize(), nil, &default_amb_VS))) + goto fail; + d3d11Globals.numVertexShaders++; + if(FAILED(d3d11Globals.d3ddevice->CreateVertexShader(ambDirBlob->GetBufferPointer(), + ambDirBlob->GetBufferSize(), nil, &default_amb_dir_VS))) + goto fail; + d3d11Globals.numVertexShaders++; + if(FAILED(d3d11Globals.d3ddevice->CreateVertexShader(allBlob->GetBufferPointer(), + allBlob->GetBufferSize(), nil, &default_all_VS))) + goto fail; + d3d11Globals.numVertexShaders++; + if(FAILED(d3d11Globals.d3ddevice->CreatePixelShader(psBlob->GetBufferPointer(), + psBlob->GetBufferSize(), nil, &default_PS))) + goto fail; + d3d11Globals.numPixelShaders++; + if(FAILED(d3d11Globals.d3ddevice->CreateInputLayout(elements, nelem(elements), + allBlob->GetBufferPointer(), allBlob->GetBufferSize(), &defaultLayout))) + goto fail; + d3d11Globals.numInputLayouts++; + + memset(&desc, 0, sizeof(desc)); + memset(&standardConstants, 0, sizeof(standardConstants)); + standardConstants.matCol[0] = 1.0f; + standardConstants.matCol[1] = 1.0f; + standardConstants.matCol[2] = 1.0f; + standardConstants.matCol[3] = 1.0f; + standardConstants.fogData[3] = 1.0f; + memset(&lightConstants, 0, sizeof(lightConstants)); + + desc.ByteWidth = sizeof(StandardConstants); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + if(FAILED(d3d11Globals.d3ddevice->CreateBuffer(&desc, nil, + &standardConstantBuffer))) + goto fail; + + desc.ByteWidth = sizeof(LightConstants); + if(FAILED(d3d11Globals.d3ddevice->CreateBuffer(&desc, nil, + &lightConstantBuffer))) + goto fail; + d3d11Globals.context->UpdateSubresource(lightConstantBuffer, 0, + nil, &lightConstants, 0, 0); + + ambBlob->Release(); + ambDirBlob->Release(); + allBlob->Release(); + psBlob->Release(); + return 1; + +fail: + if(ambBlob) ambBlob->Release(); + if(ambDirBlob) ambDirBlob->Release(); + if(allBlob) allBlob->Release(); + if(psBlob) psBlob->Release(); + closeDefaultRenderPipeline(); + return 0; +} + +void +closeDefaultRenderPipeline(void) +{ + safeRelease(lightConstantBuffer); + safeRelease(standardConstantBuffer); + if(defaultLayout){ + clearVertexDeclaration(defaultLayout); + defaultLayout->Release(); + defaultLayout = nil; + d3d11Globals.numInputLayouts--; + } + if(default_PS){ + clearPixelShader(default_PS); + default_PS->Release(); + default_PS = nil; + d3d11Globals.numPixelShaders--; + } + if(default_all_VS){ + clearVertexShader(default_all_VS); + default_all_VS->Release(); + default_all_VS = nil; + d3d11Globals.numVertexShaders--; + } + if(default_amb_dir_VS){ + clearVertexShader(default_amb_dir_VS); + default_amb_dir_VS->Release(); + default_amb_dir_VS = nil; + d3d11Globals.numVertexShaders--; + } + if(default_amb_VS){ + clearVertexShader(default_amb_VS); + default_amb_VS->Release(); + default_amb_VS = nil; + d3d11Globals.numVertexShaders--; + } +} + +static void +setAmbient(const RGBAf &color) +{ + standardConstants.ambientLight[0] = color.red; + standardConstants.ambientLight[1] = color.green; + standardConstants.ambientLight[2] = color.blue; + standardConstants.ambientLight[3] = color.alpha; +} + +static int32 +uploadLights(WorldLights *lightData) +{ + int32 i; + int32 bits = 0; + int32 firstLight[4] = { 0, 0, 0, 0 }; + + if(lightData->numAmbients) + bits |= VSLIGHT_AMBIENT; + + LightVS directionals[MAX_LIGHTS] = {}; + LightVS points[MAX_LIGHTS] = {}; + LightVS spots[MAX_LIGHTS] = {}; + int32 numDir = lightData->numDirectionals; + if(numDir > MAX_LIGHTS) + numDir = MAX_LIGHTS; + for(i = 0; i < numDir; i++){ + Light *l = lightData->directionals[i]; + directionals[i].color.x = l->color.red; + directionals[i].color.y = l->color.green; + directionals[i].color.z = l->color.blue; + directionals[i].direction = l->getFrame()->getLTM()->at; + bits |= VSLIGHT_DIRECT; + } + + int32 np = 0; + int32 ns = 0; + int32 numLocal = MAX_LIGHTS - numDir; + for(i = 0; i < lightData->numLocals && np + ns < numLocal; i++){ + Light *l = lightData->locals[i]; + + switch(l->getType()){ + case Light::POINT: + points[np].color.x = l->color.red; + points[np].color.y = l->color.green; + points[np].color.z = l->color.blue; + points[np].param0 = l->radius; + points[np].position = l->getFrame()->getLTM()->pos; + np++; + bits |= VSLIGHT_POINT; + break; + case Light::SPOT: + case Light::SOFTSPOT: + spots[ns].color.x = l->color.red; + spots[ns].color.y = l->color.green; + spots[ns].color.z = l->color.blue; + spots[ns].param0 = l->radius; + spots[ns].position = l->getFrame()->getLTM()->pos; + spots[ns].direction = l->getFrame()->getLTM()->at; + spots[ns].param1 = l->minusCosAngle; + // lower bound of falloff + if(l->getType() == Light::SOFTSPOT) + spots[ns].param2 = 0.0f; + else + spots[ns].param2 = 1.0f; + bits |= VSLIGHT_SPOT; + ns++; + break; + } + } + + firstLight[0] = 0; + firstLight[1] = numDir + firstLight[0]; + int32 numPoint = np; + firstLight[2] = numPoint + firstLight[1]; + int32 numSpot = ns; + + memset(&lightConstants, 0, sizeof(lightConstants)); + lightConstants.numLights[0] = numDir; + lightConstants.numLights[1] = numPoint; + lightConstants.numLights[2] = numSpot; + memcpy(lightConstants.firstLight, firstLight, sizeof(firstLight)); + + int32 off = 0; + if(numDir) + memcpy(&lightConstants.lights[off], directionals, + numDir*sizeof(LightVS)); + off += numDir; + if(numPoint) + memcpy(&lightConstants.lights[off], points, + numPoint*sizeof(LightVS)); + off += numPoint; + if(numSpot) + memcpy(&lightConstants.lights[off], spots, + numSpot*sizeof(LightVS)); + + d3d11Globals.context->UpdateSubresource(lightConstantBuffer, 0, + nil, &lightConstants, 0, 0); + d3d11Globals.context->VSSetConstantBuffers(VSlotLights, 1, + &lightConstantBuffer); + return bits; +} + +int32 +lightingCB_Shader(Atomic *atomic) +{ + WorldLights lightData; + Light *directionals[MAX_LIGHTS]; + Light *locals[MAX_LIGHTS]; + lightData.directionals = directionals; + lightData.numDirectionals = MAX_LIGHTS; + lightData.locals = locals; + lightData.numLocals = MAX_LIGHTS; + + if(atomic->geometry->flags & Geometry::LIGHT && engine->currentWorld){ + ((World*)engine->currentWorld)->enumerateLights(atomic, &lightData); + setAmbient(lightData.ambient); + return uploadLights(&lightData); + } + + static const RGBAf black = { 0.0f, 0.0f, 0.0f, 0.0f }; + setAmbient(black); + lightData.numAmbients = 0; + lightData.numDirectionals = 0; + lightData.numLocals = 0; + return uploadLights(&lightData); +} + +bool32 +uploadDefaultMatrices(Matrix *world) +{ + if(world == nil || engine->currentCamera == nil) + return 0; + + RawMatrix combined, worldMatrix, worldView; + Camera *cam = engine->currentCamera; + convMatrix(&worldMatrix, world); + RawMatrix::mult(&worldView, &worldMatrix, &cam->devView); + RawMatrix::mult(&combined, &worldView, &cam->devProj); + + memcpy(standardConstants.combinedMat, &combined, sizeof(combined)); + memcpy(standardConstants.worldMat, &worldMatrix, sizeof(worldMatrix)); + // D3D9 currently uploads world as the normal matrix too. + memcpy(standardConstants.normalMat, &worldMatrix, sizeof(worldMatrix)); + return 1; +} + +bool32 +uploadDefaultMaterial(const RGBA &color, const SurfaceProperties &surfaceProps) +{ + if(standardConstantBuffer == nil) + return 0; + + standardConstants.matCol[0] = color.red/255.0f; + standardConstants.matCol[1] = color.green/255.0f; + standardConstants.matCol[2] = color.blue/255.0f; + standardConstants.matCol[3] = color.alpha/255.0f; + standardConstants.surfProps[0] = surfaceProps.ambient; + standardConstants.surfProps[1] = surfaceProps.specular; + standardConstants.surfProps[2] = surfaceProps.diffuse; + standardConstants.surfProps[3] = 0.0f; + d3d11Globals.context->UpdateSubresource(standardConstantBuffer, 0, + nil, &standardConstants, 0, 0); + d3d11Globals.context->VSSetConstantBuffers(VSlotObjects, 1, + &standardConstantBuffer); + return 1; +} + +bool32 +setDefaultVertexDeclaration(void) +{ + return setVertexDeclaration(defaultLayout); +} + +bool32 +setDefaultVertexShader(int32 lightBits) +{ + if((lightBits & VSLIGHT_MASK) == 0) + return setVertexShader(default_amb_VS); + if((lightBits & VSLIGHT_MASK) == VSLIGHT_DIRECT) + return setVertexShader(default_amb_dir_VS); + return setVertexShader(default_all_VS); +} + +bool32 +setDefaultPixelShader(void) +{ + return setPixelShader(default_PS); +} + +void +drawInst_simple(d3d11::InstanceDataHeader *header, d3d11::InstanceData *inst) +{ + applyDrawState(); + d3d11Globals.context->DrawIndexed(inst->numIndex, inst->startIndex, + inst->baseIndex); +} + +// Emulate PS2 GS alpha test FB_ONLY case: failed alpha writes to frame- but not to depth buffer +void +drawInst_GSemu(d3d11::InstanceDataHeader *header, InstanceData *inst) +{ + bool32 hasAlpha = GetRenderState(VERTEXALPHA); + Raster *raster = (Raster*)GetRenderStatePtr(TEXTURERASTER); + if(raster && GETD3DRASTEREXT(raster)->hasAlpha) + hasAlpha = 1; + if(!hasAlpha){ + drawInst_simple(header, inst); + return; + } + + uint32 zwrite = GetRenderState(ZWRITEENABLE); + uint32 alphafunc = GetRenderState(ALPHATESTFUNC); + uint32 alpharef = GetRenderState(ALPHATESTREF); + if(zwrite){ + uint32 gsalpharef = GetRenderState(GSALPHATESTREF); + SetRenderState(ALPHATESTFUNC, ALPHAGREATEREQUAL); + SetRenderState(ALPHATESTREF, gsalpharef); + drawInst_simple(header, inst); + SetRenderState(ALPHATESTFUNC, ALPHALESS); + SetRenderState(ZWRITEENABLE, 0); + drawInst_simple(header, inst); + SetRenderState(ZWRITEENABLE, 1); + SetRenderState(ALPHATESTFUNC, alphafunc); + SetRenderState(ALPHATESTREF, alpharef); + }else{ + SetRenderState(ALPHATESTFUNC, ALPHAALWAYS); + drawInst_simple(header, inst); + SetRenderState(ALPHATESTFUNC, alphafunc); + } +} + +void +drawInst(d3d11::InstanceDataHeader *header, d3d11::InstanceData *inst) +{ + if(GetRenderState(GSALPHATEST)) + drawInst_GSemu(header, inst); + else + drawInst_simple(header, inst); +} + +void +defaultRenderCB_Shader(Atomic *atomic, InstanceDataHeader *header) +{ + if(atomic == nil || atomic->geometry == nil || + atomic->getFrame() == nil || header == nil) + return; + + if(!setStreamSource(0, header->vertexStream[0].vertexBuffer, 0, + header->vertexStream[0].stride)) + return; + + if(!setIndices(header->indexBuffer)) + return; + if(!setDefaultVertexDeclaration()) + return; + + d3d11Globals.context->IASetPrimitiveTopology( + (D3D11_PRIMITIVE_TOPOLOGY)header->primType); + + int32 vsBits = lightingCB_Shader(atomic); + if(!uploadDefaultMatrices(atomic->getFrame()->getLTM())) + return; + + if(!setDefaultVertexShader(vsBits) || !setDefaultPixelShader()) + return; + + uint32 flags = atomic->geometry->flags; + static const RGBA white = { 255, 255, 255, 255 }; + InstanceData *inst = header->inst; + for(uint32 i = 0; i < header->numMeshes; i++, inst++){ + Material *material = inst->material; + if(material == nil) + continue; + + SetRenderState(VERTEXALPHA, + inst->vertexAlpha || material->color.alpha != 255); + setTexture(0, material->texture); + if(!uploadDefaultMaterial((flags & Geometry::MODULATE) ? + material->color : white, material->surfaceProps)) + return; + drawInst(header, inst); + } +} + +#endif +} +} diff --git a/src/d3d/d3d11skin.cpp b/src/d3d/d3d11skin.cpp new file mode 100644 index 00000000..7e9f7257 --- /dev/null +++ b/src/d3d/d3d11skin.cpp @@ -0,0 +1,379 @@ +#include +#include +#include +#include + +#define WITH_D3D +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwrender.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwanim.h" +#include "../rwengine.h" +#include "../rwplugins.h" +#include "rwd3d.h" +#include "rwd3d11.h" + +#ifdef RW_D3D11 +#include + +#include "rwd3dimpl.h" +#include "skin_VS_d11.h" +#endif + +namespace rw { +namespace d3d11 { +using namespace d3d; + +#ifndef RW_D3D11 +void skinInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance) {} +void skinRenderCB(Atomic *atomic, InstanceDataHeader *header) {} +#else + +static ID3D11VertexShader *skin_amb_VS; +static ID3D11VertexShader *skin_amb_dir_VS; +static ID3D11VertexShader *skin_all_VS; +static ID3D11InputLayout *skinLayout; +static ID3D11Buffer *skinMatrixBuffer; +void destroySkinShaders(void); + +void +skinInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance) +{ + VertexStream *s = &header->vertexStream[0]; + bool32 isPrelit = (geo->flags & Geometry::PRELIT) != 0; + bool32 hasNormals = (geo->flags & Geometry::NORMALS) != 0; + bool32 hasTexCoords = geo->numTexCoordSets > 0; + + if(!reinstance){ + assert(s->vertexBuffer == nil); + s->offset = 0; + s->stride = sizeof(SkinVertex); + s->managed = 1; + s->geometryFlags = 0; + s->dynamicLock = 0; + s->vertexBuffer = createVertexBuffer( + header->totalNumVertex*s->stride, 0, false); + } + + Skin *skin = Skin::get(geo); + SkinVertex *vertices = (SkinVertex*)lockVertices( + s->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK); + static const V3d defaultNormal = { 0.0f, 0.0f, 1.0f }; + static const RGBA black = { 0, 0, 0, 255 }; + static const TexCoords zeroTexCoord = { 0.0f, 0.0f }; + + // A fixed D3D11 layout uses neutral values for missing geometry attributes. + if(!reinstance || (geo->lockedSinceInst & Geometry::LOCKVERTICES)) + for(uint32 i = 0; i < header->totalNumVertex; i++) + vertices[i].position = geo->morphTargets[0].vertices[i]; + + if(!reinstance || (geo->lockedSinceInst & Geometry::LOCKPRELIGHT)) + for(uint32 i = 0; i < header->totalNumVertex; i++) + vertices[i].color = isPrelit ? geo->colors[i] : black; + + if(!reinstance || (geo->lockedSinceInst & Geometry::LOCKTEXCOORDS)) + for(uint32 i = 0; i < header->totalNumVertex; i++) + vertices[i].texcoord = hasTexCoords ? + geo->texCoords[0][i] : zeroTexCoord; + + if(!reinstance || (geo->lockedSinceInst & Geometry::LOCKNORMALS)) + for(uint32 i = 0; i < header->totalNumVertex; i++) + vertices[i].normal = hasNormals ? + geo->morphTargets[0].normals[i] : defaultNormal; + + if(!reinstance){ + for(uint32 i = 0; i < header->totalNumVertex; i++) + vertices[i].weights = ((V4d*)skin->weights)[i]; + for(uint32 i = 0; i < header->totalNumVertex; i++) + memcpy(vertices[i].indices, &skin->indices[i*4], + sizeof(vertices[i].indices)); + } + unlockVertices(s->vertexBuffer); + + if(!reinstance || (geo->lockedSinceInst & Geometry::LOCKPRELIGHT)){ + InstanceData *inst = header->inst; + for(uint32 i = 0; i < header->numMeshes; i++, inst++){ + inst->vertexAlpha = 0; + if(!isPrelit) + continue; + for(uint32 j = 0; j < inst->numVertices; j++) + if(geo->colors[inst->minVert + j].alpha != 255){ + inst->vertexAlpha = 1; + break; + } + } + } +} + +static float skinMatrices[64*16]; + +void +uploadSkinMatrices(Atomic *a) +{ + Skin *skin = Skin::get(a->geometry); + assert(skin->numBones <= 64); + int i; + float *m = skinMatrices; + HAnimHierarchy *hier = Skin::getHierarchy(a); + + if(hier){ + Matrix *invMats = (Matrix*)skin->inverseMatrices; + Matrix tmp, tmp2; + + assert(skin->numBones == hier->numNodes); + if(hier->flags & HAnimHierarchy::LOCALSPACEMATRICES){ + for(i = 0; i < hier->numNodes; i++){ + invMats[i].flags = 0; + Matrix::mult(&tmp, &invMats[i], &hier->matrices[i]); + RawMatrix::transpose((RawMatrix*)m, (RawMatrix*)&tmp); + m += 12; + } + }else{ + Matrix invAtmMat; + Matrix::invert(&invAtmMat, a->getFrame()->getLTM()); + for(i = 0; i < hier->numNodes; i++){ + invMats[i].flags = 0; + Matrix::mult(&tmp, &hier->matrices[i], &invAtmMat); + Matrix::mult(&tmp2, &invMats[i], &tmp); + RawMatrix::transpose((RawMatrix*)m, (RawMatrix*)&tmp2); + m += 12; + } + } + }else{ + for(i = 0; i < skin->numBones; i++){ + m[0] = 1.0f; + m[1] = 0.0f; + m[2] = 0.0f; + m[3] = 0.0f; + + m[4] = 0.0f; + m[5] = 1.0f; + m[6] = 0.0f; + m[7] = 0.0f; + + m[8] = 0.0f; + m[9] = 0.0f; + m[10] = 1.0f; + m[11] = 0.0f; + + m += 12; + } + } + + d3d11Globals.context->UpdateSubresource(skinMatrixBuffer, 0, + nil, skinMatrices, 0, 0); + d3d11Globals.context->VSSetConstantBuffers(VSlotSkin, 1, + &skinMatrixBuffer); +} + +void +skinRenderCB(Atomic *atomic, InstanceDataHeader *header) +{ + setStreamSource(0, header->vertexStream[0].vertexBuffer, 0, + header->vertexStream[0].stride); + setIndices(header->indexBuffer); + setVertexDeclaration(skinLayout); + + d3d11Globals.context->IASetPrimitiveTopology( + (D3D11_PRIMITIVE_TOPOLOGY)header->primType); + + int32 vsBits = lightingCB_Shader(atomic); + uploadDefaultMatrices(atomic->getFrame()->getLTM()); + uploadSkinMatrices(atomic); + + if((vsBits & VSLIGHT_MASK) == 0) + setVertexShader(skin_amb_VS); + else if((vsBits & VSLIGHT_MASK) == VSLIGHT_DIRECT) + setVertexShader(skin_amb_dir_VS); + else + setVertexShader(skin_all_VS); + setDefaultPixelShader(); + + uint32 flags = atomic->geometry->flags; + static const RGBA white = { 255, 255, 255, 255 }; + InstanceData *inst = header->inst; + for(uint32 i = 0; i < header->numMeshes; i++, inst++){ + Material *material = inst->material; + + SetRenderState(VERTEXALPHA, + inst->vertexAlpha || material->color.alpha != 255); + setTexture(0, material->texture); + uploadDefaultMaterial((flags & Geometry::MODULATE) ? + material->color : white, material->surfaceProps); + drawInst(header, inst); + } +} + +static ID3DBlob* +compileSkinShader(const D3D_SHADER_MACRO *defines = nil) +{ + ID3DBlob *shader = nil; + ID3DBlob *errors = nil; + HRESULT hr = D3DCompile(skin_VS_d11_source, + strlen(skin_VS_d11_source), nil, defines, nil, + "main", "vs_4_0", 0, 0, &shader, &errors); + if(errors){ + fprintf(stderr, "%s\n", (const char*)errors->GetBufferPointer()); + errors->Release(); + } + if(FAILED(hr)) + return nil; + return shader; +} + +void +createSkinShaders(void) +{ + static const D3D_SHADER_MACRO ambDirDefines[] = { + { "DIRECTIONALS", "1" }, + { nil, nil } + }; + static const D3D_SHADER_MACRO allDefines[] = { + { "DIRECTIONALS", "1" }, + { "POINTLIGHTS", "1" }, + { "SPOTLIGHTS", "1" }, + { nil, nil } + }; + D3D11_INPUT_ELEMENT_DESC elements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(SkinVertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(SkinVertex, normal), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(SkinVertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(SkinVertex, texcoord), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "BLENDWEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(SkinVertex, weights), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "BLENDINDICES", 0, DXGI_FORMAT_R8G8B8A8_UINT, 0, offsetof(SkinVertex, indices), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + D3D11_BUFFER_DESC desc; + ID3DBlob *ambBlob = compileSkinShader(); + ID3DBlob *ambDirBlob = compileSkinShader(ambDirDefines); + ID3DBlob *allBlob = compileSkinShader(allDefines); + if(ambBlob == nil || ambDirBlob == nil || allBlob == nil) + goto fail; + + if(FAILED(d3d11Globals.d3ddevice->CreateVertexShader( + ambBlob->GetBufferPointer(), ambBlob->GetBufferSize(), nil, + &skin_amb_VS))) + goto fail; + d3d11Globals.numVertexShaders++; + if(FAILED(d3d11Globals.d3ddevice->CreateVertexShader( + ambDirBlob->GetBufferPointer(), ambDirBlob->GetBufferSize(), nil, + &skin_amb_dir_VS))) + goto fail; + d3d11Globals.numVertexShaders++; + if(FAILED(d3d11Globals.d3ddevice->CreateVertexShader( + allBlob->GetBufferPointer(), allBlob->GetBufferSize(), nil, + &skin_all_VS))) + goto fail; + d3d11Globals.numVertexShaders++; + + if(FAILED(d3d11Globals.d3ddevice->CreateInputLayout( + elements, nelem(elements), allBlob->GetBufferPointer(), + allBlob->GetBufferSize(), &skinLayout))) + goto fail; + d3d11Globals.numInputLayouts++; + + memset(&desc, 0, sizeof(desc)); + // float4x3 occupies three float4 registers, as in the D3D9 shader. + desc.ByteWidth = 64*12*sizeof(float); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + if(FAILED(d3d11Globals.d3ddevice->CreateBuffer( + &desc, nil, &skinMatrixBuffer))) + goto fail; + + ambBlob->Release(); + ambDirBlob->Release(); + allBlob->Release(); + return; + +fail: + if(ambBlob) ambBlob->Release(); + if(ambDirBlob) ambDirBlob->Release(); + if(allBlob) allBlob->Release(); + destroySkinShaders(); + assert(!"Failed to create D3D11 skin shaders"); +} + +void +destroySkinShaders(void) +{ + if(skinMatrixBuffer){ + ID3D11Buffer *buffer = nil; + d3d11Globals.context->VSSetConstantBuffers(VSlotSkin, 1, &buffer); + skinMatrixBuffer->Release(); + skinMatrixBuffer = nil; + } + if(skinLayout){ + clearVertexDeclaration(skinLayout); + skinLayout->Release(); + skinLayout = nil; + d3d11Globals.numInputLayouts--; + } + if(skin_all_VS){ + clearVertexShader(skin_all_VS); + skin_all_VS->Release(); + skin_all_VS = nil; + d3d11Globals.numVertexShaders--; + } + if(skin_amb_dir_VS){ + clearVertexShader(skin_amb_dir_VS); + skin_amb_dir_VS->Release(); + skin_amb_dir_VS = nil; + d3d11Globals.numVertexShaders--; + } + if(skin_amb_VS){ + clearVertexShader(skin_amb_VS); + skin_amb_VS->Release(); + skin_amb_VS = nil; + d3d11Globals.numVertexShaders--; + } +} + +#endif + +static void* +skinOpen(void *o, int32, int32) +{ +#ifdef RW_D3D11 + createSkinShaders(); +#endif + + skinGlobals.pipelines[PLATFORM_D3D11] = makeSkinPipeline(); + return o; +} + +static void* +skinClose(void *o, int32, int32) +{ +#ifdef RW_D3D11 + destroySkinShaders(); +#endif + + ((ObjPipeline*)skinGlobals.pipelines[PLATFORM_D3D11])->destroy(); + skinGlobals.pipelines[PLATFORM_D3D11] = nil; + return o; +} + +void +initSkin(void) +{ + Driver::registerPlugin(PLATFORM_D3D11, 0, ID_SKIN, + skinOpen, skinClose); +} + +ObjPipeline* +makeSkinPipeline(void) +{ + ObjPipeline *pipe = ObjPipeline::create(); + pipe->instanceCB = skinInstanceCB; + pipe->uninstanceCB = nil; + pipe->renderCB = skinRenderCB; + pipe->pluginID = ID_SKIN; + pipe->pluginData = 1; + return pipe; +} + +} +} diff --git a/src/d3d/d3ddevice.cpp b/src/d3d/d3ddevice.cpp index 62c46b87..58d6a87e 100644 --- a/src/d3d/d3ddevice.cpp +++ b/src/d3d/d3ddevice.cpp @@ -2017,6 +2017,7 @@ Device renderdevice = { d3d::deviceSystem, }; + #endif } } diff --git a/src/d3d/rwd3d.h b/src/d3d/rwd3d.h index cabfeffb..c3d567c8 100644 --- a/src/d3d/rwd3d.h +++ b/src/d3d/rwd3d.h @@ -6,7 +6,7 @@ namespace rw { -#ifdef RW_D3D9 +#if defined(RW_D3D9) || defined(RW_D3D11) #ifdef _WINDOWS_ struct EngineOpenParams @@ -36,6 +36,9 @@ extern Device renderdevice; extern IDirect3DDevice9 *d3ddevice; void setD3dMaterial(D3DMATERIAL9 *mat9); #endif +#endif + +#if defined(RW_D3D9) || defined(RW_D3D11) #define COLOR_ARGB(a, r, g, b) ((rw::uint32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) @@ -101,7 +104,9 @@ struct Im2DVertex float getV(void) { return this->v; } }; -#else +#endif + +#ifndef RW_D3D9 #ifndef MAKEFOURCC #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ @@ -259,11 +264,17 @@ void *createIndexBuffer(uint32 length, bool dynamic); void destroyIndexBuffer(void *indexBuffer); uint16 *lockIndices(void *indexBuffer, uint32 offset, uint32 size, uint32 flags); void unlockIndices(void *indexBuffer); +#ifdef RW_D3D11 +void *getD3D11IndexBuffer(void *indexBuffer); +#endif void *createVertexBuffer(uint32 length, uint32 fvf, bool dynamic); void destroyVertexBuffer(void *vertexBuffer); uint8 *lockVertices(void *vertexBuffer, uint32 offset, uint32 size, uint32 flags); void unlockVertices(void *vertexBuffer); +#ifdef RW_D3D11 +void *getD3D11VertexBuffer(void *vertexBuffer); +#endif void *createTexture(int32 width, int32 height, int32 levels, uint32 usage, uint32 format); void destroyTexture(void *texture); @@ -276,6 +287,11 @@ struct D3dRaster { void *texture; void *palette; +#ifdef RW_D3D11 + void *srv; + void *rtv; + void *dsv; +#endif void *lockedSurf; uint32 format; uint32 bpp; // bytes per pixel diff --git a/src/d3d/rwd3d11.h b/src/d3d/rwd3d11.h new file mode 100644 index 00000000..000a7b5c --- /dev/null +++ b/src/d3d/rwd3d11.h @@ -0,0 +1,171 @@ +namespace rw { +struct Device; +namespace d3d11 { + +enum ConstantBufferSlot +{ + VSlotObjects = 0, + VSlotLights = 1, + // Vertex and pixel shader slots are independent namespaces. + VSlotSkin = 2, + VSlotMatFX = 2, + PSSlotD3D9States = 2, + PSSlotMatFX = 3 +}; + +void registerPlatformPlugins(void); +extern Device renderdevice; +Raster *rasterCreate(Raster *raster); +uint8 *rasterLock(Raster *raster, int32 level, int32 lockMode); +void rasterUnlock(Raster *raster, int32 level); +int32 rasterNumLevels(Raster *raster); +bool32 imageFindRasterFormat(Image *img, int32 type, + int32 *width, int32 *height, int32 *depth, int32 *format); +bool32 rasterFromImage(Raster *raster, Image *image); +Image *rasterToImage(Raster *raster); +void destroyRaster(Raster *raster); + +struct VertexElement +{ + uint16 stream; + uint16 offset; + uint8 type; + uint8 method; + uint8 usage; + uint8 usageIndex; +}; + +struct VertexStream +{ + void *vertexBuffer; + uint32 offset; + uint32 stride; + uint16 geometryFlags; + uint8 managed; + uint8 dynamicLock; +}; + +struct DefaultVertex +{ + V3d position; + V3d normal; + RGBA color; + TexCoords texcoord; +}; + +struct SkinVertex +{ + V3d position; + V3d normal; + RGBA color; + TexCoords texcoord; + V4d weights; + uint8 indices[4]; +}; + +struct InstanceData +{ + uint32 numIndex; + uint32 minVert; + Material *material; + bool32 vertexAlpha; + void *vertexShader; + uint32 baseIndex; + uint32 numVertices; + uint32 startIndex; + uint32 numPrimitives; +}; + +struct InstanceDataHeader : rw::InstanceDataHeader +{ + uint32 serialNumber; + uint32 numMeshes; + void *indexBuffer; + uint32 primType; + VertexStream vertexStream[2]; + bool32 useOffsets; + void *vertexDeclaration; + uint32 totalNumIndex; + uint32 totalNumVertex; + + InstanceData *inst; +}; + +void *createVertexDeclaration(VertexElement *elements); +void destroyVertexDeclaration(void *delaration); +uint32 getDeclaration(void *declaration, VertexElement *elements); + +void drawInst_simple(d3d11::InstanceDataHeader *header, d3d11::InstanceData *inst); +// Emulate PS2 GS alpha test FB_ONLY case: failed alpha writes to frame- but not to depth buffer +void drawInst_GSemu(d3d11::InstanceDataHeader *header, InstanceData *inst); +// This one switches between the above two depending on render state; +void drawInst(d3d11::InstanceDataHeader *header, d3d11::InstanceData *inst); + +bool32 openDefaultRenderPipeline(void); +void closeDefaultRenderPipeline(void); +bool32 setIndices(void *indexBuffer); +void clearIndices(void *buffer); +bool32 setStreamSource(int n, void *buffer, uint32 offset, uint32 stride); +void clearStreamSource(void *buffer); +bool32 setVertexDeclaration(void *declaration); +void clearVertexDeclaration(void *declaration); +bool32 setVertexShader(void *shader); +void clearVertexShader(void *shader); +bool32 setPixelShader(void *shader); +void clearPixelShader(void *shader); +void setTexture(uint32 stage, Texture *texture); +void applyDrawState(void); +int32 lightingCB_Shader(Atomic *atomic); +bool32 uploadDefaultMatrices(Matrix *world); +bool32 uploadDefaultMaterial(const RGBA &color, + const SurfaceProperties &surfaceProps); +bool32 setDefaultVertexDeclaration(void); +bool32 setDefaultVertexShader(int32 lightBits); +bool32 setDefaultPixelShader(void); + +void *destroyNativeData(void *object, int32, int32); +Stream *readNativeData(Stream *stream, int32 len, void *object, int32, int32); +Stream *writeNativeData(Stream *stream, int32 len, void *object, int32, int32); +int32 getSizeNativeData(void *object, int32, int32); +void registerNativeDataPlugin(void); + +class ObjPipeline : public rw::ObjPipeline +{ +public: + void init(void); + static ObjPipeline *create(void); + + void (*instanceCB)(Geometry *geo, InstanceDataHeader *header, bool32 reinstance); + void (*uninstanceCB)(Geometry *geo, InstanceDataHeader *header); + void (*renderCB)(Atomic *atomic, InstanceDataHeader *header); +}; + +void defaultInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance); +void defaultUninstanceCB(Geometry *geo, InstanceDataHeader *header); +void defaultRenderCB_Fix(Atomic *atomic, InstanceDataHeader *header); +void defaultRenderCB_Shader(Atomic *atomic, InstanceDataHeader *header); + +ObjPipeline *makeDefaultPipeline(void); + + +// Skin plugin + +void initSkin(void); +void uploadSkinMatrices(Atomic *atomic); +void skinInstanceCB(Geometry *geo, InstanceDataHeader *header, bool32 reinstance); +void skinRenderCB(Atomic *atomic, InstanceDataHeader *header); +ObjPipeline *makeSkinPipeline(void); + +// MatFX plugin + +void initMatFX(void); +ObjPipeline *makeMatFXPipeline(void); + +// Native Texture and Raster + +Texture *readNativeTexture(Stream *stream); +void writeNativeTexture(Texture *tex, Stream *stream); +uint32 getSizeNativeTexture(Texture *tex); + +} +} diff --git a/src/d3d/rwd3dimpl.h b/src/d3d/rwd3dimpl.h index 82f8a135..26b4a5fc 100644 --- a/src/d3d/rwd3dimpl.h +++ b/src/d3d/rwd3dimpl.h @@ -1,7 +1,15 @@ +#ifdef RW_D3D11 +#ifdef WITH_D3D +#include +#include +#define MAX_D3D11_ADAPTERS 16 +#endif +#endif + namespace rw { namespace d3d { -#ifdef RW_D3D9 +#if defined(RW_D3D9) || defined(RW_D3D11) void openIm2D(void); void closeIm2D(void); void im2DRenderLine(void *vertices, int32 numVertices, int32 vert1, int32 vert2); @@ -16,7 +24,9 @@ void im3DRenderPrimitive(PrimitiveType primType); void im3DRenderIndexedPrimitive(PrimitiveType primType, void *indices, int32 numIndices); void im3DEnd(void); +#endif +#ifdef RW_D3D9 struct DisplayMode { D3DDISPLAYMODE mode; @@ -56,16 +66,72 @@ extern D3d9Globals d3d9Globals; void addVidmemRaster(Raster *raster); void removeVidmemRaster(Raster *raster); -void addDynamicVB(uint32 length, uint32 fvf, IDirect3DVertexBuffer9 **buf); // NB: don't share this pointer -void removeDynamicVB(IDirect3DVertexBuffer9 **buf); - -void addDynamicIB(uint32 length, IDirect3DIndexBuffer9 **buf); // NB: don't share this pointer -void removeDynamicIB(IDirect3DIndexBuffer9 **buf); +void addDynamicVB(uint32 length, uint32 fvf, IDirect3DVertexBuffer9** buf); // NB: don't share this pointer +void removeDynamicVB(IDirect3DVertexBuffer9** buf); +void addDynamicIB(uint32 length, IDirect3DIndexBuffer9** buf); // NB: don't share this pointer +void removeDynamicIB(IDirect3DIndexBuffer9** buf); int findFormatDepth(uint32 format); void evictD3D9Raster(Raster *raster); +#endif + +#ifdef RW_D3D11 + +struct DisplayMode +{ + DXGI_MODE_DESC mode; + uint32 flags; +}; + +struct D3d11Globals +{ + HWND window; + + IDXGIFactory* factory; + int numAdapters; + int adapter; + IDXGIAdapter* adapters[MAX_D3D11_ADAPTERS]; + DXGI_ADAPTER_DESC adapterDescs[MAX_D3D11_ADAPTERS]; + + IDXGIOutput* output; + + int numModes; + int currentMode; + DisplayMode* modes; + DisplayMode startMode; + + uint32 msLevel; + + ID3D11Device* d3ddevice; + ID3D11DeviceContext* context; + IDXGISwapChain* swapChain; + D3D_FEATURE_LEVEL featureLevel; + + DXGI_SWAP_CHAIN_DESC present; + ID3D11RenderTargetView* defaultRenderTarget; + ID3D11DepthStencilView* defaultDepthStencilView; + + int numTextures; + int numVertexShaders; + int numPixelShaders; + int numVertexBuffers; + int numIndexBuffers; + int numInputLayouts; + +}; + +extern D3d11Globals d3d11Globals; + +void addDynamicVB(uint32 length, uint32 stride, ID3D11Buffer** buf); // NB: don't share this pointer +void removeDynamicVB(ID3D11Buffer** buf); + +void addDynamicIB(uint32 length, ID3D11Buffer** buf); // NB: don't share this pointer +void removeDynamicIB(ID3D11Buffer** buf); + + + #endif Raster *rasterCreate(Raster *raster); diff --git a/src/d3d/shaders/clear_PS_d11.hlsl b/src/d3d/shaders/clear_PS_d11.hlsl new file mode 100644 index 00000000..c69e2a11 --- /dev/null +++ b/src/d3d/shaders/clear_PS_d11.hlsl @@ -0,0 +1,9 @@ +cbuffer ClearConstants : register(b0) +{ + float4 clearColor; +}; + +float4 main() : SV_Target +{ + return clearColor; +} diff --git a/src/d3d/shaders/clear_VS_d11.hlsl b/src/d3d/shaders/clear_VS_d11.hlsl new file mode 100644 index 00000000..18eae48a --- /dev/null +++ b/src/d3d/shaders/clear_VS_d11.hlsl @@ -0,0 +1,7 @@ +float4 main(uint vertexID : SV_VertexID) : SV_POSITION +{ + float2 position; + position.x = (vertexID == 1) ? 3.0f : -1.0f; + position.y = (vertexID == 2) ? -3.0f : 1.0f; + return float4(position, 1.0f, 1.0f); +} diff --git a/src/d3d/shaders/default_PS_d11.hlsl b/src/d3d/shaders/default_PS_d11.hlsl new file mode 100644 index 00000000..2627db6d --- /dev/null +++ b/src/d3d/shaders/default_PS_d11.hlsl @@ -0,0 +1,31 @@ +Texture2D tex0 : register(t0); +SamplerState samp0 : register(s0); + +#define ALPHA_ALWAYS 0 +#define ALPHA_GREATEREQUAL 1 +#define ALPHA_LESS 2 + +cbuffer D3D9StateConstants : register(b2) +{ + uint alphaEnabled; + uint alphaFunction; + float alphaReference; + float alphaPadding; +}; + +struct PSInput +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +float4 main(PSInput input) : SV_Target +{ + float4 color = input.color * tex0.Sample(samp0, input.texcoord); + if(alphaEnabled != 0 && + ((alphaFunction == ALPHA_GREATEREQUAL && color.a < alphaReference) || + (alphaFunction == ALPHA_LESS && color.a >= alphaReference))) + discard; + return color; +} diff --git a/src/d3d/shaders/default_VS_d11.hlsl b/src/d3d/shaders/default_VS_d11.hlsl new file mode 100644 index 00000000..5cf5746c --- /dev/null +++ b/src/d3d/shaders/default_VS_d11.hlsl @@ -0,0 +1,118 @@ +cbuffer StandardConstants : register(b0) +{ + float4x4 combinedMat : packoffset(c0); + float4x4 worldMat : packoffset(c4); + float3x3 normalMat : packoffset(c8); + float4 matCol : packoffset(c12); + float4 surfProps : packoffset(c13); + float4 fogData : packoffset(c14); + float4 ambientLight : packoffset(c15); +}; + +struct Light +{ + float4 color; // rgb and radius + float4 position; // xyz and -cos(angle) + float4 direction; // xyz and falloff clamp +}; + +cbuffer LightConstants : register(b1) +{ + int4 numLights; + int4 firstLight; + Light lights[8]; +}; + +#define surfAmbient (surfProps.x) +#define surfSpecular (surfProps.y) +#define surfDiffuse (surfProps.z) + +#define fogStart (fogData.x) +#define fogEnd (fogData.y) +#define fogRange (fogData.z) +#define fogDisable (fogData.w) + +#define numDirLights (numLights.x) +#define numPointLights (numLights.y) +#define numSpotLights (numLights.z) + +#define firstDirLight (firstLight.x) +#define firstPointLight (firstLight.y) +#define firstSpotLight (firstLight.z) + +float3 DoDirLight(Light light, float3 normal) +{ + float strength = max(0.0f, dot(normal, -light.direction.xyz)); + return strength * light.color.xyz; +} + +float3 DoPointLight(Light light, float3 vertex, float3 normal) +{ + float3 direction = vertex - light.position.xyz; + float distance = length(direction); + float attenuation = max(0.0f, 1.0f - distance / light.color.w); + float strength = max(0.0f, dot(normal, -normalize(direction))); + return strength * light.color.xyz * attenuation; +} + +float3 DoSpotLight(Light light, float3 vertex, float3 normal) +{ + float3 direction = vertex - light.position.xyz; + float distance = length(direction); + float attenuation = max(0.0f, 1.0f - distance / light.color.w); + direction /= distance; + float strength = max(0.0f, dot(normal, -direction)); + float pointCos = dot(direction, light.direction.xyz); + float coneCos = -light.position.w; + float falloff = (pointCos - coneCos) / (1.0f - coneCos); + if(falloff < 0.0f) + strength = 0.0f; + strength *= max(falloff, light.direction.w); + return strength * light.color.xyz * attenuation; +} + +struct VSInput +{ + float4 Position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +struct VSOutput +{ + float4 Position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + + output.Position = mul(combinedMat, input.Position); + float3 vertex = mul(worldMat, input.Position).xyz; + float3 normal = mul(normalMat, input.normal); + + output.color = input.color; + output.color.rgb += ambientLight.rgb * surfAmbient; + + int i; +#ifdef DIRECTIONALS + for(i = 0; i < numDirLights; i++) + output.color.rgb += DoDirLight(lights[i + firstDirLight], normal) * surfDiffuse; +#endif +#ifdef POINTLIGHTS + for(i = 0; i < numPointLights; i++) + output.color.rgb += DoPointLight(lights[i + firstPointLight], vertex, normal) * surfDiffuse; +#endif +#ifdef SPOTLIGHTS + for(i = 0; i < numSpotLights; i++) + output.color.rgb += DoSpotLight(lights[i + firstSpotLight], vertex, normal) * surfDiffuse; +#endif + + output.color = clamp(output.color, 0.0f, 1.0f); + output.color *= matCol; + output.texcoord = input.texcoord; + return output; +} diff --git a/src/d3d/shaders/im2d_PS_d11.hlsl b/src/d3d/shaders/im2d_PS_d11.hlsl new file mode 100644 index 00000000..50a63443 --- /dev/null +++ b/src/d3d/shaders/im2d_PS_d11.hlsl @@ -0,0 +1,31 @@ +Texture2D tex0 : register(t0); +SamplerState samp0 : register(s0); + +#define ALPHA_ALWAYS 0 +#define ALPHA_GREATEREQUAL 1 +#define ALPHA_LESS 2 + +cbuffer D3D9StateConstants : register(b2) +{ + uint alphaEnabled; + uint alphaFunction; + float alphaReference; + float padding; +}; + +struct PSIn +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +float4 main(PSIn input) : SV_Target +{ + float4 color = input.color * tex0.Sample(samp0, input.texcoord); + if(alphaEnabled != 0 && + ((alphaFunction == ALPHA_GREATEREQUAL && color.a < alphaReference) || + (alphaFunction == ALPHA_LESS && color.a >= alphaReference))) + discard; + return color; +} diff --git a/src/d3d/shaders/im2d_VS_d11.hlsl b/src/d3d/shaders/im2d_VS_d11.hlsl new file mode 100644 index 00000000..e860c8f0 --- /dev/null +++ b/src/d3d/shaders/im2d_VS_d11.hlsl @@ -0,0 +1,32 @@ +cbuffer Im2DConstants : register(b0) +{ + float4 xform; +}; + +struct VSIn +{ + float4 position : POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +struct VSOut +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +VSOut main(VSIn input) +{ + VSOut output; + float z = input.position.w; + float4 position = input.position; + position.xy = position.xy * xform.xy + xform.zw; + position.xyz *= z; + position.w = z; + output.position = position; + output.color = float4(input.color.z, input.color.y, input.color.x, input.color.w); + output.texcoord = input.texcoord; + return output; +} diff --git a/src/d3d/shaders/im3d_PS_d11.hlsl b/src/d3d/shaders/im3d_PS_d11.hlsl new file mode 100644 index 00000000..861c9594 --- /dev/null +++ b/src/d3d/shaders/im3d_PS_d11.hlsl @@ -0,0 +1,28 @@ +#define ALPHA_ALWAYS 0 +#define ALPHA_GREATEREQUAL 1 +#define ALPHA_LESS 2 + +cbuffer D3D9StateConstants : register(b2) +{ + uint alphaEnabled; + uint alphaFunction; + float alphaReference; + float padding; +}; + +struct PSInput +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +float4 main(PSInput input) : SV_Target +{ + float4 color = input.color; + if(alphaEnabled != 0 && + ((alphaFunction == ALPHA_GREATEREQUAL && color.a < alphaReference) || + (alphaFunction == ALPHA_LESS && color.a >= alphaReference))) + discard; + return color; +} diff --git a/src/d3d/shaders/im3d_VS_d11.hlsl b/src/d3d/shaders/im3d_VS_d11.hlsl new file mode 100644 index 00000000..0accf7f6 --- /dev/null +++ b/src/d3d/shaders/im3d_VS_d11.hlsl @@ -0,0 +1,42 @@ +// Shared by the D3D11 Im3D path through im3DTransform. This covers +// immediate-mode 3D primitives such as textured view planes, camera frusta +// and debug lines; regular Atomic geometry and Im2D use different shaders. +cbuffer Im3DConstants : register(b0) +{ + float4x4 combined; + float4x4 world; + float4x4 normal; + float4 viewportOffset; +}; + +struct VSInput +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +struct VSOutput +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + output.position = mul(combined, float4(input.position, 1.0f)); + + // D3D9 and D3D11 use different pixel-center conventions. In the camera + // example, opaque texels in the Im3D view plane write depth before its + // coplanar outline is drawn, so the coverage difference can hide parts + // of that outline. Apply the half-pixel correction only to Im3D; applying + // it to the global viewport would also shift Im2D and blur ImGui text. + output.position.x += output.position.w * viewportOffset.x; + output.position.y -= output.position.w * viewportOffset.y; + output.color = float4(input.color.z, input.color.y, input.color.x, input.color.w); + output.texcoord = input.texcoord; + return output; +} diff --git a/src/d3d/shaders/im3d_tex_PS_d11.hlsl b/src/d3d/shaders/im3d_tex_PS_d11.hlsl new file mode 100644 index 00000000..b095f56a --- /dev/null +++ b/src/d3d/shaders/im3d_tex_PS_d11.hlsl @@ -0,0 +1,31 @@ +Texture2D tex0 : register(t0); +SamplerState samp0 : register(s0); + +#define ALPHA_ALWAYS 0 +#define ALPHA_GREATEREQUAL 1 +#define ALPHA_LESS 2 + +cbuffer D3D9StateConstants : register(b2) +{ + uint alphaEnabled; + uint alphaFunction; + float alphaReference; + float padding; +}; + +struct PSInput +{ + float4 position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +float4 main(PSInput input) : SV_Target +{ + float4 color = input.color * tex0.Sample(samp0, input.texcoord); + if(alphaEnabled != 0 && + ((alphaFunction == ALPHA_GREATEREQUAL && color.a < alphaReference) || + (alphaFunction == ALPHA_LESS && color.a >= alphaReference))) + discard; + return color; +} diff --git a/src/d3d/shaders/matfx_env_PS_d11.hlsl b/src/d3d/shaders/matfx_env_PS_d11.hlsl new file mode 100644 index 00000000..70c3ce4d --- /dev/null +++ b/src/d3d/shaders/matfx_env_PS_d11.hlsl @@ -0,0 +1,57 @@ +Texture2D diffTex : register(t0); +Texture2D envTex : register(t1); +SamplerState diffSampler : register(s0); +SamplerState envSampler : register(s1); + +#define ALPHA_ALWAYS 0 +#define ALPHA_GREATEREQUAL 1 +#define ALPHA_LESS 2 + +cbuffer D3D9StateConstants : register(b2) +{ + uint alphaEnabled; + uint alphaFunction; + float alphaReference; + float alphaPadding; +}; + +cbuffer MatFXConstants : register(b3) +{ + float shininess; + float disableFBA; + float2 matFXPadding; +}; + +struct PSInput +{ + float4 position : SV_POSITION; + float2 texcoord0 : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; + float fog : TEXCOORD2; + float4 color : COLOR0; + float4 envColor : COLOR1; +}; + +float4 main(PSInput input) : SV_Target +{ + float4 pass1 = input.color; +#ifdef TEX + pass1 *= diffTex.Sample(diffSampler, input.texcoord0); +#endif + + float4 pass2 = input.envColor * shininess * + envTex.Sample(envSampler, input.texcoord1); + + pass2.rgb = lerp(float3(0.0f, 0.0f, 0.0f), pass2.rgb, input.fog); + + float fba = max(pass1.a, disableFBA); + float4 color; + color.rgb = pass1.rgb * pass1.a + pass2.rgb * fba; + color.a = pass1.a; + + if(alphaEnabled != 0 && + ((alphaFunction == ALPHA_GREATEREQUAL && color.a < alphaReference) || + (alphaFunction == ALPHA_LESS && color.a >= alphaReference))) + discard; + return color; +} diff --git a/src/d3d/shaders/matfx_env_VS_d11.hlsl b/src/d3d/shaders/matfx_env_VS_d11.hlsl new file mode 100644 index 00000000..34a49927 --- /dev/null +++ b/src/d3d/shaders/matfx_env_VS_d11.hlsl @@ -0,0 +1,129 @@ +cbuffer StandardConstants : register(b0) +{ + float4x4 combinedMat : packoffset(c0); + float4x4 worldMat : packoffset(c4); + float3x3 normalMat : packoffset(c8); + float4 matCol : packoffset(c12); + float4 surfProps : packoffset(c13); + float4 fogData : packoffset(c14); + float4 ambientLight : packoffset(c15); +}; + +struct Light +{ + float4 color; + float4 position; + float4 direction; +}; + +cbuffer LightConstants : register(b1) +{ + int4 numLights; + int4 firstLight; + Light lights[8]; +}; + +cbuffer MatFXConstants : register(b2) +{ + float4x4 texMat; + float4 colorClamp; + float4 envColor; +}; + +#define surfAmbient (surfProps.x) +#define surfDiffuse (surfProps.z) + +#define numDirLights (numLights.x) +#define numPointLights (numLights.y) +#define numSpotLights (numLights.z) + +#define firstDirLight (firstLight.x) +#define firstPointLight (firstLight.y) +#define firstSpotLight (firstLight.z) + +float3 DoDirLight(Light light, float3 normal) +{ + float strength = max(0.0f, dot(normal, -light.direction.xyz)); + return strength * light.color.xyz; +} + +float3 DoPointLight(Light light, float3 vertex, float3 normal) +{ + float3 direction = vertex - light.position.xyz; + float distance = length(direction); + float attenuation = max(0.0f, 1.0f - distance / light.color.w); + float strength = max(0.0f, dot(normal, -normalize(direction))); + return strength * light.color.xyz * attenuation; +} + +float3 DoSpotLight(Light light, float3 vertex, float3 normal) +{ + float3 direction = vertex - light.position.xyz; + float distance = length(direction); + float attenuation = max(0.0f, 1.0f - distance / light.color.w); + direction /= distance; + float strength = max(0.0f, dot(normal, -direction)); + float pointCos = dot(direction, light.direction.xyz); + float coneCos = -light.position.w; + float falloff = (pointCos - coneCos) / (1.0f - coneCos); + if(falloff < 0.0f) + strength = 0.0f; + strength *= max(falloff, light.direction.w); + return strength * light.color.xyz * attenuation; +} + +struct VSInput +{ + float4 Position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +struct VSOutput +{ + float4 Position : SV_POSITION; + float2 texcoord0 : TEXCOORD0; + float2 texcoord1 : TEXCOORD1; + float fog : TEXCOORD2; + float4 color : COLOR0; + float4 envColor : COLOR1; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + + output.Position = mul(combinedMat, input.Position); + float3 vertex = mul(worldMat, input.Position).xyz; + float3 normal = mul(normalMat, input.normal); + + output.texcoord0 = input.texcoord; + output.texcoord1 = mul(texMat, float4(normal, 1.0f)).xy; + + output.color = input.color; + output.color.rgb += ambientLight.rgb * surfAmbient; + + int i; +#ifdef DIRECTIONALS + for(i = 0; i < numDirLights; i++) + output.color.rgb += DoDirLight( + lights[i + firstDirLight], normal) * surfDiffuse; +#endif +#ifdef POINTLIGHTS + for(i = 0; i < numPointLights; i++) + output.color.rgb += DoPointLight( + lights[i + firstPointLight], vertex, normal) * surfDiffuse; +#endif +#ifdef SPOTLIGHTS + for(i = 0; i < numSpotLights; i++) + output.color.rgb += DoSpotLight( + lights[i + firstSpotLight], vertex, normal) * surfDiffuse; +#endif + + output.color = clamp(output.color, 0.0f, 1.0f); + output.envColor = max(output.color, colorClamp) * envColor; + output.color *= matCol; + output.fog = 1.0f; + return output; +} diff --git a/src/d3d/shaders/skin_VS_d11.hlsl b/src/d3d/shaders/skin_VS_d11.hlsl new file mode 100644 index 00000000..42031ef8 --- /dev/null +++ b/src/d3d/shaders/skin_VS_d11.hlsl @@ -0,0 +1,131 @@ +cbuffer StandardConstants : register(b0) +{ + float4x4 combinedMat : packoffset(c0); + float4x4 worldMat : packoffset(c4); + float3x3 normalMat : packoffset(c8); + float4 matCol : packoffset(c12); + float4 surfProps : packoffset(c13); + float4 fogData : packoffset(c14); + float4 ambientLight : packoffset(c15); +}; + +struct Light +{ + float4 color; + float4 position; + float4 direction; +}; + +cbuffer LightConstants : register(b1) +{ + int4 numLights; + int4 firstLight; + Light lights[8]; +}; + +cbuffer SkinConstants : register(b2) +{ + float4x3 boneMatrices[64]; +}; + +#define surfAmbient (surfProps.x) +#define surfDiffuse (surfProps.z) + +#define numDirLights (numLights.x) +#define numPointLights (numLights.y) +#define numSpotLights (numLights.z) + +#define firstDirLight (firstLight.x) +#define firstPointLight (firstLight.y) +#define firstSpotLight (firstLight.z) + +float3 DoDirLight(Light light, float3 normal) +{ + float strength = max(0.0f, dot(normal, -light.direction.xyz)); + return strength * light.color.xyz; +} + +float3 DoPointLight(Light light, float3 vertex, float3 normal) +{ + float3 direction = vertex - light.position.xyz; + float distance = length(direction); + float attenuation = max(0.0f, 1.0f - distance / light.color.w); + float strength = max(0.0f, dot(normal, -normalize(direction))); + return strength * light.color.xyz * attenuation; +} + +float3 DoSpotLight(Light light, float3 vertex, float3 normal) +{ + float3 direction = vertex - light.position.xyz; + float distance = length(direction); + float attenuation = max(0.0f, 1.0f - distance / light.color.w); + direction /= distance; + float strength = max(0.0f, dot(normal, -direction)); + float pointCos = dot(direction, light.direction.xyz); + float coneCos = -light.position.w; + float falloff = (pointCos - coneCos) / (1.0f - coneCos); + if(falloff < 0.0f) + strength = 0.0f; + strength *= max(falloff, light.direction.w); + return strength * light.color.xyz * attenuation; +} + +struct VSInput +{ + float4 Position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; + float4 weights : BLENDWEIGHT0; + uint4 indices : BLENDINDICES0; +}; + +struct VSOutput +{ + float4 Position : SV_POSITION; + float4 color : COLOR0; + float2 texcoord : TEXCOORD0; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + + float3 skinVertex = float3(0.0f, 0.0f, 0.0f); + float3 skinNormal = float3(0.0f, 0.0f, 0.0f); + for(int j = 0; j < 4; j++){ + skinVertex += mul(input.Position, + boneMatrices[input.indices[j]]).xyz * input.weights[j]; + skinNormal += mul(input.normal, + (float3x3)boneMatrices[input.indices[j]]).xyz * input.weights[j]; + } + + output.Position = mul(combinedMat, float4(skinVertex, 1.0f)); + float3 vertex = mul(worldMat, float4(skinVertex, 1.0f)).xyz; + float3 normal = mul(normalMat, skinNormal); + + output.color = input.color; + output.color.rgb += ambientLight.rgb * surfAmbient; + + int i; +#ifdef DIRECTIONALS + for(i = 0; i < numDirLights; i++) + output.color.rgb += DoDirLight( + lights[i + firstDirLight], normal) * surfDiffuse; +#endif +#ifdef POINTLIGHTS + for(i = 0; i < numPointLights; i++) + output.color.rgb += DoPointLight( + lights[i + firstPointLight], vertex, normal) * surfDiffuse; +#endif +#ifdef SPOTLIGHTS + for(i = 0; i < numSpotLights; i++) + output.color.rgb += DoSpotLight( + lights[i + firstSpotLight], vertex, normal) * surfDiffuse; +#endif + + output.color = clamp(output.color, 0.0f, 1.0f); + output.color *= matCol; + output.texcoord = input.texcoord; + return output; +} diff --git a/src/engine.cpp b/src/engine.cpp index 0583cb39..5965efca 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -15,6 +15,9 @@ #include "d3d/rwd3d.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" +#ifdef RW_D3D11 +#include "d3d/rwd3d11.h" +#endif #include "gl/rwgl3.h" #include "gl/rwwdgl.h" @@ -234,6 +237,9 @@ Engine::init(MemoryFunctions *memfuncs) xbox::registerPlatformPlugins(); d3d8::registerPlatformPlugins(); d3d9::registerPlatformPlugins(); + #ifdef RW_D3D11 + d3d11::registerPlatformPlugins(); + #endif wdgl::registerPlatformPlugins(); gl3::registerPlatformPlugins(); @@ -268,6 +274,8 @@ Engine::open(EngineOpenParams *p) engine->device = ps2::renderdevice; #elif RW_GL3 engine->device = gl3::renderdevice; +#elif RW_D3D11 + engine->device = d3d11::renderdevice; #elif RW_D3D9 engine->device = d3d::renderdevice; #else diff --git a/src/geoplg.cpp b/src/geoplg.cpp index c1e13567..aa46d536 100644 --- a/src/geoplg.cpp +++ b/src/geoplg.cpp @@ -16,6 +16,9 @@ #include "d3d/rwxbox.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" +#ifdef RW_D3D11 +#include "d3d/rwd3d11.h" +#endif #include "gl/rwwdgl.h" #include "gl/rwgl3.h" @@ -249,6 +252,10 @@ destroyNativeData(void *object, int32 offset, int32 size) return d3d8::destroyNativeData(object, offset, size); if(geometry->instData->platform == PLATFORM_D3D9) return d3d9::destroyNativeData(object, offset, size); +#ifdef RW_D3D11 + if(geometry->instData->platform == PLATFORM_D3D11) + return d3d11::destroyNativeData(object, offset, size); +#endif if(geometry->instData->platform == PLATFORM_GL3) return gl3::destroyNativeData(object, offset, size); return object; @@ -276,6 +283,10 @@ readNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s) return d3d8::readNativeData(stream, len, object, o, s); else if(platform == PLATFORM_D3D9) return d3d9::readNativeData(stream, len, object, o, s); +#ifdef RW_D3D11 + else if(platform == PLATFORM_D3D11) + return d3d11::readNativeData(stream, len, object, o, s); +#endif else{ fprintf(stderr, "unknown platform %d\n", platform); stream->seek(len); @@ -303,6 +314,10 @@ writeNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s) return d3d8::writeNativeData(stream, len, object, o, s); else if(geometry->instData->platform == PLATFORM_D3D9) return d3d9::writeNativeData(stream, len, object, o, s); +#ifdef RW_D3D11 + else if(geometry->instData->platform == PLATFORM_D3D11) + return d3d11::writeNativeData(stream, len, object, o, s); +#endif return stream; } @@ -322,6 +337,10 @@ getSizeNativeData(void *object, int32 offset, int32 size) return d3d8::getSizeNativeData(object, offset, size); else if(geometry->instData->platform == PLATFORM_D3D9) return d3d9::getSizeNativeData(object, offset, size); +#ifdef RW_D3D11 + else if(geometry->instData->platform == PLATFORM_D3D11) + return d3d11::getSizeNativeData(object, offset, size); +#endif return 0; } diff --git a/src/matfx.cpp b/src/matfx.cpp index c143fc17..e8d4942d 100644 --- a/src/matfx.cpp +++ b/src/matfx.cpp @@ -16,6 +16,9 @@ #include "d3d/rwxbox.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" +#ifdef RW_D3D11 +#include "d3d/rwd3d11.h" +#endif #include "gl/rwwdgl.h" #include "gl/rwgl3.h" #include "gl/rwgl3plg.h" @@ -617,6 +620,9 @@ registerMatFXPlugin(void) xbox::initMatFX(); d3d8::initMatFX(); d3d9::initMatFX(); + #ifdef RW_D3D11 + d3d11::initMatFX(); + #endif wdgl::initMatFX(); gl3::initMatFX(); diff --git a/src/raster.cpp b/src/raster.cpp index c7ebffe0..89273c46 100644 --- a/src/raster.cpp +++ b/src/raster.cpp @@ -460,6 +460,81 @@ d3d_to_gl3(rw::Raster *ras) #endif } +#ifdef RW_D3D11 +static bool32 +copy_raster_mip(rw::Raster *source, rw::Raster *destination, int32 mipLevel) +{ + using namespace rw; + + if(source->lock(mipLevel, Raster::LOCKREAD) == nil) + return 0; + + Image *image = source->toImage(); + source->unlock(mipLevel); + if(image == nil) + return 0; + image->unpalettize(); + + if(destination->lock(mipLevel, + Raster::LOCKWRITE | Raster::LOCKNOFETCH) == nil){ + image->destroy(); + return 0; + } + + bool32 converted = destination->setFromImage(image) != nil; //Copy only in Cpu memory + destination->unlock( mipLevel ); //Here upload the mipmap level to the GPU + image->destroy(); + return converted; +} + +static rw::Raster* +d3d_to_d3d11(rw::Raster *source) +{ + using namespace rw; + + Image *baseImage = source->toImage(); + if(baseImage == nil) + return nil; + baseImage->unpalettize(); + + int32 width, height, depth, format; + if(!Raster::imageFindRasterFormat(baseImage, Raster::TEXTURE, + &width, &height, &depth, &format)){ + baseImage->destroy(); + return nil; + } + + format |= source->format & (Raster::MIPMAP | Raster::AUTOMIPMAP); + Raster *destination = Raster::create(width, height, depth, format); + if(destination == nil){ + baseImage->destroy(); + return nil; + } + + bool32 baseConverted = destination->setFromImage(baseImage) != nil; + baseImage->destroy(); + if(!baseConverted){ + destination->destroy(); + return nil; + } + + int32 numLevels = source->getNumLevels(); + int32 destinationNumLevels = destination->getNumLevels(); + if(numLevels > destinationNumLevels) + numLevels = destinationNumLevels; + + for(int32 mipLevel = 1; mipLevel < numLevels; mipLevel++) + if(!copy_raster_mip(source, destination, mipLevel)){ + destination->destroy(); + return nil; + } + + GETD3DRASTEREXT(destination)->hasAlpha = + GETD3DRASTEREXT(source)->hasAlpha; + return destination; +} +#endif + static rw::Raster* xbox_to_gl3(rw::Raster *ras) { @@ -515,6 +590,15 @@ Raster::convertTexToCurrentPlatform(rw::Raster *ras) ras->destroy(); return newras; } +#ifdef RW_D3D11 + }else if((ras->platform == PLATFORM_D3D8 || ras->platform == PLATFORM_D3D9) && + rw::platform == PLATFORM_D3D11){ + Raster *newras = d3d_to_d3d11(ras); + if(newras){ + ras->destroy(); + return newras; + } +#endif }else if(ras->platform == PLATFORM_XBOX && (rw::platform == PLATFORM_D3D9 || rw::platform == PLATFORM_D3D8)){ Raster *newras = xbox_to_d3d(ras); if(newras){ diff --git a/src/rwbase.h b/src/rwbase.h index 6bc8a544..af2c2675 100644 --- a/src/rwbase.h +++ b/src/rwbase.h @@ -27,6 +27,10 @@ #define RWHALFPIXEL #endif +#ifdef RW_D3D11 +#define RWDEVICE d3d +#endif + #ifdef RW_D3D8 #define RWDEVICE d3d #endif @@ -537,6 +541,7 @@ enum Platform // SOFTRAS PLATFORM_D3D8 = 8, PLATFORM_D3D9 = 9, + PLATFORM_D3D11 = 10, // PSP // non-stock-RW platforms @@ -544,6 +549,7 @@ enum Platform PLATFORM_WDGL = 11, // WarDrum OpenGL PLATFORM_GL3 = 12, // my GL3 implementation + NUM_PLATFORMS, FOURCC_PS2 = 0x00325350 // 'PS2\0' diff --git a/src/skin.cpp b/src/skin.cpp index abaa5487..bbb2eb3d 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -16,6 +16,9 @@ #include "d3d/rwxbox.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" +#ifdef RW_D3D11 +#include "d3d/rwd3d11.h" +#endif #include "gl/rwwdgl.h" #include "gl/rwgl3.h" #include "gl/rwgl3plg.h" @@ -371,6 +374,9 @@ registerSkinPlugin(void) xbox::initSkin(); d3d8::initSkin(); d3d9::initSkin(); +#ifdef RW_D3D11 + d3d11::initSkin(); +#endif wdgl::initSkin(); gl3::initSkin(); diff --git a/src/texture.cpp b/src/texture.cpp index 961649e0..d223e492 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -15,6 +15,9 @@ #include "d3d/rwxbox.h" #include "d3d/rwd3d8.h" #include "d3d/rwd3d9.h" +#ifdef RW_D3D11 +#include "d3d/rwd3d11.h" +#endif #include "d3d/rwd3dimpl.h" #include "gl/rwgl3.h" @@ -477,6 +480,10 @@ Texture::streamReadNative(Stream *stream) return d3d8::readNativeTexture(stream); if(platform == PLATFORM_D3D9) return d3d9::readNativeTexture(stream); +#ifdef RW_D3D11 + if(platform == PLATFORM_D3D11) + return d3d11::readNativeTexture(stream); +#endif if(platform == PLATFORM_XBOX) return xbox::readNativeTexture(stream); if(platform == PLATFORM_GL3) @@ -494,6 +501,10 @@ Texture::streamWriteNative(Stream *stream) d3d8::writeNativeTexture(this, stream); else if(this->raster->platform == PLATFORM_D3D9) d3d9::writeNativeTexture(this, stream); +#ifdef RW_D3D11 + else if(this->raster->platform == PLATFORM_D3D11) + d3d11::writeNativeTexture(this, stream); +#endif else if(this->raster->platform == PLATFORM_XBOX) xbox::writeNativeTexture(this, stream); else if(this->raster->platform == PLATFORM_GL3) @@ -511,6 +522,10 @@ Texture::streamGetSizeNative(void) return d3d8::getSizeNativeTexture(this); if(this->raster->platform == PLATFORM_D3D9) return d3d9::getSizeNativeTexture(this); +#ifdef RW_D3D11 + if(this->raster->platform == PLATFORM_D3D11) + return d3d11::getSizeNativeTexture(this); +#endif if(this->raster->platform == PLATFORM_XBOX) return xbox::getSizeNativeTexture(this); if(this->raster->platform == PLATFORM_GL3)