Add gouraud shading, can choose lighting options

This commit is contained in:
Doyle Thai 2017-06-08 21:46:03 +10:00
parent ee31383906
commit 285d3d2681
5 changed files with 292 additions and 261 deletions

View File

@ -869,78 +869,6 @@ void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const in
}
}
FILE_SCOPE void DebugTestStrToF32Converter()
{
const f32 EPSILON = 0.001f;
const char a[] = "-0.66248";
f32 vA = Dqn_StrToF32(a, DQN_ARRAY_COUNT(a));
DQN_ASSERT(DQN_ABS(vA) - DQN_ABS(-0.66248f) < EPSILON);
const char b[] = "-0.632053";
f32 vB = Dqn_StrToF32(b, DQN_ARRAY_COUNT(b));
DQN_ASSERT(DQN_ABS(vB) - DQN_ABS(-0.632053f) < EPSILON);
const char c[] = "-0.244271";
f32 vC = Dqn_StrToF32(c, DQN_ARRAY_COUNT(c));
DQN_ASSERT(DQN_ABS(vC) - DQN_ABS(-0.244271f) < EPSILON);
const char d[] = "-0.511812";
f32 vD = Dqn_StrToF32(d, DQN_ARRAY_COUNT(d));
DQN_ASSERT(DQN_ABS(vD) - DQN_ABS(-0.511812f) < EPSILON);
const char e[] = "-0.845392";
f32 vE = Dqn_StrToF32(e, DQN_ARRAY_COUNT(e));
DQN_ASSERT(DQN_ABS(vE) - DQN_ABS(-0.845392f) < EPSILON);
const char f[] = "0.127809";
f32 vF = Dqn_StrToF32(f, DQN_ARRAY_COUNT(f));
DQN_ASSERT(DQN_ABS(vF) - DQN_ABS(-0.127809f) < EPSILON);
const char g[] = "0.532";
f32 vG = Dqn_StrToF32(g, DQN_ARRAY_COUNT(g));
DQN_ASSERT(DQN_ABS(vG) - DQN_ABS(-0.532f) < EPSILON);
const char h[] = "0.923";
f32 vH = Dqn_StrToF32(h, DQN_ARRAY_COUNT(h));
DQN_ASSERT(DQN_ABS(vH) - DQN_ABS(-0.923f) < EPSILON);
const char i[] = "0.000";
f32 vI = Dqn_StrToF32(i, DQN_ARRAY_COUNT(i));
DQN_ASSERT(DQN_ABS(vI) - DQN_ABS(-0.000f) < EPSILON);
const char j[] = "0.000283538";
f32 vJ = Dqn_StrToF32(j, DQN_ARRAY_COUNT(j));
DQN_ASSERT(DQN_ABS(vJ) - DQN_ABS(-0.000283538f) < EPSILON);
const char k[] = "-1.25";
f32 vK = Dqn_StrToF32(k, DQN_ARRAY_COUNT(k));
DQN_ASSERT(DQN_ABS(vK) - DQN_ABS(-1.25f) < EPSILON);
const char l[] = "0.286843";
f32 vL = Dqn_StrToF32(l, DQN_ARRAY_COUNT(l));
DQN_ASSERT(DQN_ABS(vL) - DQN_ABS(-0.286843f) < EPSILON);
const char m[] = "-0.406";
f32 vM = Dqn_StrToF32(m, DQN_ARRAY_COUNT(m));
DQN_ASSERT(DQN_ABS(vM) - DQN_ABS(-0.406f) < EPSILON);
const char n[] = "-0.892";
f32 vN = Dqn_StrToF32(n, DQN_ARRAY_COUNT(n));
DQN_ASSERT(DQN_ABS(vN) - DQN_ABS(-0.892f) < EPSILON);
const char o[] = "0.201";
f32 vO = Dqn_StrToF32(o, DQN_ARRAY_COUNT(o));
DQN_ASSERT(DQN_ABS(vO) - DQN_ABS(-0.201f) < EPSILON);
const char p[] = "1.25";
f32 vP = Dqn_StrToF32(p, DQN_ARRAY_COUNT(p));
DQN_ASSERT(DQN_ABS(vP) - DQN_ABS(1.25f) < EPSILON);
const char q[] = "9.64635e-05";
f32 vQ = Dqn_StrToF32(q, DQN_ARRAY_COUNT(q));
DQN_ASSERT(DQN_ABS(vQ) - DQN_ABS(9.64635e-05) < EPSILON);
}
extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
PlatformInput *const input,
PlatformMemory *const memory)
@ -1000,8 +928,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
////////////////////////////////////////////////////////////////////////
if (DTR_DEBUG)
{
DebugTestStrToF32Converter();
// DTRDebug_TestMeshFaceAndVertexParser(&state->mesh);
DTRDebug_TestMeshFaceAndVertexParser(&state->mesh);
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->tempStack);
DTRBitmap test = {};
@ -1060,18 +987,22 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
{
DTRDebug_BeginCycleCount("DTR_Update_RenderPrimitiveTriangles",
DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
DTRRender_Triangle(&renderBuffer, t0[0], t0[1], t0[2], colorRed);
DTRRender_Triangle(&renderBuffer, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(&renderBuffer, t3[0], t3[1], t3[2], colorRed, rotatingXform);
DTRRender_Triangle(&renderBuffer, t2[0], t2[1], t2[2], colorRed);
DTRRender_Triangle(&renderBuffer, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(&renderBuffer, t5[0], t5[1], t5[2], colorRed);
DTRRenderLight lighting = {};
lighting.mode = DTRRenderShadingMode_FullBright;
DTRRender_Triangle(&renderBuffer, lighting, t0[0], t0[1], t0[2], colorRed);
DTRRender_Triangle(&renderBuffer, lighting, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(&renderBuffer, lighting, t3[0], t3[1], t3[2], colorRed, rotatingXform);
DTRRender_Triangle(&renderBuffer, lighting, t2[0], t2[1], t2[2], colorRed);
DTRRender_Triangle(&renderBuffer, lighting, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(&renderBuffer, lighting, t5[0], t5[1], t5[2], colorRed);
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
}
if (1)
{
LOCAL_PERSIST bool runTinyRendererOnce = true;
LOCAL_PERSIST bool runTinyRendererOnce = false;
if (1 && runTinyRendererOnce)
{
DTRDebug_RunTinyRenderer();
@ -1082,7 +1013,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
////////////////////////////////////////////////////////////////////////
// Draw Loaded Model
////////////////////////////////////////////////////////////////////////
const DqnV3 LIGHT = DqnV3_3i(0, 0, -1);
const DqnV3 LIGHT = DqnV3_Normalise(DqnV3_3f(1, -1, 1.0f));
const f32 MODEL_SCALE = 1;
DTRMesh *const mesh = &state->mesh;
DqnV3 modelP = DqnV3_3f(0, 0, 0);

View File

@ -25,7 +25,6 @@ void DTRDebug_TestMeshFaceAndVertexParser(DTRMesh *const mesh)
DTRMeshFace *myFace = &mesh->faces[i];
DQN_ASSERT(myFace->numVertexIndex == correctFace.size());
for (i32 j = 0; j < (i32)myFace->numVertexIndex; j++)
{
// Ensure the vertex index references are correct per face
@ -42,6 +41,20 @@ void DTRDebug_TestMeshFaceAndVertexParser(DTRMesh *const mesh)
DQN_ASSERT(delta < 0.1f);
}
}
for (i32 j = 0; j < (i32)myFace->numNormalIndex; j++)
{
Vec3f tmp = tmpModel.norm(i, j);
DqnV3 correctNormal = DqnV3_3f(tmp[0], tmp[1], tmp[2]);
DqnV3 myNormal = (mesh->normals[myFace->normalIndex[j]]);
// Ensure the vertex values read are correct
for (i32 k = 0; k < DQN_ARRAY_COUNT(correctNormal.e); k++)
{
f32 delta = DQN_ABS(correctNormal.e[k] - myNormal.e[k]);
DQN_ASSERT(delta < 0.1f);
}
}
}
}
}

View File

@ -782,6 +782,9 @@ FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer,
const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width;
// TODO(doyle): Copy lighting work over. But not important since using this
// function causes performance problems.
// Rasterise buffer(X, Y) pixel
{
__m128 isGreater = _mm_cmpge_ps(signedArea, ZERO_4X);
@ -817,7 +820,9 @@ FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer,
FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1, const DqnV3 p2,
const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3,
const DTRBitmap *const texture, const DqnV4 color, const DqnV2i min,
const f32 lightIntensity1, const f32 lightIntensity2,
const f32 lightIntensity3, const bool ignoreLight,
DTRBitmap *const texture, DqnV4 color, const DqnV2i min,
const DqnV2i max)
{
@ -831,6 +836,20 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
__m128 simdColor = _mm_set_ps(color.a, color.b, color.g, color.r);
simdColor = SIMDSRGB1ToLinearSpace(simdColor);
simdColor = SIMDPreMultiplyAlpha1(simdColor);
f32 preserveAlpha = ((f32 *)&simdColor)[3];
const __m128 ZERO_4X = _mm_set_ps1(0.0f);
__m128 simdLightIntensity1 = _mm_set_ps1(lightIntensity1);
__m128 simdLightIntensity2 = _mm_set_ps1(lightIntensity2);
__m128 simdLightIntensity3 = _mm_set_ps1(lightIntensity3);
simdLightIntensity1 = _mm_max_ps(simdLightIntensity1, ZERO_4X);
simdLightIntensity2 = _mm_max_ps(simdLightIntensity2, ZERO_4X);
simdLightIntensity3 = _mm_max_ps(simdLightIntensity3, ZERO_4X);
__m128 p1Light = _mm_mul_ps(simdColor, simdLightIntensity1);
__m128 p2Light = _mm_mul_ps(simdColor, simdLightIntensity2);
__m128 p3Light = _mm_mul_ps(simdColor, simdLightIntensity3);
////////////////////////////////////////////////////////////////////////////
// Setup SIMD data
@ -897,7 +916,6 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble);
#if UNROLL_LOOP
const __m128 ZERO_4X = _mm_set_ps1(0.0f);
const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width;
#endif
@ -936,12 +954,29 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor;
if (!ignoreLight)
{
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]);
__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]);
__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x);
__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x);
__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x);
__m128 light =
_mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light);
((f32 *)&finalColor)[3] = preserveAlpha;
}
if (texture)
{
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, simdColor);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
}
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
}
@ -970,12 +1005,30 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor;
if (!ignoreLight)
{
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]);
__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]);
__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x);
__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x);
__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x);
__m128 light =
_mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light);
((f32 *)&finalColor)[3] = preserveAlpha;
}
if (texture)
{
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, simdColor);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
}
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
}
@ -1002,6 +1055,8 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1, const DqnV3 p2,
const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3,
const f32 lightIntensity1, const f32 lightIntensity2,
const f32 lightIntensity3, const bool ignoreLight,
DTRBitmap *const texture, DqnV4 color, const DqnV2i min,
const DqnV2i max)
{
@ -1069,6 +1124,10 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer * const renderBuffer, const DqnV3 p
const f32 INV_255 = 1 / 255.0f;
DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble);
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Rasterise);
DqnV3 p1Light = color.rgb * DQN_MAX(0, lightIntensity1);
DqnV3 p2Light = color.rgb * DQN_MAX(0, lightIntensity2);
DqnV3 p3Light = color.rgb * DQN_MAX(0, lightIntensity3);
for (i32 bufferY = min.y; bufferY < max.y; bufferY++)
{
f32 signedArea1 = signedArea1Pixel;
@ -1080,6 +1139,7 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer * const renderBuffer, const DqnV3 p
if (signedArea1 >= 0 && signedArea2 >= 0 && signedArea3 >= 0)
{
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
f32 barycentricB = signedArea2 * invSignedAreaParallelogram;
f32 barycentricC = signedArea3 * invSignedAreaParallelogram;
@ -1091,6 +1151,15 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer * const renderBuffer, const DqnV3 p
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
DqnV4 finalColor = color;
if (!ignoreLight)
{
DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) +
(p3Light * barycentricC);
finalColor.rgb *= light;
}
if (texture)
{
DqnV2 uv = uv1 + (uv2SubUv1 * barycentricB) + (uv3SubUv1 * barycentricC);
@ -1120,16 +1189,13 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer * const renderBuffer, const DqnV3 p
color1 *= INV_255;
color1 = DTRRender_SRGB1ToLinearSpaceV4(color1);
DqnV4 blend = color * color1;
SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear);
finalColor *= color1;
}
else
{
SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
SetPixel(renderBuffer, bufferX, bufferY, finalColor, ColorSpace_Linear);
}
DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
}
}
signedArea1 += signedArea1DeltaX;
signedArea2 += signedArea2DeltaX;
@ -1144,7 +1210,7 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer * const renderBuffer, const DqnV3 p
DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle);
}
DqnMat4 DqnMat4_GLViewport(f32 x, f32 y, f32 width, f32 height)
DqnMat4 GLViewport(f32 x, f32 y, f32 width, f32 height)
{
// Given a normalised coordinate from [-1, 1] for X, Y and Z, we want to map this
// back to viewport coordinates, or i.e. screen coordinates.
@ -1171,44 +1237,16 @@ DqnMat4 DqnMat4_GLViewport(f32 x, f32 y, f32 width, f32 height)
return result;
}
DqnMat4 DqnMat4_LookAt(DqnV3 eye, DqnV3 center, DqnV3 up)
{
DqnMat4 result = {0};
DqnV3 f = DqnV3_Normalise(DqnV3_Sub(eye, center));
DqnV3 s = DqnV3_Normalise(DqnV3_Cross(up, f));
DqnV3 u = DqnV3_Cross(f, s);
result.e[0][0] = s.x;
result.e[0][1] = u.x;
result.e[0][2] = f.x;
result.e[1][0] = s.y;
result.e[1][1] = u.y;
result.e[1][2] = f.y;
result.e[2][0] = s.z;
result.e[2][1] = u.z;
result.e[2][2] = f.z;
result.e[3][0] = DqnV3_Dot(s, eye);
result.e[3][1] = DqnV3_Dot(u, eye);
result.e[3][2] = -DqnV3_Dot(f, eye);
result.e[3][3] = 1.0f;
return result;
}
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
DqnV4 color, const DTRRenderTransform transform)
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DTRRenderLight lighting,
DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3,
DTRBitmap *const texture, DqnV4 color,
const DTRRenderTransform transform)
{
////////////////////////////////////////////////////////////////////////////
// Transform vertexes p1, p2, p3 inplace
////////////////////////////////////////////////////////////////////////////
Make3PointsClockwise(&p1, &p2, &p3);
#if 0
// TODO(doyle): Transform is only in 2d right now
DqnV2 origin = Get2DOriginFromTransformAnchor(p1.xy, p2.xy, p3.xy, transform);
DqnV2 pList[] = {p1.xy - origin, p2.xy - origin, p3.xy - origin};
TransformPoints(origin, pList, DQN_ARRAY_COUNT(pList), transform.scale, transform.rotation);
@ -1216,9 +1254,6 @@ void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, D
p1.xy = pList[0];
p2.xy = pList[1];
p3.xy = pList[2];
#else
DqnV2 pList[] = {p1.xy, p2.xy, p3.xy};
#endif
DqnRect bounds = GetBoundingBox(pList, DQN_ARRAY_COUNT(pList));
DqnRect screenSpace = DqnRect_4i(0, 0, renderBuffer->width - 1, renderBuffer->height - 1);
@ -1227,16 +1262,49 @@ void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, D
DqnV2i max = DqnV2i_V2(bounds.max);
////////////////////////////////////////////////////////////////////////////
// SIMD/Slow Path
// Calculate light
////////////////////////////////////////////////////////////////////////////
if (globalDTRPlatformFlags.canUseSSE2 && 1)
f32 lightIntensity1 = 1, lightIntensity2 = 1, lightIntensity3 = 1;
bool ignoreLight = false;
if (lighting.mode == DTRRenderShadingMode_FullBright)
{
SIMDTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, texture, color, min, max);
ignoreLight = true;
}
else
{
SlowTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, texture, color, min,
max);
lighting.lightVector = DqnV3_Normalise(lighting.lightVector);
if (lighting.mode == DTRRenderShadingMode_Flat)
{
DqnV3 p2SubP1 = p2 - p1;
DqnV3 p3SubP1 = p3 - p1;
DqnV3 normal = DqnV3_Normalise(DqnV3_Cross(p2SubP1, p3SubP1));
f32 intensity = DqnV3_Dot(normal, lighting.lightVector);
intensity = DQN_MAX(0, intensity);
color.rgb *= intensity;
}
else
{
DQN_ASSERT(lighting.numNormals == 3);
DQN_ASSERT(lighting.mode == DTRRenderShadingMode_Gouraud);
lightIntensity1 = DqnV3_Dot(DqnV3_Normalise(lighting.normals[0]), lighting.lightVector);
lightIntensity2 = DqnV3_Dot(DqnV3_Normalise(lighting.normals[1]), lighting.lightVector);
lightIntensity3 = DqnV3_Dot(DqnV3_Normalise(lighting.normals[2]), lighting.lightVector);
}
}
////////////////////////////////////////////////////////////////////////////
// SIMD/Slow Path
////////////////////////////////////////////////////////////////////////////
if (globalDTRPlatformFlags.canUseSSE2)
{
SIMDTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2,
lightIntensity3, ignoreLight, texture, color, min, max);
}
else
{
SlowTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2,
lightIntensity3, ignoreLight, texture, color, min, max);
}
////////////////////////////////////////////////////////////////////////////
@ -1253,98 +1321,59 @@ void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, D
}
}
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_CPP_MODE
#include "external/tests/HandmadeMath.h"
FILE_SCOPE void Test()
{
f32 aspectRatio = 1;
DqnMat4 dqnPerspective = DqnMat4_Perspective(90, aspectRatio, 100, 1000);
hmm_mat4 hmmPerspective = HMM_Perspective (90, aspectRatio, 100, 1000);
{
hmm_vec3 hmmVec = HMM_Vec3i(1, 2, 3);
DqnV3 dqnVec = DqnV3_3i(1, 2, 3);
DqnMat4 dqnTranslate = DqnMat4_Translate(dqnVec.x, dqnVec.y, dqnVec.z);
hmm_mat4 hmmTranslate = HMM_Translate(hmmVec);
dqnVec *= 2;
hmmVec *= 2;
DqnMat4 dqnScale = DqnMat4_Scale(dqnVec.x, dqnVec.y, dqnVec.z);
hmm_mat4 hmmScale = HMM_Scale(hmmVec);
DqnMat4 dqnTsMatrix = DqnMat4_Mul(dqnTranslate, dqnScale);
hmm_mat4 hmmTsMatrix = HMM_MultiplyMat4(hmmTranslate, hmmScale);
for (i32 i = 0; i < 16; i++)
{
f32 *hmmTsMatrixf = (f32 *)&hmmTsMatrix;
f32 *dqnTsMatrixf = (f32 *)&dqnTsMatrix;
DQN_ASSERT(hmmTsMatrixf[i] == dqnTsMatrixf[i]);
}
int breakHere = 5;
}
{
DqnMat4 dqnViewMatrix = DqnMat4_LookAt(DqnV3_3f(4, 3, 3), DqnV3_1f(0), DqnV3_3f(0, 1, 0));
hmm_mat4 hmmViewMatrix =
HMM_LookAt(HMM_Vec3(4, 3, 3), HMM_Vec3(0, 0, 0), HMM_Vec3(0, 1, 0));
for (i32 i = 0; i < 16; i++)
{
f32 *hmmViewMatrixf = (f32 *)&hmmViewMatrix;
f32 *dqnViewMatrixf = (f32 *)&dqnViewMatrix;
DQN_ASSERT(hmmViewMatrixf[i] == dqnViewMatrixf[i]);
}
}
}
void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, const DqnV3 pos,
const f32 scale, const DqnV3 lightVector, const f32 dt)
{
if (!mesh) return;
Test();
for (u32 i = 0; i < mesh->numFaces; i++)
{
DTRMeshFace face = mesh->faces[i];
DqnV4 v1, v2, v3;
DqnV3 norm1, norm2, norm3;
{
DQN_ASSERT(face.numVertexIndex == 3);
i32 vertAIndex = face.vertexIndex[0];
i32 vertBIndex = face.vertexIndex[1];
i32 vertCIndex = face.vertexIndex[2];
DQN_ASSERT(face.numNormalIndex == 3);
DqnV4 vertA = mesh->vertexes[vertAIndex];
DqnV4 vertB = mesh->vertexes[vertBIndex];
DqnV4 vertC = mesh->vertexes[vertCIndex];
DQN_ASSERT(vertA.w == 1);
DQN_ASSERT(vertB.w == 1);
DQN_ASSERT(vertC.w == 1);
i32 v1Index = face.vertexIndex[0];
i32 v2Index = face.vertexIndex[1];
i32 v3Index = face.vertexIndex[2];
// TODO(doyle): Some models have -ve indexes to refer to relative
// vertices. We should resolve that to positive indexes at run time.
DQN_ASSERT(vertAIndex < (i32)mesh->numVertexes);
DQN_ASSERT(vertBIndex < (i32)mesh->numVertexes);
DQN_ASSERT(vertCIndex < (i32)mesh->numVertexes);
DQN_ASSERT(v1Index < (i32)mesh->numVertexes);
DQN_ASSERT(v2Index < (i32)mesh->numVertexes);
DQN_ASSERT(v3Index < (i32)mesh->numVertexes);
// TODO(doyle): Use normals from model
DqnV4 vertAB = vertB - vertA;
DqnV4 vertAC = vertC - vertA;
DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz);
v1 = mesh->vertexes[v1Index];
v2 = mesh->vertexes[v2Index];
v3 = mesh->vertexes[v3Index];
f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), lightVector);
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
modelCol.rgb *= DQN_ABS(intensity);
DQN_ASSERT(v1.w == 1);
DQN_ASSERT(v2.w == 1);
DQN_ASSERT(v3.w == 1);
i32 norm1Index = face.normalIndex[0];
i32 norm2Index = face.normalIndex[1];
i32 norm3Index = face.normalIndex[2];
DQN_ASSERT(norm1Index < (i32)mesh->numNormals);
DQN_ASSERT(norm2Index < (i32)mesh->numNormals);
DQN_ASSERT(norm3Index < (i32)mesh->numNormals);
norm1 = mesh->normals[norm1Index];
norm2 = mesh->normals[norm2Index];
norm3 = mesh->normals[norm3Index];
}
// Apply vertex shader, model view projection
DqnMat4 modelMatrix = {};
{
LOCAL_PERSIST f32 rotateDegrees = 0;
rotateDegrees += (dt * 0.0025f);
rotateDegrees = 0.0f;
DqnMat4 translateMatrix = DqnMat4_Translate(pos.x, pos.y, pos.z);
DqnMat4 scaleMatrix = DqnMat4_Scale(scale, scale, scale);
DqnMat4 rotateMatrix = DqnMat4_Rotate(DQN_DEGREES_TO_RADIANS(rotateDegrees), 0.0f, 1.0f, 0.0f);
@ -1362,71 +1391,83 @@ void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, co
perspective = DqnMat4_Identity();
perspective.e[2][3] = -1.0f / DqnV3_Length(eye, center);
DqnMat4 viewport = DqnMat4_GLViewport(0, 0, (f32)renderBuffer->width, (f32)renderBuffer->height);
DqnMat4 viewport = GLViewport(0, 0, (f32)renderBuffer->width, (f32)renderBuffer->height);
DqnMat4 modelView = DqnMat4_Mul(viewMatrix, modelMatrix);
DqnMat4 modelViewProjection = DqnMat4_Mul(perspective, modelView);
DqnMat4 viewPModelViewProjection = DqnMat4_Mul(viewport, modelViewProjection);
vertA = DqnMat4_MulV4(viewPModelViewProjection, vertA);
vertB = DqnMat4_MulV4(viewPModelViewProjection, vertB);
vertC = DqnMat4_MulV4(viewPModelViewProjection, vertC);
v1 = DqnMat4_MulV4(viewPModelViewProjection, v1);
v2 = DqnMat4_MulV4(viewPModelViewProjection, v2);
v3 = DqnMat4_MulV4(viewPModelViewProjection, v3);
// Perspective Divide to Normalise Device Coordinates
vertA.xyz = (vertA.xyz / vertA.w);
vertB.xyz = (vertB.xyz / vertB.w);
vertC.xyz = (vertC.xyz / vertC.w);
v1.xyz = (v1.xyz / v1.w);
v2.xyz = (v2.xyz / v2.w);
v3.xyz = (v3.xyz / v3.w);
// NOTE: Because we need to draw on pixel boundaries. We need to round
// up to closest pixel otherwise we will have gaps.
vertA.x = (f32)(i32)(vertA.x + 0.5f);
vertA.y = (f32)(i32)(vertA.y + 0.5f);
vertB.x = (f32)(i32)(vertB.x + 0.5f);
vertB.y = (f32)(i32)(vertB.y + 0.5f);
vertC.x = (f32)(i32)(vertC.x + 0.5f);
vertC.y = (f32)(i32)(vertC.y + 0.5f);
v1.x = (f32)(i32)(v1.x + 0.5f);
v1.y = (f32)(i32)(v1.y + 0.5f);
v2.x = (f32)(i32)(v2.x + 0.5f);
v2.y = (f32)(i32)(v2.y + 0.5f);
v3.x = (f32)(i32)(v3.x + 0.5f);
v3.y = (f32)(i32)(v3.y + 0.5f);
i32 textureAIndex = face.texIndex[0];
i32 textureBIndex = face.texIndex[1];
i32 textureCIndex = face.texIndex[2];
DqnV2 texA = mesh->texUV[textureAIndex].xy;
DqnV2 texB = mesh->texUV[textureBIndex].xy;
DqnV2 texC = mesh->texUV[textureCIndex].xy;
DqnV2 uv1 = mesh->texUV[textureAIndex].xy;
DqnV2 uv2 = mesh->texUV[textureBIndex].xy;
DqnV2 uv3 = mesh->texUV[textureCIndex].xy;
DQN_ASSERT(textureAIndex < (i32)mesh->numTexUV);
DQN_ASSERT(textureBIndex < (i32)mesh->numTexUV);
DQN_ASSERT(textureCIndex < (i32)mesh->numTexUV);
bool DEBUG_SIMPLE_MODE = false;
DqnV4 modelCol = DqnV4_1f(1);
DTRRenderLight lighting = {};
lighting.mode = DTRRenderShadingMode_Gouraud;
lighting.lightVector = lightVector;
lighting.normals[0] = norm1;
lighting.normals[1] = norm2;
lighting.normals[2] = norm3;
lighting.numNormals = 3;
if (DTR_DEBUG && DEBUG_SIMPLE_MODE)
{
DTRRender_Triangle(renderBuffer, vertA.xyz, vertB.xyz, vertC.xyz, modelCol);
DTRRender_Triangle(renderBuffer, lighting, v1.xyz, v2.xyz, v3.xyz, modelCol);
}
else
{
DTRRender_TexturedTriangle(renderBuffer, vertA.xyz, vertB.xyz, vertC.xyz, texA, texB,
texC, &mesh->tex, modelCol);
DTRRender_TexturedTriangle(renderBuffer, lighting, v1.xyz, v2.xyz, v3.xyz, uv1, uv2,
uv3, &mesh->tex, modelCol);
}
bool DEBUG_WIREFRAME = false;
if (DTR_DEBUG && DEBUG_WIREFRAME)
{
DqnV4 wireColor = DqnV4_4f(1.0f, 1.0f, 1.0f, 0.01f);
DTRRender_Line(renderBuffer, DqnV2i_V2(vertA.xy), DqnV2i_V2(vertB.xy),
DTRRender_Line(renderBuffer, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy),
wireColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(vertB.xy), DqnV2i_V2(vertC.xy),
DTRRender_Line(renderBuffer, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy),
wireColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(vertC.xy), DqnV2i_V2(vertA.xy),
DTRRender_Line(renderBuffer, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy),
wireColor);
}
}
}
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV4 color, const DTRRenderTransform transform)
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DTRRenderLight lighting,
DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color,
const DTRRenderTransform transform)
{
const DqnV2 noUV = {};
DTRRender_TexturedTriangle(renderBuffer, p1, p2, p3, noUV, noUV, noUV, NULL, color, transform);
DTRRender_TexturedTriangle(renderBuffer, lighting, p1, p2, p3, noUV, noUV, noUV, NULL, color,
transform);
}
void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos,

View File

@ -59,12 +59,29 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color);
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: All colors should be in the range of [0->1] where DqnV4 is a struct with 4 floats, rgba
// Leaving len = -1 for text will make the system use strlen to determine len.
enum DTRRenderShadingMode
{
DTRRenderShadingMode_FullBright,
DTRRenderShadingMode_Flat,
DTRRenderShadingMode_Gouraud,
};
typedef struct DTRRenderLight
{
enum DTRRenderShadingMode mode;
DqnV3 lightVector;
DqnV3 normals[4];
u32 numNormals;
} DTRRenderLight;
void DTRRender_Text (DTRRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1);
void DTRRender_Line (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle (DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Mesh (DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, const DqnV3 pos, const f32 scale, const DqnV3 lightVector);
void DTRRender_Triangle (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_Mesh (DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, const DqnV3 pos, const f32 scale, const DqnV3 lightVector, const f32 dt);
void DTRRender_Triangle (DTRRenderBuffer *const renderBuffer, DTRRenderLight lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DTRRenderLight lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_Bitmap (DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1));
void DTRRender_Clear (DTRRenderBuffer *const renderBuffer, DqnV3 color);

View File

@ -621,8 +621,11 @@ typedef union DqnMat4
} DqnMat4;
DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity ();
DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 zNear, f32 zFar);
DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective (f32 fovYDegrees, f32 aspectRatio, f32 zNear, f32 zFar);
DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt (DqnV3 eye, DqnV3 center, DqnV3 up);
DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate (f32 x, f32 y, f32 z);
DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate (f32 radians, f32 x, f32 y, f32 z);
DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale (f32 x, f32 y, f32 z);
@ -2359,6 +2362,33 @@ DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective(f32 fovYDegrees, f32 aspectRatio, f32
return result;
}
DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt(DqnV3 eye, DqnV3 center, DqnV3 up)
{
DqnMat4 result = {0};
DqnV3 f = DqnV3_Normalise(DqnV3_Sub(eye, center));
DqnV3 s = DqnV3_Normalise(DqnV3_Cross(up, f));
DqnV3 u = DqnV3_Cross(f, s);
result.e[0][0] = s.x;
result.e[0][1] = u.x;
result.e[0][2] = f.x;
result.e[1][0] = s.y;
result.e[1][1] = u.y;
result.e[1][2] = f.y;
result.e[2][0] = s.z;
result.e[2][1] = u.z;
result.e[2][2] = f.z;
result.e[3][0] = DqnV3_Dot(s, eye);
result.e[3][1] = DqnV3_Dot(u, eye);
result.e[3][2] = -DqnV3_Dot(f, eye);
result.e[3][3] = 1.0f;
return result;
}
DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate(f32 x, f32 y, f32 z)
{
DqnMat4 result = DqnMat4_Identity();
@ -2373,20 +2403,19 @@ DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate(f32 radians, f32 x, f32 y, f32 z)
DqnMat4 result = DqnMat4_Identity();
f32 sinVal = sinf(radians);
f32 cosVal = cosf(radians);
f32 oneMinusCosVal = 1 - cosVal;
result.e[0][0] = (cosVal + (DQN_SQUARED(x) * (1.0f - cosVal)));
result.e[0][1] = ((y * z * (1.0f - cosVal)) + (z * sinVal));
result.e[0][2] = ((z * x * (1.0f - cosVal)) - (y * sinVal));
result.e[0][0] = (DQN_SQUARED(x) * oneMinusCosVal) + cosVal;
result.e[0][1] = (x * y * oneMinusCosVal) + (z * sinVal);
result.e[0][2] = (x * z * oneMinusCosVal) - (y * sinVal);
result.e[1][0] = ((x * y * (1.0f - cosVal)) - (z * sinVal));
result.e[1][1] = (cosVal + (DQN_SQUARED(y) * (1.0f - cosVal)));
result.e[1][2] = ((z * y * (1.0f - cosVal)) + (x * sinVal));
result.e[1][0] = (y * x * oneMinusCosVal) - (z * sinVal);
result.e[1][1] = (DQN_SQUARED(y) * oneMinusCosVal) + cosVal;
result.e[1][2] = (y * z * oneMinusCosVal) + (x * sinVal);
result.e[2][0] = ((x * z * (1.0f - cosVal)) + (y * sinVal));
result.e[2][1] = ((y * z * (1.0f - cosVal)) - (x * sinVal));
result.e[2][2] = (cosVal + (DQN_SQUARED(z) * (1.0f - cosVal)));
result.e[3][3] = 1;
result.e[2][0] = (z * x * oneMinusCosVal) + (y * sinVal);
result.e[2][1] = (z * y * oneMinusCosVal) - (x * sinVal);
result.e[2][2] = (DQN_SQUARED(z) * oneMinusCosVal) + cosVal;
return result;
}