Start parser for Wavefront 3D Object file format
This commit is contained in:
parent
a25b50c501
commit
ce539d4903
@ -11,6 +11,153 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
typedef struct ModelFace
|
||||||
|
{
|
||||||
|
i32 numVertex;
|
||||||
|
i32 *vertexIndex;
|
||||||
|
i32 *textureIndex;
|
||||||
|
i32 *normalIndex;
|
||||||
|
} ModelFace;
|
||||||
|
|
||||||
|
FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const memory,
|
||||||
|
const char *const path)
|
||||||
|
{
|
||||||
|
if (!memory || ! path) return false;
|
||||||
|
|
||||||
|
PlatformFile file = {};
|
||||||
|
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
|
||||||
|
return false; // TODO(doyle): Logging
|
||||||
|
|
||||||
|
DqnTempBuffer tmpMemRegion = DqnMemBuffer_BeginTempRegion(&memory->transientBuffer);
|
||||||
|
u8 *rawBytes = (u8 *)DqnMemBuffer_Allocate(&memory->transientBuffer, file.size);
|
||||||
|
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
|
||||||
|
size_t fileSize = file.size;
|
||||||
|
api.FileClose(&file);
|
||||||
|
if (bytesRead != file.size)
|
||||||
|
{
|
||||||
|
// TODO(doyle): Logging
|
||||||
|
DqnMemBuffer_EndTempRegion(tmpMemRegion);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
DqnV3 *vertex;
|
||||||
|
ModelFace *face;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum WavefrontVertexType {
|
||||||
|
WavefrontVertexType_Invalid,
|
||||||
|
WavefrontVertexType_Geometric,
|
||||||
|
WavefrontVertexType_Texture,
|
||||||
|
WavefrontVertexType_Normal,
|
||||||
|
};
|
||||||
|
|
||||||
|
DqnArray<DqnV4> vGeometricArray = {};
|
||||||
|
DqnArray<DqnV3> vTextureArray = {};
|
||||||
|
DqnArray<DqnV3> vNormalArray = {};
|
||||||
|
DQN_ASSERT(DqnArray_Init(&vGeometricArray, 1000) && DqnArray_Init(&vTextureArray, 1000) &&
|
||||||
|
DqnArray_Init(&vNormalArray, 1000));
|
||||||
|
|
||||||
|
for (char *scan = (char *)rawBytes; scan;)
|
||||||
|
{
|
||||||
|
switch (*scan)
|
||||||
|
{
|
||||||
|
// Vertex Format: v[ |t|n|p] f32 f32 f32 [f32]
|
||||||
|
case 'v':
|
||||||
|
{
|
||||||
|
scan++;
|
||||||
|
DQN_ASSERT(scan);
|
||||||
|
|
||||||
|
enum WavefrontVertexType type = WavefrontVertexType_Invalid;
|
||||||
|
|
||||||
|
if (*scan == ' ') type = WavefrontVertexType_Geometric;
|
||||||
|
else if (*scan == 't' || *scan == 'n')
|
||||||
|
{
|
||||||
|
scan++;
|
||||||
|
if (*scan == 't') type = WavefrontVertexType_Texture;
|
||||||
|
else type = WavefrontVertexType_Normal;
|
||||||
|
}
|
||||||
|
else DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
|
|
||||||
|
i32 vIndex = 0;
|
||||||
|
DqnV4 v4 = {0, 0, 0, 1.0f};
|
||||||
|
|
||||||
|
// Progress to first non space character after vertex identifier
|
||||||
|
for (; scan && *scan == ' '; scan++)
|
||||||
|
if (!scan) DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
char *f32StartPtr = scan;
|
||||||
|
for (; *scan != ' ' && *scan != '\n';)
|
||||||
|
{
|
||||||
|
DQN_ASSERT(DqnChar_IsDigit(*scan) || (*scan == '.') || (*scan == '-') ||
|
||||||
|
*scan == 'e');
|
||||||
|
scan++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 f32Len = (i32)((size_t)scan - (size_t)f32StartPtr);
|
||||||
|
v4.e[vIndex++] = Dqn_StrToF32(f32StartPtr, f32Len);
|
||||||
|
DQN_ASSERT(vIndex < DQN_ARRAY_COUNT(v4.e));
|
||||||
|
|
||||||
|
while (scan && (*scan == ' ' || *scan == '\n')) scan++;
|
||||||
|
|
||||||
|
if (!scan) break;
|
||||||
|
if (!(DqnChar_IsDigit(*scan) || *scan == '-')) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_ASSERT(vIndex == 3 || vIndex == 4);
|
||||||
|
if (type == WavefrontVertexType_Geometric)
|
||||||
|
{
|
||||||
|
DqnArray_Push(&vGeometricArray, v4);
|
||||||
|
}
|
||||||
|
else if (type == WavefrontVertexType_Texture)
|
||||||
|
{
|
||||||
|
DqnArray_Push(&vTextureArray, v4.xyz);
|
||||||
|
}
|
||||||
|
else if (type == WavefrontVertexType_Normal)
|
||||||
|
{
|
||||||
|
DqnArray_Push(&vNormalArray, v4.xyz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Face Format: i32/i32/i32 i32/i32/i32 i32/i32/i32
|
||||||
|
case 'f':
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
case '#':
|
||||||
|
{
|
||||||
|
// Skip comment line until new line
|
||||||
|
while (scan && *scan != '\n')
|
||||||
|
scan++;
|
||||||
|
|
||||||
|
// Skip new lines and any leading white spaces
|
||||||
|
while (scan && (*scan == '\n' || *scan == ' '))
|
||||||
|
scan++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DqnMemBuffer_EndTempRegion(tmpMemRegion);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
|
FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
|
||||||
PlatformMemory *const memory,
|
PlatformMemory *const memory,
|
||||||
DTRFont *const font, const char *const path,
|
DTRFont *const font, const char *const path,
|
||||||
@ -1031,6 +1178,78 @@ void CompAssignment(PlatformRenderBuffer *const renderBuffer, PlatformInput *con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE void TestStrToF32Converter()
|
||||||
|
{
|
||||||
|
const f32 EPSILON = 0.001f;
|
||||||
|
const char a[] = "-0.66248";
|
||||||
|
f32 vA = Dqn_StrToF32(a, DQN_ARRAY_COUNT(a));
|
||||||
|
DQN_ASSERT(DQN_ABS(vA) - DQN_ABS(-0.66248f) < EPSILON);
|
||||||
|
|
||||||
|
const char b[] = "-0.632053";
|
||||||
|
f32 vB = Dqn_StrToF32(b, DQN_ARRAY_COUNT(b));
|
||||||
|
DQN_ASSERT(DQN_ABS(vB) - DQN_ABS(-0.632053f) < EPSILON);
|
||||||
|
|
||||||
|
const char c[] = "-0.244271";
|
||||||
|
f32 vC = Dqn_StrToF32(c, DQN_ARRAY_COUNT(c));
|
||||||
|
DQN_ASSERT(DQN_ABS(vC) - DQN_ABS(-0.244271f) < EPSILON);
|
||||||
|
|
||||||
|
const char d[] = "-0.511812";
|
||||||
|
f32 vD = Dqn_StrToF32(d, DQN_ARRAY_COUNT(d));
|
||||||
|
DQN_ASSERT(DQN_ABS(vD) - DQN_ABS(-0.511812f) < EPSILON);
|
||||||
|
|
||||||
|
const char e[] = "-0.845392";
|
||||||
|
f32 vE = Dqn_StrToF32(e, DQN_ARRAY_COUNT(e));
|
||||||
|
DQN_ASSERT(DQN_ABS(vE) - DQN_ABS(-0.845392f) < EPSILON);
|
||||||
|
|
||||||
|
const char f[] = "0.127809";
|
||||||
|
f32 vF = Dqn_StrToF32(f, DQN_ARRAY_COUNT(f));
|
||||||
|
DQN_ASSERT(DQN_ABS(vF) - DQN_ABS(-0.127809f) < EPSILON);
|
||||||
|
|
||||||
|
const char g[] = "0.532";
|
||||||
|
f32 vG = Dqn_StrToF32(g, DQN_ARRAY_COUNT(g));
|
||||||
|
DQN_ASSERT(DQN_ABS(vG) - DQN_ABS(-0.532f) < EPSILON);
|
||||||
|
|
||||||
|
const char h[] = "0.923";
|
||||||
|
f32 vH = Dqn_StrToF32(h, DQN_ARRAY_COUNT(h));
|
||||||
|
DQN_ASSERT(DQN_ABS(vH) - DQN_ABS(-0.923f) < EPSILON);
|
||||||
|
|
||||||
|
const char i[] = "0.000";
|
||||||
|
f32 vI = Dqn_StrToF32(i, DQN_ARRAY_COUNT(i));
|
||||||
|
DQN_ASSERT(DQN_ABS(vI) - DQN_ABS(-0.000f) < EPSILON);
|
||||||
|
|
||||||
|
const char j[] = "0.000283538";
|
||||||
|
f32 vJ = Dqn_StrToF32(j, DQN_ARRAY_COUNT(j));
|
||||||
|
DQN_ASSERT(DQN_ABS(vJ) - DQN_ABS(-0.000283538f) < EPSILON);
|
||||||
|
|
||||||
|
const char k[] = "-1.25";
|
||||||
|
f32 vK = Dqn_StrToF32(k, DQN_ARRAY_COUNT(k));
|
||||||
|
DQN_ASSERT(DQN_ABS(vK) - DQN_ABS(-1.25f) < EPSILON);
|
||||||
|
|
||||||
|
const char l[] = "0.286843";
|
||||||
|
f32 vL = Dqn_StrToF32(l, DQN_ARRAY_COUNT(l));
|
||||||
|
DQN_ASSERT(DQN_ABS(vL) - DQN_ABS(-0.286843f) < EPSILON);
|
||||||
|
|
||||||
|
const char m[] = "-0.406";
|
||||||
|
f32 vM = Dqn_StrToF32(m, DQN_ARRAY_COUNT(m));
|
||||||
|
DQN_ASSERT(DQN_ABS(vM) - DQN_ABS(-0.406f) < EPSILON);
|
||||||
|
|
||||||
|
const char n[] = "-0.892";
|
||||||
|
f32 vN = Dqn_StrToF32(n, DQN_ARRAY_COUNT(n));
|
||||||
|
DQN_ASSERT(DQN_ABS(vN) - DQN_ABS(-0.892f) < EPSILON);
|
||||||
|
|
||||||
|
const char o[] = "0.201";
|
||||||
|
f32 vO = Dqn_StrToF32(o, DQN_ARRAY_COUNT(o));
|
||||||
|
DQN_ASSERT(DQN_ABS(vO) - DQN_ABS(-0.201f) < EPSILON);
|
||||||
|
|
||||||
|
const char p[] = "1.25";
|
||||||
|
f32 vP = Dqn_StrToF32(p, DQN_ARRAY_COUNT(p));
|
||||||
|
DQN_ASSERT(DQN_ABS(vP) - DQN_ABS(1.25f) < EPSILON);
|
||||||
|
|
||||||
|
const char q[] = "9.64635e-05";
|
||||||
|
f32 vQ = Dqn_StrToF32(q, DQN_ARRAY_COUNT(q));
|
||||||
|
DQN_ASSERT(DQN_ABS(vQ) - DQN_ABS(9.64635e-05) < EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
|
extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
|
||||||
PlatformInput *const input,
|
PlatformInput *const input,
|
||||||
PlatformMemory *const memory)
|
PlatformMemory *const memory)
|
||||||
@ -1045,6 +1264,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
|
|||||||
DTR_DEBUG_TIMED_FUNCTION();
|
DTR_DEBUG_TIMED_FUNCTION();
|
||||||
if (!memory->isInit)
|
if (!memory->isInit)
|
||||||
{
|
{
|
||||||
|
TestStrToF32Converter();
|
||||||
DTR_DEBUG_TIMED_BLOCK("DTR_Update Memory Initialisation");
|
DTR_DEBUG_TIMED_BLOCK("DTR_Update Memory Initialisation");
|
||||||
// NOTE(doyle): Do premultiply ourselves
|
// NOTE(doyle): Do premultiply ourselves
|
||||||
stbi_set_unpremultiply_on_load(true);
|
stbi_set_unpremultiply_on_load(true);
|
||||||
@ -1067,8 +1287,9 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
|
|||||||
&memory->transientBuffer);
|
&memory->transientBuffer);
|
||||||
int x = 5;
|
int x = 5;
|
||||||
DqnMemBuffer_EndTempRegion(tmp);
|
DqnMemBuffer_EndTempRegion(tmp);
|
||||||
}
|
|
||||||
|
|
||||||
|
ObjWavefrontLoad(input->api, memory, "african_head.obj");
|
||||||
|
}
|
||||||
DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0));
|
DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0));
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
126
src/dqn.h
126
src/dqn.h
@ -28,9 +28,9 @@ typedef uint32_t u32;
|
|||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
|
|
||||||
typedef int32_t i64;
|
typedef int64_t i64;
|
||||||
typedef int32_t i32;
|
typedef int32_t i32;
|
||||||
typedef int64_t i16;
|
typedef int16_t i16;
|
||||||
|
|
||||||
typedef double f64;
|
typedef double f64;
|
||||||
typedef float f32;
|
typedef float f32;
|
||||||
@ -535,10 +535,13 @@ DQN_FILE_SCOPE inline bool operator==(DqnV3 a, DqnV3 b) { return DqnV3_E
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Vec4
|
// Vec4
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
typedef union DqnV4
|
typedef union DqnV4 {
|
||||||
{
|
|
||||||
struct { f32 x, y, z, w; };
|
struct { f32 x, y, z, w; };
|
||||||
|
DqnV3 xyz;
|
||||||
|
|
||||||
struct { f32 r, g, b, a; };
|
struct { f32 r, g, b, a; };
|
||||||
|
DqnV3 rgb;
|
||||||
|
|
||||||
f32 e[4];
|
f32 e[4];
|
||||||
DqnV2 v2[2];
|
DqnV2 v2[2];
|
||||||
} DqnV4;
|
} DqnV4;
|
||||||
@ -626,12 +629,16 @@ DQN_FILE_SCOPE i32 Dqn_StrFindFirstOccurence(const char *const src, const i32 s
|
|||||||
DQN_FILE_SCOPE bool Dqn_StrHasSubstring (const char *const src, const i32 srcLen, const char *const find, const i32 findLen);
|
DQN_FILE_SCOPE bool Dqn_StrHasSubstring (const char *const src, const i32 srcLen, const char *const find, const i32 findLen);
|
||||||
|
|
||||||
#define DQN_32BIT_NUM_MAX_STR_SIZE 11
|
#define DQN_32BIT_NUM_MAX_STR_SIZE 11
|
||||||
#define DQN_64BIT_NUM_MAX_STR_SIZE 20
|
#define DQN_64BIT_NUM_MAX_STR_SIZE 21
|
||||||
// Return the len of the derived string. If buf is NULL and or bufSize is 0 the
|
// Return the len of the derived string. If buf is NULL and or bufSize is 0 the
|
||||||
// function returns the required string length for the integer.
|
// function returns the required string length for the integer.
|
||||||
DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *const buf, const i32 bufSize);
|
DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *const buf, const i32 bufSize);
|
||||||
|
|
||||||
DQN_FILE_SCOPE i64 Dqn_StrToI64(const char *const buf, const i32 bufSize);
|
DQN_FILE_SCOPE i64 Dqn_StrToI64(const char *const buf, const i32 bufSize);
|
||||||
|
|
||||||
|
// WARNING: Not robust, precision errors and whatnot but good enough!
|
||||||
|
DQN_FILE_SCOPE f32 Dqn_StrToF32(const char *const buf, const i32 bufSize);
|
||||||
|
|
||||||
// Both return the number of bytes read, return 0 if invalid codepoint or UTF8
|
// Both return the number of bytes read, return 0 if invalid codepoint or UTF8
|
||||||
DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character);
|
DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character);
|
||||||
DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character);
|
DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character);
|
||||||
@ -2535,7 +2542,6 @@ DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *const buf, const i32 bufSize)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(doyle): Max 32bit integer (+-)2147483647
|
|
||||||
i32 charIndex = 0;
|
i32 charIndex = 0;
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if (value < 0) negative = true;
|
if (value < 0) negative = true;
|
||||||
@ -2546,12 +2552,30 @@ DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *const buf, const i32 bufSize)
|
|||||||
charIndex++;
|
charIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 val = DQN_ABS(value);
|
bool lastDigitDecremented = false;
|
||||||
|
i64 val = DQN_ABS(value);
|
||||||
|
if (val < 0)
|
||||||
|
{
|
||||||
|
// TODO(doyle): This will occur if we are checking the smallest number
|
||||||
|
// possible in i64 since the range of negative numbers is one more than
|
||||||
|
// it is for positives, so ABS will fail.
|
||||||
|
lastDigitDecremented = true;
|
||||||
|
val = DQN_ABS(val - 1);
|
||||||
|
DQN_ASSERT(val >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (validBuffer)
|
if (validBuffer)
|
||||||
{
|
{
|
||||||
|
if (lastDigitDecremented)
|
||||||
|
{
|
||||||
|
i64 rem = (val % 10) + 1;
|
||||||
|
buf[charIndex++] = (u8)rem + '0';
|
||||||
|
val /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
while (val != 0 && charIndex < bufSize)
|
while (val != 0 && charIndex < bufSize)
|
||||||
{
|
{
|
||||||
i32 rem = val % 10;
|
i64 rem = val % 10;
|
||||||
buf[charIndex++] = (u8)rem + '0';
|
buf[charIndex++] = (u8)rem + '0';
|
||||||
val /= 10;
|
val /= 10;
|
||||||
}
|
}
|
||||||
@ -2616,6 +2640,92 @@ DQN_FILE_SCOPE i64 Dqn_StrToI64(const char *const buf, const i32 bufSize)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE f32 Dqn_StrToF32(const char *const buf, const i32 bufSize)
|
||||||
|
{
|
||||||
|
if (!buf || bufSize == 0) return 0;
|
||||||
|
|
||||||
|
i32 index = 0;
|
||||||
|
bool isNegative = false;
|
||||||
|
if (buf[index] == '-')
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
isNegative = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPastDecimal = false;
|
||||||
|
i32 numDigitsAfterDecimal = 0;
|
||||||
|
i32 rawNumber = 0;
|
||||||
|
|
||||||
|
f32 digitShiftValue = 1.0f;
|
||||||
|
f32 digitShiftMultiplier = 0.1f;
|
||||||
|
for (i32 i = index; i < bufSize; i++)
|
||||||
|
{
|
||||||
|
char ch = buf[i];
|
||||||
|
if (ch == '.')
|
||||||
|
{
|
||||||
|
isPastDecimal = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Handle scientific notation
|
||||||
|
else if (ch == 'e')
|
||||||
|
{
|
||||||
|
bool digitShiftIsPositive = true;
|
||||||
|
if (i < bufSize)
|
||||||
|
{
|
||||||
|
if (buf[i + 1] == '-') digitShiftIsPositive = false;
|
||||||
|
DQN_ASSERT(buf[i + 1] == '-' || buf[i + 1] == '+');
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 exponentPow = 0;
|
||||||
|
bool scientificNotation = false;
|
||||||
|
while (i < bufSize)
|
||||||
|
{
|
||||||
|
scientificNotation = true;
|
||||||
|
char exponentCh = buf[i];
|
||||||
|
if (DqnChar_IsDigit(exponentCh))
|
||||||
|
{
|
||||||
|
exponentPow *= 10;
|
||||||
|
exponentPow += (buf[i] - '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = bufSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(doyle): If exponent not specified but this branch occurred,
|
||||||
|
// the float string has a malformed scientific notation in the
|
||||||
|
// string, i.e. "e" followed by no number.
|
||||||
|
DQN_ASSERT(scientificNotation);
|
||||||
|
|
||||||
|
numDigitsAfterDecimal += exponentPow;
|
||||||
|
if (digitShiftIsPositive) digitShiftMultiplier = 10.0f;
|
||||||
|
}
|
||||||
|
else if (DqnChar_IsDigit(ch))
|
||||||
|
{
|
||||||
|
numDigitsAfterDecimal += (i32)isPastDecimal;
|
||||||
|
rawNumber *= 10;
|
||||||
|
rawNumber += (ch - '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < numDigitsAfterDecimal; i++)
|
||||||
|
digitShiftValue *= digitShiftMultiplier;
|
||||||
|
|
||||||
|
f32 result = (f32)rawNumber;
|
||||||
|
if (numDigitsAfterDecimal > 0) result *= digitShiftValue;
|
||||||
|
if (isNegative) result *= -1;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Encoding
|
Encoding
|
||||||
The following byte sequences are used to represent a character. The sequence
|
The following byte sequences are used to represent a character. The sequence
|
||||||
|
Loading…
Reference in New Issue
Block a user