Add temp fix for model gaps in tri rasterisation

This commit is contained in:
Doyle Thai 2017-05-23 18:23:31 +10:00
parent 237e73253a
commit e922efb897
6 changed files with 120 additions and 110 deletions

View File

@ -11,42 +11,15 @@
#include <math.h>
typedef struct WavefrontModelFace
{
DqnArray<i32> vertexArray;
DqnArray<i32> textureArray;
DqnArray<i32> normalArray;
} WavefrontModelFace;
FILE_SCOPE inline WavefrontModelFace ObjWavefrontModelFaceInit(i32 capacity = 3)
{
WavefrontModelFace result = {};
DQN_ASSERT(DqnArray_Init(&result.vertexArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.vertexArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.textureArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.normalArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.normalArray, capacity));
return result;
}
typedef struct WavefrontModel
{
// TODO(doyle): Fixed size
char *groupName[16];
i32 groupNameIndex;
i32 groupSmoothing;
DqnArray<WavefrontModelFace> faces;
} WavefrontModel;
typedef struct WavefrontObj
{
DqnArray<DqnV4> geometryArray;
DqnArray<DqnV3> texUVArray;
DqnArray<DqnV3> normalArray;
WavefrontModel model;
} WavefrontObj;
FILE_SCOPE bool ObjWaveFrontInit(WavefrontObj *const obj, const i32 vertexInitCapacity = 1000,
const i32 faceInitCapacity = 200)
{
@ -147,7 +120,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
}
i32 f32Len = (i32)((size_t)scan - (size_t)f32StartPtr);
v4.e[vIndex++] = Dqn_StrToF32(f32StartPtr, f32Len);
v4.e[vIndex++] = (f32)atof(f32StartPtr); // Dqn_StrToF32(f32StartPtr, f32Len);
DQN_ASSERT(vIndex < DQN_ARRAY_COUNT(v4.e));
while (scan && (*scan == ' ' || *scan == '\n')) scan++;
@ -1480,7 +1453,6 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
}
DTR_DEBUG_TIMED_FUNCTION();
LOCAL_PERSIST WavefrontObj waveObj = {};
if (!memory->isInit)
{
TestStrToF32Converter();
@ -1504,80 +1476,72 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->permMemStack);
BitmapLoad(input->api, &test, "byte_read_check.bmp",
&memory->transMemStack);
int x = 5;
DqnMemStack_EndTempRegion(tmp);
#if 0
DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &waveObj));
#endif
DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &state->obj));
}
DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0));
DTRRender_Clear(renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
#if 1
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
for (i32 i = 0; i < waveObj.model.faces.count; i++)
const DqnV3 LIGHT = DqnV3_3i(0, 0, -1);
const f32 MODEL_SCALE = DQN_MIN(renderBuffer->width, renderBuffer->height) * 0.5f;
WavefrontObj *const waveObj = &state->obj;
DqnV2 modelP = DqnV2_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f);
for (i32 i = 0; i < waveObj->model.faces.count; i++)
{
WavefrontModelFace face = waveObj.model.faces.data[i];
WavefrontModelFace face = waveObj->model.faces.data[i];
DQN_ASSERT(face.vertexArray.count == 3);
#if 0
i32 vertAIndex = face.vertexArray.data[0];
i32 vertBIndex = face.vertexArray.data[1];
i32 vertCIndex = face.vertexArray.data[2];
DqnV4 vertA = waveObj.geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj.geometryArray.data[vertBIndex];
DqnV4 vertC = waveObj.geometryArray.data[vertCIndex];
DqnV4 vertA = waveObj->geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj->geometryArray.data[vertBIndex];
DqnV4 vertC = waveObj->geometryArray.data[vertCIndex];
vertA.x *= (renderBuffer->width * 0.5f);
vertA.y *= (renderBuffer->height * 0.5f);
DqnV4 vertAB = vertB - vertA;
DqnV4 vertAC = vertC - vertA;
DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz);
vertB.x *= (renderBuffer->width * 0.5f);
vertB.y *= (renderBuffer->height * 0.5f);
vertC.x *= (renderBuffer->width * 0.5f);
vertC.y *= (renderBuffer->height * 0.5f);
vertA.x += (renderBuffer->width * 0.5f);
vertA.y += (renderBuffer->height * 0.5f);
vertB.x += (renderBuffer->width * 0.5f);
vertB.y += (renderBuffer->height * 0.5f);
vertC.x += (renderBuffer->width * 0.5f);
vertC.y += (renderBuffer->height * 0.5f);
DTRRender_Triangle(renderBuffer, vertA.xy, vertB.xy, vertC.xy, modelCol);
#else
const i32 NUM_VERTEXES = 3;
for (i32 j = 0; j < NUM_VERTEXES; j++)
f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT);
if (intensity > 0)
{
i32 vertAIndex = face.vertexArray.data[j];
i32 vertBIndex = face.vertexArray.data[(j + 1) % NUM_VERTEXES];
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
modelCol.rgb *= intensity;
DqnV4 vertA = waveObj.geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj.geometryArray.data[vertBIndex];
DqnV2 screenVertA = (vertA.xy * MODEL_SCALE) + modelP;
DqnV2 screenVertB = (vertB.xy * MODEL_SCALE) + modelP;
DqnV2 screenVertC = (vertC.xy * MODEL_SCALE) + modelP;
vertA.x = (vertA.x * (renderBuffer->width * 0.5f)) + renderBuffer->width * 0.5f;
vertA.y = (vertA.y * (renderBuffer->height * 0.5f)) + renderBuffer->height * 0.5f;
// TODO(doyle): Why do we need rounding here? Maybe it's because
// I don't do any interpolation in the triangle routine for jagged
// edges.
screenVertA.x = (f32)(i32)(screenVertA.x + 0.5f);
screenVertA.y = (f32)(i32)(screenVertA.y + 0.5f);
screenVertB.x = (f32)(i32)(screenVertB.x + 0.5f);
screenVertB.y = (f32)(i32)(screenVertB.y + 0.5f);
screenVertC.x = (f32)(i32)(screenVertC.x + 0.5f);
screenVertC.y = (f32)(i32)(screenVertC.y + 0.5f);
vertB.x = (vertB.x * (renderBuffer->width * 0.5f)) + renderBuffer->width * 0.5f;
vertB.y = (vertB.y * (renderBuffer->height * 0.5f)) + renderBuffer->height * 0.5f;
DTRRender_Line(renderBuffer, DqnV2i_V2(vertA.xy), DqnV2i_V2(vertB.xy), modelCol);
}
#endif
}
#endif
DTRRender_Triangle(renderBuffer, screenVertA, screenVertB, screenVertC, modelCol);
#if 0
DqnV4 wireColor = DqnV4_1f(1.0f);
for (i32 j = 0; j < 3; j++)
{
DTRRender_Line(renderBuffer, DqnV2i_V2(screenVertA), DqnV2i_V2(screenVertB), wireColor);
}
#endif
}
}
#if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
DqnV2i bufferMidP =
DqnV2i_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f);
i32 boundsOffset = 100;
DqnV2 t0[3] = {DqnV2_2i(10, 70), DqnV2_2i(50, 160), DqnV2_2i(70, 80)};
DqnV2 t0[3] = {DqnV2_2i(10, 70), DqnV2_2i(50, 160), DqnV2_2i(70, 80)};
DqnV2 t1[3] = {DqnV2_2i(180, 50), DqnV2_2i(150, 1), DqnV2_2i(70, 180)};
DqnV2 t2[3] = {DqnV2_2i(180, 150), DqnV2_2i(120, 160), DqnV2_2i(130, 180)};
LOCAL_PERSIST DqnV2 t3[3] = {
@ -1589,16 +1553,20 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DTRRender_Triangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
DqnV2 t4[3] = {DqnV2_2i(100, 150), DqnV2_2i(200, 150), DqnV2_2i(200, 250)};
DqnV2 t5[3] = {DqnV2_2i(300, 150), DqnV2_2i(201, 150), DqnV2_2i(200, 250)};
DTRRender_Triangle(renderBuffer, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(renderBuffer, t5[0], t5[1], t5[2], colorRed);
DqnV4 colorRedHalfA = DqnV4_4f(1, 0, 0, 0.1f);
LOCAL_PERSIST f32 rotation = 0;
rotation += input->deltaForFrame * 0.25f;
#if 1
DTRRenderTransform defaultTransform = DTRRender_DefaultTransform();
defaultTransform.rotation = rotation + 45;
DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), DqnV4_4f(0, 1.0f, 1.0f, 1.0f),
defaultTransform);
#endif
// Rotating triangle
{
@ -1624,8 +1592,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DTRRender_Bitmap(renderBuffer, &state->bitmap, bitmapP, transform, color);
#else
CompAssignment(renderBuffer, input, memory);
#endif
// CompAssignment(renderBuffer, input, memory);
#endif
DTRDebug_Update(state, renderBuffer, input, memory);
}

View File

@ -8,6 +8,32 @@ typedef void DTR_UpdateFunction(struct PlatformRenderBuffer *const renderBuffer,
struct PlatformInput *const input,
struct PlatformMemory *const memory);
typedef struct WavefrontModelFace
{
DqnArray<i32> vertexArray;
DqnArray<i32> textureArray;
DqnArray<i32> normalArray;
} WavefrontModelFace;
typedef struct WavefrontModel
{
// TODO(doyle): Fixed size
char *groupName[16];
i32 groupNameIndex;
i32 groupSmoothing;
DqnArray<WavefrontModelFace> faces;
} WavefrontModel;
typedef struct WavefrontObj
{
DqnArray<DqnV4> geometryArray;
DqnArray<DqnV3> texUVArray;
DqnArray<DqnV3> normalArray;
WavefrontModel model;
} WavefrontObj;
typedef struct DTRFont
{
u8 *bitmap;
@ -27,7 +53,8 @@ typedef struct DTRBitmap
typedef struct DTRState
{
DTRFont font;
DTRBitmap bitmap;
DTRFont font;
DTRBitmap bitmap;
WavefrontObj obj;
} DTRState;
#endif

View File

@ -3,11 +3,11 @@
#include "dqn.h"
#define DTR_DEBUG 1
#ifdef DTR_DEBUG
#if DTR_DEBUG
#define DTR_DEBUG_RENDER 0
#define DTR_DEBUG_PROFILING 1
#ifdef DTR_DEBUG_PROFILING
#define DTR_DEBUG_PROFILING 0
#if DTR_DEBUG_PROFILING
#define BUILD_WITH_EASY_PROFILER 1
#include "external/easy/profiler.h"

View File

@ -580,7 +580,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
= (bx - ax)(1) = (bx - ax)
Then we can see that when we progress along x, we only need to change by
the value of SignedArea by (ay - by) and similarly for y, (bx - ay)
the value of SignedArea by (ay - by) and similarly for y, (bx - ax)
/////////////////////////////////////////////////////////////////////////
// Barycentric Coordinates
@ -632,16 +632,16 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
const DqnV2 b = p2;
const DqnV2 c = p3;
DqnV2i scanP = DqnV2i_2i(min.x, min.y);
f32 signedArea1 = ((b.x - a.x) * (scanP.y - a.y)) - ((b.y - a.y) * (scanP.x - a.x));
DqnV2i startP = min;
f32 signedArea1 = ((b.x - a.x) * (startP.y - a.y)) - ((b.y - a.y) * (startP.x - a.x));
f32 signedArea1DeltaX = a.y - b.y;
f32 signedArea1DeltaY = b.x - a.x;
f32 signedArea2 = ((c.x - b.x) * (scanP.y - b.y)) - ((c.y - b.y) * (scanP.x - b.x));
f32 signedArea2 = ((c.x - b.x) * (startP.y - b.y)) - ((c.y - b.y) * (startP.x - b.x));
f32 signedArea2DeltaX = b.y - c.y;
f32 signedArea2DeltaY = c.x - b.x;
f32 signedArea3 = ((a.x - c.x) * (scanP.y - c.y)) - ((a.y - c.y) * (scanP.x - c.x));
f32 signedArea3 = ((a.x - c.x) * (startP.y - c.y)) - ((a.y - c.y) * (startP.x - c.x));
f32 signedArea3DeltaX = c.y - a.y;
f32 signedArea3DeltaY = a.x - c.x;
@ -650,18 +650,19 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
////////////////////////////////////////////////////////////////////////////
// Scan and Render
////////////////////////////////////////////////////////////////////////////
for (scanP.y = min.y; scanP.y < max.y; scanP.y++)
color.rgb *= 0.1f;
for (i32 bufferY = min.y; bufferY < max.y; bufferY++)
{
f32 signedArea1Row = signedArea1;
f32 signedArea2Row = signedArea2;
f32 signedArea3Row = signedArea3;
for (scanP.x = min.x; scanP.x < max.x; scanP.x++)
for (i32 bufferX = min.x; bufferX < max.x; bufferX++)
{
if (signedArea1Row >= 0 && signedArea2Row >= 0 && signedArea3Row >= 0)
{
SetPixel(renderBuffer, scanP.x, scanP.y, color, ColorSpace_Linear);
SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
}
signedArea1Row += signedArea1DeltaX;

View File

@ -61,7 +61,8 @@ REM Compile
REM ////////////////////////////////////////////////////////////////////////////
del *.pdb >NUL 2>NUL
cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags%
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link ..\src\external\easy\easy_profiler.lib /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%
REM cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link ..\src\external\easy\easy_profiler.lib /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%
popd
set LastError=%ERRORLEVEL%

View File

@ -504,6 +504,8 @@ DQN_FILE_SCOPE inline bool operator==(DqnV2i a, DqnV2i b) { return DqnV
typedef union DqnV3
{
struct { f32 x, y, z; };
DqnV2 xy;
struct { f32 r, g, b; };
f32 e[3];
} DqnV3;
@ -528,6 +530,8 @@ DQN_FILE_SCOPE f32 DqnV3_Dot (DqnV3 a, DqnV3 b);
DQN_FILE_SCOPE bool DqnV3_Equals (DqnV3 a, DqnV3 b);
DQN_FILE_SCOPE DqnV3 DqnV3_Cross (DqnV3 a, DqnV3 b);
DQN_FILE_SCOPE DqnV3 DqnV3_Normalise(DqnV3 a);
DQN_FILE_SCOPE inline DqnV3 operator- (DqnV3 a, DqnV3 b) { return DqnV3_Sub (a, b); }
DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, DqnV3 b) { return DqnV3_Add (a, b); }
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, DqnV3 b) { return DqnV3_Hadamard(a, b); }
@ -575,17 +579,18 @@ DQN_FILE_SCOPE DqnV4 DqnV4_Hadamard(DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE f32 DqnV4_Dot (DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE bool DqnV4_Equals (DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE inline DqnV4 operator- (DqnV4 a, DqnV4 b) { return DqnV4_Sub (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, DqnV4 b) { return DqnV4_Add (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, DqnV4 b) { return DqnV4_Hadamard(a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, i32 b) { return DqnV4_Scalei (a, b); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Hadamard(a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, f32 b) { return (a = DqnV4_Scalef (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, i32 b) { return (a = DqnV4_Scalei (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator+=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Add (a, b)); }
DQN_FILE_SCOPE inline bool operator==(DqnV4 a, DqnV4 b) { return DqnV4_Equals (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator- (DqnV4 a, DqnV4 b) { return DqnV4_Sub (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, DqnV4 b) { return DqnV4_Add (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, f32 b) { return DqnV4_Add (a, DqnV4_1f(b)); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, DqnV4 b) { return DqnV4_Hadamard(a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, i32 b) { return DqnV4_Scalei (a, b); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Hadamard(a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, f32 b) { return (a = DqnV4_Scalef (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, i32 b) { return (a = DqnV4_Scalei (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator+=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Add (a, b)); }
DQN_FILE_SCOPE inline bool operator==(DqnV4 a, DqnV4 b) { return DqnV4_Equals (a, b); }
////////////////////////////////////////////////////////////////////////////////
// 4D Matrix Mat4
@ -2125,6 +2130,15 @@ DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b)
return result;
}
DQN_FILE_SCOPE DqnV3 DqnV3_Normalise(DqnV3 a)
{
f32 length = DqnMath_Sqrtf(DQN_SQUARED(a.x) + DQN_SQUARED(a.y) + DQN_SQUARED(a.z));
f32 invLength = 1 / length;
DqnV3 result = a * invLength;
return result;
}
DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z)
{
DqnV3i result = {x, y, z};