diff --git a/backends/include/pd_system/gfx_opengl2.hpp b/backends/include/pd_system/gfx_opengl2.hpp index d250857..07a5bf3 100644 --- a/backends/include/pd_system/gfx_opengl2.hpp +++ b/backends/include/pd_system/gfx_opengl2.hpp @@ -36,6 +36,7 @@ class GfxOpenGL2 : public GfxDriverBase { u32 IBO = 0; int pLocTex = 0; int pLocAlfa = 0; + int pLocIsSDF = 0; int pLocProjection = 0; static const char* pVertCode; static const char* pFragCode; diff --git a/backends/include/pd_system/gfx_opengl3.hpp b/backends/include/pd_system/gfx_opengl3.hpp index 8b6da99..283be0d 100644 --- a/backends/include/pd_system/gfx_opengl3.hpp +++ b/backends/include/pd_system/gfx_opengl3.hpp @@ -36,6 +36,7 @@ class GfxOpenGL3 : public GfxDriverBase { u32 VAO = 0; int pLocTex = 0; int pLocAlfa = 0; + int pLocIsSDF = 0; int pLocProjection = 0; }; } // namespace PD \ No newline at end of file diff --git a/backends/include/pd_system/shaders.hpp b/backends/include/pd_system/shaders.hpp index 75be486..a3cc1ba 100644 --- a/backends/include/pd_system/shaders.hpp +++ b/backends/include/pd_system/shaders.hpp @@ -11,7 +11,7 @@ namespace Shaders { const unsigned int VertexShader[] = { 0x7230203, 0x10000, 0x8000B, 0x2B, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0xB000F, 0x0, 0x4, 0x6E69616D, 0x0, 0xD, 0x19, 0x24, 0x25, 0x27, 0x29, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x60005, 0xB, 0x505F6C67, 0x65567265, 0x78657472, 0x0, 0x60006, 0xB, 0x0, 0x505F6C67, 0x7469736F, 0x6E6F69, 0x70006, 0xB, 0x1, 0x505F6C67, 0x746E696F, 0x657A6953, 0x0, 0x70006, 0xB, 0x2, 0x435F6C67, 0x4470696C, 0x61747369, 0x65636E, 0x70006, 0xB, 0x3, 0x435F6C67, 0x446C6C75, 0x61747369, 0x65636E, 0x30005, 0xD, 0x0, 0x30005, 0x11, 0x4F4255, 0x60006, 0x11, 0x0, 0x6A6F7270, 0x69746365, 0x6E6F, 0x30005, 0x13, 0x6F6275, 0x30005, 0x19, 0x736F70, 0x30005, 0x24, 0x56556F, 0x30005, 0x25, 0x7675, 0x40005, 0x27, 0x6C6F436F, 0x726F, 0x40005, 0x29, 0x6F6C6F63, 0x72, 0x30047, 0xB, 0x2, 0x50048, 0xB, 0x0, 0xB, 0x0, 0x50048, 0xB, 0x1, 0xB, 0x1, 0x50048, 0xB, 0x2, 0xB, 0x3, 0x50048, 0xB, 0x3, 0xB, 0x4, 0x30047, 0x11, 0x2, 0x40048, 0x11, 0x0, 0x5, 0x50048, 0x11, 0x0, 0x7, 0x10, 0x50048, 0x11, 0x0, 0x23, 0x0, 0x40047, 0x13, 0x21, 0x0, 0x40047, 0x13, 0x22, 0x0, 0x40047, 0x19, 0x1E, 0x0, 0x40047, 0x24, 0x1E, 0x0, 0x40047, 0x25, 0x1E, 0x1, 0x40047, 0x27, 0x1E, 0x1, 0x40047, 0x29, 0x1E, 0x2, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40015, 0x8, 0x20, 0x0, 0x4002B, 0x8, 0x9, 0x1, 0x4001C, 0xA, 0x6, 0x9, 0x6001E, 0xB, 0x7, 0x6, 0xA, 0xA, 0x40020, 0xC, 0x3, 0xB, 0x4003B, 0xC, 0xD, 0x3, 0x40015, 0xE, 0x20, 0x1, 0x4002B, 0xE, 0xF, 0x0, 0x40018, 0x10, 0x7, 0x4, 0x3001E, 0x11, 0x10, 0x40020, 0x12, 0x2, 0x11, 0x4003B, 0x12, 0x13, 0x2, 0x40020, 0x14, 0x2, 0x10, 0x40017, 0x17, 0x6, 0x2, 0x40020, 0x18, 0x1, 0x17, 0x4003B, 0x18, 0x19, 0x1, 0x4002B, 0x6, 0x1B, 0x0, 0x4002B, 0x6, 0x1C, 0x3F800000, 0x40020, 0x21, 0x3, 0x7, 0x40020, 0x23, 0x3, 0x17, 0x4003B, 0x23, 0x24, 0x3, 0x4003B, 0x18, 0x25, 0x1, 0x4003B, 0x21, 0x27, 0x3, 0x40020, 0x28, 0x1, 0x7, 0x4003B, 0x28, 0x29, 0x1, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x50041, 0x14, 0x15, 0x13, 0xF, 0x4003D, 0x10, 0x16, 0x15, 0x4003D, 0x17, 0x1A, 0x19, 0x50051, 0x6, 0x1D, 0x1A, 0x0, 0x50051, 0x6, 0x1E, 0x1A, 0x1, 0x70050, 0x7, 0x1F, 0x1D, 0x1E, 0x1B, 0x1C, 0x50091, 0x7, 0x20, 0x16, 0x1F, 0x50041, 0x21, 0x22, 0xD, 0xF, 0x3003E, 0x22, 0x20, 0x4003D, 0x17, 0x26, 0x25, 0x3003E, 0x24, 0x26, 0x4003D, 0x7, 0x2A, 0x29, 0x3003E, 0x27, 0x2A, 0x100FD, 0x10038, }; // clang-format on // clang-format off -const unsigned int FragmentShader[] = { 0x7230203, 0x10000, 0x8000B, 0x39, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0x8000F, 0x0, 0x4, 0x6E69616D, 0x0, 0x11, 0x22, 0x24, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x30005, 0x9, 0x6374, 0x30005, 0xD, 0x786574, 0x30005, 0x11, 0x56556F, 0x50005, 0x16, 0x68737550, 0x61746144, 0x0, 0x50006, 0x16, 0x0, 0x61666C61, 0x0, 0x40005, 0x18, 0x68737570, 0x0, 0x50005, 0x22, 0x67617246, 0x6F6C6F43, 0x72, 0x40005, 0x24, 0x6C6F436F, 0x726F, 0x40047, 0xD, 0x21, 0x0, 0x40047, 0xD, 0x22, 0x0, 0x40047, 0x11, 0x1E, 0x0, 0x30047, 0x16, 0x2, 0x50048, 0x16, 0x0, 0x23, 0x0, 0x40047, 0x24, 0x1E, 0x1, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40020, 0x8, 0x7, 0x7, 0x90019, 0xA, 0x6, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3001B, 0xB, 0xA, 0x40020, 0xC, 0x0, 0xB, 0x4003B, 0xC, 0xD, 0x0, 0x40017, 0xF, 0x6, 0x2, 0x40020, 0x10, 0x1, 0xF, 0x4003B, 0x10, 0x11, 0x1, 0x4002B, 0x6, 0x13, 0x0, 0x40015, 0x15, 0x20, 0x1, 0x3001E, 0x16, 0x15, 0x40020, 0x17, 0x9, 0x16, 0x4003B, 0x17, 0x18, 0x9, 0x4002B, 0x15, 0x19, 0x0, 0x40020, 0x1A, 0x9, 0x15, 0x20014, 0x1D, 0x40020, 0x21, 0x3, 0x7, 0x4003B, 0x21, 0x22, 0x3, 0x40020, 0x23, 0x1, 0x7, 0x4003B, 0x23, 0x24, 0x1, 0x40017, 0x25, 0x6, 0x3, 0x40015, 0x28, 0x20, 0x0, 0x4002B, 0x28, 0x29, 0x3, 0x40020, 0x2A, 0x7, 0x6, 0x40020, 0x2D, 0x1, 0x6, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x4003B, 0x8, 0x9, 0x7, 0x4003D, 0xB, 0xE, 0xD, 0x4003D, 0xF, 0x12, 0x11, 0x70058, 0x7, 0x14, 0xE, 0x12, 0x2, 0x13, 0x3003E, 0x9, 0x14, 0x50041, 0x1A, 0x1B, 0x18, 0x19, 0x4003D, 0x15, 0x1C, 0x1B, 0x500AB, 0x1D, 0x1E, 0x1C, 0x19, 0x300F7, 0x20, 0x0, 0x400FA, 0x1E, 0x1F, 0x35, 0x200F8, 0x1F, 0x4003D, 0x7, 0x26, 0x24, 0x8004F, 0x25, 0x27, 0x26, 0x26, 0x0, 0x1, 0x2, 0x50041, 0x2A, 0x2B, 0x9, 0x29, 0x4003D, 0x6, 0x2C, 0x2B, 0x50041, 0x2D, 0x2E, 0x24, 0x29, 0x4003D, 0x6, 0x2F, 0x2E, 0x50085, 0x6, 0x30, 0x2C, 0x2F, 0x50051, 0x6, 0x31, 0x27, 0x0, 0x50051, 0x6, 0x32, 0x27, 0x1, 0x50051, 0x6, 0x33, 0x27, 0x2, 0x70050, 0x7, 0x34, 0x31, 0x32, 0x33, 0x30, 0x3003E, 0x22, 0x34, 0x200F9, 0x20, 0x200F8, 0x35, 0x4003D, 0x7, 0x36, 0x9, 0x4003D, 0x7, 0x37, 0x24, 0x50085, 0x7, 0x38, 0x36, 0x37, 0x3003E, 0x22, 0x38, 0x200F9, 0x20, 0x200F8, 0x20, 0x100FD, 0x10038, }; +const unsigned int FragmentShader[] = { 0x7230203, 0x10000, 0x8000B, 0x50, 0x0, 0x20011, 0x1, 0x6000B, 0x1, 0x4C534C47, 0x6474732E, 0x3035342E, 0x0, 0x3000E, 0x0, 0x1, 0x8000F, 0x0, 0x4, 0x6E69616D, 0x0, 0x11, 0x2C, 0x2E, 0x30003, 0x2, 0x1CC, 0x40005, 0x4, 0x6E69616D, 0x0, 0x30005, 0x9, 0x6374, 0x30005, 0xD, 0x786574, 0x30005, 0x11, 0x56556F, 0x50005, 0x16, 0x68737550, 0x61746144, 0x0, 0x50006, 0x16, 0x0, 0x61666C61, 0x0, 0x50006, 0x16, 0x1, 0x735F7369, 0x6664, 0x40005, 0x18, 0x68737570, 0x0, 0x40005, 0x23, 0x68706C61, 0x61, 0x50005, 0x2C, 0x67617246, 0x6F6C6F43, 0x72, 0x40005, 0x2E, 0x6C6F436F, 0x726F, 0x40047, 0xD, 0x21, 0x0, 0x40047, 0xD, 0x22, 0x0, 0x40047, 0x11, 0x1E, 0x0, 0x30047, 0x16, 0x2, 0x50048, 0x16, 0x0, 0x23, 0x0, 0x50048, 0x16, 0x1, 0x23, 0x4, 0x40047, 0x2E, 0x1E, 0x1, 0x20013, 0x2, 0x30021, 0x3, 0x2, 0x30016, 0x6, 0x20, 0x40017, 0x7, 0x6, 0x4, 0x40020, 0x8, 0x7, 0x7, 0x90019, 0xA, 0x6, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x3001B, 0xB, 0xA, 0x40020, 0xC, 0x0, 0xB, 0x4003B, 0xC, 0xD, 0x0, 0x40017, 0xF, 0x6, 0x2, 0x40020, 0x10, 0x1, 0xF, 0x4003B, 0x10, 0x11, 0x1, 0x4002B, 0x6, 0x13, 0x0, 0x40015, 0x15, 0x20, 0x1, 0x4001E, 0x16, 0x15, 0x15, 0x40020, 0x17, 0x9, 0x16, 0x4003B, 0x17, 0x18, 0x9, 0x4002B, 0x15, 0x19, 0x1, 0x40020, 0x1A, 0x9, 0x15, 0x4002B, 0x15, 0x1D, 0x0, 0x20014, 0x1E, 0x40020, 0x22, 0x7, 0x6, 0x4002B, 0x6, 0x24, 0x3EE66666, 0x4002B, 0x6, 0x25, 0x3F0CCCCD, 0x40015, 0x26, 0x20, 0x0, 0x4002B, 0x26, 0x27, 0x3, 0x40020, 0x2B, 0x3, 0x7, 0x4003B, 0x2B, 0x2C, 0x3, 0x40020, 0x2D, 0x1, 0x7, 0x4003B, 0x2D, 0x2E, 0x1, 0x40017, 0x2F, 0x6, 0x3, 0x40020, 0x33, 0x1, 0x6, 0x50036, 0x2, 0x4, 0x0, 0x3, 0x200F8, 0x5, 0x4003B, 0x8, 0x9, 0x7, 0x4003B, 0x22, 0x23, 0x7, 0x4003D, 0xB, 0xE, 0xD, 0x4003D, 0xF, 0x12, 0x11, 0x70058, 0x7, 0x14, 0xE, 0x12, 0x2, 0x13, 0x3003E, 0x9, 0x14, 0x50041, 0x1A, 0x1B, 0x18, 0x19, 0x4003D, 0x15, 0x1C, 0x1B, 0x500AB, 0x1E, 0x1F, 0x1C, 0x1D, 0x300F7, 0x21, 0x0, 0x400FA, 0x1F, 0x20, 0x3B, 0x200F8, 0x20, 0x50041, 0x22, 0x28, 0x9, 0x27, 0x4003D, 0x6, 0x29, 0x28, 0x8000C, 0x6, 0x2A, 0x1, 0x31, 0x24, 0x25, 0x29, 0x3003E, 0x23, 0x2A, 0x4003D, 0x7, 0x30, 0x2E, 0x8004F, 0x2F, 0x31, 0x30, 0x30, 0x0, 0x1, 0x2, 0x4003D, 0x6, 0x32, 0x23, 0x50041, 0x33, 0x34, 0x2E, 0x27, 0x4003D, 0x6, 0x35, 0x34, 0x50085, 0x6, 0x36, 0x32, 0x35, 0x50051, 0x6, 0x37, 0x31, 0x0, 0x50051, 0x6, 0x38, 0x31, 0x1, 0x50051, 0x6, 0x39, 0x31, 0x2, 0x70050, 0x7, 0x3A, 0x37, 0x38, 0x39, 0x36, 0x3003E, 0x2C, 0x3A, 0x200F9, 0x21, 0x200F8, 0x3B, 0x50041, 0x1A, 0x3C, 0x18, 0x1D, 0x4003D, 0x15, 0x3D, 0x3C, 0x500AB, 0x1E, 0x3E, 0x3D, 0x1D, 0x300F7, 0x40, 0x0, 0x400FA, 0x3E, 0x3F, 0x4C, 0x200F8, 0x3F, 0x4003D, 0x7, 0x41, 0x2E, 0x8004F, 0x2F, 0x42, 0x41, 0x41, 0x0, 0x1, 0x2, 0x50041, 0x22, 0x43, 0x9, 0x27, 0x4003D, 0x6, 0x44, 0x43, 0x50041, 0x33, 0x45, 0x2E, 0x27, 0x4003D, 0x6, 0x46, 0x45, 0x50085, 0x6, 0x47, 0x44, 0x46, 0x50051, 0x6, 0x48, 0x42, 0x0, 0x50051, 0x6, 0x49, 0x42, 0x1, 0x50051, 0x6, 0x4A, 0x42, 0x2, 0x70050, 0x7, 0x4B, 0x48, 0x49, 0x4A, 0x47, 0x3003E, 0x2C, 0x4B, 0x200F9, 0x40, 0x200F8, 0x4C, 0x4003D, 0x7, 0x4D, 0x9, 0x4003D, 0x7, 0x4E, 0x2E, 0x50085, 0x7, 0x4F, 0x4D, 0x4E, 0x3003E, 0x2C, 0x4F, 0x200F9, 0x40, 0x200F8, 0x40, 0x200F9, 0x21, 0x200F8, 0x21, 0x100FD, 0x10038, }; // clang-format on } // namespace Shaders } // namespace PD \ No newline at end of file diff --git a/backends/source/gfx_citro3d.cpp b/backends/source/gfx_citro3d.cpp index 37b64d2..9486e52 100644 --- a/backends/source/gfx_citro3d.cpp +++ b/backends/source/gfx_citro3d.cpp @@ -84,7 +84,7 @@ struct GfxCitro3D::Impl { } } - void SetupPixelStage() { + void SetupPixelStage(bool sdf) { shaderProgramUse(&pShader); C3D_BindProgram(&pShader); C3D_SetAttrInfo(&pAttr); @@ -92,25 +92,46 @@ struct GfxCitro3D::Impl { if (!CurrentTex) return; C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnvInit(env); - switch (CurrentTex->fmt) { - case GPU_A4: - case GPU_A8: - case GPU_L4: - case GPU_L8: - C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0); - C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); - C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); - break; - case GPU_RGB565: - C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0); - C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); - C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); - break; + C3D_TexEnv* env1 = C3D_GetTexEnv(1); + C3D_TexEnvInit(env1); - default: - C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0); - C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); - break; + if (sdf) { + C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR); + C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); + + C3D_TexEnvColor(env, 0x60606060); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_CONSTANT); + C3D_TexEnvOpAlpha(env, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_SUBTRACT); + C3D_TexEnvScale(env, C3D_Alpha, GPU_TEVSCALE_4); + + C3D_TexEnvSrc(env1, C3D_RGB, GPU_PREVIOUS); + C3D_TexEnvFunc(env1, C3D_RGB, GPU_REPLACE); + + C3D_TexEnvSrc(env1, C3D_Alpha, GPU_PREVIOUS, GPU_PRIMARY_COLOR); + C3D_TexEnvOpAlpha(env, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA); + C3D_TexEnvFunc(env1, C3D_Alpha, GPU_MODULATE); + } else { + switch (CurrentTex->fmt) { + case GPU_A4: + case GPU_A8: + case GPU_L4: + case GPU_L8: + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); + break; + case GPU_RGB565: + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); + break; + + default: + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + break; + } } } }; @@ -146,7 +167,7 @@ void GfxCitro3D::SysDeinit() { void GfxCitro3D::Submit(size_t count, size_t start) { if (!impl) return; BindTexture(CurrentTex); - impl->SetupPixelStage(); // needs to be called after + impl->SetupPixelStage(CurrentTexIsSDF); // needs to be called after C3D_Mtx proj; Mtx_OrthoTilt(&proj, 0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f, false); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, impl->uLocProjection, &proj); diff --git a/backends/source/gfx_directx9.cpp b/backends/source/gfx_directx9.cpp index 107bf58..a781ffd 100644 --- a/backends/source/gfx_directx9.cpp +++ b/backends/source/gfx_directx9.cpp @@ -15,41 +15,45 @@ static const char* g_vsCode = R"( float4x4 projection; struct VS_IN { - float2 pos : POSITION0; - float2 uv : TEXCOORD0; - float4 col : COLOR0; + float2 pos : POSITION0; + float2 uv : TEXCOORD0; + float4 col : COLOR0; }; struct VS_OUT { - float4 pos : POSITION0; - float2 uv : TEXCOORD0; - float4 col : COLOR0; + float4 pos : POSITION0; + float2 uv : TEXCOORD0; + float4 col : COLOR0; }; VS_OUT main(VS_IN input) { - VS_OUT o; - o.pos = mul(projection, float4(input.pos, 0.0, 1.0)); - o.uv = input.uv; - o.col = input.col.bgra; - return o; + VS_OUT o; + o.pos = mul(projection, float4(input.pos, 0.0, 1.0)); + o.uv = input.uv; + o.col = input.col.bgra; + return o; } )"; static const char* g_psCode = R"( sampler2D tex : register(s0); -float alfa; +float alfa : register(c1); +float is_sdf : register(c2); struct PS_IN { - float2 uv : TEXCOORD0; - float4 col : COLOR0; + float2 uv : TEXCOORD0; + float4 col : COLOR0; }; float4 main(PS_IN input) : COLOR0 { - float4 tc = tex2D(tex, input.uv); - if (alfa > 0.5) - return float4(input.col.rgb, tc.a * input.col.a); - else - return tc * input.col; + float4 tc = tex2D(tex, input.uv); + if (is_sdf > 0.5) { + float alpha = smoothstep(0.45, 0.55, tc.a); + return float4(input.col.rgb, alpha * input.col.a); + } else if (alfa > 0.5) + return float4(input.col.rgb, tc.a * input.col.a); + else + return tc * input.col; } )"; @@ -159,6 +163,9 @@ void GfxDirectX9::BindTexture(TextureID id) { float v = a8 ? 1.0f : 0.0f; impl->Device->SetPixelShaderConstantF(0, &v, 1); + + float sdf = CurrentTexIsSDF ? 1.0f : 0.0f; + impl->Device->SetPixelShaderConstantF(1, &sdf, 1); } void GfxDirectX9::SysReset() { diff --git a/backends/source/gfx_opengl2.cpp b/backends/source/gfx_opengl2.cpp index 9e39be4..926749b 100644 --- a/backends/source/gfx_opengl2.cpp +++ b/backends/source/gfx_opengl2.cpp @@ -38,10 +38,15 @@ const char* GfxOpenGL2::pFragCode = R"( uniform sampler2D tex; uniform bool alfa; + uniform bool is_sdf; void main() { vec4 tc = texture2D(tex, oUV); - if (alfa) { + if (is_sdf) { + float dist = tc.a; + float alpha = smoothstep(0.45, 0.55, dist); + gl_FragColor = vec4(oColor.rgb, alpha * oColor.a); + } else if (alfa) { gl_FragColor = vec4(oColor.rgb, tc.a * oColor.a); } else { gl_FragColor = tc * oColor; @@ -78,6 +83,7 @@ void GfxOpenGL2::SysInit() { pSetupShaderAttribs(pShader); pLocTex = glGetUniformLocation(pShader, "tex"); pLocAlfa = glGetUniformLocation(pShader, "alfa"); + pLocIsSDF = glGetUniformLocation(pShader, "is_sdf"); pLocProjection = glGetUniformLocation(pShader, "projection"); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -114,6 +120,7 @@ void GfxOpenGL2::BindTexture(TextureID id) { GLint fmt = 0; glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt); glUniform1i(pLocAlfa, fmt == GL_ALPHA); + glUniform1i(pLocIsSDF, CurrentTexIsSDF); } void GfxOpenGL2::SysReset() { diff --git a/backends/source/gfx_opengl3.cpp b/backends/source/gfx_opengl3.cpp index 02a5a06..74b23cf 100644 --- a/backends/source/gfx_opengl3.cpp +++ b/backends/source/gfx_opengl3.cpp @@ -47,6 +47,7 @@ void GfxOpenGL3::SysInit() { pLocTex = glGetUniformLocation(pShader, "tex"); pLocAlfa = glGetUniformLocation(pShader, "push.alfa"); + pLocIsSDF = glGetUniformLocation(pShader, "push.is_sdf"); pLocProjection = glGetUniformLocation(pShader, "ubo.projection"); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -81,6 +82,7 @@ void GfxOpenGL3::BindTexture(TextureID id) { GLint fmt = 0; glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt); glUniform1i(pLocAlfa, fmt == GL_R8); + glUniform1i(pLocIsSDF, CurrentTexIsSDF); } void GfxOpenGL3::SysReset() { diff --git a/include/pd/drivers/gfx.hpp b/include/pd/drivers/gfx.hpp index 18a4e52..4104d6b 100755 --- a/include/pd/drivers/gfx.hpp +++ b/include/pd/drivers/gfx.hpp @@ -76,7 +76,9 @@ class PD_API GfxDriver : public DriverInterface { size_t CurrentVertex = 0; size_t pCountDrawcalls = 0; size_t pCountCommands = 0; + // State Variables oder so TextureID CurrentTex = 0; + bool CurrentTexIsSDF = false; Mat4 Projection; ivec2 ViewPort; std::unordered_map pTextureRegestry; @@ -114,12 +116,14 @@ class GfxDriverBase : public GfxDriver { UploadPools(); while (index < commands.size()) { CurrentTex = commands[index].Tex; + CurrentTexIsSDF = commands[index].SDF; if (!CurrentTex) { CurrentTex = pWhite.GetID(); } size_t startidx = commands[index].FirstIndex; size_t num_indices = 0; while (index < commands.size() && + CurrentTexIsSDF == commands[index].SDF && (CurrentTex == commands[index].Tex || (CurrentTex == pWhite.GetID() && commands[index].Tex == 0))) { num_indices += commands[index].IndexCount; diff --git a/include/pd/lithium/command.hpp b/include/pd/lithium/command.hpp index 5a731b5..6dfc018 100644 --- a/include/pd/lithium/command.hpp +++ b/include/pd/lithium/command.hpp @@ -20,6 +20,7 @@ class Command { int Layer = 0; ptr Tex = 0; + bool SDF = false; size_t FirstVertex = 0; size_t FirstIndex = 0; size_t VertexCount = 0; diff --git a/include/pd/lithium/font.hpp b/include/pd/lithium/font.hpp index 0aa0b82..573dff1 100644 --- a/include/pd/lithium/font.hpp +++ b/include/pd/lithium/font.hpp @@ -14,6 +14,13 @@ enum LiTextFlags_ : PD::u32 { LiTextFlags_NoOOS = 1 << 6, ///< No Out of Screen Rendering }; +using LiFontFlags = PD::u32; +enum LiFontFlags_ : PD::u32 { + LiFontFlags_None = 0, ///< Not special (bitmap font) + LiFontFlags_SDF = 1 << 0, ///< SDF Texture (and mode) + LiFontFlags_Monospace = 1 << 1, ///< Monospace Rendering +}; + namespace PD { namespace Li { class Drawlist; @@ -24,24 +31,31 @@ class PD_API Font { fvec4 SimpleUV; size_t Tex = 0; fvec2 Size; - float Offset = 0.f; + fvec2 Offset; + // float Offset = 0.f; + float AdvanceX = 0.f; bool pInvalid = false; }; Font() {} ~Font() {} + bool IsMonospace() { return pFlags & LiFontFlags_Monospace; } + bool IsSDF() { return pFlags & LiFontFlags_SDF; } + /** * Load a TTF File * @param path Path to the TTF file * @param px_height Pixelheight of the codepoints (limit by 64) */ - void LoadTTF(const std::string& path, int px_height = 32); + void LoadTTF(const std::string& path, int px_height = 32, + LiFontFlags flags = LiFontFlags_None); /** * Load a TTF File from Memory * @param data File data * @param px_height Pixelheight of the codepoints (limit by 64) */ - void LoadTTF(const std::vector& data, int px_height = 32); + void LoadTTF(const std::vector& data, int px_height = 32, + LiFontFlags flags = LiFontFlags_None); /** * Function that loads a default integrated font... * This will only work if PD_LI_INCLUDE_FONTS was set @@ -105,6 +119,7 @@ class PD_API Font { private: size_t pCurrentTex = 0; + LiFontFlags pFlags = 0; }; } // namespace Li } // namespace PD \ No newline at end of file diff --git a/source/lithium/command.cpp b/source/lithium/command.cpp index 64c71a6..07299d0 100644 --- a/source/lithium/command.cpp +++ b/source/lithium/command.cpp @@ -24,6 +24,7 @@ void Command::Reserve(size_t vtx, size_t idx) { void Command::Reset() { Layer = 0; Tex = 0; + SDF = false; FirstIndex = 0; FirstVertex = 0; IndexCount = 0; diff --git a/source/lithium/font.cpp b/source/lithium/font.cpp index 510ccc1..e9d778f 100644 --- a/source/lithium/font.cpp +++ b/source/lithium/font.cpp @@ -8,10 +8,12 @@ #include #include +#include namespace PD { namespace Li { -PD_API void Font::LoadTTF(const std::string& path, int px_height) { +PD_API void Font::LoadTTF(const std::string& path, int px_height, + LiFontFlags flags) { /** * Just use LoadFile2Mem which looks way cleaner * and helps not having the font loading code twice @@ -21,16 +23,18 @@ PD_API void Font::LoadTTF(const std::string& path, int px_height) { TT::Scope st("LI_LoadTTF_" + path); auto font = PD::IO::LoadFile2Mem(path); PDLOG("Font Size: {}", PD::Strings::FormatBytes(font.size())); - LoadTTF(font, px_height); + LoadTTF(font, px_height, flags); } -PD_API void Font::LoadTTF(const std::vector& data, int px_height) { +PD_API void Font::LoadTTF(const std::vector& data, int px_height, + LiFontFlags flags) { /** * Some additional Info: * Removed the stbtt get bitmapbox as we dont need to place * the glyps nicely in the tex. next step would be using the free * space on the y axis to get mor glyphs inside */ + pFlags = flags; PixelHeight = px_height; int texszs = PD::Bits::GetPow2(px_height * 16); if (texszs > 1024) { @@ -48,6 +52,17 @@ PD_API void Font::LoadTTF(const std::vector& data, int px_height) { stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap); int baseline = static_cast(ascent * scale); + float mono_advance = 0.f; + if (IsMonospace()) { + int a, l; + int rgi = stbtt_FindGlyphIndex(&inf, 'W'); + if (rgi == 0) rgi = stbtt_FindGlyphIndex(&inf, '0'); + if (rgi != 0) { + stbtt_GetGlyphHMetrics(&inf, rgi, &a, &l); + mono_advance = a * scale; + } + } + // Cache to not render same codepoint tex twice std::map buf_cache; @@ -56,77 +71,112 @@ PD_API void Font::LoadTTF(const std::vector& data, int px_height) { bool empty = true; - for (u32 ii = 0x0000; ii <= 0xFFFF; ii++) { - int gi = stbtt_FindGlyphIndex(&inf, ii); - if (gi == 0) continue; - if (stbtt_IsGlyphEmpty(&inf, gi)) continue; + std::vector> ranges = { + {0x0020, 0x007E}, // ASCII + {0x00A0, 0x00FF}, // LATIN-1 + }; - int w = 0, h = 0, xo = 0, yo = 0; - unsigned char* bitmap = - stbtt_GetCodepointBitmap(&inf, scale, scale, ii, &w, &h, &xo, &yo); - if (!bitmap || w <= 0 || h <= 0) { - if (bitmap) free(bitmap); - continue; - } + for (auto& it : ranges) { + for (u32 ii = it.first; ii <= it.second; ii++) { + int gi = stbtt_FindGlyphIndex(&inf, ii); + if (gi == 0) continue; - u32 hashed_map = IO::HashMemory(std::vector(bitmap, bitmap + (w * h))); - if (buf_cache.find(hashed_map) != buf_cache.end()) { - Codepoint c = GetCodepoint(buf_cache[hashed_map]); + int advance, lsb; + stbtt_GetGlyphHMetrics(&inf, gi, &advance, &lsb); + float sadvance = advance * scale; + float final_advance = sadvance; + float center_offset = 0.f; + + if (IsMonospace() && mono_advance > 0.f) { + final_advance = mono_advance; + center_offset = (mono_advance - sadvance) * 0.5f; + } + + if (stbtt_IsGlyphEmpty(&inf, gi)) { + Codepoint c; + c.AdvanceX = final_advance; + c.Size = fvec2(0.f); + c.pCodepoint = ii; + c.pInvalid = false; + CodeMap[ii] = c; + continue; + } + + int w = 0, h = 0, xo = 0, yo = 0; + unsigned char* bitmap = nullptr; + if (IsSDF()) { + bitmap = stbtt_GetCodepointSDF(&inf, scale, ii, 5, 128, 255.f / 5.f, &w, + &h, &xo, &yo); + } else { + bitmap = + stbtt_GetCodepointBitmap(&inf, scale, scale, ii, &w, &h, &xo, &yo); + } + if (!bitmap || w <= 0 || h <= 0) { + if (bitmap) free(bitmap); + continue; + } + + u32 hashed_map = + IO::HashMemory(std::vector(bitmap, bitmap + (w * h))); + if (buf_cache.find(hashed_map) != buf_cache.end()) { + Codepoint c = GetCodepoint(buf_cache[hashed_map]); + c.pCodepoint = ii; + CodeMap[ii] = c; + free(bitmap); + continue; + } else { + buf_cache[hashed_map] = ii; + } + + // Next row + if (off.x + w > texszs) { + off.y += PixelHeight; + off.x = 0.0f; + } + // Bake cause we go out of the tex + if (off.y + PixelHeight > texszs) { + BakeAndPush(false, font_tex, texszs); + off = 0; + std::fill(font_tex.begin(), font_tex.end(), 0); + empty = true; + } + + // UVs & Codepoint + Codepoint c; + fvec4 uvs; + // cast the ints to floats and not the floats... + // dont know where my mind was when creating the code + uvs.x = off.x / static_cast(texszs); + uvs.y = off.y / static_cast(texszs); + uvs.z = (off.x + w) / static_cast(texszs); + uvs.w = (off.y + h) / static_cast(texszs); + // Flip if needed + if (PD::Gfx::GetFlags() & PDGfxBackendFlags_FlipUV_Y) { + uvs.y = 1.f - uvs.y; + uvs.w = 1.f - uvs.w; + } + c.SimpleUV = uvs; + c.Tex = pCurrentTex; + c.Size = fvec2(w, h); + c.Offset = fvec2(xo + center_offset, baseline + yo); + c.AdvanceX = final_advance; c.pCodepoint = ii; + + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + int map_pos = ((static_cast(off.y) + y) * texszs + + (static_cast(off.x) + x)); + font_tex[map_pos] = bitmap[x + y * w]; + } + } + + empty = false; CodeMap[ii] = c; free(bitmap); - continue; - } else { - buf_cache[hashed_map] = ii; - } - // Next row - if (off.x + w > texszs) { - off.y += PixelHeight; - off.x = 0.0f; + // offset by 1 (prevents visual glitches i had) + off.x += w + 1; } - // Bake cause we go out of the tex - if (off.y + PixelHeight > texszs) { - BakeAndPush(false, font_tex, texszs); - off = 0; - std::fill(font_tex.begin(), font_tex.end(), 0); - empty = true; - } - - // UVs & Codepoint - Codepoint c; - fvec4 uvs; - // cast the ints to floats and not the floats... - // dont know where my mind was when creating the code - uvs.x = off.x / static_cast(texszs); - uvs.y = off.y / static_cast(texszs); - uvs.z = (off.x + w) / static_cast(texszs); - uvs.w = (off.y + h) / static_cast(texszs); - // Flip if needed - if (PD::Gfx::GetFlags() & PDGfxBackendFlags_FlipUV_Y) { - uvs.y = 1.f - uvs.y; - uvs.w = 1.f - uvs.w; - } - c.SimpleUV = uvs; - c.Tex = pCurrentTex; - c.Size = fvec2(w, h); - c.Offset = baseline + yo; - c.pCodepoint = ii; - - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - int map_pos = ((static_cast(off.y) + y) * texszs + - (static_cast(off.x) + x)); - font_tex[map_pos] = bitmap[x + y * w]; - } - } - - empty = false; - CodeMap[ii] = c; - free(bitmap); - - // offset by 1 (prevents visual glitches i had) - off.x += w + 1; } if (!empty) { @@ -173,30 +223,19 @@ PD_API fvec2 Font::GetTextBounds(const char* text, float scale) { u32 c; while (it.Decode32(c)) { auto cp = GetCodepoint(c); - if (cp.pInvalid && c != '\n' && c != '\t' && c != ' ') { + if ((cp.pInvalid && c != L'\n' && c != L'\t' && c != L' ') && c != L'\r') + continue; + if (c == L'\n') { + res.y += lh; + res.x = std::max(res.x, x); + x = 0.f; continue; } - switch (c) { - case L'\n': - res.y += lh; - res.x = std::max(res.x, x); - x = 0.f; - break; - case L'\t': - x += 16 * cfs; - break; - case L' ': - x += 4 * cfs; - // Fall trough here to get the same result as in - // TextCommand if/else Section - default: - x += cp.Size.x * cfs; - // Omly passing c cause i know its not used - if (it.PeekNext32(c)) { - x += 2 * cfs; - } - break; + if (c == L'\t') { + x += (cp.AdvanceX > 0 ? cp.AdvanceX : 16.f) * 4.f * cfs; + continue; } + x += cp.AdvanceX * cfs; } res.x = std::max(res.x, x); res.y += lh; @@ -243,38 +282,35 @@ PD_API void Font::CmdTextEx(Drawlist& dl, const fvec2& pos, u32 color, off.x = 0.f; continue; } - if (c == L'\t') { - off.x += 16 * cfs; - continue; - } - if (c == L' ') { - off.x += 4 * cfs; + off.x += (cp.AdvanceX > 0 ? cp.AdvanceX : 16.f) * 4.f * cfs; continue; } - if (cmd == nullptr || cmd->Tex != Textures[cp.Tex]) { - if (cp.Tex >= Textures.size()) continue; - cmd = &dl.NewCommand(); - cmd->Tex = Textures[cp.Tex]; + if (cp.Size.x > 0 && cp.Size.y > 0) { + if (cmd == nullptr || cmd->Tex != Textures[cp.Tex]) { + if (cp.Tex >= Textures.size()) continue; + cmd = &dl.NewCommand(); + cmd->Tex = Textures[cp.Tex]; + cmd->SDF = IsSDF(); + } + + // calculating once and using PrimTextQuad to directly push + // saves ~42% on raw multiline text draw time 6.3 -> 3.7 ms + // and ~25% on the whole frametime 20.3 -> 15.2 ms + // tested with Craftus-Next 0.8.0 commit: + // 33298ccc276bf996d341710e69ecf05f99c57961 + float cx = rpos.x + off.x + (cp.Offset.x * cfs); + float cy = rpos.y + off.y + (cp.Offset.y * cfs); + float cw = cp.Size.x * cfs; + float ch = cp.Size.y * cfs; + + if (flags & LiTextFlags_Shaddow) { + PrimTextQuad(*cmd, cx + 1.f, cy + 1.f, cw, ch, cp.SimpleUV, 0xff111111); + } + PrimTextQuad(*cmd, cx, cy, cw, ch, cp.SimpleUV, color); } - - // calculating once and using PrimTextQuad to directly push - // saves ~42% on raw multiline text draw time 6.3 -> 3.7 ms - // and ~25% on the whole frametime 20.3 -> 15.2 ms - // tested with Craftus-Next 0.8.0 commit: - // 33298ccc276bf996d341710e69ecf05f99c57961 - float cw = cp.Size.x * cfs; - float ch = cp.Size.y * cfs; - float cx = rpos.x + off.x; - float cy = rpos.y + off.y + (cp.Offset * cfs); - - if (flags & LiTextFlags_Shaddow) { - PrimTextQuad(*cmd, cx + 1.f, cy + 1.f, cw, ch, cp.SimpleUV, 0xff111111); - } - PrimTextQuad(*cmd, cx, cy, cw, ch, cp.SimpleUV, color); - - off.x += cp.Size.x * cfs + 2 * cfs; + off.x += cp.AdvanceX * cfs; } } diff --git a/tests/gfx/source/main.cpp b/tests/gfx/source/main.cpp index c7c88ee..53826a1 100644 --- a/tests/gfx/source/main.cpp +++ b/tests/gfx/source/main.cpp @@ -254,7 +254,7 @@ int main(int argc, char** argv) { // LeftStick.Render(pList); // RightStick.Render(pList); pList.UnbindTexture(); - pList.PathRect(50, PD::fvec2(450, 240)); + // pList.PathRect(50, PD::fvec2(450, 240)); /*pList.PathFillGradient("#ff0000", "#990000", PD::Radians(135)); pList.PathAdd(PD::fvec2(100, 120)); pList.PathAdd(PD::fvec2(250, 260)); @@ -264,6 +264,13 @@ int main(int argc, char** argv) { pList.PathAdd(PD::fvec2(1000, 360)); pList.PathStroke("#ff00ff", 10, LiDrawFlags_AA);*/ + pList.SetFontscale(std::sin(PD::Os::GetTime() * 0.001f) * 1.85f + 2.15f); + pList.DrawText(PD::fvec2(5, 130), "Some text...", "#fff00fff"); +#ifdef __3DS__ + pList.SetFontscale(0.4); +#else + pList.SetFontscale(); +#endif int __i = 0; for (auto& it : PD::TT::GetTraceMap()) { pList.DrawText( diff --git a/tools/pdsg/shaders/shader.frag b/tools/pdsg/shaders/shader.frag index 122c222..cbc5bf9 100644 --- a/tools/pdsg/shaders/shader.frag +++ b/tools/pdsg/shaders/shader.frag @@ -6,13 +6,17 @@ layout(location = 1) in vec4 oColor; uniform sampler2D tex; layout(push_constant) uniform PushData { int alfa; + int is_sdf; } push; out vec4 FragColor; void main() { vec4 tc = texture(tex, oUV); - if (push.alfa != 0) { + if(push.is_sdf != 0) { + float alpha = smoothstep(0.45, 0.55, tc.a); + FragColor = vec4(oColor.rgb, alpha * oColor.a); + } else if (push.alfa != 0) { FragColor = vec4(oColor.rgb, tc.a * oColor.a); } else { FragColor = tc * oColor;