Fix zbuffer bug clipping at poly's behind 0, 0

Mistakenly use FLT_MIN as the largest negative number possible, where we should
be using -FLT_MAX.
This commit is contained in:
Doyle Thai 2017-05-25 22:22:47 +10:00
parent a03de5de80
commit 4eb54c09b1
13 changed files with 1919 additions and 123 deletions

View File

@ -6,17 +6,60 @@
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h"
// #define DTR_DEBUG_RENDER_FONT_BITMAP
#ifdef DTR_DEBUG_RENDER_FONT_BITMAP
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/tests/stb_image_write.h"
#endif
#define DQN_IMPLEMENTATION
#include "dqn.h"
#include "external/tests/tinyrenderer/geometry.h"
#include "external/tests/tinyrenderer/model.cpp"
#include <algorithm>
#include <vector>
FILE_SCOPE void DebugTestWavefrontFaceAndVertexParser(WavefrontObj *const obj)
{
if (!obj) DQN_ASSERT(DQN_INVALID_CODE_PATH);
Model model = Model("african_head.obj");
DQN_ASSERT(obj->model.faces.count == model.nfaces());
for (i32 i = 0; i < model.nfaces(); i++)
{
std::vector<i32> correctFace = model.face(i);
WavefrontModelFace *myFace = &obj->model.faces.data[i];
DQN_ASSERT(myFace->vertexIndexArray.count == correctFace.size());
for (i32 j = 0; j < myFace->vertexIndexArray.count; j++)
{
// Ensure the vertex index references are correct per face
DQN_ASSERT(myFace->vertexIndexArray.data[j] == correctFace[j]);
Vec3f tmp = model.vert(correctFace[j]);
DqnV3 correctVertex = DqnV3_3f(tmp[0], tmp[1], tmp[2]);
DqnV3 myVertex = (obj->geometryArray.data[myFace->vertexIndexArray.data[j]]).xyz;
// Ensure the vertex values read are correct
for (i32 k = 0; k < DQN_ARRAY_COUNT(correctVertex.e); k++)
{
f32 delta = DQN_ABS(correctVertex.e[k] - myVertex.e[k]);
DQN_ASSERT(delta < 0.1f);
}
}
}
}
#include <math.h>
FILE_SCOPE inline WavefrontModelFace ObjWavefrontModelFaceInit(i32 capacity = 3)
{
WavefrontModelFace result = {};
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.vertexIndexArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.textureIndexArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.normalIndexArray, capacity));
return result;
}
@ -28,14 +71,14 @@ FILE_SCOPE bool ObjWaveFrontInit(WavefrontObj *const obj, const i32 vertexInitCa
bool initialised = false;
initialised |= DqnArray_Init(&obj->geometryArray, vertexInitCapacity);
initialised |= DqnArray_Init(&obj->texUVArray, vertexInitCapacity);
initialised |= DqnArray_Init(&obj->textureArray, vertexInitCapacity);
initialised |= DqnArray_Init(&obj->normalArray, vertexInitCapacity);
initialised |= DqnArray_Init(&obj->model.faces, faceInitCapacity);
if (!initialised)
{
DqnArray_Free(&obj->geometryArray);
DqnArray_Free(&obj->texUVArray);
DqnArray_Free(&obj->textureArray);
DqnArray_Free(&obj->normalArray);
DqnArray_Free(&obj->model.faces);
}
@ -49,7 +92,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
if (!memory || !path || !obj) return false;
PlatformFile file = {};
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return false; // TODO(doyle): Logging
// TODO(doyle): Make arrays use given memory not malloc
@ -121,7 +164,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
}
i32 f32Len = (i32)((size_t)scan - (size_t)f32StartPtr);
v4.e[vIndex++] = (f32)atof(f32StartPtr); // Dqn_StrToF32(f32StartPtr, f32Len);
v4.e[vIndex++] = Dqn_StrToF32(f32StartPtr, f32Len);
DQN_ASSERT(vIndex < DQN_ARRAY_COUNT(v4.e));
while (scan && (*scan == ' ' || *scan == '\n')) scan++;
@ -137,7 +180,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
}
else if (type == WavefrontVertexType_Texture)
{
DqnArray_Push(&obj->texUVArray, v4.xyz);
DqnArray_Push(&obj->textureArray, v4.xyz);
}
else if (type == WavefrontVertexType_Normal)
{
@ -214,19 +257,19 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
{
// 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;
i32 vertIndex = (i32)Dqn_StrToI64(numStartPtr, numLen) - 1;
if (type == WavefrontVertexType_Geometric)
{
DQN_ASSERT(DqnArray_Push(&face.vertexArray, index));
DQN_ASSERT(DqnArray_Push(&face.vertexIndexArray, vertIndex));
}
else if (type == WavefrontVertexType_Texture)
{
DQN_ASSERT(DqnArray_Push(&face.textureArray, index));
DQN_ASSERT(DqnArray_Push(&face.textureIndexArray, vertIndex));
}
else if (type == WavefrontVertexType_Normal)
{
DQN_ASSERT(DqnArray_Push(&face.normalArray, index));
DQN_ASSERT(DqnArray_Push(&face.normalIndexArray, vertIndex));
}
}
@ -248,11 +291,6 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
moreVertexesToParse = false;
}
}
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));
@ -368,7 +406,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
// Load font data
////////////////////////////////////////////////////////////////////////////
PlatformFile file = {};
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return false; // TODO(doyle): Logging
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
@ -451,6 +489,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
return true;
}
// TODO(doyle): Uses malloc
FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
const char *const path,
DqnMemStack *const transMemStack)
@ -458,7 +497,7 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
if (!bitmap) return false;
PlatformFile file = {};
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return false;
DqnTempMemStack tempBuffer = DqnMemStack_BeginTempRegion(transMemStack);
@ -474,8 +513,10 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
return false;
}
const u32 FORCE_4_BPP = 4;
bitmap->memory = stbi_load_from_memory(rawData, (i32)file.size, &bitmap->dim.w,
&bitmap->dim.h, &bitmap->bytesPerPixel, 4);
&bitmap->dim.h, NULL, FORCE_4_BPP);
bitmap->bytesPerPixel = FORCE_4_BPP;
}
DqnMemStack_EndTempRegion(tempBuffer);
if (!bitmap->memory) return false;
@ -495,14 +536,15 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
color.g = (f32)((pixel >> 8) & 0xFF);
color.r = (f32)((pixel >> 0) & 0xFF);
color *= DTRRENDER_INV_255;
color = DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(color);
color *= 255.0f;
DqnV4 preMulColor = color;
preMulColor *= DTRRENDER_INV_255;
preMulColor = DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(preMulColor);
preMulColor *= 255.0f;
pixel = (((u32)color.a << 24) |
((u32)color.b << 16) |
((u32)color.g << 8) |
((u32)color.r << 0));
pixel = (((u32)preMulColor.a << 24) |
((u32)preMulColor.b << 16) |
((u32)preMulColor.g << 8) |
((u32)preMulColor.r << 0));
pixelPtr[x] = pixel;
}
@ -1370,7 +1412,7 @@ void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const in
}
}
FILE_SCOPE void TestStrToF32Converter()
FILE_SCOPE void DebugTestStrToF32Converter()
{
const f32 EPSILON = 0.001f;
const char a[] = "-0.66248";
@ -1459,7 +1501,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
DTR_DEBUG_EP_TIMED_FUNCTION();
if (!memory->isInit)
{
TestStrToF32Converter();
DebugTestStrToF32Converter();
DTR_DEBUG_EP_TIMED_BLOCK("DTR_Update Memory Initialisation");
// NOTE(doyle): Do premultiply ourselves
stbi_set_unpremultiply_on_load(true);
@ -1482,7 +1524,11 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
&memory->transMemStack);
DqnMemStack_EndTempRegion(tmp);
DQN_ASSERT(BitmapLoad(input->api, &state->objTex, "african_head_diffuse.tga",
&memory->transMemStack));
DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &state->obj));
DebugTestWavefrontFaceAndVertexParser(&state->obj);
}
DqnTempMemStack transMemTmpRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
@ -1502,7 +1548,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
////////////////////////////////////////////////////////////////////////////
// Update and Render
////////////////////////////////////////////////////////////////////////////
DTRRender_Clear(&renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
DTRRender_Clear(&renderBuffer, DqnV3_3f(0.5f, 0.0f, 1.0f));
#if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
@ -1543,25 +1589,31 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
for (i32 i = 0; i < waveObj->model.faces.count; i++)
{
if (i == 852)
{
int BreakHere = 0;
}
WavefrontModelFace face = waveObj->model.faces.data[i];
DQN_ASSERT(face.vertexArray.count == 3);
i32 vertAIndex = face.vertexArray.data[0];
i32 vertBIndex = face.vertexArray.data[1];
i32 vertCIndex = face.vertexArray.data[2];
DQN_ASSERT(face.vertexIndexArray.count == 3);
i32 vertAIndex = face.vertexIndexArray.data[0];
i32 vertBIndex = face.vertexIndexArray.data[1];
i32 vertCIndex = face.vertexIndexArray.data[2];
DqnV4 vertA = waveObj->geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj->geometryArray.data[vertBIndex];
DqnV4 vertC = waveObj->geometryArray.data[vertCIndex];
DQN_ASSERT(vertAIndex < waveObj->geometryArray.count);
DQN_ASSERT(vertBIndex < waveObj->geometryArray.count);
DQN_ASSERT(vertCIndex < waveObj->geometryArray.count);
DqnV4 vertAB = vertB - vertA;
DqnV4 vertAC = vertC - vertA;
DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz);
f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT);
if (intensity > 0)
{
if (intensity < 0) continue;
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
modelCol.rgb *= intensity;
modelCol.rgb *= DQN_ABS(intensity);
DqnV3 screenVA = (vertA.xyz * MODEL_SCALE) + modelP;
DqnV3 screenVB = (vertB.xyz * MODEL_SCALE) + modelP;
@ -1577,20 +1629,41 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
screenVC.x = (f32)(i32)(screenVC.x + 0.5f);
screenVC.y = (f32)(i32)(screenVC.y + 0.5f);
DTRRender_Triangle(&renderBuffer, screenVA, screenVB, screenVC, modelCol);
i32 textureAIndex = face.textureIndexArray.data[0];
i32 textureBIndex = face.textureIndexArray.data[1];
i32 textureCIndex = face.textureIndexArray.data[2];
#if 0
DqnV4 wireColor = DqnV4_1f(1.0f);
for (i32 j = 0; j < 3; j++)
DqnV2 texA = waveObj->textureArray.data[textureAIndex].xy;
DqnV2 texB = waveObj->textureArray.data[textureBIndex].xy;
DqnV2 texC = waveObj->textureArray.data[textureCIndex].xy;
DQN_ASSERT(textureAIndex < waveObj->textureArray.count);
DQN_ASSERT(textureBIndex < waveObj->textureArray.count);
DQN_ASSERT(textureCIndex < waveObj->textureArray.count);
bool DEBUG_SIMPLE_MODE = false;
if (DTR_DEBUG && DEBUG_SIMPLE_MODE)
{
DTRRender_Line(renderBuffer, DqnV2i_V2(screenVertA), DqnV2i_V2(screenVertB), wireColor);
DTRRender_Triangle(&renderBuffer, screenVA, screenVB, screenVC, modelCol);
}
#endif
else
{
DTRRender_TexturedTriangle(&renderBuffer, screenVA, screenVB, screenVC, texA, texB,
texC, &state->objTex, 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(screenVA.xy), DqnV2i_V2(screenVB.xy), wireColor);
DTRRender_Line(&renderBuffer, DqnV2i_V2(screenVB.xy), DqnV2i_V2(screenVC.xy), wireColor);
DTRRender_Line(&renderBuffer, DqnV2i_V2(screenVC.xy), DqnV2i_V2(screenVA.xy), wireColor);
}
}
}
// Rect drawing
if (0)
{
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.rotation = rotation + 45;
@ -1600,6 +1673,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
}
// Bitmap drawing
if (0)
{
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.scale = DqnV2_1f(2.0f);
@ -1618,11 +1692,12 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
#endif
DTRDebug_Update(state, &renderBuffer, input, memory);
////////////////////////////////////////////////////////////////////////////
// End Update
////////////////////////////////////////////////////////////////////////////
DqnMemStack_EndTempRegion(transMemTmpRegion);
DqnMemStack_ClearCurrBlock(&memory->transMemStack, true);
DQN_ASSERT(memory->transMemStack.tempStackCount == 0);
DQN_ASSERT(memory->permMemStack.tempStackCount == 0);
}

View File

@ -10,9 +10,9 @@ typedef void DTR_UpdateFunction(struct PlatformRenderBuffer *const renderBuffer,
typedef struct WavefrontModelFace
{
DqnArray<i32> vertexArray;
DqnArray<i32> textureArray;
DqnArray<i32> normalArray;
DqnArray<i32> vertexIndexArray;
DqnArray<i32> textureIndexArray;
DqnArray<i32> normalIndexArray;
} WavefrontModelFace;
typedef struct WavefrontModel
@ -28,7 +28,7 @@ typedef struct WavefrontModel
typedef struct WavefrontObj
{
DqnArray<DqnV4> geometryArray;
DqnArray<DqnV3> texUVArray;
DqnArray<DqnV3> textureArray;
DqnArray<DqnV3> normalArray;
WavefrontModel model;
@ -56,5 +56,6 @@ typedef struct DTRState
DTRFont font;
DTRBitmap bitmap;
WavefrontObj obj;
DTRBitmap objTex;
} DTRState;
#endif

View File

@ -3,8 +3,56 @@
#include "DTRendererPlatform.h"
#include "DTRendererRender.h"
#include "dqn.h"
DTRDebug globalDebug;
void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *const transMemStack)
{
if (DTR_DEBUG)
{
PlatformAPI *const api = &globalDebug.input->api;
PlatformFile file = {};
u32 permissions = (PlatformFilePermissionFlag_Read | PlatformFilePermissionFlag_Write);
if (!api->FileOpen("zBufferDump.txt", &file, permissions,
PlatformFileAction_CreateIfNotExist))
{
if (!api->FileOpen("zBufferDump.txt", &file, permissions,
PlatformFileAction_ClearIfExist))
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
}
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(transMemStack);
size_t bufSize = DQN_MEGABYTE(16);
char *bufString = (char *)DqnMemStack_Push(transMemStack, bufSize);
char *bufPtr = bufString;
for (i32 i = 0; i < renderBuffer->width * renderBuffer->height; i++)
{
f32 zValue = renderBuffer->zBuffer[i];
if (zValue == DQN_F32_MIN) continue;
i32 chWritten = Dqn_sprintf(bufPtr, "index %06d: %05.5f\n", i, zValue);
if ((bufPtr + chWritten) > (bufString + bufSize))
{
size_t bufPtrAddr = (size_t)(bufPtr + chWritten);
size_t bufStringAddr = (size_t)(bufString + bufSize);
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
bufPtr += chWritten;
}
size_t writeSize = (size_t)bufPtr - (size_t)bufString;
size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize);
api->FileClose(&file);
DqnMemStack_EndTempRegion(tmpMemRegion);
}
}
void DTRDebug_PushText(const char *const formatStr, ...)
{
if (DTR_DEBUG)
@ -105,6 +153,21 @@ void DTRDebug_Update(DTRState *const state,
debug->totalSetPixels += debug->counter[DTRDebugCounter_SetPixels];
debug->totalSetPixels = DQN_MAX(0, debug->totalSetPixels);
// memory
{
PushMemStackText("PermBuffer", &memory->permMemStack);
PushMemStackText("TransBuffer", &memory->transMemStack);
}
DTRDebug_PushText("Mouse: %d, %d", input->mouse.x, input->mouse.y);
DTRDebug_PushText("MouseLBtn: %s", (input->mouse.leftBtn.endedDown) ? "true" : "false");
DTRDebug_PushText("MouseRBtn: %s", (input->mouse.rightBtn.endedDown) ? "true" : "false");
DTRDebug_PushText("");
DTRDebug_PushText("SSE2Support: %s", (input->canUseSSE2) ? "true" : "false");
DTRDebug_PushText("RDTSCSupport: %s", (input->canUseRdtsc) ? "true" : "false");
DTRDebug_PushText("");
DTRDebug_PushText("TotalSetPixels: %'lld", debug->totalSetPixels);
DTRDebug_PushText("SetPixelsPerFrame: %'lld", debug->counter[DTRDebugCounter_SetPixels]);
DTRDebug_PushText("TrianglesRendered: %'lld", debug->counter[DTRDebugCounter_RenderTriangle]);
@ -116,15 +179,10 @@ void DTRDebug_Update(DTRState *const state,
}
DTRDebug_PushText("");
// memory
{
PushMemStackText("PermBuffer", &memory->permMemStack);
PushMemStackText("TransBuffer", &memory->transMemStack);
}
DTRDebug_PushText("SSE2Support: %s", (input->canUseSSE2) ? "true" : "false");
DTRDebug_PushText("SSE2Support: %s", (input->canUseRdtsc) ? "true" : "false");
////////////////////////////////////////////////////////////////////////
// End Debug Update
////////////////////////////////////////////////////////////////////////
debug->displayP =
DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset);

View File

@ -4,7 +4,7 @@
#include "dqn.h"
#define DTR_DEBUG 1
#if DTR_DEBUG
#define DTR_DEBUG_RENDER 0
#define DTR_DEBUG_RENDER 1
#define DTR_DEBUG_PROFILING_EASY_PROFILER 0
#if DTR_DEBUG_PROFILING_EASY_PROFILER
@ -67,6 +67,7 @@ typedef struct DTRDebug
extern DTRDebug globalDebug;
void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *const transMemStack);
void DTRDebug_PushText(const char *const formatStr, ...);
void DTRDebug_Update(DTRState *const state,
DTRRenderBuffer *const renderBuffer,

View File

@ -10,6 +10,13 @@ enum PlatformFilePermissionFlag
PlatformFilePermissionFlag_Write = (1 << 1),
};
enum PlatformFileAction
{
PlatformFileAction_OpenOnly,
PlatformFileAction_CreateIfNotExist,
PlatformFileAction_ClearIfExist,
};
typedef struct PlatformFile
{
void *handle;
@ -17,16 +24,16 @@ typedef struct PlatformFile
u32 permissionFlags;
} PlatformFile;
typedef bool PlatformAPI_FileOpen (const char *const path, PlatformFile *const file,
const u32 permissionFlags);
typedef size_t PlatformAPI_FileRead (PlatformFile *const file, u8 *const buf,
const size_t bytesToRead); // Return bytes read
typedef bool PlatformAPI_FileOpen (const char *const path, PlatformFile *const file, const u32 permissionFlags, const enum PlatformFileAction actionFlags);
typedef size_t PlatformAPI_FileRead (PlatformFile *const file, u8 *const buf, const size_t bytesToRead); // Return bytes read
typedef size_t PlatformAPI_FileWrite(PlatformFile *const file, u8 *const buf, const size_t numBytesToWrite); // Return bytes read
typedef void PlatformAPI_FileClose(PlatformFile *const file);
typedef void PlatformAPI_Print (const char *const string);
typedef struct PlatformAPI
{
PlatformAPI_FileOpen *FileOpen;
PlatformAPI_FileRead *FileRead;
PlatformAPI_FileWrite *FileWrite;
PlatformAPI_FileClose *FileClose;
PlatformAPI_Print *Print;
} PlatformAPI;
@ -68,6 +75,14 @@ typedef struct KeyState
u32 halfTransitionCount;
} KeyState;
typedef struct PlatformMouse
{
i32 x;
i32 y;
KeyState leftBtn;
KeyState rightBtn;
} PlatformMouse;
typedef struct PlatformInput
{
f32 deltaForFrame;
@ -77,6 +92,7 @@ typedef struct PlatformInput
bool canUseRdtsc;
PlatformAPI api;
PlatformMouse mouse;
union {
KeyState key[key_count];
struct

View File

@ -7,16 +7,11 @@
#include "external/stb_rect_pack.h"
#include "external/stb_truetype.h"
// #define DTR_DEBUG_RENDER_FONT_BITMAP
#ifdef DTR_DEBUG_RENDER_FONT_BITMAP
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/stb_image_write.h"
#endif
FILE_SCOPE const f32 COLOR_EPSILON = 0.9f;
FILE_SCOPE inline DqnV4 PreMultiplyAlpha1(const DqnV4 color)
{
DQN_ASSERT(color.a >= 0.0f && color.a <= 1.0f);
DqnV4 result;
result.r = color.r * color.a;
result.g = color.g * color.a;
@ -26,7 +21,10 @@ FILE_SCOPE inline DqnV4 PreMultiplyAlpha1(const DqnV4 color)
DQN_ASSERT(result.r >= 0.0f && result.r <= 1.0f);
DQN_ASSERT(result.g >= 0.0f && result.g <= 1.0f);
DQN_ASSERT(result.b >= 0.0f && result.b <= 1.0f);
DQN_ASSERT(result.a >= 0.0f && result.a <= 1.0f);
DQN_ASSERT(result.a >= result.r);
DQN_ASSERT(result.a >= result.g);
DQN_ASSERT(result.a >= result.b);
return result;
}
@ -113,10 +111,8 @@ FILE_SCOPE inline void SetPixel(DTRRenderBuffer *const renderBuffer, const i32 x
// If some alpha is involved, we need to apply gamma correction, but if the
// new pixel is totally opaque or invisible then we're just flat out
// overwriting/keeping the state of the pixel so we can save cycles by skipping.
#if 1
bool needGammaFix = (color.a > 0.0f || color.a < 1.0f + COLOR_EPSILON) && (colorSpace == ColorSpace_SRGB);
if (needGammaFix) color = DTRRender_SRGB1ToLinearSpaceV4(color);
#endif
u32 src = bitmapPtr[x + (y * pitchInU32)];
f32 srcR = (f32)((src >> 16) & 0xFF) * DTRRENDER_INV_255;
@ -484,6 +480,237 @@ void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 m
}
}
FILE_SCOPE void DebugBarycentricInternal(DqnV2 p, DqnV2 a, DqnV2 b, DqnV2 c, f32 *u, f32 *v, f32 *w)
{
DqnV2 v0 = b - a;
DqnV2 v1 = c - a;
DqnV2 v2 = p - a;
f32 d00 = DqnV2_Dot(v0, v0);
f32 d01 = DqnV2_Dot(v0, v1);
f32 d11 = DqnV2_Dot(v1, v1);
f32 d20 = DqnV2_Dot(v2, v0);
f32 d21 = DqnV2_Dot(v2, v1);
f32 denom = d00 * d11 - d01 * d01;
*v = (d11 * d20 - d01 * d21) / denom;
*w = (d00 * d21 - d01 * d20) / denom;
*u = 1.0f - *v - *w;
}
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)
{
DTR_DEBUG_EP_TIMED_FUNCTION();
////////////////////////////////////////////////////////////////////////////
// Transform vertexes
////////////////////////////////////////////////////////////////////////////
DqnV3 p1p2 = p2 - p1;
DqnV3 p1p3 = p3 - p1;
// TODO(doyle): Transform is only in 2d right now
DqnV2 p1p2Anchored = p1p2.xy * transform.anchor;
DqnV2 p1p3Anchored = p1p3.xy * transform.anchor;
DqnV2 origin = p1.xy + p1p2Anchored + p1p3Anchored;
DqnV2 pList[3] = {p1.xy - origin, p2.xy - origin, p3.xy - origin};
TransformPoints(origin, pList, DQN_ARRAY_COUNT(pList), transform.scale, transform.rotation);
p1.xy = pList[0];
p2.xy = pList[1];
p3.xy = pList[2];
color = DTRRender_SRGB1ToLinearSpaceV4(color);
color = PreMultiplyAlpha1(color);
////////////////////////////////////////////////////////////////////////////
// Calculate Bounding Box
////////////////////////////////////////////////////////////////////////////
DqnV2i max = DqnV2i_2f(DQN_MAX(DQN_MAX(p1.x, p2.x), p3.x),
DQN_MAX(DQN_MAX(p1.y, p2.y), p3.y));
DqnV2i min = DqnV2i_2f(DQN_MIN(DQN_MIN(p1.x, p2.x), p3.x),
DQN_MIN(DQN_MIN(p1.y, p2.y), p3.y));
min.x = DQN_MAX(min.x, 0);
min.y = DQN_MAX(min.y, 0);
max.x = DQN_MIN(max.x, renderBuffer->width - 1);
max.y = DQN_MIN(max.y, renderBuffer->height - 1);
f32 area2Times = ((p2.x - p1.x) * (p2.y + p1.y)) +
((p3.x - p2.x) * (p3.y + p2.y)) +
((p1.x - p3.x) * (p1.y + p3.y));
if (area2Times > 0)
{
// Clockwise swap any point to make it clockwise
DQN_SWAP(DqnV3, p2, p3);
}
////////////////////////////////////////////////////////////////////////////
// Signed Area - See Render_Triangle for explanation
////////////////////////////////////////////////////////////////////////////
const DqnV3 a = p1;
const DqnV3 b = p2;
const DqnV3 c = p3;
DqnV2i startP = min;
f32 oldSignedArea1 = ((b.x - a.x) * (startP.y - a.y)) - ((b.y - a.y) * (startP.x - a.x));
f32 oldSignedArea2 = ((c.x - b.x) * (startP.y - b.y)) - ((c.y - b.y) * (startP.x - b.x));
f32 oldSignedArea3 = ((a.x - c.x) * (startP.y - c.y)) - ((a.y - c.y) * (startP.x - c.x));
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) * (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) * (startP.y - c.y)) - ((a.y - c.y) * (startP.x - c.x));
f32 signedArea3DeltaX = c.y - a.y;
f32 signedArea3DeltaY = a.x - c.x;
f32 signedAreaParallelogram = signedArea1 + signedArea2 + signedArea3;
if (signedAreaParallelogram == 0) return;
f32 invSignedAreaParallelogram = 1 / signedAreaParallelogram;
DTRDebug_BeginCycleCount(DTRDebugCycleCount_RenderTriangle_Rasterise);
////////////////////////////////////////////////////////////////////////////
// Scan and Render
////////////////////////////////////////////////////////////////////////////
const u32 zBufferPitch = renderBuffer->width;
const f32 BARYCENTRIC_EPSILON = 0.1f;
u8 *texturePtr = texture->memory;
const u32 texturePitch = texture->bytesPerPixel * texture->dim.w;
for (i32 bufferY = min.y; bufferY < max.y; bufferY++)
{
f32 signedArea1Row = signedArea1;
f32 signedArea2Row = signedArea2;
f32 signedArea3Row = signedArea3;
for (i32 bufferX = min.x; bufferX < max.x; bufferX++)
{
if (signedArea1Row >= 0 && signedArea2Row >= 0 && signedArea3Row >= 0)
{
f32 barycentricB = signedArea3Row * invSignedAreaParallelogram;
f32 barycentricC = signedArea1Row * invSignedAreaParallelogram;
if (DTR_DEBUG)
{
const f32 EPSILON = 0.1f;
f32 debugSignedArea1 = ((b.x - a.x) * (bufferY - a.y)) - ((b.y - a.y) * (bufferX - a.x));
f32 debugSignedArea2 = ((c.x - b.x) * (bufferY - b.y)) - ((c.y - b.y) * (bufferX - b.x));
f32 debugSignedArea3 = ((a.x - c.x) * (bufferY - c.y)) - ((a.y - c.y) * (bufferX - c.x));
f32 deltaSignedArea1 = debugSignedArea1 - signedArea1Row;
f32 deltaSignedArea2 = debugSignedArea2 - signedArea2Row;
f32 deltaSignedArea3 = debugSignedArea3 - signedArea3Row;
DQN_ASSERT(deltaSignedArea1 < EPSILON && deltaSignedArea2 < EPSILON &&
deltaSignedArea3 < EPSILON)
f32 debugBarycentricA, debugBarycentricB, debugBarycentricC;
DebugBarycentricInternal(DqnV2_2i(bufferX, bufferY), a.xy, b.xy, c.xy,
&debugBarycentricA, &debugBarycentricB,
&debugBarycentricC);
f32 deltaBaryB = DQN_ABS(barycentricB - debugBarycentricB);
f32 deltaBaryC = DQN_ABS(barycentricC - debugBarycentricC);
DQN_ASSERT(deltaBaryB < EPSILON && deltaBaryC < EPSILON)
}
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
f32 pixelZValue = a.z + (barycentricB * (b.z - a.z)) + (barycentricC * (c.z - a.z));
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
const bool DEBUG_SAMPLE_TEXTURE = true;
DqnV2 uv = uv1 + ((uv2 - uv1) * barycentricB) + ((uv3 - uv1) * barycentricC);
const f32 EPSILON = 0.1f;
DQN_ASSERT(uv.x >= 0 && uv.x < 1.0f + EPSILON);
DQN_ASSERT(uv.y >= 0 && uv.y < 1.0f + EPSILON);
uv.x = DqnMath_Clampf(uv.x, 0.0f, 1.0f);
uv.y = DqnMath_Clampf(uv.y, 0.0f, 1.0f);
f32 texelXf = uv.x * texture->dim.w;
f32 texelYf = uv.y * texture->dim.h;
DQN_ASSERT(texelXf >= 0 && texelXf < texture->dim.w);
DQN_ASSERT(texelYf >= 0 && texelYf < texture->dim.h);
i32 texelX = (i32)texelXf;
i32 texelY = (i32)texelYf;
u32 texel1 = *(u32 *)(texturePtr + (texelX * texture->bytesPerPixel) +
(texelY * texturePitch));
DqnV4 color1;
color1.a = (f32)(texel1 >> 24);
color1.b = (f32)((texel1 >> 16) & 0xFF);
color1.g = (f32)((texel1 >> 8) & 0xFF);
color1.r = (f32)((texel1 >> 0) & 0xFF);
color1 *= DTRRENDER_INV_255;
color1 = DTRRender_SRGB1ToLinearSpaceV4(color1);
DqnV4 blend = color * color1;
SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear);
}
}
signedArea1Row += signedArea1DeltaX;
signedArea2Row += signedArea2DeltaX;
signedArea3Row += signedArea3DeltaX;
}
signedArea1 += signedArea1DeltaY;
signedArea2 += signedArea2DeltaY;
signedArea3 += signedArea3DeltaY;
}
DTRDebug_EndCycleCount(DTRDebugCycleCount_RenderTriangle_Rasterise);
////////////////////////////////////////////////////////////////////////////
// Debug
////////////////////////////////////////////////////////////////////////////
DTRDebug_CounterIncrement(DTRDebugCounter_RenderTriangle);
if (DTR_DEBUG_RENDER)
{
// Draw Bounding box
if (0)
{
DTRRender_Line(renderBuffer, DqnV2i_2i(min.x, min.y), DqnV2i_2i(min.x, max.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2i(min.x, max.y), DqnV2i_2i(max.x, max.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2i(max.x, max.y), DqnV2i_2i(max.x, min.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2i(max.x, min.y), DqnV2i_2i(min.x, min.y), color);
}
// Draw Triangle Coordinate Basis
if (0)
{
DqnV2 xAxis = DqnV2_2f(cosf(transform.rotation), sinf(transform.rotation)) * transform.scale.x;
DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x) * transform.scale.y;
DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1);
i32 axisLen = 50;
DTRRender_Line(renderBuffer, DqnV2i_V2(origin), DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(origin), DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor);
}
// Draw axis point
if (0)
{
DqnV4 green = DqnV4_4f(0, 1, 0, 1);
DqnV4 blue = DqnV4_4f(0, 0, 1, 1);
DqnV4 purple = DqnV4_4f(1, 0, 1, 1);
DTRRender_Rectangle(renderBuffer, p1.xy - DqnV2_1f(5), p1.xy + DqnV2_1f(5), green);
DTRRender_Rectangle(renderBuffer, p2.xy - DqnV2_1f(5), p2.xy + DqnV2_1f(5), blue);
DTRRender_Rectangle(renderBuffer, p3.xy - DqnV2_1f(5), p3.xy + DqnV2_1f(5), purple);
}
}
}
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV4 color, const DTRRenderTransform transform)
{
@ -670,30 +897,17 @@ void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2,
{
if (signedArea1Row >= 0 && signedArea2Row >= 0 && signedArea3Row >= 0)
{
#if 1
f32 barycentricA = signedArea2Row * invSignedAreaParallelogram;
f32 barycentricB = signedArea3Row * invSignedAreaParallelogram;
f32 barycentricC = signedArea1Row * invSignedAreaParallelogram;
if (DTR_DEBUG)
{
f32 barycentricSum = barycentricA + barycentricB + barycentricC;
DQN_ASSERT((1.0f - barycentricSum) < BARYCENTRIC_EPSILON);
}
f32 pixelZValue =
(a.z * barycentricA) + (b.z * barycentricB) + (c.z * barycentricC);
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
f32 pixelZValue = a.z + (barycentricB * (b.z - a.z)) + (barycentricC * (c.z - a.z));
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
}
#else
SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
#endif
}
signedArea1Row += signedArea1DeltaX;
@ -996,5 +1210,3 @@ void DTRRender_Clear(DTRRenderBuffer *const renderBuffer,
}
}
}

View File

@ -63,6 +63,7 @@ void DTRRender_Text (DTRRenderBuffer *const renderBuffer, const DTRFont font
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_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_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

@ -40,16 +40,20 @@ void Platform_Print(const char *const string)
OutputDebugString(string);
}
bool Platform_FileOpen(const char *const path, PlatformFile *const file,
const u32 permissionFlags)
bool Platform_FileOpen(const char *const path, PlatformFile *const file, const u32 permissionFlags,
const enum PlatformFileAction fileAction)
{
if (!path || !file) return false;
DQN_ASSERT((permissionFlags &
~(PlatformFilePermissionFlag_Write |
PlatformFilePermissionFlag_Read)) == 0);
DQN_ASSERT((fileAction &
~(PlatformFileAction_OpenOnly | PlatformFileAction_CreateIfNotExist |
PlatformFileAction_ClearIfExist)) == 0);
DqnFile dqnFile = {};
if (DqnFile_Open(path, &dqnFile, permissionFlags, DqnFileAction_OpenOnly))
if (DqnFile_Open(path, &dqnFile, permissionFlags, (enum DqnFileAction)fileAction))
{
*file = DqnFileToPlatformFileInternal(dqnFile);
return true;
@ -69,6 +73,17 @@ size_t Platform_FileRead(PlatformFile *const file, u8 *const buf,
return numBytesRead;
}
size_t Platform_FileWrite(PlatformFile *const file, u8 *const buf,
const size_t numBytesToWrite)
{
if (!file || !buf) return 0;
DqnFile dqnFile = PlatformFileToDqnFileInternal(*file);
size_t numBytesRead = DqnFile_Write(&dqnFile, buf, numBytesToWrite, 0);
return numBytesRead;
}
void Platform_FileClose(PlatformFile *const file)
{
if (!file) return;
@ -81,6 +96,7 @@ void Platform_FileClose(PlatformFile *const file)
// Win32 Layer
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
typedef struct Win32RenderBitmap
{
@ -314,6 +330,34 @@ FILE_SCOPE void Win32ProcessMessages(HWND window, PlatformInput *input)
}
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
{
bool isDown = (msg.message == WM_LBUTTONDOWN || msg.message == WM_RBUTTONDOWN);
if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONUP)
{
Win32UpdateKey(&input->mouse.leftBtn, isDown);
}
else if (msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP)
{
Win32UpdateKey(&input->mouse.rightBtn, isDown);
}
}
break;
case WM_MOUSEMOVE:
{
LONG height;
DqnWin32_GetClientDim(window, NULL, &height);
input->mouse.x = GET_X_LPARAM(msg.lParam);
input->mouse.y = height - GET_Y_LPARAM(msg.lParam);
}
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
@ -431,8 +475,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// when you blit to the screen blackness, the area that is being blitted to
// is slightly smaller than 800x600. Windows provides a function to help
// calculate the size you'd need by accounting for the window style.
const u32 MIN_WIDTH = 1024;
const u32 MIN_HEIGHT = 768;
const u32 MIN_WIDTH = 800;
const u32 MIN_HEIGHT = 800;
RECT rect = {};
rect.right = MIN_WIDTH;
rect.bottom = MIN_HEIGHT;
@ -508,6 +552,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PlatformAPI platformAPI = {};
platformAPI.FileOpen = Platform_FileOpen;
platformAPI.FileRead = Platform_FileRead;
platformAPI.FileWrite = Platform_FileWrite;
platformAPI.FileClose = Platform_FileClose;
platformAPI.Print = Platform_Print;
@ -590,6 +635,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
frameTimeInS = DqnTime_NowInS() - startFrameTimeInS;
f32 msPerFrame = 1000.0f * (f32)frameTimeInS;
f32 framesPerSecond = 1.0f / (f32)frameTimeInS;
////////////////////////////////////////////////////////////////////////
// Misc
@ -600,7 +646,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// Update title bar
char windowTitleBuffer[128] = {};
Dqn_sprintf(windowTitleBuffer, "drenderer - dev - %5.2f ms/f - mem %'dkb", msPerFrame,
Dqn_sprintf(windowTitleBuffer, "drenderer - dev - %5.2f ms/f - %5.2f fps - mem %'dkb", msPerFrame, framesPerSecond,
(u32)(memCounter.PagefileUsage / 1024.0f));
SetWindowTextA(mainWindow, windowTitleBuffer);
}

View File

@ -36,7 +36,7 @@ typedef int16_t i16;
typedef double f64;
typedef float f32;
#define DQN_F32_MIN FLT_MIN
#define DQN_F32_MIN -FLT_MAX
#define DQN_TERABYTE(val) (DQN_GIGABYTE(val) * 1024LL)
#define DQN_GIGABYTE(val) (DQN_MEGABYTE(val) * 1024LL)
@ -766,7 +766,6 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max);
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#define DQN_WIN32_ERROR_BOX(text, title) MessageBoxA(NULL, text, title, MB_OK);
// Out is a pointer to the buffer to receive the characters.
// outLen is the length/capacity of the out buffer

1092
src/external/tests/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,221 @@
#ifndef __GEOMETRY_H__
#define __GEOMETRY_H__
#include <cmath>
#include <vector>
#include <cassert>
#include <iostream>
template<size_t DimCols,size_t DimRows,typename T> class mat;
template <size_t DIM, typename T> struct vec {
vec() { for (size_t i=DIM; i--; data_[i] = T()); }
T& operator[](const size_t i) { assert(i<DIM); return data_[i]; }
const T& operator[](const size_t i) const { assert(i<DIM); return data_[i]; }
private:
T data_[DIM];
};
/////////////////////////////////////////////////////////////////////////////////
template <typename T> struct vec<2,T> {
vec() : x(T()), y(T()) {}
vec(T X, T Y) : x(X), y(Y) {}
template <class U> vec<2,T>(const vec<2,U> &v);
T& operator[](const size_t i) { assert(i<2); return i<=0 ? x : y; }
const T& operator[](const size_t i) const { assert(i<2); return i<=0 ? x : y; }
T x,y;
};
/////////////////////////////////////////////////////////////////////////////////
template <typename T> struct vec<3,T> {
vec() : x(T()), y(T()), z(T()) {}
vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
template <class U> vec<3,T>(const vec<3,U> &v);
T& operator[](const size_t i) { assert(i<3); return i<=0 ? x : (1==i ? y : z); }
const T& operator[](const size_t i) const { assert(i<3); return i<=0 ? x : (1==i ? y : z); }
float norm() { return std::sqrt(x*x+y*y+z*z); }
vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; }
T x,y,z;
};
/////////////////////////////////////////////////////////////////////////////////
template<size_t DIM,typename T> T operator*(const vec<DIM,T>& lhs, const vec<DIM,T>& rhs) {
T ret = T();
for (size_t i=DIM; i--; ret+=lhs[i]*rhs[i]);
return ret;
}
template<size_t DIM,typename T>vec<DIM,T> operator+(vec<DIM,T> lhs, const vec<DIM,T>& rhs) {
for (size_t i=DIM; i--; lhs[i]+=rhs[i]);
return lhs;
}
template<size_t DIM,typename T>vec<DIM,T> operator-(vec<DIM,T> lhs, const vec<DIM,T>& rhs) {
for (size_t i=DIM; i--; lhs[i]-=rhs[i]);
return lhs;
}
template<size_t DIM,typename T,typename U> vec<DIM,T> operator*(vec<DIM,T> lhs, const U& rhs) {
for (size_t i=DIM; i--; lhs[i]*=rhs);
return lhs;
}
template<size_t DIM,typename T,typename U> vec<DIM,T> operator/(vec<DIM,T> lhs, const U& rhs) {
for (size_t i=DIM; i--; lhs[i]/=rhs);
return lhs;
}
template<size_t LEN,size_t DIM,typename T> vec<LEN,T> embed(const vec<DIM,T> &v, T fill=1) {
vec<LEN,T> ret;
for (size_t i=LEN; i--; ret[i]=(i<DIM?v[i]:fill));
return ret;
}
template<size_t LEN,size_t DIM, typename T> vec<LEN,T> proj(const vec<DIM,T> &v) {
vec<LEN,T> ret;
for (size_t i=LEN; i--; ret[i]=v[i]);
return ret;
}
template <typename T> vec<3,T> cross(vec<3,T> v1, vec<3,T> v2) {
return vec<3,T>(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
}
template <size_t DIM, typename T> std::ostream& operator<<(std::ostream& out, vec<DIM,T>& v) {
for(unsigned int i=0; i<DIM; i++) {
out << v[i] << " " ;
}
return out ;
}
/////////////////////////////////////////////////////////////////////////////////
template<size_t DIM,typename T> struct dt {
static T det(const mat<DIM,DIM,T>& src) {
T ret=0;
for (size_t i=DIM; i--; ret += src[0][i]*src.cofactor(0,i));
return ret;
}
};
template<typename T> struct dt<1,T> {
static T det(const mat<1,1,T>& src) {
return src[0][0];
}
};
/////////////////////////////////////////////////////////////////////////////////
template<size_t DimRows,size_t DimCols,typename T> class mat {
vec<DimCols,T> rows[DimRows];
public:
mat() {}
vec<DimCols,T>& operator[] (const size_t idx) {
assert(idx<DimRows);
return rows[idx];
}
const vec<DimCols,T>& operator[] (const size_t idx) const {
assert(idx<DimRows);
return rows[idx];
}
vec<DimRows,T> col(const size_t idx) const {
assert(idx<DimCols);
vec<DimRows,T> ret;
for (size_t i=DimRows; i--; ret[i]=rows[i][idx]);
return ret;
}
void set_col(size_t idx, vec<DimRows,T> v) {
assert(idx<DimCols);
for (size_t i=DimRows; i--; rows[i][idx]=v[i]);
}
static mat<DimRows,DimCols,T> identity() {
mat<DimRows,DimCols,T> ret;
for (size_t i=DimRows; i--; )
for (size_t j=DimCols;j--; ret[i][j]=(i==j));
return ret;
}
T det() const {
return dt<DimCols,T>::det(*this);
}
mat<DimRows-1,DimCols-1,T> get_minor(size_t row, size_t col) const {
mat<DimRows-1,DimCols-1,T> ret;
for (size_t i=DimRows-1; i--; )
for (size_t j=DimCols-1;j--; ret[i][j]=rows[i<row?i:i+1][j<col?j:j+1]);
return ret;
}
T cofactor(size_t row, size_t col) const {
return get_minor(row,col).det()*((row+col)%2 ? -1 : 1);
}
mat<DimRows,DimCols,T> adjugate() const {
mat<DimRows,DimCols,T> ret;
for (size_t i=DimRows; i--; )
for (size_t j=DimCols; j--; ret[i][j]=cofactor(i,j));
return ret;
}
mat<DimRows,DimCols,T> invert_transpose() {
mat<DimRows,DimCols,T> ret = adjugate();
T tmp = ret[0]*rows[0];
return ret/tmp;
}
mat<DimRows,DimCols,T> invert() {
return invert_transpose().transpose();
}
mat<DimCols,DimRows,T> transpose() {
mat<DimCols,DimRows,T> ret;
for (size_t i=DimCols; i--; ret[i]=this->col(i));
return ret;
}
};
/////////////////////////////////////////////////////////////////////////////////
template<size_t DimRows,size_t DimCols,typename T> vec<DimRows,T> operator*(const mat<DimRows,DimCols,T>& lhs, const vec<DimCols,T>& rhs) {
vec<DimRows,T> ret;
for (size_t i=DimRows; i--; ret[i]=lhs[i]*rhs);
return ret;
}
template<size_t R1,size_t C1,size_t C2,typename T>mat<R1,C2,T> operator*(const mat<R1,C1,T>& lhs, const mat<C1,C2,T>& rhs) {
mat<R1,C2,T> result;
for (size_t i=R1; i--; )
for (size_t j=C2; j--; result[i][j]=lhs[i]*rhs.col(j));
return result;
}
template<size_t DimRows,size_t DimCols,typename T>mat<DimCols,DimRows,T> operator/(mat<DimRows,DimCols,T> lhs, const T& rhs) {
for (size_t i=DimRows; i--; lhs[i]=lhs[i]/rhs);
return lhs;
}
template <size_t DimRows,size_t DimCols,class T> std::ostream& operator<<(std::ostream& out, mat<DimRows,DimCols,T>& m) {
for (size_t i=0; i<DimRows; i++) out << m[i] << std::endl;
return out;
}
/////////////////////////////////////////////////////////////////////////////////
typedef vec<2, float> Vec2f;
typedef vec<2, int> Vec2i;
typedef vec<3, float> Vec3f;
typedef vec<3, int> Vec3i;
typedef vec<4, float> Vec4f;
typedef mat<4,4,float> Matrix;
#endif //__GEOMETRY_H__

View File

@ -0,0 +1,54 @@
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include "model.h"
Model::Model(const char *filename) : verts_(), faces_() {
std::ifstream in;
in.open (filename, std::ifstream::in);
if (in.fail()) return;
std::string line;
while (!in.eof()) {
std::getline(in, line);
std::istringstream iss(line.c_str());
char trash;
if (!line.compare(0, 2, "v ")) {
iss >> trash;
Vec3f v;
for (int i=0;i<3;i++) iss >> v[i];
verts_.push_back(v);
} else if (!line.compare(0, 2, "f ")) {
std::vector<int> f;
int itrash, idx;
iss >> trash;
while (iss >> idx >> trash >> itrash >> trash >> itrash) {
idx--; // in wavefront obj all indices start at 1, not zero
f.push_back(idx);
}
faces_.push_back(f);
}
}
std::cerr << "# v# " << verts_.size() << " f# " << faces_.size() << std::endl;
}
Model::~Model() {
}
int Model::nverts() {
return (int)verts_.size();
}
int Model::nfaces() {
return (int)faces_.size();
}
std::vector<int> Model::face(int idx) {
return faces_[idx];
}
Vec3f Model::vert(int i) {
return verts_[i];
}

20
src/external/tests/tinyrenderer/model.h vendored Normal file
View File

@ -0,0 +1,20 @@
#ifndef __MODEL_H__
#define __MODEL_H__
#include <vector>
#include "geometry.h"
class Model {
private:
std::vector<Vec3f> verts_;
std::vector<std::vector<int> > faces_;
public:
Model(const char *filename);
~Model();
int nverts();
int nfaces();
Vec3f vert(int i);
std::vector<int> face(int idx);
};
#endif //__MODEL_H__