From 237e73253aab274cecb1b74597ef3fffd52123b2 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Mon, 22 May 2017 20:54:34 +1000 Subject: [PATCH] Fix incorrect indexing into vertex array for model Wavefront model obj format indexes starting from 1, offset during load by -1 to make all indexes be 0 based. --- src/DTRenderer.cpp | 95 +++++++++++++++++++++++++++++++++++-------- src/DTRendererDebug.h | 2 +- src/dqn.h | 33 +++++++++++---- 3 files changed, 106 insertions(+), 24 deletions(-) diff --git a/src/DTRenderer.cpp b/src/DTRenderer.cpp index 4fb163f..a8ae4f3 100644 --- a/src/DTRenderer.cpp +++ b/src/DTRenderer.cpp @@ -71,9 +71,9 @@ FILE_SCOPE bool ObjWaveFrontInit(WavefrontObj *const obj, const i32 vertexInitCa } FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const memory, - const char *const path) + const char *const path, WavefrontObj *const obj) { - if (!memory || ! path) return false; + if (!memory || !path || !obj) return false; PlatformFile file = {}; if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read)) @@ -98,8 +98,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me WavefrontVertexType_Normal, }; - WavefrontObj obj = {}; - if (!ObjWaveFrontInit(&obj)) + if (!ObjWaveFrontInit(obj)) { DqnMemStack_EndTempRegion(tmpMemRegion); return false; @@ -160,15 +159,15 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me DQN_ASSERT(vIndex == 3 || vIndex == 4); if (type == WavefrontVertexType_Geometric) { - DqnArray_Push(&obj.geometryArray, v4); + DqnArray_Push(&obj->geometryArray, v4); } else if (type == WavefrontVertexType_Texture) { - DqnArray_Push(&obj.texUVArray, v4.xyz); + DqnArray_Push(&obj->texUVArray, v4.xyz); } else if (type == WavefrontVertexType_Normal) { - DqnArray_Push(&obj.normalArray, v4.xyz); + DqnArray_Push(&obj->normalArray, v4.xyz); } else { @@ -239,7 +238,9 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me i32 numLen = (i32)((size_t)scan - (size_t)numStartPtr); if (numLen > 0) { - i32 index = (i32)Dqn_StrToI64(numStartPtr, numLen); + // NOTE(doyle): Obj format starts indexing from 1, + // so offset by -1 to make it zero-based indexes. + i32 index = (i32)Dqn_StrToI64(numStartPtr, numLen) - 1; if (type == WavefrontVertexType_Geometric) { @@ -274,13 +275,13 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me } } - if (obj.model.faces.count == 7470 || obj.model.faces.count == 2491) + if (obj->model.faces.count == 7470 || obj->model.faces.count == 2491) { int x = 5; } } DQN_ASSERT(numVertexesParsed >= 3); - DQN_ASSERT(DqnArray_Push(&obj.model.faces, face)); + DQN_ASSERT(DqnArray_Push(&obj->model.faces, face)); } break; @@ -307,14 +308,14 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me if (scan) { i32 nameLen = (i32)((size_t)scan - (size_t)namePtr); - DQN_ASSERT(obj.model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj.model.groupName)); + DQN_ASSERT(obj->model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj->model.groupName)); - DQN_ASSERT(!obj.model.groupName[obj.model.groupNameIndex]); - obj.model.groupName[obj.model.groupNameIndex++] = (char *)DqnMemStack_Allocate( + DQN_ASSERT(!obj->model.groupName[obj->model.groupNameIndex]); + obj->model.groupName[obj->model.groupNameIndex++] = (char *)DqnMemStack_Allocate( &memory->permMemStack, (nameLen + 1) * sizeof(char)); for (i32 i = 0; i < nameLen; i++) - obj.model.groupName[obj.model.groupNameIndex - 1][i] = namePtr[i]; + obj->model.groupName[obj->model.groupNameIndex - 1][i] = namePtr[i]; while (scan && (*scan == ' ' || *scan == '\n')) scan++; @@ -342,7 +343,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me i32 numLen = (i32)((size_t)scan - (size_t)numStartPtr); i32 groupSmoothing = (i32)Dqn_StrToI64(numStartPtr, numLen); - obj.model.groupSmoothing = groupSmoothing; + obj->model.groupSmoothing = groupSmoothing; } while (scan && *scan == ' ' || *scan == '\n') scan++; @@ -1479,6 +1480,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, } DTR_DEBUG_TIMED_FUNCTION(); + LOCAL_PERSIST WavefrontObj waveObj = {}; if (!memory->isInit) { TestStrToF32Converter(); @@ -1505,10 +1507,70 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, int x = 5; DqnMemStack_EndTempRegion(tmp); - ObjWavefrontLoad(input->api, memory, "african_head.obj"); +#if 0 + DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &waveObj)); +#endif } DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0)); +#if 1 + DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1); + for (i32 i = 0; i < waveObj.model.faces.count; 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]; + + 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); + + 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++) + { + i32 vertAIndex = face.vertexArray.data[j]; + i32 vertBIndex = face.vertexArray.data[(j + 1) % NUM_VERTEXES]; + + DqnV4 vertA = waveObj.geometryArray.data[vertAIndex]; + DqnV4 vertB = waveObj.geometryArray.data[vertBIndex]; + + vertA.x = (vertA.x * (renderBuffer->width * 0.5f)) + renderBuffer->width * 0.5f; + vertA.y = (vertA.y * (renderBuffer->height * 0.5f)) + renderBuffer->height * 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 + +#if 0 #if 1 DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1); DqnV2i bufferMidP = @@ -1563,6 +1625,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, #else CompAssignment(renderBuffer, input, memory); +#endif #endif DTRDebug_Update(state, renderBuffer, input, memory); } diff --git a/src/DTRendererDebug.h b/src/DTRendererDebug.h index 92a06d7..0c3105d 100644 --- a/src/DTRendererDebug.h +++ b/src/DTRendererDebug.h @@ -4,7 +4,7 @@ #include "dqn.h" #define DTR_DEBUG 1 #ifdef DTR_DEBUG - #define DTR_DEBUG_RENDER 1 + #define DTR_DEBUG_RENDER 0 #define DTR_DEBUG_PROFILING 1 #ifdef DTR_DEBUG_PROFILING diff --git a/src/dqn.h b/src/dqn.h index fef11d2..49d12ea 100644 --- a/src/dqn.h +++ b/src/dqn.h @@ -129,11 +129,12 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem (DqnMemStack *const stack, u8 * DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out -DQN_FILE_SCOPE void *DqnMemStack_Allocate (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails -DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack +DQN_FILE_SCOPE void *DqnMemStack_Allocate (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails +DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack +DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock (DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong -DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block. -DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock (DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0 +DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block. +DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock (DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0 // TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack. // Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original @@ -547,8 +548,12 @@ DQN_FILE_SCOPE DqnV3i DqnV3i_3f(f32 x, f32 y, f32 z); // Vec4 //////////////////////////////////////////////////////////////////////////////// typedef union DqnV4 { - struct { f32 x, y, z, w; }; + struct + { + f32 x, y, z, w; + }; DqnV3 xyz; + DqnV2 xy; struct { f32 r, g, b, a; }; DqnV3 rgb; @@ -1498,8 +1503,22 @@ DQN_FILE_SCOPE void *DqnMemStack_Allocate(DqnMemStack *const stack, size_t size) return result; } -DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, - DqnMemStackBlock *block) +DQN_FILE_SCOPE bool DqnMemStack_Pop(DqnMemStack *const stack, void *ptr, size_t size) +{ + if (!stack || !stack->block) return false; + + u8 *currPtr = stack->block->memory + stack->block->used; + DQN_ASSERT((u8 *)ptr >= stack->block->memory && ptr < currPtr); + + size_t calcSize = (size_t)currPtr - (size_t)ptr; + DQN_ASSERT(calcSize == size); + + stack->block->used -= size; + + return true; +} + +DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block) { if (!stack || !block || !stack->block) return false; if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false;