Add gouraud shading, can choose lighting options
This commit is contained in:
parent
ee31383906
commit
285d3d2681
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
51
src/dqn.h
51
src/dqn.h
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user