From 2118b1fbd9d3d2900ec3a8790286f66fd996ac34 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 29 Jan 2026 13:27:38 -0600 Subject: [PATCH] render_state: add DDS texture image loading --- Makefile | 1 + include/dds.h | 124 +++++++++++++++++++++++++++ include/dds_validate.hpp | 11 +++ include/render_state.hpp | 3 + main.rc | 2 +- models/robot_player/robot_player.DDS | Bin 0 -> 2872 bytes src/dds_validate.cpp | 66 ++++++++++++++ src/effect/collada_scene.fx | 8 +- src/main.cpp | 15 ++-- src/render_state.cpp | 60 ++++++++++++- 10 files changed, 275 insertions(+), 15 deletions(-) create mode 100644 include/dds.h create mode 100644 include/dds_validate.hpp create mode 100755 models/robot_player/robot_player.DDS create mode 100644 src/dds_validate.cpp diff --git a/Makefile b/Makefile index 02651c6..8e08727 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ OBJS = \ $(BUILD_TYPE)/print.obj \ $(BUILD_TYPE)/render_state.obj \ $(BUILD_TYPE)/input.obj \ + $(BUILD_TYPE)/dds_validate.obj \ $(BUILD_TYPE)/collada.obj \ $(BUILD_TYPE)/collada_scene.obj \ $(BUILD_TYPE)/scenes/curve_interpolation/curve_interpolation.obj diff --git a/include/dds.h b/include/dds.h new file mode 100644 index 0000000..f3cddeb --- /dev/null +++ b/include/dds.h @@ -0,0 +1,124 @@ +//-------------------------------------------------------------------------------------- +// dds.h +// +// This header defines constants and structures that are useful when parsing +// DDS files. DDS files were originally designed to use several structures +// and constants that are native to DirectDraw and are defined in ddraw.h, +// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar +// (compatible) constants and structures so that one can use DDS files +// without needing to include ddraw.h. +//-------------------------------------------------------------------------------------- + +#ifndef _DDS_H_ +#define _DDS_H_ + +#include +#include + +#pragma pack(push,1) + +#define DDS_MAGIC 0x20534444 // "DDS " + +struct DDS_PIXELFORMAT +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFourCC; + DWORD dwRGBBitCount; + DWORD dwRBitMask; + DWORD dwGBitMask; + DWORD dwBBitMask; + DWORD dwABitMask; +}; + +#define DDS_FOURCC 0x00000004 // DDPF_FOURCC +#define DDS_RGB 0x00000040 // DDPF_RGB +#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS +#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE +#define DDS_ALPHA 0x00000002 // DDPF_ALPHA + +const DDS_PIXELFORMAT DDSPF_DXT1 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT2 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT3 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT4 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT5 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_A8R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; + +const DDS_PIXELFORMAT DDSPF_A1R5G5B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 }; + +const DDS_PIXELFORMAT DDSPF_A4R4G4B4 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 }; + +const DDS_PIXELFORMAT DDSPF_R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }; + +const DDS_PIXELFORMAT DDSPF_R5G6B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 }; + +// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat) +const DDS_PIXELFORMAT DDSPF_DX10 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }; + +#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT +#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT +#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH +#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH +#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE + +#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE +#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP +#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX + +#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX +#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX +#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY +#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY +#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ +#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ + +#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\ + DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\ + DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ ) + +#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME + +typedef struct +{ + DWORD dwSize; + DWORD dwHeaderFlags; + DWORD dwHeight; + DWORD dwWidth; + DWORD dwPitchOrLinearSize; + DWORD dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags + DWORD dwMipMapCount; + DWORD dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + DWORD dwSurfaceFlags; + DWORD dwCubemapFlags; + DWORD dwReserved2[3]; +} DDS_HEADER; + +typedef struct +{ + DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + UINT miscFlag; + UINT arraySize; + UINT reserved; +} DDS_HEADER_DXT10; + +#pragma pack(pop) + +#endif // _DDS_H diff --git a/include/dds_validate.hpp b/include/dds_validate.hpp new file mode 100644 index 0000000..a9bf692 --- /dev/null +++ b/include/dds_validate.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "dds.h" + +struct DDS_FILE { + DWORD dwMagic; + DDS_HEADER header; +}; + +void dds_validate(DDS_FILE const * const buf, unsigned int size, + D3D10_SUBRESOURCE_DATA * subresourceData); diff --git a/include/render_state.hpp b/include/render_state.hpp index 870a922..10836b9 100644 --- a/include/render_state.hpp +++ b/include/render_state.hpp @@ -8,6 +8,9 @@ HRESULT LoadTexture2D(const wchar_t * resourceName, const DXGI_FORMAT format, ID3D10ShaderResourceView ** pTextureShaderResourceView); +HRESULT LoadDDSTexture2D(const wchar_t * resourceName, + ID3D10ShaderResourceView ** pTextureShaderResourceView); + HRESULT LoadTexture3D(const wchar_t * resourceName, const int width, const int height, diff --git a/main.rc b/main.rc index 55feb50..e51fd27 100644 --- a/main.rc +++ b/main.rc @@ -4,7 +4,7 @@ RES_VOLUME_FXO RCDATA "volume.fxo" RES_BLOOM_FXO RCDATA "bloom.fxo" RES_STATIC_FXO RCDATA "static.fxo" RES_PERLIN RCDATA "texture/perlin.data" -RES_ROBOT_PLAYER RCDATA "models/robot_player/robot_player.data" +RES_ROBOT_PLAYER RCDATA "models/robot_player/robot_player.DDS" RES_FONT_TERMINUS_6X12 RCDATA "font/terminus_128x64_6x12.data" RES_COLLADA_FXO RCDATA "collada.fxo" diff --git a/models/robot_player/robot_player.DDS b/models/robot_player/robot_player.DDS new file mode 100755 index 0000000000000000000000000000000000000000..09802d5d5d92c209f5fcf7309c8d8e2176afa676 GIT binary patch literal 2872 zcmeHJO=uHA6do}(d(ue*l4FALpjb3W?}_9fo%u8nG1%N(~6I7ts_9 zN_(&(Yf9Y6Tq4nv9z66=a6|k_PZen_1z{U(vOCUfvkDuQEWL?&F!^}j%)D>%=I3oR zI^v%N034t#+-bKdGIQ^O<6l1=>7p%~OoSMA84Pz(01(6MP^-5@0AdT8@+AuZlK!B< z4>a3K4bz~=4vWo~Q?WQdrYW*8c_o>Qa64F4x3}%|tb7Z9&ide>Pp`~D;BvVLp7Q|+ zVGFmj*>&zL$<&zbt$YouYr3 z;c1TtsNY@*XfmBHWn_U&uQjb`jT7O9(mY+Cm3QjrL|H%x?du?@R^-gtFuG;c?d3bw zvyRJ&oALdFUay&7wvI5hUV7GkYh0&377vbi9~>b}m)*0DKC;F)eOV}+WB0>AkH=&3 zPWAfZ*lpVTdF|(~pTB?k{M41<3Glp}uPfIl!0|WFjJjS%yY-#oQFvqJQU20SfSXy; zG_C7h*KsN1<6gYg@oFaM-yk)dqu&n*nHb=}LGDE`e)GN#IlC7tHr7 z!qIv|5DIYjg%(j&yZJeBHFL=AuCRA9nM#hE^JU@WC;&eaERIUeZvOwukG=o(5L9*a zc!lnlB%uiR@#(s*>t;Rn2rL*(^V>o;5{Ydrt} literal 0 HcmV?d00001 diff --git a/src/dds_validate.cpp b/src/dds_validate.cpp new file mode 100644 index 0000000..1f2abc7 --- /dev/null +++ b/src/dds_validate.cpp @@ -0,0 +1,66 @@ +#include +#include + +#include "dds_validate.hpp" + +static inline unsigned int max(unsigned int a, unsigned int b) +{ + return (a > b) ? a : b; +} + +struct dds_size_levels { + unsigned int const size; + unsigned int const levels; +}; + +static inline unsigned int dim(unsigned int d) +{ + return max(1, (d / 4)); +} + +static inline dds_size_levels dds_mip_total_size(uintptr_t data, + unsigned int height, + unsigned int width, + unsigned int max_mip_levels, + D3D10_SUBRESOURCE_DATA * subresourceData) +{ + unsigned int mip_total_size = 0; + unsigned int mip_levels = 0; + while (true) { + unsigned int mip_size = dim(height) * dim(width) * 8; + mip_total_size += mip_size; + subresourceData[mip_levels].pSysMem = (const void *)data; + subresourceData[mip_levels].SysMemPitch = dim(width) * 8; + mip_levels += 1; + assert(mip_levels <= max_mip_levels); + data += mip_size; + + if (width == 1 && height == 1) + break; + + height /= 2; + width /= 2; + } + + return (dds_size_levels){mip_total_size, mip_levels}; +} + +void dds_validate(DDS_FILE const * const dds, unsigned int size, + D3D10_SUBRESOURCE_DATA * subresourceData) +{ + assert(dds->dwMagic == DDS_MAGIC); + assert(dds->header.dwSize == 124); + assert(dds->header.ddspf.dwSize == 32); + assert(dds->header.ddspf.dwFlags == DDS_FOURCC); + assert(dds->header.ddspf.dwFourCC == MAKEFOURCC('D','X','T','1')); + + assert(dds->header.dwDepth == 0); + + dds_size_levels ret = dds_mip_total_size(((uintptr_t)dds) + (sizeof (DDS_FILE)), + dds->header.dwHeight, + dds->header.dwWidth, + dds->header.dwMipMapCount, + subresourceData); + assert(ret.size + (sizeof (DDS_FILE)) == size); + assert(ret.levels == dds->header.dwMipMapCount); +} diff --git a/src/effect/collada_scene.fx b/src/effect/collada_scene.fx index 0c593b5..31e3cad 100644 --- a/src/effect/collada_scene.fx +++ b/src/effect/collada_scene.fx @@ -58,14 +58,18 @@ PS_INPUT VS(VS_INPUT input) float4 PS(PS_INPUT input) : SV_Target { float3 normal = normalize(input.Norm); - float3 view_dir = normalize(ViewEye.xyz - input.Pos.xyz); + float3 view_dir = normalize(ViewEye.xyz - input.WPos.xyz); float3 color = Emission.xyz; for (int i = 0; i < 2; i++) { float3 light_dir = normalize(-LightDir[i].xyz); float diffuse_intensity = max(dot(normal, light_dir), 0.0); - color += Diffuse.xyz * diffuse_intensity * LightColor[i].xyz; + + float distance = length(LightPos[i].xyz - input.WPos.xyz); + float attenuation = 1.0 / (0.02 * distance * distance); + + color += Diffuse.xyz * diffuse_intensity * LightColor[i].xyz * attenuation; } return float4(color.xyz, 1); diff --git a/src/main.cpp b/src/main.cpp index cc25f9e..a805d1a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -503,12 +503,8 @@ HRESULT LoadMesh() // textures ////////////////////////////////////////////////////////////////////// - hr = LoadTexture2D(L"RES_ROBOT_PLAYER", - 64, // width - 64, // height - 64 * 4, // pitch - DXGI_FORMAT_R8G8B8A8_UNORM, - &g_pTextureShaderResourceView); + hr = LoadDDSTexture2D(L"RES_ROBOT_PLAYER", + &g_pTextureShaderResourceView); if (FAILED(hr)) { print("LoadTexture2D\n"); return hr; @@ -1412,7 +1408,7 @@ void RenderModel(float t) XMMATRIX rx = XMMatrixRotationX(XM_PI * -0.0f); XMMATRIX ry = XMMatrixRotationY(XM_PI * -1.0f + t); XMMATRIX mWorldTranslate = XMMatrixTranslation(0.0f, 0.0f, 2.0f); - g_World1 = XMMatrixMultiply(rx, ry) * mWorldTranslate; + g_World1 = XMMatrixScaling(5, 5, 5), XMMatrixMultiply(rx, ry) * mWorldTranslate; // matrices g_pViewVariable->SetMatrix((float *)&g_View); @@ -1701,7 +1697,8 @@ void RenderBloom() float deadzone(float f) { - const float threshold = 0.25f; + //const float threshold = 0.25f; + const float threshold = 0.01f; if (fabsf(f) <= threshold) return 0.0f; else { @@ -1825,7 +1822,7 @@ void Render(float t, float dt) g_pd3dDevice->ClearDepthStencilView(g_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0); // render - //RenderModel(t); + RenderModel(t); const float ClearColorZero[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; ID3D10RenderTargetView * RenderTargets[] = { diff --git a/src/render_state.cpp b/src/render_state.cpp index f74a3c7..496af1c 100644 --- a/src/render_state.cpp +++ b/src/render_state.cpp @@ -6,6 +6,7 @@ #include "globals.hpp" #include "print.hpp" #include "render_state.hpp" +#include "dds_validate.hpp" HRESULT LoadTexture2D(const wchar_t * resourceName, const int width, @@ -54,7 +55,60 @@ HRESULT LoadTexture2D(const wchar_t * resourceName, descSRV.Format = textureDesc.Format; descSRV.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; descSRV.Texture2D.MostDetailedMip = 0; - descSRV.Texture2D.MipLevels = 1; + descSRV.Texture2D.MipLevels = textureDesc.MipLevels; + hr = g_pd3dDevice->CreateShaderResourceView(pTexture, &descSRV, pTextureShaderResourceView); + if (FAILED(hr)) { + print("CreateShaderResourceView\n"); + return hr; + } + + return S_OK; +} + +HRESULT LoadDDSTexture2D(const wchar_t * resourceName, + ID3D10ShaderResourceView ** pTextureShaderResourceView) +{ + HRESULT hr; + + printW(L"LoadDDSTexture2D %s\n", resourceName); + + // texture + HRSRC hRes = FindResource(NULL, resourceName, RT_RCDATA); + if (hRes == NULL) { + print("FindResource %s\n", resourceName); + return -1; + } + DWORD dwResourceSize = SizeofResource(NULL, hRes); + void const * data = LockResource(LoadResource(NULL, hRes)); + DDS_FILE const * dds = (DDS_FILE const *)data; + D3D10_SUBRESOURCE_DATA subresourceData[dds->header.dwMipMapCount]; + dds_validate(dds, dwResourceSize, subresourceData); + + D3D10_TEXTURE2D_DESC textureDesc; + textureDesc.Width = dds->header.dwWidth; + textureDesc.Height = dds->header.dwHeight; + textureDesc.MipLevels = dds->header.dwMipMapCount; + textureDesc.ArraySize = 1; + textureDesc.Format = DXGI_FORMAT_BC1_UNORM; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.Usage = D3D10_USAGE_IMMUTABLE; + textureDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + textureDesc.CPUAccessFlags = 0; + textureDesc.MiscFlags = 0; + + ID3D10Texture2D * pTexture; + hr = g_pd3dDevice->CreateTexture2D(&textureDesc, subresourceData, &pTexture); + if (FAILED(hr)) { + print("DDS CreateTexture2D\n"); + return hr; + } + + D3D10_SHADER_RESOURCE_VIEW_DESC descSRV; + descSRV.Format = textureDesc.Format; + descSRV.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; + descSRV.Texture2D.MostDetailedMip = 0; + descSRV.Texture2D.MipLevels = textureDesc.MipLevels; hr = g_pd3dDevice->CreateShaderResourceView(pTexture, &descSRV, pTextureShaderResourceView); if (FAILED(hr)) { print("CreateShaderResourceView\n"); @@ -113,7 +167,7 @@ HRESULT LoadTexture3D(const wchar_t * resourceName, descSRV.Format = textureDesc.Format; descSRV.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE3D; descSRV.Texture3D.MostDetailedMip = 0; - descSRV.Texture3D.MipLevels = 1; + descSRV.Texture3D.MipLevels = textureDesc.MipLevels; hr = g_pd3dDevice->CreateShaderResourceView(pTexture, &descSRV, pTextureShaderResourceView); if (FAILED(hr)) { print("CreateShaderResourceView\n"); @@ -161,7 +215,7 @@ HRESULT CreateTextureRenderTargetView(const int width, descSRV.Format = textureDesc.Format; descSRV.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; descSRV.Texture2D.MostDetailedMip = 0; - descSRV.Texture2D.MipLevels = 1; + descSRV.Texture2D.MipLevels = textureDesc.MipLevels; hr = g_pd3dDevice->CreateShaderResourceView(pTexture, &descSRV, pTextureShaderResourceView); if (FAILED(hr)) { print("CreateShaderResourceView\n");