render_state: add DDS texture image loading

This commit is contained in:
Zack Buhman 2026-01-29 13:27:38 -06:00
parent b9cfcde9c7
commit 2118b1fbd9
10 changed files with 275 additions and 15 deletions

View File

@ -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

124
include/dds.h Normal file
View File

@ -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 <dxgiformat.h>
#include <d3d10.h>
#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

11
include/dds_validate.hpp Normal file
View File

@ -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);

View File

@ -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,

View File

@ -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"

Binary file not shown.

66
src/dds_validate.cpp Normal file
View File

@ -0,0 +1,66 @@
#include <assert.h>
#include <d3d10.h>
#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);
}

View File

@ -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);

View File

@ -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[] = {

View File

@ -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");