mirror of
https://github.com/isledecomp/isle-portable.git
synced 2025-09-23 03:55:44 -04:00
Align hardware lighting with software (#221)
This commit is contained in:
parent
f08aec7438
commit
2affbdfcc7
@ -1,9 +1,11 @@
|
||||
#include "ShaderIndex.h"
|
||||
#include "d3drmrenderer.h"
|
||||
#include "d3drmrenderer_sdl3gpu.h"
|
||||
#include "ddraw_impl.h"
|
||||
#include "miniwin.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <cstddef>
|
||||
|
||||
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device)
|
||||
{
|
||||
@ -33,21 +35,36 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
|
||||
vertexBufferDescs[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
||||
vertexBufferDescs[0].instance_step_rate = 0;
|
||||
|
||||
SDL_GPUVertexAttribute vertexAttrs[3] = {};
|
||||
SDL_GPUVertexAttribute vertexAttrs[6] = {};
|
||||
vertexAttrs[0].location = 0;
|
||||
vertexAttrs[0].buffer_slot = 0;
|
||||
vertexAttrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
|
||||
vertexAttrs[0].offset = 0;
|
||||
vertexAttrs[0].offset = offsetof(PositionColorVertex, position);
|
||||
|
||||
vertexAttrs[1].location = 1;
|
||||
vertexAttrs[1].buffer_slot = 0;
|
||||
vertexAttrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
|
||||
vertexAttrs[1].offset = sizeof(float) * 3;
|
||||
vertexAttrs[1].offset = offsetof(PositionColorVertex, normals);
|
||||
|
||||
vertexAttrs[2].location = 2;
|
||||
vertexAttrs[2].buffer_slot = 0;
|
||||
vertexAttrs[2].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM;
|
||||
vertexAttrs[2].offset = sizeof(float) * 6;
|
||||
vertexAttrs[2].offset = offsetof(PositionColorVertex, colors);
|
||||
|
||||
vertexAttrs[3].location = 3;
|
||||
vertexAttrs[3].buffer_slot = 0;
|
||||
vertexAttrs[3].format = SDL_GPU_VERTEXELEMENTFORMAT_UINT;
|
||||
vertexAttrs[3].offset = offsetof(PositionColorVertex, texId);
|
||||
|
||||
vertexAttrs[4].location = 4;
|
||||
vertexAttrs[4].buffer_slot = 0;
|
||||
vertexAttrs[4].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
|
||||
vertexAttrs[4].offset = offsetof(PositionColorVertex, texCoord);
|
||||
|
||||
vertexAttrs[5].location = 5;
|
||||
vertexAttrs[5].buffer_slot = 0;
|
||||
vertexAttrs[5].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
|
||||
vertexAttrs[5].offset = offsetof(PositionColorVertex, shininess);
|
||||
|
||||
SDL_GPUVertexInputState vertexInputState = {};
|
||||
vertexInputState.vertex_buffer_descriptions = vertexBufferDescs;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,28 @@
|
||||
struct VS_Input
|
||||
{
|
||||
float3 Position : TEXCOORD0;
|
||||
float3 Normal : TEXCOORD1;
|
||||
float4 Color : TEXCOORD2;
|
||||
float3 Position : POSITION;
|
||||
float3 Normal : NORMAL0;
|
||||
float4 Color : COLOR0;
|
||||
uint TexId : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float Shininess : TEXCOORD2;
|
||||
};
|
||||
|
||||
struct FS_Input
|
||||
{
|
||||
float4 Color : TEXCOORD0;
|
||||
float3 Normal : TEXCOORD1;
|
||||
float4 Position : SV_Position;
|
||||
float4 Position : SV_POSITION;
|
||||
float3 Normal : NORMAL0;
|
||||
float4 Color : COLOR0;
|
||||
uint TexId : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD1;
|
||||
float Shininess : TEXCOORD2;
|
||||
float3 WorldPosition : TEXCOORD3;
|
||||
};
|
||||
|
||||
struct FS_Output
|
||||
{
|
||||
float4 Color : SV_Target0;
|
||||
float Depth : SV_Depth;
|
||||
float Depth : SV_Depth;
|
||||
};
|
||||
|
||||
struct SceneLight {
|
||||
|
@ -8,8 +8,13 @@ cbuffer ViewportUniforms : register(b0, space1)
|
||||
FS_Input main(VS_Input input)
|
||||
{
|
||||
FS_Input output;
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.Color = input.Color;
|
||||
output.Normal = input.Normal;
|
||||
output.Position = mul(perspective, float4(input.Position, 1.0));
|
||||
output.WorldPosition = input.Position;
|
||||
output.TexId = input.TexId;
|
||||
output.Shininess = input.Shininess;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -9,53 +9,50 @@ cbuffer LightBuffer : register(b0, space3)
|
||||
FS_Output main(FS_Input input)
|
||||
{
|
||||
FS_Output output;
|
||||
float3 normal = normalize(input.Normal);
|
||||
float3 fragPos = input.Position.xyz / input.Position.w;
|
||||
|
||||
float3 viewPos = float3(0, 0, 0);
|
||||
float3 viewDir = normalize(viewPos - fragPos);
|
||||
|
||||
float3 result = float3(0, 0, 0);
|
||||
|
||||
const float shininess = 20.0; // All materials use this in Isle
|
||||
float3 diffuse = float3(0, 0, 0);
|
||||
float3 specular = float3(0, 0, 0);
|
||||
|
||||
for (int i = 0; i < lightCount; ++i) {
|
||||
float3 lightColor = lights[i].color.rgb;
|
||||
|
||||
bool hasPos = lights[i].position.w == 1.0;
|
||||
bool hasDir = lights[i].direction.w == 1.0;
|
||||
|
||||
if (!hasPos && !hasDir) {
|
||||
// D3DRMLIGHT_AMBIENT
|
||||
result += input.Color.rgb * lightColor;
|
||||
if (lights[i].position.w == 0.0 && lights[i].direction.w == 0.0) {
|
||||
diffuse += lightColor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasPos) {
|
||||
// D3DRMLIGHT_POINT
|
||||
float3 lightVec;
|
||||
if (lights[i].direction.w == 1.0) {
|
||||
lightVec = normalize(-lights[i].direction.xyz);
|
||||
}
|
||||
else {
|
||||
float3 lightPos = lights[i].position.xyz;
|
||||
float3 lightDir = normalize(lightPos - fragPos);
|
||||
float diff = max(dot(normal, lightDir), 0.0);
|
||||
float distance = length(lightPos - fragPos);
|
||||
float attenuation = 1.0 / (1.0 + 0.09 * distance + 0.032 * distance * distance);
|
||||
float3 halfwayDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
|
||||
result += (input.Color.rgb * diff + spec) * lightColor * attenuation;
|
||||
continue;
|
||||
lightVec = lightPos - input.WorldPosition;
|
||||
|
||||
float len = length(lightVec);
|
||||
if (len == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lightVec /= len;
|
||||
}
|
||||
|
||||
if (hasDir) {
|
||||
// D3DRMLIGHT_DIRECTIONAL
|
||||
float3 lightDir = normalize(-lights[i].direction.xyz);
|
||||
float diff = max(dot(normal, lightDir), 0.0);
|
||||
float3 halfwayDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
|
||||
result += (input.Color.rgb * diff + spec) * lightColor;
|
||||
continue;
|
||||
float dotNL = dot(input.Normal, lightVec);
|
||||
if (dotNL > 0.0f) {
|
||||
diffuse += dotNL * lightColor;
|
||||
|
||||
if (input.Shininess != 0.0f) {
|
||||
// Using dotNL ignores view angle, but this matches DirectX 5 behavior.
|
||||
float spec1 = pow(dotNL, input.Shininess);
|
||||
specular += spec1 * lightColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.Color = float4(result, input.Color.a);
|
||||
float3 baseColor = input.Color.rgb;
|
||||
float3 finalColor = saturate(diffuse * baseColor + specular);
|
||||
|
||||
output.Color = float4(finalColor, input.Color.a);
|
||||
output.Depth = input.Position.w;
|
||||
return output;
|
||||
}
|
||||
|
@ -47,10 +47,10 @@ void Direct3DRMSoftwareRenderer::ClearZBuffer()
|
||||
|
||||
void Direct3DRMSoftwareRenderer::ProjectVertex(const PositionColorVertex& v, D3DRMVECTOR4D& p) const
|
||||
{
|
||||
float px = proj[0][0] * v.x + proj[1][0] * v.y + proj[2][0] * v.z + proj[3][0];
|
||||
float py = proj[0][1] * v.x + proj[1][1] * v.y + proj[2][1] * v.z + proj[3][1];
|
||||
float pz = proj[0][2] * v.x + proj[1][2] * v.y + proj[2][2] * v.z + proj[3][2];
|
||||
float pw = proj[0][3] * v.x + proj[1][3] * v.y + proj[2][3] * v.z + proj[3][3];
|
||||
float px = proj[0][0] * v.position.x + proj[1][0] * v.position.y + proj[2][0] * v.position.z + proj[3][0];
|
||||
float py = proj[0][1] * v.position.x + proj[1][1] * v.position.y + proj[2][1] * v.position.z + proj[3][1];
|
||||
float pz = proj[0][2] * v.position.x + proj[1][2] * v.position.y + proj[2][2] * v.position.z + proj[3][2];
|
||||
float pw = proj[0][3] * v.position.x + proj[1][3] * v.position.y + proj[2][3] * v.position.z + proj[3][3];
|
||||
|
||||
p.w = pw;
|
||||
|
||||
@ -69,23 +69,23 @@ void Direct3DRMSoftwareRenderer::ProjectVertex(const PositionColorVertex& v, D3D
|
||||
|
||||
PositionColorVertex SplitEdge(PositionColorVertex a, const PositionColorVertex& b, float plane)
|
||||
{
|
||||
float t = (plane - a.z) / (b.z - a.z);
|
||||
a.x = a.x + t * (b.x - a.x);
|
||||
a.y = a.y + t * (b.y - a.y);
|
||||
a.z = plane;
|
||||
float t = (plane - a.position.z) / (b.position.z - a.position.z);
|
||||
a.position.x = a.position.x + t * (b.position.x - a.position.x);
|
||||
a.position.y = a.position.y + t * (b.position.y - a.position.y);
|
||||
a.position.z = plane;
|
||||
|
||||
a.u = a.u + t * (b.u - a.u);
|
||||
a.v = a.v + t * (b.v - a.v);
|
||||
a.texCoord.u = a.texCoord.u + t * (b.texCoord.u - a.texCoord.u);
|
||||
a.texCoord.v = a.texCoord.v + t * (b.texCoord.v - a.texCoord.v);
|
||||
|
||||
a.nx = a.nx + t * (b.nx - a.nx);
|
||||
a.ny = a.ny + t * (b.ny - a.ny);
|
||||
a.nz = a.nz + t * (b.nz - a.nz);
|
||||
a.normals.x = a.normals.x + t * (b.normals.x - a.normals.x);
|
||||
a.normals.y = a.normals.y + t * (b.normals.y - a.normals.y);
|
||||
a.normals.z = a.normals.z + t * (b.normals.z - a.normals.z);
|
||||
|
||||
float len = std::sqrt(a.nx * a.nx + a.ny * a.ny + a.nz * a.nz);
|
||||
float len = std::sqrt(a.normals.x * a.normals.x + a.normals.y * a.normals.y + a.normals.z * a.normals.z);
|
||||
if (len > 0.0001f) {
|
||||
a.nx /= len;
|
||||
a.ny /= len;
|
||||
a.nz /= len;
|
||||
a.normals.x /= len;
|
||||
a.normals.y /= len;
|
||||
a.normals.z /= len;
|
||||
}
|
||||
|
||||
return a;
|
||||
@ -97,9 +97,9 @@ void Direct3DRMSoftwareRenderer::DrawTriangleClipped(
|
||||
const PositionColorVertex& v2
|
||||
)
|
||||
{
|
||||
bool in0 = v0.z >= m_front;
|
||||
bool in1 = v1.z >= m_front;
|
||||
bool in2 = v2.z >= m_front;
|
||||
bool in0 = v0.position.z >= m_front;
|
||||
bool in1 = v1.position.z >= m_front;
|
||||
bool in2 = v2.position.z >= m_front;
|
||||
|
||||
int insideCount = in0 + in1 + in2;
|
||||
|
||||
@ -168,11 +168,11 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const PositionColorVertex& v
|
||||
FColor diffuse = {0, 0, 0, 0};
|
||||
|
||||
// Position and normal
|
||||
D3DVECTOR position = {vertex.x, vertex.y, vertex.z};
|
||||
D3DVECTOR normal = {vertex.nx, vertex.ny, vertex.nz};
|
||||
D3DVECTOR position = vertex.position;
|
||||
D3DVECTOR normal = vertex.normals;
|
||||
float normLen = std::sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
|
||||
if (normLen == 0.0f) {
|
||||
return {vertex.r, vertex.g, vertex.b, vertex.a};
|
||||
return vertex.colors;
|
||||
}
|
||||
|
||||
normal.x /= normLen;
|
||||
@ -225,10 +225,10 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const PositionColorVertex& v
|
||||
}
|
||||
|
||||
return SDL_Color{
|
||||
static_cast<Uint8>(std::min(255.0f, diffuse.r * vertex.r + specular.r * 255.0f)),
|
||||
static_cast<Uint8>(std::min(255.0f, diffuse.g * vertex.g + specular.g * 255.0f)),
|
||||
static_cast<Uint8>(std::min(255.0f, diffuse.b * vertex.b + specular.b * 255.0f)),
|
||||
vertex.a
|
||||
static_cast<Uint8>(std::min(255.0f, diffuse.r * vertex.colors.r + specular.r * 255.0f)),
|
||||
static_cast<Uint8>(std::min(255.0f, diffuse.g * vertex.colors.g + specular.g * 255.0f)),
|
||||
static_cast<Uint8>(std::min(255.0f, diffuse.b * vertex.colors.b + specular.b * 255.0f)),
|
||||
vertex.colors.a
|
||||
};
|
||||
}
|
||||
|
||||
@ -324,7 +324,7 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
|
||||
Uint8 b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
|
||||
Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel;
|
||||
|
||||
if (v0.a == 255) {
|
||||
if (v0.colors.a == 255) {
|
||||
zref = z;
|
||||
|
||||
if (texels) {
|
||||
@ -334,8 +334,12 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
|
||||
continue;
|
||||
}
|
||||
invW = 1.0 / invW;
|
||||
float u = static_cast<float>(((w0 * v0.u / p0.w) + (w1 * v1.u / p1.w) + (w2 * v2.u / p2.w)) * invW);
|
||||
float v = static_cast<float>(((w0 * v0.v / p0.w) + (w1 * v1.v / p1.w) + (w2 * v2.v / p2.w)) * invW);
|
||||
float u = static_cast<float>(
|
||||
((w0 * v0.texCoord.u / p0.w) + (w1 * v1.texCoord.u / p1.w) + (w2 * v2.texCoord.u / p2.w)) * invW
|
||||
);
|
||||
float v = static_cast<float>(
|
||||
((w0 * v0.texCoord.v / p0.w) + (w1 * v1.texCoord.v / p1.w) + (w2 * v2.texCoord.v / p2.w)) * invW
|
||||
);
|
||||
|
||||
// Tile textures
|
||||
u = u - std::floor(u);
|
||||
@ -363,7 +367,7 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
|
||||
}
|
||||
else {
|
||||
// Transparent alpha blending with vertex alpha
|
||||
BlendPixel(pixelAddr, r, g, b, v0.a);
|
||||
BlendPixel(pixelAddr, r, g, b, v0.colors.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -422,6 +426,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture)
|
||||
if (texRef.texture == nullptr) {
|
||||
texRef.texture = texture;
|
||||
texRef.cached = convertedRender;
|
||||
texRef.version = texture->m_version;
|
||||
AddTextureDestroyCallback(i, texture);
|
||||
return i;
|
||||
}
|
||||
|
@ -296,20 +296,17 @@ HRESULT Direct3DRMViewportImpl::CollectSceneData()
|
||||
}
|
||||
|
||||
PositionColorVertex vtx;
|
||||
vtx.x = viewPos.x;
|
||||
vtx.y = viewPos.y;
|
||||
vtx.z = viewPos.z;
|
||||
vtx.nx = viewNorm.x;
|
||||
vtx.ny = viewNorm.y;
|
||||
vtx.nz = viewNorm.z;
|
||||
vtx.r = (color >> 16) & 0xFF;
|
||||
vtx.g = (color >> 8) & 0xFF;
|
||||
vtx.b = (color >> 0) & 0xFF;
|
||||
vtx.a = (color >> 24) & 0xFF;
|
||||
vtx.position = viewPos;
|
||||
vtx.normals = viewNorm;
|
||||
vtx.colors = {
|
||||
static_cast<Uint8>((color >> 16) & 0xFF),
|
||||
static_cast<Uint8>((color >> 8) & 0xFF),
|
||||
static_cast<Uint8>((color >> 0) & 0xFF),
|
||||
static_cast<Uint8>((color >> 24) & 0xFF)
|
||||
};
|
||||
vtx.shininess = shininess;
|
||||
vtx.texId = texId;
|
||||
vtx.u = dv.tu;
|
||||
vtx.v = dv.tv;
|
||||
vtx.texCoord = {dv.tu, dv.tv};
|
||||
verts.push_back(vtx);
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,19 @@
|
||||
|
||||
#define NO_TEXTURE_ID 0xffffffff
|
||||
|
||||
typedef struct PositionColorVertex {
|
||||
float x, y, z;
|
||||
float nx, ny, nz;
|
||||
Uint8 r, g, b, a;
|
||||
Uint32 texId = NO_TEXTURE_ID;
|
||||
struct TexCoord {
|
||||
float u, v;
|
||||
};
|
||||
|
||||
struct PositionColorVertex {
|
||||
D3DVECTOR position;
|
||||
D3DVECTOR normals;
|
||||
SDL_Color colors;
|
||||
Uint32 texId;
|
||||
TexCoord texCoord;
|
||||
float shininess;
|
||||
} PositionColorVertex;
|
||||
};
|
||||
static_assert(sizeof(PositionColorVertex) == 44);
|
||||
|
||||
struct FColor {
|
||||
float r, g, b, a;
|
||||
@ -26,6 +31,7 @@ struct SceneLight {
|
||||
D3DVECTOR direction;
|
||||
float directional = 0.f; // direction is valid if 1.f
|
||||
};
|
||||
static_assert(sizeof(SceneLight) == 48);
|
||||
|
||||
class Direct3DRMRenderer : public IDirect3DDevice2 {
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user