mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-12-13 19:42:29 +00:00
chore: initial commit
This commit is contained in:
commit
70b00c5c38
965 changed files with 264882 additions and 0 deletions
236
src/gx/Blit.cpp
Normal file
236
src/gx/Blit.cpp
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
#include "gx/Blit.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <tempest/Vector.hpp>
|
||||
|
||||
int32_t initBlit = 0;
|
||||
BLIT_FUNCTION s_blits[BlitFormats_Last][BlitFormats_Last][BlitAlphas_Last];
|
||||
|
||||
BlitFormat GxGetBlitFormat(EGxTexFormat format) {
|
||||
static BlitFormat blitTable[] = {
|
||||
BlitFormat_Unknown, // GxTex_Unknown
|
||||
BlitFormat_Abgr8888, // GxTex_Abgr8888
|
||||
BlitFormat_Argb8888, // GxTex_Argb8888
|
||||
BlitFormat_Argb4444, // GxTex_Argb4444
|
||||
BlitFormat_Argb1555, // GxTex_Argb1555
|
||||
BlitFormat_Rgb565, // GxTex_Rgb565
|
||||
BlitFormat_Dxt1, // GxTex_Dxt1
|
||||
BlitFormat_Dxt3, // GxTex_Dxt3
|
||||
BlitFormat_Dxt5, // GxTex_Dxt5
|
||||
BlitFormat_Uv88, // GxTex_Uv88
|
||||
BlitFormat_Gr1616F, // GxTex_Gr1616F
|
||||
BlitFormat_R32F, // GxTex_R32F
|
||||
BlitFormat_D24X8 // GxTex_D24X8
|
||||
};
|
||||
|
||||
return blitTable[format];
|
||||
}
|
||||
|
||||
void Blit_uint16_uint16(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
if (inStride == 2 * size.x && outStride == 2 * size.x) {
|
||||
memcpy(out, in, 2 * size.x * size.y);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* in_ = reinterpret_cast<const char*>(in);
|
||||
char* out_ = reinterpret_cast<char*>(out);
|
||||
|
||||
for (int32_t i = 0; i < size.y; i++) {
|
||||
memcpy(out, in, 2 * size.x);
|
||||
in_ += inStride;
|
||||
out_ += outStride;
|
||||
}
|
||||
}
|
||||
|
||||
void Blit_uint32_uint32(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
if (inStride == 4 * size.x && outStride == 4 * size.x) {
|
||||
memcpy(out, in, 4 * size.x * size.y);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* in_ = reinterpret_cast<const char*>(in);
|
||||
char* out_ = reinterpret_cast<char*>(out);
|
||||
|
||||
for (int32_t i = 0; i < size.y; i++) {
|
||||
memcpy(out, in, 4 * size.x);
|
||||
in_ += inStride;
|
||||
out_ += outStride;
|
||||
}
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Abgr8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
Blit_uint32_uint32(size, in, inStride, out, outStride);
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Argb8888_A1(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Argb8888_A8(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Argb1555(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb8888_Rgb565(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb4444_Abgr8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Argb4444_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
Blit_uint16_uint16(size, in, inStride, out, outStride);
|
||||
}
|
||||
|
||||
void Blit_Argb1555_Argb1555(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Rgb565_Rgb565(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt1_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt1_Argb1555(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt1_Rgb565(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt1_Dxt1(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
const char* in_ = static_cast<const char*>(in);
|
||||
char* out_ = static_cast<char*>(out);
|
||||
|
||||
int32_t v6 = std::max(size.x, 4);
|
||||
int32_t v7 = std::max(size.y, 4);
|
||||
|
||||
memcpy(out_, in_, (4 * v6 * v7) >> 3);
|
||||
}
|
||||
|
||||
void Blit_Dxt3_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt3_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt35_Dxt35(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
int32_t v5 = std::max(size.x, 4);
|
||||
int32_t v6 = std::max(size.y / 4, 1);
|
||||
|
||||
const char* in_ = static_cast<const char*>(in);
|
||||
char* out_ = static_cast<char*>(out);
|
||||
|
||||
if (inStride == v5 * 4 && outStride == v5 * 4) {
|
||||
memcpy(out_, in_, v5 * v6 * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t i = v6; i > 0; i--) {
|
||||
memcpy(out_, in_, v5 * 4);
|
||||
in_ += inStride;
|
||||
out_ += outStride;
|
||||
}
|
||||
}
|
||||
|
||||
void Blit_Dxt5_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Dxt5_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Uv88_Uv88(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_Gr1616F_Gr1616F(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_R32F_R32F(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Blit_D24X8_D24X8(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void InitBlit() {
|
||||
// Source: Argb8888
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Abgr8888] [BlitAlpha_0] = &Blit_Argb8888_Abgr8888;
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Argb8888_Argb8888;
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb8888] [BlitAlpha_1] = &Blit_Argb8888_Argb8888_A1;
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb8888] [BlitAlpha_8] = &Blit_Argb8888_Argb8888_A8;
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Argb8888_Argb4444;
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb1555] [BlitAlpha_0] = &Blit_Argb8888_Argb1555;
|
||||
s_blits [BlitFormat_Argb8888] [BlitFormat_Rgb565] [BlitAlpha_0] = &Blit_Argb8888_Rgb565;
|
||||
|
||||
// Source: Argb4444
|
||||
s_blits [BlitFormat_Argb4444] [BlitFormat_Abgr8888] [BlitAlpha_0] = &Blit_Argb4444_Abgr8888;
|
||||
s_blits [BlitFormat_Argb4444] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Argb4444_Argb4444;
|
||||
|
||||
// Source: Argb1555
|
||||
s_blits [BlitFormat_Argb1555] [BlitFormat_Argb1555] [BlitAlpha_0] = &Blit_Argb1555_Argb1555;
|
||||
|
||||
// Source: Rgb565
|
||||
s_blits [BlitFormat_Rgb565] [BlitFormat_Rgb565] [BlitAlpha_0] = &Blit_Rgb565_Rgb565;
|
||||
|
||||
// Source: Dxt1
|
||||
s_blits [BlitFormat_Dxt1] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Dxt1_Argb8888;
|
||||
s_blits [BlitFormat_Dxt1] [BlitFormat_Argb1555] [BlitAlpha_0] = &Blit_Dxt1_Argb1555;
|
||||
s_blits [BlitFormat_Dxt1] [BlitFormat_Rgb565] [BlitAlpha_0] = &Blit_Dxt1_Rgb565;
|
||||
s_blits [BlitFormat_Dxt1] [BlitFormat_Dxt1] [BlitAlpha_0] = &Blit_Dxt1_Dxt1;
|
||||
|
||||
// Source: Dxt3
|
||||
s_blits [BlitFormat_Dxt3] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Dxt3_Argb8888;
|
||||
s_blits [BlitFormat_Dxt3] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Dxt3_Argb4444;
|
||||
s_blits [BlitFormat_Dxt3] [BlitFormat_Dxt3] [BlitAlpha_0] = &Blit_Dxt35_Dxt35;
|
||||
|
||||
// Source: Dxt5
|
||||
s_blits [BlitFormat_Dxt5] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Dxt5_Argb8888;
|
||||
s_blits [BlitFormat_Dxt5] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Dxt5_Argb4444;
|
||||
s_blits [BlitFormat_Dxt5] [BlitFormat_Dxt5] [BlitAlpha_0] = &Blit_Dxt35_Dxt35;
|
||||
|
||||
// Source: Uv88
|
||||
s_blits [BlitFormat_Uv88] [BlitFormat_Uv88] [BlitAlpha_0] = &Blit_Uv88_Uv88;
|
||||
|
||||
// Source: Gr1616F
|
||||
s_blits [BlitFormat_Gr1616F] [BlitFormat_Gr1616F] [BlitAlpha_0] = &Blit_Gr1616F_Gr1616F;
|
||||
|
||||
// Source: R32F
|
||||
s_blits [BlitFormat_R32F] [BlitFormat_R32F] [BlitAlpha_0] = &Blit_R32F_R32F;
|
||||
|
||||
// Source: D24X8
|
||||
s_blits [BlitFormat_D24X8] [BlitFormat_D24X8] [BlitAlpha_0] = &Blit_D24X8_D24X8;
|
||||
}
|
||||
|
||||
void Blit(const C2iVector& size, BlitAlpha alpha, const void* src, uint32_t srcStride, BlitFormat srcFmt, void* dst, uint32_t dstStride, BlitFormat dstFmt) {
|
||||
if (!initBlit) {
|
||||
InitBlit();
|
||||
initBlit = 1;
|
||||
}
|
||||
|
||||
BLIT_FUNCTION blit = s_blits[srcFmt][dstFmt][alpha];
|
||||
|
||||
blit(size, src, srcStride, dst, dstStride);
|
||||
}
|
||||
15
src/gx/Blit.hpp
Normal file
15
src/gx/Blit.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef GX_BLIT_HPP
|
||||
#define GX_BLIT_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class C2iVector;
|
||||
|
||||
typedef void (*BLIT_FUNCTION)(const C2iVector&, const void*, uint32_t, void*, uint32_t);
|
||||
|
||||
void Blit(const C2iVector&, BlitAlpha, const void*, uint32_t, BlitFormat, void*, uint32_t, BlitFormat);
|
||||
|
||||
BlitFormat GxGetBlitFormat(EGxTexFormat);
|
||||
|
||||
#endif
|
||||
213
src/gx/Buffer.cpp
Normal file
213
src/gx/Buffer.cpp
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
#include "gx/Buffer.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
|
||||
CGxVertexAttrib vertexAttribsP[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_P, GxVA_Position), 12 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPN[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PN, GxVA_Position), 24 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PN, GxVA_Normal), 24 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPNC[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNC, GxVA_Position), 28 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNC, GxVA_Normal), 28 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNC, GxVA_Color0), 28 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPNT[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNT, GxVA_Position), 32 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNT, GxVA_Normal), 32 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNT, GxVA_TexCoord0), 32 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPNCT[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNCT, GxVA_Position), 36 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNCT, GxVA_Normal), 36 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNCT, GxVA_Color0), 36 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNCT, GxVA_TexCoord0), 36 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPNT2[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNT2, GxVA_Position), 40 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNT2, GxVA_Normal), 40 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNT2, GxVA_TexCoord0), 40 },
|
||||
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PNT2, GxVA_TexCoord1), 40 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPNCT2[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_Position), 44 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_Normal), 44 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_Color0), 44 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_TexCoord0), 44 },
|
||||
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_TexCoord1), 44 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPC[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PC, GxVA_Position), 16 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PC, GxVA_Color0), 16 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPCT[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PCT, GxVA_Position), 24 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PCT, GxVA_Color0), 24 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PCT, GxVA_TexCoord0), 24 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPCT2[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PCT2, GxVA_Position), 32 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PCT2, GxVA_Color0), 32 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PCT2, GxVA_TexCoord0), 32 },
|
||||
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PCT2, GxVA_TexCoord1), 32 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPT[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PT, GxVA_Position), 20 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PT, GxVA_TexCoord0), 20 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPT2[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PT2, GxVA_Position), 28 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PT2, GxVA_TexCoord0), 28 },
|
||||
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PT2, GxVA_TexCoord1), 28 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPBNT2[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_Position), 48 },
|
||||
{ GxVA_BlendWeight, 2, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_BlendWeight), 48 },
|
||||
{ GxVA_BlendIndices, 1, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_BlendIndices), 48 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_Normal), 48 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_TexCoord0), 48 },
|
||||
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_TexCoord1), 48 }
|
||||
};
|
||||
|
||||
CGxVertexAttrib vertexAttribsPNC2T2[] = {
|
||||
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Position), 48 },
|
||||
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Normal), 48 },
|
||||
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Color0), 48 },
|
||||
{ GxVA_Color1, 0, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Color0), 48 },
|
||||
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_TexCoord0), 48 },
|
||||
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_TexCoord1), 48 }
|
||||
};
|
||||
|
||||
VertexBufDesc Buffer::s_vertexBufDesc[] = {
|
||||
// GxVBF_P
|
||||
{ vertexAttribsP, 1, 12, GxPrim_Position },
|
||||
|
||||
// GxVBF_PN
|
||||
{ vertexAttribsPN, 2, 24, GxPrim_Position | GxPrim_Normal },
|
||||
|
||||
// GxVBF_PNC
|
||||
{ vertexAttribsPNC, 3, 28, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 },
|
||||
|
||||
// GxVBF_PNT
|
||||
{ vertexAttribsPNT, 3, 32, GxPrim_Position | GxPrim_Normal | GxPrim_TexCoord0 },
|
||||
|
||||
// GxVBF_PNCT
|
||||
{ vertexAttribsPNCT, 4, 36, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 | GxPrim_TexCoord0 },
|
||||
|
||||
// GxVBF_PNT2
|
||||
{ vertexAttribsPNT2, 4, 40, GxPrim_Position | GxPrim_Normal | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
|
||||
|
||||
// GxVBF_PNCT2
|
||||
{ vertexAttribsPNCT2, 5, 44, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
|
||||
|
||||
// GxVBF_PC
|
||||
{ vertexAttribsPC, 2, 16, GxPrim_Position | GxPrim_Color0 },
|
||||
|
||||
// GxVBF_PCT
|
||||
{ vertexAttribsPCT, 3, 24, GxPrim_Position | GxPrim_Color0 | GxPrim_TexCoord0 },
|
||||
|
||||
// GxVBF_PCT2
|
||||
{ vertexAttribsPCT2, 4, 32, GxPrim_Position | GxPrim_Color0 | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
|
||||
|
||||
// GxVBF_PT
|
||||
{ vertexAttribsPT, 2, 20, GxPrim_Position | GxPrim_TexCoord0 },
|
||||
|
||||
// GxVBF_PT2
|
||||
{ vertexAttribsPT2, 3, 28, GxPrim_Position | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
|
||||
|
||||
// GxVBF_PBNT2
|
||||
{ vertexAttribsPBNT2, 6, 48, GxPrim_Position | GxPrim_BlendWeight | GxPrim_BlendIndices | GxPrim_Normal | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
|
||||
|
||||
// GxVBF_PNC2T2
|
||||
{ vertexAttribsPNC2T2, 6, 48, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 | GxPrim_Color1 | GxPrim_TexCoord0 | GxPrim_TexCoord1 }
|
||||
};
|
||||
|
||||
int32_t Buffer::s_vertexBufOffset[GxVertexBufferFormats_Last][GxVAs_Last] = {
|
||||
// GxVBF_P
|
||||
{ 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PN
|
||||
{ 0, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PNC
|
||||
{ 0, -1, -1, 12, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PNT
|
||||
{ 0, -1, -1, 12, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PNCT
|
||||
{ 0, -1, -1, 12, 24, -1, 28, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PNT2
|
||||
{ 0, -1, -1, 12, -1, -1, 24, 32, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PNCT2
|
||||
{ 0, -1, -1, 12, 24, -1, 28, 36, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PC
|
||||
{ 0, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PCT
|
||||
{ 0, -1, -1, -1, 12, -1, 16, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PCT2
|
||||
{ 0, -1, -1, -1, 12, -1, 16, 24, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PT
|
||||
{ 0, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PT2
|
||||
{ 0, -1, -1, -1, -1, -1, 12, 20, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PBNT2
|
||||
{ 0, 12, 16, 20, -1, -1, 32, 40, -1, -1, -1, -1, -1, -1 },
|
||||
|
||||
// GxVBF_PNC2T2
|
||||
{ 0, -1, -1, 12, 24, 28, 32, 40, -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
|
||||
uint32_t GxVertexAttribOffset(EGxVertexBufferFormat format, EGxVertexAttrib attrib) {
|
||||
return Buffer::s_vertexBufOffset[format][attrib];
|
||||
}
|
||||
|
||||
CGxBuf* GxBufCreate(CGxPool* pool, uint32_t itemSize, uint32_t itemCount, uint32_t index) {
|
||||
return g_theGxDevicePtr->BufCreate(pool, itemSize, itemCount, index);
|
||||
}
|
||||
|
||||
char* GxBufLock(CGxBuf* buf) {
|
||||
return g_theGxDevicePtr->BufLock(buf);
|
||||
}
|
||||
|
||||
void GxBufUnlock(CGxBuf* buf, uint32_t size) {
|
||||
g_theGxDevicePtr->BufUnlock(buf, size);
|
||||
buf->unk1C = 1;
|
||||
}
|
||||
|
||||
CGxPool* GxPoolCreate(EGxPoolTarget target, EGxPoolUsage usage, uint32_t size, EGxPoolHintBits hint, char* name) {
|
||||
return g_theGxDevicePtr->PoolCreate(target, usage, size, hint, name);
|
||||
}
|
||||
|
||||
void GxPrimIndexPtr(CGxBuf* buf) {
|
||||
g_theGxDevicePtr->PrimIndexPtr(buf);
|
||||
}
|
||||
|
||||
void GxPrimVertexPtr(CGxBuf* buf, EGxVertexBufferFormat format) {
|
||||
auto desc = &Buffer::s_vertexBufDesc[format];
|
||||
|
||||
g_theGxDevicePtr->PrimVertexFormat(buf, desc->attribs, desc->attribCount);
|
||||
g_theGxDevicePtr->PrimVertexMask(desc->mask);
|
||||
g_theGxDevicePtr->PrimVertexPtr(buf, format);
|
||||
}
|
||||
38
src/gx/Buffer.hpp
Normal file
38
src/gx/Buffer.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef GX_BUFFER_HPP
|
||||
#define GX_BUFFER_HPP
|
||||
|
||||
#include "gx/buffer/CGxBuf.hpp"
|
||||
#include "gx/buffer/CGxPool.hpp"
|
||||
#include "gx/buffer/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class CGxBuf;
|
||||
class CGxPool;
|
||||
|
||||
struct VertexBufDesc {
|
||||
CGxVertexAttrib* attribs;
|
||||
uint32_t attribCount;
|
||||
uint32_t size;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
namespace Buffer {
|
||||
extern VertexBufDesc s_vertexBufDesc[GxVertexBufferFormats_Last];
|
||||
extern int32_t s_vertexBufOffset[GxVertexBufferFormats_Last][GxVAs_Last];
|
||||
}
|
||||
|
||||
uint32_t GxVertexAttribOffset(EGxVertexBufferFormat, EGxVertexAttrib);
|
||||
|
||||
CGxBuf* GxBufCreate(CGxPool*, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
char* GxBufLock(CGxBuf* buf);
|
||||
|
||||
void GxBufUnlock(CGxBuf*, uint32_t);
|
||||
|
||||
CGxPool* GxPoolCreate(EGxPoolTarget, EGxPoolUsage, uint32_t, EGxPoolHintBits, char*);
|
||||
|
||||
void GxPrimIndexPtr(CGxBuf*);
|
||||
|
||||
void GxPrimVertexPtr(CGxBuf*, EGxVertexBufferFormat);
|
||||
|
||||
#endif
|
||||
58
src/gx/CCamera.cpp
Normal file
58
src/gx/CCamera.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include "gx/CCamera.hpp"
|
||||
#include "gx/Shader.hpp"
|
||||
#include "gx/Transform.hpp"
|
||||
#include <cmath>
|
||||
#include <tempest/Math.hpp>
|
||||
#include <tempest/Matrix.hpp>
|
||||
#include <tempest/Rect.hpp>
|
||||
|
||||
const C3Vector CCamera::DEFAULT_POSITION = { 100.0f, 0.0f, 0.0f };
|
||||
const float CCamera::DEFAULT_DIST = 100.0f;
|
||||
const float CCamera::DEFAULT_FARZ = 5000.0f;
|
||||
const float CCamera::DEFAULT_NEARZ = 8.0f;
|
||||
|
||||
float CAngle::ClampTo2Pi(float angle) {
|
||||
double v1 = floor(static_cast<double>(CMath::OO_TWO_PI) * angle) * CMath::TWO_PI;
|
||||
|
||||
if (angle < 0.0f) {
|
||||
v1 -= CMath::TWO_PI;
|
||||
}
|
||||
|
||||
return angle - v1;
|
||||
}
|
||||
|
||||
void CAngle::Set(const float& angle) {
|
||||
float clampedAngle = CAngle::ClampTo2Pi(angle);
|
||||
|
||||
if (this->m_data != clampedAngle) {
|
||||
this->m_flags |= CBaseManaged::UPDATED;
|
||||
this->m_data = clampedAngle;
|
||||
}
|
||||
|
||||
this->m_cos = cos(this->m_data);
|
||||
this->m_sin = sin(this->m_data);
|
||||
}
|
||||
|
||||
void CCamera::SetupWorldProjection(const CRect& projectionRect, uint32_t flags) {
|
||||
C44Matrix projMat;
|
||||
float aspect = (projectionRect.maxX - projectionRect.minX) / (projectionRect.maxY - projectionRect.minY);
|
||||
GxuXformCreateProjection_SG(this->m_fov.m_data, aspect, this->m_zNear.m_data, this->m_zFar.m_data, projMat);
|
||||
GxXformSetProjection(projMat);
|
||||
|
||||
C44Matrix viewMat;
|
||||
C3Vector cameraPos = { 0.0f, 0.0f, 0.0f };
|
||||
C3Vector cameraVec = {
|
||||
this->m_target.m_data.x - this->m_position.m_data.x,
|
||||
this->m_target.m_data.y - this->m_position.m_data.y,
|
||||
this->m_target.m_data.z - this->m_position.m_data.z
|
||||
};
|
||||
C3Vector upVec = {
|
||||
this->m_rotation.m_sin * this->m_roll.m_sin,
|
||||
-(this->m_rotation.m_cos * this->m_roll.m_sin),
|
||||
this->m_roll.m_cos
|
||||
};
|
||||
GxuXformCreateLookAtSgCompat(cameraPos, cameraVec, upVec, viewMat);
|
||||
GxXformSetView(viewMat);
|
||||
|
||||
CShaderEffect::UpdateProjMatrix();
|
||||
}
|
||||
70
src/gx/CCamera.hpp
Normal file
70
src/gx/CCamera.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef GX_C_CAMERA_HPP
|
||||
#define GX_C_CAMERA_HPP
|
||||
|
||||
#include <common/DataMgr.hpp>
|
||||
|
||||
class CRect;
|
||||
|
||||
class CAngle : public TManaged<float> {
|
||||
public:
|
||||
// Static functions
|
||||
static float ClampTo2Pi(float angle);
|
||||
|
||||
// Member variables
|
||||
float m_cos;
|
||||
float m_sin;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void Set(const float& angle);
|
||||
|
||||
// Member functions
|
||||
CAngle(float angle) {
|
||||
this->Set(angle);
|
||||
};
|
||||
};
|
||||
|
||||
class CCamera : public CDataMgr {
|
||||
public:
|
||||
static const C3Vector DEFAULT_POSITION;
|
||||
static const float DEFAULT_DIST;
|
||||
static const float DEFAULT_FARZ;
|
||||
static const float DEFAULT_NEARZ;
|
||||
|
||||
// Member variables
|
||||
TManaged<C3Vector> m_position;
|
||||
TManaged<C3Vector> m_target;
|
||||
TManaged<float> m_distance;
|
||||
TManaged<float> m_zFar;
|
||||
TManaged<float> m_zNear;
|
||||
CAngle m_aoa;
|
||||
CAngle m_fov;
|
||||
CAngle m_roll;
|
||||
CAngle m_rotation;
|
||||
|
||||
// Member functions
|
||||
CCamera()
|
||||
: m_position(DEFAULT_POSITION)
|
||||
, m_distance(DEFAULT_DIST)
|
||||
, m_zFar(DEFAULT_FARZ)
|
||||
, m_zNear(DEFAULT_NEARZ)
|
||||
, m_aoa(0.0f)
|
||||
, m_fov(0.0f)
|
||||
, m_roll(0.0f)
|
||||
, m_rotation(0.0f)
|
||||
{
|
||||
this->m_managedArray.SetCount(9);
|
||||
|
||||
this->AddManaged(&this->m_position, 7, 0x0);
|
||||
this->AddManaged(&this->m_target, 8, 0x0);
|
||||
this->AddManaged(&this->m_distance, 1, 0x0);
|
||||
this->AddManaged(&this->m_zFar, 2, 0x0);
|
||||
this->AddManaged(&this->m_zNear, 3, 0x0);
|
||||
this->AddManaged(&this->m_aoa, 0, 0x0);
|
||||
this->AddManaged(&this->m_fov, 4, 0x0);
|
||||
this->AddManaged(&this->m_roll, 5, 0x0);
|
||||
this->AddManaged(&this->m_rotation, 6, 0x0);
|
||||
}
|
||||
void SetupWorldProjection(const CRect& projectionRect, uint32_t flags);
|
||||
};
|
||||
|
||||
#endif
|
||||
17
src/gx/CGxBatch.hpp
Normal file
17
src/gx/CGxBatch.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef GX_C_GX_BATCH_HPP
|
||||
#define GX_C_GX_BATCH_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class CGxBatch {
|
||||
public:
|
||||
// Member variables
|
||||
EGxPrim m_primType;
|
||||
uint32_t m_start;
|
||||
uint32_t m_count;
|
||||
uint16_t m_minIndex;
|
||||
uint16_t m_maxIndex;
|
||||
};
|
||||
|
||||
#endif
|
||||
28
src/gx/CGxCaps.hpp
Normal file
28
src/gx/CGxCaps.hpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef GX_C_GX_CAPS_HPP
|
||||
#define GX_C_GX_CAPS_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class CGxCaps {
|
||||
public:
|
||||
int32_t m_pixelCenterOnEdge = 0;
|
||||
int32_t m_texelCenterOnEdge = 0;
|
||||
EGxColorFormat m_colorFormat = GxCF_argb;
|
||||
int32_t m_generateMipMaps = 0;
|
||||
uint32_t m_maxTextureSize = 0;
|
||||
int32_t m_texFmtDxt1 = 0;
|
||||
int32_t m_texFmtDxt3 = 0;
|
||||
int32_t m_texFmtDxt5 = 0;
|
||||
EGxShVS m_vertexShaderTarget = GxShVS_none;
|
||||
EGxShPS m_pixelShaderTarget = GxShPS_none;
|
||||
int32_t m_texFilterAnisotropic = 0;
|
||||
uint32_t m_maxTexAnisotropy = 0;
|
||||
int32_t m_texTarget[GxTexTargets_Last];
|
||||
uint32_t m_texMaxSize[GxTexTargets_Last];
|
||||
int32_t int130 = 1;
|
||||
int32_t int134 = 0;
|
||||
int32_t int138 = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
1020
src/gx/CGxDevice.cpp
Normal file
1020
src/gx/CGxDevice.cpp
Normal file
File diff suppressed because it is too large
Load diff
160
src/gx/CGxDevice.hpp
Normal file
160
src/gx/CGxDevice.hpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#ifndef GX_C_GX_DEVICE_HPP
|
||||
#define GX_C_GX_DEVICE_HPP
|
||||
|
||||
#include "gx/Buffer.hpp"
|
||||
#include "gx/CGxCaps.hpp"
|
||||
#include "gx/CGxFormat.hpp"
|
||||
#include "gx/CGxMatrixStack.hpp"
|
||||
#include "gx/CGxStateBom.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include "gx/Shader.hpp"
|
||||
#include <cstdint>
|
||||
#include <storm/Hash.hpp>
|
||||
#include <tempest/Box.hpp>
|
||||
#include <tempest/Rect.hpp>
|
||||
|
||||
class CGxBatch;
|
||||
class CGxTex;
|
||||
class CGxTexFlags;
|
||||
|
||||
struct CGxAppRenderState {
|
||||
CGxStateBom m_value;
|
||||
uint32_t m_stackDepth;
|
||||
int32_t m_dirty;
|
||||
};
|
||||
|
||||
struct CGxPushedRenderState {
|
||||
EGxRenderState m_which;
|
||||
CGxStateBom m_value;
|
||||
uint32_t m_stackDepth;
|
||||
};
|
||||
|
||||
struct ShaderConstants {
|
||||
C4Vector constants[256];
|
||||
uint32_t unk1;
|
||||
uint32_t unk2;
|
||||
};
|
||||
|
||||
class CGxDevice {
|
||||
public:
|
||||
// Static variables
|
||||
static uint32_t s_alphaRef[];
|
||||
static C3Vector s_pointScaleIdentity;
|
||||
static ShaderConstants s_shadowConstants[2];
|
||||
static uint32_t s_streamPoolSize[];
|
||||
static uint32_t s_texFormatBitDepth[];
|
||||
static uint32_t s_texFormatBytesPerBlock[];
|
||||
|
||||
// Static functions
|
||||
static CGxDevice* NewGLL(void);
|
||||
static CGxDevice* NewOpenGl(void);
|
||||
|
||||
// Member variables
|
||||
TSGrowableArray<CGxPushedRenderState> m_pushedStates;
|
||||
TSGrowableArray<size_t> m_stackOffsets;
|
||||
TSGrowableArray<EGxRenderState> m_dirtyStates;
|
||||
CRect m_defWindowRect;
|
||||
CRect m_curWindowRect;
|
||||
EGxApi m_api = GxApis_Last;
|
||||
CGxFormat m_format;
|
||||
CGxCaps m_caps;
|
||||
int32_t m_shaderProfiles[GxShTargets_Last] = { 6, 0, 0, 0, 12, 0 }; // TODO placeholder
|
||||
TSHashTable<CGxShader, HASHKEY_STRI> m_shaderList[GxShTargets_Last];
|
||||
int32_t m_context = 0;
|
||||
CBoundingBox m_viewport;
|
||||
C44Matrix m_projection;
|
||||
C44Matrix m_projNative;
|
||||
CGxMatrixStack m_xforms[GxXforms_Last];
|
||||
uint32_t m_appMasterEnables = 0;
|
||||
uint32_t m_hwMasterEnables = 0;
|
||||
TSList<CGxPool, TSGetLink<CGxPool>> m_poolList;
|
||||
CGxBuf* m_bufLocked[GxPoolTargets_Last];
|
||||
CGxPool* m_vertexPool = nullptr;
|
||||
CGxPool* m_indexPool = nullptr;
|
||||
CGxBuf* m_streamBufs[GxPoolTargets_Last];
|
||||
CGxVertexAttrib m_primVertexFormatAttrib[GxVertexBufferFormats_Last];
|
||||
CGxBuf* m_primVertexFormatBuf[GxVertexBufferFormats_Last];
|
||||
uint32_t m_primVertexMask = 0;
|
||||
uint32_t m_primVertexDirty = 0;
|
||||
EGxVertexBufferFormat m_primVertexFormat = GxVertexBufferFormats_Last;
|
||||
CGxBuf* m_primVertexBuf = nullptr;
|
||||
uint32_t m_primVertexSize;
|
||||
CGxBuf* m_primIndexBuf = nullptr;
|
||||
int32_t m_primIndexDirty = 0;
|
||||
TSFixedArray<CGxAppRenderState> m_appRenderStates;
|
||||
TSFixedArray<CGxStateBom> m_hwRenderStates;
|
||||
uint32_t m_baseMipLevel = 0; // TODO placeholder
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ITexMarkAsUpdated(CGxTex*) = 0;
|
||||
virtual void IRsSendToHw(EGxRenderState) = 0;
|
||||
virtual void ICursorCreate(const CGxFormat& format);
|
||||
virtual int32_t DeviceCreate(long (*)(void*, uint32_t, uint32_t, long), const CGxFormat&);
|
||||
virtual int32_t DeviceSetFormat(const CGxFormat&);
|
||||
virtual void CapsWindowSize(CRect&) = 0;
|
||||
virtual void CapsWindowSizeInScreenCoords(CRect& dst) = 0;
|
||||
virtual void ScenePresent(void);
|
||||
virtual void SceneClear(uint32_t, CImVector) {};
|
||||
virtual void XformSetProjection(const C44Matrix&);
|
||||
virtual void XformSetView(const C44Matrix&);
|
||||
virtual void Draw(CGxBatch*, int32_t) {};
|
||||
virtual void ValidateDraw(CGxBatch*, int32_t);
|
||||
virtual void MasterEnableSet(EGxMasterEnables, int32_t);
|
||||
virtual void PoolSizeSet(CGxPool*, uint32_t) = 0;
|
||||
virtual char* BufLock(CGxBuf*);
|
||||
virtual int32_t BufUnlock(CGxBuf*, uint32_t);
|
||||
virtual int32_t TexCreate(EGxTexTarget, uint32_t, uint32_t, uint32_t, EGxTexFormat, EGxTexFormat, CGxTexFlags, void*, void (*)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&), const char*, CGxTex*&);
|
||||
virtual void TexDestroy(CGxTex* texId);
|
||||
virtual void ShaderCreate(CGxShader*[], EGxShTarget, const char*, const char*, int32_t);
|
||||
virtual void ShaderConstantsSet(EGxShTarget, uint32_t, const float*, uint32_t);
|
||||
virtual void IShaderCreate(CGxShader*) = 0;
|
||||
virtual int32_t StereoEnabled(void) = 0;
|
||||
|
||||
// Member functions
|
||||
CGxDevice();
|
||||
CGxBuf* BufCreate(CGxPool*, uint32_t, uint32_t, uint32_t);
|
||||
CGxBuf* BufStream(EGxPoolTarget, uint32_t, uint32_t);
|
||||
void DeviceCreatePools(void);
|
||||
void DeviceCreateStreamBufs(void);
|
||||
const CRect& DeviceCurWindow(void);
|
||||
void DeviceSetCurWindow(const CRect&);
|
||||
void DeviceSetDefWindow(CRect const&);
|
||||
const CRect& DeviceDefWindow(void);
|
||||
int32_t IDevIsWindowed();
|
||||
void IRsDirty(EGxRenderState);
|
||||
void IRsForceUpdate(void);
|
||||
void IRsForceUpdate(EGxRenderState);
|
||||
void IRsInit(void);
|
||||
void IRsSync(int32_t);
|
||||
void IShaderBind(void) {};
|
||||
void IShaderLoad(CGxShader*[], EGxShTarget, const char*, const char*, int32_t);
|
||||
void ITexBind(void) {};
|
||||
void ITexWHDStartEnd(CGxTex*, uint32_t&, uint32_t&, uint32_t&, uint32_t&);
|
||||
int32_t MasterEnable(EGxMasterEnables);
|
||||
CGxPool* PoolCreate(EGxPoolTarget, EGxPoolUsage, uint32_t, EGxPoolHintBits, const char*);
|
||||
void PrimIndexPtr(CGxBuf*);
|
||||
void PrimVertexFormat(CGxBuf*, CGxVertexAttrib*, uint32_t);
|
||||
void PrimVertexMask(uint32_t);
|
||||
void PrimVertexPtr(CGxBuf*, EGxVertexBufferFormat);
|
||||
void RsGet(EGxRenderState, int32_t&);
|
||||
void RsSet(EGxRenderState, int32_t);
|
||||
void RsSet(EGxRenderState, void*);
|
||||
void RsSetAlphaRef(void);
|
||||
void RsPop(void);
|
||||
void RsPush(void);
|
||||
void ShaderConstantsClear(void);
|
||||
char* ShaderConstantsLock(EGxShTarget target);
|
||||
void ShaderConstantsUnlock(EGxShTarget target, uint32_t index, uint32_t count);
|
||||
void TexMarkForUpdate(CGxTex*, const CiRect&, int32_t);
|
||||
void TexSetWrap(CGxTex* texId, EGxTexWrapMode wrapU, EGxTexWrapMode wrapV);
|
||||
void XformPop(EGxXform xf);
|
||||
void XformProjection(C44Matrix&);
|
||||
void XformProjNative(C44Matrix&);
|
||||
void XformPush(EGxXform xf);
|
||||
void XformSet(EGxXform xf, const C44Matrix& matrix);
|
||||
void XformSetViewport(float, float, float, float, float, float);
|
||||
void XformView(C44Matrix&);
|
||||
void XformViewport(float&, float&, float&, float&, float&, float&);
|
||||
};
|
||||
|
||||
#endif
|
||||
32
src/gx/CGxFormat.hpp
Normal file
32
src/gx/CGxFormat.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef GX_C_GX_FORMAT_HPP
|
||||
#define GX_C_GX_FORMAT_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <tempest/Vector.hpp>
|
||||
|
||||
class CGxFormat {
|
||||
public:
|
||||
// Types
|
||||
enum Format {
|
||||
Fmt_Rgb565 = 0,
|
||||
Fmt_ArgbX888 = 1,
|
||||
Fmt_Argb8888 = 2,
|
||||
Fmt_Argb2101010 = 3,
|
||||
Fmt_Ds160 = 4,
|
||||
Fmt_Ds24X = 5,
|
||||
Fmt_Ds248 = 6,
|
||||
Fmt_Ds320 = 7,
|
||||
Formats_Last = 8
|
||||
};
|
||||
|
||||
// Member variables
|
||||
int8_t window;
|
||||
int32_t maximize;
|
||||
Format depthFormat;
|
||||
C2iVector size;
|
||||
uint32_t sampleCount;
|
||||
Format colorFormat;
|
||||
uint32_t refreshRate;
|
||||
};
|
||||
|
||||
#endif
|
||||
30
src/gx/CGxMatrixStack.cpp
Normal file
30
src/gx/CGxMatrixStack.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "gx/CGxMatrixStack.hpp"
|
||||
|
||||
CGxMatrixStack::CGxMatrixStack() {
|
||||
this->m_flags[0] = 0x1;
|
||||
}
|
||||
|
||||
void CGxMatrixStack::Pop() {
|
||||
if (this->m_level > 0) {
|
||||
this->m_level--;
|
||||
}
|
||||
|
||||
this->m_dirty = 1;
|
||||
}
|
||||
|
||||
void CGxMatrixStack::Push() {
|
||||
if (this->m_level < 3) {
|
||||
this->m_level++;
|
||||
}
|
||||
|
||||
this->m_mtx[this->m_level] = this->m_mtx[this->m_level - 1];
|
||||
this->m_flags[this->m_level] = this->m_flags[this->m_level - 1];
|
||||
|
||||
this->m_dirty = 1;
|
||||
}
|
||||
|
||||
C44Matrix& CGxMatrixStack::Top() {
|
||||
this->m_dirty = 1;
|
||||
this->m_flags[this->m_level] &= 0xFFFFFFFE;
|
||||
return this->m_mtx[this->m_level];
|
||||
}
|
||||
22
src/gx/CGxMatrixStack.hpp
Normal file
22
src/gx/CGxMatrixStack.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef GX_C_GX_MATRIX_STACK_HPP
|
||||
#define GX_C_GX_MATRIX_STACK_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <tempest/Matrix.hpp>
|
||||
|
||||
class CGxMatrixStack {
|
||||
public:
|
||||
// Member variables
|
||||
uint32_t m_level = 0;
|
||||
int8_t m_dirty = 0;
|
||||
C44Matrix m_mtx[4];
|
||||
uint32_t m_flags[4] = {};
|
||||
|
||||
// Member functions
|
||||
CGxMatrixStack();
|
||||
void Pop(void);
|
||||
void Push(void);
|
||||
C44Matrix& Top(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
85
src/gx/CGxStateBom.cpp
Normal file
85
src/gx/CGxStateBom.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#include "gx/CGxStateBom.hpp"
|
||||
#include <tempest/Vector.hpp>
|
||||
|
||||
const CGxStateBom& CGxStateBom::operator=(int32_t value) {
|
||||
this->m_data.i[0] = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CGxStateBom& CGxStateBom::operator=(uint32_t value) {
|
||||
this->m_data.i[0] = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CGxStateBom& CGxStateBom::operator=(float value) {
|
||||
this->m_data.f[0] = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CGxStateBom& CGxStateBom::operator=(void* value) {
|
||||
this->m_data.p = value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CGxStateBom& CGxStateBom::operator=(C3Vector& value) {
|
||||
this->m_data.f[0] = value.x;
|
||||
this->m_data.f[1] = value.y;
|
||||
this->m_data.f[2] = value.z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CGxStateBom::operator!=(int32_t value) {
|
||||
return this->m_data.i[0] != value;
|
||||
}
|
||||
|
||||
bool CGxStateBom::operator!=(uint32_t value) {
|
||||
return this->m_data.i[0] != value;
|
||||
}
|
||||
|
||||
bool CGxStateBom::operator!=(float value) {
|
||||
return this->m_data.f[0] != value;
|
||||
}
|
||||
|
||||
bool CGxStateBom::operator!=(void* value) {
|
||||
return this->m_data.p != value;
|
||||
}
|
||||
|
||||
bool CGxStateBom::operator!=(C3Vector& value) {
|
||||
return this->m_data.f[0] != value.x
|
||||
|| this->m_data.f[1] != value.y
|
||||
|| this->m_data.f[2] != value.z;
|
||||
}
|
||||
|
||||
bool CGxStateBom::operator!=(CGxStateBom& value) {
|
||||
return (this->m_data.i[0] - value.m_data.i[0])
|
||||
| (this->m_data.i[1] - value.m_data.i[1])
|
||||
| (this->m_data.i[2] - value.m_data.i[2])
|
||||
| (this->filler - value.filler);
|
||||
}
|
||||
|
||||
CGxStateBom::operator CImVector() const {
|
||||
CImVector color;
|
||||
color.value = this->m_data.i[0];
|
||||
return color;
|
||||
}
|
||||
|
||||
CGxStateBom::operator float() const {
|
||||
return this->m_data.f[0];
|
||||
}
|
||||
|
||||
CGxStateBom::operator int32_t() const {
|
||||
return this->m_data.i[0];
|
||||
}
|
||||
|
||||
CGxStateBom::operator uint32_t() const {
|
||||
return this->m_data.i[0];
|
||||
}
|
||||
|
||||
CGxStateBom::operator void*() const {
|
||||
return this->m_data.p;
|
||||
}
|
||||
39
src/gx/CGxStateBom.hpp
Normal file
39
src/gx/CGxStateBom.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef GX_C_GX_STATE_BOM_HPP
|
||||
#define GX_C_GX_STATE_BOM_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class C3Vector;
|
||||
class CImVector;
|
||||
|
||||
class CGxStateBom {
|
||||
public:
|
||||
// Member variables
|
||||
union {
|
||||
int32_t i[3];
|
||||
float f[3];
|
||||
void* p;
|
||||
} m_data;
|
||||
|
||||
int32_t filler;
|
||||
|
||||
// Member functions
|
||||
const CGxStateBom& operator=(float);
|
||||
const CGxStateBom& operator=(int32_t);
|
||||
const CGxStateBom& operator=(uint32_t);
|
||||
const CGxStateBom& operator=(void*);
|
||||
const CGxStateBom& operator=(C3Vector&);
|
||||
bool operator!=(float);
|
||||
bool operator!=(int32_t);
|
||||
bool operator!=(uint32_t);
|
||||
bool operator!=(void*);
|
||||
bool operator!=(C3Vector&);
|
||||
bool operator!=(CGxStateBom&);
|
||||
explicit operator CImVector() const;
|
||||
explicit operator float() const;
|
||||
explicit operator int32_t() const;
|
||||
explicit operator uint32_t() const;
|
||||
explicit operator void*() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
43
src/gx/CMakeLists.txt
Normal file
43
src/gx/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
file(GLOB GX_SOURCES
|
||||
"*.cpp"
|
||||
"buffer/*.cpp"
|
||||
"font/*.cpp"
|
||||
"shader/*.cpp"
|
||||
"texture/*.cpp"
|
||||
)
|
||||
|
||||
if(WHOA_SYSTEM_MAC)
|
||||
file(GLOB GLL_SOURCES "gll/*.cpp" "gll/*.mm")
|
||||
set_source_files_properties(${GLL_SOURCES}
|
||||
PROPERTIES COMPILE_FLAGS "-x objective-c++"
|
||||
)
|
||||
list(APPEND GX_SOURCES ${GLL_SOURCES})
|
||||
endif()
|
||||
|
||||
add_library(gx STATIC ${GX_SOURCES})
|
||||
|
||||
target_include_directories(gx
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
target_link_libraries(gx
|
||||
PRIVATE
|
||||
event
|
||||
math
|
||||
model
|
||||
ui
|
||||
util
|
||||
PUBLIC
|
||||
freetype-2.0
|
||||
storm
|
||||
tempest
|
||||
)
|
||||
|
||||
if(WHOA_SYSTEM_MAC)
|
||||
target_link_libraries(gx
|
||||
PRIVATE
|
||||
"-framework AppKit"
|
||||
"-framework OpenGL"
|
||||
)
|
||||
endif()
|
||||
70
src/gx/Camera.cpp
Normal file
70
src/gx/Camera.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include "gx/Camera.hpp"
|
||||
#include "gx/CCamera.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
#include "gx/Transform.hpp"
|
||||
#include <common/Handle.hpp>
|
||||
#include <storm/Error.hpp>
|
||||
|
||||
HCAMERA CameraCreate() {
|
||||
void* m = SMemAlloc(sizeof(CCamera), __FILE__, __LINE__, 0x0);
|
||||
auto camera = new (m) CCamera();
|
||||
return HandleCreate(camera);
|
||||
}
|
||||
|
||||
void CameraSetupScreenProjection(const CRect& projectionRect, const C2Vector& screenPoint, float depth, int32_t a4) {
|
||||
float offsetX = (projectionRect.minX + projectionRect.maxX) * 0.5f;
|
||||
float offsetY = (projectionRect.minY + projectionRect.maxY) * 0.5f;
|
||||
|
||||
CRect frustumRect = {
|
||||
projectionRect.minY - offsetY,
|
||||
projectionRect.minX - offsetX,
|
||||
projectionRect.maxY - offsetY,
|
||||
projectionRect.maxX - offsetX
|
||||
};
|
||||
|
||||
float minZ = -500.0f;
|
||||
float maxZ = 500.0f;
|
||||
|
||||
C44Matrix proj;
|
||||
|
||||
if (a4 || !g_theGxDevicePtr->StereoEnabled()) {
|
||||
GxuXformCreateOrtho(
|
||||
frustumRect.minX,
|
||||
frustumRect.maxX,
|
||||
frustumRect.minY,
|
||||
frustumRect.maxY,
|
||||
minZ,
|
||||
maxZ,
|
||||
proj
|
||||
);
|
||||
|
||||
C3Vector v50 = { 1.0f, 1.0f, -1.0f };
|
||||
proj.Scale(v50);
|
||||
} else {
|
||||
GxuXformCreateOrthoDepth(
|
||||
frustumRect.minX,
|
||||
frustumRect.maxX,
|
||||
frustumRect.minY,
|
||||
frustumRect.maxY,
|
||||
minZ,
|
||||
maxZ,
|
||||
proj
|
||||
);
|
||||
}
|
||||
|
||||
// TODO some caps stuff
|
||||
|
||||
GxXformSetProjection(proj);
|
||||
|
||||
C44Matrix view;
|
||||
C3Vector move = { screenPoint.x - offsetX, screenPoint.y - offsetY, 0.0f };
|
||||
view.Translate(move);
|
||||
|
||||
GxXformSetView(view);
|
||||
}
|
||||
|
||||
void CameraSetupWorldProjection(HCAMERA camera, const CRect& projectionRect, uint32_t flags) {
|
||||
auto cameraPtr = reinterpret_cast<CCamera*>(camera);
|
||||
STORM_ASSERT(cameraPtr);
|
||||
cameraPtr->SetupWorldProjection(projectionRect, flags);
|
||||
}
|
||||
18
src/gx/Camera.hpp
Normal file
18
src/gx/Camera.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef GX_CAMERA_HPP
|
||||
#define GX_CAMERA_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <common/DataMgr.hpp>
|
||||
|
||||
typedef HDATAMGR HCAMERA;
|
||||
|
||||
class CRect;
|
||||
class C2Vector;
|
||||
|
||||
HCAMERA CameraCreate(void);
|
||||
|
||||
void CameraSetupScreenProjection(const CRect&, const C2Vector&, float, int32_t);
|
||||
|
||||
void CameraSetupWorldProjection(HCAMERA camera, const CRect& projectionRect, uint32_t flags);
|
||||
|
||||
#endif
|
||||
58
src/gx/Coordinate.cpp
Normal file
58
src/gx/Coordinate.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include "gx/Coordinate.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace Coordinate {
|
||||
float s_aspect = 1.333333f;
|
||||
float s_aspectCompensation = 1.0f;
|
||||
float s_y = 0.6f;
|
||||
float s_x = 0.8f;
|
||||
}
|
||||
|
||||
float CoordinateGetAspectCompensation() {
|
||||
return Coordinate::s_aspectCompensation;
|
||||
}
|
||||
|
||||
void CoordinateSetAspectRatio(float aspect) {
|
||||
Coordinate::s_aspect = aspect;
|
||||
Coordinate::s_aspectCompensation = aspect * 0.75;
|
||||
|
||||
float v1 = 1.0 / sqrt(aspect * aspect + 1.0);
|
||||
Coordinate::s_y = v1;
|
||||
Coordinate::s_x = aspect * v1;
|
||||
}
|
||||
|
||||
void DDCToNDC(float ddcx, float ddcy, float* ndcx, float* ndcy) {
|
||||
if (ndcx) {
|
||||
*ndcx = ddcx / Coordinate::s_x;
|
||||
}
|
||||
|
||||
if (ndcy) {
|
||||
*ndcy = ddcy / Coordinate::s_y;
|
||||
}
|
||||
}
|
||||
|
||||
float DDCToNDCHeight(float ddcy) {
|
||||
return ddcy / Coordinate::s_y;
|
||||
}
|
||||
|
||||
float DDCToNDCWidth(float ddcx) {
|
||||
return ddcx / Coordinate::s_x;
|
||||
}
|
||||
|
||||
void NDCToDDC(float ndcx, float ndcy, float* ddcx, float* ddcy) {
|
||||
if (ddcx) {
|
||||
*ddcx = Coordinate::s_x * ndcx;
|
||||
}
|
||||
|
||||
if (ddcy) {
|
||||
*ddcy = Coordinate::s_y * ndcy;
|
||||
}
|
||||
}
|
||||
|
||||
float NDCToDDCHeight(float ndcy) {
|
||||
return Coordinate::s_y * ndcy;
|
||||
}
|
||||
|
||||
float NDCToDDCWidth(float ndcx) {
|
||||
return Coordinate::s_x * ndcx;
|
||||
}
|
||||
20
src/gx/Coordinate.hpp
Normal file
20
src/gx/Coordinate.hpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef GX_COORDINATE_HPP
|
||||
#define GX_COORDINATE_HPP
|
||||
|
||||
float CoordinateGetAspectCompensation(void);
|
||||
|
||||
void CoordinateSetAspectRatio(float);
|
||||
|
||||
void DDCToNDC(float, float, float*, float*);
|
||||
|
||||
float DDCToNDCHeight(float);
|
||||
|
||||
float DDCToNDCWidth(float);
|
||||
|
||||
void NDCToDDC(float, float, float*, float*);
|
||||
|
||||
float NDCToDDCHeight(float);
|
||||
|
||||
float NDCToDDCWidth(float);
|
||||
|
||||
#endif
|
||||
51
src/gx/Device.cpp
Normal file
51
src/gx/Device.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include "gx/Device.hpp"
|
||||
#include "gx/CGxDevice.hpp"
|
||||
#include "gx/Gx.hpp"
|
||||
|
||||
CGxDevice* g_theGxDevicePtr = nullptr;
|
||||
|
||||
CGxDevice* GxDevCreate(EGxApi api, long (*windowProc)(void*, uint32_t, uint32_t, long), const CGxFormat& format) {
|
||||
CGxDevice* device;
|
||||
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
if (api == GxApi_OpenGl) {
|
||||
device = CGxDevice::NewOpenGl();
|
||||
} else if (api == GxApi_D3d9) {
|
||||
device = CGxDevice::NewD3d();
|
||||
} else if (api == GxApi_D3d9Ex) {
|
||||
device = CGxDevice::NewD3d9Ex();
|
||||
} else {
|
||||
// Error
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC)
|
||||
if (api == GxApi_OpenGl) {
|
||||
device = CGxDevice::NewOpenGl();
|
||||
} else if (api == GxApi_GLL) {
|
||||
device = CGxDevice::NewGLL();
|
||||
} else {
|
||||
// Error
|
||||
}
|
||||
#endif
|
||||
|
||||
g_theGxDevicePtr = device;
|
||||
|
||||
if (g_theGxDevicePtr->DeviceCreate(windowProc, format)) {
|
||||
return g_theGxDevicePtr;
|
||||
} else {
|
||||
if (g_theGxDevicePtr) {
|
||||
delete g_theGxDevicePtr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
EGxApi GxDevApi() {
|
||||
return g_theGxDevicePtr->m_api;
|
||||
}
|
||||
|
||||
int32_t GxMasterEnable(EGxMasterEnables state) {
|
||||
return g_theGxDevicePtr->MasterEnable(state);
|
||||
}
|
||||
18
src/gx/Device.hpp
Normal file
18
src/gx/Device.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef GX_DEVICE_HPP
|
||||
#define GX_DEVICE_HPP
|
||||
|
||||
#include "gx/CGxDevice.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class CGxFormat;
|
||||
|
||||
extern CGxDevice* g_theGxDevicePtr;
|
||||
|
||||
CGxDevice* GxDevCreate(EGxApi, long (*)(void*, uint32_t, uint32_t, long), const CGxFormat&);
|
||||
|
||||
EGxApi GxDevApi(void);
|
||||
|
||||
int32_t GxMasterEnable(EGxMasterEnables state);
|
||||
|
||||
#endif
|
||||
21
src/gx/Draw.cpp
Normal file
21
src/gx/Draw.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include "gx/Draw.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
|
||||
void GxDraw(CGxBatch* batches, int32_t count) {
|
||||
g_theGxDevicePtr->Draw(batches, count);
|
||||
}
|
||||
|
||||
void GxSceneClear(uint32_t mask, CImVector color) {
|
||||
g_theGxDevicePtr->SceneClear(mask, color);
|
||||
}
|
||||
|
||||
void GxScenePresent() {
|
||||
C3Vector v2 = { 0.0f, 0.0f, 0.0f };
|
||||
GxuFlushDrawList(GxuCat_2, v2);
|
||||
|
||||
g_theGxDevicePtr->ScenePresent();
|
||||
}
|
||||
|
||||
void GxuFlushDrawList(EGxuDrawListCategory a1, const C3Vector& a2) {
|
||||
// TODO
|
||||
}
|
||||
19
src/gx/Draw.hpp
Normal file
19
src/gx/Draw.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef GX_DRAW_HPP
|
||||
#define GX_DRAW_HPP
|
||||
|
||||
#include "gx/CGxBatch.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class C3Vector;
|
||||
class CImVector;
|
||||
|
||||
void GxDraw(CGxBatch*, int32_t);
|
||||
|
||||
void GxSceneClear(uint32_t, CImVector);
|
||||
|
||||
void GxScenePresent(void);
|
||||
|
||||
void GxuFlushDrawList(EGxuDrawListCategory, const C3Vector&);
|
||||
|
||||
#endif
|
||||
996
src/gx/Font.cpp
Normal file
996
src/gx/Font.cpp
Normal file
|
|
@ -0,0 +1,996 @@
|
|||
#include "gx/Font.hpp"
|
||||
#include "gx/font/CGxFont.hpp"
|
||||
#include "gx/font/CGxString.hpp"
|
||||
#include "gx/font/CGxStringBatch.hpp"
|
||||
#include "gx/font/Wrap.hpp"
|
||||
#include "gx/Coordinate.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
#include "gx/FontInternal.hpp"
|
||||
#include "gx/Gx.hpp"
|
||||
#include "gx/Shader.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <storm/Error.hpp>
|
||||
#include <storm/Memory.hpp>
|
||||
#include <storm/String.hpp>
|
||||
#include <storm/Unicode.hpp>
|
||||
#include <tempest/Math.hpp>
|
||||
|
||||
CGxShader* g_fontPixelShader[1];
|
||||
CGxShader* g_fontVertexShader[2];
|
||||
TSList<CGxFont, TSGetLink<CGxFont>> g_fonts;
|
||||
TSHashTable<FONTHASHOBJ, HASHKEY_STR> s_fontHash;
|
||||
uint32_t g_heightPixels;
|
||||
uint32_t g_widthPixels;
|
||||
float g_indentPixelWidth;
|
||||
float g_indentNormWidth;
|
||||
TSList<CGxStringBatch, TSGetLink<CGxStringBatch>> s_unusedBatches;
|
||||
STORM_LIST(CGxString) g_freeStrings;
|
||||
STORM_LIST(CGxString) g_strings;
|
||||
|
||||
FONTHASHOBJ::~FONTHASHOBJ() {
|
||||
if (this->font) {
|
||||
GxuFontDestroyFont(this->font);
|
||||
}
|
||||
}
|
||||
|
||||
TEXTBLOCK::~TEXTBLOCK() {
|
||||
GxuFontDestroyString(this->string);
|
||||
}
|
||||
|
||||
void CalculateYOffset(uint32_t pixelHeight, uint32_t a2, FT_Face face, uint32_t glyphHeight, int32_t* yOffset, int32_t* yStart) {
|
||||
uint32_t v6 = 0;
|
||||
int32_t v8 = 0;
|
||||
|
||||
if (glyphHeight <= pixelHeight) {
|
||||
uint32_t v9 = face->glyph->bitmap_top;
|
||||
|
||||
if (v9 <= a2) {
|
||||
v8 = a2 - v9;
|
||||
} else {
|
||||
v8 = 0;
|
||||
v6 = v9 - a2;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t v10 = v8 <= 0 ? 0 : v8;
|
||||
uint32_t v11 = pixelHeight - glyphHeight;
|
||||
|
||||
if (v11 >= v10) {
|
||||
*yOffset = v6;
|
||||
*yStart = v10;
|
||||
} else {
|
||||
*yOffset = pixelHeight - v10 - glyphHeight;
|
||||
*yStart = v11;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ConvertStringFlags(uint32_t flags) {
|
||||
uint32_t convertedFlags = 0x0;
|
||||
|
||||
if (flags & 0x100) {
|
||||
convertedFlags |= 0x1;
|
||||
}
|
||||
|
||||
if (flags & 0x200) {
|
||||
convertedFlags |= 0x4;
|
||||
}
|
||||
|
||||
if (flags & 0x400) {
|
||||
convertedFlags |= 0x8;
|
||||
}
|
||||
|
||||
if (flags & 0x800) {
|
||||
convertedFlags |= 0x10;
|
||||
}
|
||||
|
||||
if (flags & 0x40) {
|
||||
convertedFlags |= 0x2;
|
||||
}
|
||||
|
||||
if (flags & 0x1000) {
|
||||
convertedFlags |= 0x40;
|
||||
}
|
||||
|
||||
if (flags & 0x2000) {
|
||||
convertedFlags |= 0x100;
|
||||
}
|
||||
|
||||
if (flags & 0x4000) {
|
||||
convertedFlags |= 0x200;
|
||||
}
|
||||
|
||||
if (flags & 0x8000) {
|
||||
convertedFlags |= 0x400;
|
||||
}
|
||||
|
||||
if (flags & 0x80) {
|
||||
convertedFlags |= 0x800;
|
||||
}
|
||||
|
||||
if (flags & 0x10000) {
|
||||
convertedFlags |= 0x1000;
|
||||
}
|
||||
|
||||
if (flags & 0x20000) {
|
||||
convertedFlags |= 0x2000;
|
||||
}
|
||||
|
||||
return convertedFlags;
|
||||
}
|
||||
|
||||
float GetCharacterWidth(const char* text, uint32_t flags, uint32_t prevCode, CGxFont* font, float a5) {
|
||||
if (!prevCode) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float width = 0.0f;
|
||||
|
||||
while (*text) {
|
||||
int32_t advance;
|
||||
uint32_t code;
|
||||
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, flags, code);
|
||||
|
||||
text += advance;
|
||||
|
||||
if (quotedCode == CODE_INVALIDCODE) {
|
||||
if (flags & 0x10) {
|
||||
// TODO
|
||||
// width = font->ComputeStepFixedWidth(prevCode, code);
|
||||
} else {
|
||||
width = font->ComputeStep(prevCode, code);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (quotedCode == CODE_NEWLINE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (width == 0.0f) {
|
||||
auto glyph = font->NewCodeDesc(prevCode);
|
||||
|
||||
if (glyph) {
|
||||
width = font->GetGlyphBearing(glyph, flags & 0x80, a5) + glyph->bitmapData.m_glyphCellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
float GetIndentNormWidth() {
|
||||
return g_indentNormWidth;
|
||||
}
|
||||
|
||||
float GetIndentPixelWidth() {
|
||||
return g_indentPixelWidth;
|
||||
}
|
||||
|
||||
uint32_t GetScreenPixelHeight() {
|
||||
return g_heightPixels;
|
||||
}
|
||||
|
||||
uint32_t GetScreenPixelWidth() {
|
||||
return g_widthPixels;
|
||||
}
|
||||
|
||||
QUOTEDCODE GxuDetermineQuotedCode(const char* text, int32_t& advance, CImVector* color, uint32_t flags, uint32_t& wide) {
|
||||
wide = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(text), &advance);
|
||||
|
||||
switch (wide) {
|
||||
case 0x0:
|
||||
case 0xFFFFFFFF:
|
||||
return CODE_INVALIDCODE;
|
||||
|
||||
case '\r':
|
||||
advance = 2 - (SUniSGetUTF8(reinterpret_cast<const uint8_t*>(text + 1), &advance) != '\n');
|
||||
return CODE_NEWLINE;
|
||||
|
||||
case '\n':
|
||||
advance = 1;
|
||||
return CODE_NEWLINE;
|
||||
}
|
||||
|
||||
if (wide != '|' || flags & 0x800) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
auto quotedCode = text[advance];
|
||||
|
||||
if (!quotedCode) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
switch (quotedCode) {
|
||||
case 'N':
|
||||
case 'n': {
|
||||
if (flags & 0x200) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = 2;
|
||||
return CODE_NEWLINE;
|
||||
}
|
||||
|
||||
// TODO handle other control codes
|
||||
}
|
||||
|
||||
// TODO remainder of function
|
||||
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
int32_t GxuFontAddToBatch(CGxStringBatch* batch, CGxString* string) {
|
||||
if (batch && string) {
|
||||
batch->AddString(string);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GxuFontAddShadow(CGxString* string, const CImVector& color, const C2Vector& offset) {
|
||||
if (string) {
|
||||
if (!(string->m_flags & 0x80)) {
|
||||
string->AddShadow(offset, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGxStringBatch* GxuFontCreateBatch(bool a1, bool a2) {
|
||||
CGxStringBatch* batch;
|
||||
|
||||
if (s_unusedBatches.Head()) {
|
||||
batch = s_unusedBatches.Head();
|
||||
s_unusedBatches.UnlinkNode(batch);
|
||||
} else {
|
||||
void* m = SMemAlloc(sizeof(CGxStringBatch), __FILE__, __LINE__, 0x8);
|
||||
batch = new (m) CGxStringBatch();
|
||||
}
|
||||
|
||||
if (a1) {
|
||||
batch->m_flags |= 0x1;
|
||||
} else {
|
||||
batch->m_flags &= ~0x1;
|
||||
}
|
||||
|
||||
if (a2) {
|
||||
batch->m_flags |= 0x2;
|
||||
} else {
|
||||
batch->m_flags &= ~0x2;
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
int32_t GxuFontCreateFont(const char* name, float fontHeight, CGxFont*& face, uint32_t flags) {
|
||||
STORM_ASSERT(name);
|
||||
STORM_ASSERT(*name);
|
||||
STORM_ASSERT((fontHeight <= 1.0f) && (fontHeight > 0.0f));
|
||||
|
||||
CGxFont* newFace = g_fonts.NewNode(2, 0, 0);
|
||||
|
||||
uint32_t v12 = flags;
|
||||
|
||||
if (flags & 0x8) {
|
||||
v12 |= 0x1;
|
||||
}
|
||||
|
||||
int32_t v13 = newFace->Initialize(name, v12, fontHeight);
|
||||
|
||||
if (!v13) {
|
||||
g_fonts.DeleteNode(newFace);
|
||||
newFace = nullptr;
|
||||
}
|
||||
|
||||
face = newFace;
|
||||
|
||||
return v13;
|
||||
}
|
||||
|
||||
int32_t GxuFontCreateString(CGxFont* face, const char* text, float fontHeight, const C3Vector& position, float blockWidth, float blockHeight, float spacing, CGxString*& string, EGxFontVJusts vertJustification, EGxFontHJusts horzJustification, uint32_t flags, const CImVector& color, float charSpacing, float scale) {
|
||||
STORM_ASSERT(face);
|
||||
STORM_ASSERT(text);
|
||||
// TODO
|
||||
// STORM_ASSERT(fontHeight || (flags & EGxStringFlags_FixedSize));
|
||||
STORM_ASSERT(vertJustification < GxVJ_Last);
|
||||
STORM_ASSERT(horzJustification < GxHJ_Last);
|
||||
|
||||
auto newString = CGxString::GetNewString(1);
|
||||
|
||||
int32_t result = newString->Initialize(
|
||||
fontHeight,
|
||||
position,
|
||||
blockWidth,
|
||||
blockHeight,
|
||||
face,
|
||||
text,
|
||||
vertJustification,
|
||||
horzJustification,
|
||||
spacing,
|
||||
flags & ~0x1,
|
||||
color,
|
||||
scale
|
||||
);
|
||||
|
||||
if (result) {
|
||||
string = newString;
|
||||
} else {
|
||||
GxuFontDestroyString(newString);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t GxuFontDestroyBatch(CGxStringBatch* batch) {
|
||||
if (!batch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
batch->m_fontBatch.Clear();
|
||||
|
||||
s_unusedBatches.LinkToTail(batch);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GxuFontDestroyFont(CGxFont*& font) {
|
||||
if (font) {
|
||||
g_fonts.DeleteNode(font);
|
||||
}
|
||||
|
||||
font = nullptr;
|
||||
}
|
||||
|
||||
void GxuFontDestroyString(CGxString*& string) {
|
||||
if (string) {
|
||||
string->Unlink();
|
||||
string->Recycle();
|
||||
string = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GxuFontGetFontFlags(CGxFont* font) {
|
||||
if (font) {
|
||||
return font->m_flags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* GxuFontGetFontName(CGxFont* font) {
|
||||
return font
|
||||
? font->GetName()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
uint32_t GxuFontGetMaxCharsWithinWidth(CGxFont* font, const char* text, float height, float maxWidth, uint32_t lineBytes, float* extent, float a7, float scale, float a9, uint32_t flags) {
|
||||
return InternalGetMaxCharsWithinWidth(
|
||||
font,
|
||||
text,
|
||||
height,
|
||||
maxWidth,
|
||||
lineBytes,
|
||||
extent,
|
||||
flags,
|
||||
a7,
|
||||
scale,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t GxuFontGetMaxCharsWithinWidthAndHeight(CGxFont* font, const char* text, float fontHeight, float maxWidth, float maxHeight, uint32_t lineBytes, float a7, float scale, float a9, uint32_t flags) {
|
||||
if (!font) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text || !*text) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fontHeight == 0.0f || maxWidth == 0.0f || maxHeight == 0.0f || g_heightPixels == 0.0f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lineBytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & 0x4) {
|
||||
fontHeight = GxuFontGetOneToOneHeight(font);
|
||||
}
|
||||
|
||||
auto v24 = static_cast<float>(g_heightPixels) * a9;
|
||||
auto v22 = CMath::fuint_pi(v24);
|
||||
auto v12 = static_cast<float>(v22) / static_cast<float>(g_heightPixels);
|
||||
bool v26 = true;
|
||||
auto v27 = v12;
|
||||
v24 = 0.0f;
|
||||
auto v13 = fontHeight;
|
||||
const char* nextText;
|
||||
|
||||
uint32_t maxChars = 0;
|
||||
|
||||
auto currentText = text;
|
||||
int32_t v25 = 0;
|
||||
while (*currentText) {
|
||||
if (flags & 0x2000 && v25 == 1) {
|
||||
maxWidth -= g_indentNormWidth;
|
||||
}
|
||||
|
||||
float v21;
|
||||
CalcWrapPoint(
|
||||
font,
|
||||
currentText,
|
||||
fontHeight,
|
||||
maxWidth,
|
||||
&v22,
|
||||
&v21,
|
||||
&nextText,
|
||||
a7,
|
||||
flags,
|
||||
&v26,
|
||||
0,
|
||||
scale
|
||||
);
|
||||
|
||||
v22 = nextText - currentText;
|
||||
if (nextText == currentText) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto v15 = v24;
|
||||
auto v16 = v25 + 1 < 0;
|
||||
auto v17 = v24 + fontHeight;
|
||||
|
||||
v25++;
|
||||
|
||||
float v18 = v25;
|
||||
|
||||
if (v16) {
|
||||
v18 = v18 + 4294967300.0;
|
||||
}
|
||||
|
||||
if (v18 * 0.00000095367431640625 + maxHeight < v17) {
|
||||
break;
|
||||
}
|
||||
|
||||
maxChars += nextText - currentText;
|
||||
currentText = nextText;
|
||||
v24 = fontHeight + v15 + v27;
|
||||
|
||||
if (!v26 || !nextText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return maxChars;
|
||||
}
|
||||
|
||||
float GxuFontGetOneToOneHeight(CGxFont* font) {
|
||||
STORM_ASSERT(font);
|
||||
|
||||
return PixelToScreenHeight(font->GetPixelSize());
|
||||
}
|
||||
|
||||
void GxuFontGetTextExtent(CGxFont* font, const char* text, uint32_t numBytes, float a4, float* extent, float a6, float a7, float a8, uint32_t flags) {
|
||||
InternalGetTextExtent(font, text, numBytes, a4, extent, flags, a6, a7);
|
||||
}
|
||||
|
||||
float GxuFontGetWrappedTextHeight(CGxFont* font, const char* text, float a3, float a4, const C2Vector& a5, float a6, float a7, uint32_t flags) {
|
||||
STORM_ASSERT(font);
|
||||
STORM_ASSERT(text);
|
||||
|
||||
if (flags & 0x04) {
|
||||
a3 = GxuFontGetOneToOneHeight(font);
|
||||
}
|
||||
|
||||
int32_t advance;
|
||||
uint32_t numBytes;
|
||||
uint32_t code;
|
||||
int32_t v8 = 0;
|
||||
float extent = 0.0f;
|
||||
float v17 = 0.0f;
|
||||
float v18 = 0.0f;
|
||||
const char* currentText = text;
|
||||
const char* nextText = nullptr;
|
||||
bool v21 = true;
|
||||
|
||||
while (currentText && *currentText) {
|
||||
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(currentText, advance, nullptr, flags, code);
|
||||
|
||||
if (flags & 0x2000 && v8 == 1) {
|
||||
a4 = a4 - g_indentNormWidth;
|
||||
}
|
||||
|
||||
if (quotedCode == CODE_NEWLINE) {
|
||||
nextText = currentText + advance;
|
||||
} else {
|
||||
CalcWrapPoint(
|
||||
font,
|
||||
currentText,
|
||||
a3,
|
||||
a4,
|
||||
&numBytes,
|
||||
&extent,
|
||||
&nextText,
|
||||
a5.x,
|
||||
flags,
|
||||
&v21,
|
||||
&v17,
|
||||
a6
|
||||
);
|
||||
|
||||
if (currentText == nextText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v8++;
|
||||
currentText = nextText;
|
||||
|
||||
float v14 = (float)GetScreenPixelHeight() * a3;
|
||||
if (v14 < v17) {
|
||||
v18 = v17 - v14 + v18;
|
||||
}
|
||||
|
||||
if (flags & 0x02) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & 0x02) && currentText > text && GxuDetermineQuotedCode(currentText - 1, advance, nullptr, flags, code) == CODE_NEWLINE) {
|
||||
v8++;
|
||||
}
|
||||
|
||||
if (!v8) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float v22 = GetScreenPixelHeight();
|
||||
float v14 = v22 * a7;
|
||||
float v13 = v14 + 0.99994999f;
|
||||
float v23 = v13 / v22;
|
||||
|
||||
return (v18 / v22 + v23 * (float)(v8 - 1) + (float)v8 * a3);
|
||||
}
|
||||
|
||||
void GxuFontInitialize() {
|
||||
g_theGxDevicePtr->ShaderCreate(g_fontVertexShader, GxSh_Vertex, "Shaders\\Vertex", "UI", 2);
|
||||
g_theGxDevicePtr->ShaderCreate(g_fontPixelShader, GxSh_Pixel, "Shaders\\Pixel", "UI", 1);
|
||||
|
||||
BATCHEDRENDERFONTDESC::Initialize();
|
||||
|
||||
FreeTypeInitialize();
|
||||
|
||||
GxuFontWindowSizeChanged();
|
||||
|
||||
// TODO
|
||||
// sub_6BD160();
|
||||
}
|
||||
|
||||
void GxuFontRenderBatch(CGxStringBatch* batch) {
|
||||
if (batch) {
|
||||
batch->RenderBatch();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GxuFontSetStringColor(CGxString* string, const CImVector& color) {
|
||||
STORM_ASSERT(string);
|
||||
|
||||
string->SetColor(color);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GxuFontSetStringPosition(CGxString* string, const C3Vector& position) {
|
||||
STORM_ASSERT(string);
|
||||
|
||||
string->SetStringPosition(position);
|
||||
}
|
||||
|
||||
void GxuFontUpdate() {
|
||||
for (auto string = g_strings.Head(); string; string = g_strings.Link(string)->Next()) {
|
||||
string->Tick();
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GxuFontWindowSizeChanged() {
|
||||
static CRect s_currentRect = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
CRect rect = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
GxCapsWindowSize(rect);
|
||||
|
||||
if (rect.maxY - rect.minY == 0.0f || rect.maxX - rect.minX == 0.0f) {
|
||||
rect = { 0.0f, 0.0f, 480.0f, 640.0f };
|
||||
}
|
||||
|
||||
if (s_currentRect == rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_currentRect = rect;
|
||||
|
||||
g_widthPixels = rect.maxX - rect.minX;
|
||||
g_heightPixels = rect.maxY - rect.minY;
|
||||
g_indentPixelWidth = 15.0f;
|
||||
g_indentNormWidth = 15.0f / (rect.maxX - rect.minX);
|
||||
|
||||
// TODO
|
||||
// - walk s_fonts and trigger HandleScreenSizeChange
|
||||
}
|
||||
|
||||
int32_t IGxuFontGlyphRenderGlyph(FT_Face face, uint32_t pixelHeight, uint32_t code, uint32_t baseline, GLYPHBITMAPDATA* dataPtr, int32_t monochrome, uint32_t a7) {
|
||||
STORM_ASSERT(face);
|
||||
STORM_ASSERT(pixelHeight);
|
||||
STORM_ASSERT(dataPtr);
|
||||
|
||||
if (!FT_Get_Char_Index(face, code)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!FREETYPE_RenderGlyph(code, monochrome != 0, face)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto glyph = face->glyph;
|
||||
|
||||
uint32_t width = glyph->bitmap.width;
|
||||
uint32_t height = std::min(static_cast<uint32_t>(glyph->bitmap.rows), pixelHeight);
|
||||
size_t dataSize = glyph->bitmap.pitch * glyph->bitmap.rows;
|
||||
auto srcData = glyph->bitmap.buffer;
|
||||
uint32_t pitch = glyph->bitmap.pitch;
|
||||
|
||||
int32_t dummyGlyph = 0;
|
||||
|
||||
if (!width || !height || !srcData || !pitch || !dataSize) {
|
||||
width = (pixelHeight + 3) >> 2;
|
||||
height = pixelHeight;
|
||||
|
||||
if (!width) {
|
||||
width = pixelHeight;
|
||||
}
|
||||
|
||||
if (monochrome) {
|
||||
pitch = (width + 7) & 0xFFFFFFF8;
|
||||
} else {
|
||||
pitch = width;
|
||||
}
|
||||
|
||||
dataSize = pixelHeight * pitch;
|
||||
dummyGlyph = 1;
|
||||
}
|
||||
|
||||
void* data = SMemAlloc(dataSize, __FILE__, __LINE__, 0x0);
|
||||
|
||||
if (data) {
|
||||
memset(data, 0, dataSize);
|
||||
}
|
||||
|
||||
if (srcData) {
|
||||
memcpy(data, srcData, dataSize);
|
||||
}
|
||||
|
||||
dataPtr->m_data = data;
|
||||
dataPtr->m_dataSize = dataSize;
|
||||
dataPtr->m_glyphPitch = pitch;
|
||||
dataPtr->m_glyphWidth = width;
|
||||
dataPtr->m_glyphHeight = height;
|
||||
dataPtr->m_glyphCellWidth = width + a7;
|
||||
dataPtr->m_glyphAdvance = (double)(face->glyph->metrics.horiAdvance / 64) + 1.0;
|
||||
dataPtr->m_glyphBearing = (double)face->glyph->metrics.horiBearingX * 0.015625;
|
||||
dataPtr->m_yOffset = 0;
|
||||
dataPtr->m_yStart = 0;
|
||||
|
||||
if (width && height && data && !dummyGlyph) {
|
||||
CalculateYOffset(pixelHeight, baseline, face, height, &dataPtr->m_yOffset, &dataPtr->m_yStart);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
float PixelToScreenHeight(int32_t height) {
|
||||
return (double)height / (double)g_heightPixels;
|
||||
}
|
||||
|
||||
float PixelToScreenWidth(int32_t width) {
|
||||
return (double)width / (double)g_widthPixels;
|
||||
}
|
||||
|
||||
float PixelToScreenWidth(float width) {
|
||||
return width / (double)g_widthPixels;
|
||||
}
|
||||
|
||||
float ScreenToPixelHeight(int32_t billboarded, float height) {
|
||||
if (billboarded) {
|
||||
return height;
|
||||
}
|
||||
|
||||
float pixelCoords = static_cast<double>(g_heightPixels) * height;
|
||||
return CMath::fint_n(pixelCoords);
|
||||
}
|
||||
|
||||
float ScreenToPixelWidth(int32_t billboarded, float width) {
|
||||
if (billboarded) {
|
||||
return width;
|
||||
}
|
||||
|
||||
float pixelCoords = static_cast<double>(g_widthPixels) * width;
|
||||
return CMath::fint_n(pixelCoords);
|
||||
}
|
||||
|
||||
float Sub6C2280(FT_Face face, float height) {
|
||||
int32_t numFixedSizes = face->num_fixed_sizes;
|
||||
|
||||
if (numFixedSizes == 0) {
|
||||
return height;
|
||||
}
|
||||
|
||||
int32_t v4 = INT_MAX;
|
||||
|
||||
auto availableSizes = face->available_sizes;
|
||||
|
||||
for (int32_t i = 0; i < numFixedSizes; i++) {
|
||||
if (v4 >= availableSizes->height) {
|
||||
v4 = availableSizes->height;
|
||||
}
|
||||
|
||||
availableSizes++;
|
||||
}
|
||||
|
||||
float v7 = PixelToScreenHeight(v4);
|
||||
|
||||
return v7 >= height ? v7 : height;
|
||||
}
|
||||
|
||||
void TextBlockAddShadow(HTEXTBLOCK string, CImVector color, const C2Vector& offset) {
|
||||
STORM_ASSERT(string);
|
||||
|
||||
C2Vector ndcOffset;
|
||||
DDCToNDC(offset.x, offset.y, &ndcOffset.x, &ndcOffset.y);
|
||||
|
||||
GxuFontAddShadow(TextBlockGetStringPtr(string), color, offset);
|
||||
}
|
||||
|
||||
HTEXTBLOCK TextBlockCreate(HTEXTFONT font, const char* text, const CImVector& color, const C3Vector& pos, float fontHeight, float blockWidth, float blockHeight, uint32_t flags, float charSpacing, float lineSpacing, float scale) {
|
||||
STORM_ASSERT(font);
|
||||
STORM_ASSERT(text);
|
||||
|
||||
void* m = SMemAlloc(sizeof(TEXTBLOCK), __FILE__, __LINE__, 0x0);
|
||||
auto textBlock = new (m) TEXTBLOCK();
|
||||
|
||||
C3Vector position = { 0.0f, 0.0f, pos.z };
|
||||
DDCToNDC(pos.x, pos.y, &position.x, &position.y);
|
||||
|
||||
EGxFontHJusts hjust = GxHJ_Center;
|
||||
|
||||
if (flags & 0x4) {
|
||||
hjust = GxHJ_Right;
|
||||
} else if (!(flags & 0x2) && flags & 0x1) {
|
||||
hjust = GxHJ_Left;
|
||||
}
|
||||
|
||||
EGxFontVJusts vjust = GxVJ_Middle;
|
||||
|
||||
if (flags & 0x8) {
|
||||
vjust = GxVJ_Top;
|
||||
} else if (flags & 0x20) {
|
||||
vjust = GxVJ_Bottom;
|
||||
}
|
||||
|
||||
uint32_t v16 = ConvertStringFlags(flags);
|
||||
|
||||
float v15 = DDCToNDCWidth(charSpacing);
|
||||
float v20 = DDCToNDCHeight(lineSpacing);
|
||||
float v21 = DDCToNDCHeight(blockHeight);
|
||||
float v22 = DDCToNDCWidth(blockWidth);
|
||||
float v23 = DDCToNDCHeight(fontHeight);
|
||||
|
||||
GxuFontCreateString(
|
||||
reinterpret_cast<FONTHASHOBJ*>(font)->font,
|
||||
text,
|
||||
v23,
|
||||
position,
|
||||
v22,
|
||||
v21,
|
||||
v20,
|
||||
textBlock->string,
|
||||
vjust,
|
||||
hjust,
|
||||
v16,
|
||||
color,
|
||||
v15,
|
||||
scale
|
||||
);
|
||||
|
||||
return HandleCreate(textBlock);
|
||||
}
|
||||
|
||||
HTEXTFONT TextBlockGenerateFont(const char* fontName, uint32_t fontFlags, float fontHeight) {
|
||||
STORM_ASSERT(fontName);
|
||||
STORM_ASSERT(*fontName);
|
||||
|
||||
float fontHeightNDC = DDCToNDCHeight(fontHeight);
|
||||
|
||||
if (fontHeightNDC >= 1.0) {
|
||||
fontHeightNDC = 1.0;
|
||||
}
|
||||
|
||||
char hashKey[276];
|
||||
|
||||
SStrPrintf(hashKey, 276, "%s-%d-%f", fontName, fontFlags, fontHeightNDC);
|
||||
|
||||
auto v7 = s_fontHash.Ptr(hashKey);
|
||||
|
||||
if (v7) {
|
||||
return HandleCreate(v7);
|
||||
}
|
||||
|
||||
v7 = s_fontHash.New(hashKey, 0, 0);
|
||||
|
||||
uint32_t v14 = 0;
|
||||
|
||||
if (fontFlags & FONT_OUTLINE) {
|
||||
v14 |= 0x1;
|
||||
}
|
||||
|
||||
if (fontFlags & FONT_THICKOUTLINE) {
|
||||
v14 |= 0x8;
|
||||
}
|
||||
|
||||
if (fontFlags & FONT_MONOCHROME) {
|
||||
v14 |= 0x2;
|
||||
}
|
||||
|
||||
if (GxuFontCreateFont(fontName, fontHeightNDC, v7->font, v14)) {
|
||||
return HandleCreate(v7);
|
||||
} else {
|
||||
// TODO
|
||||
// sub_723270(v12);
|
||||
// (s_fontHash)(&s_fontHash, v12);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TextBlockGetFontFlags(HTEXTFONT fontHandle) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
|
||||
uint32_t gxFlags = GxuFontGetFontFlags(TextBlockGetFontPtr(fontHandle));
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (gxFlags & 0x1) {
|
||||
flags |= 0x1;
|
||||
}
|
||||
|
||||
if (gxFlags & 0x2) {
|
||||
flags |= 0x2;
|
||||
}
|
||||
|
||||
if (gxFlags & 0x8) {
|
||||
flags |= 0x4;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
const char* TextBlockGetFontName(HTEXTFONT fontHandle) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
|
||||
return GxuFontGetFontName(reinterpret_cast<FONTHASHOBJ*>(fontHandle)->font);
|
||||
}
|
||||
|
||||
CGxFont* TextBlockGetFontPtr(HTEXTFONT fontHandle) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
|
||||
return reinterpret_cast<FONTHASHOBJ*>(fontHandle)->font;
|
||||
}
|
||||
|
||||
uint32_t TextBlockGetMaxCharsWithinWidth(HTEXTFONT fontHandle, const char* text, float height, float maxWidth, uint32_t lineBytes, float* extent, float a7, float scale, float a9, uint32_t flags) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
STORM_ASSERT(text);
|
||||
|
||||
return GxuFontGetMaxCharsWithinWidth(
|
||||
TextBlockGetFontPtr(fontHandle),
|
||||
text,
|
||||
DDCToNDCHeight(height),
|
||||
DDCToNDCWidth(maxWidth),
|
||||
lineBytes,
|
||||
extent,
|
||||
DDCToNDCWidth(a7),
|
||||
scale,
|
||||
DDCToNDCWidth(a9),
|
||||
ConvertStringFlags(flags)
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t TextBlockGetMaxCharsWithinWidthAndHeight(HTEXTFONT fontHandle, const char* text, float height, float maxWidth, float maxHeight, uint32_t lineBytes, float a7, float scale, float a9, uint32_t flags) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
STORM_ASSERT(text);
|
||||
|
||||
return GxuFontGetMaxCharsWithinWidthAndHeight(
|
||||
TextBlockGetFontPtr(fontHandle),
|
||||
text,
|
||||
DDCToNDCHeight(height),
|
||||
DDCToNDCWidth(maxWidth),
|
||||
DDCToNDCHeight(maxHeight),
|
||||
lineBytes,
|
||||
DDCToNDCWidth(a7),
|
||||
scale,
|
||||
DDCToNDCWidth(a9),
|
||||
ConvertStringFlags(flags)
|
||||
);
|
||||
}
|
||||
|
||||
CGxString* TextBlockGetStringPtr(HTEXTBLOCK stringHandle) {
|
||||
STORM_ASSERT(stringHandle);
|
||||
|
||||
return reinterpret_cast<TEXTBLOCK*>(stringHandle)->string;
|
||||
}
|
||||
|
||||
void TextBlockGetTextExtent(HTEXTFONT fontHandle, const char* text, uint32_t numChars, float fontHeight, float* extent, float a6, float scale, float a8, uint32_t flags) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
STORM_ASSERT(text);
|
||||
STORM_ASSERT(extent);
|
||||
|
||||
*extent = 0.0f;
|
||||
|
||||
GxuFontGetTextExtent(
|
||||
TextBlockGetFontPtr(fontHandle),
|
||||
text,
|
||||
numChars,
|
||||
DDCToNDCHeight(fontHeight),
|
||||
extent,
|
||||
DDCToNDCWidth(a6),
|
||||
scale,
|
||||
DDCToNDCWidth(a8),
|
||||
ConvertStringFlags(flags)
|
||||
);
|
||||
|
||||
NDCToDDC(*extent, 0.0f, extent, nullptr);
|
||||
}
|
||||
|
||||
float TextBlockGetWrappedTextHeight(HTEXTFONT fontHandle, const char* text, float a3, float a4, const C2Vector& a5, float a6, float a7, uint32_t flags) {
|
||||
STORM_ASSERT(fontHandle);
|
||||
STORM_ASSERT(text);
|
||||
|
||||
float shadowWidth;
|
||||
float shadowHeight;
|
||||
DDCToNDC(a5.x, a5.y, &shadowWidth, &shadowHeight);
|
||||
C2Vector shadowSize = { shadowWidth, shadowHeight };
|
||||
|
||||
float height = GxuFontGetWrappedTextHeight(
|
||||
TextBlockGetFontPtr(fontHandle),
|
||||
text,
|
||||
DDCToNDCHeight(a3),
|
||||
DDCToNDCWidth(a4),
|
||||
shadowSize,
|
||||
a6,
|
||||
DDCToNDCHeight(a7),
|
||||
ConvertStringFlags(flags)
|
||||
);
|
||||
|
||||
return NDCToDDCHeight(height);
|
||||
}
|
||||
|
||||
void TextBlockSetStringPos(HTEXTBLOCK stringHandle, const C3Vector& pos) {
|
||||
STORM_ASSERT(stringHandle);
|
||||
|
||||
C3Vector ndcPos = { 0.0f, 0.0f, pos.z };
|
||||
DDCToNDC(pos.x, pos.y, &ndcPos.x, &ndcPos.y);
|
||||
GxuFontSetStringPosition(TextBlockGetStringPtr(stringHandle), ndcPos);
|
||||
}
|
||||
|
||||
void TextBlockUpdateColor(HTEXTBLOCK stringHandle, const CImVector& color) {
|
||||
STORM_ASSERT(stringHandle);
|
||||
|
||||
GxuFontSetStringColor(TextBlockGetStringPtr(stringHandle), color);
|
||||
}
|
||||
140
src/gx/Font.hpp
Normal file
140
src/gx/Font.hpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#ifndef GX_FONT_HPP
|
||||
#define GX_FONT_HPP
|
||||
|
||||
#include "gx/font/FreeType.hpp"
|
||||
#include "gx/font/Types.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
#include <common/Handle.hpp>
|
||||
#include <storm/Hash.hpp>
|
||||
|
||||
#define FONT_OUTLINE 0x1
|
||||
#define FONT_MONOCHROME 0x2
|
||||
#define FONT_THICKOUTLINE 0x4
|
||||
|
||||
class C2Vector;
|
||||
class C3Vector;
|
||||
class CGxFont;
|
||||
class CGxShader;
|
||||
class CGxString;
|
||||
class CGxStringBatch;
|
||||
class CImVector;
|
||||
struct GLYPHBITMAPDATA;
|
||||
|
||||
class FONTHASHOBJ : public CHandleObject, public TSHashObject<FONTHASHOBJ, HASHKEY_STR> {
|
||||
public:
|
||||
CGxFont* font = nullptr;
|
||||
virtual ~FONTHASHOBJ();
|
||||
};
|
||||
|
||||
class TEXTBLOCK : public CHandleObject {
|
||||
public:
|
||||
CGxString* string = nullptr;
|
||||
virtual ~TEXTBLOCK();
|
||||
};
|
||||
|
||||
extern CGxShader* g_fontPixelShader[1];
|
||||
|
||||
extern CGxShader* g_fontVertexShader[2];
|
||||
|
||||
extern STORM_LIST(CGxString) g_freeStrings;
|
||||
|
||||
extern STORM_LIST(CGxString) g_strings;
|
||||
|
||||
void CalculateYOffset(uint32_t, uint32_t, FT_Face, uint32_t, int32_t*, int32_t*);
|
||||
|
||||
float GetCharacterWidth(const char*, uint32_t, uint32_t, CGxFont*, float);
|
||||
|
||||
float GetIndentNormWidth();
|
||||
|
||||
float GetIndentPixelWidth(void);
|
||||
|
||||
uint32_t GetScreenPixelHeight(void);
|
||||
|
||||
uint32_t GetScreenPixelWidth(void);
|
||||
|
||||
QUOTEDCODE GxuDetermineQuotedCode(const char*, int32_t&, CImVector*, uint32_t, uint32_t&);
|
||||
|
||||
int32_t GxuFontAddToBatch(CGxStringBatch*, CGxString*);
|
||||
|
||||
void GxuFontAddShadow(CGxString* string, const CImVector& color, const C2Vector& offset);
|
||||
|
||||
CGxStringBatch* GxuFontCreateBatch(bool, bool);
|
||||
|
||||
int32_t GxuFontCreateFont(const char*, float, CGxFont*&, uint32_t);
|
||||
|
||||
int32_t GxuFontCreateString(CGxFont*, const char*, float, const C3Vector&, float, float, float, CGxString*&, EGxFontVJusts, EGxFontHJusts, uint32_t, const CImVector&, float, float);
|
||||
|
||||
int32_t GxuFontDestroyBatch(CGxStringBatch*);
|
||||
|
||||
void GxuFontDestroyFont(CGxFont*& font);
|
||||
|
||||
void GxuFontDestroyString(CGxString*&);
|
||||
|
||||
uint32_t GxuFontGetFontFlags(CGxFont*);
|
||||
|
||||
const char* GxuFontGetFontName(CGxFont*);
|
||||
|
||||
uint32_t GxuFontGetMaxCharsWithinWidth(CGxFont*, const char*, float, float, uint32_t, float*, float, float, float, uint32_t);
|
||||
|
||||
uint32_t GxuFontGetMaxCharsWithinWidthAndHeight(CGxFont*, const char*, float, float, float, uint32_t, float, float, float, uint32_t);
|
||||
|
||||
float GxuFontGetOneToOneHeight(CGxFont*);
|
||||
|
||||
void GxuFontGetTextExtent(CGxFont*, const char*, uint32_t, float, float*, float, float, float, uint32_t);
|
||||
|
||||
float GxuFontGetWrappedTextHeight(CGxFont*, const char*, float, float, const C2Vector&, float, float, uint32_t);
|
||||
|
||||
void GxuFontInitialize(void);
|
||||
|
||||
void GxuFontRenderBatch(CGxStringBatch*);
|
||||
|
||||
int32_t GxuFontSetStringColor(CGxString*, const CImVector&);
|
||||
|
||||
void GxuFontSetStringPosition(CGxString* string, const C3Vector& position);
|
||||
|
||||
void GxuFontUpdate();
|
||||
|
||||
void GxuFontWindowSizeChanged(void);
|
||||
|
||||
int32_t IGxuFontGlyphRenderGlyph(FT_Face, uint32_t, uint32_t, uint32_t, GLYPHBITMAPDATA*, int32_t, uint32_t);
|
||||
|
||||
void TextBlockAddShadow(HTEXTBLOCK, CImVector, const C2Vector&);
|
||||
|
||||
HTEXTBLOCK TextBlockCreate(HTEXTFONT, const char*, const CImVector&, const C3Vector&, float, float, float, uint32_t, float, float, float);
|
||||
|
||||
HTEXTFONT TextBlockGenerateFont(const char*, uint32_t, float);
|
||||
|
||||
uint32_t TextBlockGetFontFlags(HTEXTFONT);
|
||||
|
||||
const char* TextBlockGetFontName(HTEXTFONT);
|
||||
|
||||
CGxFont* TextBlockGetFontPtr(HTEXTFONT);
|
||||
|
||||
uint32_t TextBlockGetMaxCharsWithinWidth(HTEXTFONT, const char*, float, float, uint32_t, float*, float, float, float, uint32_t);
|
||||
|
||||
uint32_t TextBlockGetMaxCharsWithinWidthAndHeight(HTEXTFONT, const char*, float, float, float, uint32_t, float, float, float, uint32_t);
|
||||
|
||||
CGxString* TextBlockGetStringPtr(HTEXTBLOCK);
|
||||
|
||||
void TextBlockGetTextExtent(HTEXTFONT, const char*, uint32_t, float, float*, float, float, float, uint32_t);
|
||||
|
||||
float TextBlockGetWrappedTextHeight(HTEXTFONT, const char*, float, float, const C2Vector&, float, float, uint32_t);
|
||||
|
||||
void TextBlockSetStringPos(HTEXTBLOCK stringHandle, const C3Vector& pos);
|
||||
|
||||
void TextBlockUpdateColor(HTEXTBLOCK, const CImVector&);
|
||||
|
||||
float PixelToScreenHeight(int32_t);
|
||||
|
||||
float PixelToScreenWidth(int32_t);
|
||||
|
||||
float PixelToScreenWidth(float);
|
||||
|
||||
float ScreenToPixelHeight(int32_t, float);
|
||||
|
||||
float ScreenToPixelWidth(int32_t, float);
|
||||
|
||||
float Sub6C2280(FT_Face, float);
|
||||
|
||||
#endif
|
||||
200
src/gx/FontInternal.cpp
Normal file
200
src/gx/FontInternal.cpp
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
#include "gx/FontInternal.hpp"
|
||||
#include "gx/Font.hpp"
|
||||
#include "gx/font/CGxFont.hpp"
|
||||
#include <cmath>
|
||||
#include <storm/Error.hpp>
|
||||
#include <tempest/Math.hpp>
|
||||
|
||||
uint32_t InternalGetMaxCharsWithinWidth(CGxFont* face, const char* text, float height, float maxWidth, uint32_t lineBytes, float* extent, uint32_t flags, float a8, float scale, uint32_t* bytesInString, float* widthArray, float* widthArrayGuard) {
|
||||
STORM_ASSERT(face);
|
||||
STORM_ASSERT(text);
|
||||
STORM_ASSERT(extent);
|
||||
|
||||
uint32_t numChars = 0;
|
||||
int32_t billboarded = (flags & 0x80) != 0;
|
||||
|
||||
if (!billboarded && (height == 0.0f || flags & 0x4)) {
|
||||
height = GxuFontGetOneToOneHeight(face);
|
||||
}
|
||||
|
||||
float width = 0.0f;
|
||||
|
||||
if (a8 > 0.0f) {
|
||||
width += ceil(ScreenToPixelWidth(0, a8));
|
||||
}
|
||||
|
||||
if (face->m_flags & 0x8) {
|
||||
width += 4.0f;
|
||||
} else if (face->m_flags & 0x1) {
|
||||
width += 2.0f;
|
||||
}
|
||||
|
||||
float pixelSize = face->GetPixelSize();
|
||||
float pixelHeight = ScreenToPixelHeight(billboarded, height);
|
||||
float pixelScale = pixelHeight / pixelSize;
|
||||
float pixelMaxWidth = CMath::fuint_pi((pixelSize * GetScreenPixelWidth() * maxWidth) / std::max(pixelHeight, 1.0f));
|
||||
|
||||
const char* originalText = text;
|
||||
float lastWidth = 0.0f;
|
||||
int32_t advance;
|
||||
uint32_t code;
|
||||
uint32_t prevCode = 0;
|
||||
|
||||
while (*text && lineBytes) {
|
||||
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, flags, code);
|
||||
|
||||
text += advance;
|
||||
lineBytes -= advance;
|
||||
|
||||
switch (quotedCode) {
|
||||
case CODE_COLORON:
|
||||
case CODE_COLORRESTORE:
|
||||
case CODE_HYPERLINKSTART:
|
||||
case CODE_HYPERLINKSTOP:
|
||||
case CODE_TEXTURESTOP:
|
||||
break;
|
||||
|
||||
case CODE_NEWLINE: {
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
case CODE_TEXTURESTART: {
|
||||
// TODO
|
||||
}
|
||||
|
||||
default: {
|
||||
if (face->NewCodeDesc(code)) {
|
||||
float stepWidth = 0.0f;
|
||||
|
||||
if (prevCode) {
|
||||
stepWidth = flags & 0x10
|
||||
? face->ComputeStepFixedWidth(prevCode, code)
|
||||
: face->ComputeStep(prevCode, code);
|
||||
}
|
||||
|
||||
float characterWidth = GetCharacterWidth(text, flags, code, face, height);
|
||||
|
||||
if (pixelMaxWidth < width + stepWidth + characterWidth) {
|
||||
text -= advance;
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
width += stepWidth;
|
||||
numChars++;
|
||||
|
||||
prevCode = code;
|
||||
lastWidth = characterWidth;
|
||||
|
||||
if (widthArray) {
|
||||
float v34 = (lastWidth + width) * pixelScale;
|
||||
|
||||
if (billboarded) {
|
||||
*widthArray = v34;
|
||||
} else {
|
||||
*widthArray = v34 / GetScreenPixelWidth();
|
||||
}
|
||||
|
||||
widthArray++;
|
||||
}
|
||||
} else {
|
||||
numChars++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
|
||||
float v26 = (lastWidth + width) * pixelScale;
|
||||
|
||||
if (billboarded) {
|
||||
*extent = v26;
|
||||
} else {
|
||||
*extent = v26 / GetScreenPixelWidth();
|
||||
}
|
||||
|
||||
if (bytesInString) {
|
||||
*bytesInString = text - originalText;
|
||||
}
|
||||
|
||||
return numChars;
|
||||
}
|
||||
|
||||
void InternalGetTextExtent(CGxFont* font, const char* text, uint32_t numBytes, float height, float* extent, uint32_t flags, float a7, float a8) {
|
||||
STORM_ASSERT(font);
|
||||
STORM_ASSERT(text);
|
||||
STORM_ASSERT(extent);
|
||||
|
||||
int32_t billboarded = (flags & 0x80) != 0;
|
||||
|
||||
if (height == 0.0f || flags & 0x4) {
|
||||
height = GxuFontGetOneToOneHeight(font);
|
||||
}
|
||||
|
||||
float width = 0.0f;
|
||||
float lastWidth = 0.0f;
|
||||
float maxWidth = 0.0f;
|
||||
|
||||
if (a7 > 0.0f) {
|
||||
width = ceil(ScreenToPixelWidth(0, a7));
|
||||
}
|
||||
|
||||
if (font->m_flags & 0x8) {
|
||||
width += 4.0f;
|
||||
} else if (font->m_flags & 0x1) {
|
||||
width += 2.0f;
|
||||
}
|
||||
|
||||
uint32_t prevCode = 0;
|
||||
|
||||
while (numBytes && *text) {
|
||||
int32_t advance;
|
||||
uint32_t code;
|
||||
CImVector quotedColor;
|
||||
|
||||
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, flags, code);
|
||||
|
||||
numBytes -= advance;
|
||||
text += advance;
|
||||
|
||||
if (
|
||||
quotedCode == CODE_COLORON
|
||||
|| quotedCode == CODE_COLORRESTORE
|
||||
|| quotedCode == CODE_HYPERLINKSTART
|
||||
|| quotedCode == CODE_HYPERLINKSTOP
|
||||
|| quotedCode == CODE_TEXTURESTOP
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quotedCode == CODE_NEWLINE || code == '\n') {
|
||||
maxWidth = std::max(maxWidth, lastWidth + width);
|
||||
lastWidth = 0.0f;
|
||||
width = 0.0f;
|
||||
} else if (quotedCode == CODE_TEXTURESTART) {
|
||||
// TODO
|
||||
} else if (font->NewCodeDesc(code)) {
|
||||
float stepWidth = 0.0f;
|
||||
|
||||
if (prevCode) {
|
||||
stepWidth = flags & 0x10
|
||||
? font->ComputeStepFixedWidth(prevCode, code)
|
||||
: font->ComputeStep(prevCode, code);
|
||||
}
|
||||
|
||||
lastWidth = GetCharacterWidth(text, flags, code, font, height);
|
||||
width += stepWidth;
|
||||
|
||||
prevCode = code;
|
||||
}
|
||||
}
|
||||
|
||||
float pixelSize = font->GetPixelSize();
|
||||
float pixelHeight = ScreenToPixelHeight(billboarded, height);
|
||||
float pixelScale = pixelHeight / pixelSize;
|
||||
|
||||
maxWidth = std::max(maxWidth, lastWidth + width);
|
||||
maxWidth *= pixelScale;
|
||||
|
||||
*extent = billboarded ? maxWidth : PixelToScreenWidth(maxWidth);
|
||||
}
|
||||
12
src/gx/FontInternal.hpp
Normal file
12
src/gx/FontInternal.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef GX_FONT_INTERNAL_HPP
|
||||
#define GX_FONT_INTERNAL_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class CGxFont;
|
||||
|
||||
uint32_t InternalGetMaxCharsWithinWidth(CGxFont*, const char*, float, float, uint32_t, float*, uint32_t, float, float, uint32_t*, float*, float*);
|
||||
|
||||
void InternalGetTextExtent(CGxFont*, const char*, uint32_t, float, float*, uint32_t, float, float);
|
||||
|
||||
#endif
|
||||
96
src/gx/Gx.cpp
Normal file
96
src/gx/Gx.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#include "gx/Gx.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
|
||||
// TODO
|
||||
// - remove placeholder after proper implementation
|
||||
static CGxCaps* g_placeholderGxCaps = new CGxCaps();
|
||||
|
||||
const char* vsProfileNames[] = {
|
||||
"none", "vs_1_1", "vs_2_0", "vs_3_0", "vs_4_0", "vs_5_0", "arbvp1", "arbvp1_cg12", "nvvp", "nvvp2", "nvvp3", "glsl"
|
||||
};
|
||||
|
||||
const char* hsProfileNames[] = {
|
||||
"none", "hs_5_0"
|
||||
};
|
||||
|
||||
const char* dsProfileNames[] = {
|
||||
"none", "ds_5_0"
|
||||
};
|
||||
|
||||
const char* gsProfileNames[] = {
|
||||
"none", "gs_4_0", "gs_5_0"
|
||||
};
|
||||
|
||||
const char* psProfileNames[] = {
|
||||
"none", "ps_1_1", "ps_1_4", "ps_2_0", "ps_3_0", "ps_4_0", "ps_5_0", "nvrc", "nvts", "nvts2", "nvts3", "nvfp2", "arbfp1", "glsl"
|
||||
};
|
||||
|
||||
const char* csProfileNames[] = {
|
||||
"none", "cs_5_0", "cs_cuda", "cs_ocl"
|
||||
};
|
||||
|
||||
const char** g_gxShaderProfileNames[GxShTargets_Last] = {
|
||||
vsProfileNames,
|
||||
hsProfileNames,
|
||||
dsProfileNames,
|
||||
gsProfileNames,
|
||||
psProfileNames,
|
||||
csProfileNames
|
||||
};
|
||||
|
||||
CGxCaps* GxCaps() {
|
||||
// TODO
|
||||
|
||||
g_placeholderGxCaps->m_pixelCenterOnEdge = 1;
|
||||
g_placeholderGxCaps->m_texelCenterOnEdge = 1;
|
||||
|
||||
g_placeholderGxCaps->m_colorFormat = GxCF_rgba;
|
||||
|
||||
g_placeholderGxCaps->m_generateMipMaps = 1;
|
||||
|
||||
g_placeholderGxCaps->m_maxTextureSize = 4096;
|
||||
|
||||
g_placeholderGxCaps->m_texFmtDxt1 = 1;
|
||||
g_placeholderGxCaps->m_texFmtDxt3 = 1;
|
||||
g_placeholderGxCaps->m_texFmtDxt5 = 1;
|
||||
|
||||
g_placeholderGxCaps->m_vertexShaderTarget = GxShVS_arbvp1;
|
||||
g_placeholderGxCaps->m_pixelShaderTarget = GxShPS_arbfp1;
|
||||
|
||||
g_placeholderGxCaps->m_texFilterAnisotropic = 1;
|
||||
g_placeholderGxCaps->m_maxTexAnisotropy = 16;
|
||||
|
||||
g_placeholderGxCaps->m_texTarget[GxTex_2d] = 1;
|
||||
g_placeholderGxCaps->m_texTarget[GxTex_CubeMap] = 1;
|
||||
g_placeholderGxCaps->m_texTarget[GxTex_Rectangle] = 1;
|
||||
g_placeholderGxCaps->m_texTarget[GxTex_NonPow2] = 1;
|
||||
|
||||
g_placeholderGxCaps->m_texMaxSize[GxTex_2d] = 4096;
|
||||
g_placeholderGxCaps->m_texMaxSize[GxTex_CubeMap] = 4096;
|
||||
g_placeholderGxCaps->m_texMaxSize[GxTex_Rectangle] = 4096;
|
||||
g_placeholderGxCaps->m_texMaxSize[GxTex_NonPow2] = 4096;
|
||||
|
||||
return g_placeholderGxCaps;
|
||||
}
|
||||
|
||||
bool GxCapsWindowHasFocus(int32_t a1) {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
void GxCapsWindowSize(CRect& rect) {
|
||||
g_theGxDevicePtr->CapsWindowSize(rect);
|
||||
}
|
||||
|
||||
void GxFormatColor(CImVector& color) {
|
||||
if (GxCaps()->m_colorFormat == GxCF_rgba) {
|
||||
CImVector formattedColor = {
|
||||
color.r,
|
||||
color.g,
|
||||
color.b,
|
||||
color.a
|
||||
};
|
||||
|
||||
color = formattedColor;
|
||||
}
|
||||
}
|
||||
21
src/gx/Gx.hpp
Normal file
21
src/gx/Gx.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef GX_GX_HPP
|
||||
#define GX_GX_HPP
|
||||
|
||||
#include "gx/CGxCaps.hpp"
|
||||
#include "gx/CGxFormat.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class CRect;
|
||||
|
||||
extern const char** g_gxShaderProfileNames[GxShTargets_Last];
|
||||
|
||||
CGxCaps* GxCaps(void);
|
||||
|
||||
bool GxCapsWindowHasFocus(int32_t);
|
||||
|
||||
void GxCapsWindowSize(CRect&);
|
||||
|
||||
void GxFormatColor(CImVector&);
|
||||
|
||||
#endif
|
||||
31
src/gx/RenderState.cpp
Normal file
31
src/gx/RenderState.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "gx/RenderState.hpp"
|
||||
#include "gx/Shader.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include "gx/texture/CGxTex.hpp"
|
||||
#include <storm/Error.hpp>
|
||||
|
||||
void GxRsPop() {
|
||||
g_theGxDevicePtr->RsPop();
|
||||
}
|
||||
|
||||
void GxRsPush() {
|
||||
g_theGxDevicePtr->RsPush();
|
||||
}
|
||||
|
||||
void GxRsSet(EGxRenderState which, int32_t value) {
|
||||
STORM_ASSERT(which < GxRenderStates_Last);
|
||||
g_theGxDevicePtr->RsSet(which, value);
|
||||
}
|
||||
|
||||
void GxRsSet(EGxRenderState which, CGxShader* value) {
|
||||
g_theGxDevicePtr->RsSet(which, value);
|
||||
}
|
||||
|
||||
void GxRsSet(EGxRenderState which, CGxTex* value) {
|
||||
g_theGxDevicePtr->RsSet(which, value);
|
||||
}
|
||||
|
||||
void GxRsSetAlphaRef() {
|
||||
g_theGxDevicePtr->RsSetAlphaRef();
|
||||
}
|
||||
22
src/gx/RenderState.hpp
Normal file
22
src/gx/RenderState.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef GX_RENDER_STATE_HPP
|
||||
#define GX_RENDER_STATE_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
class CGxShader;
|
||||
class CGxTex;
|
||||
|
||||
void GxRsPop(void);
|
||||
|
||||
void GxRsPush(void);
|
||||
|
||||
void GxRsSet(EGxRenderState, int32_t);
|
||||
|
||||
void GxRsSet(EGxRenderState, CGxShader*);
|
||||
|
||||
void GxRsSet(EGxRenderState, CGxTex*);
|
||||
|
||||
void GxRsSetAlphaRef(void);
|
||||
|
||||
#endif
|
||||
237
src/gx/Screen.cpp
Normal file
237
src/gx/Screen.cpp
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
#include "gx/Screen.hpp"
|
||||
#include "event/Event.hpp"
|
||||
#include "gx/Coordinate.hpp"
|
||||
#include "gx/Draw.hpp"
|
||||
#include "gx/Font.hpp"
|
||||
#include "gx/Gx.hpp"
|
||||
#include "gx/Transform.hpp"
|
||||
#include "util/Filesystem.hpp"
|
||||
#include <tempest/Matrix.hpp>
|
||||
|
||||
int32_t Screen::s_captureScreen = 0;
|
||||
float Screen::s_elapsedSec = 0.0f;
|
||||
int32_t Screen::s_presentDisable = 0;
|
||||
HOBJECT Screen::s_stockObjects[];
|
||||
float Screen::s_stockObjectHeights[] = { 0.01953125f, 0.01953125f };
|
||||
STORM_EXPLICIT_LIST(CILayer, zorderlink) Screen::s_zorderlist;
|
||||
|
||||
int32_t OnIdle(const EVENT_DATA_IDLE* data, void* a2) {
|
||||
Screen::s_elapsedSec = data->elapsedSec + Screen::s_elapsedSec;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t OnPaint(const void* a1, void* a2) {
|
||||
// TODO
|
||||
// if (!g_theGxDevicePtr || !g_theGxDevicePtr->CapsHasContext(-1) || !g_theGxDevicePtr->CapsIsWindowVisible(-1)) {
|
||||
// // TODO
|
||||
// // - sound engine logic
|
||||
//
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
CILayer* layer;
|
||||
|
||||
CSRgn rgn;
|
||||
|
||||
SRgnCreate(&rgn.m_handle, 0);
|
||||
|
||||
RECTF baseRect;
|
||||
|
||||
baseRect.left = 0.0f;
|
||||
baseRect.bottom = 0.0f;
|
||||
baseRect.right = 1.0f;
|
||||
baseRect.top = 1.0f;
|
||||
|
||||
SRgnCombineRectf(&rgn.m_handle, &baseRect, 0, 2);
|
||||
|
||||
layer = Screen::s_zorderlist.Head();
|
||||
|
||||
while (layer) {
|
||||
SRgnGetBoundingRectf(&rgn.m_handle, &layer->visible);
|
||||
|
||||
layer->visible.left = std::max(layer->visible.left, layer->rect.left);
|
||||
layer->visible.bottom = std::max(layer->visible.bottom, layer->rect.bottom);
|
||||
layer->visible.right = std::max(layer->visible.right, layer->rect.right);
|
||||
layer->visible.top = std::max(layer->visible.top, layer->rect.top);
|
||||
|
||||
if (layer->flags & 0x1) {
|
||||
SRgnCombineRectf(&rgn.m_handle, &layer->rect, 0, 4);
|
||||
}
|
||||
|
||||
layer = layer->zorderlink.Next();
|
||||
}
|
||||
|
||||
SRgnDelete(&rgn.m_handle);
|
||||
|
||||
// Save viewport
|
||||
float minX, maxX, minY, maxY, minZ, maxZ;
|
||||
GxXformViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
|
||||
layer = Screen::s_zorderlist.Head();
|
||||
|
||||
while (layer) {
|
||||
if (layer->visible.right > layer->visible.left && layer->visible.top > layer->visible.bottom) {
|
||||
if (layer->flags & 0x4) {
|
||||
GxXformSetViewport(
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f
|
||||
);
|
||||
} else {
|
||||
GxXformSetViewport(
|
||||
layer->visible.left,
|
||||
layer->visible.right,
|
||||
layer->visible.bottom,
|
||||
layer->visible.top,
|
||||
0.0f,
|
||||
1.0f
|
||||
);
|
||||
}
|
||||
|
||||
if (layer->flags & 0x2) {
|
||||
C44Matrix identity;
|
||||
GxXformSetView(identity);
|
||||
|
||||
C44Matrix orthoProj;
|
||||
GxuXformCreateOrtho(
|
||||
layer->visible.left,
|
||||
layer->visible.right,
|
||||
layer->visible.bottom,
|
||||
layer->visible.top,
|
||||
0.0f,
|
||||
500.0f,
|
||||
orthoProj
|
||||
);
|
||||
GxXformSetProjection(orthoProj);
|
||||
}
|
||||
|
||||
layer->paintfunc(
|
||||
layer->param,
|
||||
&layer->rect,
|
||||
&layer->visible,
|
||||
Screen::s_elapsedSec
|
||||
);
|
||||
}
|
||||
|
||||
layer = layer->zorderlink.Next();
|
||||
}
|
||||
|
||||
// Restore viewport
|
||||
GxXformSetViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
|
||||
GxuFontUpdate();
|
||||
|
||||
if (!Screen::s_presentDisable) {
|
||||
if (Screen::s_captureScreen) {
|
||||
// TODO
|
||||
|
||||
GxScenePresent();
|
||||
|
||||
// TODO
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
GxScenePresent();
|
||||
}
|
||||
|
||||
Screen::s_elapsedSec = 0.0f;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ILayerInitialize() {
|
||||
EventRegister(EVENT_ID_IDLE, reinterpret_cast<EVENTHANDLERFUNC>(OnIdle));
|
||||
EventRegister(EVENT_ID_PAINT, &OnPaint);
|
||||
}
|
||||
|
||||
void IStockInitialize() {
|
||||
GxuFontInitialize();
|
||||
|
||||
char fontFile[260];
|
||||
|
||||
OsBuildFontFilePath("FRIZQT__.TTF", fontFile, 260);
|
||||
|
||||
if (*fontFile) {
|
||||
ScrnSetStockFont(STOCK_SYSFONT, fontFile);
|
||||
} else {
|
||||
// TODO
|
||||
// SErrSetLastError(0x57u);
|
||||
}
|
||||
|
||||
if (*fontFile) {
|
||||
ScrnSetStockFont(STOCK_PERFFONT, fontFile);
|
||||
} else {
|
||||
// TODO
|
||||
// SErrSetLastError(0x57u);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrnInitialize(int32_t a1) {
|
||||
ILayerInitialize();
|
||||
|
||||
// TODO
|
||||
// consoleInitialized = a1;
|
||||
|
||||
IStockInitialize();
|
||||
}
|
||||
|
||||
void ScrnLayerCreate(const RECTF* rect, float zorder, unsigned long flags, void* param, void (*paintFunc)(void*, const RECTF*, const RECTF*, float), HLAYER* layer) {
|
||||
static RECTF defaultrect = { 0.0f, 0.0f, 1.0f, 1.0f };
|
||||
|
||||
const RECTF* r = rect ? rect : &defaultrect;
|
||||
|
||||
void* m = SMemAlloc(sizeof(CILayer), __FILE__, __LINE__, 0);
|
||||
|
||||
CILayer* l = new (m) CILayer();
|
||||
|
||||
l->rect.left = r->left;
|
||||
l->rect.bottom = r->bottom;
|
||||
l->rect.right = r->right;
|
||||
l->rect.top = r->top;
|
||||
|
||||
l->zorder = zorder;
|
||||
l->flags = flags;
|
||||
l->param = param;
|
||||
l->paintfunc = paintFunc;
|
||||
|
||||
auto node = Screen::s_zorderlist.Head();
|
||||
|
||||
while (node && zorder < node->zorder) {
|
||||
node = node->zorderlink.Next();
|
||||
}
|
||||
|
||||
Screen::s_zorderlist.LinkNode(l, 1, node);
|
||||
|
||||
*layer = HandleCreate(l);
|
||||
}
|
||||
|
||||
void ScrnSetStockFont(SCRNSTOCK stockID, const char* fontTexturePath) {
|
||||
if (Screen::s_stockObjects[stockID]) {
|
||||
HandleClose(Screen::s_stockObjects[stockID]);
|
||||
}
|
||||
|
||||
float fontHeight = NDCToDDCHeight(Screen::s_stockObjectHeights[stockID]);
|
||||
HTEXTFONT font = TextBlockGenerateFont(fontTexturePath, 0, fontHeight);
|
||||
Screen::s_stockObjects[stockID] = font;
|
||||
}
|
||||
|
||||
void SRgnCombineRectf(HSRGN* handle, RECTF* rect, void* param, int32_t combinemode) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void SRgnCreate(HSRGN* handle, uint32_t reserved) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void SRgnDelete(HSRGN* handle) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void SRgnGetBoundingRectf(HSRGN* handle, RECTF* rect) {
|
||||
// TODO
|
||||
}
|
||||
67
src/gx/Screen.hpp
Normal file
67
src/gx/Screen.hpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef GX_SCREEN_HPP
|
||||
#define GX_SCREEN_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <common/Handle.hpp>
|
||||
#include <storm/List.hpp>
|
||||
|
||||
typedef HOBJECT HLAYER;
|
||||
typedef HOBJECT HSRGN;
|
||||
|
||||
enum SCRNSTOCK {
|
||||
STOCK_SYSFONT = 0,
|
||||
STOCK_PERFFONT = 1,
|
||||
SCRNSTOCKOBJECTS = 2
|
||||
};
|
||||
|
||||
struct RECTF {
|
||||
float left;
|
||||
float bottom;
|
||||
float right;
|
||||
float top;
|
||||
};
|
||||
|
||||
class CILayer : public CHandleObject {
|
||||
public:
|
||||
RECTF rect;
|
||||
RECTF visible;
|
||||
float zorder;
|
||||
uint32_t flags;
|
||||
void* param;
|
||||
void (*paintfunc)(void*, const RECTF*, const RECTF*, float);
|
||||
TSLink<CILayer> zorderlink;
|
||||
};
|
||||
|
||||
class CSRgn {
|
||||
public:
|
||||
HSRGN m_handle;
|
||||
};
|
||||
|
||||
namespace Screen {
|
||||
extern int32_t s_captureScreen;
|
||||
extern float s_elapsedSec;
|
||||
extern int32_t s_presentDisable;
|
||||
extern HOBJECT s_stockObjects[SCRNSTOCKOBJECTS];
|
||||
extern float s_stockObjectHeights[SCRNSTOCKOBJECTS];
|
||||
extern STORM_EXPLICIT_LIST(CILayer, zorderlink) s_zorderlist;
|
||||
}
|
||||
|
||||
void ILayerInitialize(void);
|
||||
|
||||
void IStockInitialize(void);
|
||||
|
||||
void ScrnInitialize(int32_t);
|
||||
|
||||
void ScrnLayerCreate(const RECTF*, float, unsigned long, void*, void (*)(void*, const RECTF*, const RECTF*, float), HLAYER*);
|
||||
|
||||
void ScrnSetStockFont(SCRNSTOCK, const char*);
|
||||
|
||||
void SRgnCombineRectf(HSRGN*, RECTF*, void*, int32_t);
|
||||
|
||||
void SRgnCreate(HSRGN*, uint32_t);
|
||||
|
||||
void SRgnDelete(HSRGN*);
|
||||
|
||||
void SRgnGetBoundingRectf(HSRGN*, RECTF*);
|
||||
|
||||
#endif
|
||||
14
src/gx/Shader.cpp
Normal file
14
src/gx/Shader.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "gx/Shader.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
|
||||
char* GxShaderConstantsLock(EGxShTarget target) {
|
||||
return g_theGxDevicePtr->ShaderConstantsLock(target);
|
||||
}
|
||||
|
||||
void GxShaderConstantsSet(EGxShTarget target, uint32_t index, const float* constants, uint32_t count) {
|
||||
g_theGxDevicePtr->ShaderConstantsSet(target, index, constants, count);
|
||||
}
|
||||
|
||||
void GxShaderConstantsUnlock(EGxShTarget target, uint32_t index, uint32_t count) {
|
||||
g_theGxDevicePtr->ShaderConstantsUnlock(target, index, count);
|
||||
}
|
||||
16
src/gx/Shader.hpp
Normal file
16
src/gx/Shader.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef GX_SHADER_HPP
|
||||
#define GX_SHADER_HPP
|
||||
|
||||
#include "gx/shader/CGxShader.hpp"
|
||||
#include "gx/shader/CShaderEffect.hpp"
|
||||
#include "gx/shader/CShaderEffectManager.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
char* GxShaderConstantsLock(EGxShTarget target);
|
||||
|
||||
void GxShaderConstantsSet(EGxShTarget, uint32_t, const float*, uint32_t);
|
||||
|
||||
void GxShaderConstantsUnlock(EGxShTarget target, uint32_t index, uint32_t count);
|
||||
|
||||
#endif
|
||||
1096
src/gx/Texture.cpp
Normal file
1096
src/gx/Texture.cpp
Normal file
File diff suppressed because it is too large
Load diff
82
src/gx/Texture.hpp
Normal file
82
src/gx/Texture.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef GX_TEXTURE_HPP
|
||||
#define GX_TEXTURE_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
#include "gx/texture/CGxTex.hpp"
|
||||
#include "gx/texture/CTexture.hpp"
|
||||
|
||||
typedef HOBJECT HTEXTURE;
|
||||
|
||||
typedef void (TEXTURE_CALLBACK)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&);
|
||||
|
||||
class CImVector;
|
||||
|
||||
void AsyncTextureWait(CTexture*);
|
||||
|
||||
uint32_t CalcLevelCount(uint32_t, uint32_t);
|
||||
|
||||
uint32_t CalcLevelOffset(uint32_t, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
uint32_t CalcLevelSize(uint32_t, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
uint32_t GetBitDepth(uint32_t);
|
||||
|
||||
uint32_t GxCalcTexelStrideInBytes(EGxTexFormat, uint32_t);
|
||||
|
||||
int32_t GxTexCreate(CGxTexParms const&, CGxTex*&);
|
||||
|
||||
int32_t GxTexCreate(EGxTexTarget, uint32_t, uint32_t, uint32_t, EGxTexFormat, EGxTexFormat, CGxTexFlags, void*, void (*)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&), const char*, CGxTex*&);
|
||||
|
||||
void GxTexDestroy(CGxTex* texId);
|
||||
|
||||
void GxTexParameters(const CGxTex* texId, CGxTexParms& parms);
|
||||
|
||||
bool GxTexReusable(CGxTexParms&);
|
||||
|
||||
void GxTexSetWrap(CGxTex* texId, EGxTexWrapMode wrapU, EGxTexWrapMode wrapV);
|
||||
|
||||
void GxTexUpdate(CGxTex*, int32_t, int32_t, int32_t, int32_t, int32_t);
|
||||
|
||||
void GxTexUpdate(CGxTex*, CiRect&, int32_t);
|
||||
|
||||
TEXTURE_CALLBACK GxuUpdateSingleColorTexture;
|
||||
|
||||
MipBits* MippedImgAllocA(uint32_t, uint32_t, uint32_t, const char*, int32_t);
|
||||
|
||||
uint32_t MippedImgCalcSize(uint32_t, uint32_t, uint32_t);
|
||||
|
||||
CGxTex* TextureAllocGxTex(EGxTexTarget, uint32_t, uint32_t, uint32_t, EGxTexFormat, CGxTexFlags, void*, void (*userFunc)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&), EGxTexFormat);
|
||||
|
||||
HTEXTURE TextureCacheGetTexture(char*, char*, CGxTexFlags);
|
||||
|
||||
HTEXTURE TextureCacheGetTexture(const CImVector&);
|
||||
|
||||
void TextureCacheNewTexture(CTexture*, CGxTexFlags);
|
||||
|
||||
void TextureCacheNewTexture(CTexture*, const CImVector&);
|
||||
|
||||
HTEXTURE TextureCreate(const char*, CGxTexFlags, CStatus*, int32_t);
|
||||
|
||||
HTEXTURE TextureCreate(uint32_t, uint32_t, EGxTexFormat, EGxTexFormat, CGxTexFlags, void*, void (*)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&), const char*, int32_t);
|
||||
|
||||
HTEXTURE TextureCreate(EGxTexTarget, uint32_t, uint32_t, uint32_t, EGxTexFormat, EGxTexFormat, CGxTexFlags, void*, void (*)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&), const char*, int32_t);
|
||||
|
||||
HTEXTURE TextureCreateSolid(const CImVector&);
|
||||
|
||||
int32_t TextureGetDimensions(HTEXTURE, uint32_t*, uint32_t*, int32_t);
|
||||
|
||||
void TextureIncreasePriority(CTexture*);
|
||||
|
||||
void TextureInitialize(void);
|
||||
|
||||
int32_t TextureIsSame(HTEXTURE textureHandle, const char* fileName);
|
||||
|
||||
void TextureFreeGxTex(CGxTex* texId);
|
||||
|
||||
CGxTex* TextureGetGxTex(CTexture*, int32_t, CStatus*);
|
||||
|
||||
CGxTex* TextureGetGxTex(HTEXTURE, int32_t, CStatus*);
|
||||
|
||||
CTexture* TextureGetTexturePtr(HTEXTURE);
|
||||
|
||||
#endif
|
||||
217
src/gx/Transform.cpp
Normal file
217
src/gx/Transform.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
#include "gx/Transform.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
#include "gx/Types.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <storm/Error.hpp>
|
||||
#include <tempest/Math.hpp>
|
||||
#include <tempest/Matrix.hpp>
|
||||
#include <tempest/Vector.hpp>
|
||||
|
||||
void GxXformPop(EGxXform xf) {
|
||||
g_theGxDevicePtr->XformPop(xf);
|
||||
}
|
||||
|
||||
void GxXformProjection(C44Matrix& matrix) {
|
||||
g_theGxDevicePtr->XformProjection(matrix);
|
||||
}
|
||||
|
||||
void GxXformProjNative(C44Matrix& matrix) {
|
||||
g_theGxDevicePtr->XformProjNative(matrix);
|
||||
}
|
||||
|
||||
void GxXformProjNativeTranspose(C44Matrix& matrix) {
|
||||
C44Matrix p;
|
||||
GxXformProjNative(p);
|
||||
|
||||
matrix = p.Transpose();
|
||||
}
|
||||
|
||||
void GxXformPush(EGxXform xf) {
|
||||
g_theGxDevicePtr->XformPush(xf);
|
||||
}
|
||||
|
||||
void GxXformSet(EGxXform xf, const C44Matrix& matrix) {
|
||||
g_theGxDevicePtr->XformSet(xf, matrix);
|
||||
}
|
||||
|
||||
void GxXformSetProjection(const C44Matrix& matrix) {
|
||||
g_theGxDevicePtr->XformSetProjection(matrix);
|
||||
}
|
||||
|
||||
void GxXformSetView(const C44Matrix& matrix) {
|
||||
g_theGxDevicePtr->XformSetView(matrix);
|
||||
}
|
||||
|
||||
void GxXformSetViewport(float minX, float maxX, float minY, float maxY, float minZ, float maxZ) {
|
||||
minX = std::max(minX, 0.0f);
|
||||
maxX = std::min(maxX, 1.0f);
|
||||
minY = std::max(minY, 0.0f);
|
||||
maxY = std::min(maxY, 1.0f);
|
||||
|
||||
STORM_ASSERT(minX < maxX);
|
||||
STORM_ASSERT(minY < maxY);
|
||||
STORM_ASSERT(minZ <= maxZ);
|
||||
|
||||
g_theGxDevicePtr->XformSetViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
}
|
||||
|
||||
void GxXformView(C44Matrix& matrix) {
|
||||
g_theGxDevicePtr->XformView(matrix);
|
||||
}
|
||||
|
||||
void GxXformViewport(float& minX, float& maxX, float& minY, float& maxY, float& minZ, float& maxZ) {
|
||||
g_theGxDevicePtr->XformViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
}
|
||||
|
||||
void GxXformViewProjNativeTranspose(C44Matrix& matrix) {
|
||||
C44Matrix v;
|
||||
GxXformView(v);
|
||||
|
||||
C44Matrix p;
|
||||
GxXformProjNative(p);
|
||||
|
||||
matrix = (v * p).Transpose();
|
||||
}
|
||||
|
||||
void GxuXformCreateLookAtSgCompat(const C3Vector& eye, const C3Vector& center, const C3Vector& up, C44Matrix& dst) {
|
||||
C3Vector v16 = {
|
||||
center.x - eye.x,
|
||||
center.y - eye.y,
|
||||
center.z - eye.z
|
||||
};
|
||||
|
||||
if (v16.SquaredMag() >= 0.01f && up.SquaredMag() >= 0.01f) {
|
||||
v16.Normalize();
|
||||
|
||||
C3Vector v15 = {
|
||||
up.z * v16.y - up.y * v16.z,
|
||||
up.x * v16.z - up.z * v16.x,
|
||||
up.y * v16.x - up.x * v16.y
|
||||
};
|
||||
|
||||
v15.Normalize();
|
||||
|
||||
C3Vector v14 = {
|
||||
v16.z * v15.y - v16.y * v15.z,
|
||||
v16.x * v15.z - v16.z * v15.x,
|
||||
v16.y * v15.x - v16.x * v15.y
|
||||
};
|
||||
|
||||
v14.Normalize();
|
||||
|
||||
dst.a0 = v15.x;
|
||||
dst.a1 = v14.x;
|
||||
dst.a2 = v16.x;
|
||||
|
||||
dst.b0 = v15.y;
|
||||
dst.b1 = v14.y;
|
||||
dst.b2 = v16.y;
|
||||
|
||||
dst.c0 = v15.z;
|
||||
dst.c1 = v14.z;
|
||||
dst.c2 = v16.z;
|
||||
|
||||
C3Vector move = { -eye.x, -eye.y, -eye.z };
|
||||
dst.Translate(move);
|
||||
}
|
||||
}
|
||||
|
||||
void GxuXformCreateOrtho(float minX, float maxX, float minY, float maxY, float minZ, float maxZ, C44Matrix& dst) {
|
||||
STORM_ASSERT(minX != maxX);
|
||||
STORM_ASSERT(minY != maxY);
|
||||
STORM_ASSERT(minZ < maxZ);
|
||||
|
||||
double v10 = maxX - minX;
|
||||
double v11 = maxY - minY;
|
||||
double v12 = maxZ - minZ;
|
||||
|
||||
dst.a0 = 2.0 / v10;
|
||||
dst.a1 = 0.0f;
|
||||
dst.a2 = 0.0f;
|
||||
dst.a3 = 0.0f;
|
||||
|
||||
dst.b0 = 0.0f;
|
||||
dst.b1 = 2.0 / v11;
|
||||
dst.b2 = 0.0f;
|
||||
dst.b3 = 0.0f;
|
||||
|
||||
dst.c0 = 0.0f;
|
||||
dst.c1 = 0.0f;
|
||||
dst.c2 = 2.0 / v12;
|
||||
dst.c3 = 0.0f;
|
||||
|
||||
dst.d0 = 0.0f;
|
||||
dst.d1 = 0.0f;
|
||||
dst.d2 = 0.0f;
|
||||
dst.d3 = 1.0f;
|
||||
}
|
||||
|
||||
void GxuXformCreateOrthoDepth(float minX, float maxX, float minY, float maxY, float minZ, float maxZ, C44Matrix& dst) {
|
||||
STORM_ASSERT(minX != maxX);
|
||||
STORM_ASSERT(minY != maxY);
|
||||
STORM_ASSERT(minZ < maxZ);
|
||||
|
||||
int32_t stereoEnabled = g_theGxDevicePtr->StereoEnabled();
|
||||
|
||||
dst.a0 = 2.0 / (maxX - minX);
|
||||
dst.a1 = 0.0f;
|
||||
dst.a2 = 0.0f;
|
||||
dst.a3 = 0.0f;
|
||||
|
||||
dst.b0 = 0.0f;
|
||||
dst.b1 = 2.0 / (maxY - minY);
|
||||
dst.b2 = 0.0f;
|
||||
dst.b3 = 0.0f;
|
||||
|
||||
dst.c0 = 0.0f;
|
||||
dst.c1 = 0.0f;
|
||||
dst.c2 = stereoEnabled ? 1.00008f : 2.0 / (maxZ - minZ);
|
||||
dst.c3 = stereoEnabled ? 1.0f : 0.0f;
|
||||
|
||||
dst.d0 = -((maxX + minX) / (maxX - minX));
|
||||
dst.d1 = -((maxY + minY) / (maxY - minY));
|
||||
dst.d2 = stereoEnabled ? -0.40001601f : -((maxZ + minZ) / (maxZ - minZ));
|
||||
dst.d3 = stereoEnabled ? 0.0f : 1.0f;
|
||||
}
|
||||
|
||||
void GxuXformCreateProjection_Exact(float fovyInRadians, float aspect, float minZ, float maxZ, C44Matrix& dst) {
|
||||
STORM_ASSERT(fovyInRadians > 0.0f && fovyInRadians < CMath::PI);
|
||||
STORM_ASSERT(aspect > 0.0f);
|
||||
STORM_ASSERT(minZ < maxZ);
|
||||
|
||||
float v8 = fovyInRadians * 0.5;
|
||||
float v9 = tan(v8);
|
||||
float v10 = v9 * minZ;
|
||||
float v11 = v10 * aspect;
|
||||
float v7 = maxZ - minZ;
|
||||
|
||||
dst.a0 = minZ / v11;
|
||||
dst.b0 = 0.0f;
|
||||
dst.c0 = 0.0f;
|
||||
dst.d0 = 0.0f;
|
||||
|
||||
dst.a1 = 0.0f;
|
||||
dst.b1 = minZ / v10;
|
||||
dst.c1 = 0.0f;
|
||||
dst.d1 = 0.0f;
|
||||
|
||||
dst.a2 = 0.0f;
|
||||
dst.b2 = 0.0f;
|
||||
dst.c2 = (minZ + maxZ) / v7;
|
||||
dst.d2 = minZ * (maxZ * -2.0f) / v7;
|
||||
|
||||
dst.a3 = 0.0f;
|
||||
dst.b3 = 0.0f;
|
||||
dst.c3 = 1.0f;
|
||||
dst.d3 = 0.0f;
|
||||
}
|
||||
|
||||
void GxuXformCreateProjection_SG(float fov, float aspect, float minZ, float maxZ, C44Matrix& dst) {
|
||||
float v6 = aspect * aspect + 1.0f;
|
||||
float v7 = sqrt(v6);
|
||||
float v8 = 1.0f / v7;
|
||||
float v9 = v8 * fov;
|
||||
|
||||
GxuXformCreateProjection_Exact(v9, aspect, minZ, maxZ, dst);
|
||||
}
|
||||
43
src/gx/Transform.hpp
Normal file
43
src/gx/Transform.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef GX_TRANSFORM_HPP
|
||||
#define GX_TRANSFORM_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
|
||||
class C3Vector;
|
||||
class C44Matrix;
|
||||
|
||||
void GxXformPop(EGxXform xf);
|
||||
|
||||
void GxXformProjection(C44Matrix&);
|
||||
|
||||
void GxXformProjNative(C44Matrix&);
|
||||
|
||||
void GxXformProjNativeTranspose(C44Matrix&);
|
||||
|
||||
void GxXformPush(EGxXform xf);
|
||||
|
||||
void GxXformSet(EGxXform xf, const C44Matrix& matrix);
|
||||
|
||||
void GxXformSetProjection(const C44Matrix&);
|
||||
|
||||
void GxXformSetView(const C44Matrix&);
|
||||
|
||||
void GxXformSetViewport(float, float, float, float, float, float);
|
||||
|
||||
void GxXformView(C44Matrix&);
|
||||
|
||||
void GxXformViewport(float&, float&, float&, float&, float&, float&);
|
||||
|
||||
void GxXformViewProjNativeTranspose(C44Matrix&);
|
||||
|
||||
void GxuXformCreateLookAtSgCompat(const C3Vector& eye, const C3Vector& center, const C3Vector& up, C44Matrix& dst);
|
||||
|
||||
void GxuXformCreateOrtho(float, float, float, float, float, float, C44Matrix&);
|
||||
|
||||
void GxuXformCreateOrthoDepth(float, float, float, float, float, float, C44Matrix&);
|
||||
|
||||
void GxuXformCreateProjection_Exact(float fovyInRadians, float aspect, float minZ, float maxZ, C44Matrix& dst);
|
||||
|
||||
void GxuXformCreateProjection_SG(float fov, float aspect, float minZ, float maxZ, C44Matrix& dst);
|
||||
|
||||
#endif
|
||||
343
src/gx/Types.hpp
Normal file
343
src/gx/Types.hpp
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
#ifndef GX_TYPES_HPP
|
||||
#define GX_TYPES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum BlitAlpha {
|
||||
BlitAlpha_0 = 0,
|
||||
BlitAlpha_1 = 1,
|
||||
BlitAlpha_8 = 2,
|
||||
BlitAlpha_Filler = 3,
|
||||
BlitAlphas_Last = 4
|
||||
};
|
||||
|
||||
enum BlitFormat {
|
||||
BlitFormat_Unknown = 0,
|
||||
BlitFormat_Abgr8888 = 1,
|
||||
BlitFormat_Argb8888 = 2,
|
||||
BlitFormat_Argb4444 = 3,
|
||||
BlitFormat_Argb1555 = 4,
|
||||
BlitFormat_Rgb565 = 5,
|
||||
BlitFormat_Dxt1 = 6,
|
||||
BlitFormat_Dxt3 = 7,
|
||||
BlitFormat_Dxt5 = 8,
|
||||
BlitFormat_Uv88 = 9,
|
||||
BlitFormat_Gr1616F = 10,
|
||||
BlitFormat_R32F = 11,
|
||||
BlitFormat_D24X8 = 12,
|
||||
BlitFormats_Last = 13
|
||||
};
|
||||
|
||||
enum EGxApi {
|
||||
GxApi_OpenGl = 0,
|
||||
GxApi_D3d9 = 1,
|
||||
GxApi_D3d9Ex = 2,
|
||||
GxApi_D3d10 = 3,
|
||||
GxApi_D3d11 = 4,
|
||||
GxApi_GLL = 5,
|
||||
GxApis_Last = 6
|
||||
};
|
||||
|
||||
enum EGxBlend {
|
||||
GxBlend_Opaque = 0,
|
||||
GxBlend_AlphaKey = 1,
|
||||
GxBlend_Alpha = 2,
|
||||
GxBlend_Add = 3,
|
||||
GxBlend_Mod = 4,
|
||||
GxBlend_Mod2x = 5,
|
||||
GxBlend_ModAdd = 6,
|
||||
GxBlend_InvSrcAlphaAdd = 7,
|
||||
GxBlend_InvSrcAlphaOpaque = 8,
|
||||
GxBlend_SrcAlphaOpaque = 9,
|
||||
GxBlend_NoAlphaAdd = 10,
|
||||
GxBlend_ConstantAlpha = 11,
|
||||
GxBlends_Last = 12
|
||||
};
|
||||
|
||||
enum EGxColorFormat {
|
||||
GxCF_argb = 0,
|
||||
GxCF_rgba = 1,
|
||||
GxColorFormats_Last = 2,
|
||||
};
|
||||
|
||||
enum EGxFontHJusts {
|
||||
GxHJ_Left = 0,
|
||||
GxHJ_Center = 1,
|
||||
GxHJ_Right = 2,
|
||||
GxHJ_Last = 3
|
||||
};
|
||||
|
||||
enum EGxFontVJusts {
|
||||
GxVJ_Top = 0,
|
||||
GxVJ_Middle = 1,
|
||||
GxVJ_Bottom = 2,
|
||||
GxVJ_Last = 3
|
||||
};
|
||||
|
||||
enum EGxMasterEnables {
|
||||
GxMasterEnable_Lighting = 0,
|
||||
GxMasterEnable_Fog = 1,
|
||||
GxMasterEnable_DepthTest = 2,
|
||||
GxMasterEnable_DepthWrite = 3,
|
||||
GxMasterEnable_ColorWrite = 4,
|
||||
GxMasterEnable_Culling = 5,
|
||||
GxMasterEnable_DoubleBuffering = 6,
|
||||
GxMasterEnable_NormalProjection = 7,
|
||||
GxMasterEnable_PolygonFill = 8,
|
||||
GxMasterEnables_Last = 9
|
||||
};
|
||||
|
||||
enum EGxPrim {
|
||||
GxPrim_Points = 0,
|
||||
GxPrim_Lines = 1,
|
||||
GxPrim_LineStrip = 2,
|
||||
GxPrim_Triangles = 3,
|
||||
GxPrim_TriangleStrip = 4,
|
||||
GxPrim_TriangleFan = 5,
|
||||
GxPrims_Last = 6
|
||||
};
|
||||
|
||||
enum EGxPrimMask {
|
||||
GxPrim_Position = 0x1,
|
||||
GxPrim_BlendWeight = 0x2,
|
||||
GxPrim_BlendIndices = 0x4,
|
||||
GxPrim_Normal = 0x8,
|
||||
GxPrim_Color0 = 0x10,
|
||||
GxPrim_Color1 = 0x20,
|
||||
GxPrim_TexCoord0 = 0x40,
|
||||
GxPrim_TexCoord1 = 0x80
|
||||
};
|
||||
|
||||
enum EGxRenderState {
|
||||
GxRs_PolygonOffset = 0,
|
||||
GxRs_MatDiffuse = 1,
|
||||
GxRs_MatEmissive = 2,
|
||||
GxRs_MatSpecular = 3,
|
||||
GxRs_MatSpecularExp = 4,
|
||||
GxRs_NormalizeNormals = 5,
|
||||
GxRs_BlendingMode = 6,
|
||||
GxRs_AlphaRef = 7,
|
||||
GxRs_FogStart = 8,
|
||||
GxRs_FogEnd = 9,
|
||||
GxRs_FogColor = 10,
|
||||
GxRs_Lighting = 11,
|
||||
GxRs_Fog = 12,
|
||||
GxRs_DepthTest = 13,
|
||||
GxRs_DepthFunc = 14,
|
||||
GxRs_DepthWrite = 15,
|
||||
GxRs_ColorWrite = 16,
|
||||
GxRs_Culling = 17,
|
||||
GxRs_ClipPlaneMask = 18,
|
||||
GxRs_Multisample = 19,
|
||||
GxRs_ScissorTest = 20,
|
||||
GxRs_Texture0 = 21,
|
||||
GxRs_Texture1 = 22,
|
||||
GxRs_Texture2 = 23,
|
||||
GxRs_Texture3 = 24,
|
||||
GxRs_Texture4 = 25,
|
||||
GxRs_Texture5 = 26,
|
||||
GxRs_Texture6 = 27,
|
||||
GxRs_Texture7 = 28,
|
||||
GxRs_Texture8 = 29,
|
||||
GxRs_Texture9 = 30,
|
||||
GxRs_Texture10 = 31,
|
||||
GxRs_Texture11 = 32,
|
||||
GxRs_Texture12 = 33,
|
||||
GxRs_Texture13 = 34,
|
||||
GxRs_Texture14 = 35,
|
||||
GxRs_Texture15 = 36,
|
||||
GxRs_ColorOp0 = 37,
|
||||
GxRs_ColorOp1 = 38,
|
||||
GxRs_ColorOp2 = 39,
|
||||
GxRs_ColorOp3 = 40,
|
||||
GxRs_ColorOp4 = 41,
|
||||
GxRs_ColorOp5 = 42,
|
||||
GxRs_ColorOp6 = 43,
|
||||
GxRs_ColorOp7 = 44,
|
||||
GxRs_AlphaOp0 = 45,
|
||||
GxRs_AlphaOp1 = 46,
|
||||
GxRs_AlphaOp2 = 47,
|
||||
GxRs_AlphaOp3 = 48,
|
||||
GxRs_AlphaOp4 = 49,
|
||||
GxRs_AlphaOp5 = 50,
|
||||
GxRs_AlphaOp6 = 51,
|
||||
GxRs_AlphaOp7 = 52,
|
||||
GxRs_TexGen0 = 53,
|
||||
GxRs_TexGen1 = 54,
|
||||
GxRs_TexGen2 = 55,
|
||||
GxRs_TexGen3 = 56,
|
||||
GxRs_TexGen4 = 57,
|
||||
GxRs_TexGen5 = 58,
|
||||
GxRs_TexGen6 = 59,
|
||||
GxRs_TexGen7 = 60,
|
||||
GxRs_Unk61 = 61,
|
||||
GxRs_Unk62 = 62,
|
||||
GxRs_Unk63 = 63,
|
||||
GxRs_Unk64 = 64,
|
||||
GxRs_Unk65 = 65,
|
||||
GxRs_Unk66 = 66,
|
||||
GxRs_Unk67 = 67,
|
||||
GxRs_Unk68 = 68,
|
||||
GxRs_Unk69 = 69,
|
||||
GxRs_Unk70 = 70,
|
||||
GxRs_Unk71 = 71,
|
||||
GxRs_Unk72 = 72,
|
||||
GxRs_Unk73 = 73,
|
||||
GxRs_Unk74 = 74,
|
||||
GxRs_Unk75 = 75,
|
||||
GxRs_Unk76 = 76,
|
||||
GxRs_VertexShader = 77,
|
||||
GxRs_PixelShader = 78,
|
||||
GxRs_PointScale = 79,
|
||||
GxRs_PointScaleAttenuation = 80,
|
||||
GxRs_PointScaleMin = 81,
|
||||
GxRs_PointScaleMax = 82,
|
||||
GxRs_PointSprite = 83,
|
||||
GxRs_Unk84 = 84,
|
||||
GxRs_ColorMaterial = 85,
|
||||
GxRenderStates_Last = 86
|
||||
};
|
||||
|
||||
enum EGxShPS {
|
||||
GxShPS_none = 0,
|
||||
GxShPS_ps_1_1 = 1,
|
||||
GxShPS_ps_1_4 = 2,
|
||||
GxShPS_ps_2_0 = 3,
|
||||
GxShPS_ps_3_0 = 4,
|
||||
GxShPS_ps_4_0 = 5,
|
||||
GxShPS_ps_5_0 = 6,
|
||||
GxShPS_nvrc = 7,
|
||||
GxShPS_nvts = 8,
|
||||
GxShPS_nvts2 = 9,
|
||||
GxShPS_nvts3 = 10,
|
||||
GxShPS_nvfp2 = 11,
|
||||
GxShPS_arbfp1 = 12,
|
||||
GxShPS_glsl = 13,
|
||||
};
|
||||
|
||||
enum EGxShTarget {
|
||||
GxSh_Vertex = 0,
|
||||
GxSh_Hull = 1,
|
||||
GxSh_Domain = 2,
|
||||
GxSh_Geometry = 3,
|
||||
GxSh_Pixel = 4,
|
||||
GxSh_Compute = 5,
|
||||
GxShTargets_Last = 6
|
||||
};
|
||||
|
||||
enum EGxShVS {
|
||||
GxShVS_none = 0,
|
||||
GxShVS_vs_1_1 = 1,
|
||||
GxShVS_vs_2_0 = 2,
|
||||
GxShVS_vs_3_0 = 3,
|
||||
GxShVS_vs_4_0 = 4,
|
||||
GxShVS_vs_5_0 = 5,
|
||||
GxShVS_arbvp1 = 6,
|
||||
GxShVS_arbvp1_cg12 = 7,
|
||||
GxShVS_nvvp = 8,
|
||||
GxShVS_nvvp2 = 9,
|
||||
GxShVS_nvvp3 = 10,
|
||||
GxShVS_glsl = 11
|
||||
};
|
||||
|
||||
enum EGxTexCommand {
|
||||
GxTex_Lock = 0,
|
||||
GxTex_Latch = 1,
|
||||
GxTex_Unlock = 2,
|
||||
GxTexCommands_Last = 3
|
||||
};
|
||||
|
||||
enum EGxTexFilter {
|
||||
GxTex_Nearest = 0x0,
|
||||
GxTex_Linear = 0x1,
|
||||
GxTex_NearestMipNearest = 0x2,
|
||||
GxTex_LinearMipNearest = 0x3,
|
||||
GxTex_LinearMipLinear = 0x4,
|
||||
GxTex_Anisotropic = 0x5,
|
||||
GxTexFilters_Last = 0x6,
|
||||
};
|
||||
|
||||
enum EGxTexFormat {
|
||||
GxTex_Unknown = 0x0,
|
||||
GxTex_Abgr8888 = 0x1,
|
||||
GxTex_Argb8888 = 0x2,
|
||||
GxTex_Argb4444 = 0x3,
|
||||
GxTex_Argb1555 = 0x4,
|
||||
GxTex_Rgb565 = 0x5,
|
||||
GxTex_Dxt1 = 0x6,
|
||||
GxTex_Dxt3 = 0x7,
|
||||
GxTex_Dxt5 = 0x8,
|
||||
GxTex_Uv88 = 0x9,
|
||||
GxTex_Gr1616F = 0xA,
|
||||
GxTex_R32F = 0xB,
|
||||
GxTex_D24X8 = 0xC,
|
||||
GxTexFormats_Last = 0xD,
|
||||
};
|
||||
|
||||
enum EGxTexTarget {
|
||||
GxTex_2d = 0x0,
|
||||
GxTex_CubeMap = 0x1,
|
||||
GxTex_Rectangle = 0x2,
|
||||
GxTex_NonPow2 = 0x3,
|
||||
GxTexTargets_Last = 0x4
|
||||
};
|
||||
|
||||
enum EGxTexWrapMode {
|
||||
GxTex_WrapMode0 = 0,
|
||||
GxTex_WrapMode1 = 1
|
||||
};
|
||||
|
||||
enum EGxXform {
|
||||
GxXform_Tex0 = 0,
|
||||
GxXform_Tex1 = 1,
|
||||
GxXform_Tex2 = 2,
|
||||
GxXform_Tex3 = 3,
|
||||
GxXform_Tex4 = 4,
|
||||
GxXform_Tex5 = 5,
|
||||
GxXform_Tex6 = 6,
|
||||
GxXform_Tex7 = 7,
|
||||
GxXform_World = 8,
|
||||
GxXform_Projection = 9,
|
||||
GxXform_View = 10,
|
||||
GxXforms_Last = 11
|
||||
};
|
||||
|
||||
enum EGxuDrawListCategory {
|
||||
GxuCat_0 = 0,
|
||||
GxuCat_1 = 1,
|
||||
GxuCat_2 = 2
|
||||
};
|
||||
|
||||
enum COLOR_FILE_FORMAT {
|
||||
COLOR_JPEG = 0,
|
||||
COLOR_PAL = 1,
|
||||
COLOR_DXT = 2,
|
||||
COLOR_3 = 3
|
||||
};
|
||||
|
||||
enum PIXEL_FORMAT {
|
||||
PIXEL_DXT1 = 0x0,
|
||||
PIXEL_DXT3 = 0x1,
|
||||
PIXEL_ARGB8888 = 0x2,
|
||||
PIXEL_ARGB1555 = 0x3,
|
||||
PIXEL_ARGB4444 = 0x4,
|
||||
PIXEL_RGB565 = 0x5,
|
||||
PIXEL_A8 = 0x6,
|
||||
PIXEL_DXT5 = 0x7,
|
||||
PIXEL_UNSPECIFIED = 0x8,
|
||||
PIXEL_ARGB2565 = 0x9,
|
||||
NUM_PIXEL_FORMATS = 0xA
|
||||
};
|
||||
|
||||
struct C4Pixel {
|
||||
char b;
|
||||
char g;
|
||||
char r;
|
||||
char a;
|
||||
};
|
||||
|
||||
struct MipBits {
|
||||
C4Pixel* mip[1];
|
||||
};
|
||||
|
||||
#endif
|
||||
35
src/gx/Window.cpp
Normal file
35
src/gx/Window.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "gx/Window.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
|
||||
bool s_forceOnscreen;
|
||||
Rect s_savedWindowRect;
|
||||
Rect s_savedWindowZoomedRect;
|
||||
|
||||
int32_t OsGetDefaultWindowRect(tagRECT* rect) {
|
||||
auto window = g_theGxDevicePtr->DeviceDefWindow();
|
||||
|
||||
rect->left = window.minX;
|
||||
rect->top = window.minY;
|
||||
rect->right = window.maxX;
|
||||
rect->bottom = window.maxY;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Rect* GetSavedWindowBounds() {
|
||||
return &s_savedWindowRect;
|
||||
}
|
||||
|
||||
Rect* GetSavedZoomedWindowBounds() {
|
||||
return &s_savedWindowZoomedRect;
|
||||
}
|
||||
|
||||
void SetSavedWindowBounds(Rect rect) {
|
||||
s_forceOnscreen = true;
|
||||
s_savedWindowRect = rect;
|
||||
}
|
||||
|
||||
void SetSavedZoomedWindowBounds(Rect rect) {
|
||||
s_forceOnscreen = true;
|
||||
s_savedWindowZoomedRect = rect;
|
||||
}
|
||||
36
src/gx/Window.hpp
Normal file
36
src/gx/Window.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef GX_WINDOW_HPP
|
||||
#define GX_WINDOW_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
#if defined(WHOA_SYSTEM_LINUX) || defined(WHOA_SYSTEM_WIN)
|
||||
struct Rect {
|
||||
int16_t top;
|
||||
int16_t left;
|
||||
int16_t bottom;
|
||||
int16_t right;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct tagRECT {
|
||||
int32_t left;
|
||||
int32_t top;
|
||||
int32_t right;
|
||||
int32_t bottom;
|
||||
};
|
||||
|
||||
int32_t OsGetDefaultWindowRect(tagRECT* rect);
|
||||
|
||||
Rect* GetSavedWindowBounds();
|
||||
|
||||
Rect* GetSavedZoomedWindowBounds();
|
||||
|
||||
void SetSavedWindowBounds(Rect rect);
|
||||
|
||||
void SetSavedZoomedWindowBounds(Rect rect);
|
||||
|
||||
#endif
|
||||
37
src/gx/buffer/CGxBuf.hpp
Normal file
37
src/gx/buffer/CGxBuf.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef GX_BUFFER_C_GX_BUF_HPP
|
||||
#define GX_BUFFER_C_GX_BUF_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <storm/List.hpp>
|
||||
|
||||
class CGxPool;
|
||||
|
||||
class CGxBuf : public TSLinkedNode<CGxBuf> {
|
||||
public:
|
||||
// Member variables
|
||||
CGxPool* m_pool;
|
||||
uint32_t m_itemSize;
|
||||
uint32_t m_itemCount;
|
||||
uint32_t m_size;
|
||||
uint32_t m_index;
|
||||
uint8_t unk1C; // TODO
|
||||
uint8_t unk1D; // TODO
|
||||
uint8_t unk1E; // TODO
|
||||
uint8_t unk1F; // TODO
|
||||
|
||||
// Member functions
|
||||
CGxBuf() = default;
|
||||
CGxBuf(CGxPool* pool, uint32_t itemSize, uint32_t itemCount, uint32_t index)
|
||||
: m_pool(pool)
|
||||
, m_itemSize(itemSize)
|
||||
, m_itemCount(itemCount)
|
||||
, m_size(itemSize * itemCount)
|
||||
, m_index(index)
|
||||
, unk1C(0)
|
||||
, unk1D(1)
|
||||
, unk1E(0)
|
||||
, unk1F(0)
|
||||
{};
|
||||
};
|
||||
|
||||
#endif
|
||||
9
src/gx/buffer/CGxPool.cpp
Normal file
9
src/gx/buffer/CGxPool.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include "gx/buffer/CGxPool.hpp"
|
||||
|
||||
void CGxPool::Discard() {
|
||||
for (auto buf = this->m_bufList.Head(); buf; buf = this->m_bufList.Link(buf)->Next()) {
|
||||
buf->unk1C = 0;
|
||||
}
|
||||
|
||||
this->unk1C = 0;
|
||||
}
|
||||
36
src/gx/buffer/CGxPool.hpp
Normal file
36
src/gx/buffer/CGxPool.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef GX_BUFFER_C_GX_POOL_HPP
|
||||
#define GX_BUFFER_C_GX_POOL_HPP
|
||||
|
||||
#include "gx/buffer/CGxBuf.hpp"
|
||||
#include "gx/buffer/Types.hpp"
|
||||
#include <cstdint>
|
||||
#include <storm/List.hpp>
|
||||
|
||||
class CGxPool : public TSLinkedNode<CGxPool> {
|
||||
public:
|
||||
// Member variables
|
||||
EGxPoolTarget m_target;
|
||||
EGxPoolUsage m_usage;
|
||||
int32_t m_size;
|
||||
void* m_apiSpecific;
|
||||
void* m_mem;
|
||||
int32_t unk1C; // TODO
|
||||
TSList<CGxBuf, TSGetLink<CGxBuf>> m_bufList;
|
||||
EGxPoolHintBits m_hint;
|
||||
const char* m_name;
|
||||
|
||||
// Member functions
|
||||
CGxPool() = default;
|
||||
CGxPool(EGxPoolTarget target, EGxPoolUsage usage, uint32_t size, EGxPoolHintBits hint, const char* name)
|
||||
: m_target(target)
|
||||
, m_usage(usage)
|
||||
, m_size(size)
|
||||
, m_apiSpecific(nullptr)
|
||||
, unk1C(0)
|
||||
, m_hint(hint)
|
||||
, m_name(name)
|
||||
{};
|
||||
void Discard(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
91
src/gx/buffer/Types.hpp
Normal file
91
src/gx/buffer/Types.hpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef GX_BUFFER_TYPES_HPP
|
||||
#define GX_BUFFER_TYPES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <tempest/Vector.hpp>
|
||||
|
||||
enum EGxPoolHintBits {
|
||||
GxPoolHintBit_Unk0 = 0,
|
||||
GxPoolHintBit_Unk1 = 1,
|
||||
GxPoolHintBit_Unk2 = 2,
|
||||
GxPoolHintBit_Unk3 = 3
|
||||
};
|
||||
|
||||
enum EGxPoolTarget {
|
||||
GxPoolTarget_Vertex = 0,
|
||||
GxPoolTarget_Index = 1,
|
||||
GxPoolTargets_Last = 2
|
||||
};
|
||||
|
||||
enum EGxPoolUsage {
|
||||
GxPoolUsage_Static = 0,
|
||||
GxPoolUsage_Dynamic = 1,
|
||||
GxPoolUsage_Stream = 2,
|
||||
GxPoolUsages_Last = 3
|
||||
};
|
||||
|
||||
enum EGxVertexAttrib {
|
||||
GxVA_Position = 0,
|
||||
GxVA_BlendWeight = 1,
|
||||
GxVA_BlendIndices = 2,
|
||||
GxVA_Normal = 3,
|
||||
GxVA_Color0 = 4,
|
||||
GxVA_Color1 = 5,
|
||||
GxVA_TexCoord0 = 6,
|
||||
GxVA_TexCoord1 = 7,
|
||||
GxVA_TexCoord2 = 8,
|
||||
GxVA_TexCoord3 = 9,
|
||||
GxVA_TexCoord4 = 10,
|
||||
GxVA_TexCoord5 = 11,
|
||||
GxVA_TexCoord6 = 12,
|
||||
GxVA_TexCoord7 = 13,
|
||||
GxVAs_Last = 14
|
||||
};
|
||||
|
||||
enum EGxVertexBufferFormat {
|
||||
GxVBF_P = 0,
|
||||
GxVBF_PN = 1,
|
||||
GxVBF_PNC = 2,
|
||||
GxVBF_PNT = 3,
|
||||
GxVBF_PNCT = 4,
|
||||
GxVBF_PNT2 = 5,
|
||||
GxVBF_PNCT2 = 6,
|
||||
GxVBF_PC = 7,
|
||||
GxVBF_PCT = 8,
|
||||
GxVBF_PCT2 = 9,
|
||||
GxVBF_PT = 10,
|
||||
GxVBF_PT2 = 11,
|
||||
GxVBF_PBNT2 = 12,
|
||||
GxVBF_PNC2T2 = 13,
|
||||
GxVertexBufferFormats_Last = 14
|
||||
};
|
||||
|
||||
struct ubyte4 {
|
||||
union {
|
||||
uint8_t b[4];
|
||||
uint32_t u;
|
||||
};
|
||||
};
|
||||
|
||||
struct CGxVertexAttrib {
|
||||
EGxVertexAttrib attrib;
|
||||
uint32_t type;
|
||||
uint32_t offset;
|
||||
uint32_t bufSize;
|
||||
};
|
||||
|
||||
struct CGxVertexPBNT2 {
|
||||
C3Vector p;
|
||||
ubyte4 bw;
|
||||
ubyte4 bi;
|
||||
C3Vector n;
|
||||
C2Vector tc[2];
|
||||
};
|
||||
|
||||
struct CGxVertexPCT {
|
||||
C3Vector p;
|
||||
CImVector c;
|
||||
C2Vector tc[1];
|
||||
};
|
||||
|
||||
#endif
|
||||
928
src/gx/font/CGxFont.cpp
Normal file
928
src/gx/font/CGxFont.cpp
Normal file
|
|
@ -0,0 +1,928 @@
|
|||
#include "gx/font/CGxFont.hpp"
|
||||
#include "gx/font/FontFace.hpp"
|
||||
#include "gx/Texture.hpp"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <storm/Error.hpp>
|
||||
#include <storm/String.hpp>
|
||||
#include <storm/Unicode.hpp>
|
||||
|
||||
uint16_t TEXTURECACHE::s_textureData[256 * 256];
|
||||
|
||||
GLYPHBITMAPDATA::~GLYPHBITMAPDATA() {
|
||||
if (this->m_data) {
|
||||
SMemFree(this->m_data, __FILE__, __LINE__, 0x0);
|
||||
}
|
||||
|
||||
this->m_data = nullptr;
|
||||
}
|
||||
|
||||
void GLYPHBITMAPDATA::CopyFrom(GLYPHBITMAPDATA* data) {
|
||||
if (this->m_data) {
|
||||
SMemFree(this->m_data, __FILE__, __LINE__, 0);
|
||||
}
|
||||
|
||||
this->m_data = nullptr;
|
||||
*this = *data;
|
||||
data->m_data = nullptr;
|
||||
}
|
||||
|
||||
uint32_t CHARCODEDESC::GapToNextTexture() {
|
||||
CHARCODEDESC* next = this->textureRowLink.Next();
|
||||
|
||||
return next
|
||||
? next->glyphStartPixel - this->glyphEndPixel - 1
|
||||
: 255 - this->glyphEndPixel;
|
||||
}
|
||||
|
||||
uint32_t CHARCODEDESC::GapToPreviousTexture() {
|
||||
CHARCODEDESC* previous = this->textureRowLink.Prev();
|
||||
|
||||
return previous
|
||||
? this->glyphStartPixel - previous->glyphEndPixel - 1
|
||||
: this->glyphStartPixel;
|
||||
}
|
||||
|
||||
void CHARCODEDESC::GenerateTextureCoords(uint32_t rowNumber, uint32_t glyphSide) {
|
||||
this->bitmapData.m_textureCoords.minY = (glyphSide * rowNumber) / 256.0f;
|
||||
this->bitmapData.m_textureCoords.minX = this->glyphStartPixel / 256.0f;
|
||||
this->bitmapData.m_textureCoords.maxY = ((glyphSide * rowNumber) + glyphSide) / 256.0f;
|
||||
this->bitmapData.m_textureCoords.maxX = (this->glyphStartPixel + this->bitmapData.m_glyphCellWidth) / 256.0f;
|
||||
}
|
||||
|
||||
KERNINGHASHKEY& KERNINGHASHKEY::operator=(const KERNINGHASHKEY& rhs) {
|
||||
if (this->code != rhs.code) {
|
||||
this->code = rhs.code;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool KERNINGHASHKEY::operator==(const KERNINGHASHKEY& rhs) {
|
||||
return this->code == rhs.code;
|
||||
}
|
||||
|
||||
CHARCODEDESC* TEXTURECACHEROW::CreateNewDesc(GLYPHBITMAPDATA* data, uint32_t rowNumber, uint32_t glyphCellHeight) {
|
||||
uint32_t glyphWidth = data->m_glyphCellWidth;
|
||||
|
||||
if (this->widestFreeSlot < glyphWidth) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!this->glyphList.Head()) {
|
||||
CHARCODEDESC* newCode = this->glyphList.NewNode(2, 0, 0);
|
||||
|
||||
newCode->glyphStartPixel = 0;
|
||||
newCode->glyphEndPixel = glyphWidth - 1;
|
||||
newCode->rowNumber = rowNumber;
|
||||
newCode->bitmapData.CopyFrom(data);
|
||||
newCode->GenerateTextureCoords(rowNumber, glyphCellHeight);
|
||||
|
||||
this->widestFreeSlot -= glyphWidth;
|
||||
|
||||
return newCode;
|
||||
}
|
||||
|
||||
uint32_t gapToPrevious = this->glyphList.Head()->GapToPreviousTexture();
|
||||
this->widestFreeSlot = gapToPrevious;
|
||||
|
||||
if (gapToPrevious >= glyphWidth) {
|
||||
void* m = SMemAlloc(sizeof(CHARCODEDESC), __FILE__, __LINE__, 0);
|
||||
CHARCODEDESC* newCode = new (m) CHARCODEDESC();
|
||||
|
||||
this->glyphList.LinkNode(newCode, 2, this->glyphList.Head());
|
||||
|
||||
newCode->glyphEndPixel = this->glyphList.Head()->glyphStartPixel - 1;
|
||||
newCode->glyphStartPixel = newCode->glyphEndPixel - glyphWidth + 1;
|
||||
newCode->rowNumber = rowNumber;
|
||||
newCode->bitmapData.CopyFrom(data);
|
||||
newCode->GenerateTextureCoords(rowNumber, glyphCellHeight);
|
||||
|
||||
this->widestFreeSlot = this->glyphList.Head()
|
||||
? this->glyphList.Head()->GapToPreviousTexture()
|
||||
: 0;
|
||||
|
||||
for (auto code = this->glyphList.Head(); code; code = this->glyphList.Link(code)->Next()) {
|
||||
uint32_t gapToNext = code->GapToNextTexture();
|
||||
if (gapToNext > this->widestFreeSlot) {
|
||||
this->widestFreeSlot = gapToNext;
|
||||
}
|
||||
}
|
||||
|
||||
return newCode;
|
||||
}
|
||||
|
||||
int32_t inserted = 0;
|
||||
CHARCODEDESC* newCode = nullptr;
|
||||
|
||||
for (auto code = this->glyphList.Head(); code; code = this->glyphList.Link(code)->Next()) {
|
||||
uint32_t gapToNext = code->GapToNextTexture();
|
||||
|
||||
if (inserted) {
|
||||
if (gapToNext > this->widestFreeSlot) {
|
||||
this->widestFreeSlot = gapToNext;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gapToNext >= glyphWidth) {
|
||||
void* m = SMemAlloc(sizeof(CHARCODEDESC), __FILE__, __LINE__, 0);
|
||||
newCode = new (m) CHARCODEDESC();
|
||||
|
||||
this->glyphList.LinkNode(newCode, 1, code);
|
||||
|
||||
newCode->glyphStartPixel = code->glyphEndPixel + 1;
|
||||
newCode->glyphEndPixel = code->glyphEndPixel + glyphWidth;
|
||||
newCode->rowNumber = rowNumber;
|
||||
newCode->bitmapData.CopyFrom(data);
|
||||
newCode->GenerateTextureCoords(rowNumber, glyphCellHeight);
|
||||
|
||||
inserted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return newCode;
|
||||
}
|
||||
|
||||
void TEXTURECACHEROW::EvictGlyph(CHARCODEDESC* desc) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void TEXTURECACHE::TextureCallback(EGxTexCommand cmd, uint32_t w, uint32_t h, uint32_t d, uint32_t mipLevel, void* userArg, uint32_t& texelStrideInBytes, const void*& texels) {
|
||||
TEXTURECACHE* cache = static_cast<TEXTURECACHE*>(userArg);
|
||||
|
||||
switch (cmd) {
|
||||
case GxTex_Latch: {
|
||||
for (int32_t i = cache->m_textureRows.Count() - 1; i >= 0; i--) {
|
||||
auto& cacheRow = cache->m_textureRows[i];
|
||||
|
||||
for (auto glyph = cacheRow.glyphList.Head(); glyph; glyph = cacheRow.glyphList.Next(glyph)) {
|
||||
cache->WriteGlyphToTexture(glyph);
|
||||
}
|
||||
}
|
||||
|
||||
texelStrideInBytes = 512;
|
||||
texels = TEXTURECACHE::s_textureData;
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CHARCODEDESC* TEXTURECACHE::AllocateNewGlyph(GLYPHBITMAPDATA* data) {
|
||||
for (int32_t i = 0; i < this->m_textureRows.Count(); i++) {
|
||||
auto& cacheRow = this->m_textureRows[i];
|
||||
CHARCODEDESC* glyph = cacheRow.CreateNewDesc(data, i, this->m_theFace->m_cellHeight);
|
||||
|
||||
if (glyph) {
|
||||
return glyph;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TEXTURECACHE::CreateTexture(int32_t filter) {
|
||||
CGxTexFlags flags = CGxTexFlags(filter ? GxTex_Linear : GxTex_Nearest, 0, 0, 0, 0, 0, 1);
|
||||
|
||||
HTEXTURE texture = TextureCreate(
|
||||
256,
|
||||
256,
|
||||
GxTex_Argb4444,
|
||||
GxTex_Argb4444,
|
||||
flags,
|
||||
this,
|
||||
TEXTURECACHE::TextureCallback,
|
||||
"GxuFont",
|
||||
0
|
||||
);
|
||||
|
||||
this->m_texture = texture;
|
||||
}
|
||||
|
||||
void TEXTURECACHE::Initialize(CGxFont* face, uint32_t pixelSize) {
|
||||
this->m_theFace = face;
|
||||
|
||||
uint32_t rowCount = 256 / pixelSize;
|
||||
this->m_textureRows.SetCount(rowCount);
|
||||
|
||||
for (int32_t i = 0; i < rowCount; i++) {
|
||||
this->m_textureRows[i].widestFreeSlot = 256;
|
||||
}
|
||||
}
|
||||
|
||||
void TEXTURECACHE::PasteGlyph(const GLYPHBITMAPDATA& data, uint16_t* dst) {
|
||||
if (this->m_theFace->m_flags & FONT_OUTLINE) {
|
||||
if (this->m_theFace->m_flags & FONT_MONOCHROME) {
|
||||
this->PasteGlyphOutlinedMonochrome(data, dst);
|
||||
} else {
|
||||
this->PasteGlyphOutlinedAA(data, dst);
|
||||
}
|
||||
} else if (this->m_theFace->m_flags & FONT_MONOCHROME) {
|
||||
this->PasteGlyphNonOutlinedMonochrome(data, dst);
|
||||
} else {
|
||||
this->PasteGlyphNonOutlinedAA(data, dst);
|
||||
}
|
||||
}
|
||||
|
||||
void TEXTURECACHE::PasteGlyphNonOutlinedAA(const GLYPHBITMAPDATA& glyphData, uint16_t* dst) {
|
||||
auto src = reinterpret_cast<uint8_t*>(glyphData.m_data);
|
||||
auto pitch = glyphData.m_glyphPitch;
|
||||
auto dstCellStride = glyphData.m_glyphCellWidth * 2;
|
||||
|
||||
for (int32_t y = 0; y < glyphData.m_yStart; y++) {
|
||||
memset(dst, 0, dstCellStride);
|
||||
dst += 256;
|
||||
}
|
||||
|
||||
for (int32_t y = 0; y < glyphData.m_glyphHeight; y++) {
|
||||
for (int32_t x = 0; x < glyphData.m_glyphWidth; x++) {
|
||||
dst[x] = ((src[x] & 0xF0) << 8) | 0xFFF;
|
||||
}
|
||||
|
||||
src += pitch;
|
||||
dst += 256;
|
||||
}
|
||||
|
||||
auto glyphHeight = glyphData.m_glyphHeight;
|
||||
auto yStart = glyphData.m_yStart;
|
||||
if (this->m_theFace->m_cellHeight - glyphHeight - yStart > 0 && this->m_theFace->m_cellHeight - glyphHeight != yStart) {
|
||||
for (int32_t y = 0; y < this->m_theFace->m_cellHeight - glyphHeight - yStart; y++) {
|
||||
memset(dst, 0, dstCellStride);
|
||||
dst += 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TEXTURECACHE::PasteGlyphNonOutlinedMonochrome(const GLYPHBITMAPDATA& data, uint16_t* dst) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void TEXTURECACHE::PasteGlyphOutlinedAA(const GLYPHBITMAPDATA& glyphData, uint16_t* dst) {
|
||||
uint32_t v6;
|
||||
uint32_t v7;
|
||||
uint16_t* v8;
|
||||
int32_t v9;
|
||||
int32_t v15;
|
||||
int32_t v16;
|
||||
uint32_t v17;
|
||||
uint32_t v18;
|
||||
uint32_t v19;
|
||||
uint32_t v20;
|
||||
int32_t v21;
|
||||
int32_t v22;
|
||||
int32_t v23;
|
||||
int32_t v24;
|
||||
int32_t v25;
|
||||
uint32_t v26;
|
||||
uint32_t v27;
|
||||
uint32_t v28;
|
||||
bool v29;
|
||||
bool v30;
|
||||
int32_t v31;
|
||||
int32_t v32;
|
||||
int32_t v33;
|
||||
int32_t v34;
|
||||
int32_t v35;
|
||||
int32_t v36;
|
||||
bool v37;
|
||||
int32_t v38;
|
||||
int32_t v39;
|
||||
int32_t v40;
|
||||
uint32_t v41;
|
||||
uint8_t v42;
|
||||
bool v43;
|
||||
uint16_t v44[9216];
|
||||
uint16_t v45[9216];
|
||||
uint16_t v46[9216];
|
||||
uint32_t v49;
|
||||
uint16_t* v52;
|
||||
uint32_t v52_2;
|
||||
uint32_t v52_3;
|
||||
int32_t v53;
|
||||
|
||||
static uint8_t pixelsLitLevels[] = {
|
||||
0, 1, 1, 3, 5, 7, 9, 0xB, 0xD, 0xF, 0, 0
|
||||
};
|
||||
|
||||
const char* src = reinterpret_cast<char*>(glyphData.m_data);
|
||||
uint32_t thick = this->m_theFace->m_flags & 0x8;
|
||||
|
||||
memset(v45, 0, sizeof(v45));
|
||||
memset(v46, 0, sizeof(v46));
|
||||
|
||||
uint32_t ofs = thick
|
||||
? 256 * glyphData.m_yStart + 258
|
||||
: 256 * glyphData.m_yStart + 257;
|
||||
|
||||
for (int32_t y = 0; y < glyphData.m_glyphHeight; y++) {
|
||||
for (int32_t x = 0; x < glyphData.m_glyphWidth; x++) {
|
||||
uint8_t v10 = src[(y * glyphData.m_glyphPitch) + x];
|
||||
|
||||
if (v10) {
|
||||
v45[ofs + (y * 256) + x] = v10;
|
||||
v46[ofs + (y * 256) + x] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v52_2 = 0;
|
||||
|
||||
v15 = glyphData.m_yStart - 1;
|
||||
|
||||
for (int32_t i = 0; i < (thick != 0) + 1; i++) {
|
||||
v49 = 2 * (i != 0) + 2;
|
||||
v16 = 2 * (i != 0) + 1;
|
||||
v17 = v15 < 0 ? 0 : v15;
|
||||
v53 = v15 < 0 ? 0 : v15;
|
||||
|
||||
if (v17 >= this->m_theFace->m_cellHeight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
v18 = glyphData.m_glyphCellWidth;
|
||||
v19 = v17 << 8;
|
||||
v20 = 0;
|
||||
|
||||
if (!v18) {
|
||||
goto LABEL_68;
|
||||
}
|
||||
|
||||
do {
|
||||
v21 = v19 + v20;
|
||||
|
||||
if (v46[v19 + v20] & v16) {
|
||||
goto LABEL_66;
|
||||
}
|
||||
|
||||
if (v53) {
|
||||
if (v53 == this->m_theFace->m_cellHeight - 1) {
|
||||
if (v20) {
|
||||
if (v20 == v18 - 1) {
|
||||
if (
|
||||
v46[v21 - 1] & v16
|
||||
|| v46[v19 + v20 - 257] & v16
|
||||
) {
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
v22 = v46[v19 + v20 - 256];
|
||||
} else {
|
||||
if (
|
||||
v46[v19 + v20 - 257] & v16
|
||||
|| v46[v19 + v20 - 256] & v16
|
||||
|| v46[v19 + v20 - 255] & v16
|
||||
|| v46[v21 - 1] & v16
|
||||
) {
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
v22 = v46[v21 + 1];
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
v46[v19 - 256] & v16
|
||||
|| v46[v19 - 255] & v16
|
||||
) {
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
v22 = v46[v19 + 1];
|
||||
}
|
||||
} else if (v20) {
|
||||
v24 = v19 + v20;
|
||||
|
||||
if (v20 == v18 - 1) {
|
||||
if (
|
||||
v46[v24 - 256] & v16
|
||||
|| v46[v19 + v20 - 257] & v16
|
||||
|| v46[v21 - 1] & v16
|
||||
|| v46[v21 + 255] & v16
|
||||
) {
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
v22 = v46[v21 + 256];
|
||||
} else {
|
||||
if (
|
||||
v46[v24 - 257] & v16
|
||||
|| v46[v19 + v20 - 256] & v16
|
||||
|| v46[v19 + v20 - 255] & v16
|
||||
|| v46[v21 - 1] & v16
|
||||
|| v46[v21 + 1] & v16
|
||||
|| v46[v21 + 255] & v16
|
||||
|| v46[v21 + 256] & v16
|
||||
) {
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
v22 = v46[v21 + 257];
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
v46[v19 - 256] & v16
|
||||
|| v46[v19 - 255] & v16
|
||||
|| v46[v19 + 1] & v16
|
||||
|| v46[v19 + 257] & v16
|
||||
) {
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
v22 = v46[v19 + 256];
|
||||
}
|
||||
LABEL_64:
|
||||
if (!(v22 & v16)) {
|
||||
goto LABEL_66;
|
||||
}
|
||||
|
||||
goto LABEL_65;
|
||||
}
|
||||
|
||||
if (v20) {
|
||||
v23 = v46[v20 - 1];
|
||||
|
||||
if (v20 == v18 - 1) {
|
||||
if (!(v23 & v16) && !(v46[v20 + 255] & v16)) {
|
||||
v22 = v46[v20 + 256];
|
||||
goto LABEL_64;
|
||||
}
|
||||
} else if (!(v23 & v16) && !(v46[v20 + 1] & v16) && !(v46[v20 + 255] & v16) && !(v46[v20 + 256] & v16)) {
|
||||
v22 = v46[v20 + 257];
|
||||
goto LABEL_64;
|
||||
}
|
||||
} else if (!(v46[1] & v16) && !(v46[257] & v16)) {
|
||||
v22 = v46[256];
|
||||
goto LABEL_64;
|
||||
}
|
||||
LABEL_65:
|
||||
v46[v21] = v49;
|
||||
LABEL_66:
|
||||
++v20;
|
||||
} while (v20 < v18);
|
||||
|
||||
v17 = v53;
|
||||
LABEL_68:
|
||||
v53 = ++v17;
|
||||
} while (v17 < this->m_theFace->m_cellHeight);
|
||||
}
|
||||
|
||||
memset(v44, 0, sizeof(v44));
|
||||
|
||||
v26 = 0;
|
||||
v53 = 0;
|
||||
|
||||
if (!this->m_theFace->m_cellHeight) {
|
||||
goto LABEL_95;
|
||||
}
|
||||
|
||||
while (2) {
|
||||
v27 = glyphData.m_glyphCellWidth;
|
||||
v28 = v26 << 8;
|
||||
v25 = 0;
|
||||
|
||||
if (!v27) {
|
||||
goto LABEL_94;
|
||||
}
|
||||
|
||||
while (2) {
|
||||
v37 = v46[v28 + v25] == 0;
|
||||
v52 = &v46[v28 + v25];
|
||||
v29 = !v37;
|
||||
v30 = !v37;
|
||||
|
||||
if (v26) {
|
||||
if (v53 == this->m_theFace->m_cellHeight - 1) {
|
||||
if (!v25) {
|
||||
v31 = v30 + (v46[v28 + 1] != 0) + (v46[v28 - 255] != 0) + (v46[v28 - 256] != 0);
|
||||
goto LABEL_92;
|
||||
}
|
||||
|
||||
v37 = v25 == v27 - 1;
|
||||
v34 = v28 + v25;
|
||||
|
||||
if (v37) {
|
||||
v31 = (v46[v28 + v25 - 256] != 0) + (v46[v34 - 257] != 0) + v30 + (*(v52 - 1) != 0);
|
||||
goto LABEL_92;
|
||||
}
|
||||
|
||||
v35 = (v46[v34 - 256] != 0) + (v46[v28 + v25 - 257] != 0);
|
||||
v36 = 0;
|
||||
v37 = v46[v28 + v25 - 255] == 0;
|
||||
v38 = v28 + v25;
|
||||
} else {
|
||||
if (!v25) {
|
||||
v31 = v30
|
||||
+ (v46[v28 + 256] != 0)
|
||||
+ (v46[v28 + 1] != 0)
|
||||
+ (v46[v28 + 257] != 0)
|
||||
+ (v46[v28 - 255] != 0)
|
||||
+ (v46[v28 - 256] != 0);
|
||||
|
||||
goto LABEL_92;
|
||||
}
|
||||
|
||||
v37 = v25 == v27 - 1;
|
||||
v39 = v28 + v25;
|
||||
|
||||
if (v37) {
|
||||
v31 = (v46[v28 + v25 + 256] != 0)
|
||||
+ (v46[v28 + v25 + 255] != 0)
|
||||
+ (v46[v28 + v25 - 256] != 0)
|
||||
+ (v46[v39 - 257] != 0)
|
||||
+ v30
|
||||
+ (*(v52 - 1) != 0);
|
||||
|
||||
goto LABEL_92;
|
||||
}
|
||||
|
||||
v37 = v46[v39 - 256] == 0;
|
||||
v38 = v28 + v25;
|
||||
v35 = (v46[v28 + v25 + 256] != 0)
|
||||
+ (v46[v28 + v25 + 255] != 0)
|
||||
+ (v46[v28 + v25 - 255] != 0)
|
||||
+ !v37
|
||||
+ (v46[v28 + v25 - 257] != 0);
|
||||
v36 = 0;
|
||||
v37 = v46[v28 + v25 + 257] == 0;
|
||||
}
|
||||
|
||||
v36 = !v37;
|
||||
v31 = (v46[v38 + 1] != 0) + v36 + v35 + v30 + (*(v52 - 1) != 0);
|
||||
} else if (v25) {
|
||||
if (v25 == v27 - 1) {
|
||||
v32 = (v46[v25 + 255] != 0) + (v46[v25 - 1] != 0);
|
||||
v33 = v29 + (v46[v25 + 256] != 0);
|
||||
} else {
|
||||
v32 = (v46[v25 + 257] != 0)
|
||||
+ (v46[v25 + 256] != 0)
|
||||
+ (v46[v25 + 255] != 0)
|
||||
+ (v46[v25 - 1] != 0);
|
||||
v33 = v29 + (v46[v25 + 1] != 0);
|
||||
}
|
||||
|
||||
v31 = v33 + v32;
|
||||
} else {
|
||||
v31 = v29 + (v46[1] != 0) + (v46[257] != 0) + (v46[256] != 0);
|
||||
}
|
||||
LABEL_92:
|
||||
v26 = v53;
|
||||
|
||||
v44[v28 + v25] = pixelsLitLevels[v31];
|
||||
|
||||
v27 = glyphData.m_glyphCellWidth;
|
||||
|
||||
if (++v25 < v27) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LABEL_94:
|
||||
v53 = ++v26;
|
||||
|
||||
if (v26 < this->m_theFace->m_cellHeight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LABEL_95:
|
||||
v40 = 0;
|
||||
|
||||
for (int32_t y = 0; y < this->m_theFace->m_cellHeight; y++) {
|
||||
for (int32_t x = 0; x < glyphData.m_glyphCellWidth; x++) {
|
||||
if (v46[v40 + x]) {
|
||||
if (v45[v40 + x]) {
|
||||
v42 = (255 * v45[v40 + x]) >> 12;
|
||||
dst[v40 + x] = v42 | (16 * (v42 | (16 * (v42 | (16 * v44[v40 + x])))));
|
||||
} else {
|
||||
dst[v40 + x] = v44[v40 + x] << 12;
|
||||
}
|
||||
} else {
|
||||
dst[v40 + x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
v40 += 256;
|
||||
}
|
||||
}
|
||||
|
||||
void TEXTURECACHE::PasteGlyphOutlinedMonochrome(const GLYPHBITMAPDATA& data, uint16_t* dst) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void TEXTURECACHE::UpdateDirty() {
|
||||
if (this->m_anyDirtyGlyphs && this->m_texture) {
|
||||
CGxTex* gxTex = TextureGetGxTex(this->m_texture, 1, nullptr);
|
||||
CiRect updateRect = { 0, 0, 256, 256 };
|
||||
GxTexUpdate(gxTex, updateRect, 1);
|
||||
|
||||
this->m_anyDirtyGlyphs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TEXTURECACHE::WriteGlyphToTexture(CHARCODEDESC* glyph) {
|
||||
if (!this->m_texture || !this->m_theFace || !this->m_theFace->m_cellHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t ofs = glyph->glyphStartPixel + (glyph->rowNumber * this->m_theFace->m_cellHeight << 8);
|
||||
uint16_t* ptr = &TEXTURECACHE::s_textureData[ofs];
|
||||
|
||||
this->PasteGlyph(glyph->bitmapData, ptr);
|
||||
}
|
||||
|
||||
CGxFont::~CGxFont() {
|
||||
this->Clear();
|
||||
}
|
||||
|
||||
int32_t CGxFont::CheckStringGlyphs(const char* string) {
|
||||
if (!string || !*string) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (*string) {
|
||||
int32_t advance;
|
||||
auto code = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(string), &advance);
|
||||
|
||||
HASHKEY_NONE key = {};
|
||||
|
||||
if (code != '\r' && code != '\n' && !this->m_activeCharacters.Ptr(code, key)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
string += advance;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CGxFont::Clear() {
|
||||
if (this->m_faceHandle) {
|
||||
FontFaceCloseHandle(this->m_faceHandle);
|
||||
}
|
||||
|
||||
this->m_faceHandle = nullptr;
|
||||
|
||||
this->ClearGlyphs();
|
||||
}
|
||||
|
||||
void CGxFont::ClearGlyphs() {
|
||||
for (int32_t i = 0; i < 8; i++) {
|
||||
auto& cache = this->m_textureCache[i];
|
||||
|
||||
if (cache.m_texture) {
|
||||
HandleClose(this->m_textureCache[i].m_texture);
|
||||
}
|
||||
|
||||
cache.m_texture = nullptr;
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
this->m_activeCharacters.Clear();
|
||||
|
||||
this->m_activeCharacterCache.DeleteAll();
|
||||
|
||||
this->m_kernInfo.Clear();
|
||||
}
|
||||
|
||||
float CGxFont::ComputeStep(uint32_t currentCode, uint32_t nextCode) {
|
||||
KERNINGHASHKEY kernKey = { nextCode | (currentCode << 16) };
|
||||
KERNNODE* kern = this->m_kernInfo.Ptr(currentCode, kernKey);
|
||||
|
||||
if (kern && kern->flags & 0x02) {
|
||||
return kern->proporportionalSpacing;
|
||||
}
|
||||
|
||||
auto face = FontFaceGetFace(this->m_faceHandle);
|
||||
auto currentIndex = FT_Get_Char_Index(face, currentCode);
|
||||
auto nextIndex = FT_Get_Char_Index(face, nextCode);
|
||||
|
||||
FT_Vector vector;
|
||||
vector.x = 0;
|
||||
|
||||
if (face->face_flags & FT_FACE_FLAG_KERNING) {
|
||||
FT_Get_Kerning(face, currentIndex, nextIndex, ft_kerning_unscaled, &vector);
|
||||
vector.x &= (vector.x >= 0) - 1;
|
||||
}
|
||||
|
||||
HASHKEY_NONE charKey = {};
|
||||
auto activeChar = this->m_activeCharacters.Ptr(currentCode, charKey);
|
||||
|
||||
float advance = 0.0f;
|
||||
|
||||
if (activeChar) {
|
||||
advance = this->m_flags & 0x08
|
||||
? activeChar->bitmapData.m_glyphAdvance + 1.0f
|
||||
: activeChar->bitmapData.m_glyphAdvance;
|
||||
}
|
||||
|
||||
float spacing = (this->m_pixelsPerUnit * vector.x) + advance;
|
||||
|
||||
if (!kern) {
|
||||
kern = this->m_kernInfo.New(currentCode, kernKey, 0, 0);
|
||||
}
|
||||
|
||||
kern->flags |= 0x02;
|
||||
kern->proporportionalSpacing = ceil(spacing);
|
||||
|
||||
return kern->proporportionalSpacing;
|
||||
}
|
||||
|
||||
float CGxFont::ComputeStepFixedWidth(uint32_t currentCode, uint32_t nextCode) {
|
||||
// TODO
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float CGxFont::GetGlyphBearing(const CHARCODEDESC* glyph, bool billboarded, float height) {
|
||||
if (billboarded) {
|
||||
float v8 = ScreenToPixelHeight(1, height) / this->GetPixelSize();
|
||||
return glyph->bitmapData.m_glyphBearing * v8;
|
||||
}
|
||||
|
||||
return ceil(glyph->bitmapData.m_glyphBearing);
|
||||
}
|
||||
|
||||
int32_t CGxFont::GetGlyphData(GLYPHBITMAPDATA* glyphData, uint32_t code) {
|
||||
FT_Face face = FontFaceGetFace(this->m_faceHandle);
|
||||
FT_Set_Pixel_Sizes(face, this->m_pixelSize, 0);
|
||||
|
||||
uint32_t v6 = 0;
|
||||
|
||||
if (this->m_flags & 0x8) {
|
||||
v6 = 4;
|
||||
} else if (this->m_flags & FONT_OUTLINE) {
|
||||
v6 = 2;
|
||||
}
|
||||
|
||||
return IGxuFontGlyphRenderGlyph(
|
||||
face,
|
||||
this->m_pixelSize,
|
||||
code,
|
||||
this->m_baseline,
|
||||
glyphData,
|
||||
this->m_flags & FONT_MONOCHROME,
|
||||
v6
|
||||
);
|
||||
}
|
||||
|
||||
const char* CGxFont::GetName(void) const {
|
||||
STORM_ASSERT(this->m_faceHandle);
|
||||
|
||||
return FontFaceGetFontName(this->m_faceHandle);
|
||||
}
|
||||
|
||||
uint32_t CGxFont::GetPixelSize() {
|
||||
return this->m_pixelSize;
|
||||
}
|
||||
|
||||
int32_t CGxFont::Initialize(const char* name, uint32_t newFlags, float fontHeight) {
|
||||
SStrPrintf(this->m_fontName, 260, "%s", name);
|
||||
|
||||
this->m_requestedFontHeight = fontHeight;
|
||||
|
||||
this->Clear();
|
||||
|
||||
this->m_flags = newFlags;
|
||||
|
||||
this->m_faceHandle = FontFaceGetHandle(name, GetFreeTypeLibrary());
|
||||
|
||||
if (this->m_faceHandle) {
|
||||
return this->UpdateDimensions();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const CHARCODEDESC* CGxFont::NewCodeDesc(uint32_t code) {
|
||||
HASHKEY_NONE key = {};
|
||||
CHARCODEDESC* charDesc = this->m_activeCharacters.Ptr(code, key);
|
||||
|
||||
if (charDesc) {
|
||||
this->m_activeCharacterCache.LinkToHead(charDesc);
|
||||
return charDesc;
|
||||
}
|
||||
|
||||
GLYPHBITMAPDATA data;
|
||||
|
||||
if (!CGxFont::GetGlyphData(&data, code)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Attempt to allocate the character off of texture caches
|
||||
for (uint32_t textureNumber = 0; textureNumber < 8; textureNumber++) {
|
||||
TEXTURECACHE* textureCache = &this->m_textureCache[textureNumber];
|
||||
|
||||
if (textureCache->m_texture && TextureGetGxTex(reinterpret_cast<CTexture*>(textureCache->m_texture), 1, nullptr)) {
|
||||
charDesc = textureCache->AllocateNewGlyph(&data);
|
||||
|
||||
if (charDesc) {
|
||||
charDesc->textureNumber = textureNumber;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
textureCache->CreateTexture(this->m_flags & 0x4);
|
||||
textureCache->Initialize(this, this->m_cellHeight);
|
||||
|
||||
charDesc = textureCache->AllocateNewGlyph(&data);
|
||||
|
||||
if (charDesc) {
|
||||
charDesc->textureNumber = textureNumber;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No character was allocated from the texture caches, so evict the oldest character and
|
||||
// attempt to allocate from that character's texture cache row
|
||||
if (!charDesc) {
|
||||
CHARCODEDESC* oldestDesc = this->m_activeCharacterCache.Tail();
|
||||
|
||||
if (oldestDesc) {
|
||||
uint32_t textureNumber = oldestDesc->textureNumber;
|
||||
uint32_t rowNumber = oldestDesc->rowNumber;
|
||||
|
||||
TEXTURECACHE* textureCache = &this->m_textureCache[textureNumber];
|
||||
TEXTURECACHEROW* cacheRow = &textureCache->m_textureRows[rowNumber];
|
||||
cacheRow->EvictGlyph(oldestDesc);
|
||||
|
||||
this->RegisterEvictNotice(textureNumber);
|
||||
|
||||
charDesc = cacheRow->CreateNewDesc(&data, rowNumber, this->m_cellHeight);
|
||||
|
||||
if (charDesc) {
|
||||
charDesc->rowNumber = rowNumber;
|
||||
charDesc->textureNumber = textureNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (charDesc) {
|
||||
this->m_activeCharacters.Insert(charDesc, code, key);
|
||||
this->m_activeCharacterCache.LinkToHead(charDesc);
|
||||
this->m_textureCache[charDesc->textureNumber].m_anyDirtyGlyphs = 1;
|
||||
}
|
||||
|
||||
return charDesc;
|
||||
}
|
||||
|
||||
void CGxFont::RegisterEvictNotice(uint32_t a2) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int32_t CGxFont::UpdateDimensions() {
|
||||
FT_Face theFace = FontFaceGetFace(this->m_faceHandle);
|
||||
|
||||
float v11 = Sub6C2280(theFace, this->m_requestedFontHeight);
|
||||
float v3 = 2.0 / GetScreenPixelHeight();
|
||||
|
||||
if (v11 > v3) {
|
||||
v3 = v11;
|
||||
}
|
||||
|
||||
float height = v3;
|
||||
|
||||
uint32_t pixelSize = ScreenToPixelHeight(0, height);
|
||||
|
||||
if (pixelSize <= 32) {
|
||||
if (!pixelSize) {
|
||||
// TODO
|
||||
// nullsub_3();
|
||||
}
|
||||
} else {
|
||||
pixelSize = 32;
|
||||
}
|
||||
|
||||
this->m_pixelSize = pixelSize;
|
||||
|
||||
uint32_t v10 = theFace->ascender + abs(theFace->descender);
|
||||
|
||||
if (!v10) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->m_cellHeight = pixelSize;
|
||||
float baseline = (double)(pixelSize * theFace->ascender) / (double)v10;
|
||||
|
||||
this->m_baseline = (int64_t)(baseline + 0.5);
|
||||
|
||||
uint32_t flags = this->m_flags;
|
||||
|
||||
if (flags & 0x8) {
|
||||
this->m_cellHeight = pixelSize + 4;
|
||||
} else if (flags & 0x1) {
|
||||
this->m_cellHeight = pixelSize + 2;
|
||||
}
|
||||
|
||||
int32_t result = FT_Set_Pixel_Sizes(theFace, pixelSize, 0) == FT_Err_Ok;
|
||||
|
||||
this->m_pixelsPerUnit = (double)theFace->size->metrics.x_ppem / (double)theFace->units_per_EM;
|
||||
|
||||
return result;
|
||||
}
|
||||
141
src/gx/font/CGxFont.hpp
Normal file
141
src/gx/font/CGxFont.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#ifndef GX_C_GX_FONT_HPP
|
||||
#define GX_C_GX_FONT_HPP
|
||||
|
||||
#include "gx/font/CGxString.hpp"
|
||||
#include "gx/Font.hpp"
|
||||
#include "gx/Texture.hpp"
|
||||
#include <cstdint>
|
||||
#include <storm/Hash.hpp>
|
||||
#include <storm/List.hpp>
|
||||
|
||||
class CTexture;
|
||||
|
||||
class GLYPHBITMAPDATA {
|
||||
public:
|
||||
// Member variables
|
||||
void* m_data = nullptr;
|
||||
uint32_t m_dataSize = 0;
|
||||
uint32_t m_glyphWidth;
|
||||
uint32_t m_glyphHeight;
|
||||
uint32_t m_glyphCellWidth;
|
||||
float m_glyphAdvance;
|
||||
float m_glyphBearing;
|
||||
uint32_t m_glyphPitch;
|
||||
int32_t m_yOffset;
|
||||
int32_t m_yStart;
|
||||
CRect m_textureCoords;
|
||||
|
||||
// Member functions
|
||||
~GLYPHBITMAPDATA();
|
||||
void CopyFrom(GLYPHBITMAPDATA*);
|
||||
};
|
||||
|
||||
class CHARCODEDESC : public TSHashObject<CHARCODEDESC, HASHKEY_NONE> {
|
||||
public:
|
||||
// Member variables
|
||||
TSLink<CHARCODEDESC> textureRowLink;
|
||||
TSLink<CHARCODEDESC> fontGlyphLink;
|
||||
uint32_t textureNumber = -1;
|
||||
uint32_t rowNumber = -1;
|
||||
uint32_t glyphStartPixel = -1;
|
||||
uint32_t glyphEndPixel = 0;
|
||||
GLYPHBITMAPDATA bitmapData;
|
||||
|
||||
// Member functions
|
||||
uint32_t GapToNextTexture(void);
|
||||
uint32_t GapToPreviousTexture(void);
|
||||
void GenerateTextureCoords(uint32_t, uint32_t);
|
||||
};
|
||||
|
||||
class KERNINGHASHKEY {
|
||||
public:
|
||||
// Member variables
|
||||
uint32_t code;
|
||||
|
||||
// Member functions
|
||||
KERNINGHASHKEY& operator=(const KERNINGHASHKEY&);
|
||||
bool operator==(const KERNINGHASHKEY&);
|
||||
};
|
||||
|
||||
class KERNNODE : public TSHashObject<KERNNODE, KERNINGHASHKEY> {
|
||||
public:
|
||||
// Member variables
|
||||
uint32_t flags = 0x0;
|
||||
float proporportionalSpacing = 0.0f;
|
||||
float fixedWidthSpacing = 0.0f;
|
||||
};
|
||||
|
||||
class TEXTURECACHEROW {
|
||||
public:
|
||||
// Member variables
|
||||
uint32_t widestFreeSlot = 0;
|
||||
STORM_EXPLICIT_LIST(CHARCODEDESC, textureRowLink) glyphList;
|
||||
|
||||
// Member functions
|
||||
CHARCODEDESC* CreateNewDesc(GLYPHBITMAPDATA*, uint32_t, uint32_t);
|
||||
void EvictGlyph(CHARCODEDESC*);
|
||||
};
|
||||
|
||||
class TEXTURECACHE {
|
||||
public:
|
||||
// Static variables
|
||||
static uint16_t s_textureData[256 * 256];
|
||||
|
||||
// Static functions
|
||||
static void TextureCallback(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&);
|
||||
|
||||
// Member variables
|
||||
HTEXTURE m_texture = nullptr;
|
||||
CGxFont* m_theFace = nullptr;
|
||||
int8_t m_anyDirtyGlyphs = 0;
|
||||
int8_t pad[3];
|
||||
TSFixedArray<TEXTURECACHEROW> m_textureRows;
|
||||
|
||||
// Member functions
|
||||
CHARCODEDESC* AllocateNewGlyph(GLYPHBITMAPDATA*);
|
||||
void CreateTexture(int32_t);
|
||||
void Initialize(CGxFont*, uint32_t);
|
||||
void PasteGlyph(const GLYPHBITMAPDATA&, uint16_t*);
|
||||
void PasteGlyphNonOutlinedAA(const GLYPHBITMAPDATA&, uint16_t*);
|
||||
void PasteGlyphNonOutlinedMonochrome(const GLYPHBITMAPDATA&, uint16_t*);
|
||||
void PasteGlyphOutlinedAA(const GLYPHBITMAPDATA&, uint16_t*);
|
||||
void PasteGlyphOutlinedMonochrome(const GLYPHBITMAPDATA&, uint16_t*);
|
||||
void UpdateDirty(void);
|
||||
void WriteGlyphToTexture(CHARCODEDESC*);
|
||||
};
|
||||
|
||||
class CGxFont : public TSLinkedNode<CGxFont> {
|
||||
public:
|
||||
// Member variables
|
||||
STORM_EXPLICIT_LIST(CGxString, m_fontStringLink) m_strings;
|
||||
TSHashTable<CHARCODEDESC, HASHKEY_NONE> m_activeCharacters;
|
||||
TSHashTable<KERNNODE, KERNINGHASHKEY> m_kernInfo;
|
||||
STORM_EXPLICIT_LIST(CHARCODEDESC, fontGlyphLink) m_activeCharacterCache;
|
||||
HFACE m_faceHandle;
|
||||
char m_fontName[260];
|
||||
uint32_t m_cellHeight = 0;
|
||||
uint32_t m_baseline;
|
||||
uint32_t m_flags;
|
||||
float m_requestedFontHeight;
|
||||
float m_pixelsPerUnit = 0.0f;
|
||||
TEXTURECACHE m_textureCache[8];
|
||||
uint32_t m_pixelSize;
|
||||
|
||||
// Member functions
|
||||
~CGxFont();
|
||||
int32_t CheckStringGlyphs(const char*);
|
||||
void Clear(void);
|
||||
void ClearGlyphs(void);
|
||||
float ComputeStep(uint32_t, uint32_t);
|
||||
float ComputeStepFixedWidth(uint32_t, uint32_t);
|
||||
float GetGlyphBearing(const CHARCODEDESC*, bool, float);
|
||||
int32_t GetGlyphData(GLYPHBITMAPDATA*, uint32_t);
|
||||
const char* GetName(void) const;
|
||||
uint32_t GetPixelSize(void);
|
||||
int32_t Initialize(const char*, uint32_t, float);
|
||||
const CHARCODEDESC* NewCodeDesc(uint32_t);
|
||||
void RegisterEvictNotice(uint32_t);
|
||||
int32_t UpdateDimensions(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
638
src/gx/font/CGxString.cpp
Normal file
638
src/gx/font/CGxString.cpp
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
#include "gx/font/CGxString.hpp"
|
||||
#include "gx/Buffer.hpp"
|
||||
#include "gx/font/CGxFont.hpp"
|
||||
#include "gx/font/Wrap.hpp"
|
||||
#include "gx/Font.hpp"
|
||||
#include "gx/Gx.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <new>
|
||||
#include <storm/Memory.hpp>
|
||||
#include <storm/String.hpp>
|
||||
#include <tempest/Math.hpp>
|
||||
|
||||
TEXTLINETEXTURE* TEXTLINETEXTURE::NewTextLineTexture() {
|
||||
// TODO
|
||||
// Allocate off of TEXTLINETEXTURE::s_freeTextLineTextures
|
||||
|
||||
void* m = SMemAlloc(sizeof(TEXTLINETEXTURE), __FILE__, __LINE__, 0x0);
|
||||
return new (m) TEXTLINETEXTURE();
|
||||
}
|
||||
|
||||
void TEXTLINETEXTURE::Recycle(TEXTLINETEXTURE* ptr) {
|
||||
// TODO if (TEXTLINETEXTURE::s_recycledBytes <= 0x80000)
|
||||
|
||||
if (ptr) {
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TEXTLINETEXTURE::WriteGeometry(CGxVertexPCT* buf, const CImVector& fontColor, const C2Vector& shadowOffset, const CImVector& shadowColor, const C3Vector& viewTranslation, bool a7, bool a8, int32_t ofs, int32_t size) {
|
||||
if (!size || !this->m_vert.Count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t colorCount = this->m_vert.Count() == this->m_colors.Count()
|
||||
? this->m_colors.Count()
|
||||
: 0;
|
||||
|
||||
if (ofs >= this->m_vert.Count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t v24 = this->m_vert.Count() - ofs;
|
||||
|
||||
if (size >= v24) {
|
||||
size = v24;
|
||||
}
|
||||
|
||||
if (a7) {
|
||||
C3Vector shadowTranslation = {
|
||||
viewTranslation.x + floor(ScreenToPixelWidth(0, shadowOffset.x)),
|
||||
viewTranslation.y + floor(ScreenToPixelHeight(0, shadowOffset.y)),
|
||||
viewTranslation.z
|
||||
};
|
||||
|
||||
auto color = colorCount ? this->m_colors[ofs] : fontColor;
|
||||
|
||||
for (int32_t i = 0; i < size; i++) {
|
||||
auto& vert = this->m_vert[i + ofs];
|
||||
|
||||
C3Vector p = {
|
||||
vert.vc.x + shadowTranslation.x,
|
||||
vert.vc.y + shadowTranslation.y,
|
||||
vert.vc.z + shadowTranslation.z
|
||||
};
|
||||
|
||||
buf->p = p;
|
||||
buf->tc[0] = vert.tc;
|
||||
|
||||
auto formattedShadowColor = shadowColor;
|
||||
if (a8 && colorCount) {
|
||||
formattedShadowColor.a = static_cast<uint8_t>(
|
||||
(static_cast<float>(formattedShadowColor.a) * static_cast<float>(color.a)) / 65536.0f
|
||||
);
|
||||
}
|
||||
GxFormatColor(formattedShadowColor);
|
||||
buf->c = formattedShadowColor;
|
||||
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
// if (BATCHEDRENDERFONTDESC::s_billboarded) {
|
||||
// // TODO
|
||||
// }
|
||||
|
||||
for (int32_t i = 0; i < size; i++) {
|
||||
auto& vert = this->m_vert[i + ofs];
|
||||
|
||||
auto color = colorCount ? this->m_colors[i + ofs] : fontColor;
|
||||
GxFormatColor(color);
|
||||
|
||||
// if (BATCHEDRENDERFONTDESC::s_billboarded) {
|
||||
// // TODO
|
||||
// continue;
|
||||
// }
|
||||
|
||||
C3Vector p = {
|
||||
vert.vc.x + viewTranslation.x,
|
||||
vert.vc.y + viewTranslation.y,
|
||||
vert.vc.z + viewTranslation.z
|
||||
};
|
||||
|
||||
buf->p = p;
|
||||
buf->tc[0] = vert.tc;
|
||||
|
||||
buf->c = color;
|
||||
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
CGxString* CGxString::GetNewString(int32_t linkOnList) {
|
||||
CGxString* string = g_freeStrings.Head();
|
||||
|
||||
if (string) {
|
||||
g_strings.LinkToTail(string);
|
||||
return string;
|
||||
}
|
||||
|
||||
void* m = SMemAlloc(sizeof(CGxString), __FILE__, __LINE__, 0x8);
|
||||
string = new (m) CGxString();
|
||||
|
||||
if (linkOnList) {
|
||||
g_strings.LinkToTail(string);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
CGxString::~CGxString() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void CGxString::AddShadow(const C2Vector& offset, const CImVector& color) {
|
||||
this->m_shadowColor = color;
|
||||
this->m_shadowColor.a = std::min(this->m_shadowColor.a, this->m_fontColor.a);
|
||||
this->m_shadowOffset = offset;
|
||||
|
||||
this->m_flags |= 0x1;
|
||||
|
||||
if (this->m_flags & 0x20) {
|
||||
this->ClearInstanceData();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CGxString::CalculateVertsNeeded(int32_t line) {
|
||||
if (this->m_flags & 0x01) {
|
||||
return 2 * this->m_textLines[line]->m_vert.Count();
|
||||
}
|
||||
|
||||
return this->m_textLines[line]->m_vert.Count();
|
||||
}
|
||||
|
||||
bool CGxString::CheckGeometry() {
|
||||
if (this->m_textureEvicted) {
|
||||
if (!this->m_currentFace->CheckStringGlyphs(this->m_text)) {
|
||||
this->ClearInstanceData();
|
||||
}
|
||||
|
||||
this->m_textureEvicted = 0;
|
||||
}
|
||||
|
||||
this->CreateGeometry();
|
||||
this->m_intD4 = 0;
|
||||
|
||||
return this->m_intB0 != 0;
|
||||
}
|
||||
|
||||
void CGxString::ClearInstanceData() {
|
||||
// TODO this->m_hyperlinkInfo->SetCount(0);
|
||||
// TODO this->m_textureInfo->SetCount(0);
|
||||
|
||||
// TODO this->dwordA4 = 0;
|
||||
this->m_lastGradientStart = -1;
|
||||
this->m_lastGradientLength = -1;
|
||||
this->m_intB0 = 0;
|
||||
|
||||
for (int32_t i = 0; i < 8; i++) {
|
||||
if (this->m_textLines[i]) {
|
||||
TEXTLINETEXTURE::Recycle(this->m_textLines[i]);
|
||||
this->m_textLines[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGxString::CreateGeometry() {
|
||||
if (this->m_intB0 || !this->m_text || !*this->m_text) {
|
||||
return;
|
||||
}
|
||||
|
||||
EMBEDDEDPARSEINFO info;
|
||||
uint32_t flags = this->m_flags;
|
||||
uint32_t numBytes = 0;
|
||||
const char* currentText = this->m_text;
|
||||
const char* nextText = nullptr;
|
||||
int32_t advance = 0;
|
||||
uint32_t wide = 0;
|
||||
int32_t gStart = this->m_lastGradientStart;
|
||||
int32_t gLength = this->m_lastGradientLength;
|
||||
CImVector lineColor = this->m_fontColor;
|
||||
float height = -this->m_currentFontHeight;
|
||||
C3Vector linePos = {
|
||||
0.0f,
|
||||
this->m_flags & 0x80 ? 0.0f : ScreenToPixelHeight(0, -this->m_currentFontHeight),
|
||||
0.0f
|
||||
};
|
||||
bool a10 = true;
|
||||
float blockWidth = this->m_blockWidth;
|
||||
|
||||
auto v611 = static_cast<float>(CMath::fuint_pi(GetScreenPixelHeight() * this->m_spacing));
|
||||
auto v51 = ScreenToPixelHeight(0, this->m_currentFontHeight);
|
||||
auto spacing = this->m_flags & 0x80 ? this->m_spacing : v611 / static_cast<float>(GetScreenPixelHeight());
|
||||
auto v59 = this->m_flags & 0x80 ? this->m_currentFontHeight + this->m_spacing : v611 + v51;
|
||||
|
||||
float v49 = 0.0f;
|
||||
|
||||
while (*currentText) {
|
||||
if (this->m_blockHeight <= v49) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->m_flags & 0x2000 && this->m_intB0 == 1) {
|
||||
blockWidth -= GetIndentNormWidth();
|
||||
}
|
||||
|
||||
v49 += this->m_currentFontHeight + spacing;
|
||||
|
||||
QUOTEDCODE code = GxuDetermineQuotedCode(currentText, advance, 0, flags, wide);
|
||||
|
||||
if (code == CODE_NEWLINE) {
|
||||
currentText += advance;
|
||||
this->m_intB0++;
|
||||
linePos.y -= v59;
|
||||
|
||||
// TODO
|
||||
// info.dword0C -= v59;
|
||||
// info.dword04 -= v59;
|
||||
// info.dword34 -= v59;
|
||||
// info.dword2C -= v59;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
float extent = 0.0f;
|
||||
float a8 = 0.0f;
|
||||
float a11 = 0.0f;
|
||||
|
||||
if (this->m_flags & 0x1) {
|
||||
a8 = this->m_shadowOffset.x;
|
||||
}
|
||||
|
||||
CalcWrapPoint(
|
||||
this->m_currentFace,
|
||||
currentText,
|
||||
this->m_currentFontHeight,
|
||||
blockWidth,
|
||||
&numBytes,
|
||||
&extent,
|
||||
&nextText,
|
||||
a8,
|
||||
this->m_flags,
|
||||
&a10,
|
||||
&a11,
|
||||
this->m_scale
|
||||
);
|
||||
|
||||
if (nextText == currentText || !nextText || (!numBytes && !*nextText)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->m_horzJust == GxHJ_Right) {
|
||||
float indent = this->m_flags & 0x2000 && this->m_intB0 ? GetIndentPixelWidth() : 0.0f;
|
||||
linePos.x = ScreenToPixelWidth(this->m_flags & 0x80, -extent) - indent;
|
||||
} else if (this->m_horzJust == GxHJ_Center) {
|
||||
linePos.x = ScreenToPixelWidth(this->m_flags & 0x80, -(extent * 0.5f));
|
||||
} else if (this->m_flags & 0x2000 && this->m_intB0) {
|
||||
linePos.x = GetIndentPixelWidth();
|
||||
} else {
|
||||
linePos.x = 0.0f;
|
||||
}
|
||||
|
||||
float offsetY = 0.0f;
|
||||
if (v51 < a11) {
|
||||
if (this->m_vertJust == GxVJ_Bottom) {
|
||||
offsetY = a11 - v51;
|
||||
} else if (this->m_vertJust == GxVJ_Middle) {
|
||||
offsetY = floor((a11 - v51) * 0.5);
|
||||
}
|
||||
}
|
||||
linePos.y -= offsetY;
|
||||
|
||||
// TODO
|
||||
// info.dword0C -= v62;
|
||||
// info.dword04 -= v62;
|
||||
// info.dword34 = linePos.y;
|
||||
// info.dword2C = linePos.y + v59;
|
||||
// if (info.dword00) {
|
||||
// info.dword08 = linePos.x;
|
||||
// }
|
||||
|
||||
uint32_t texturePagesUsedFlag = 0;
|
||||
|
||||
this->InitializeTextLine(currentText, numBytes, lineColor, linePos, &texturePagesUsedFlag, info);
|
||||
this->m_intB0++;
|
||||
|
||||
this->m_texturePagesUsed |= texturePagesUsedFlag;
|
||||
|
||||
currentText = nextText;
|
||||
|
||||
linePos.y -= offsetY + v59;
|
||||
|
||||
if (this->m_flags & 0x2) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// info.dword0C -= offsetY + v59;
|
||||
// info.dword04 -= offsetY + v59;
|
||||
// info.dword34 = linePos.y;
|
||||
};
|
||||
|
||||
this->InitializeViewTranslation();
|
||||
|
||||
if (this->m_flags & 0x20 && (gStart != -1 || gLength != -1)) {
|
||||
this->SetGradient(gStart, gLength);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t CGxString::Initialize(float fontHeight, const C3Vector& position, float blockWidth, float blockHeight, CGxFont* face, const char* text, EGxFontVJusts vertJust, EGxFontHJusts horzJust, float spacing, uint32_t flags, const CImVector& color, float scale) {
|
||||
uint32_t textLen = SStrLen(text) + 1;
|
||||
if (textLen > this->m_textLen) {
|
||||
if (this->m_text) {
|
||||
SMemFree(this->m_text, __FILE__, __LINE__, 0x0);
|
||||
}
|
||||
|
||||
this->m_textLen = textLen;
|
||||
this->m_text = static_cast<char*>(SMemAlloc(textLen, __FILE__, __LINE__, 0x0));
|
||||
}
|
||||
|
||||
SStrCopy(this->m_text, text, this->m_textLen);
|
||||
|
||||
this->m_blockWidth = blockWidth;
|
||||
this->m_blockHeight = blockHeight;
|
||||
this->m_spacing = spacing;
|
||||
this->m_position = position;
|
||||
this->m_horzJust = horzJust;
|
||||
this->m_vertJust = vertJust;
|
||||
this->m_flags = flags;
|
||||
this->m_fontColor = color;
|
||||
this->m_scale = scale;
|
||||
this->m_currentFace = face;
|
||||
|
||||
face->m_strings.LinkToTail(this);
|
||||
|
||||
float requestedFontHeight = this->m_flags & 0x4 && !(this->m_flags & 0x80)
|
||||
? GxuFontGetOneToOneHeight(face)
|
||||
: fontHeight;
|
||||
this->m_requestedFontHeight = requestedFontHeight;
|
||||
|
||||
this->m_currentFontHeight = std::max(this->m_requestedFontHeight, 2.0f / GetScreenPixelHeight());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CGxString::InitializeTextLine(const char* currentText, uint32_t numBytes, CImVector& workingColor, const C3Vector& position, uint32_t* texturePagesUsedFlag, EMBEDDEDPARSEINFO& info) {
|
||||
if (this->m_flags & 0x08) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
C3Vector curPos = position;
|
||||
|
||||
float screenPixelHeight = ScreenToPixelHeight(this->m_flags & 0x80, this->m_currentFontHeight);
|
||||
float glyphToScreenPixels = screenPixelHeight / this->m_currentFace->GetPixelSize();
|
||||
float glyphPixelHeight = ScreenToPixelHeight(this->m_flags & 0x80, this->m_currentFontHeight);
|
||||
|
||||
if (this->m_currentFace->m_flags & 0x08) {
|
||||
glyphPixelHeight += 4.0f;
|
||||
} else if (this->m_currentFace->m_flags & 0x01) {
|
||||
glyphPixelHeight += 2.0f;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// - billboard adjustment table init
|
||||
// - EMBEDDEDPARSEINFO update
|
||||
|
||||
float stepGlyph = 0.0f;
|
||||
float stepScreen = 0.0f;
|
||||
uint32_t prevCode = 0;
|
||||
CImVector color;
|
||||
|
||||
while (numBytes && *currentText) {
|
||||
int32_t advance;
|
||||
uint32_t code;
|
||||
CImVector quotedColor;
|
||||
|
||||
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(currentText, advance, "edColor, this->m_flags, code);
|
||||
|
||||
currentText += advance;
|
||||
numBytes -= advance;
|
||||
|
||||
if (prevCode) {
|
||||
if (this->m_flags & 0x10) {
|
||||
// TODO
|
||||
// stepGlyph = this->m_currentFace->ComputeStepFixedWidth(prevCode, code);
|
||||
} else {
|
||||
stepGlyph = this->m_currentFace->ComputeStep(prevCode, code);
|
||||
}
|
||||
}
|
||||
|
||||
stepScreen = stepGlyph * glyphToScreenPixels;
|
||||
|
||||
switch (quotedCode) {
|
||||
case CODE_COLORON:
|
||||
if (!(this->m_flags & 0x08)) {
|
||||
color = quotedColor;
|
||||
color.a = this->m_fontColor.a;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// EMBEDDEDPARSEINFO update
|
||||
|
||||
continue;
|
||||
|
||||
case CODE_COLORRESTORE:
|
||||
color = this->m_fontColor;
|
||||
|
||||
continue;
|
||||
|
||||
case CODE_NEWLINE:
|
||||
continue;
|
||||
|
||||
case CODE_HYPERLINKSTART:
|
||||
// TODO
|
||||
|
||||
continue;
|
||||
|
||||
case CODE_HYPERLINKSTOP:
|
||||
// TODO
|
||||
|
||||
continue;
|
||||
|
||||
case CODE_TEXTURESTART:
|
||||
// TODO
|
||||
|
||||
continue;
|
||||
|
||||
case CODE_TEXTURESTOP:
|
||||
continue;
|
||||
|
||||
default: {
|
||||
auto glyph = this->m_currentFace->NewCodeDesc(code);
|
||||
|
||||
if (!glyph) {
|
||||
glyph = this->m_currentFace->NewCodeDesc('?');
|
||||
}
|
||||
|
||||
if (!glyph) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*texturePagesUsedFlag |= 1 << glyph->textureNumber;
|
||||
|
||||
if (!this->m_textLines[glyph->textureNumber]) {
|
||||
this->m_textLines[glyph->textureNumber] = TEXTLINETEXTURE::NewTextLineTexture();
|
||||
}
|
||||
|
||||
auto line = this->m_textLines[glyph->textureNumber];
|
||||
|
||||
if (!(this->m_flags & 0x08)) {
|
||||
uint32_t index = line->m_colors.Add(4, 0, &color);
|
||||
|
||||
if (this->m_flags & 0x20) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
if (!(this->m_flags & 0x80)) {
|
||||
stepScreen = floor(stepScreen + 0.5f);
|
||||
}
|
||||
|
||||
curPos.x += stepScreen;
|
||||
|
||||
VERT vert;
|
||||
vert.vc = { curPos.x, curPos.y, curPos.z };
|
||||
vert.tc = { 0.0f, 0.0f };
|
||||
|
||||
vert.vc.x += this->m_currentFace->GetGlyphBearing(
|
||||
glyph,
|
||||
this->m_flags & 0x80,
|
||||
this->m_currentFontHeight
|
||||
);
|
||||
|
||||
if (this->m_currentFace->m_flags & 0x08) {
|
||||
vert.vc.y -= 2.0f;
|
||||
} else if (this->m_currentFace->m_flags & 0x01) {
|
||||
vert.vc.y -= 1.0f;
|
||||
}
|
||||
|
||||
vert.vc.y += (glyph->bitmapData.m_yOffset * glyphToScreenPixels);
|
||||
|
||||
uint32_t index = line->m_vert.Add(4, 0, &vert);
|
||||
VERT* verts = &line->m_vert[index];
|
||||
|
||||
float width = this->m_flags & 0x80
|
||||
? glyph->bitmapData.m_glyphCellWidth * glyphToScreenPixels
|
||||
: floor(glyph->bitmapData.m_glyphCellWidth * glyphToScreenPixels);
|
||||
float height = this->m_flags & 0x80
|
||||
? screenPixelHeight
|
||||
: glyphPixelHeight;
|
||||
|
||||
verts[0].vc.x = verts[1].vc.x;
|
||||
verts[3].vc.x = verts[3].vc.x + width;
|
||||
verts[2].vc.x = verts[3].vc.x;
|
||||
verts[3].vc.y = verts[3].vc.y + height;
|
||||
verts[1].vc.y = verts[3].vc.y;
|
||||
verts[0].vc.y = verts[2].vc.y;
|
||||
|
||||
verts[2].tc.y = glyph->bitmapData.m_textureCoords.maxY;
|
||||
verts[0].tc.y = verts[2].tc.y;
|
||||
verts[3].tc.y = glyph->bitmapData.m_textureCoords.minY;
|
||||
verts[1].tc.y = verts[3].tc.y;
|
||||
verts[1].tc.x = glyph->bitmapData.m_textureCoords.minX;
|
||||
verts[0].tc.x = verts[1].tc.x;
|
||||
verts[3].tc.x = glyph->bitmapData.m_textureCoords.maxX;
|
||||
verts[2].tc.x = verts[3].tc.x;
|
||||
|
||||
if (this->m_flags & 0x80) {
|
||||
// TODO
|
||||
// verts[3].tc.y += flt_C7D2E8;
|
||||
// verts[1].tc.y += flt_C7D2E8;
|
||||
// verts[1].tc.x += flt_C7D2EC;
|
||||
// verts[0].tc.x += flt_C7D2EC;
|
||||
// verts[2].tc.y += flt_C7D2F0;
|
||||
// verts[0].tc.y += flt_C7D2F0;
|
||||
// verts[3].tc.x += flt_C7D2F4;
|
||||
// verts[2].tc.x += flt_C7D2F4;
|
||||
}
|
||||
|
||||
prevCode = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// info.dword10 = curPos.x + stepScreen;
|
||||
}
|
||||
|
||||
void CGxString::InitializeViewTranslation() {
|
||||
this->m_viewTranslation = this->m_position;
|
||||
|
||||
if (!this->m_intB0 || this->m_flags & 0x80) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m_horzJust == GxHJ_Right) {
|
||||
this->m_viewTranslation.x += this->m_blockWidth;
|
||||
} else if (this->m_horzJust == GxHJ_Center) {
|
||||
this->m_viewTranslation.x += (this->m_blockWidth * 0.5f);
|
||||
}
|
||||
|
||||
float v13 = ((this->m_spacing * (float)GetScreenPixelHeight()) + 0.9999499917030334f) / (float)GetScreenPixelHeight();
|
||||
float v24 = v13 * (float)(this->m_intB0 - 1) + (float)this->m_intB0 * this->m_currentFontHeight;
|
||||
|
||||
if (this->m_intD4 >= 4) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// TODO
|
||||
// - current font height logic
|
||||
|
||||
if (this->m_vertJust == GxVJ_Bottom) {
|
||||
this->m_viewTranslation.y += v24;
|
||||
} else if (this->m_vertJust == GxVJ_Middle) {
|
||||
this->m_viewTranslation.y += 0.5f * (this->m_blockHeight - v24) + v24;
|
||||
} else {
|
||||
this->m_viewTranslation.y += this->m_blockHeight;
|
||||
}
|
||||
|
||||
this->m_viewTranslation.x = floor((float)GetScreenPixelWidth() * this->m_viewTranslation.x);
|
||||
this->m_viewTranslation.y = floor((float)GetScreenPixelHeight() * this->m_viewTranslation.y);
|
||||
}
|
||||
|
||||
void CGxString::Recycle() {
|
||||
this->m_batchedStringLink.Unlink();
|
||||
g_freeStrings.LinkToTail(this);
|
||||
this->ClearInstanceData();
|
||||
}
|
||||
|
||||
void CGxString::SetColor(const CImVector& color) {
|
||||
if (this->m_fontColor == color) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->m_fontColor = color;
|
||||
this->m_shadowColor.a = std::min(color.a, this->m_shadowColor.a);
|
||||
|
||||
if (!(this->m_flags & 0x8) || this->m_flags & 0x20 || this->m_intD4) {
|
||||
this->ClearInstanceData();
|
||||
}
|
||||
}
|
||||
|
||||
int32_t CGxString::SetGradient(int32_t startCharacter, int32_t length) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void CGxString::SetStringPosition(const C3Vector& position) {
|
||||
this->m_position = position;
|
||||
this->InitializeViewTranslation();
|
||||
}
|
||||
|
||||
void CGxString::Tick() {
|
||||
if (this->m_intB0) {
|
||||
this->m_intD4++;
|
||||
|
||||
if (this->m_intD4 - 1 > 30) {
|
||||
this->ClearInstanceData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGxString::WriteGeometry(CGxVertexPCT* buf, int32_t line, int32_t ofs, int32_t size) {
|
||||
auto textLine = this->m_textLines[line];
|
||||
|
||||
if (textLine) {
|
||||
textLine->WriteGeometry(
|
||||
buf,
|
||||
this->m_fontColor,
|
||||
this->m_shadowOffset,
|
||||
this->m_shadowColor,
|
||||
this->m_viewTranslation,
|
||||
this->m_flags & 0x01,
|
||||
this->m_flags & 0x20,
|
||||
ofs,
|
||||
size
|
||||
);
|
||||
}
|
||||
}
|
||||
84
src/gx/font/CGxString.hpp
Normal file
84
src/gx/font/CGxString.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#ifndef GX_C_GX_STRING_HPP
|
||||
#define GX_C_GX_STRING_HPP
|
||||
|
||||
#include "gx/Types.hpp"
|
||||
#include <cstdint>
|
||||
#include <storm/Array.hpp>
|
||||
#include <storm/List.hpp>
|
||||
#include <tempest/Vector.hpp>
|
||||
|
||||
struct EMBEDDEDPARSEINFO;
|
||||
class CGxFont;
|
||||
class CGxVertexPCT;
|
||||
|
||||
struct VERT {
|
||||
C3Vector vc;
|
||||
C2Vector tc;
|
||||
};
|
||||
|
||||
class TEXTLINETEXTURE {
|
||||
public:
|
||||
// Static functions
|
||||
static TEXTLINETEXTURE* NewTextLineTexture(void);
|
||||
static void Recycle(TEXTLINETEXTURE* ptr);
|
||||
|
||||
// Member variables
|
||||
TSGrowableArray<VERT> m_vert;
|
||||
TSGrowableArray<CImVector> m_colors;
|
||||
|
||||
// Member functions
|
||||
void WriteGeometry(CGxVertexPCT*, const CImVector&, const C2Vector&, const CImVector&, const C3Vector&, bool, bool, int32_t, int32_t);
|
||||
};
|
||||
|
||||
class CGxString : public TSLinkedNode<CGxString> {
|
||||
public:
|
||||
// Static functions
|
||||
static CGxString* GetNewString(int32_t linkOnList);
|
||||
|
||||
// Member variables
|
||||
TSLink<CGxString> m_fontStringLink;
|
||||
TSLink<CGxString> m_batchedStringLink;
|
||||
float m_requestedFontHeight = 0.02f;
|
||||
float m_currentFontHeight = 0.02f;
|
||||
C3Vector m_position;
|
||||
CImVector m_fontColor = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
CImVector m_shadowColor = { 0x00, 0x00, 0x00, 0xFF };
|
||||
C2Vector m_shadowOffset = { 0.00125f, -0.00125f };
|
||||
float m_blockWidth = 1.0f;
|
||||
float m_blockHeight = 1.0f;
|
||||
CGxFont* m_currentFace = nullptr;
|
||||
char* m_text = nullptr;
|
||||
int32_t m_textLen = 0;
|
||||
EGxFontVJusts m_vertJust = GxVJ_Top;
|
||||
EGxFontHJusts m_horzJust = GxHJ_Left;
|
||||
float m_spacing = 0.0f;
|
||||
uint32_t m_flags = 0;
|
||||
uint32_t m_texturePagesUsed = 0;
|
||||
int32_t m_textureEvicted = 0;
|
||||
int32_t m_lastGradientStart = -1;
|
||||
int32_t m_lastGradientLength = -1;
|
||||
C3Vector m_viewTranslation;
|
||||
float m_scale = 1.0f;
|
||||
int32_t m_intB0 = 0;
|
||||
TEXTLINETEXTURE* m_textLines[8] = {};
|
||||
int32_t m_intD4 = 0;
|
||||
|
||||
// Member functions
|
||||
~CGxString();
|
||||
void AddShadow(const C2Vector& offset, const CImVector& color);
|
||||
uint32_t CalculateVertsNeeded(int32_t);
|
||||
bool CheckGeometry(void);
|
||||
void ClearInstanceData(void);
|
||||
void CreateGeometry(void);
|
||||
int32_t Initialize(float, const C3Vector&, float, float, CGxFont*, const char*, EGxFontVJusts, EGxFontHJusts, float, uint32_t, const CImVector&, float);
|
||||
void InitializeTextLine(const char*, uint32_t, CImVector&, const C3Vector&, uint32_t*, EMBEDDEDPARSEINFO&);
|
||||
void InitializeViewTranslation(void);
|
||||
void Recycle();
|
||||
void SetColor(const CImVector&);
|
||||
int32_t SetGradient(int32_t, int32_t);
|
||||
void SetStringPosition(const C3Vector& position);
|
||||
void Tick();
|
||||
void WriteGeometry(CGxVertexPCT*, int32_t, int32_t, int32_t);
|
||||
};
|
||||
|
||||
#endif
|
||||
289
src/gx/font/CGxStringBatch.cpp
Normal file
289
src/gx/font/CGxStringBatch.cpp
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
#include "gx/font/CGxStringBatch.hpp"
|
||||
#include "gx/font/CGxFont.hpp"
|
||||
#include "gx/Buffer.hpp"
|
||||
#include "gx/CGxBatch.hpp"
|
||||
#include "gx/Device.hpp"
|
||||
#include "gx/Draw.hpp"
|
||||
#include "gx/Font.hpp"
|
||||
#include "gx/Gx.hpp"
|
||||
#include "gx/RenderState.hpp"
|
||||
#include "gx/Shader.hpp"
|
||||
#include "gx/Texture.hpp"
|
||||
#include "gx/Transform.hpp"
|
||||
#include <cmath>
|
||||
#include <storm/Error.hpp>
|
||||
|
||||
bool BATCHEDRENDERFONTDESC::s_billboarded;
|
||||
CGxBuf* BATCHEDRENDERFONTDESC::s_indexBuf;
|
||||
CGxPool* BATCHEDRENDERFONTDESC::s_indexPool;
|
||||
|
||||
int32_t SetProjection() {
|
||||
float minX, maxX, minY, maxY, minZ, maxZ;
|
||||
GxXformViewport(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
|
||||
float v14 = 0.0f;
|
||||
float v15 = 0.0f;
|
||||
|
||||
if (!GxCaps()->m_pixelCenterOnEdge) {
|
||||
v14 = -0.5f;
|
||||
v15 = 0.5f;
|
||||
}
|
||||
|
||||
C44Matrix proj;
|
||||
|
||||
uint32_t pixelWidth = GetScreenPixelWidth();
|
||||
float pixelMinX = floor(minX * pixelWidth);
|
||||
float pixelMaxX = floor(maxX * pixelWidth);
|
||||
|
||||
if (pixelMinX >= pixelMaxX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t pixelHeight = GetScreenPixelHeight();
|
||||
float pixelMinY = floor(minY * pixelHeight);
|
||||
float pixelMaxY = floor(maxY * pixelHeight);
|
||||
|
||||
if (pixelMinY >= pixelMaxY) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pixelHeight > pixelMaxY) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
pixelMinX += v14;
|
||||
pixelMaxX += v14;
|
||||
pixelMinY += v15;
|
||||
pixelMaxY += v15;
|
||||
|
||||
GxuXformCreateOrthoDepth(pixelMinX, pixelMaxX, pixelMinY, pixelMaxY, -5000.0f, 5000.0f, proj);
|
||||
GxXformSetProjection(proj);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BATCHEDRENDERFONTDESC::Initialize() {
|
||||
CGxPool* indexPool = GxPoolCreate(
|
||||
GxPoolTarget_Index,
|
||||
GxPoolUsage_Static,
|
||||
6144,
|
||||
GxPoolHintBit_Unk0,
|
||||
"BATCHEDRENDERFONTDESC_idx"
|
||||
);
|
||||
|
||||
CGxBuf* indexBuf = GxBufCreate(
|
||||
indexPool,
|
||||
2,
|
||||
3072,
|
||||
0
|
||||
);
|
||||
|
||||
BATCHEDRENDERFONTDESC::s_indexPool = indexPool;
|
||||
BATCHEDRENDERFONTDESC::s_indexBuf = indexBuf;
|
||||
}
|
||||
|
||||
void BATCHEDRENDERFONTDESC::InitializeIndexBuff() {
|
||||
char* indexData = g_theGxDevicePtr->BufLock(BATCHEDRENDERFONTDESC::s_indexBuf);
|
||||
uint16_t* indexBuf = reinterpret_cast<uint16_t*>(indexData);
|
||||
|
||||
uint16_t index = 0;
|
||||
|
||||
for (int32_t i = 0; i < 512; i++) {
|
||||
indexBuf[i * 6 + 0] = index + 0;
|
||||
indexBuf[i * 6 + 1] = index + 2;
|
||||
indexBuf[i * 6 + 2] = index + 1;
|
||||
indexBuf[i * 6 + 3] = index + 2;
|
||||
indexBuf[i * 6 + 4] = index + 3;
|
||||
indexBuf[i * 6 + 5] = index + 1;
|
||||
|
||||
index += 4;
|
||||
}
|
||||
|
||||
GxBufUnlock(BATCHEDRENDERFONTDESC::s_indexBuf, 0);
|
||||
};
|
||||
|
||||
CGxVertexPCT* BATCHEDRENDERFONTDESC::UnlockVertexPtrAndRender(CGxBuf*& buf, int32_t count) {
|
||||
GxBufUnlock(buf, sizeof(CGxVertexPCT) * count);
|
||||
|
||||
if (!BATCHEDRENDERFONTDESC::s_indexBuf->unk1C || !BATCHEDRENDERFONTDESC::s_indexBuf->unk1D) {
|
||||
BATCHEDRENDERFONTDESC::InitializeIndexBuff();
|
||||
}
|
||||
|
||||
if (BATCHEDRENDERFONTDESC::s_indexBuf->unk1C && BATCHEDRENDERFONTDESC::s_indexBuf->unk1D) {
|
||||
GxPrimVertexPtr(buf, GxVBF_PCT);
|
||||
GxPrimIndexPtr(BATCHEDRENDERFONTDESC::s_indexBuf);
|
||||
|
||||
CGxBatch batch;
|
||||
batch.m_primType = GxPrim_Triangles;
|
||||
batch.m_start = 0;
|
||||
batch.m_count = 6 * (count / 4);
|
||||
batch.m_minIndex = 0;
|
||||
batch.m_maxIndex = count - 1;
|
||||
|
||||
GxDraw(&batch, 1);
|
||||
}
|
||||
|
||||
return reinterpret_cast<CGxVertexPCT*>(g_theGxDevicePtr->BufLock(buf));
|
||||
}
|
||||
|
||||
void BATCHEDRENDERFONTDESC::RenderBatch() {
|
||||
if (!BATCHEDRENDERFONTDESC::s_indexPool) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto string = this->m_strings.Head(); string; string = this->m_strings.Next(string)) {
|
||||
string->CheckGeometry();
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 8; i++) {
|
||||
this->m_face->m_textureCache[i].UpdateDirty();
|
||||
}
|
||||
|
||||
int32_t maxBatchCapacity = 2048;
|
||||
|
||||
CGxBuf* vertexStream = g_theGxDevicePtr->BufStream(GxPoolTarget_Vertex, 0x18, maxBatchCapacity);
|
||||
char* vertexData = g_theGxDevicePtr->BufLock(vertexStream);
|
||||
CGxVertexPCT* vertexBuf = reinterpret_cast<CGxVertexPCT*>(vertexData);
|
||||
|
||||
for (int32_t i = 0; i < 8; i++) {
|
||||
auto& textureCache = this->m_face->m_textureCache[i];
|
||||
auto texture = textureCache.m_texture;
|
||||
|
||||
if (texture) {
|
||||
auto gxTex = TextureGetGxTex(reinterpret_cast<CTexture*>(texture), 1, nullptr);
|
||||
|
||||
if (gxTex) {
|
||||
GxRsSet(GxRs_Texture0, gxTex);
|
||||
|
||||
for (auto string = this->m_strings.Head(); string; string = this->m_strings.Next(string)) {
|
||||
auto line = string->m_textLines[i];
|
||||
|
||||
if (line) {
|
||||
int32_t vertsNeeded = string->CalculateVertsNeeded(i);
|
||||
int32_t batchOffset = 0;
|
||||
int32_t batchCapacity = maxBatchCapacity;
|
||||
|
||||
while (vertsNeeded) {
|
||||
int32_t batchCount = std::min(vertsNeeded, batchCapacity);
|
||||
|
||||
string->WriteGeometry(vertexBuf, i, batchOffset, batchCount);
|
||||
|
||||
vertsNeeded -= batchCount;
|
||||
batchOffset += batchCount;
|
||||
batchCapacity -= batchCount;
|
||||
vertexBuf += batchCount;
|
||||
|
||||
if (!batchCapacity) {
|
||||
vertexBuf = this->UnlockVertexPtrAndRender(vertexStream, maxBatchCapacity);
|
||||
batchCapacity = maxBatchCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
if (batchCapacity != maxBatchCapacity) {
|
||||
vertexBuf = this->UnlockVertexPtrAndRender(vertexStream, maxBatchCapacity - batchCapacity);
|
||||
batchCapacity = maxBatchCapacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_theGxDevicePtr->BufUnlock(vertexStream, 0);
|
||||
}
|
||||
|
||||
CGxStringBatch::~CGxStringBatch() {
|
||||
this->m_fontBatch.Clear();
|
||||
}
|
||||
|
||||
void CGxStringBatch::AddString(CGxString* string) {
|
||||
STORM_ASSERT(string);
|
||||
STORM_ASSERT(string->m_currentFace);
|
||||
|
||||
auto face = string->m_currentFace;
|
||||
uint32_t hashval = reinterpret_cast<uintptr_t>(face);
|
||||
HASHKEY_PTR key = { face };
|
||||
|
||||
auto batch = this->m_fontBatch.Ptr(hashval, key);
|
||||
|
||||
if (!batch) {
|
||||
batch = this->m_fontBatch.New(hashval, key, 0, 0);
|
||||
batch->m_face = face;
|
||||
}
|
||||
|
||||
batch->m_strings.LinkToTail(string);
|
||||
}
|
||||
|
||||
void CGxStringBatch::RenderBatch() {
|
||||
// TODO
|
||||
// if (!g_perf) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
C44Matrix oldProjection;
|
||||
C44Matrix oldView;
|
||||
|
||||
GxXformProjection(oldProjection);
|
||||
GxXformView(oldView);
|
||||
|
||||
GxRsPush();
|
||||
|
||||
GxRsSet(GxRs_Fog, 0);
|
||||
GxRsSet(GxRs_Culling, 0);
|
||||
GxRsSet(GxRs_BlendingMode, GxBlend_Alpha);
|
||||
GxRsSetAlphaRef();
|
||||
|
||||
int32_t setProjection;
|
||||
int32_t stereoEnabled;
|
||||
|
||||
if (this->m_flags & 0x1) {
|
||||
BATCHEDRENDERFONTDESC::s_billboarded = true;
|
||||
|
||||
GxRsSet(GxRs_DepthTest, 1);
|
||||
GxRsSet(GxRs_DepthWrite, 1);
|
||||
GxRsSet(GxRs_AlphaRef, 1);
|
||||
|
||||
setProjection = 1;
|
||||
stereoEnabled = 0;
|
||||
} else {
|
||||
C44Matrix view;
|
||||
GxXformSetView(view);
|
||||
|
||||
GxRsSet(GxRs_DepthTest, 0);
|
||||
GxRsSet(GxRs_DepthWrite, 0);
|
||||
|
||||
setProjection = SetProjection();
|
||||
stereoEnabled = g_theGxDevicePtr->StereoEnabled();
|
||||
}
|
||||
|
||||
CGxShader* vs = g_fontVertexShader[stereoEnabled ? 1 : 0];
|
||||
CGxShader* ps = g_fontPixelShader[0];
|
||||
|
||||
if (setProjection && vs->Valid() && ps->Valid()) {
|
||||
GxRsSet(GxRs_VertexShader, vs);
|
||||
GxRsSet(GxRs_PixelShader, ps);
|
||||
|
||||
C44Matrix viewProjMat;
|
||||
GxXformViewProjNativeTranspose(viewProjMat);
|
||||
GxShaderConstantsSet(GxSh_Vertex, 0, reinterpret_cast<float*>(&viewProjMat), 4);
|
||||
|
||||
for (auto fontBatch = this->m_fontBatch.Head(); fontBatch; fontBatch = this->m_fontBatch.Next(fontBatch)) {
|
||||
if (fontBatch->m_strings.Head()) {
|
||||
fontBatch->RenderBatch();
|
||||
|
||||
if (this->m_flags & 0x2) {
|
||||
// TODO
|
||||
}
|
||||
} else {
|
||||
this->m_fontBatch.Unlink(fontBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BATCHEDRENDERFONTDESC::s_billboarded = false;
|
||||
|
||||
GxRsPop();
|
||||
|
||||
GxXformSetView(oldView);
|
||||
GxXformSetProjection(oldProjection);
|
||||
}
|
||||
45
src/gx/font/CGxStringBatch.hpp
Normal file
45
src/gx/font/CGxStringBatch.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef GX_C_GX_STRING_BATCH_HPP
|
||||
#define GX_C_GX_STRING_BATCH_HPP
|
||||
|
||||
#include "gx/font/CGxString.hpp"
|
||||
#include <cstdint>
|
||||
#include <storm/Hash.hpp>
|
||||
#include <storm/List.hpp>
|
||||
|
||||
class CGxBuf;
|
||||
class CGxFont;
|
||||
class CGxPool;
|
||||
|
||||
class BATCHEDRENDERFONTDESC : public TSHashObject<BATCHEDRENDERFONTDESC, HASHKEY_PTR> {
|
||||
public:
|
||||
// Static variables
|
||||
static bool s_billboarded;
|
||||
static CGxBuf* s_indexBuf;
|
||||
static CGxPool* s_indexPool;
|
||||
|
||||
// Static functions
|
||||
static void Initialize(void);
|
||||
static void InitializeIndexBuff(void);
|
||||
CGxVertexPCT* UnlockVertexPtrAndRender(CGxBuf*&, int32_t);
|
||||
|
||||
// Member variables
|
||||
CGxFont* m_face = nullptr;
|
||||
STORM_EXPLICIT_LIST(CGxString, m_batchedStringLink) m_strings;
|
||||
|
||||
// Member functions
|
||||
void RenderBatch(void);
|
||||
};
|
||||
|
||||
class CGxStringBatch : public TSLinkedNode<CGxStringBatch> {
|
||||
public:
|
||||
// Member variables
|
||||
TSHashTable<BATCHEDRENDERFONTDESC, HASHKEY_PTR> m_fontBatch;
|
||||
uint32_t m_flags = 0x0;
|
||||
|
||||
// Member functions
|
||||
~CGxStringBatch();
|
||||
void AddString(CGxString*);
|
||||
void RenderBatch(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
12
src/gx/font/FaceData.cpp
Normal file
12
src/gx/font/FaceData.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include "gx/font/FaceData.hpp"
|
||||
#include "util/SFile.hpp"
|
||||
|
||||
FACEDATA::~FACEDATA() {
|
||||
if (this->face) {
|
||||
FT_Done_Face(this->face);
|
||||
}
|
||||
|
||||
if (this->data) {
|
||||
SFile::Unload(this->data);
|
||||
}
|
||||
}
|
||||
17
src/gx/font/FaceData.hpp
Normal file
17
src/gx/font/FaceData.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef GX_FONT_FACE_DATA_HPP
|
||||
#define GX_FONT_FACE_DATA_HPP
|
||||
|
||||
#include "gx/font/FreeType.hpp"
|
||||
#include "gx/font/Types.hpp"
|
||||
#include <common/Handle.hpp>
|
||||
#include <storm/Hash.hpp>
|
||||
|
||||
class FACEDATA : public CHandleObject, public TSHashObject<FACEDATA, HASHKEY_STRI> {
|
||||
public:
|
||||
void* data = nullptr;
|
||||
FT_Face face = nullptr;
|
||||
HFACE selfReference;
|
||||
virtual ~FACEDATA();
|
||||
};
|
||||
|
||||
#endif
|
||||
80
src/gx/font/FontFace.cpp
Normal file
80
src/gx/font/FontFace.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include "gx/font/FontFace.hpp"
|
||||
#include "gx/font/FaceData.hpp"
|
||||
#include "util/SFile.hpp"
|
||||
#include <storm/Error.hpp>
|
||||
#include <storm/Hash.hpp>
|
||||
|
||||
TSHashTable<FACEDATA, HASHKEY_STRI> s_faceHash;
|
||||
|
||||
void FontFaceCloseHandle(HFACE handle) {
|
||||
STORM_ASSERT(handle);
|
||||
|
||||
HandleClose(handle);
|
||||
|
||||
FACEDATA* dataPtr = reinterpret_cast<FACEDATA*>(handle);
|
||||
|
||||
if (dataPtr->m_refcount <= 1) {
|
||||
HandleClose(dataPtr->selfReference);
|
||||
dataPtr->selfReference = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FT_Face FontFaceGetFace(HFACE handle) {
|
||||
STORM_ASSERT(handle);
|
||||
|
||||
return reinterpret_cast<FACEDATA*>(handle)->face;
|
||||
}
|
||||
|
||||
const char* FontFaceGetFontName(HFACE handle) {
|
||||
STORM_ASSERT(handle);
|
||||
|
||||
return reinterpret_cast<FACEDATA*>(handle)->m_key.m_str;
|
||||
}
|
||||
|
||||
HFACE FontFaceGetHandle(const char* fileName, FT_Library library) {
|
||||
if (!library || !fileName || !*fileName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto existing = s_faceHash.Ptr(fileName)) {
|
||||
return HandleDuplicate(existing->selfReference);
|
||||
}
|
||||
|
||||
void* data = nullptr;
|
||||
size_t size;
|
||||
|
||||
if (!SFile::Load(nullptr, fileName, &data, &size, 0, 0x3, nullptr) || !data) {
|
||||
if (data) {
|
||||
SFile::Unload(data);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FT_Face theFace;
|
||||
|
||||
if (FT_New_Memory_Face(library, (FT_Byte*)data, size, 0, &theFace) != FT_Err_Ok || !theFace) {
|
||||
if (data) {
|
||||
SFile::Unload(data);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (FT_Select_Charmap(theFace, ft_encoding_unicode) != FT_Err_Ok) {
|
||||
if (data) {
|
||||
SFile::Unload(data);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto faceData = s_faceHash.New(fileName, 0, 0);
|
||||
auto handle = HandleCreate(faceData);
|
||||
|
||||
faceData->data = data;
|
||||
faceData->face = theFace;
|
||||
faceData->selfReference = handle;
|
||||
|
||||
return HandleDuplicate(handle);
|
||||
}
|
||||
15
src/gx/font/FontFace.hpp
Normal file
15
src/gx/font/FontFace.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef GX_FONT_FONT_FACE_HPP
|
||||
#define GX_FONT_FONT_FACE_HPP
|
||||
|
||||
#include "gx/font/FreeType.hpp"
|
||||
#include "gx/font/Types.hpp"
|
||||
|
||||
void FontFaceCloseHandle(HFACE);
|
||||
|
||||
FT_Face FontFaceGetFace(HFACE);
|
||||
|
||||
const char* FontFaceGetFontName(HFACE);
|
||||
|
||||
HFACE FontFaceGetHandle(const char*, FT_Library);
|
||||
|
||||
#endif
|
||||
44
src/gx/font/FreeType.cpp
Normal file
44
src/gx/font/FreeType.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include "gx/font/FreeType.hpp"
|
||||
#include "gx/font/FreeTypeInternal.hpp"
|
||||
#include "freetype/ftmodule.h"
|
||||
#include <storm/Memory.hpp>
|
||||
|
||||
FT_Library g_FTLibrary;
|
||||
|
||||
FT_MemoryRec_ s_GxuMemoryRecord = {
|
||||
nullptr,
|
||||
&FreeTypeAllocFunction,
|
||||
&FreeTypeFreeFunction,
|
||||
&FreeTypeReallocFunction
|
||||
};
|
||||
|
||||
void FreeTypeInitialize() {
|
||||
FT_New_Library(&s_GxuMemoryRecord, &g_FTLibrary);
|
||||
FT_Add_Default_Modules(g_FTLibrary);
|
||||
}
|
||||
|
||||
int32_t FREETYPE_RenderGlyph(uint32_t code, bool monochrome, FT_Face face) {
|
||||
FT_UInt index = FT_Get_Char_Index(face, code);
|
||||
|
||||
if (!index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FT_Int flags = monochrome
|
||||
? FT_LOAD_NO_HINTING | FT_LOAD_CROP_BITMAP | FT_LOAD_PEDANTIC | FT_LOAD_LINEAR_DESIGN
|
||||
: FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC | FT_LOAD_LINEAR_DESIGN;
|
||||
|
||||
if (FT_Load_Glyph(face, index, flags)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FT_Render_Glyph(face->glyph, monochrome ? ft_render_mode_mono : ft_render_mode_normal)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
FT_Library GetFreeTypeLibrary() {
|
||||
return g_FTLibrary;
|
||||
};
|
||||
13
src/gx/font/FreeType.hpp
Normal file
13
src/gx/font/FreeType.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef GX_FONT_FREE_TYPE_HPP
|
||||
#define GX_FONT_FREE_TYPE_HPP
|
||||
|
||||
#include "freetype/freetype.h"
|
||||
#include <cstdint>
|
||||
|
||||
void FreeTypeInitialize();
|
||||
|
||||
int32_t FREETYPE_RenderGlyph(uint32_t, bool, FT_Face);
|
||||
|
||||
FT_Library GetFreeTypeLibrary();
|
||||
|
||||
#endif
|
||||
16
src/gx/font/FreeTypeInternal.cpp
Normal file
16
src/gx/font/FreeTypeInternal.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include "gx/font/FreeTypeInternal.hpp"
|
||||
#include <storm/Memory.hpp>
|
||||
|
||||
void* FreeTypeAllocFunction(FT_Memory memory, long size) {
|
||||
return SMemAlloc(size, __FILE__, __LINE__, 0);
|
||||
};
|
||||
|
||||
void FreeTypeFreeFunction(FT_Memory memory, void* block) {
|
||||
if (block) {
|
||||
SMemFree(block, __FILE__, __LINE__, 0);
|
||||
}
|
||||
};
|
||||
|
||||
void* FreeTypeReallocFunction(FT_Memory memory, long currentSize, long newSize, void* block) {
|
||||
return SMemReAlloc(block, newSize, __FILE__, __LINE__, 0);
|
||||
};
|
||||
12
src/gx/font/FreeTypeInternal.hpp
Normal file
12
src/gx/font/FreeTypeInternal.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef GX_FONT_FREE_TYPE_INTERNAL_HPP
|
||||
#define GX_FONT_FREE_TYPE_INTERNAL_HPP
|
||||
|
||||
#include "freetype/freetype.h"
|
||||
|
||||
void* FreeTypeAllocFunction(FT_Memory memory, long size);
|
||||
|
||||
void FreeTypeFreeFunction(FT_Memory memory, void* block);
|
||||
|
||||
void* FreeTypeReallocFunction(FT_Memory memory, long currentSize, long newSize, void* block);
|
||||
|
||||
#endif
|
||||
45
src/gx/font/Types.hpp
Normal file
45
src/gx/font/Types.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef GX_FONT_TYPES_HPP
|
||||
#define GX_FONT_TYPES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <common/Handle.hpp>
|
||||
|
||||
typedef HOBJECT HTEXTBLOCK;
|
||||
typedef HOBJECT HTEXTFONT;
|
||||
typedef HOBJECT HFACE;
|
||||
|
||||
enum QUOTEDCODE {
|
||||
CODE_INVALIDCODE = 0x0,
|
||||
CODE_COLORON = 0x1,
|
||||
CODE_COLORRESTORE = 0x2,
|
||||
CODE_NEWLINE = 0x3,
|
||||
CODE_PIPE = 0x4,
|
||||
CODE_HYPERLINKSTART = 0x5,
|
||||
CODE_HYPERLINKSTOP = 0x6,
|
||||
CODE_TEXTURESTART = 0x7,
|
||||
CODE_TEXTURESTOP = 0x8,
|
||||
NUM_QUOTEDCODES = 0x9
|
||||
};
|
||||
|
||||
struct EMBEDDEDPARSEINFO {
|
||||
// TODO
|
||||
};
|
||||
|
||||
struct GXUEMBEDDEDTEXTUREINFO {
|
||||
float float0 = 0.0f;
|
||||
float float4 = 0.0f;
|
||||
float float8 = 0.0f;
|
||||
float floatC = 0.0f;
|
||||
uint32_t dword10 = 0;
|
||||
uint32_t dword14 = 0;
|
||||
float float18 = 0.0f;
|
||||
float float1C = 0.0f;
|
||||
float float20 = 0.0f;
|
||||
float float24 = 0.0f;
|
||||
float float28 = 0.0f;
|
||||
float float2C = 0.0f;
|
||||
float float30 = 0.0f;
|
||||
float float34 = 0.0f;
|
||||
};
|
||||
|
||||
#endif
|
||||
476
src/gx/font/Wrap.cpp
Normal file
476
src/gx/font/Wrap.cpp
Normal file
|
|
@ -0,0 +1,476 @@
|
|||
#include "gx/font/Wrap.hpp"
|
||||
#include "gx/font/CGxFont.hpp"
|
||||
#include "gx/Font.hpp"
|
||||
#include <cmath>
|
||||
#include <cwctype>
|
||||
#include <storm/Unicode.hpp>
|
||||
|
||||
void CalcWrapPoint(CGxFont* face, const char* currentText, float fontHeight, float blockWidth, uint32_t* numBytes, float* extent, const char** nextText, float a8, uint32_t flags, bool* a10, float* a11, float scale) {
|
||||
if (fontHeight < 0.0f || blockWidth <= 0.0f || !currentText || !*currentText) {
|
||||
*numBytes = 0;
|
||||
*extent = 0.0f;
|
||||
*nextText = nullptr;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & 0x80) {
|
||||
CalcWrapPointBillboarded(
|
||||
currentText,
|
||||
flags,
|
||||
face,
|
||||
fontHeight,
|
||||
numBytes,
|
||||
extent,
|
||||
nextText,
|
||||
a11,
|
||||
scale
|
||||
);
|
||||
} else {
|
||||
CalcWrapPointNonBillboarded(
|
||||
currentText,
|
||||
face,
|
||||
fontHeight,
|
||||
blockWidth,
|
||||
numBytes,
|
||||
extent,
|
||||
nextText,
|
||||
a8,
|
||||
flags,
|
||||
a10,
|
||||
a11,
|
||||
scale
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void CalcWrapPointBillboarded(const char* currentText, uint32_t flags, CGxFont* face, float fontHeight, uint32_t* numBytes, float* extent, const char** nextText, float* a8, float scale) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void CalcWrapPointNonBillboarded(const char* currentText, CGxFont* face, float fontHeight, float blockWidth, uint32_t* numBytes, float* extent, const char** nextText, float a8, uint32_t flags, bool* a10, float* a11, float scale) {
|
||||
if (fontHeight == 0.0f || flags & 0x4) {
|
||||
fontHeight = GxuFontGetOneToOneHeight(face);
|
||||
}
|
||||
|
||||
float v46 = 0.0f;
|
||||
|
||||
if (a8 > 0.0f) {
|
||||
v46 += ceil(ScreenToPixelWidth(0, a8));
|
||||
}
|
||||
|
||||
if (face->m_flags & 0x8) {
|
||||
v46 += 4.0f;
|
||||
} else if (face->m_flags & 0x1) {
|
||||
v46 += 2.0f;
|
||||
}
|
||||
|
||||
float pixelFontHeight = ScreenToPixelHeight(0, fontHeight);
|
||||
float v41 = static_cast<float>(face->GetPixelSize()) / pixelFontHeight;
|
||||
float pixelBlockWidth = ceil(v41 * blockWidth * static_cast<float>(GetScreenPixelWidth()));
|
||||
|
||||
if (a11) {
|
||||
*a11 = 0.0f;
|
||||
}
|
||||
|
||||
uint32_t v18 = 0;
|
||||
uint32_t prevCode = 0;
|
||||
float v42 = 0.0f;
|
||||
float v56 = 0.0f;
|
||||
auto startText = currentText;
|
||||
int32_t advance = 0;
|
||||
QUOTEDCODE quotedCode = CODE_NEWLINE;
|
||||
|
||||
while (*currentText) {
|
||||
uint32_t code;
|
||||
quotedCode = GxuDetermineQuotedCode(currentText, advance, 0, flags, code);
|
||||
|
||||
if (quotedCode == CODE_NEWLINE) {
|
||||
currentText += advance;
|
||||
v18 = currentText - startText;
|
||||
v56 = v42 + v46;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
quotedCode == CODE_COLORON
|
||||
|| quotedCode == CODE_COLORRESTORE
|
||||
|| quotedCode == CODE_HYPERLINKSTART
|
||||
|| quotedCode == CODE_HYPERLINKSTOP
|
||||
|| quotedCode == CODE_TEXTURESTOP
|
||||
) {
|
||||
currentText += advance;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quotedCode == CODE_TEXTURESTART) {
|
||||
GXUEMBEDDEDTEXTUREINFO textureInfo;
|
||||
|
||||
// TODO
|
||||
// if (!ParseEmbeddedTexture(currentText, textureInfo, pixelFontHeight, scale, fontHeight)) {
|
||||
// currentText += advance;
|
||||
//
|
||||
// continue;
|
||||
// }
|
||||
|
||||
float v21 = textureInfo.float1C + v46;
|
||||
|
||||
if (pixelBlockWidth >= v21) {
|
||||
v46 = v21;
|
||||
|
||||
if (a11 && *a11 < textureInfo.float18) {
|
||||
*a11 = textureInfo.float18;
|
||||
}
|
||||
|
||||
currentText += advance;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
prevCode = code;
|
||||
advance = 0;
|
||||
}
|
||||
|
||||
if (face->NewCodeDesc(code)) {
|
||||
float step = 0.0f;
|
||||
|
||||
if (prevCode) {
|
||||
if (flags & 0x10) {
|
||||
step = face->ComputeStepFixedWidth(prevCode, code);
|
||||
} else {
|
||||
step = face->ComputeStep(prevCode, code);
|
||||
}
|
||||
}
|
||||
|
||||
if (CanWrapBetween(code, prevCode)) {
|
||||
if (*a10 || v18) {
|
||||
v18 = currentText - startText;
|
||||
}
|
||||
|
||||
*a10 = true;
|
||||
v56 = v42 + v46;
|
||||
}
|
||||
|
||||
float v38 = GetCharacterWidth(¤tText[advance], flags, code, face, fontHeight);
|
||||
float v24 = step + v46;
|
||||
if (pixelBlockWidth < v38 + v24) {
|
||||
break;
|
||||
}
|
||||
|
||||
prevCode = code;
|
||||
v46 = v24;
|
||||
v42 = v38;
|
||||
}
|
||||
|
||||
currentText += advance;
|
||||
}
|
||||
|
||||
v46 = (v42 + v46) / static_cast<float>(GetScreenPixelWidth());
|
||||
float v57 = v56 / static_cast<float>(GetScreenPixelWidth());
|
||||
v41 = pixelFontHeight / static_cast<float>(face->GetPixelSize());
|
||||
|
||||
if (quotedCode == CODE_NEWLINE || !*currentText) {
|
||||
*extent = v46 * v41;
|
||||
*nextText = currentText;
|
||||
*numBytes = currentText - startText;
|
||||
} else {
|
||||
if (!v18 || flags & 0x2) {
|
||||
*a10 = flags & 0x40;
|
||||
*numBytes = currentText - startText;
|
||||
*extent = v46 * v41;
|
||||
} else {
|
||||
*numBytes = v18;
|
||||
*extent = v57 * v41;
|
||||
currentText = &startText[v18];
|
||||
}
|
||||
|
||||
while (*currentText) {
|
||||
auto code = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(currentText), &advance);
|
||||
|
||||
if (!iswspace(code)) {
|
||||
break;
|
||||
}
|
||||
|
||||
currentText += advance;
|
||||
}
|
||||
|
||||
*nextText = currentText;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t CanWrapBetween(uint32_t codeA, uint32_t codeB) {
|
||||
if (!codeB) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeB != '-' && codeB != ';' && codeB != '/' && codeA != ('|') && codeA != '\xFF\xFF\xFF\xFF') {
|
||||
if (iswspace(codeB)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!iswspace(codeA)) {
|
||||
bool v3, v5;
|
||||
|
||||
if (codeB > 0x3008) {
|
||||
if (codeB <= 0x3014) {
|
||||
if (codeB != 0x3014) {
|
||||
switch (codeB) {
|
||||
case 0x300A:
|
||||
case 0x300C:
|
||||
case 0x300E:
|
||||
case 0x3010:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
goto LABEL_18;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeB > 0xFF08) {
|
||||
switch (codeB) {
|
||||
case 0xFF3B:
|
||||
case 0xFF5B:
|
||||
case 0xFFE1:
|
||||
case 0xFFE5:
|
||||
case 0xFFE6:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
goto LABEL_18;
|
||||
}
|
||||
}
|
||||
|
||||
if (codeB == 0xFF08) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeB > 0xFE5B) {
|
||||
if (codeB == 0xFE5D) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
v3 = codeB == 0xFF04;
|
||||
} else {
|
||||
if (codeB == 0xFE5B || codeB == 0x301D) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
v3 = codeB == 0xFE59;
|
||||
}
|
||||
} else {
|
||||
if (codeB == 0x3008) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeB <= '{') {
|
||||
if (codeB != '{') {
|
||||
switch (codeB) {
|
||||
case '$':
|
||||
case '(':
|
||||
case '[':
|
||||
case '\\':
|
||||
return 0;
|
||||
|
||||
default:
|
||||
goto LABEL_18;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeB == 0x2018 || codeB == 0x201C) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
v3 = codeB == 0x2035;
|
||||
}
|
||||
|
||||
if (v3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
LABEL_18:
|
||||
if (codeA <= 0x2014) {
|
||||
if (codeA < 0x2013) {
|
||||
switch (codeA) {
|
||||
case '!':
|
||||
case '%':
|
||||
case ')':
|
||||
case ',':
|
||||
case '.':
|
||||
case ':':
|
||||
case ';':
|
||||
case '?':
|
||||
case ']':
|
||||
case '}':
|
||||
case 0xB0:
|
||||
case 0xB7:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeA > 0xFE30) {
|
||||
if (codeA > 0xFF5D) {
|
||||
switch (codeA) {
|
||||
case 0xFF70:
|
||||
case 0xFF9E:
|
||||
case 0xFF9F:
|
||||
case 0xFFE0:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
}
|
||||
|
||||
if (codeA != 0xFF5D) {
|
||||
switch (codeA) {
|
||||
case 0xFE50:
|
||||
case 0xFE51:
|
||||
case 0xFE52:
|
||||
case 0xFE54:
|
||||
case 0xFE55:
|
||||
case 0xFE56:
|
||||
case 0xFE57:
|
||||
case 0xFE5A:
|
||||
case 0xFE5C:
|
||||
case 0xFE5E:
|
||||
case 0xFF01:
|
||||
case 0xFF05:
|
||||
case 0xFF09:
|
||||
case 0xFF0C:
|
||||
case 0xFF0E:
|
||||
case 0xFF1A:
|
||||
case 0xFF1B:
|
||||
case 0xFF1F:
|
||||
case 0xFF3D:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeA == 0xFE30) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeA > 0x3009) {
|
||||
switch (codeA) {
|
||||
case 0x300B:
|
||||
case 0x300D:
|
||||
case 0x300F:
|
||||
case 0x3011:
|
||||
case 0x3015:
|
||||
case 0x301E:
|
||||
case 0x30FC:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
}
|
||||
|
||||
if (codeA == 0x3009) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeA <= 0x2027) {
|
||||
if (codeA >= 0x2026 || codeA == 0x2019 || codeA == 0x201D || codeA == 0x2022) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
|
||||
if (codeA > 0x2103) {
|
||||
if (codeA < 0x3001) {
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
|
||||
v5 = codeA <= 0x3002;
|
||||
} else {
|
||||
if (codeA == 0x2103) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (codeA < 0x2032) {
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
|
||||
v5 = codeA <= 0x2033;
|
||||
}
|
||||
|
||||
if (v5) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return codeB == 0x3002
|
||||
|| codeB == 0xFF0C
|
||||
|| (codeA >= 0x1100 && codeA <= 0x11FF)
|
||||
|| (codeA >= 0x3000 && codeA <= 0xD7AF)
|
||||
|| (codeA >= 0xF900 && codeA <= 0xFAFF)
|
||||
|| (codeA >= 0xFF00 && codeA <= 0xFF9F)
|
||||
|| codeA - 0xFFA0 <= 0x3C;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
16
src/gx/font/Wrap.hpp
Normal file
16
src/gx/font/Wrap.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef GX_FONT_WRAP_HPP
|
||||
#define GX_FONT_WRAP_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class CGxFont;
|
||||
|
||||
void CalcWrapPoint(CGxFont*, const char*, float, float, uint32_t*, float*, const char**, float, uint32_t, bool*, float*, float);
|
||||
|
||||
void CalcWrapPointBillboarded(const char*, uint32_t, CGxFont*, float, uint32_t*, float*, const char**, float*, float);
|
||||
|
||||
void CalcWrapPointNonBillboarded(const char*, CGxFont*, float, float, uint32_t*, float*, const char**, float, uint32_t, bool*, float*, float);
|
||||
|
||||
int32_t CanWrapBetween(uint32_t codeA, uint32_t codeB);
|
||||
|
||||
#endif
|
||||
1312
src/gx/gll/CGxDeviceGLL.cpp
Normal file
1312
src/gx/gll/CGxDeviceGLL.cpp
Normal file
File diff suppressed because it is too large
Load diff
80
src/gx/gll/CGxDeviceGLL.hpp
Normal file
80
src/gx/gll/CGxDeviceGLL.hpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#ifndef GX_GLL_C_GX_DEVICE_GLL_HPP
|
||||
#define GX_GLL_C_GX_DEVICE_GLL_HPP
|
||||
|
||||
#include "gx/CGxDevice.hpp"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLWindow.h"
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
class CGxBatch;
|
||||
class CGxShader;
|
||||
|
||||
class CGxDeviceGLL : public CGxDevice {
|
||||
public:
|
||||
// Static variables
|
||||
static GLEnum s_glCubeMapFaces[];
|
||||
static GLEnum s_glDstBlend[];
|
||||
static GLEnum s_glSrcBlend[];
|
||||
static GLTextureFormat s_gxTexFmtToGLLFmt[];
|
||||
static GLEnum s_poolTarget2BufferFormat[];
|
||||
static GLEnum s_poolTarget2BufferType[];
|
||||
static GLEnum s_poolUsage2BufferUsage[];
|
||||
static GLEnum s_primitiveConversion[];
|
||||
|
||||
// Member variables
|
||||
GLDevice m_glDevice;
|
||||
GLWindow m_glWindow;
|
||||
GLVertexFormat m_glFormats[GxVertexBufferFormats_Last] = {};
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ITexMarkAsUpdated(CGxTex*);
|
||||
virtual void IRsSendToHw(EGxRenderState);
|
||||
virtual int32_t DeviceCreate(long (*)(void*, uint32_t, uint32_t, long), const CGxFormat&);
|
||||
virtual int32_t DeviceSetFormat(const CGxFormat&);
|
||||
virtual void CapsWindowSize(CRect&);
|
||||
virtual void CapsWindowSizeInScreenCoords(CRect& dst);
|
||||
virtual void ScenePresent(void);
|
||||
virtual void SceneClear(uint32_t, CImVector);
|
||||
virtual void XformSetProjection(const C44Matrix&);
|
||||
virtual void XformSetView(const C44Matrix&);
|
||||
virtual void Draw(CGxBatch*, int32_t);
|
||||
virtual void PoolSizeSet(CGxPool*, uint32_t);
|
||||
virtual char* BufLock(CGxBuf*);
|
||||
virtual int32_t BufUnlock(CGxBuf*, uint32_t);
|
||||
virtual void TexDestroy(CGxTex* texId);
|
||||
virtual void IShaderCreate(CGxShader*);
|
||||
virtual void ShaderCreate(CGxShader*[], EGxShTarget, const char*, const char*, int32_t);
|
||||
virtual int32_t StereoEnabled(void);
|
||||
|
||||
// Member functions
|
||||
CGxDeviceGLL();
|
||||
char* IBufLock(CGxBuf*);
|
||||
int32_t IBufUnlock(CGxBuf*);
|
||||
void ISceneBegin();
|
||||
void ISetCaps(void);
|
||||
void IShaderBindPixel(CGxShader*);
|
||||
void IShaderBindVertex(CGxShader*);
|
||||
void IShaderConstantsFlush(void);
|
||||
void IShaderCreatePixel(CGxShader*);
|
||||
void IShaderCreateVertex(CGxShader*);
|
||||
void IStateSetGLLDefaults();
|
||||
void IStateSync(void);
|
||||
void IStateSyncEnables(void);
|
||||
void IStateSyncIndexPtr(void);
|
||||
void IStateSyncLights(void);
|
||||
void IStateSyncMaterial(void);
|
||||
void IStateSyncScissorRect(void);
|
||||
void IStateSyncVertexPtrs(void);
|
||||
void IStateSyncXforms(void);
|
||||
void ITexCreate(CGxTex*);
|
||||
void ITexSetFlags(CGxTex*);
|
||||
void ITexUpload(CGxTex*);
|
||||
void IXformSetProjection(const C44Matrix&);
|
||||
void IXformSetView(const C44Matrix&);
|
||||
void IXformSetViewport(void);
|
||||
void PatchPixelShader(CGxShader*);
|
||||
void PatchVertexShader(CGxShader*);
|
||||
void Resize(uint32_t width, uint32_t height);
|
||||
};
|
||||
|
||||
#endif
|
||||
50
src/gx/gll/GL.cpp
Normal file
50
src/gx/gll/GL.cpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#include "gx/gll/GL.h"
|
||||
|
||||
TextureFormatInfo k_TextureFormatInfo[GLTF_NUM_TEXTURE_FORMATS] = {
|
||||
{ 0, 0, 0, 0, 0, "GLTF INVALID!!" },
|
||||
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0, 4, "ARGB8888" },
|
||||
{ GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0, 4, "XRGB8888" },
|
||||
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 0, 4, "RGBA8888" },
|
||||
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0, 4, "ABGR8888" },
|
||||
{ GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0, 4, "ARGB0888" },
|
||||
{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, 0, 3, "RGB888" },
|
||||
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, 0, 3, "BGR888" },
|
||||
{ GL_RGBA32F_ARB, GL_RGBA, GL_FLOAT, 0, 16, "RGBA32F" },
|
||||
{ GL_RGBA16F_ARB, GL_RGBA, GL_HALF_FLOAT, 0, 8, "RGBA16F" },
|
||||
{ GL_RGB16F_ARB, GL_RGB, GL_HALF_FLOAT, 0, 6, "RG16F" },
|
||||
{ GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 4, "D32" },
|
||||
{ GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 4, "D24" },
|
||||
{ GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0, 2, "D16" },
|
||||
{ GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_HALF_FLOAT, 0, 4, "DF" },
|
||||
{ GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0, 4, "D24S8" },
|
||||
{ GL_ALPHA8, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0, 1, "S8" },
|
||||
{ GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, 0, 2, "ARGB4444" },
|
||||
{ GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0, 2, "ARGB1555" },
|
||||
{ GL_RGB5, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0, 2, "ARGB0555" },
|
||||
{ GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0, 2, "RGB565" },
|
||||
{ GL_RGBA, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, 0, 4, "A2RGB10" },
|
||||
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT, 0, 6, "RGB16" },
|
||||
{ GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, 1, "L8" },
|
||||
{ GL_ALPHA8, GL_ALPHA, GL_UNSIGNED_BYTE, 0, 1, "A8" },
|
||||
{ GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 0, 2, "A8L8" },
|
||||
{ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 1, 8, "DXT1" },
|
||||
{ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 1, 16, "DXT3" },
|
||||
{ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 1, 16, "DXT5" }
|
||||
};
|
||||
|
||||
VertexTypeInfo k_VertexTypeInfo[GLVT_NUM_VERTEX_TYPES] = {
|
||||
{ 0, 0, 0, 0, "INVALID" },
|
||||
{ GL_FLOAT, 1, 0, 4, "FLOAT1" },
|
||||
{ GL_FLOAT, 2, 0, 8, "FLOAT2" },
|
||||
{ GL_FLOAT, 3, 0, 12, "FLOAT3" },
|
||||
{ GL_FLOAT, 4, 0, 16, "FLOAT4" },
|
||||
{ GL_UNSIGNED_BYTE, 4, 0, 4, "UBYTE4" },
|
||||
{ GL_UNSIGNED_BYTE, 4, 1, 4, "UBYTE4N" },
|
||||
{ GL_SHORT, 1, 0, 2, "SHORT" },
|
||||
{ GL_SHORT, 2, 0, 4, "SHORT2" },
|
||||
{ GL_SHORT, 4, 0, 8, "SHORT4" },
|
||||
{ GL_SHORT, 2, 1, 4, "SHORT2N" },
|
||||
{ GL_SHORT, 4, 1, 8, "SHORT4N" },
|
||||
{ GL_UNSIGNED_SHORT, 2, 1, 4, "USHORT2N" },
|
||||
{ GL_UNSIGNED_SHORT, 4, 1, 8, "USHORT4N" }
|
||||
};
|
||||
31
src/gx/gll/GL.h
Normal file
31
src/gx/gll/GL.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef GX_GLL_GL_H
|
||||
#define GX_GLL_GL_H
|
||||
|
||||
#include "gx/gll/GLTypes.h"
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
typedef GLenum GLEnum;
|
||||
|
||||
#define kMAX_VERTEX_ATTRIBS 16
|
||||
|
||||
struct TextureFormatInfo {
|
||||
GLenum m_InternalFormat;
|
||||
GLenum m_DataFormat;
|
||||
GLenum m_DataType;
|
||||
int32_t m_IsCompressed;
|
||||
int32_t m_BytePerPixel;
|
||||
char m_Name[16];
|
||||
};
|
||||
|
||||
struct VertexTypeInfo {
|
||||
GLenum m_Type;
|
||||
GLint m_Size;
|
||||
GLboolean m_Normalized;
|
||||
GLint m_ByteSize;
|
||||
const char* m_Name;
|
||||
};
|
||||
|
||||
extern TextureFormatInfo k_TextureFormatInfo[GLTF_NUM_TEXTURE_FORMATS];
|
||||
extern VertexTypeInfo k_VertexTypeInfo[GLVT_NUM_VERTEX_TYPES];
|
||||
|
||||
#endif
|
||||
19
src/gx/gll/GLAbstractWindow.cpp
Normal file
19
src/gx/gll/GLAbstractWindow.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "gx/gll/GLAbstractWindow.h"
|
||||
#include <cmath>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
int32_t GLAbstractWindow::GetBackingWidth() {
|
||||
return static_cast<int32_t>(std::floor(this->GetBackingRect().size.width));
|
||||
}
|
||||
|
||||
int32_t GLAbstractWindow::GetBackingHeight() {
|
||||
return static_cast<int32_t>(std::floor(this->GetBackingRect().size.height));
|
||||
}
|
||||
|
||||
int32_t GLAbstractWindow::GetWidth() {
|
||||
return static_cast<int32_t>(std::floor(this->GetRect().size.width));
|
||||
}
|
||||
|
||||
int32_t GLAbstractWindow::GetHeight() {
|
||||
return static_cast<int32_t>(std::floor(this->GetRect().size.height));
|
||||
}
|
||||
36
src/gx/gll/GLAbstractWindow.h
Normal file
36
src/gx/gll/GLAbstractWindow.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef GX_GLL_GL_ABSTRACT_WINDOW_H
|
||||
#define GX_GLL_GL_ABSTRACT_WINDOW_H
|
||||
|
||||
#ifdef __OBJC__
|
||||
#include <AppKit/AppKit.h>
|
||||
#else
|
||||
#include <objc/runtime.h>
|
||||
typedef struct objc_object NSWindow;
|
||||
typedef struct objc_object NSView;
|
||||
#endif
|
||||
|
||||
struct CGRect;
|
||||
class GLContext;
|
||||
|
||||
class GLAbstractWindow {
|
||||
public:
|
||||
// Virtual member functions
|
||||
virtual int32_t GetWidth(void);
|
||||
virtual int32_t GetHeight(void);
|
||||
virtual CGRect GetRect(void) = 0;
|
||||
virtual void Show(void) = 0;
|
||||
virtual void Resize(uint32_t, uint32_t) = 0;
|
||||
virtual void SetTitle(const char*) = 0;
|
||||
virtual void CreateView(void) = 0;
|
||||
virtual void SetOpenGLContext(GLContext*) = 0;
|
||||
// virtual NSWindow* GetNSWindow(void) = 0;
|
||||
virtual NSView* GetNSView(void) = 0;
|
||||
virtual bool CanEnterFullscreenMode(void) = 0;
|
||||
// virtual void EnterFullscreenMode(uint32_t, bool) = 0;
|
||||
virtual void ExitFullscreenMode(void) = 0;
|
||||
virtual CGRect GetBackingRect() = 0;
|
||||
virtual int32_t GetBackingWidth();
|
||||
virtual int32_t GetBackingHeight();
|
||||
};
|
||||
|
||||
#endif
|
||||
45
src/gx/gll/GLBatch.h
Normal file
45
src/gx/gll/GLBatch.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef GX_GLL_GL_BATCH_H
|
||||
#define GX_GLL_GL_BATCH_H
|
||||
|
||||
#include "gx/gll/GLBuffer.h"
|
||||
#include "gx/gll/GLShader.h"
|
||||
#include "gx/gll/GLTexture.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
#include "gx/gll/GLVertexFormat.h"
|
||||
#include <cstdint>
|
||||
|
||||
class GLBatch {
|
||||
public:
|
||||
GLShader* var0;
|
||||
GLShader* var1;
|
||||
GLTexture* textures[16];
|
||||
GLBuffer* var3;
|
||||
GLBuffer* var4[4];
|
||||
uint32_t var5[4];
|
||||
uint32_t var6[4];
|
||||
GLVertexFormat* var7;
|
||||
uint32_t var8;
|
||||
uint32_t var9;
|
||||
uint32_t var10;
|
||||
uint32_t var11;
|
||||
uint32_t var12;
|
||||
uint32_t var13;
|
||||
uint32_t var14;
|
||||
int32_t var15;
|
||||
bool var16;
|
||||
bool var17;
|
||||
GLStates var18;
|
||||
GLTexture2D* colorBuffer[4];
|
||||
GLTexture2D* var20;
|
||||
uint32_t var21[128];
|
||||
char var22[64];
|
||||
char var23[1024];
|
||||
uint32_t var24;
|
||||
bool var25;
|
||||
int64_t var26;
|
||||
int64_t var27;
|
||||
float var28[4096];
|
||||
float var29[1024];
|
||||
};
|
||||
|
||||
#endif
|
||||
128
src/gx/gll/GLBuffer.cpp
Normal file
128
src/gx/gll/GLBuffer.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#include "gx/gll/GLBuffer.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLPool.h"
|
||||
#include "util/BlizzardCore.hpp"
|
||||
|
||||
bool GLBuffer::m_UsingVBO = 1;
|
||||
|
||||
GLEnum GLBuffer::s_FlagToAccess[] = {
|
||||
GL_READ_WRITE, // GLMap_None
|
||||
GL_WRITE_ONLY, // GLMap_Unk1
|
||||
GL_WRITE_ONLY, // GLMap_Unk2
|
||||
GL_READ_ONLY // GLMap_Unk3
|
||||
};
|
||||
|
||||
GLBuffer* GLBuffer::Create(GLEnum type, uint32_t size, const void* a3, GLEnum usage, GLEnum format) {
|
||||
GLBuffer* buffer = GLPool<GLBuffer>::Get()->GetNextObject();
|
||||
|
||||
buffer->m_Type = type;
|
||||
buffer->m_Size = size;
|
||||
buffer->m_Usage = usage;
|
||||
buffer->m_IndexFormat = format;
|
||||
|
||||
GLDevice* device = GLDevice::Get();
|
||||
device->BindBuffer(buffer, GL_ZERO);
|
||||
|
||||
if (GLBuffer::m_UsingVBO) {
|
||||
glBufferData(buffer->m_Type, buffer->m_Size, a3, buffer->m_Usage);
|
||||
glBufferParameteriAPPLE(buffer->m_Type, GL_BUFFER_SERIALIZED_MODIFY_APPLE, buffer->m_Usage - GL_DYNAMIC_DRAW > 1);
|
||||
glBufferParameteriAPPLE(buffer->m_Type, GL_BUFFER_FLUSHING_UNMAP_APPLE, 0);
|
||||
} else {
|
||||
Blizzard::Memory::Free(buffer->m_Data);
|
||||
|
||||
void* data = Blizzard::Memory::Allocate(size);
|
||||
if (a3) {
|
||||
memcpy(data, a3, size);
|
||||
}
|
||||
|
||||
buffer->m_Data = reinterpret_cast<char*>(data);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// buffer->m_TimeStamp = Blizzard::Time::GetTimestamp();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
GLBuffer::GLBuffer() : GLObject() {
|
||||
if (GLBuffer::m_UsingVBO) {
|
||||
this->m_BufferID = GLPool<GLBuffer>::Get()->GetNextName();
|
||||
}
|
||||
}
|
||||
|
||||
char* GLBuffer::Map(uint32_t offset, uint32_t size, eMapFlag flag) {
|
||||
BLIZZARD_ASSERT((offset + size) <= this->m_Size);
|
||||
BLIZZARD_ASSERT(this->m_Usage == GL_STATIC_DRAW || flag != GLMap_None);
|
||||
BLIZZARD_ASSERT(this->m_MapFlag == GLMap_NotMapped);
|
||||
BLIZZARD_ASSERT(flag >= GLMap_None && flag < GLMap_Count);
|
||||
|
||||
this->m_MapOffset = offset;
|
||||
this->m_MapSize = offset + size == 0 ? this->m_Size : size;
|
||||
this->m_MapFlag = flag;
|
||||
|
||||
if (GLBuffer::m_UsingVBO) {
|
||||
GLDevice* device = GLDevice::Get();
|
||||
device->BindBuffer(this, GL_ZERO);
|
||||
|
||||
if (flag == GLMap_Unk2) {
|
||||
if (this->m_Usage - GL_DYNAMIC_DRAW <= 1) {
|
||||
BLIZZARD_ASSERT(offset == 0);
|
||||
}
|
||||
|
||||
glBufferData(this->m_Type, this->m_Size, nullptr, this->m_Usage);
|
||||
}
|
||||
|
||||
void* data = glMapBuffer(this->m_Type, GLBuffer::s_FlagToAccess[flag]);
|
||||
this->m_Data = reinterpret_cast<char*>(data);
|
||||
|
||||
BLIZZARD_ASSERT(this->m_Data != nullptr);
|
||||
}
|
||||
|
||||
return this->m_Data + offset;
|
||||
}
|
||||
|
||||
void GLBuffer::ReleaseObject() {
|
||||
if (GLBuffer::m_UsingVBO) {
|
||||
if (this->m_Type) {
|
||||
GLDevice* device = GLDevice::Get();
|
||||
device->BindBuffer(this, GL_ZERO);
|
||||
|
||||
glBufferData(this->m_Type, 1, nullptr, this->m_Usage);
|
||||
|
||||
// TODO GLPool<GLBuffer>::GLObjectPool::Push((GLPool<GLBuffer>::m_pool + 32776), this);
|
||||
} else {
|
||||
// TODO GLPool<GLBuffer>::GLObjectPool::Push((GLPool<GLBuffer>::m_pool + 32776), this);
|
||||
}
|
||||
} else {
|
||||
Blizzard::Memory::Free(this->m_Data);
|
||||
this->m_Data = nullptr;
|
||||
|
||||
// TODO GLPool<GLBuffer>::GLObjectPool::Push((GLPool<GLBuffer>::m_pool + 32776), this);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBuffer::Unmap(uint32_t size) {
|
||||
BLIZZARD_ASSERT((this->m_MapOffset + size) <= m_Size);
|
||||
|
||||
GLDevice* device = GLDevice::Get();
|
||||
device->BindBuffer(this, GL_ZERO);
|
||||
|
||||
if (this->m_MapFlag != 3) {
|
||||
if (GLBuffer::m_UsingVBO) {
|
||||
glFlushMappedBufferRangeAPPLE(this->m_Type, this->m_MapOffset, size ? size : this->m_MapSize);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// this->m_TimeStamp = Blizzard::Time::GetTimestamp();
|
||||
}
|
||||
|
||||
if (!GLBuffer::m_UsingVBO) {
|
||||
this->m_MapFlag = GLMap_NotMapped;
|
||||
return;
|
||||
}
|
||||
|
||||
GLboolean result = glUnmapBuffer(this->m_Type);
|
||||
BLIZZARD_ASSERT(result);
|
||||
|
||||
this->m_MapFlag = GLMap_NotMapped;
|
||||
}
|
||||
47
src/gx/gll/GLBuffer.h
Normal file
47
src/gx/gll/GLBuffer.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef GX_GLL_GL_BUFFER_H
|
||||
#define GX_GLL_GL_BUFFER_H
|
||||
|
||||
#include "gx/gll/GL.h"
|
||||
#include "gx/gll/GLObject.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
|
||||
class GLBuffer : public GLObject {
|
||||
public:
|
||||
// Types
|
||||
enum eMapFlag {
|
||||
GLMap_NotMapped = -1,
|
||||
GLMap_None = 0,
|
||||
GLMap_Unk1 = 1,
|
||||
GLMap_Unk2 = 2,
|
||||
GLMap_Unk3 = 3,
|
||||
GLMap_Count = 4
|
||||
};
|
||||
|
||||
// Static variables
|
||||
static bool m_UsingVBO;
|
||||
static GLEnum s_FlagToAccess[];
|
||||
|
||||
// Static functions
|
||||
static GLBuffer* Create(GLEnum, uint32_t, const void*, GLEnum, GLEnum);
|
||||
|
||||
// Member variables
|
||||
uint32_t m_Size = 0;
|
||||
GLEnum m_Type = 0;
|
||||
GLEnum m_Usage = 0;
|
||||
uint32_t m_BufferID = 0;
|
||||
GLEnum m_IndexFormat = 0;
|
||||
char* m_Data = nullptr;
|
||||
uint32_t m_MapOffset = 0;
|
||||
uint32_t m_MapSize = 0;
|
||||
uint32_t m_MapFlag = GLMap_NotMapped;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ReleaseObject();
|
||||
|
||||
// Member functions
|
||||
GLBuffer();
|
||||
char* Map(uint32_t, uint32_t, eMapFlag);
|
||||
void Unmap(uint32_t);
|
||||
};
|
||||
|
||||
#endif
|
||||
8
src/gx/gll/GLBufferPool.h
Normal file
8
src/gx/gll/GLBufferPool.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef GX_GLL_GL_BUFFER_POOL_H
|
||||
#define GX_GLL_GL_BUFFER_POOL_H
|
||||
|
||||
class GLBufferPool {
|
||||
public:
|
||||
};
|
||||
|
||||
#endif
|
||||
24
src/gx/gll/GLCommand.cpp
Normal file
24
src/gx/gll/GLCommand.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "gx/gll/GLCommand.h"
|
||||
#include "gx/gll/GLTexture.h"
|
||||
|
||||
void GLFlush::Execute(GLDevice* device) {
|
||||
glFlush();
|
||||
}
|
||||
|
||||
GLTexUnmap::GLTexUnmap(GLTexture* texture, GLMipmap* mipmap, GLMipmap::MapParams* mapParams) {
|
||||
this->m_Texture = texture;
|
||||
this->m_Mipmap = mipmap;
|
||||
this->m_MapParams = mapParams;
|
||||
}
|
||||
|
||||
void GLTexUnmap::Execute(GLDevice* device) {
|
||||
this->m_Mipmap->Unmap(this->m_MapParams);
|
||||
}
|
||||
|
||||
GLTexDestroy::GLTexDestroy(GLTexture* texture) {
|
||||
this->m_Texture = texture;
|
||||
}
|
||||
|
||||
void GLTexDestroy::Execute(GLDevice* device) {
|
||||
this->m_Texture->FreeTexture();
|
||||
}
|
||||
46
src/gx/gll/GLCommand.h
Normal file
46
src/gx/gll/GLCommand.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef GX_GLL_GL_COMMAND_H
|
||||
#define GX_GLL_GL_COMMAND_H
|
||||
|
||||
#include "gx/gll/GLMipmap.h"
|
||||
|
||||
class GLDevice;
|
||||
|
||||
class GLCommand {
|
||||
public:
|
||||
// Virtual member functions
|
||||
virtual void Execute(GLDevice*) = 0;
|
||||
};
|
||||
|
||||
class GLFlush : public GLCommand {
|
||||
public:
|
||||
// Virtual member functions
|
||||
virtual void Execute(GLDevice* device);
|
||||
};
|
||||
|
||||
class GLTexUnmap : public GLCommand {
|
||||
public:
|
||||
// Member variables
|
||||
GLTexture* m_Texture;
|
||||
GLMipmap* m_Mipmap;
|
||||
GLMipmap::MapParams* m_MapParams;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void Execute(GLDevice*);
|
||||
|
||||
// Member functions
|
||||
GLTexUnmap(GLTexture*, GLMipmap*, GLMipmap::MapParams*);
|
||||
};
|
||||
|
||||
class GLTexDestroy : public GLCommand {
|
||||
public:
|
||||
// Member variables
|
||||
GLTexture* m_Texture;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void Execute(GLDevice* device);
|
||||
|
||||
// Member functions
|
||||
GLTexDestroy(GLTexture* texture);
|
||||
};
|
||||
|
||||
#endif
|
||||
96
src/gx/gll/GLContext.h
Normal file
96
src/gx/gll/GLContext.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef GX_GLL_GL_CONTEXT_H
|
||||
#define GX_GLL_GL_CONTEXT_H
|
||||
|
||||
#include "gx/gll/GLAbstractWindow.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
#include "util/BlizzardCore.hpp"
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#else
|
||||
typedef struct objc_object NSOpenGLContext;
|
||||
typedef struct objc_object NSOpenGLPixelFormat;
|
||||
#endif
|
||||
|
||||
class GLDevice;
|
||||
|
||||
class GLContext {
|
||||
public:
|
||||
// Types
|
||||
struct Context {
|
||||
NSOpenGLContext* context;
|
||||
NSOpenGLPixelFormat* pixelFormat;
|
||||
int32_t sampleCount;
|
||||
|
||||
~Context();
|
||||
};
|
||||
|
||||
struct GammaFormula {
|
||||
float m_RedMin;
|
||||
float m_RedMax;
|
||||
float m_RedGamma;
|
||||
float m_GreenMin;
|
||||
float m_GreenMax;
|
||||
float m_GreenGamma;
|
||||
float m_BlueMin;
|
||||
float m_BlueMax;
|
||||
float m_BlueGamma;
|
||||
};
|
||||
|
||||
// Static variables
|
||||
static NSOpenGLContext* s_MainContext;
|
||||
static Blizzard::Thread::TLSSlot s_CurrentContext;
|
||||
static Blizzard::Thread::TLSSlot s_CurrentGLContext;
|
||||
static CFDictionaryRef s_DesktopMode;
|
||||
|
||||
// Static functions
|
||||
static NSOpenGLContext* GetNSOpenGLCurrentContext(void);
|
||||
static NSOpenGLContext* GetCurrentContext(void);
|
||||
static void SetCurrentContext(NSOpenGLContext*);
|
||||
static GLContext* GetCurrentGLContext(void);
|
||||
static void SetCurrentGLContext(GLContext*);
|
||||
|
||||
// Member variables
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char>> m_DebugName;
|
||||
std::map<uint32_t, GLContext::Context, std::less<uint32_t>, std::allocator<std::pair<const uint32_t, GLContext::Context>>> m_Contexts;
|
||||
Context* m_Context;
|
||||
GLDevice* m_Device;
|
||||
GLAbstractWindow* m_Window;
|
||||
bool m_Windowed;
|
||||
bool m_MTGLEnabled;
|
||||
bool m_VSyncEnabled;
|
||||
bool m_CaptureDisplay;
|
||||
uint32_t m_Width;
|
||||
uint32_t m_Height;
|
||||
uint32_t m_RefreshRate;
|
||||
GammaFormula m_GammaFormula;
|
||||
bool m_GammaTablesSet;
|
||||
std::vector<uint16_t, std::allocator<uint16_t>> m_GammaTableR;
|
||||
std::vector<uint16_t, std::allocator<uint16_t>> m_GammaTableG;
|
||||
std::vector<uint16_t, std::allocator<uint16_t>> m_GammaTableB;
|
||||
std::vector<uint16_t, std::allocator<uint16_t>> m_OsGammaTableR;
|
||||
std::vector<uint16_t, std::allocator<uint16_t>> m_OsGammaTableG;
|
||||
std::vector<uint16_t, std::allocator<uint16_t>> m_OsGammaTableB;
|
||||
|
||||
// Member functions
|
||||
GLContext(GLDevice*, const char*);
|
||||
int32_t GetBackingWidth();
|
||||
int32_t GetBackingHeight();
|
||||
int32_t GetWidth(void);
|
||||
int32_t GetHeight(void);
|
||||
bool IsCurrentContext(void);
|
||||
void MakeCurrent(bool);
|
||||
void SetContextFormat(GLTextureFormat, uint32_t);
|
||||
void SetFullscreenMode(uint32_t, uint32_t, uint32_t, bool);
|
||||
void SetWindow(GLAbstractWindow*, bool);
|
||||
void Swap(void);
|
||||
void Update(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
389
src/gx/gll/GLContext.mm
Normal file
389
src/gx/gll/GLContext.mm
Normal file
|
|
@ -0,0 +1,389 @@
|
|||
#include "gx/gll/GLContext.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "util/Autorelease.hpp"
|
||||
|
||||
NSOpenGLContext* GLContext::s_MainContext;
|
||||
Blizzard::Thread::TLSSlot GLContext::s_CurrentContext;
|
||||
Blizzard::Thread::TLSSlot GLContext::s_CurrentGLContext;
|
||||
CFDictionaryRef GLContext::s_DesktopMode;
|
||||
|
||||
void* Sub2A1E0(void* ptr) {
|
||||
NSOpenGLContext** ptrptr = new NSOpenGLContext*;
|
||||
*ptrptr = nullptr;
|
||||
return ptrptr;
|
||||
}
|
||||
|
||||
void Sub2A200(void* ptr) {
|
||||
delete static_cast<NSOpenGLContext**>(ptr);
|
||||
}
|
||||
|
||||
void* Sub720A0(void* ptr) {
|
||||
GLContext** ptrptr = new GLContext*;
|
||||
*ptrptr = nullptr;
|
||||
return ptrptr;
|
||||
}
|
||||
|
||||
void Sub720C0(void* ptr) {
|
||||
delete static_cast<GLContext**>(ptr);
|
||||
}
|
||||
|
||||
GLContext::Context::~Context() {
|
||||
if (this->context) {
|
||||
glFlush();
|
||||
|
||||
[this->context clearDrawable];
|
||||
|
||||
if (GLContext::GetCurrentContext() == context) {
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
GLContext::SetCurrentContext(nullptr);
|
||||
}
|
||||
|
||||
[this->context release];
|
||||
}
|
||||
|
||||
[this->pixelFormat release];
|
||||
}
|
||||
|
||||
NSOpenGLContext* GLContext::GetNSOpenGLCurrentContext() {
|
||||
return [NSOpenGLContext currentContext];
|
||||
}
|
||||
|
||||
NSOpenGLContext* GLContext::GetCurrentContext() {
|
||||
return *static_cast<NSOpenGLContext**>(
|
||||
Blizzard::Thread::RegisterLocalStorage(&GLContext::s_CurrentContext, Sub2A1E0, 0, Sub2A200)
|
||||
);
|
||||
}
|
||||
|
||||
void GLContext::SetCurrentContext(NSOpenGLContext* context) {
|
||||
*static_cast<NSOpenGLContext**>(
|
||||
Blizzard::Thread::RegisterLocalStorage(&GLContext::s_CurrentContext, Sub2A1E0, 0, Sub2A200)
|
||||
) = context;
|
||||
}
|
||||
|
||||
GLContext* GLContext::GetCurrentGLContext() {
|
||||
return *static_cast<GLContext**>(
|
||||
Blizzard::Thread::RegisterLocalStorage(&GLContext::s_CurrentGLContext, Sub720A0, 0, Sub720C0)
|
||||
);
|
||||
}
|
||||
|
||||
void GLContext::SetCurrentGLContext(GLContext* context) {
|
||||
*static_cast<GLContext**>(
|
||||
Blizzard::Thread::RegisterLocalStorage(&GLContext::s_CurrentGLContext, Sub720A0, 0, Sub720C0)
|
||||
) = context;
|
||||
}
|
||||
|
||||
GLContext::GLContext(GLDevice* a2, const char* a3) {
|
||||
this->m_Context = nullptr;
|
||||
this->m_Window = nullptr;
|
||||
this->m_Windowed = false;
|
||||
this->m_MTGLEnabled = false;
|
||||
this->m_Device = a2;
|
||||
this->m_Width = 0;
|
||||
this->m_Height = 0;
|
||||
this->m_RefreshRate = 0;
|
||||
}
|
||||
|
||||
int32_t GLContext::GetBackingWidth() {
|
||||
if (this->m_Windowed) {
|
||||
return this->m_Window->GetBackingWidth();
|
||||
} else {
|
||||
return this->m_Width;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GLContext::GetBackingHeight() {
|
||||
if (this->m_Windowed) {
|
||||
return this->m_Window->GetBackingHeight();
|
||||
} else {
|
||||
return this->m_Height;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GLContext::GetWidth() {
|
||||
if (this->m_Windowed) {
|
||||
return this->m_Window->GetWidth();
|
||||
} else {
|
||||
return this->m_Width;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GLContext::GetHeight() {
|
||||
if (this->m_Windowed) {
|
||||
return this->m_Window->GetHeight();
|
||||
} else {
|
||||
return this->m_Height;
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContext::IsCurrentContext() {
|
||||
return GLContext::GetCurrentGLContext() == this;
|
||||
}
|
||||
|
||||
void GLContext::MakeCurrent(bool a2) {
|
||||
BLIZZARD_ASSERT(this->m_Context->context != nullptr);
|
||||
|
||||
if (a2) {
|
||||
NSOpenGLContext* v6 = GLContext::GetNSOpenGLCurrentContext();
|
||||
GLContext::SetCurrentContext(v6);
|
||||
}
|
||||
|
||||
if (this->m_Context->context != GLContext::GetCurrentContext()) {
|
||||
int32_t mtglEnabled = 0;
|
||||
|
||||
if (GLContext::GetCurrentContext()) {
|
||||
mtglEnabled = this->m_MTGLEnabled;
|
||||
|
||||
// TODO
|
||||
// this->ToggleMTGL(0);
|
||||
// GLOcclusionQuery::DeleteAllQueries();
|
||||
// GLFence::DeleteAllFences();
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
[this->m_Context->context makeCurrentContext];
|
||||
|
||||
GLContext::SetCurrentContext(this->m_Context->context);
|
||||
GLContext::SetCurrentGLContext(this);
|
||||
|
||||
// TODO
|
||||
// GLOcclusionQuery::RecreateAllQueries();
|
||||
// GLFence::RecreateAllFences();
|
||||
// this->ToggleMTGL(mtglEnabled);
|
||||
|
||||
GLDevice* device = GLDevice::Get();
|
||||
|
||||
if (device && this->m_Contexts.size() > 1) {
|
||||
device->ApplyGLStates(device->m_States, 1);
|
||||
device->ApplyGLBindings(device->m_States, 1);
|
||||
device->m_DefaultVertexArrayObject.ApplyGLStates(device->m_DefaultVertexArrayObject.m_GLStates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::SetContextFormat(GLTextureFormat a2, uint32_t sampleCount) {
|
||||
System_Autorelease::ScopedPool autorelease;
|
||||
|
||||
uint32_t v61 = sampleCount | (a2 << 8);
|
||||
|
||||
if (this->m_Contexts.find(v61) != this->m_Contexts.end()) {
|
||||
this->m_Context = &this->m_Contexts[v61];
|
||||
|
||||
if (this->m_Window) {
|
||||
this->m_Window->SetOpenGLContext(this);
|
||||
}
|
||||
} else {
|
||||
auto& context = this->m_Contexts[v61];
|
||||
|
||||
CGDirectDisplayID v6 = CGMainDisplayID();
|
||||
|
||||
NSOpenGLPixelFormatAttribute formatAttributes[] = {
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
NSOpenGLPFANoRecovery,
|
||||
NSOpenGLPFAAccelerated,
|
||||
NSOpenGLPFADepthSize, 0,
|
||||
NSOpenGLPFAStencilSize, 0,
|
||||
NSOpenGLPFAColorSize, 32,
|
||||
NSOpenGLPFAWindow,
|
||||
NSOpenGLPFAFullScreen,
|
||||
NSOpenGLPFAScreenMask, CGDisplayIDToOpenGLDisplayMask(v6),
|
||||
0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
switch (a2) {
|
||||
case GLTF_INVALID:
|
||||
break;
|
||||
|
||||
case GLTF_D32:
|
||||
formatAttributes[4] = 32;
|
||||
break;
|
||||
|
||||
case GLTF_D24:
|
||||
formatAttributes[4] = 24;
|
||||
break;
|
||||
|
||||
case GLTF_D16:
|
||||
formatAttributes[4] = 16;
|
||||
break;
|
||||
|
||||
case GLTF_D24S8:
|
||||
formatAttributes[4] = 24;
|
||||
formatAttributes[6] = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
BLIZZARD_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sampleCount > 1) {
|
||||
BLIZZARD_ASSERT(sampleCount % 2 == 0);
|
||||
BLIZZARD_ASSERT(formatAttributes[13] == 0);
|
||||
BLIZZARD_ASSERT(formatAttributes[14] == 0);
|
||||
BLIZZARD_ASSERT(formatAttributes[15] == 0);
|
||||
BLIZZARD_ASSERT(formatAttributes[16] == 0);
|
||||
BLIZZARD_ASSERT(formatAttributes[17] == 0);
|
||||
|
||||
formatAttributes[13] = NSOpenGLPFASampleBuffers;
|
||||
formatAttributes[14] = 1;
|
||||
formatAttributes[15] = NSOpenGLPFASamples;
|
||||
formatAttributes[16] = sampleCount;
|
||||
}
|
||||
|
||||
context.sampleCount = sampleCount;
|
||||
|
||||
context.pixelFormat = [[NSOpenGLPixelFormat alloc]
|
||||
initWithAttributes: formatAttributes
|
||||
];
|
||||
|
||||
BLIZZARD_ASSERT(context.pixelFormat != nullptr);
|
||||
|
||||
context.context = [[NSOpenGLContext alloc]
|
||||
initWithFormat: context.pixelFormat
|
||||
shareContext: GLContext::s_MainContext
|
||||
];
|
||||
|
||||
BLIZZARD_ASSERT(context.context != nullptr);
|
||||
|
||||
this->m_Context = &context;
|
||||
|
||||
auto contextObj = [context.context CGLContextObj];
|
||||
|
||||
int32_t vsyncEnabled = this->m_VSyncEnabled;
|
||||
CGLSetParameter(contextObj, kCGLCPSwapInterval, &vsyncEnabled);
|
||||
|
||||
auto result = this->m_MTGLEnabled
|
||||
? CGLEnable(contextObj, kCGLCEMPEngine)
|
||||
: CGLDisable(contextObj, kCGLCEMPEngine);
|
||||
BLIZZARD_ASSERT(result == kCGLNoError);
|
||||
|
||||
if (this->m_Window) {
|
||||
this->m_Window->SetOpenGLContext(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m_Context->context != GLContext::GetCurrentContext()) {
|
||||
this->MakeCurrent(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::SetFullscreenMode(uint32_t, uint32_t, uint32_t, bool) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GLContext::SetWindow(GLAbstractWindow* a2, bool a3) {
|
||||
if (!a2) {
|
||||
if (this->m_Window) {
|
||||
this->m_Window->SetOpenGLContext(nullptr);
|
||||
}
|
||||
|
||||
this->m_Window = nullptr;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m_Windowed && a2 == this->m_Window) {
|
||||
if (a3) {
|
||||
a2->Show();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NSView* v5;
|
||||
|
||||
if (this->m_Window) {
|
||||
v5 = this->m_Window->GetNSView();
|
||||
|
||||
if (v5 && this->m_Windowed && a2 != this->m_Window) {
|
||||
this->m_Window = a2;
|
||||
this->m_Window->SetOpenGLContext(this);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
v5 = nullptr;
|
||||
}
|
||||
|
||||
this->m_Window = a2;
|
||||
|
||||
if (!a2->GetNSView()) {
|
||||
this->m_Window->CreateView();
|
||||
}
|
||||
|
||||
float v15;
|
||||
bool v16 = false;
|
||||
CGDisplayFadeReservationToken v17 = 0;
|
||||
|
||||
if (v5 && GLDevice::GetRendererInfo().unk100 > 2639 && this->m_Window->CanEnterFullscreenMode()) {
|
||||
if (!this->m_Windowed) {
|
||||
if (!GLContext::s_DesktopMode) {
|
||||
// TODO
|
||||
// Blizzard::Debug::Assert(
|
||||
// "s_DesktopMode",
|
||||
// "/Users/Shared/BuildServer/wow2.old/work/WoW-code/branches/wow-patch-3_3_5-BNet/WoW/Source/Mac/../../../"
|
||||
// "Engine/Source/Gx/CGxDeviceGLL/GLLayer/GLContext.cpp",
|
||||
// 215
|
||||
// );
|
||||
}
|
||||
|
||||
v15 = 1.25;
|
||||
v16 = false;
|
||||
CGDisplayFadeReservationToken v8 = 0;
|
||||
|
||||
CGError v7 = CGAcquireDisplayFadeReservation(2.25, &v17);
|
||||
|
||||
if (!v7) {
|
||||
v8 = v17;
|
||||
}
|
||||
|
||||
v17 = v8;
|
||||
|
||||
if (v8) {
|
||||
v16 = CGDisplayFade(v8, 0.25, 0, 1.0, 0, 0, 0, 1) == kCGErrorSuccess;
|
||||
}
|
||||
|
||||
CGDirectDisplayID v10 = CGMainDisplayID();
|
||||
CGDisplaySwitchToMode(v10, GLContext::s_DesktopMode);
|
||||
|
||||
this->m_Window->ExitFullscreenMode();
|
||||
|
||||
// TODO
|
||||
// SetSystemUIMode(0, 0);
|
||||
}
|
||||
|
||||
CGReleaseAllDisplays();
|
||||
}
|
||||
|
||||
if (a3) {
|
||||
this->m_Window->Show();
|
||||
}
|
||||
|
||||
this->m_Windowed = 1;
|
||||
CGDisplayRestoreColorSyncSettings();
|
||||
|
||||
if (v17) {
|
||||
if (v16) {
|
||||
float v6 = v15;
|
||||
|
||||
if (v15 > 1.0) {
|
||||
usleep(1000);
|
||||
v6 = v15 - 1.0;
|
||||
}
|
||||
|
||||
CGDisplayFade(v17, v6, 1.0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
CGReleaseDisplayFadeReservation(v17);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void GLContext::Swap() {
|
||||
[this->m_Context->context flushBuffer];
|
||||
}
|
||||
|
||||
void GLContext::Update() {
|
||||
[this->m_Context->context update];
|
||||
}
|
||||
8
src/gx/gll/GLDebugMipmap2D.h
Normal file
8
src/gx/gll/GLDebugMipmap2D.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef GX_GLL_GL_DEBUG_MIPMAP_2D_H
|
||||
#define GX_GLL_GL_DEBUG_MIPMAP_2D_H
|
||||
|
||||
class GLDebugMipmap2D {
|
||||
public:
|
||||
};
|
||||
|
||||
#endif
|
||||
2612
src/gx/gll/GLDevice.cpp
Normal file
2612
src/gx/gll/GLDevice.cpp
Normal file
File diff suppressed because it is too large
Load diff
191
src/gx/gll/GLDevice.h
Normal file
191
src/gx/gll/GLDevice.h
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
#ifndef GX_GLL_GL_DEVICE_H
|
||||
#define GX_GLL_GL_DEVICE_H
|
||||
|
||||
#include "gx/gll/GL.h"
|
||||
#include "gx/gll/GLAbstractWindow.h"
|
||||
#include "gx/gll/GLBatch.h"
|
||||
#include "gx/gll/GLBufferPool.h"
|
||||
#include "gx/gll/GLContext.h"
|
||||
#include "gx/gll/GLDebugMipmap2D.h"
|
||||
#include "gx/gll/GLFramebuffer.h"
|
||||
#include "gx/gll/GLGLSLProgram.h"
|
||||
#include "gx/gll/GLMipmap.h"
|
||||
#include "gx/gll/GLShader.h"
|
||||
#include "gx/gll/GLTexture.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
#include "gx/gll/GLVertexArray.h"
|
||||
#include "gx/gll/GLWorker.h"
|
||||
#include "util/BlizzardCore.hpp"
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class GLDevice {
|
||||
public:
|
||||
// Types
|
||||
enum GLDeviceOption {
|
||||
eUseMTGL = 0,
|
||||
eUseVertexArray = 1,
|
||||
eUseGLSL = 2,
|
||||
eCheckGLStates = 3,
|
||||
eFlushBeforeDraw = 4,
|
||||
eDeviceOption5 = 5,
|
||||
eUseHybridShader = 6,
|
||||
eDeviceOption7 = 7,
|
||||
eDeviceOption8 = 8,
|
||||
eShaderConstantBindings = 9
|
||||
};
|
||||
|
||||
struct RendererInfo {
|
||||
uint8_t init = 0;
|
||||
uint32_t vendor_id;
|
||||
uint32_t renderer_id;
|
||||
uint32_t max_color_attachments;
|
||||
uint32_t unk36; // max clip planes
|
||||
uint32_t unk100;
|
||||
};
|
||||
|
||||
// Static variables
|
||||
static Blizzard::Thread::TLSSlot m_CurrentDevice;
|
||||
static std::vector<GLDevice *, std::allocator<GLDevice*>> m_Devices;
|
||||
static bool m_ExtARBShadow;
|
||||
static bool m_ExtColorMaskIndexed;
|
||||
static RendererInfo m_RendererInfo;
|
||||
static bool m_ShaderConstantBindings;
|
||||
static int32_t m_StaticResourcesRefCount;
|
||||
static bool m_UseHybridShader;
|
||||
static GLBuffer* m_BlitQuadVBO;
|
||||
static GLShader* m_DeviceShaders[];
|
||||
static GLTexture* m_DeviceTextures[];
|
||||
static GLVertexFormat m_NormalBlitVF;
|
||||
static GLVertexFormat m_InvertedBlitVF;
|
||||
static GLFramebuffer* m_F8330C;
|
||||
|
||||
// Static functions
|
||||
static GLDevice* Get(void);
|
||||
static void Set(GLDevice*);
|
||||
static void InitPools(void);
|
||||
static RendererInfo GetRendererInfo(void);
|
||||
static void InitRendererInfo(void);
|
||||
static void SetOption(GLDeviceOption, bool);
|
||||
static void StaticInit(void);
|
||||
|
||||
// Member variables
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char>> m_DebugName;
|
||||
GLStates m_States;
|
||||
GLTexture* m_Textures[16] = {};
|
||||
GLShader* m_PixelShader = nullptr;
|
||||
GLShader* m_VertexShader = nullptr;
|
||||
GLGLSLProgram* m_GLSLProgram = nullptr;
|
||||
GLVertexArray* m_VertexArrayObject = &m_DefaultVertexArrayObject;
|
||||
GLFramebuffer* m_SystemTarget = nullptr;
|
||||
GLFramebuffer* m_FBOTarget = nullptr;
|
||||
GLFramebuffer* m_CurrentTarget = nullptr;
|
||||
GLMipmap* m_CurrentTargetColor[4] = {};
|
||||
GLMipmap* m_CurrentTargetDepth = nullptr;
|
||||
GLMipmap* m_CurrentTargetStencil = nullptr;
|
||||
GLMipmap* m_CurrentDepthBuffer = nullptr;
|
||||
GLTexture2D* m_BackBufferColor = nullptr;
|
||||
GLTexture2D* m_BackBufferDepth = nullptr;
|
||||
GLTexture2D* m_BackBufferStencil = nullptr;
|
||||
GLContext m_Context;
|
||||
GLBufferPool* m_PBOPool = nullptr;
|
||||
GLWorker* m_TexWorker = nullptr;
|
||||
GLTexture* m_BoundTextures[4][16] = {};
|
||||
GLVertexArray m_DefaultVertexArrayObject;
|
||||
GLDirtyRange m_DirtyVertexShaderConsts;
|
||||
GLDirtyRange m_DirtyPixelShaderConsts;
|
||||
float m_ConstantDepthBias = 0.0f;
|
||||
float m_SlopeScaledDepthBias = 0.0f;
|
||||
bool m_Init = 0;
|
||||
uint32_t m_DrawCount = 0;
|
||||
uint32_t m_ID = -1;
|
||||
std::list<GLTexture*, std::allocator<GLTexture*>> m_TextureList;
|
||||
std::list<GLTexture*>::iterator m_OldestActiveTexture;
|
||||
uint32_t m_TextureTotalSize = 0;
|
||||
uint32_t m_FrameNumber = 1;
|
||||
std::list<GLDebugMipmap2D*, std::allocator<GLDebugMipmap2D*>> m_DebugMipmaps;
|
||||
bool m_BatchViewerEnabled = 0;
|
||||
bool m_UseWindowSystemBuffer = 0;
|
||||
bool m_FlippedSystemBuffer = 0;
|
||||
bool m_ShaderCompiler = 0;
|
||||
bool m_WorkerDevice;
|
||||
GLStates m_DefaultStates;
|
||||
std::vector<GLBatch, std::allocator<GLBatch>>* m_FrameBatches;
|
||||
bool m_CaptureOnlyOneFrame = 0;
|
||||
bool m_StopCapturingBatches = 0;
|
||||
bool m_CaptureBatches = 0;
|
||||
int32_t m_IndentLevel = 0;
|
||||
GLAbstractWindow* m_FirstCapturedWindow = nullptr;
|
||||
|
||||
// Member functions
|
||||
GLDevice();
|
||||
void ApplyGLBindings(const GLStates&, bool);
|
||||
void ApplyGLStates(const GLStates&, bool);
|
||||
void ApplyShaderConstants(void);
|
||||
void ApplyTransforms(void);
|
||||
void BindBuffer(GLBuffer*, GLEnum);
|
||||
void BindFramebuffer(GLFramebuffer*);
|
||||
void BindGLSLProgram(GLGLSLProgram*);
|
||||
void BindShader(GLShader*);
|
||||
void BindTexture(GLEnum, GLTexture*);
|
||||
void BindVertexArray(GLVertexArray*);
|
||||
void BlitFramebuffer(GLMipmap*, const GLRect*, GLMipmap*, const GLRect*, GLEnum, GLEnum);
|
||||
void CheckDepthTarget(void);
|
||||
void Clear(uint32_t, const GLColor4f&, double, int32_t);
|
||||
void CopyTex(uint32_t, uint32_t, GLMipmap*, const GLRect*);
|
||||
GLBuffer* CreateBuffer(GLEnum, uint32_t, const void*, GLEnum, GLEnum);
|
||||
GLShader* CreateShader(GLShader::ShaderType, const void*, int32_t, const char*);
|
||||
GLTexture* CreateTexture2D(uint32_t, uint32_t, uint32_t, GLTextureFormat, uint32_t);
|
||||
GLTexture* CreateTextureCubeMap(uint32_t, uint32_t, GLTextureFormat, uint32_t);
|
||||
void Draw(GLEnum, uint32_t, uint32_t);
|
||||
void DrawIndexed(GLEnum, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
|
||||
void DrawRect(void);
|
||||
GLFramebuffer* GetCurrentTarget(void); // invented name
|
||||
uint32_t GetID(void);
|
||||
GLShader* GetShader(GLShader::ShaderType);
|
||||
const GLStates::VertexArrayObject& GetVertexArrayStates();
|
||||
void GLLDraw(GLEnum, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
|
||||
void Init(GLAbstractWindow*, const char*, uint32_t, GLTextureFormat);
|
||||
void LoadDefaultStates(void);
|
||||
void ResetBackbuffer(uint32_t width, uint32_t height, GLTextureFormat colorFormat, GLTextureFormat depthFormat, uint32_t sampleCount);
|
||||
void Resize(uint32_t width, uint32_t height);
|
||||
void RestoreTextures(void);
|
||||
void SetActiveTexture(uint32_t);
|
||||
void SetAlphaBlend(GLEnum, GLEnum, GLEnum);
|
||||
void SetAlphaBlendEnable(bool);
|
||||
void SetAlphaTest(GLEnum, float);
|
||||
void SetAlphaTestEnable(bool);
|
||||
void SetClearColor(const GLColor4f&);
|
||||
void SetClearDepth(double);
|
||||
void SetClearStencil(int32_t);
|
||||
void SetColorWriteMask(bool red, bool green, bool blue, bool alpha, uint32_t index);
|
||||
void SetCullMode(GLEnum);
|
||||
void SetDepthBias(float constantBias, float slopeScaledBias);
|
||||
void SetDepthTestEnable(bool);
|
||||
void SetDepthTestFunc(GLEnum);
|
||||
void SetDepthWriteMask(bool);
|
||||
void SetDisplay(uint32_t, uint32_t, GLTextureFormat, GLTextureFormat, uint32_t, bool, bool, uint32_t);
|
||||
void SetFogColor(float r, float g, float b, float a);
|
||||
void SetFogEnable(bool enable);
|
||||
void SetFogParam(GLEnum param, float value);
|
||||
void SetIndexBuffer(GLBuffer*);
|
||||
void SetLightingEnable(bool enable);
|
||||
void SetScissor(bool, const GLRect&);
|
||||
void SetShader(GLShader::ShaderType, GLShader*);
|
||||
void SetShaderConstants(GLShader::ShaderType, uint32_t, const float*, uint32_t);
|
||||
void SetShaderConstantsInternal(GLShader::ShaderType, uint32_t, const float*, uint32_t);
|
||||
void SetTexture(uint32_t, GLTexture*);
|
||||
void SetTransform(GLEnum, const float*);
|
||||
void SetUnpackClientStorage(bool);
|
||||
void SetVertexBuffer(uint32_t, GLBuffer*, uint32_t, uint32_t);
|
||||
void SetVertexFormat(GLVertexFormat*);
|
||||
void SetViewport(const GLRect&, double, double);
|
||||
void Sub34BB0(GLEnum a2, GLMipmap* a3, uint32_t index);
|
||||
void Sub38460(bool);
|
||||
void Swap(void);
|
||||
void UpdateFFPTexturing(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
149
src/gx/gll/GLFramebuffer.cpp
Normal file
149
src/gx/gll/GLFramebuffer.cpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#include "gx/gll/GLFramebuffer.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLMipmap.h"
|
||||
#include "gx/gll/GLPool.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
|
||||
GLFramebuffer* GLFramebuffer::Create(bool a1) {
|
||||
GLFramebuffer* framebuffer = new GLFramebuffer(a1);
|
||||
|
||||
if (!a1) {
|
||||
// TODO
|
||||
// BLIZZARD_ASSERT(framebuffer->m_FramebufferID >= PoolStats<GLFramebuffer>::NAME_POOL_FIRST_NAME);
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT(framebuffer->m_NumAttach == 0);
|
||||
|
||||
framebuffer->m_Width = 0;
|
||||
framebuffer->m_Height = 0;
|
||||
framebuffer->m_Device = GLDevice::Get();
|
||||
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
GLFramebuffer::GLFramebuffer(bool a1) : GLObject() {
|
||||
if (!a1) {
|
||||
this->m_FramebufferID = GLPool<GLFramebuffer>::Get()->GetNextName();
|
||||
}
|
||||
}
|
||||
|
||||
void GLFramebuffer::Attach(GLMipmap* image, GLenum a3, int32_t a4) {
|
||||
BLIZZARD_ASSERT(this->m_Device == GLDevice::Get());
|
||||
|
||||
if (!image) {
|
||||
this->Detach(a3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a3 == GL_DEPTH_STENCIL) {
|
||||
BLIZZARD_ASSERT(image->GetFormat() == GLTF_D24S8);
|
||||
|
||||
this->Attach(image, GL_DEPTH_ATTACHMENT, 0);
|
||||
this->Attach(image, GL_STENCIL_ATTACHMENT, 0);
|
||||
|
||||
(*image->m_AttachPoints)[this->m_FramebufferID].point = GL_DEPTH_STENCIL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t index;
|
||||
|
||||
if (a3 == GL_DEPTH_ATTACHMENT) {
|
||||
index = 4;
|
||||
} else if (a3 == GL_STENCIL_ATTACHMENT) {
|
||||
index = 5;
|
||||
} else {
|
||||
index = a3 - GL_COLOR_ATTACHMENT0;
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT(index < MAX_ATTACHMENT);
|
||||
|
||||
GLMipmap* oldImage = this->m_Attachments[index];
|
||||
|
||||
if (image != oldImage) {
|
||||
if (oldImage) {
|
||||
oldImage->Detach(this, a3, true);
|
||||
} else {
|
||||
++this->m_NumAttach;
|
||||
}
|
||||
|
||||
this->m_Attachments[index] = image;
|
||||
|
||||
this->m_Width = image->m_Width;
|
||||
this->m_Height = image->m_Height;
|
||||
|
||||
image->Attach(this, a3, a4);
|
||||
this->m_Device->Sub38460(0);
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT((*image->m_AttachPoints)[m_FramebufferID].framebuffer == this);
|
||||
}
|
||||
|
||||
void GLFramebuffer::Detach(GLenum a2) {
|
||||
int32_t v2 = a2;
|
||||
int32_t index;
|
||||
|
||||
if (a2 == GL_DEPTH_STENCIL) {
|
||||
index = 5;
|
||||
v2 = GL_STENCIL_ATTACHMENT;
|
||||
this->Detach(GL_DEPTH_ATTACHMENT);
|
||||
} else if (a2 == GL_DEPTH_ATTACHMENT) {
|
||||
index = 4;
|
||||
} else if (a2 == GL_STENCIL_ATTACHMENT) {
|
||||
index = 5;
|
||||
} else {
|
||||
index = a2 - GL_COLOR_ATTACHMENT0;
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT(index < MAX_ATTACHMENT);
|
||||
|
||||
GLMipmap* oldImage = this->m_Attachments[index];
|
||||
|
||||
if (oldImage) {
|
||||
oldImage->Detach(this, v2, 0);
|
||||
|
||||
--this->m_NumAttach;
|
||||
|
||||
this->m_Attachments[index] = 0;
|
||||
|
||||
if (this->m_Device == GLDevice::Get()) {
|
||||
this->m_Device->Sub38460(0);
|
||||
}
|
||||
|
||||
if (this->m_NumAttach == 0) {
|
||||
this->m_Width = 0;
|
||||
this->m_Height = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLMipmap* GLFramebuffer::GetAttachment(GLEnum a2) {
|
||||
int32_t index;
|
||||
|
||||
if (a2 == GL_DEPTH_ATTACHMENT) {
|
||||
index = 4;
|
||||
} else if (a2 == GL_STENCIL_ATTACHMENT) {
|
||||
index = 5;
|
||||
} else {
|
||||
index = a2 - GL_COLOR_ATTACHMENT0;
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT(index < MAX_ATTACHMENT);
|
||||
|
||||
return this->m_Attachments[index];
|
||||
}
|
||||
|
||||
int32_t GLFramebuffer::GetSampleCount() {
|
||||
return this->m_FramebufferID
|
||||
? 1
|
||||
: this->m_Device->m_Context.m_Context->sampleCount;
|
||||
}
|
||||
|
||||
bool GLFramebuffer::IsValid() {
|
||||
auto status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
|
||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||
}
|
||||
|
||||
void GLFramebuffer::ReleaseObject() {
|
||||
// TODO
|
||||
}
|
||||
38
src/gx/gll/GLFramebuffer.h
Normal file
38
src/gx/gll/GLFramebuffer.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef GX_GLL_GL_FRAMEBUFFER_H
|
||||
#define GX_GLL_GL_FRAMEBUFFER_H
|
||||
|
||||
#include "gx/gll/GL.h"
|
||||
#include "gx/gll/GLObject.h"
|
||||
#include <cstdint>
|
||||
|
||||
#define MAX_ATTACHMENT 6
|
||||
|
||||
class GLDevice;
|
||||
class GLMipmap;
|
||||
|
||||
class GLFramebuffer : public GLObject {
|
||||
public:
|
||||
// Static functions
|
||||
static GLFramebuffer* Create(bool);
|
||||
|
||||
// Member variables
|
||||
int32_t m_Width = 0;
|
||||
int32_t m_Height = 0;
|
||||
uint32_t m_FramebufferID = 0;
|
||||
GLDevice* m_Device;
|
||||
GLMipmap* m_Attachments[6] = {};
|
||||
uint32_t m_NumAttach = 0;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ReleaseObject();
|
||||
|
||||
// Member functions
|
||||
GLFramebuffer(bool);
|
||||
void Attach(GLMipmap*, GLenum, int32_t);
|
||||
void Detach(GLenum);
|
||||
GLMipmap* GetAttachment(GLEnum);
|
||||
int32_t GetSampleCount(void);
|
||||
bool IsValid();
|
||||
};
|
||||
|
||||
#endif
|
||||
7
src/gx/gll/GLGLSLProgram.cpp
Normal file
7
src/gx/gll/GLGLSLProgram.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include "gx/gll/GLGLSLProgram.h"
|
||||
#include "gx/gll/GLShader.h"
|
||||
|
||||
GLGLSLProgram* GLGLSLProgram::Find(GLShader* a1, GLShader* a2) {
|
||||
// TODO
|
||||
return nullptr;
|
||||
}
|
||||
14
src/gx/gll/GLGLSLProgram.h
Normal file
14
src/gx/gll/GLGLSLProgram.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef GX_GLL_GL_GLSL_PROGRAM_H
|
||||
#define GX_GLL_GL_GLSL_PROGRAM_H
|
||||
|
||||
#include "gx/gll/GLObject.h"
|
||||
|
||||
class GLShader;
|
||||
|
||||
class GLGLSLProgram : public GLObject {
|
||||
public:
|
||||
// Static functions
|
||||
static GLGLSLProgram* Find(GLShader*, GLShader*);
|
||||
};
|
||||
|
||||
#endif
|
||||
39
src/gx/gll/GLLayerView.h
Normal file
39
src/gx/gll/GLLayerView.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef GX_GLL_GL_LAYER_VIEW_H
|
||||
#define GX_GLL_GL_LAYER_VIEW_H
|
||||
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
class GLWindow;
|
||||
|
||||
@interface GLLayerView : NSView <NSWindowDelegate>
|
||||
|
||||
@property CGDirectDisplayID m_display;
|
||||
@property GLWindow* m_GLWindow;
|
||||
@property (retain) NSOpenGLContext* m_savedContext;
|
||||
@property (retain) NSCursor* m_cursor;
|
||||
|
||||
- (BOOL)acceptsFirstResponder;
|
||||
- (void)drawRect:(NSRect)dirtyRect;
|
||||
- (id)initWithFrame:(NSRect)frame glWindow:(GLWindow*)window;
|
||||
- (void)keyDown:(NSEvent*)event;
|
||||
- (void)keyUp:(NSEvent*)event;
|
||||
- (void)mouseDown:(NSEvent*)event;
|
||||
- (void)mouseDragged:(NSEvent*)event;
|
||||
- (void)mouseMoved:(NSEvent*)event;
|
||||
- (void)mouseUp:(NSEvent*)event;
|
||||
- (void)otherMouseDown:(NSEvent*)event;
|
||||
- (void)otherMouseDragged:(NSEvent*)event;
|
||||
- (void)otherMouseUp:(NSEvent*)event;
|
||||
- (void)rightMouseDown:(NSEvent*)event;
|
||||
- (void)rightMouseDragged:(NSEvent*)event;
|
||||
- (void)rightMouseUp:(NSEvent*)event;
|
||||
- (void)scrollWheel:(NSEvent*)event;
|
||||
- (void)viewDidChangeBackingProperties;
|
||||
- (void)viewDidEndLiveResize;
|
||||
- (void)update;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
179
src/gx/gll/GLLayerView.mm
Normal file
179
src/gx/gll/GLLayerView.mm
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#include "gx/gll/GLLayerView.h"
|
||||
#include "gx/gll/GLContext.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLWindow.h"
|
||||
#include <cmath>
|
||||
|
||||
@implementation GLLayerView
|
||||
|
||||
- (BOOL)acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (GLWindowCallbacks*)callbacks {
|
||||
if (self.m_GLWindow) {
|
||||
return self.m_GLWindow->m_ActiveCallbacks;
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
GLContext* context = self.m_GLWindow->m_Context;
|
||||
|
||||
if (context && context->m_Device) {
|
||||
context->m_Device->DrawRect();
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(NSRect)frame glWindow:(GLWindow*)window {
|
||||
self = [super initWithFrame:frame];
|
||||
[self setWantsBestResolutionOpenGLSurface:YES];
|
||||
|
||||
if (self) {
|
||||
[self setGLWindow:window];
|
||||
}
|
||||
|
||||
CGSetLocalEventsSuppressionInterval(0.0);
|
||||
|
||||
self.m_display = [self findMyDisplay];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setGLWindow:(GLWindow*)window {
|
||||
self.m_GLWindow = window;
|
||||
}
|
||||
|
||||
- (CGDirectDisplayID)findMyDisplay {
|
||||
NSRect frame = self.frame;
|
||||
|
||||
uint32_t displayCount;
|
||||
CGDirectDisplayID displays[1];
|
||||
|
||||
CGGetDisplaysWithPoint(frame.origin, 1, displays, &displayCount);
|
||||
|
||||
if (displayCount) {
|
||||
return displays[0];
|
||||
} else {
|
||||
return CGMainDisplayID();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent*)event {
|
||||
[self callbacks]->OnKeyDown(event);
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent*)event {
|
||||
[self callbacks]->OnKeyUp(event);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)event {
|
||||
NSPoint location = event.locationInWindow;
|
||||
NSRect frame = self.frame;
|
||||
|
||||
float x = location.x;
|
||||
float y = frame.size.height - location.y;
|
||||
|
||||
NSInteger buttonNumber = event.buttonNumber;
|
||||
|
||||
[self callbacks]->OnMouseDown(
|
||||
buttonNumber,
|
||||
static_cast<int32_t>(floor(x)),
|
||||
static_cast<int32_t>(floor(y))
|
||||
);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent*)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent*)event {
|
||||
float v20 = 0.0;
|
||||
float v21 = 0.0;
|
||||
|
||||
// TODO
|
||||
// - logic to handle fullscreen mouse movement
|
||||
|
||||
NSPoint location = event.locationInWindow;
|
||||
NSRect frame = self.frame;
|
||||
|
||||
float x = location.x + v21;
|
||||
float y = (frame.size.height - location.y) + v20;
|
||||
|
||||
[self callbacks]->OnMouseMoved(
|
||||
static_cast<int32_t>(floor(x)),
|
||||
static_cast<int32_t>(floor(y))
|
||||
);
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent*)event {
|
||||
NSPoint location = event.locationInWindow;
|
||||
NSRect frame = self.frame;
|
||||
|
||||
float x = location.x;
|
||||
float y = frame.size.height - location.y;
|
||||
|
||||
NSInteger buttonNumber = event.buttonNumber;
|
||||
|
||||
[self callbacks]->OnMouseUp(
|
||||
buttonNumber,
|
||||
static_cast<int32_t>(floor(x)),
|
||||
static_cast<int32_t>(floor(y))
|
||||
);
|
||||
}
|
||||
|
||||
- (void)otherMouseDown:(NSEvent*)event {
|
||||
[self mouseDown:event];
|
||||
}
|
||||
|
||||
- (void)otherMouseDragged:(NSEvent*)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)otherMouseUp:(NSEvent*)event {
|
||||
[self mouseUp:event];
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent*)event {
|
||||
[self mouseDown:event];
|
||||
}
|
||||
|
||||
- (void)rightMouseDragged:(NSEvent*)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)rightMouseUp:(NSEvent*)event {
|
||||
[self mouseUp:event];
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent*)event {
|
||||
// TODO
|
||||
}
|
||||
|
||||
- (void)viewDidChangeBackingProperties {
|
||||
[self update];
|
||||
}
|
||||
|
||||
- (void)viewDidEndLiveResize {
|
||||
int32_t width = std::floor(self.frame.size.width);
|
||||
int32_t height = std::floor(self.frame.size.height);
|
||||
|
||||
[self update];
|
||||
|
||||
[self callbacks]->OnResized(
|
||||
width,
|
||||
height,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
- (void)update {
|
||||
self.m_display = [self findMyDisplay];
|
||||
|
||||
if (self.m_GLWindow->m_Context) {
|
||||
self.m_GLWindow->m_Context->Update();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
492
src/gx/gll/GLMipmap.cpp
Normal file
492
src/gx/gll/GLMipmap.cpp
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
#include "gx/gll/GLMipmap.h"
|
||||
#include "gx/gll/GLCommand.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLFramebuffer.h"
|
||||
|
||||
int32_t GLMipmap::GetDepthBits() {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GLMipmap::Attach(GLFramebuffer* framebuffer, GLenum attachPoint, int32_t a4) {
|
||||
if (!this->m_AttachPoints) {
|
||||
this->m_AttachPoints = new std::vector<GLAttachPoint>();
|
||||
}
|
||||
|
||||
auto& attachPoints = *this->m_AttachPoints;
|
||||
auto framebufferID = framebuffer->m_FramebufferID;
|
||||
|
||||
if (framebufferID >= attachPoints.size()) {
|
||||
attachPoints.resize(framebufferID + 1);
|
||||
} else {
|
||||
BLIZZARD_ASSERT(attachPoints[framebufferID].framebuffer != framebuffer || attachPoints[framebufferID].point != attachPoint);
|
||||
|
||||
auto& attach = attachPoints[framebufferID];
|
||||
|
||||
if (
|
||||
attach.point
|
||||
&& (attach.point != GL_DEPTH_ATTACHMENT || attachPoint != GL_STENCIL_ATTACHMENT)
|
||||
&& (attach.point != GL_STENCIL_ATTACHMENT || attachPoint != GL_DEPTH_ATTACHMENT)
|
||||
) {
|
||||
framebuffer->Detach(attach.point);
|
||||
}
|
||||
}
|
||||
|
||||
GLDevice* device = GLDevice::Get();
|
||||
|
||||
auto currentTarget = device->GetCurrentTarget();
|
||||
device->BindFramebuffer(framebuffer);
|
||||
|
||||
if (framebufferID) {
|
||||
if (this->m_Target == GL_TEXTURE_3D) {
|
||||
glFramebufferTexture3DEXT(
|
||||
GL_FRAMEBUFFER,
|
||||
attachPoint,
|
||||
GL_TEXTURE_3D,
|
||||
this->m_Texture->m_TextureID,
|
||||
this->m_Level,
|
||||
a4
|
||||
);
|
||||
} else {
|
||||
glFramebufferTexture2DEXT(
|
||||
GL_FRAMEBUFFER,
|
||||
attachPoint,
|
||||
this->m_Target,
|
||||
this->m_Texture->m_TextureID,
|
||||
this->m_Level
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (attachPoint == GL_DEPTH_ATTACHMENT && !this->m_DepthBits) {
|
||||
GLint depthBits = 0;
|
||||
glGetIntegerv(GL_DEPTH_BITS, &depthBits);
|
||||
this->m_DepthBits = depthBits;
|
||||
}
|
||||
|
||||
device->BindFramebuffer(currentTarget);
|
||||
|
||||
auto& attach = attachPoints[framebufferID];
|
||||
attach.framebuffer = framebuffer;
|
||||
attach.zOffset = a4;
|
||||
|
||||
if (
|
||||
(attach.point != GL_DEPTH_ATTACHMENT || attachPoint != GL_STENCIL_ATTACHMENT)
|
||||
&& (attach.point != GL_STENCIL_ATTACHMENT || attachPoint != GL_DEPTH_ATTACHMENT)
|
||||
) {
|
||||
attach.point = attachPoint;
|
||||
} else {
|
||||
attach.point = GL_DEPTH_STENCIL;
|
||||
}
|
||||
}
|
||||
|
||||
void GLMipmap::Detach(GLFramebuffer* framebuffer, GLenum attachPoint, bool a4) {
|
||||
GLuint framebufferID = framebuffer->m_FramebufferID;
|
||||
|
||||
auto& attachPoints = *this->m_AttachPoints;
|
||||
|
||||
BLIZZARD_ASSERT(attachPoints.size() >= framebufferID);
|
||||
BLIZZARD_ASSERT(attachPoints[framebufferID].framebuffer == framebuffer);
|
||||
|
||||
if (!a4 && framebufferID) {
|
||||
GLDevice* v12 = GLDevice::Get();
|
||||
GLFramebuffer* v14 = v12->GetCurrentTarget();
|
||||
v12->BindFramebuffer(framebuffer);
|
||||
|
||||
if (this->m_Target == GL_TEXTURE_3D) {
|
||||
glFramebufferTexture3DEXT(GL_FRAMEBUFFER, attachPoint, GL_TEXTURE_3D, 0, 0, 0);
|
||||
} else {
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, attachPoint, this->m_Target, 0, 0);
|
||||
}
|
||||
|
||||
v12->BindFramebuffer(v14);
|
||||
}
|
||||
|
||||
GLAttachPoint* v9 = &attachPoints[framebufferID];
|
||||
|
||||
if (v9->point == GL_DEPTH_STENCIL) {
|
||||
BLIZZARD_ASSERT(this->GetFormat() == GLTF_D24S8);
|
||||
|
||||
if (attachPoint == GL_DEPTH_ATTACHMENT) {
|
||||
v9->point = GL_STENCIL_ATTACHMENT;
|
||||
} else if (attachPoint == GL_STENCIL_ATTACHMENT) {
|
||||
v9->point = GL_DEPTH_ATTACHMENT;
|
||||
} else {
|
||||
BLIZZARD_ASSERT(false);
|
||||
}
|
||||
} else {
|
||||
BLIZZARD_ASSERT(attachPoints[framebufferID].point == attachPoint);
|
||||
|
||||
v9->framebuffer = 0;
|
||||
v9->point = 0;
|
||||
v9->zOffset = 0;
|
||||
|
||||
// TODO
|
||||
// this->m_Texture->m_TimeStamp = Blizzard::Time::GetTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
void GLMipmap::DetachAll() {
|
||||
if (!this->m_AttachPoints) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& attachPoints = *this->m_AttachPoints;
|
||||
for (int32_t i = 0; i < attachPoints.size(); i++) {
|
||||
BLIZZARD_ASSERT(attachPoints[i].point != GL_ZERO);
|
||||
BLIZZARD_ASSERT(attachPoints[i].framebuffer->m_FramebufferID == i);
|
||||
|
||||
attachPoints[i].framebuffer->Detach(attachPoints[i].point);
|
||||
}
|
||||
}
|
||||
|
||||
GLTextureFormat GLMipmap::GetFormat() {
|
||||
return this->m_Texture->GetFormat();
|
||||
}
|
||||
|
||||
TextureFormatInfo& GLMipmap::GetFormatInfo() {
|
||||
return this->m_Texture->GetFormatInfo();
|
||||
};
|
||||
|
||||
uint16_t GLMipmap::GetHeight() {
|
||||
return this->m_Height;
|
||||
}
|
||||
|
||||
int32_t GLMipmap::GetPitch() {
|
||||
int32_t bpp = this->GetFormatInfo().m_BytePerPixel;
|
||||
int32_t v4 = this->m_Texture->var12 >> this->m_Level;
|
||||
return v4 >= bpp ? v4 : bpp;
|
||||
}
|
||||
|
||||
GLTexture* GLMipmap::GetTexture() {
|
||||
return this->m_Texture;
|
||||
}
|
||||
|
||||
uint32_t GLMipmap::GetTextureID() {
|
||||
return this->m_Texture->m_TextureID;
|
||||
}
|
||||
|
||||
uint16_t GLMipmap::GetWidth() {
|
||||
return this->m_Width;
|
||||
}
|
||||
|
||||
void* GLMipmap::Map(GLEnum mode, const GLBox* area) {
|
||||
BLIZZARD_ASSERT(!this->m_Texture->IsSystemBuffer());
|
||||
BLIZZARD_ASSERT(this->m_Data != nullptr);
|
||||
BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget());
|
||||
BLIZZARD_ASSERT(mode != GL_ZERO);
|
||||
BLIZZARD_ASSERT(this->m_MapParams == nullptr);
|
||||
|
||||
if (mode != GL_READ_ONLY) {
|
||||
this->m_Texture->m_MappedMipmaps++;
|
||||
}
|
||||
|
||||
MapParams* mapParams = new MapParams();
|
||||
this->m_MapParams = mapParams;
|
||||
|
||||
if (area) {
|
||||
BLIZZARD_ASSERT(area->width > 0);
|
||||
BLIZZARD_ASSERT(area->height > 0);
|
||||
BLIZZARD_ASSERT(area->depth > 0);
|
||||
BLIZZARD_ASSERT(!this->GetFormatInfo().m_IsCompressed || ((area->top & 0x3) == 0 && (area->left & 0x3) == 0 && (area->width & 0x3) == 0 && (area->height & 0x3) == 0));
|
||||
BLIZZARD_ASSERT((area->height + area->top) <= this->m_Height);
|
||||
BLIZZARD_ASSERT((area->depth + area->front) <= this->m_Depth);
|
||||
BLIZZARD_ASSERT((area->width + area->left) <= this->m_Width);
|
||||
|
||||
mapParams->m_MapArea = {
|
||||
area->left,
|
||||
area->top,
|
||||
area->front,
|
||||
area->width,
|
||||
area->height,
|
||||
area->depth
|
||||
};
|
||||
|
||||
int32_t size = this->GetFormatInfo().m_BytePerPixel
|
||||
* this->m_Width
|
||||
* mapParams->m_MapArea.depth
|
||||
* mapParams->m_MapArea.height;
|
||||
|
||||
mapParams->m_Size = this->GetFormatInfo().m_IsCompressed
|
||||
? size >> 4
|
||||
: size;
|
||||
|
||||
mapParams->m_Unk7 = (this->GetFormatInfo().m_BytePerPixel * mapParams->m_MapArea.left)
|
||||
>> this->GetFormatInfo().m_IsCompressed ? 2 : 0;
|
||||
} else {
|
||||
mapParams->m_MapArea = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
this->m_Width,
|
||||
this->m_Height,
|
||||
this->m_Depth
|
||||
};
|
||||
|
||||
mapParams->m_Size = this->m_Size;
|
||||
|
||||
mapParams->m_Unk7 = 0;
|
||||
}
|
||||
|
||||
mapParams->m_MapMode = mode;
|
||||
|
||||
int32_t rowPitch = this->GetPitch();
|
||||
|
||||
BLIZZARD_ASSERT(((mapParams->m_MapArea.top * rowPitch) + mapParams->m_MapArea.left * this->GetFormatInfo().m_BytePerPixel) < (this->GetFormatInfo().m_IsCompressed ? this->m_Size << 4 : this->m_Size));
|
||||
|
||||
int32_t v22 = rowPitch * this->m_Height;
|
||||
if (this->GetFormatInfo().m_IsCompressed) {
|
||||
v22 >>= 2;
|
||||
}
|
||||
|
||||
unsigned char* v24 = this->m_Data
|
||||
+ ((mapParams->m_MapArea.top * rowPitch) >> (this->GetFormatInfo().m_IsCompressed ? 2 : 0))
|
||||
+ (mapParams->m_MapArea.front * v22);
|
||||
|
||||
mapParams->m_Unk8 = v24;
|
||||
|
||||
return v24 + mapParams->m_Unk7;
|
||||
}
|
||||
|
||||
void* GLMipmap::Map(GLEnum mode, const GLRect* rect) {
|
||||
if (rect) {
|
||||
GLBox area = {
|
||||
rect->left,
|
||||
rect->top,
|
||||
0,
|
||||
rect->width,
|
||||
rect->height,
|
||||
1
|
||||
};
|
||||
|
||||
return this->Map(mode, &area);
|
||||
} else {
|
||||
return this->Map(mode, static_cast<GLBox*>(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
void GLMipmap::ReleaseObject() {
|
||||
BLIZZARD_ASSERT(this->m_MapParams == nullptr);
|
||||
|
||||
this->RemoveDebugMipmap();
|
||||
this->DetachAll();
|
||||
|
||||
if (this->m_AttachPoints) {
|
||||
delete this->m_AttachPoints;
|
||||
}
|
||||
|
||||
this->m_AttachPoints = nullptr;
|
||||
this->m_Unk24 = 0;
|
||||
}
|
||||
|
||||
void GLMipmap::RemoveDebugMipmap() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GLMipmap::ResetData(GLEnum target, int32_t level, unsigned char* data) {
|
||||
BLIZZARD_ASSERT(this->m_Target != GL_TEXTURE_3D || !this->GetFormatInfo().m_IsCompressed);
|
||||
|
||||
this->m_Target = target;
|
||||
this->m_Level = level;
|
||||
this->m_Data = data;
|
||||
|
||||
BLIZZARD_ASSERT(this->GetFormat() != GLTF_INVALID);
|
||||
BLIZZARD_ASSERT(this->GetFormat() < GLTF_NUM_TEXTURE_FORMATS);
|
||||
|
||||
if (!this->m_Texture->IsSystemBuffer() && this->m_Texture->IsRenderTarget()) {
|
||||
BLIZZARD_ASSERT(!this->GetFormatInfo().m_IsCompressed);
|
||||
|
||||
this->TexImage(nullptr);
|
||||
this->m_Unk24 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GLMipmap::ResetSize(uint32_t width, uint32_t height, uint32_t depth) {
|
||||
this->m_Width = width ? width : 1;
|
||||
this->m_Height = height ? height : 1;
|
||||
this->m_Depth = depth ? depth : 1;
|
||||
|
||||
if (this->GetFormatInfo().m_IsCompressed) {
|
||||
BLIZZARD_ASSERT(this->m_Depth == 1);
|
||||
|
||||
this->m_Width = (this->m_Width + 3) & 0xFFFC;
|
||||
this->m_Height = (this->m_Height + 3) & 0xFFFC;
|
||||
}
|
||||
|
||||
uint32_t v11 = this->GetFormatInfo().m_BytePerPixel;
|
||||
uint32_t v20 = this->m_Texture->var12 >> this->m_Level;
|
||||
|
||||
if (v20 >= v11) {
|
||||
v11 = v20;
|
||||
}
|
||||
|
||||
uint32_t v15 = v11 * this->m_Height;
|
||||
uint32_t v12;
|
||||
|
||||
if (this->GetFormatInfo().m_IsCompressed) {
|
||||
v12 = v15 >> 2;
|
||||
} else {
|
||||
v12 = v15;
|
||||
}
|
||||
|
||||
this->m_Size = this->m_Depth * v12;
|
||||
}
|
||||
|
||||
void GLMipmap::TexImage(const void* pixels) {
|
||||
BLIZZARD_ASSERT((this->m_Texture->IsRenderTarget() || pixels != nullptr) && GLDevice::Get()->GetVertexArrayStates().buffers[eGLBT_PIXEL_UNPACK] == 0);
|
||||
|
||||
if (this->m_Target == GL_TEXTURE_3D) {
|
||||
glTexImage3D(
|
||||
GL_TEXTURE_3D,
|
||||
this->m_Level,
|
||||
this->GetFormatInfo().m_InternalFormat,
|
||||
this->m_Width,
|
||||
this->m_Height,
|
||||
this->m_Depth,
|
||||
0,
|
||||
this->GetFormatInfo().m_DataFormat,
|
||||
this->GetFormatInfo().m_DataType,
|
||||
pixels
|
||||
);
|
||||
} else if (this->GetFormatInfo().m_IsCompressed) {
|
||||
glCompressedTexImage2D(
|
||||
this->m_Target,
|
||||
this->m_Level,
|
||||
this->GetFormatInfo().m_InternalFormat,
|
||||
this->m_Width,
|
||||
this->m_Height,
|
||||
0,
|
||||
this->m_Size,
|
||||
pixels
|
||||
);
|
||||
} else {
|
||||
glTexImage2D(
|
||||
this->m_Target,
|
||||
this->m_Level,
|
||||
this->GetFormatInfo().m_InternalFormat,
|
||||
this->m_Width,
|
||||
this->m_Height,
|
||||
0,
|
||||
this->GetFormatInfo().m_DataFormat,
|
||||
this->GetFormatInfo().m_DataType,
|
||||
pixels
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void GLMipmap::TexSubImage(const GLBox& a2, int32_t size, const void* pixels) {
|
||||
// TODO
|
||||
// BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget() && pixels != 0 && GLDevice::Get()->GetVertexArrayStates().buffers[eGLBT_PIXEL_UNPACK] == 0);
|
||||
|
||||
if (this->m_Target == GL_TEXTURE_3D) {
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->m_Width);
|
||||
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, this->m_Height);
|
||||
|
||||
glTexSubImage3D(
|
||||
this->m_Target,
|
||||
this->m_Level,
|
||||
a2.left,
|
||||
a2.top,
|
||||
a2.front,
|
||||
a2.width,
|
||||
a2.height,
|
||||
a2.depth,
|
||||
this->GetFormatInfo().m_DataFormat,
|
||||
this->GetFormatInfo().m_DataType,
|
||||
pixels
|
||||
);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
|
||||
} else if (this->GetFormatInfo().m_IsCompressed) {
|
||||
glCompressedTexSubImage2D(
|
||||
this->m_Target,
|
||||
this->m_Level,
|
||||
0,
|
||||
a2.top,
|
||||
this->m_Width,
|
||||
a2.height,
|
||||
this->GetFormatInfo().m_InternalFormat,
|
||||
size,
|
||||
pixels
|
||||
);
|
||||
} else {
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->m_Width);
|
||||
|
||||
glTexSubImage2D(
|
||||
this->m_Target,
|
||||
this->m_Level,
|
||||
a2.left,
|
||||
a2.top,
|
||||
a2.width,
|
||||
a2.height,
|
||||
this->GetFormatInfo().m_DataFormat,
|
||||
this->GetFormatInfo().m_DataType,
|
||||
pixels
|
||||
);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLMipmap::Unmap() {
|
||||
BLIZZARD_ASSERT(!this->m_Texture->IsRenderTarget());
|
||||
BLIZZARD_ASSERT(!this->m_Texture->IsSystemBuffer());
|
||||
BLIZZARD_ASSERT(this->m_MapParams != nullptr);
|
||||
|
||||
if (this->m_MapParams->m_MapMode == GL_READ_ONLY) {
|
||||
delete this->m_MapParams;
|
||||
this->m_MapParams = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
GLDevice* device = GLDevice::Get();
|
||||
|
||||
BLIZZARD_ASSERT(this->m_Texture->m_MappedMipmaps > 0);
|
||||
|
||||
if (device->m_TexWorker) {
|
||||
device->m_TexWorker->Lock();
|
||||
|
||||
GLTexUnmap* command = new GLTexUnmap(this->m_Texture, this, this->m_MapParams);
|
||||
device->m_TexWorker->Send(command);
|
||||
device->m_TexWorker->Signal();
|
||||
|
||||
device->m_TexWorker->Unlock();
|
||||
} else {
|
||||
this->Unmap(this->m_MapParams);
|
||||
}
|
||||
|
||||
this->m_MapParams = nullptr;
|
||||
}
|
||||
|
||||
void GLMipmap::Unmap(MapParams* mapParams) {
|
||||
BLIZZARD_ASSERT(mapParams != nullptr);
|
||||
|
||||
this->m_Texture->Bind(nullptr, 0);
|
||||
|
||||
if (this->m_Unk24) {
|
||||
if (this->GetFormatInfo().m_IsCompressed) {
|
||||
GLBox area = {
|
||||
0,
|
||||
mapParams->m_MapArea.top,
|
||||
mapParams->m_MapArea.front,
|
||||
this->m_Width,
|
||||
mapParams->m_MapArea.height,
|
||||
mapParams->m_MapArea.depth
|
||||
};
|
||||
|
||||
this->TexSubImage(area, mapParams->m_Size, mapParams->m_Unk8);
|
||||
} else {
|
||||
this->TexSubImage(mapParams->m_MapArea, mapParams->m_Size, mapParams->m_Unk8 + mapParams->m_Unk7);
|
||||
}
|
||||
} else {
|
||||
this->TexImage(this->m_Data);
|
||||
this->m_Unk24 = 1;
|
||||
}
|
||||
|
||||
delete mapParams;
|
||||
|
||||
// TODO
|
||||
|
||||
this->m_Texture->m_MappedMipmaps--;
|
||||
}
|
||||
62
src/gx/gll/GLMipmap.h
Normal file
62
src/gx/gll/GLMipmap.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef GX_GLL_GL_MIPMAP_H
|
||||
#define GX_GLL_GL_MIPMAP_H
|
||||
|
||||
#include "gx/gll/GL.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class GLFramebuffer;
|
||||
class GLTexture;
|
||||
|
||||
class GLMipmap {
|
||||
public:
|
||||
// Types
|
||||
struct MapParams {
|
||||
GLBox m_MapArea;
|
||||
int32_t m_MapMode = 0;
|
||||
int32_t m_Unk7 = 0;
|
||||
unsigned char* m_Unk8 = nullptr;
|
||||
int32_t m_Size = 0;
|
||||
};
|
||||
|
||||
// Member variables
|
||||
GLTexture* m_Texture = nullptr;
|
||||
uint16_t m_Width = 0;
|
||||
uint16_t m_Height = 0;
|
||||
uint16_t m_Depth = 0;
|
||||
uint8_t m_Level = 0;
|
||||
uint8_t m_DepthBits = 0;
|
||||
uint32_t m_Size = 0;
|
||||
int32_t m_Target = 0;
|
||||
unsigned char* m_Data = nullptr; // TODO proper type
|
||||
MapParams* m_MapParams = nullptr;
|
||||
std::vector<GLAttachPoint>* m_AttachPoints = nullptr;
|
||||
uint32_t m_Unk20 = 0;
|
||||
uint32_t m_Unk24 = 0;
|
||||
|
||||
// Member functions
|
||||
void Attach(GLFramebuffer*, GLenum, int32_t);
|
||||
void Detach(GLFramebuffer*, GLenum, bool);
|
||||
void DetachAll();
|
||||
int32_t GetDepthBits(void);
|
||||
GLTextureFormat GetFormat(void);
|
||||
TextureFormatInfo& GetFormatInfo(void);
|
||||
uint16_t GetHeight(void);
|
||||
int32_t GetPitch(void);
|
||||
GLTexture* GetTexture();
|
||||
uint32_t GetTextureID(void);
|
||||
uint16_t GetWidth(void);
|
||||
void* Map(GLEnum, const GLBox*);
|
||||
void* Map(GLEnum, const GLRect*);
|
||||
void ReleaseObject();
|
||||
void RemoveDebugMipmap();
|
||||
void ResetData(GLEnum, int32_t, unsigned char*);
|
||||
void ResetSize(uint32_t, uint32_t, uint32_t);
|
||||
void TexImage(const void*);
|
||||
void TexSubImage(const GLBox&, int32_t, const void*);
|
||||
void Unmap(void);
|
||||
void Unmap(MapParams*);
|
||||
};
|
||||
|
||||
#endif
|
||||
22
src/gx/gll/GLObject.cpp
Normal file
22
src/gx/gll/GLObject.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include "gx/gll/GLObject.h"
|
||||
#include "util/BlizzardCore.hpp"
|
||||
|
||||
void GLObject::AddRefTwin() {
|
||||
}
|
||||
|
||||
uint32_t GLObject::Release() {
|
||||
BLIZZARD_ASSERT(this->m_RefCount > 0);
|
||||
|
||||
this->m_RefCount--;
|
||||
|
||||
if (this->m_RefCount == 0) {
|
||||
this->ReleaseObject();
|
||||
}
|
||||
|
||||
this->ReleaseTwin();
|
||||
|
||||
return this->m_RefCount;
|
||||
}
|
||||
|
||||
void GLObject::ReleaseTwin() {
|
||||
}
|
||||
22
src/gx/gll/GLObject.h
Normal file
22
src/gx/gll/GLObject.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef GX_GLL_GL_OBJECT_H
|
||||
#define GX_GLL_GL_OBJECT_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class GLObject {
|
||||
public:
|
||||
// Member variables
|
||||
GLObject* m_Next;
|
||||
uint32_t m_RefCount;
|
||||
int64_t m_TimeStamp;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ReleaseObject() = 0;
|
||||
virtual void AddRefTwin();
|
||||
virtual void ReleaseTwin();
|
||||
|
||||
// Member functions
|
||||
uint32_t Release();
|
||||
};
|
||||
|
||||
#endif
|
||||
17
src/gx/gll/GLPixelShader.cpp
Normal file
17
src/gx/gll/GLPixelShader.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include "gx/gll/GLPixelShader.h"
|
||||
#include "gx/gll/GL.h"
|
||||
|
||||
GLPixelShader* GLPixelShader::Create() {
|
||||
// TODO
|
||||
// GLPool stuff
|
||||
|
||||
GLPixelShader* shader = new GLPixelShader();
|
||||
|
||||
shader->m_ShaderID = 0;
|
||||
shader->m_RefCount = 1;
|
||||
shader->m_ShaderType = ePixelShader;
|
||||
shader->m_UsingGLSL = 0;
|
||||
shader->var5 = GL_FRAGMENT_PROGRAM_ARB;
|
||||
|
||||
return shader;
|
||||
}
|
||||
12
src/gx/gll/GLPixelShader.h
Normal file
12
src/gx/gll/GLPixelShader.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef GX_GLL_GL_PIXEL_SHADER_H
|
||||
#define GX_GLL_GL_PIXEL_SHADER_H
|
||||
|
||||
#include "gx/gll/GLShader.h"
|
||||
|
||||
class GLPixelShader : public GLShader {
|
||||
public:
|
||||
// Static functions
|
||||
static GLPixelShader* Create(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
57
src/gx/gll/GLPool.h
Normal file
57
src/gx/gll/GLPool.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef GX_GLL_GL_POOL_H
|
||||
#define GX_GLL_GL_POOL_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
template<class T>
|
||||
class GLPool {
|
||||
public:
|
||||
// Static variables
|
||||
static GLPool<T>* m_pool;
|
||||
|
||||
// Static functions
|
||||
static GLPool<T>* Get(void);
|
||||
static void Init(void);
|
||||
|
||||
// Member variables
|
||||
std::atomic<uint32_t> m_NextName;
|
||||
|
||||
// Member functions
|
||||
uint32_t GetNextName(void);
|
||||
T* GetNextObject(void);
|
||||
void SetNextName(uint32_t);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
GLPool<T>* GLPool<T>::m_pool;
|
||||
|
||||
template<class T>
|
||||
GLPool<T>* GLPool<T>::Get() {
|
||||
return GLPool<T>::m_pool;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void GLPool<T>::Init() {
|
||||
GLPool<T>::m_pool = new GLPool<T>();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uint32_t GLPool<T>::GetNextName() {
|
||||
return this->m_NextName++;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T* GLPool<T>::GetNextObject() {
|
||||
// TODO
|
||||
// - pop off of GLObjectPool
|
||||
|
||||
return new T();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void GLPool<T>::SetNextName(uint32_t name) {
|
||||
this->m_NextName = name;
|
||||
}
|
||||
|
||||
#endif
|
||||
133
src/gx/gll/GLShader.cpp
Normal file
133
src/gx/gll/GLShader.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#include "gx/gll/GLShader.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLPixelShader.h"
|
||||
#include "gx/gll/GLPool.h"
|
||||
#include "gx/gll/GLVertexShader.h"
|
||||
|
||||
// TODO
|
||||
// - threaded compiler support
|
||||
// - glsl support
|
||||
// - hybrid support
|
||||
GLShader* GLShader::Create(ShaderType shaderType, bool hybrid, bool usingCG, const char* a4, const void* buf, int32_t codeLen, const char* a7, const char* name, GLShaderLogInfo* logInfo) {
|
||||
const char* shaderCode = reinterpret_cast<const char*>(buf);
|
||||
|
||||
if (*reinterpret_cast<const int32_t*>(buf) == 'GSL1') {
|
||||
BLIZZARD_ASSERT(!usingCG);
|
||||
|
||||
const ShaderDataHeader header = *reinterpret_cast<const ShaderDataHeader*>(buf);
|
||||
|
||||
BLIZZARD_ASSERT(header.shaderType == shaderType);
|
||||
BLIZZARD_ASSERT(header.size == codeLen);
|
||||
BLIZZARD_ASSERT(header.codePos >= sizeof(ShaderDataHeader));
|
||||
BLIZZARD_ASSERT(header.codeSize > 0);
|
||||
|
||||
shaderCode = &reinterpret_cast<const char*>(buf)[header.codePos];
|
||||
}
|
||||
|
||||
GLShader* shader = nullptr;
|
||||
|
||||
if (shaderType == ePixelShader) {
|
||||
shader = GLPixelShader::Create();
|
||||
} else if (shaderType == eVertexShader) {
|
||||
shader = GLVertexShader::Create();
|
||||
} else {
|
||||
// TODO
|
||||
// sub_1C5E0(&v38, "Unknown shader type %d!", shaderType);
|
||||
}
|
||||
|
||||
shader->m_UsingCG = usingCG;
|
||||
|
||||
if (usingCG) {
|
||||
shader->CompileCG(a4, shaderCode, codeLen, a7, logInfo);
|
||||
} else {
|
||||
shader->m_Code.assign(shaderCode, codeLen);
|
||||
|
||||
// TODO
|
||||
// sub_5CD10(shader);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
bool GLShader::CheckErrorsARB(GLShaderLogInfo* logInfo) {
|
||||
GLint errorPos;
|
||||
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
|
||||
const GLubyte* errorStr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
|
||||
// TODO
|
||||
// Blizzard::Debug::VAssert(logInfo != 0 || errorPos == -1, errorStr);
|
||||
|
||||
return errorPos == -1;
|
||||
}
|
||||
|
||||
void GLShader::Compile(GLShaderLogInfo* logInfo) {
|
||||
this->ImmediateCompile(logInfo);
|
||||
}
|
||||
|
||||
void GLShader::CompileCG(const char* a2, const void* shaderCode, int32_t codeLen, const char* a5, GLShaderLogInfo* logInfo) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GLShader::FlushUniforms(GLGLSLProgram* program) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
std::string& GLShader::GetCode() {
|
||||
return this->m_Code;
|
||||
}
|
||||
|
||||
int32_t GLShader::GetShaderType() {
|
||||
return this->m_ShaderType;
|
||||
}
|
||||
|
||||
void GLShader::ImmediateCompile(GLShaderLogInfo* logInfo) {
|
||||
BLIZZARD_ASSERT(!this->GetCode().empty());
|
||||
|
||||
this->m_Device = GLDevice::Get();
|
||||
|
||||
if (!this->m_UsingGLSL) {
|
||||
if (!this->m_ShaderID) {
|
||||
if (this->m_ShaderType == eVertexShader) {
|
||||
this->m_ShaderID = GLPool<GLVertexShader>::Get()->GetNextName();
|
||||
} else {
|
||||
this->m_ShaderID = GLPool<GLPixelShader>::Get()->GetNextName();
|
||||
}
|
||||
}
|
||||
|
||||
this->m_Device->BindShader(this);
|
||||
|
||||
const char* arbCode = this->GetCode().c_str();
|
||||
size_t arbLen = strlen(arbCode);
|
||||
|
||||
glProgramStringARB(this->var5, GL_PROGRAM_FORMAT_ASCII_ARB, arbLen, arbCode);
|
||||
|
||||
BLIZZARD_ASSERT(this->CheckErrorsARB(logInfo));
|
||||
} else {
|
||||
// TODO
|
||||
// - handle GLSL shaders
|
||||
// - handle hybrid shaders
|
||||
}
|
||||
|
||||
if (logInfo) {
|
||||
// TODO
|
||||
// this->var20 = logInfo[0];
|
||||
} else {
|
||||
this->var20 = 1;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// this->m_TimeStamp = Blizzard::Time::GetTimestamp();
|
||||
}
|
||||
|
||||
bool GLShader::IsEnabled() {
|
||||
return this->m_Enabled;
|
||||
}
|
||||
|
||||
void GLShader::ReleaseObject() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GLShader::SetShaderConstants(ShaderType shaderType, uint32_t index, const float* constants, uint32_t count) {
|
||||
// TODO
|
||||
}
|
||||
75
src/gx/gll/GLShader.h
Normal file
75
src/gx/gll/GLShader.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef GX_GLL_GL_SHADER_H
|
||||
#define GX_GLL_GL_SHADER_H
|
||||
|
||||
#include "gx/gll/GLObject.h"
|
||||
#include "gx/gll/GLShaderInput.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class GLDevice;
|
||||
class GLGLSLProgram;
|
||||
class GLShaderLogInfo;
|
||||
|
||||
class GLShader : public GLObject {
|
||||
public:
|
||||
// Types
|
||||
enum ShaderType {
|
||||
eVertexShader = 1,
|
||||
ePixelShader = 2,
|
||||
eShaderTypeCount = 3
|
||||
};
|
||||
|
||||
struct ShaderDataHeader {
|
||||
uint32_t signature;
|
||||
uint32_t size;
|
||||
ShaderType shaderType;
|
||||
uint32_t codePos;
|
||||
uint32_t codeSize;
|
||||
uint32_t unk1;
|
||||
uint32_t unk2;
|
||||
uint32_t unk3;
|
||||
};
|
||||
|
||||
// Static functions
|
||||
static GLShader* Create(ShaderType, bool, bool, const char*, const void*, int32_t, const char*, const char*, GLShaderLogInfo*);
|
||||
|
||||
// Member variables
|
||||
int32_t m_ShaderType = 0;
|
||||
int32_t var5 = 0;
|
||||
uint32_t m_ShaderID = 0;
|
||||
bool m_UsingCG = false;
|
||||
bool m_UsingGLSL = false;
|
||||
uint32_t m_UniformRegisterCount = 0;
|
||||
GLShaderInput** var10 = nullptr;
|
||||
float* var11 = nullptr;
|
||||
bool var12 = false;
|
||||
uint32_t var13 = 0;
|
||||
uint32_t var14 = 0;
|
||||
std::vector<GLShaderInput*, std::allocator<GLShaderInput*>> var15;
|
||||
std::vector<GLShaderInput*, std::allocator<GLShaderInput*>> var16;
|
||||
std::vector<GLShaderInput*, std::allocator<GLShaderInput*>> var17;
|
||||
GLShader* var18 = nullptr;
|
||||
GLDevice* m_Device = nullptr;
|
||||
bool var20 = 0;
|
||||
bool m_Enabled = true;
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char>> m_Code;
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char>> var23;
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ReleaseObject();
|
||||
|
||||
// Member functions
|
||||
bool CheckErrorsARB(GLShaderLogInfo*);
|
||||
bool CheckErrorsGLSL(GLShaderLogInfo*);
|
||||
void Compile(GLShaderLogInfo*);
|
||||
void CompileCG(const char*, const void*, int32_t, const char*, GLShaderLogInfo*);
|
||||
void FlushUniforms(GLGLSLProgram*);
|
||||
std::string& GetCode(void);
|
||||
int32_t GetShaderType(void);
|
||||
void ImmediateCompile(GLShaderLogInfo*);
|
||||
bool IsEnabled(void);
|
||||
void SetShaderConstants(ShaderType, uint32_t, const float*, uint32_t);
|
||||
};
|
||||
|
||||
#endif
|
||||
33
src/gx/gll/GLShaderInput.h
Normal file
33
src/gx/gll/GLShaderInput.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef GX_GLL_GL_SHADER_INPUT_H
|
||||
#define GX_GLL_GL_SHADER_INPUT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class GLShader;
|
||||
|
||||
class GLShaderInput {
|
||||
public:
|
||||
// Member variables
|
||||
GLShader *m_Shader;
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char>> m_Name;
|
||||
std::basic_string<char, std::char_traits<char>, std::allocator<char>> var2;
|
||||
int16_t m_MapIndex;
|
||||
int16_t var4;
|
||||
int16_t var5;
|
||||
int16_t m_UsedSize;
|
||||
int16_t var7;
|
||||
int16_t var8;
|
||||
GLShaderInput *m_Parent;
|
||||
int32_t var10;
|
||||
int32_t var11;
|
||||
int32_t var12;
|
||||
int8_t m_ChildrenCount;
|
||||
int8_t var14;
|
||||
uint16_t var15;
|
||||
int8_t var16;
|
||||
int8_t m_Variability;
|
||||
int8_t var18;
|
||||
int8_t var19;
|
||||
};
|
||||
|
||||
#endif
|
||||
659
src/gx/gll/GLTexture.cpp
Normal file
659
src/gx/gll/GLTexture.cpp
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
#include "gx/gll/GLTexture.h"
|
||||
#include "gx/gll/GLCommand.h"
|
||||
#include "gx/gll/GLDevice.h"
|
||||
#include "gx/gll/GLPool.h"
|
||||
#include "gx/gll/GLUtil.h"
|
||||
#include "gx/texture/CGxTex.hpp"
|
||||
#include <deque>
|
||||
|
||||
Blizzard::Thread::TLSSlot GLTexture::m_Bindings[4];
|
||||
|
||||
void* GLTexture::CreateBindings(void* ptr) {
|
||||
return new std::deque<std::vector<Binding>>;
|
||||
}
|
||||
|
||||
void GLTexture::DestroyBindings(void* ptr) {
|
||||
delete static_cast<std::deque<std::vector<Binding>>*>(ptr);
|
||||
}
|
||||
|
||||
void GLTexture::Bind(GLDevice* device, bool force) {
|
||||
BLIZZARD_ASSERT(!this->IsSystemBuffer());
|
||||
BLIZZARD_ASSERT(this->m_Depth != 0);
|
||||
|
||||
if (!device) {
|
||||
device = GLDevice::Get();
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT(device != nullptr);
|
||||
|
||||
auto& bindings = this->GetBindings();
|
||||
uint32_t deviceID = device->GetID();
|
||||
|
||||
if (deviceID >= bindings.size()) {
|
||||
bindings.resize(deviceID + 1);
|
||||
}
|
||||
|
||||
bindings[deviceID].device = device;
|
||||
|
||||
uint32_t currentActiveTexture = device->m_States.binding.currentActiveTexture;
|
||||
|
||||
if (bindings[deviceID].boundStages[currentActiveTexture]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (force) {
|
||||
bindings[deviceID].boundStages[currentActiveTexture] = 1;
|
||||
device->BindTexture(this->m_TextureType, this);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < 16; i++) {
|
||||
if (bindings[deviceID].boundStages[i]) {
|
||||
device->SetActiveTexture(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bindings[deviceID].boundStages[currentActiveTexture] = 1;
|
||||
device->BindTexture(this->m_TextureType, this);
|
||||
}
|
||||
|
||||
void GLTexture::FreeTexture() {
|
||||
auto device = GLDevice::Get();
|
||||
|
||||
if (device->m_TexWorker) {
|
||||
// TODO
|
||||
|
||||
this->m_LastFrameUsed = 0;
|
||||
|
||||
int32_t numFace = this->m_TextureType == GL_TEXTURE_CUBE_MAP ? 6 : 1;
|
||||
for (int32_t face = 0; face < numFace; face++) {
|
||||
for (int32_t level = 0; level < this->m_NumMipmap; level++) {
|
||||
this->m_Mipmaps[face][level].ReleaseObject();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO this->Sub690D0();
|
||||
// TODO device->m_TexWorker->Sub72340(this);
|
||||
|
||||
device->m_TexWorker->Lock();
|
||||
|
||||
auto command = new GLTexDestroy(this);
|
||||
device->m_TexWorker->Send(command);
|
||||
device->m_TexWorker->Signal();
|
||||
|
||||
device->m_TexWorker->Unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t numFace = this->m_TextureType == GL_TEXTURE_CUBE_MAP ? 6 : 1;
|
||||
for (int32_t face = 0; face < numFace; face++) {
|
||||
if (this->m_Mipmaps[face]) {
|
||||
delete[] this->m_Mipmaps[face];
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m_Mipmaps) {
|
||||
delete[] this->m_Mipmaps;
|
||||
}
|
||||
|
||||
this->m_Mipmaps = nullptr;
|
||||
this->m_Depth = 0;
|
||||
|
||||
// TODO this->Sub690D0();
|
||||
|
||||
glDeleteTextures(1, &this->m_TextureID);
|
||||
|
||||
this->m_GenerateMipmaps = 0;
|
||||
this->m_MaxMipmapLevel = 1000;
|
||||
this->m_BaseMipmapLevel = 0;
|
||||
this->m_CompareMode = 0;
|
||||
|
||||
this->m_Sampler.mipmapBias = 0.0f;
|
||||
this->m_Sampler.borderColor = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
this->m_Sampler.addressModeS = GL_REPEAT;
|
||||
this->m_Sampler.addressModeT = GL_REPEAT;
|
||||
this->m_Sampler.addressModeR = GL_REPEAT;
|
||||
this->m_Sampler.magFilterMode = GL_LINEAR;
|
||||
this->m_Sampler.minFilterMode = GL_NEAREST_MIPMAP_LINEAR;
|
||||
this->m_Sampler.maxAnisotropy = 1.0f;
|
||||
|
||||
Blizzard::Memory::Free(this->m_Data);
|
||||
this->m_Data = nullptr;
|
||||
|
||||
switch (this->m_TextureType) {
|
||||
case GL_TEXTURE_3D:
|
||||
// TODO GLPool<GLTexture3D>::GLObjectPool::Push(GLPool<GLTexture3D>::m_pool + 264, this);
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
// TODO GLPool<GLTextureCubeMap>::GLObjectPool::Push(GLPool<GLTextureCubeMap>::m_pool + 520, this);
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_2D:
|
||||
// TODO GLPool<GLTexture2D>::GLObjectPool::Push(GLPool<GLTexture2D>::m_pool + 131080, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<GLTexture::Binding>& GLTexture::GetBindings() {
|
||||
uint32_t index = GLLTextureTypeToIndex(this->m_TextureType);
|
||||
|
||||
uint32_t id;
|
||||
|
||||
if (index == 0) {
|
||||
id = this->m_TextureID - 33;
|
||||
} else if (index == 1) {
|
||||
id = this->m_TextureID - 32801;
|
||||
} else if (index == 2) {
|
||||
id = this->m_TextureID - 32865;
|
||||
} else if (index == 3) {
|
||||
id = this->m_TextureID - 1;
|
||||
}
|
||||
|
||||
auto target = static_cast<std::deque<std::vector<Binding>>*>(
|
||||
Blizzard::Thread::RegisterLocalStorage(
|
||||
&GLTexture::m_Bindings[index],
|
||||
GLTexture::CreateBindings,
|
||||
nullptr,
|
||||
GLTexture::DestroyBindings
|
||||
)
|
||||
);
|
||||
|
||||
if (id >= target->size()) {
|
||||
target->resize(id + 1);
|
||||
}
|
||||
|
||||
return (*target)[id];
|
||||
}
|
||||
|
||||
GLTextureFormat GLTexture::GetFormat() {
|
||||
return this->m_Format;
|
||||
}
|
||||
|
||||
TextureFormatInfo& GLTexture::GetFormatInfo() {
|
||||
return k_TextureFormatInfo[this->m_Format];
|
||||
}
|
||||
|
||||
GLMipmap* GLTexture::GetMipmap(uint32_t level, GLEnum face) {
|
||||
BLIZZARD_ASSERT(face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
|
||||
BLIZZARD_ASSERT(level < this->m_NumMipmap);
|
||||
BLIZZARD_ASSERT(this->m_Mipmaps != nullptr);
|
||||
BLIZZARD_ASSERT(this->m_Mipmaps[face - GL_TEXTURE_CUBE_MAP_POSITIVE_X] != nullptr);
|
||||
|
||||
return &this->m_Mipmaps[face - GL_TEXTURE_CUBE_MAP_POSITIVE_X][level];
|
||||
}
|
||||
|
||||
bool GLTexture::IsRenderTarget() {
|
||||
return this->m_Flags & GLTFLAG_RENDERTARGET;
|
||||
}
|
||||
|
||||
bool GLTexture::IsSystemBuffer() {
|
||||
return this->m_Flags & GLTFLAG_SYSTEM_BUFFER;
|
||||
}
|
||||
|
||||
bool GLTexture::IsValid() {
|
||||
return this->m_Depth;
|
||||
}
|
||||
|
||||
void* GLTexture::Map(uint32_t level, const GLRect* a3, uint32_t& a4, GLEnum a5) {
|
||||
BLIZZARD_ASSERT(this->m_TextureType != GL_TEXTURE_3D);
|
||||
|
||||
auto mipmap = this->GetMipmap(level, GL_TEXTURE_CUBE_MAP_POSITIVE_X);
|
||||
a4 = mipmap->GetPitch();
|
||||
return mipmap->Map(a5, a3);
|
||||
}
|
||||
|
||||
void GLTexture::RecreateGLTexture() {
|
||||
BLIZZARD_ASSERT(GLDevice::Get()->m_TexWorker != nullptr);
|
||||
|
||||
if (this->m_TextureType == GL_TEXTURE_RECTANGLE_EXT) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isCubeMap = this->m_TextureType == GL_TEXTURE_CUBE_MAP;
|
||||
int32_t numFace = isCubeMap ? 6 : 1;
|
||||
|
||||
for (int32_t face = 0; face < numFace; face++) {
|
||||
for (int32_t level = 0; level < this->m_NumMipmap; level++) {
|
||||
this->m_Mipmaps[face][level].Map(GL_WRITE_ONLY, static_cast<GLBox*>(nullptr));
|
||||
this->m_Mipmaps[face][level].Unmap();
|
||||
}
|
||||
}
|
||||
|
||||
glTexParameterf(this->m_TextureType, GL_TEXTURE_LOD_BIAS, this->m_Sampler.mipmapBias);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_S, this->m_Sampler.addressModeS);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_T, this->m_Sampler.addressModeT);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_R, this->m_Sampler.addressModeR);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_MIN_FILTER, this->m_Sampler.minFilterMode);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_MAG_FILTER, this->m_Sampler.magFilterMode);
|
||||
glTexParameterf(this->m_TextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT, this->m_Sampler.maxAnisotropy);
|
||||
glTexParameterfv(this->m_TextureType, GL_TEXTURE_BORDER_COLOR, reinterpret_cast<GLfloat*>(&this->m_Sampler.borderColor));
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_MAX_LEVEL, this->m_MaxMipmapLevel);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_BASE_LEVEL, this->m_BaseMipmapLevel);
|
||||
glTexParameteri(this->m_TextureType, GL_GENERATE_MIPMAP, this->m_GenerateMipmaps);
|
||||
}
|
||||
|
||||
void GLTexture::ResizeMipmaps() {
|
||||
BLIZZARD_ASSERT(this->m_Mipmaps == nullptr);
|
||||
|
||||
int32_t numFace = this->m_TextureType == GL_TEXTURE_CUBE_MAP ? 6 : 1;
|
||||
|
||||
this->m_Mipmaps = new GLMipmap*[numFace];
|
||||
|
||||
for (int32_t face = 0; face < numFace; face++) {
|
||||
this->m_Mipmaps[face] = new GLMipmap[this->m_NumMipmap];
|
||||
}
|
||||
}
|
||||
|
||||
void GLTexture::SetAddressModeR(GLEnum mode) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GLTexture::SetAddressModeS(GLEnum mode) {
|
||||
if (this->m_Sampler.addressModeS == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GL_CLAMP_TO_EDGE) {
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_S, mode);
|
||||
this->m_Sampler.addressModeS = mode;
|
||||
} else {
|
||||
// Workaround for buggy GPU (possibly ATI Radeon X1900)
|
||||
if (GLDevice::GetRendererInfo().renderer_id == 0x21900) {
|
||||
if (this->m_Width & (this->m_Width - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m_Height & (this->m_Height - 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_S, mode);
|
||||
this->m_Sampler.addressModeS = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void GLTexture::SetAddressModeT(GLEnum mode) {
|
||||
if (this->m_Sampler.addressModeT == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == GL_CLAMP_TO_EDGE) {
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_T, mode);
|
||||
this->m_Sampler.addressModeT = mode;
|
||||
} else {
|
||||
// Workaround for buggy GPU (possibly ATI Radeon X1900)
|
||||
if (GLDevice::GetRendererInfo().renderer_id == 0x21900) {
|
||||
if (this->m_Width & (this->m_Width - 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m_Height & (this->m_Height - 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_WRAP_T, mode);
|
||||
this->m_Sampler.addressModeT = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void GLTexture::SetBorderColor(const GLColor4f& color) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GLTexture::SetCompareMode(GLEnum compareMode) {
|
||||
BLIZZARD_ASSERT(
|
||||
this->GetFormatInfo().m_DataFormat == GL_DEPTH_COMPONENT
|
||||
|| this->GetFormatInfo().m_DataFormat == GL_DEPTH_STENCIL_EXT
|
||||
|| compareMode == GL_NONE
|
||||
);
|
||||
|
||||
if (this->m_CompareMode != compareMode) {
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_COMPARE_MODE, compareMode);
|
||||
this->m_CompareMode = compareMode;
|
||||
}
|
||||
}
|
||||
|
||||
void GLTexture::SetMagFilterMode(GLEnum mode) {
|
||||
if (this->m_Sampler.magFilterMode == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GLDevice::GetRendererInfo().vendor_id == 2 && this->IsRenderTarget() && mode != GL_LINEAR) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_MAG_FILTER, mode);
|
||||
this->m_Sampler.magFilterMode = mode;
|
||||
}
|
||||
|
||||
void GLTexture::SetMaxAnisotropy(int32_t maxAnisotropy) {
|
||||
if (this->m_Sampler.maxAnisotropy == maxAnisotropy) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameterf(this->m_TextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy);
|
||||
this->m_Sampler.maxAnisotropy = maxAnisotropy;
|
||||
}
|
||||
|
||||
void GLTexture::SetMinFilterMode(GLEnum mode) {
|
||||
if (this->m_Sampler.minFilterMode == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GLDevice::GetRendererInfo().vendor_id == 2 && this->IsRenderTarget() && mode != GL_LINEAR) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_MIN_FILTER, mode);
|
||||
this->m_Sampler.minFilterMode = mode;
|
||||
}
|
||||
|
||||
void GLTexture::SetupTexture() {
|
||||
BLIZZARD_ASSERT(this->m_NumMipmap == 1 || (this->m_Flags & GLTFLAG_AUTOGEN_MIPMAP) == 0);
|
||||
BLIZZARD_ASSERT(!this->IsRenderTarget() || this->m_NumMipmap == 1);
|
||||
BLIZZARD_ASSERT(!this->IsRenderTarget() || (this->m_Flags & GLTFLAG_READ_ACCESS) == 0);
|
||||
|
||||
GLDevice* device = GLDevice::Get();
|
||||
|
||||
if (this->GetFormatInfo().m_IsCompressed) {
|
||||
int32_t smallestDim = std::min(this->m_Width, this->m_Height);
|
||||
|
||||
BLIZZARD_ASSERT(smallestDim >= 4);
|
||||
|
||||
if (smallestDim == 4) {
|
||||
this->m_NumMipmap = 1;
|
||||
} else if (smallestDim == 8) {
|
||||
this->m_NumMipmap = 2;
|
||||
} else if (smallestDim == 16) {
|
||||
this->m_NumMipmap = 3;
|
||||
} else if (smallestDim == 32) {
|
||||
this->m_NumMipmap = 4;
|
||||
} else if (smallestDim == 64) {
|
||||
this->m_NumMipmap = 5;
|
||||
} else if (smallestDim == 128) {
|
||||
this->m_NumMipmap = 6;
|
||||
} else if (smallestDim == 256) {
|
||||
this->m_NumMipmap = 7;
|
||||
} else if (smallestDim == 512) {
|
||||
this->m_NumMipmap = 8;
|
||||
} else if (smallestDim == 1024) {
|
||||
this->m_NumMipmap = 9;
|
||||
} else if (smallestDim == 2048) {
|
||||
this->m_NumMipmap = 10;
|
||||
} else if (smallestDim == 4096) {
|
||||
this->m_NumMipmap = 11;
|
||||
} else {
|
||||
int32_t i = smallestDim >> 1;
|
||||
int32_t n = 0;
|
||||
|
||||
while (i) {
|
||||
i >>= 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
this->m_NumMipmap = n - 1;
|
||||
}
|
||||
} else {
|
||||
int32_t largestDim = std::max(this->m_Width, this->m_Height);
|
||||
|
||||
if (largestDim == 1) {
|
||||
this->m_NumMipmap = 1;
|
||||
} else if (largestDim == 2) {
|
||||
this->m_NumMipmap = 2;
|
||||
} else if (largestDim == 4) {
|
||||
this->m_NumMipmap = 3;
|
||||
} else if (largestDim == 8) {
|
||||
this->m_NumMipmap = 4;
|
||||
} else if (largestDim == 16) {
|
||||
this->m_NumMipmap = 5;
|
||||
} else if (largestDim == 32) {
|
||||
this->m_NumMipmap = 6;
|
||||
} else if (largestDim == 64) {
|
||||
this->m_NumMipmap = 7;
|
||||
} else if (largestDim == 128) {
|
||||
this->m_NumMipmap = 8;
|
||||
} else if (largestDim == 256) {
|
||||
this->m_NumMipmap = 9;
|
||||
} else if (largestDim == 512) {
|
||||
this->m_NumMipmap = 10;
|
||||
} else if (largestDim == 1024) {
|
||||
this->m_NumMipmap = 11;
|
||||
} else if (largestDim == 2048) {
|
||||
this->m_NumMipmap = 12;
|
||||
} else if (largestDim == 4096) {
|
||||
this->m_NumMipmap = 13;
|
||||
} else {
|
||||
int32_t i = largestDim >> 1;
|
||||
int32_t n = 0;
|
||||
|
||||
while (i) {
|
||||
i >>= 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
this->m_NumMipmap = n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(this->m_Flags & GLTFLAG_SYSTEM_BUFFER)) {
|
||||
BLIZZARD_ASSERT(this->m_RequestedNumMipmaps != 0);
|
||||
|
||||
this->m_NumMipmap = std::min(this->m_NumMipmap, this->m_RequestedNumMipmaps);
|
||||
}
|
||||
|
||||
this->var12 = this->GetFormatInfo().m_BytePerPixel * this->m_Width;
|
||||
if (this->GetFormatInfo().m_IsCompressed) {
|
||||
this->var12 >>= 2;
|
||||
}
|
||||
|
||||
this->ResizeMipmaps();
|
||||
|
||||
bool isCubeMap = this->m_TextureType == GL_TEXTURE_CUBE_MAP;
|
||||
|
||||
this->m_Size = 0;
|
||||
|
||||
int32_t numFace = isCubeMap ? 6 : 1;
|
||||
|
||||
for (int32_t face = 0; face < numFace; face++) {
|
||||
for (int32_t level = 0; level < this->m_NumMipmap; level++) {
|
||||
GLMipmap* mip = this->GetMipmap(level, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face);
|
||||
|
||||
mip->m_Level = level;
|
||||
mip->m_Texture = this;
|
||||
mip->ResetSize(this->m_Width >> level, this->m_Height >> level, this->m_Depth >> level);
|
||||
|
||||
this->m_Size += mip->m_Size;
|
||||
}
|
||||
}
|
||||
|
||||
this->var7 = GLDevice::m_Devices[0]->m_TextureList.begin();
|
||||
|
||||
if (this->m_Flags & GLTFLAG_SYSTEM_BUFFER) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLIZZARD_ASSERT(this->m_Data == nullptr);
|
||||
|
||||
if (!this->IsRenderTarget()) {
|
||||
this->m_Data = static_cast<char*>(Blizzard::Memory::Allocate(this->m_Size));
|
||||
}
|
||||
|
||||
this->Bind(nullptr, 0);
|
||||
|
||||
if (this->IsRenderTarget()) {
|
||||
this->SetAddressModeR(GL_CLAMP_TO_EDGE);
|
||||
this->SetAddressModeS(GL_CLAMP_TO_EDGE);
|
||||
this->SetAddressModeT(GL_CLAMP_TO_EDGE);
|
||||
this->SetMinFilterMode(GL_LINEAR);
|
||||
this->SetMagFilterMode(GL_LINEAR);
|
||||
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
|
||||
} else {
|
||||
this->SetAddressModeR(GL_REPEAT);
|
||||
this->SetAddressModeS(GL_REPEAT);
|
||||
this->SetAddressModeT(GL_REPEAT);
|
||||
this->SetMinFilterMode(GL_NEAREST_MIPMAP_NEAREST);
|
||||
this->SetMagFilterMode(GL_NEAREST);
|
||||
}
|
||||
|
||||
if (this->GetFormatInfo().m_DataFormat == GL_DEPTH_COMPONENT || this->GetFormatInfo().m_DataFormat == GL_DEPTH_STENCIL) {
|
||||
this->SetCompareMode(GLDevice::m_ExtARBShadow >= 1 ? GL_COMPARE_R_TO_TEXTURE : 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
glTexParameteri(this->m_TextureType, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
|
||||
} else {
|
||||
this->SetCompareMode(0);
|
||||
}
|
||||
|
||||
this->SetMaxAnisotropy(1);
|
||||
|
||||
this->SetBorderColor(GLColor4f::ZERO);
|
||||
|
||||
int32_t autogenMipmap = this->m_Flags & GLTFLAG_AUTOGEN_MIPMAP;
|
||||
if (autogenMipmap != this->m_GenerateMipmaps) {
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_GENERATE_MIPMAP, autogenMipmap);
|
||||
this->m_GenerateMipmaps = autogenMipmap;
|
||||
}
|
||||
|
||||
int32_t maxMipmapLevel = this->m_NumMipmap - 1;
|
||||
if (maxMipmapLevel != this->m_MaxMipmapLevel) {
|
||||
this->Bind(nullptr, 0);
|
||||
glTexParameteri(this->m_TextureType, GL_TEXTURE_MAX_LEVEL, maxMipmapLevel);
|
||||
this->m_MaxMipmapLevel = maxMipmapLevel;
|
||||
}
|
||||
|
||||
if (this->m_TextureType == GL_TEXTURE_RECTANGLE_EXT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->IsRenderTarget()) {
|
||||
device->SetUnpackClientStorage(0);
|
||||
}
|
||||
|
||||
unsigned char* data = reinterpret_cast<unsigned char*>(this->m_Data);
|
||||
|
||||
for (int32_t face = 0; face < numFace; face++) {
|
||||
for (int32_t level = 0; level < this->m_NumMipmap; level++) {
|
||||
GLMipmap* mip = this->GetMipmap(level, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face);
|
||||
|
||||
if (this->m_TextureType == GL_TEXTURE_CUBE_MAP) {
|
||||
mip->ResetData(face, level, data);
|
||||
} else {
|
||||
mip->ResetData(this->m_TextureType, level, data);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
data += mip->m_Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// this->m_TimeStamp = Blizzard::Time::GetTimestamp();
|
||||
|
||||
if (this->IsRenderTarget()) {
|
||||
device->SetUnpackClientStorage(1);
|
||||
}
|
||||
}
|
||||
|
||||
void GLTexture::Unbind(GLDevice* device, uint32_t stage) {
|
||||
auto& bindings = this->GetBindings();
|
||||
|
||||
BLIZZARD_ASSERT(device->GetID() < bindings.size());
|
||||
BLIZZARD_ASSERT(bindings[device->GetID()].device == device);
|
||||
BLIZZARD_ASSERT(bindings[device->GetID()].boundStages[stage]);
|
||||
|
||||
bindings[device->GetID()].boundStages[stage] = 0;
|
||||
}
|
||||
|
||||
void GLTexture::Unmap(uint32_t level, GLEnum face) {
|
||||
auto mipmap = this->GetMipmap(level, face);
|
||||
mipmap->Unmap();
|
||||
}
|
||||
|
||||
GLTexture2D* GLTexture2D::Create(uint32_t width, uint32_t height, uint32_t numMipMap, GLTextureFormat format, uint32_t flags) {
|
||||
GLTexture2D* tex;
|
||||
|
||||
// TODO
|
||||
// tex = GLPool<GLTexture2D>::GLObjectPool::Pop(GLPool<GLTexture2D>::m_pool + 131080);
|
||||
tex = nullptr;
|
||||
|
||||
if (!tex) {
|
||||
tex = new GLTexture2D();
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Blizzard::Debug::Assert(tex->m_refCount == 0);
|
||||
|
||||
tex->m_RefCount = 1;
|
||||
|
||||
// TODO
|
||||
// Blizzard::Debug::Assert(tex->m_TextureID >= PoolStats<GLTexture2D>::NAME_POOL_FIRST_NAME);
|
||||
|
||||
tex->m_TextureType = GL_TEXTURE_2D;
|
||||
tex->m_Width = width;
|
||||
tex->m_Depth = 1;
|
||||
tex->m_Height = height;
|
||||
tex->m_Format = format;
|
||||
tex->m_NumMipmap = numMipMap;
|
||||
tex->m_RequestedNumMipmaps = numMipMap;
|
||||
tex->m_Flags = flags;
|
||||
|
||||
tex->SetupTexture();
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
GLTexture2D::GLTexture2D() : GLTexture() {
|
||||
this->m_TextureType = GL_TEXTURE_2D;
|
||||
this->m_TextureID = GLPool<GLTexture2D>::Get()->GetNextName();
|
||||
|
||||
// TODO
|
||||
// Blizzard::Debug::Assert(this->m_TextureID >= PoolStats<GLTexture2D>::NAME_POOL_FIRST_NAME);
|
||||
}
|
||||
|
||||
void GLTexture2D::ReleaseObject() {
|
||||
BLIZZARD_ASSERT(this->m_TextureType == GL_TEXTURE_2D);
|
||||
this->FreeTexture();
|
||||
}
|
||||
|
||||
void GLLTexSetFlags(CGxTex* texId, GLTexture* a2) {
|
||||
static GLEnum convertMagFilterToOgl[] = {
|
||||
GL_NEAREST,
|
||||
GL_LINEAR,
|
||||
GL_NEAREST,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR
|
||||
};
|
||||
|
||||
static GLEnum convertMinFilterToOgl[] = {
|
||||
GL_NEAREST,
|
||||
GL_LINEAR,
|
||||
GL_NEAREST_MIPMAP_NEAREST,
|
||||
GL_LINEAR_MIPMAP_NEAREST,
|
||||
GL_LINEAR_MIPMAP_LINEAR,
|
||||
GL_LINEAR_MIPMAP_LINEAR
|
||||
};
|
||||
|
||||
a2->SetMagFilterMode(convertMagFilterToOgl[texId->m_flags.m_filter]);
|
||||
a2->SetMinFilterMode(convertMinFilterToOgl[texId->m_flags.m_filter]);
|
||||
|
||||
a2->SetAddressModeS(texId->m_flags.m_wrapU ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
||||
a2->SetAddressModeT(texId->m_flags.m_wrapV ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
||||
|
||||
a2->SetMaxAnisotropy(texId->m_flags.m_maxAnisotropy);
|
||||
}
|
||||
100
src/gx/gll/GLTexture.h
Normal file
100
src/gx/gll/GLTexture.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#ifndef GX_GLL_GL_TEXTURE_H
|
||||
#define GX_GLL_GL_TEXTURE_H
|
||||
|
||||
#include "gx/gll/GL.h"
|
||||
#include "gx/gll/GLObject.h"
|
||||
#include "gx/gll/GLTypes.h"
|
||||
#include "util/BlizzardCore.hpp"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#define GLTFLAG_RENDERTARGET 0x1
|
||||
#define GLTFLAG_DEPTH 0x2
|
||||
#define GLTFLAG_STENCIL 0x4
|
||||
#define GLTFLAG_AUTOGEN_MIPMAP 0x8
|
||||
#define GLTFLAG_READ_ACCESS 0x10
|
||||
#define GLTFLAG_SYSTEM_BUFFER 0x20
|
||||
|
||||
class CGxTex;
|
||||
class GLMipmap;
|
||||
class GLDevice;
|
||||
|
||||
class GLTexture : public GLObject {
|
||||
public:
|
||||
// Types
|
||||
struct Binding {
|
||||
uint8_t boundStages[16];
|
||||
GLDevice* device;
|
||||
};
|
||||
|
||||
// Static variables
|
||||
static Blizzard::Thread::TLSSlot m_Bindings[4];
|
||||
|
||||
// Static functions
|
||||
static void* CreateBindings(void*);
|
||||
static void DestroyBindings(void*);
|
||||
|
||||
// Member variables
|
||||
uint32_t m_TextureID = 0;
|
||||
GLEnum m_TextureType = 0;
|
||||
GLMipmap** m_Mipmaps = nullptr;
|
||||
std::list<GLTexture*>::iterator var7;
|
||||
uint32_t m_LastFrameUsed;
|
||||
uint32_t m_Width = 0;
|
||||
uint32_t m_Height = 0;
|
||||
uint32_t m_Depth = 0;
|
||||
uint32_t var12 = 0;
|
||||
uint32_t m_Size = 0;
|
||||
GLTextureFormat m_Format = GLTF_INVALID;
|
||||
uint32_t m_Flags = 0;
|
||||
uint32_t m_NumMipmap = 0;
|
||||
uint32_t m_RequestedNumMipmaps;
|
||||
char* m_Data = nullptr;
|
||||
std::atomic<int32_t> m_MappedMipmaps = { 0 };
|
||||
GLStates::Sampler m_Sampler;
|
||||
bool m_GenerateMipmaps = 0;
|
||||
int32_t m_MaxMipmapLevel = 1000;
|
||||
int32_t m_BaseMipmapLevel = 0;
|
||||
int32_t m_CompareMode = 0;
|
||||
|
||||
// Member functions
|
||||
void Bind(GLDevice*, bool);
|
||||
void FreeTexture();
|
||||
std::vector<Binding>& GetBindings(void); // invented name
|
||||
GLTextureFormat GetFormat(void);
|
||||
TextureFormatInfo& GetFormatInfo(void);
|
||||
GLMipmap* GetMipmap(uint32_t, GLEnum);
|
||||
bool IsRenderTarget(void);
|
||||
bool IsSystemBuffer(void);
|
||||
bool IsValid(void);
|
||||
void* Map(uint32_t, const GLRect*, uint32_t&, GLEnum);
|
||||
void RecreateGLTexture(void);
|
||||
void ResizeMipmaps(void);
|
||||
void SetAddressModeR(GLEnum);
|
||||
void SetAddressModeS(GLEnum);
|
||||
void SetAddressModeT(GLEnum);
|
||||
void SetBorderColor(const GLColor4f&);
|
||||
void SetCompareMode(GLEnum);
|
||||
void SetMagFilterMode(GLEnum);
|
||||
void SetMaxAnisotropy(int32_t);
|
||||
void SetMinFilterMode(GLEnum);
|
||||
void SetupTexture(void);
|
||||
void Unbind(GLDevice*, uint32_t); // invented name
|
||||
void Unmap(uint32_t level, GLEnum face);
|
||||
};
|
||||
|
||||
class GLTexture2D : public GLTexture {
|
||||
public:
|
||||
// Static functions
|
||||
static GLTexture2D* Create(uint32_t, uint32_t, uint32_t, GLTextureFormat, uint32_t);
|
||||
|
||||
// Virtual member functions
|
||||
virtual void ReleaseObject();
|
||||
|
||||
// Member functions
|
||||
GLTexture2D();
|
||||
};
|
||||
|
||||
void GLLTexSetFlags(CGxTex*, GLTexture*);
|
||||
|
||||
#endif
|
||||
5
src/gx/gll/GLTypes.cpp
Normal file
5
src/gx/gll/GLTypes.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#include "gx/gll/GLTypes.h"
|
||||
|
||||
GLColor4f GLColor4f::ZERO = { 0.0, 0.0, 0.0, 0.0 };
|
||||
GLColor4f GLColor4f::WHITE = { 1.0, 1.0, 1.0, 1.0 };
|
||||
GLColor4f GLColor4f::BLACK = { 0.0, 0.0, 0.0, 1.0 };
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue