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> #include <math.h>
typedef struct WavefrontModelFace
{
DqnArray<i32> vertexArray;
DqnArray<i32> textureArray;
DqnArray<i32> normalArray;
} WavefrontModelFace;
FILE_SCOPE inline WavefrontModelFace ObjWavefrontModelFaceInit(i32 capacity = 3) FILE_SCOPE inline WavefrontModelFace ObjWavefrontModelFaceInit(i32 capacity = 3)
{ {
WavefrontModelFace result = {}; 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.textureArray, capacity));
DQN_ASSERT(DqnArray_Init(&result.normalArray, capacity)); DQN_ASSERT(DqnArray_Init(&result.normalArray, capacity));
return result; 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, FILE_SCOPE bool ObjWaveFrontInit(WavefrontObj *const obj, const i32 vertexInitCapacity = 1000,
const i32 faceInitCapacity = 200) 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); 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)); DQN_ASSERT(vIndex < DQN_ARRAY_COUNT(v4.e));
while (scan && (*scan == ' ' || *scan == '\n')) scan++; while (scan && (*scan == ' ' || *scan == '\n')) scan++;
@ -1480,7 +1453,6 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
} }
DTR_DEBUG_TIMED_FUNCTION(); DTR_DEBUG_TIMED_FUNCTION();
LOCAL_PERSIST WavefrontObj waveObj = {};
if (!memory->isInit) if (!memory->isInit)
{ {
TestStrToF32Converter(); TestStrToF32Converter();
@ -1504,80 +1476,72 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->permMemStack); DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->permMemStack);
BitmapLoad(input->api, &test, "byte_read_check.bmp", BitmapLoad(input->api, &test, "byte_read_check.bmp",
&memory->transMemStack); &memory->transMemStack);
int x = 5;
DqnMemStack_EndTempRegion(tmp); DqnMemStack_EndTempRegion(tmp);
#if 0 DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &state->obj));
DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &waveObj));
#endif
} }
DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0)); DTRRender_Clear(renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
#if 1 const DqnV3 LIGHT = DqnV3_3i(0, 0, -1);
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1); const f32 MODEL_SCALE = DQN_MIN(renderBuffer->width, renderBuffer->height) * 0.5f;
for (i32 i = 0; i < waveObj.model.faces.count; i++) 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); DQN_ASSERT(face.vertexArray.count == 3);
#if 0
i32 vertAIndex = face.vertexArray.data[0]; i32 vertAIndex = face.vertexArray.data[0];
i32 vertBIndex = face.vertexArray.data[1]; i32 vertBIndex = face.vertexArray.data[1];
i32 vertCIndex = face.vertexArray.data[2]; i32 vertCIndex = face.vertexArray.data[2];
DqnV4 vertA = waveObj.geometryArray.data[vertAIndex]; DqnV4 vertA = waveObj->geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj.geometryArray.data[vertBIndex]; DqnV4 vertB = waveObj->geometryArray.data[vertBIndex];
DqnV4 vertC = waveObj.geometryArray.data[vertCIndex]; DqnV4 vertC = waveObj->geometryArray.data[vertCIndex];
vertA.x *= (renderBuffer->width * 0.5f); DqnV4 vertAB = vertB - vertA;
vertA.y *= (renderBuffer->height * 0.5f); DqnV4 vertAC = vertC - vertA;
DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz);
vertB.x *= (renderBuffer->width * 0.5f); f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT);
vertB.y *= (renderBuffer->height * 0.5f); if (intensity > 0)
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]; DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
i32 vertBIndex = face.vertexArray.data[(j + 1) % NUM_VERTEXES]; modelCol.rgb *= intensity;
DqnV4 vertA = waveObj.geometryArray.data[vertAIndex]; DqnV2 screenVertA = (vertA.xy * MODEL_SCALE) + modelP;
DqnV4 vertB = waveObj.geometryArray.data[vertBIndex]; 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; // TODO(doyle): Why do we need rounding here? Maybe it's because
vertA.y = (vertA.y * (renderBuffer->height * 0.5f)) + renderBuffer->height * 0.5f; // 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; DTRRender_Triangle(renderBuffer, screenVertA, screenVertB, screenVertC, modelCol);
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 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 #if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1); DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
DqnV2i bufferMidP = DqnV2i bufferMidP =
DqnV2i_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f); DqnV2i_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f);
i32 boundsOffset = 100; 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 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)}; DqnV2 t2[3] = {DqnV2_2i(180, 150), DqnV2_2i(120, 160), DqnV2_2i(130, 180)};
LOCAL_PERSIST DqnV2 t3[3] = { 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, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(renderBuffer, t2[0], t2[1], t2[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); DqnV4 colorRedHalfA = DqnV4_4f(1, 0, 0, 0.1f);
LOCAL_PERSIST f32 rotation = 0; LOCAL_PERSIST f32 rotation = 0;
rotation += input->deltaForFrame * 0.25f; rotation += input->deltaForFrame * 0.25f;
#if 1
DTRRenderTransform defaultTransform = DTRRender_DefaultTransform(); DTRRenderTransform defaultTransform = DTRRender_DefaultTransform();
defaultTransform.rotation = rotation + 45; 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), DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), DqnV4_4f(0, 1.0f, 1.0f, 1.0f),
defaultTransform); defaultTransform);
#endif
// Rotating triangle // Rotating triangle
{ {
@ -1624,8 +1592,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DTRRender_Bitmap(renderBuffer, &state->bitmap, bitmapP, transform, color); DTRRender_Bitmap(renderBuffer, &state->bitmap, bitmapP, transform, color);
#else #else
CompAssignment(renderBuffer, input, memory); // CompAssignment(renderBuffer, input, memory);
#endif
#endif #endif
DTRDebug_Update(state, renderBuffer, input, memory); 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 PlatformInput *const input,
struct PlatformMemory *const memory); 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 typedef struct DTRFont
{ {
u8 *bitmap; u8 *bitmap;
@ -27,7 +53,8 @@ typedef struct DTRBitmap
typedef struct DTRState typedef struct DTRState
{ {
DTRFont font; DTRFont font;
DTRBitmap bitmap; DTRBitmap bitmap;
WavefrontObj obj;
} DTRState; } DTRState;
#endif #endif

View File

@ -3,11 +3,11 @@
#include "dqn.h" #include "dqn.h"
#define DTR_DEBUG 1 #define DTR_DEBUG 1
#ifdef DTR_DEBUG #if DTR_DEBUG
#define DTR_DEBUG_RENDER 0 #define DTR_DEBUG_RENDER 0
#define DTR_DEBUG_PROFILING 1 #define DTR_DEBUG_PROFILING 0
#ifdef DTR_DEBUG_PROFILING #if DTR_DEBUG_PROFILING
#define BUILD_WITH_EASY_PROFILER 1 #define BUILD_WITH_EASY_PROFILER 1
#include "external/easy/profiler.h" #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) = (bx - ax)(1) = (bx - ax)
Then we can see that when we progress along x, we only need to change by 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 // Barycentric Coordinates
@ -632,16 +632,16 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
const DqnV2 b = p2; const DqnV2 b = p2;
const DqnV2 c = p3; const DqnV2 c = p3;
DqnV2i scanP = DqnV2i_2i(min.x, min.y); DqnV2i startP = min;
f32 signedArea1 = ((b.x - a.x) * (scanP.y - a.y)) - ((b.y - a.y) * (scanP.x - a.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 signedArea1DeltaX = a.y - b.y;
f32 signedArea1DeltaY = b.x - a.x; 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 signedArea2DeltaX = b.y - c.y;
f32 signedArea2DeltaY = c.x - b.x; 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 signedArea3DeltaX = c.y - a.y;
f32 signedArea3DeltaY = a.x - c.x; f32 signedArea3DeltaY = a.x - c.x;
@ -650,18 +650,19 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Scan and Render // 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 signedArea1Row = signedArea1;
f32 signedArea2Row = signedArea2; f32 signedArea2Row = signedArea2;
f32 signedArea3Row = signedArea3; 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) 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; signedArea1Row += signedArea1DeltaX;

View File

@ -61,7 +61,8 @@ REM Compile
REM //////////////////////////////////////////////////////////////////////////// REM ////////////////////////////////////////////////////////////////////////////
del *.pdb >NUL 2>NUL del *.pdb >NUL 2>NUL
cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags% 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 popd
set LastError=%ERRORLEVEL% set LastError=%ERRORLEVEL%

View File

@ -504,6 +504,8 @@ DQN_FILE_SCOPE inline bool operator==(DqnV2i a, DqnV2i b) { return DqnV
typedef union DqnV3 typedef union DqnV3
{ {
struct { f32 x, y, z; }; struct { f32 x, y, z; };
DqnV2 xy;
struct { f32 r, g, b; }; struct { f32 r, g, b; };
f32 e[3]; f32 e[3];
} DqnV3; } 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 bool DqnV3_Equals (DqnV3 a, DqnV3 b);
DQN_FILE_SCOPE DqnV3 DqnV3_Cross (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_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_Add (a, b); }
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, DqnV3 b) { return DqnV3_Hadamard(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 f32 DqnV4_Dot (DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE bool DqnV4_Equals (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_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_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_Add (a, DqnV4_1f(b)); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (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, i32 b) { return DqnV4_Scalei (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, DqnV4 b) { return (a = DqnV4_Hadamard(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, f32 b) { return (a = DqnV4_Scalef (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, i32 b) { return (a = DqnV4_Scalei (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, DqnV4 b) { return (a = DqnV4_Sub (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_Add (a, b)); } DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (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 (a = DqnV4_Add (a, b)); }
DQN_FILE_SCOPE inline bool operator==(DqnV4 a, DqnV4 b) { return DqnV4_Equals (a, b); }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// 4D Matrix Mat4 // 4D Matrix Mat4
@ -2125,6 +2130,15 @@ DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b)
return result; 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) DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z)
{ {
DqnV3i result = {x, y, z}; DqnV3i result = {x, y, z};