790 lines
25 KiB
C
Executable File
790 lines
25 KiB
C
Executable File
#ifndef SOKOL_FONTSTASH_INCLUDED
|
|
/*
|
|
sokol_fontstash.h -- renderer for https://github.com/memononen/fontstash
|
|
on top of sokol_gl.h
|
|
|
|
Project URL: https://github.com/floooh/sokol
|
|
|
|
Do this:
|
|
|
|
#define SOKOL_FONTSTASH_IMPL
|
|
|
|
before you include this file in *one* C or C++ file to create the
|
|
implementation.
|
|
|
|
The following defines are used by the implementation to select the
|
|
platform-specific embedded shader code (these are the same defines as
|
|
used by sokol_gfx.h and sokol_app.h):
|
|
|
|
SOKOL_GLCORE33
|
|
SOKOL_GLES2
|
|
SOKOL_GLES3
|
|
SOKOL_D3D11
|
|
SOKOL_METAL
|
|
|
|
...optionally provide the following macros to override defaults:
|
|
|
|
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
|
SOKOL_MALLOC(s) - your own malloc function (default: malloc(s))
|
|
SOKOL_FREE(p) - your own free function (default: free(p))
|
|
SOKOL_API_DECL - public function declaration prefix (default: extern)
|
|
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
|
SOKOL_LOG(msg) - your own logging function (default: puts(msg))
|
|
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
|
|
|
|
Include the following headers before including sokol_fontstash.h:
|
|
|
|
sokol_gfx.h
|
|
|
|
Additionally include the following headers for including the sokol_fontstash.h
|
|
implementation:
|
|
|
|
sokol_gl.h
|
|
|
|
HOW TO
|
|
======
|
|
--- First initialize sokol-gfx and sokol-gl as usual:
|
|
|
|
sg_setup(&(sg_desc){...});
|
|
sgl_setup(&(sgl_desc){...});
|
|
|
|
--- Create at least one fontstash context with sfons_create() (this replaces
|
|
glfonsCreate() from fontstash.h's example GL renderer:
|
|
|
|
FONScontext* ctx = sfons_create(atlas_width, atlas_height, FONS_ZERO_TOPLEFT);
|
|
|
|
Each FONScontext manages one font atlas texture which can hold rasterized
|
|
glyphs for multiple fonts.
|
|
|
|
--- From here on, use fontstash.h's functions "as usual" to add TTF
|
|
font data and draw text. Note that (just like with sokol-gl), text
|
|
rendering can happen anywhere in the frame, not only inside
|
|
a sokol-gfx rendering pass.
|
|
|
|
--- You can use the helper function
|
|
|
|
uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
|
|
|
To convert a 0..255 RGBA color into a packed uint32_t color value
|
|
expected by fontstash.h.
|
|
|
|
--- Once per frame before calling sgl_draw(), call:
|
|
|
|
sfons_flush(FONScontext* ctx)
|
|
|
|
...this will update the dynamic sokol-gfx texture with the latest font
|
|
atlas content.
|
|
|
|
--- To actually render the text (and any other sokol-gl draw commands),
|
|
call sgl_draw() inside a sokol-gfx frame.
|
|
|
|
--- NOTE that you can mix fontstash.h calls with sokol-gl calls to mix
|
|
text rendering with sokol-gl rendering. You can also use
|
|
sokol-gl's matrix stack to position fontstash.h text in 3D.
|
|
|
|
--- finally on application shutdown, call:
|
|
|
|
sfons_shutdown()
|
|
|
|
before sgl_shutdown() and sg_shutdown()
|
|
|
|
|
|
WHAT HAPPENS UNDER THE HOOD:
|
|
============================
|
|
|
|
sfons_create():
|
|
- creates a sokol-gfx shader compatible with sokol-gl
|
|
- creates an sgl_pipeline object with alpha-blending using
|
|
this shader
|
|
- creates a 1-byte-per-pixel font atlas texture via sokol-gfx
|
|
(pixel format SG_PIXELFORMAT_R8)
|
|
|
|
fonsDrawText():
|
|
- this will call the following sequence of sokol-gl functions:
|
|
|
|
sgl_enable_texture();
|
|
sgl_texture(...);
|
|
sgl_push_pipeline();
|
|
sgl_load_pipeline(...);
|
|
sgl_begin_triangles();
|
|
for each vertex:
|
|
sg_v2f_t2f_c1i(...);
|
|
sgl_end();
|
|
sgl_pop_pipeline();
|
|
sgl_disable_texture();
|
|
|
|
- note that sokol-gl will merge several sgl_*_begin/sgl_end pairs
|
|
into a single draw call if no relevant state has changed, typically
|
|
all calls to fonsDrawText() will be merged into a single draw call
|
|
as long as all calls use the same FONScontext
|
|
|
|
sfons_flush():
|
|
- this will call sg_update_image() on the font atlas texture
|
|
if fontstash.h has added any rasterized glyphs since the last
|
|
frame
|
|
|
|
sfons_shutdown():
|
|
- destroy the font atlas texture, sgl_pipeline and sg_shader objects
|
|
|
|
LICENSE
|
|
=======
|
|
zlib/libpng license
|
|
|
|
Copyright (c) 2018 Andre Weissflog
|
|
|
|
This software is provided 'as-is', without any express or implied warranty.
|
|
In no event will the authors be held liable for any damages arising from the
|
|
use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software in a
|
|
product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not
|
|
be misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
distribution.
|
|
*/
|
|
#define SOKOL_FONTSTASH_INCLUDED (1)
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#if !defined(SOKOL_GFX_INCLUDED)
|
|
#error "Please include sokol_gfx.h before sokol_fontstash.h"
|
|
#endif
|
|
|
|
#ifndef SOKOL_API_DECL
|
|
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL)
|
|
#define SOKOL_API_DECL __declspec(dllexport)
|
|
#elif defined(_WIN32) && defined(SOKOL_DLL)
|
|
#define SOKOL_API_DECL __declspec(dllimport)
|
|
#else
|
|
#define SOKOL_API_DECL extern
|
|
#endif
|
|
#endif
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
SOKOL_API_DECL FONScontext* sfons_create(int width, int height, int flags);
|
|
SOKOL_API_DECL void sfons_destroy(FONScontext* ctx);
|
|
SOKOL_API_DECL void sfons_flush(FONScontext* ctx);
|
|
SOKOL_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
#endif /* SOKOL_FONTSTASH_INCLUDED */
|
|
|
|
/*-- IMPLEMENTATION ----------------------------------------------------------*/
|
|
#ifdef SOKOL_FONTSTASH_IMPL
|
|
#define SOKOL_FONTSTASH_IMPL_INCLUDED (1)
|
|
#include <string.h> /* memset, memcpy */
|
|
|
|
#if !defined(SOKOL_GL_INCLUDED)
|
|
#error "Please include sokol_gl.h before sokol_fontstash.h"
|
|
#endif
|
|
#if !defined(FONS_H)
|
|
#error "Please include fontstash.h before sokol_fontstash.h"
|
|
#endif
|
|
|
|
#ifndef SOKOL_API_IMPL
|
|
#define SOKOL_API_IMPL
|
|
#endif
|
|
#ifndef SOKOL_DEBUG
|
|
#ifndef NDEBUG
|
|
#define SOKOL_DEBUG (1)
|
|
#endif
|
|
#endif
|
|
#ifndef SOKOL_ASSERT
|
|
#include <assert.h>
|
|
#define SOKOL_ASSERT(c) assert(c)
|
|
#endif
|
|
#ifndef SOKOL_MALLOC
|
|
#include <stdlib.h>
|
|
#define SOKOL_MALLOC(s) malloc(s)
|
|
#define SOKOL_FREE(p) free(p)
|
|
#endif
|
|
#ifndef SOKOL_LOG
|
|
#ifdef SOKOL_DEBUG
|
|
#include <stdio.h>
|
|
#define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
|
|
#else
|
|
#define SOKOL_LOG(s)
|
|
#endif
|
|
#endif
|
|
#ifndef SOKOL_UNREACHABLE
|
|
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
|
|
#endif
|
|
|
|
#if defined(SOKOL_GLCORE33)
|
|
static const char* _sfons_vs_src =
|
|
"#version 330\n"
|
|
"uniform mat4 mvp;\n"
|
|
"uniform mat4 tm;\n"
|
|
"in vec4 position;\n"
|
|
"in vec2 texcoord0;\n"
|
|
"in vec4 color0;\n"
|
|
"out vec4 uv;\n"
|
|
"out vec4 color;\n"
|
|
"void main() {\n"
|
|
" gl_Position = mvp * position;\n"
|
|
" uv = tm * vec4(texcoord0, 0.0, 1.0);\n"
|
|
" color = color0;\n"
|
|
"}\n";
|
|
static const char* _sfons_fs_src =
|
|
"#version 330\n"
|
|
"uniform sampler2D tex;\n"
|
|
"in vec4 uv;\n"
|
|
"in vec4 color;\n"
|
|
"out vec4 frag_color;\n"
|
|
"void main() {\n"
|
|
" frag_color = vec4(1.0, 1.0, 1.0, texture(tex, uv.xy).r) * color;\n"
|
|
"}\n";
|
|
#elif defined(SOKOL_GLES2) || defined(SOKOL_GLES3)
|
|
static const char* _sfons_vs_src =
|
|
"uniform mat4 mvp;\n"
|
|
"uniform mat4 tm;\n"
|
|
"attribute vec4 position;\n"
|
|
"attribute vec2 texcoord0;\n"
|
|
"attribute vec4 color0;\n"
|
|
"varying vec4 uv;\n"
|
|
"varying vec4 color;\n"
|
|
"void main() {\n"
|
|
" gl_Position = mvp * position;\n"
|
|
" uv = tm * vec4(texcoord0, 0.0, 1.0);\n"
|
|
" color = color0;\n"
|
|
"}\n";
|
|
static const char* _sfons_fs_src =
|
|
"precision mediump float;\n"
|
|
"uniform sampler2D tex;\n"
|
|
"varying vec4 uv;\n"
|
|
"varying vec4 color;\n"
|
|
"void main() {\n"
|
|
" gl_FragColor = vec4(1.0, 1.0, 1.0, texture2D(tex, uv.xy).r) * color;\n"
|
|
"}\n";
|
|
#elif defined(SOKOL_METAL)
|
|
static const char* _sfons_vs_src =
|
|
"#include <metal_stdlib>\n"
|
|
"using namespace metal;\n"
|
|
"struct params_t {\n"
|
|
" float4x4 mvp;\n"
|
|
" float4x4 tm;\n"
|
|
"};\n"
|
|
"struct vs_in {\n"
|
|
" float4 pos [[attribute(0)]];\n"
|
|
" float2 uv [[attribute(1)]];\n"
|
|
" float4 color [[attribute(2)]];\n"
|
|
"};\n"
|
|
"struct vs_out {\n"
|
|
" float4 pos [[position]];\n"
|
|
" float4 uv;\n"
|
|
" float4 color;\n"
|
|
"};\n"
|
|
"vertex vs_out _main(vs_in in [[stage_in]], constant params_t& params [[buffer(0)]]) {\n"
|
|
" vs_out out;\n"
|
|
" out.pos = params.mvp * in.pos;\n"
|
|
" out.uv = params.tm * float4(in.uv, 0.0, 1.0);\n"
|
|
" out.color = in.color;\n"
|
|
" return out;\n"
|
|
"}\n";
|
|
static const char* _sfons_fs_src =
|
|
"#include <metal_stdlib>\n"
|
|
"using namespace metal;\n"
|
|
"struct fs_in {\n"
|
|
" float4 uv;\n"
|
|
" float4 color;\n"
|
|
"};\n"
|
|
"fragment float4 _main(fs_in in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n"
|
|
" return float4(1.0, 1.0, 1.0, tex.sample(smp, in.uv.xy).r) * in.color;\n"
|
|
"}\n";
|
|
#elif defined(SOKOL_D3D11)
|
|
/*
|
|
Shader blobs for D3D11, compiled with:
|
|
|
|
fxc.exe /T vs_4_0 /Fh vs.h /Gec /O3 vs.hlsl
|
|
fxc.exe /T ps_4_0 /Fh fs.h /Gec /O3 fs.hlsl
|
|
|
|
Vertex shader source:
|
|
|
|
cbuffer params: register(b0) {
|
|
float4x4 mvp;
|
|
float4x4 tm;
|
|
};
|
|
struct vs_in {
|
|
float4 pos: POSITION;
|
|
float2 uv: TEXCOORD0;
|
|
float4 color: COLOR0;
|
|
};
|
|
struct vs_out {
|
|
float4 uv: TEXCOORD0;
|
|
float4 color: COLOR0;
|
|
float4 pos: SV_Position;
|
|
};
|
|
vs_out main(vs_in inp) {
|
|
vs_out outp;
|
|
outp.pos = mul(mvp, inp.pos);
|
|
outp.uv = mul(tm, float4(inp.uv, 0.0, 1.0));
|
|
outp.color = inp.color;
|
|
return outp;
|
|
};
|
|
|
|
Pixel shader source:
|
|
|
|
Texture2D<float4> tex: register(t0);
|
|
sampler smp: register(s0);
|
|
float4 main(float4 uv: TEXCOORD0, float4 color: COLOR0): SV_Target0 {
|
|
return float4(1.0, 1.0, 1.0, tex.Sample(smp, uv.xy).r) * color;
|
|
}
|
|
*/
|
|
static const uint8_t _sfons_vs_bin[] = {
|
|
68, 88, 66, 67, 89, 173,
|
|
124, 225, 74, 102, 159, 55,
|
|
47, 64, 241, 32, 31, 107,
|
|
240, 204, 1, 0, 0, 0,
|
|
244, 3, 0, 0, 5, 0,
|
|
0, 0, 52, 0, 0, 0,
|
|
8, 1, 0, 0, 120, 1,
|
|
0, 0, 236, 1, 0, 0,
|
|
120, 3, 0, 0, 82, 68,
|
|
69, 70, 204, 0, 0, 0,
|
|
1, 0, 0, 0, 68, 0,
|
|
0, 0, 1, 0, 0, 0,
|
|
28, 0, 0, 0, 0, 4,
|
|
254, 255, 0, 17, 0, 0,
|
|
163, 0, 0, 0, 60, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 0, 1, 0, 0, 0,
|
|
112, 97, 114, 97, 109, 115,
|
|
0, 171, 60, 0, 0, 0,
|
|
2, 0, 0, 0, 92, 0,
|
|
0, 0, 128, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 140, 0, 0, 0,
|
|
0, 0, 0, 0, 64, 0,
|
|
0, 0, 2, 0, 0, 0,
|
|
144, 0, 0, 0, 0, 0,
|
|
0, 0, 160, 0, 0, 0,
|
|
64, 0, 0, 0, 64, 0,
|
|
0, 0, 2, 0, 0, 0,
|
|
144, 0, 0, 0, 0, 0,
|
|
0, 0, 109, 118, 112, 0,
|
|
3, 0, 3, 0, 4, 0,
|
|
4, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 116, 109,
|
|
0, 77, 105, 99, 114, 111,
|
|
115, 111, 102, 116, 32, 40,
|
|
82, 41, 32, 72, 76, 83,
|
|
76, 32, 83, 104, 97, 100,
|
|
101, 114, 32, 67, 111, 109,
|
|
112, 105, 108, 101, 114, 32,
|
|
49, 48, 46, 49, 0, 171,
|
|
73, 83, 71, 78, 104, 0,
|
|
0, 0, 3, 0, 0, 0,
|
|
8, 0, 0, 0, 80, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 3, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
15, 15, 0, 0, 89, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 3, 0,
|
|
0, 0, 1, 0, 0, 0,
|
|
3, 3, 0, 0, 98, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 3, 0,
|
|
0, 0, 2, 0, 0, 0,
|
|
15, 15, 0, 0, 80, 79,
|
|
83, 73, 84, 73, 79, 78,
|
|
0, 84, 69, 88, 67, 79,
|
|
79, 82, 68, 0, 67, 79,
|
|
76, 79, 82, 0, 79, 83,
|
|
71, 78, 108, 0, 0, 0,
|
|
3, 0, 0, 0, 8, 0,
|
|
0, 0, 80, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 15, 0,
|
|
0, 0, 89, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 3, 0, 0, 0,
|
|
1, 0, 0, 0, 15, 0,
|
|
0, 0, 95, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 0, 3, 0, 0, 0,
|
|
2, 0, 0, 0, 15, 0,
|
|
0, 0, 84, 69, 88, 67,
|
|
79, 79, 82, 68, 0, 67,
|
|
79, 76, 79, 82, 0, 83,
|
|
86, 95, 80, 111, 115, 105,
|
|
116, 105, 111, 110, 0, 171,
|
|
83, 72, 68, 82, 132, 1,
|
|
0, 0, 64, 0, 1, 0,
|
|
97, 0, 0, 0, 89, 0,
|
|
0, 4, 70, 142, 32, 0,
|
|
0, 0, 0, 0, 8, 0,
|
|
0, 0, 95, 0, 0, 3,
|
|
242, 16, 16, 0, 0, 0,
|
|
0, 0, 95, 0, 0, 3,
|
|
50, 16, 16, 0, 1, 0,
|
|
0, 0, 95, 0, 0, 3,
|
|
242, 16, 16, 0, 2, 0,
|
|
0, 0, 101, 0, 0, 3,
|
|
242, 32, 16, 0, 0, 0,
|
|
0, 0, 101, 0, 0, 3,
|
|
242, 32, 16, 0, 1, 0,
|
|
0, 0, 103, 0, 0, 4,
|
|
242, 32, 16, 0, 2, 0,
|
|
0, 0, 1, 0, 0, 0,
|
|
104, 0, 0, 2, 1, 0,
|
|
0, 0, 56, 0, 0, 8,
|
|
242, 0, 16, 0, 0, 0,
|
|
0, 0, 86, 21, 16, 0,
|
|
1, 0, 0, 0, 70, 142,
|
|
32, 0, 0, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0,
|
|
0, 10, 242, 0, 16, 0,
|
|
0, 0, 0, 0, 70, 142,
|
|
32, 0, 0, 0, 0, 0,
|
|
4, 0, 0, 0, 6, 16,
|
|
16, 0, 1, 0, 0, 0,
|
|
70, 14, 16, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 8,
|
|
242, 32, 16, 0, 0, 0,
|
|
0, 0, 70, 14, 16, 0,
|
|
0, 0, 0, 0, 70, 142,
|
|
32, 0, 0, 0, 0, 0,
|
|
7, 0, 0, 0, 54, 0,
|
|
0, 5, 242, 32, 16, 0,
|
|
1, 0, 0, 0, 70, 30,
|
|
16, 0, 2, 0, 0, 0,
|
|
56, 0, 0, 8, 242, 0,
|
|
16, 0, 0, 0, 0, 0,
|
|
86, 21, 16, 0, 0, 0,
|
|
0, 0, 70, 142, 32, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 0, 50, 0, 0, 10,
|
|
242, 0, 16, 0, 0, 0,
|
|
0, 0, 70, 142, 32, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 6, 16, 16, 0,
|
|
0, 0, 0, 0, 70, 14,
|
|
16, 0, 0, 0, 0, 0,
|
|
50, 0, 0, 10, 242, 0,
|
|
16, 0, 0, 0, 0, 0,
|
|
70, 142, 32, 0, 0, 0,
|
|
0, 0, 2, 0, 0, 0,
|
|
166, 26, 16, 0, 0, 0,
|
|
0, 0, 70, 14, 16, 0,
|
|
0, 0, 0, 0, 50, 0,
|
|
0, 10, 242, 32, 16, 0,
|
|
2, 0, 0, 0, 70, 142,
|
|
32, 0, 0, 0, 0, 0,
|
|
3, 0, 0, 0, 246, 31,
|
|
16, 0, 0, 0, 0, 0,
|
|
70, 14, 16, 0, 0, 0,
|
|
0, 0, 62, 0, 0, 1,
|
|
83, 84, 65, 84, 116, 0,
|
|
0, 0, 9, 0, 0, 0,
|
|
1, 0, 0, 0, 0, 0,
|
|
0, 0, 6, 0, 0, 0,
|
|
7, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0
|
|
};
|
|
static uint8_t _sfons_fs_bin[] = {
|
|
68, 88, 66, 67, 180, 53,
|
|
115, 174, 239, 17, 254, 112,
|
|
63, 104, 217, 123, 150, 145,
|
|
179, 27, 1, 0, 0, 0,
|
|
120, 2, 0, 0, 5, 0,
|
|
0, 0, 52, 0, 0, 0,
|
|
200, 0, 0, 0, 24, 1,
|
|
0, 0, 76, 1, 0, 0,
|
|
252, 1, 0, 0, 82, 68,
|
|
69, 70, 140, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 2, 0, 0, 0,
|
|
28, 0, 0, 0, 0, 4,
|
|
255, 255, 0, 17, 0, 0,
|
|
100, 0, 0, 0, 92, 0,
|
|
0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 0, 1, 0, 0, 0,
|
|
96, 0, 0, 0, 2, 0,
|
|
0, 0, 5, 0, 0, 0,
|
|
4, 0, 0, 0, 255, 255,
|
|
255, 255, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 13, 0,
|
|
0, 0, 115, 109, 112, 0,
|
|
116, 101, 120, 0, 77, 105,
|
|
99, 114, 111, 115, 111, 102,
|
|
116, 32, 40, 82, 41, 32,
|
|
72, 76, 83, 76, 32, 83,
|
|
104, 97, 100, 101, 114, 32,
|
|
67, 111, 109, 112, 105, 108,
|
|
101, 114, 32, 49, 48, 46,
|
|
49, 0, 73, 83, 71, 78,
|
|
72, 0, 0, 0, 2, 0,
|
|
0, 0, 8, 0, 0, 0,
|
|
56, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
3, 0, 0, 0, 0, 0,
|
|
0, 0, 15, 3, 0, 0,
|
|
65, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
3, 0, 0, 0, 1, 0,
|
|
0, 0, 15, 15, 0, 0,
|
|
84, 69, 88, 67, 79, 79,
|
|
82, 68, 0, 67, 79, 76,
|
|
79, 82, 0, 171, 79, 83,
|
|
71, 78, 44, 0, 0, 0,
|
|
1, 0, 0, 0, 8, 0,
|
|
0, 0, 32, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 15, 0,
|
|
0, 0, 83, 86, 95, 84,
|
|
97, 114, 103, 101, 116, 0,
|
|
171, 171, 83, 72, 68, 82,
|
|
168, 0, 0, 0, 64, 0,
|
|
0, 0, 42, 0, 0, 0,
|
|
90, 0, 0, 3, 0, 96,
|
|
16, 0, 0, 0, 0, 0,
|
|
88, 24, 0, 4, 0, 112,
|
|
16, 0, 0, 0, 0, 0,
|
|
85, 85, 0, 0, 98, 16,
|
|
0, 3, 50, 16, 16, 0,
|
|
0, 0, 0, 0, 98, 16,
|
|
0, 3, 242, 16, 16, 0,
|
|
1, 0, 0, 0, 101, 0,
|
|
0, 3, 242, 32, 16, 0,
|
|
0, 0, 0, 0, 104, 0,
|
|
0, 2, 1, 0, 0, 0,
|
|
69, 0, 0, 9, 242, 0,
|
|
16, 0, 0, 0, 0, 0,
|
|
70, 16, 16, 0, 0, 0,
|
|
0, 0, 150, 115, 16, 0,
|
|
0, 0, 0, 0, 0, 96,
|
|
16, 0, 0, 0, 0, 0,
|
|
54, 0, 0, 5, 18, 0,
|
|
16, 0, 0, 0, 0, 0,
|
|
1, 64, 0, 0, 0, 0,
|
|
128, 63, 56, 0, 0, 7,
|
|
242, 32, 16, 0, 0, 0,
|
|
0, 0, 6, 12, 16, 0,
|
|
0, 0, 0, 0, 70, 30,
|
|
16, 0, 1, 0, 0, 0,
|
|
62, 0, 0, 1, 83, 84,
|
|
65, 84, 116, 0, 0, 0,
|
|
4, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
3, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 1, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0,
|
|
0, 0
|
|
};
|
|
#elif defined(SOKOL_DUMMY_BACKEND)
|
|
static const char* _sfons_vs_src = "";
|
|
static const char* _sfons_fs_src = "";
|
|
#endif
|
|
|
|
typedef struct _sfons_t {
|
|
sg_shader shd;
|
|
sgl_pipeline pip;
|
|
sg_image img;
|
|
int width, height;
|
|
bool img_dirty;
|
|
} _sfons_t;
|
|
|
|
static int _sfons_render_create(void* user_ptr, int width, int height) {
|
|
SOKOL_ASSERT(user_ptr && (width > 8) && (height > 8));
|
|
_sfons_t* sfons = (_sfons_t*) user_ptr;
|
|
|
|
/* sokol-gl compatible shader which treats RED channel as alpha */
|
|
if (sfons->shd.id == SG_INVALID_ID) {
|
|
sg_shader_desc shd_desc;
|
|
memset(&shd_desc, 0, sizeof(shd_desc));
|
|
shd_desc.attrs[0].name = "position";
|
|
shd_desc.attrs[1].name = "texcoord0";
|
|
shd_desc.attrs[2].name = "color0";
|
|
shd_desc.attrs[0].sem_name = "POSITION";
|
|
shd_desc.attrs[1].sem_name = "TEXCOORD";
|
|
shd_desc.attrs[2].sem_name = "COLOR";
|
|
sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0];
|
|
ub->size = 128;
|
|
ub->uniforms[0].name = "mvp";
|
|
ub->uniforms[0].type = SG_UNIFORMTYPE_MAT4;
|
|
ub->uniforms[1].name = "tm";
|
|
ub->uniforms[1].type = SG_UNIFORMTYPE_MAT4;
|
|
shd_desc.fs.images[0].name = "tex";
|
|
shd_desc.fs.images[0].type = SG_IMAGETYPE_2D;
|
|
#if defined(SOKOL_D3D11)
|
|
shd_desc.vs.byte_code = _sfons_vs_bin;
|
|
shd_desc.vs.byte_code_size = sizeof(_sfons_vs_bin);
|
|
shd_desc.fs.byte_code = _sfons_fs_bin;
|
|
shd_desc.fs.byte_code_size = sizeof(_sfons_fs_bin);
|
|
#else
|
|
shd_desc.vs.source = _sfons_vs_src;
|
|
shd_desc.fs.source = _sfons_fs_src;
|
|
#endif
|
|
shd_desc.label = "sfons-shader";
|
|
sfons->shd = sg_make_shader(&shd_desc);
|
|
}
|
|
|
|
/* sokol-gl pipeline object */
|
|
if (sfons->pip.id == SG_INVALID_ID) {
|
|
sg_pipeline_desc pip_desc;
|
|
memset(&pip_desc, 0, sizeof(pip_desc));
|
|
pip_desc.shader = sfons->shd;
|
|
pip_desc.blend.enabled = true;
|
|
pip_desc.blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
|
|
pip_desc.blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
|
sfons->pip = sgl_make_pipeline(&pip_desc);
|
|
}
|
|
|
|
/* create or re-create font atlas texture */
|
|
if (sfons->img.id != SG_INVALID_ID) {
|
|
sg_destroy_image(sfons->img);
|
|
sfons->img.id = SG_INVALID_ID;
|
|
}
|
|
sfons->width = width;
|
|
sfons->height = height;
|
|
|
|
SOKOL_ASSERT(sfons->img.id == SG_INVALID_ID);
|
|
sg_image_desc img_desc;
|
|
memset(&img_desc, 0, sizeof(img_desc));
|
|
img_desc.width = sfons->width;
|
|
img_desc.height = sfons->height;
|
|
img_desc.min_filter = SG_FILTER_LINEAR;
|
|
img_desc.mag_filter = SG_FILTER_LINEAR;
|
|
img_desc.usage = SG_USAGE_DYNAMIC;
|
|
img_desc.pixel_format = SG_PIXELFORMAT_R8;
|
|
sfons->img = sg_make_image(&img_desc);
|
|
return 1;
|
|
}
|
|
|
|
static int _sfons_render_resize(void* user_ptr, int width, int height) {
|
|
return _sfons_render_create(user_ptr, width, height);
|
|
}
|
|
|
|
static void _sfons_render_update(void* user_ptr, int* rect, const unsigned char* data) {
|
|
SOKOL_ASSERT(user_ptr && rect && data);
|
|
_sfons_t* sfons = (_sfons_t*) user_ptr;
|
|
sfons->img_dirty = true;
|
|
}
|
|
|
|
static void _sfons_render_draw(void* user_ptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) {
|
|
SOKOL_ASSERT(user_ptr && verts && tcoords && colors && (nverts > 0));
|
|
_sfons_t* sfons = (_sfons_t*) user_ptr;
|
|
sgl_enable_texture();
|
|
sgl_texture(sfons->img);
|
|
sgl_push_pipeline();
|
|
sgl_load_pipeline(sfons->pip);
|
|
sgl_begin_triangles();
|
|
for (int i = 0; i < nverts; i++) {
|
|
sgl_v2f_t2f_c1i(verts[2*i+0], verts[2*i+1], tcoords[2*i+0], tcoords[2*i+1], colors[i]);
|
|
}
|
|
sgl_end();
|
|
sgl_pop_pipeline();
|
|
sgl_disable_texture();
|
|
}
|
|
|
|
static void _sfons_render_delete(void* user_ptr) {
|
|
SOKOL_ASSERT(user_ptr);
|
|
_sfons_t* sfons = (_sfons_t*) user_ptr;
|
|
if (sfons->img.id != SG_INVALID_ID) {
|
|
sg_destroy_image(sfons->img);
|
|
sfons->img.id = SG_INVALID_ID;
|
|
}
|
|
if (sfons->pip.id != SG_INVALID_ID) {
|
|
sgl_destroy_pipeline(sfons->pip);
|
|
sfons->pip.id = SG_INVALID_ID;
|
|
}
|
|
if (sfons->shd.id != SG_INVALID_ID) {
|
|
sg_destroy_shader(sfons->shd);
|
|
sfons->shd.id = SG_INVALID_ID;
|
|
}
|
|
SOKOL_FREE(sfons);
|
|
}
|
|
|
|
SOKOL_API_IMPL FONScontext* sfons_create(int width, int height, int flags) {
|
|
SOKOL_ASSERT((width > 0) && (height > 0));
|
|
FONSparams params;
|
|
_sfons_t* sfons = (_sfons_t*) SOKOL_MALLOC(sizeof(_sfons_t));
|
|
memset(sfons, 0, sizeof(_sfons_t));
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.width = width;
|
|
params.height = height;
|
|
params.flags = (unsigned char) flags;
|
|
params.renderCreate = _sfons_render_create;
|
|
params.renderResize = _sfons_render_resize;
|
|
params.renderUpdate = _sfons_render_update;
|
|
params.renderDraw = _sfons_render_draw;
|
|
params.renderDelete = _sfons_render_delete;
|
|
params.userPtr = sfons;
|
|
return fonsCreateInternal(¶ms);
|
|
}
|
|
|
|
SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) {
|
|
SOKOL_ASSERT(ctx);
|
|
fonsDeleteInternal(ctx);
|
|
}
|
|
|
|
SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) {
|
|
SOKOL_ASSERT(ctx && ctx->params.userPtr);
|
|
_sfons_t* sfons = (_sfons_t*) ctx->params.userPtr;
|
|
if (sfons->img_dirty) {
|
|
sfons->img_dirty = false;
|
|
sg_image_content content;
|
|
memset(&content, 0, sizeof(content));
|
|
content.subimage[0][0].ptr = ctx->texData;
|
|
content.subimage[0][0].size = sfons->width * sfons->height;
|
|
sg_update_image(sfons->img, &content);
|
|
}
|
|
}
|
|
|
|
SOKOL_API_IMPL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
|
return (r) | (g<<8) | (b<<16) | (a<<24);
|
|
}
|
|
|
|
#endif /* SOKOL_FONTSTASH_IMPL */
|