diff --git a/src/DTRenderer.cpp b/src/DTRenderer.cpp index a8ae4f3..a093cce 100644 --- a/src/DTRenderer.cpp +++ b/src/DTRenderer.cpp @@ -11,42 +11,15 @@ #include -typedef struct WavefrontModelFace -{ - DqnArray vertexArray; - DqnArray textureArray; - DqnArray 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 faces; -} WavefrontModel; - -typedef struct WavefrontObj -{ - DqnArray geometryArray; - DqnArray texUVArray; - DqnArray 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); } diff --git a/src/DTRenderer.h b/src/DTRenderer.h index 5e022e6..e41cece 100644 --- a/src/DTRenderer.h +++ b/src/DTRenderer.h @@ -8,6 +8,32 @@ typedef void DTR_UpdateFunction(struct PlatformRenderBuffer *const renderBuffer, struct PlatformInput *const input, struct PlatformMemory *const memory); +typedef struct WavefrontModelFace +{ + DqnArray vertexArray; + DqnArray textureArray; + DqnArray normalArray; +} WavefrontModelFace; + +typedef struct WavefrontModel +{ + // TODO(doyle): Fixed size + char *groupName[16]; + i32 groupNameIndex; + i32 groupSmoothing; + + DqnArray faces; +} WavefrontModel; + +typedef struct WavefrontObj +{ + DqnArray geometryArray; + DqnArray texUVArray; + DqnArray 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 diff --git a/src/DTRendererDebug.h b/src/DTRendererDebug.h index 0c3105d..a41f87c 100644 --- a/src/DTRendererDebug.h +++ b/src/DTRendererDebug.h @@ -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" diff --git a/src/DTRendererRender.cpp b/src/DTRendererRender.cpp index d76ecae..2fa5006 100644 --- a/src/DTRendererRender.cpp +++ b/src/DTRendererRender.cpp @@ -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; diff --git a/src/build.bat b/src/build.bat index ccaf0d2..1fd2bed 100644 --- a/src/build.bat +++ b/src/build.bat @@ -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% diff --git a/src/dqn.h b/src/dqn.h index 49d12ea..8a005ac 100644 --- a/src/dqn.h +++ b/src/dqn.h @@ -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};