mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
thirdparty: update all sokol and fontstash headers with their upstream versions (#16940)
This commit is contained in:
parent
d1306ffcf5
commit
e854051c1f
6
examples/sokol/.gitignore
vendored
Normal file
6
examples/sokol/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
02_cubes_glsl/cube_glsl.h
|
||||
03_march_tracing_glsl/rt_glsl.h
|
||||
04_multi_shader_glsl/rt_glsl_march.h
|
||||
04_multi_shader_glsl/rt_glsl_puppy.h
|
||||
05_instancing_glsl/rt_glsl_instancing.h
|
||||
06_obj_viewer/gouraud.h
|
582
thirdparty/fontstash/stb_truetype.h
vendored
582
thirdparty/fontstash/stb_truetype.h
vendored
@ -1,5 +1,5 @@
|
||||
// stb_truetype.h - v1.24 - public domain
|
||||
// authored from 2009-2020 by Sean Barrett / RAD Game Tools
|
||||
// stb_truetype.h - v1.26 - public domain
|
||||
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
|
||||
//
|
||||
// =======================================================================
|
||||
//
|
||||
@ -58,6 +58,8 @@
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.26 (2021-08-28) fix broken rasterizer
|
||||
// 1.25 (2021-07-11) many fixes
|
||||
// 1.24 (2020-02-05) fix warning
|
||||
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
||||
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||
@ -270,8 +272,8 @@
|
||||
//// SAMPLE PROGRAMS
|
||||
////
|
||||
//
|
||||
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
|
||||
//
|
||||
// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
|
||||
// See "tests/truetype_demo_win32.c" for a complete version.
|
||||
#if 0
|
||||
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
||||
#include "stb_truetype.h"
|
||||
@ -297,6 +299,8 @@ void my_stbtt_initfont(void)
|
||||
void my_stbtt_print(float x, float y, char *text)
|
||||
{
|
||||
// assume orthographic projection with units = screen pixels, origin at top left
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, ftex);
|
||||
glBegin(GL_QUADS);
|
||||
@ -304,10 +308,10 @@ void my_stbtt_print(float x, float y, char *text)
|
||||
if (*text >= 32 && *text < 128) {
|
||||
stbtt_aligned_quad q;
|
||||
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
|
||||
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
|
||||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
|
||||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
|
||||
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
|
||||
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
|
||||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
|
||||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
|
||||
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
|
||||
}
|
||||
++text;
|
||||
}
|
||||
@ -853,6 +857,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
|
||||
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
||||
// frees the data allocated above
|
||||
|
||||
STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
|
||||
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
|
||||
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
|
||||
// fills svg with the character's SVG data.
|
||||
@ -1539,12 +1544,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
|
||||
search += 2;
|
||||
|
||||
{
|
||||
stbtt_uint16 offset, start;
|
||||
stbtt_uint16 offset, start, last;
|
||||
stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
|
||||
|
||||
STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
|
||||
start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
|
||||
if (unicode_codepoint < start)
|
||||
last = ttUSHORT(data + endCount + 2*item);
|
||||
if (unicode_codepoint < start || unicode_codepoint > last)
|
||||
return 0;
|
||||
|
||||
offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
|
||||
@ -1871,7 +1876,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||
if (comp_verts) STBTT_free(comp_verts, info->userdata);
|
||||
return 0;
|
||||
}
|
||||
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
|
||||
if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
|
||||
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
|
||||
if (vertices) STBTT_free(vertices, info->userdata);
|
||||
vertices = tmp;
|
||||
@ -2134,7 +2139,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
||||
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
|
||||
has_subrs = 1;
|
||||
}
|
||||
// fallthrough
|
||||
// FALLTHROUGH
|
||||
case 0x1D: // callgsubr
|
||||
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
||||
v = (int) s[--sp];
|
||||
@ -2239,7 +2244,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
||||
} break;
|
||||
|
||||
default:
|
||||
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
|
||||
if (b0 != 255 && b0 != 28 && b0 < 32)
|
||||
return STBTT__CSERR("reserved operator");
|
||||
|
||||
// push immediate
|
||||
@ -2351,7 +2356,7 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningent
|
||||
return length;
|
||||
}
|
||||
|
||||
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||
{
|
||||
stbtt_uint8 *data = info->data + info->kern;
|
||||
stbtt_uint32 needle, straw;
|
||||
@ -2381,243 +2386,225 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph
|
||||
return 0;
|
||||
}
|
||||
|
||||
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
|
||||
static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
|
||||
{
|
||||
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
|
||||
switch(coverageFormat) {
|
||||
case 1: {
|
||||
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
||||
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
|
||||
switch (coverageFormat) {
|
||||
case 1: {
|
||||
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
||||
|
||||
// Binary search.
|
||||
stbtt_int32 l=0, r=glyphCount-1, m;
|
||||
int straw, needle=glyph;
|
||||
while (l <= r) {
|
||||
stbtt_uint8 *glyphArray = coverageTable + 4;
|
||||
stbtt_uint16 glyphID;
|
||||
m = (l + r) >> 1;
|
||||
glyphID = ttUSHORT(glyphArray + 2 * m);
|
||||
straw = glyphID;
|
||||
if (needle < straw)
|
||||
r = m - 1;
|
||||
else if (needle > straw)
|
||||
l = m + 1;
|
||||
else {
|
||||
return m;
|
||||
}
|
||||
// Binary search.
|
||||
stbtt_int32 l=0, r=glyphCount-1, m;
|
||||
int straw, needle=glyph;
|
||||
while (l <= r) {
|
||||
stbtt_uint8 *glyphArray = coverageTable + 4;
|
||||
stbtt_uint16 glyphID;
|
||||
m = (l + r) >> 1;
|
||||
glyphID = ttUSHORT(glyphArray + 2 * m);
|
||||
straw = glyphID;
|
||||
if (needle < straw)
|
||||
r = m - 1;
|
||||
else if (needle > straw)
|
||||
l = m + 1;
|
||||
else {
|
||||
return m;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
||||
stbtt_uint8 *rangeArray = coverageTable + 4;
|
||||
case 2: {
|
||||
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
||||
stbtt_uint8 *rangeArray = coverageTable + 4;
|
||||
|
||||
// Binary search.
|
||||
stbtt_int32 l=0, r=rangeCount-1, m;
|
||||
int strawStart, strawEnd, needle=glyph;
|
||||
while (l <= r) {
|
||||
stbtt_uint8 *rangeRecord;
|
||||
m = (l + r) >> 1;
|
||||
rangeRecord = rangeArray + 6 * m;
|
||||
strawStart = ttUSHORT(rangeRecord);
|
||||
strawEnd = ttUSHORT(rangeRecord + 2);
|
||||
if (needle < strawStart)
|
||||
r = m - 1;
|
||||
else if (needle > strawEnd)
|
||||
l = m + 1;
|
||||
else {
|
||||
stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
|
||||
return startCoverageIndex + glyph - strawStart;
|
||||
}
|
||||
// Binary search.
|
||||
stbtt_int32 l=0, r=rangeCount-1, m;
|
||||
int strawStart, strawEnd, needle=glyph;
|
||||
while (l <= r) {
|
||||
stbtt_uint8 *rangeRecord;
|
||||
m = (l + r) >> 1;
|
||||
rangeRecord = rangeArray + 6 * m;
|
||||
strawStart = ttUSHORT(rangeRecord);
|
||||
strawEnd = ttUSHORT(rangeRecord + 2);
|
||||
if (needle < strawStart)
|
||||
r = m - 1;
|
||||
else if (needle > strawEnd)
|
||||
l = m + 1;
|
||||
else {
|
||||
stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
|
||||
return startCoverageIndex + glyph - strawStart;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// There are no other cases.
|
||||
STBTT_assert(0);
|
||||
} break;
|
||||
}
|
||||
default: return -1; // unsupported
|
||||
}
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
||||
{
|
||||
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
||||
switch(classDefFormat)
|
||||
{
|
||||
case 1: {
|
||||
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
||||
stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
|
||||
stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
|
||||
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
||||
switch (classDefFormat)
|
||||
{
|
||||
case 1: {
|
||||
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
||||
stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
|
||||
stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
|
||||
|
||||
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
||||
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
||||
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
||||
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
||||
break;
|
||||
}
|
||||
|
||||
classDefTable = classDef1ValueArray + 2 * glyphCount;
|
||||
} break;
|
||||
case 2: {
|
||||
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
||||
stbtt_uint8 *classRangeRecords = classDefTable + 4;
|
||||
|
||||
case 2: {
|
||||
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
||||
stbtt_uint8 *classRangeRecords = classDefTable + 4;
|
||||
// Binary search.
|
||||
stbtt_int32 l=0, r=classRangeCount-1, m;
|
||||
int strawStart, strawEnd, needle=glyph;
|
||||
while (l <= r) {
|
||||
stbtt_uint8 *classRangeRecord;
|
||||
m = (l + r) >> 1;
|
||||
classRangeRecord = classRangeRecords + 6 * m;
|
||||
strawStart = ttUSHORT(classRangeRecord);
|
||||
strawEnd = ttUSHORT(classRangeRecord + 2);
|
||||
if (needle < strawStart)
|
||||
r = m - 1;
|
||||
else if (needle > strawEnd)
|
||||
l = m + 1;
|
||||
else
|
||||
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Binary search.
|
||||
stbtt_int32 l=0, r=classRangeCount-1, m;
|
||||
int strawStart, strawEnd, needle=glyph;
|
||||
while (l <= r) {
|
||||
stbtt_uint8 *classRangeRecord;
|
||||
m = (l + r) >> 1;
|
||||
classRangeRecord = classRangeRecords + 6 * m;
|
||||
strawStart = ttUSHORT(classRangeRecord);
|
||||
strawEnd = ttUSHORT(classRangeRecord + 2);
|
||||
if (needle < strawStart)
|
||||
r = m - 1;
|
||||
else if (needle > strawEnd)
|
||||
l = m + 1;
|
||||
else
|
||||
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
||||
}
|
||||
default:
|
||||
return -1; // Unsupported definition type, return an error.
|
||||
}
|
||||
|
||||
classDefTable = classRangeRecords + 6 * classRangeCount;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// There are no other cases.
|
||||
STBTT_assert(0);
|
||||
} break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
// "All glyphs not assigned to a class fall into class 0". (OpenType spec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Define to STBTT_assert(x) if you want to break on unimplemented formats.
|
||||
#define STBTT_GPOS_TODO_assert(x)
|
||||
|
||||
static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||
static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||
{
|
||||
stbtt_uint16 lookupListOffset;
|
||||
stbtt_uint8 *lookupList;
|
||||
stbtt_uint16 lookupCount;
|
||||
stbtt_uint8 *data;
|
||||
stbtt_int32 i;
|
||||
stbtt_uint16 lookupListOffset;
|
||||
stbtt_uint8 *lookupList;
|
||||
stbtt_uint16 lookupCount;
|
||||
stbtt_uint8 *data;
|
||||
stbtt_int32 i, sti;
|
||||
|
||||
if (!info->gpos) return 0;
|
||||
if (!info->gpos) return 0;
|
||||
|
||||
data = info->data + info->gpos;
|
||||
data = info->data + info->gpos;
|
||||
|
||||
if (ttUSHORT(data+0) != 1) return 0; // Major version 1
|
||||
if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
|
||||
if (ttUSHORT(data+0) != 1) return 0; // Major version 1
|
||||
if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
|
||||
|
||||
lookupListOffset = ttUSHORT(data+8);
|
||||
lookupList = data + lookupListOffset;
|
||||
lookupCount = ttUSHORT(lookupList);
|
||||
lookupListOffset = ttUSHORT(data+8);
|
||||
lookupList = data + lookupListOffset;
|
||||
lookupCount = ttUSHORT(lookupList);
|
||||
|
||||
for (i=0; i<lookupCount; ++i) {
|
||||
stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
|
||||
stbtt_uint8 *lookupTable = lookupList + lookupOffset;
|
||||
for (i=0; i<lookupCount; ++i) {
|
||||
stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
|
||||
stbtt_uint8 *lookupTable = lookupList + lookupOffset;
|
||||
|
||||
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
||||
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
||||
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
||||
switch(lookupType) {
|
||||
case 2: { // Pair Adjustment Positioning Subtable
|
||||
stbtt_int32 sti;
|
||||
for (sti=0; sti<subTableCount; sti++) {
|
||||
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
||||
stbtt_uint8 *table = lookupTable + subtableOffset;
|
||||
stbtt_uint16 posFormat = ttUSHORT(table);
|
||||
stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
|
||||
stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
|
||||
if (coverageIndex == -1) continue;
|
||||
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
||||
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
||||
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
||||
if (lookupType != 2) // Pair Adjustment Positioning Subtable
|
||||
continue;
|
||||
|
||||
switch (posFormat) {
|
||||
case 1: {
|
||||
stbtt_int32 l, r, m;
|
||||
int straw, needle;
|
||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
||||
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
||||
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
||||
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
||||
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
||||
stbtt_uint8 *pairValueArray = pairValueTable + 2;
|
||||
// TODO: Support more formats.
|
||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
||||
if (valueFormat1 != 4) return 0;
|
||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
||||
if (valueFormat2 != 0) return 0;
|
||||
for (sti=0; sti<subTableCount; sti++) {
|
||||
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
||||
stbtt_uint8 *table = lookupTable + subtableOffset;
|
||||
stbtt_uint16 posFormat = ttUSHORT(table);
|
||||
stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
|
||||
stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
|
||||
if (coverageIndex == -1) continue;
|
||||
|
||||
STBTT_assert(coverageIndex < pairSetCount);
|
||||
STBTT__NOTUSED(pairSetCount);
|
||||
switch (posFormat) {
|
||||
case 1: {
|
||||
stbtt_int32 l, r, m;
|
||||
int straw, needle;
|
||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
||||
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
||||
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
||||
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
||||
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
||||
stbtt_uint8 *pairValueArray = pairValueTable + 2;
|
||||
|
||||
needle=glyph2;
|
||||
r=pairValueCount-1;
|
||||
l=0;
|
||||
if (coverageIndex >= pairSetCount) return 0;
|
||||
|
||||
// Binary search.
|
||||
while (l <= r) {
|
||||
stbtt_uint16 secondGlyph;
|
||||
stbtt_uint8 *pairValue;
|
||||
m = (l + r) >> 1;
|
||||
pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
|
||||
secondGlyph = ttUSHORT(pairValue);
|
||||
straw = secondGlyph;
|
||||
if (needle < straw)
|
||||
r = m - 1;
|
||||
else if (needle > straw)
|
||||
l = m + 1;
|
||||
else {
|
||||
stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
|
||||
return xAdvance;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
needle=glyph2;
|
||||
r=pairValueCount-1;
|
||||
l=0;
|
||||
|
||||
case 2: {
|
||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||
// Binary search.
|
||||
while (l <= r) {
|
||||
stbtt_uint16 secondGlyph;
|
||||
stbtt_uint8 *pairValue;
|
||||
m = (l + r) >> 1;
|
||||
pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
|
||||
secondGlyph = ttUSHORT(pairValue);
|
||||
straw = secondGlyph;
|
||||
if (needle < straw)
|
||||
r = m - 1;
|
||||
else if (needle > straw)
|
||||
l = m + 1;
|
||||
else {
|
||||
stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
|
||||
return xAdvance;
|
||||
}
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
||||
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
||||
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
||||
int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
|
||||
case 2: {
|
||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
||||
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
||||
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
||||
int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
|
||||
|
||||
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
||||
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
||||
STBTT_assert(glyph1class < class1Count);
|
||||
STBTT_assert(glyph2class < class2Count);
|
||||
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
||||
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
||||
stbtt_uint8 *class1Records, *class2Records;
|
||||
stbtt_int16 xAdvance;
|
||||
|
||||
// TODO: Support more formats.
|
||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
||||
if (valueFormat1 != 4) return 0;
|
||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
||||
if (valueFormat2 != 0) return 0;
|
||||
if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
|
||||
if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
|
||||
|
||||
if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
|
||||
stbtt_uint8 *class1Records = table + 16;
|
||||
stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
|
||||
stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
||||
return xAdvance;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// There are no other cases.
|
||||
STBTT_assert(0);
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
class1Records = table + 16;
|
||||
class2Records = class1Records + 2 * (glyph1class * class2Count);
|
||||
xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
||||
return xAdvance;
|
||||
} else
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: Implement other stuff.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0; // Unsupported position format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
|
||||
@ -3075,6 +3062,23 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg
|
||||
}
|
||||
}
|
||||
|
||||
static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
|
||||
{
|
||||
STBTT_assert(top_width >= 0);
|
||||
STBTT_assert(bottom_width >= 0);
|
||||
return (top_width + bottom_width) / 2.0f * height;
|
||||
}
|
||||
|
||||
static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
|
||||
{
|
||||
return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
|
||||
}
|
||||
|
||||
static float stbtt__sized_triangle_area(float height, float width)
|
||||
{
|
||||
return height * width / 2;
|
||||
}
|
||||
|
||||
static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
|
||||
{
|
||||
float y_bottom = y_top+1;
|
||||
@ -3129,13 +3133,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
||||
float height;
|
||||
// simple case, only spans one pixel
|
||||
int x = (int) x_top;
|
||||
height = sy1 - sy0;
|
||||
height = (sy1 - sy0) * e->direction;
|
||||
STBTT_assert(x >= 0 && x < len);
|
||||
scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
|
||||
scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
|
||||
scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
|
||||
scanline_fill[x] += height; // everything right of this pixel is filled
|
||||
} else {
|
||||
int x,x1,x2;
|
||||
float y_crossing, step, sign, area;
|
||||
float y_crossing, y_final, step, sign, area;
|
||||
// covers 2+ pixels
|
||||
if (x_top > x_bottom) {
|
||||
// flip scanline vertically; signed area is the same
|
||||
@ -3148,29 +3152,79 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
||||
dy = -dy;
|
||||
t = x0, x0 = xb, xb = t;
|
||||
}
|
||||
STBTT_assert(dy >= 0);
|
||||
STBTT_assert(dx >= 0);
|
||||
|
||||
x1 = (int) x_top;
|
||||
x2 = (int) x_bottom;
|
||||
// compute intersection with y axis at x1+1
|
||||
y_crossing = (x1+1 - x0) * dy + y_top;
|
||||
y_crossing = y_top + dy * (x1+1 - x0);
|
||||
|
||||
// compute intersection with y axis at x2
|
||||
y_final = y_top + dy * (x2 - x0);
|
||||
|
||||
// x1 x_top x2 x_bottom
|
||||
// y_top +------|-----+------------+------------+--------|---+------------+
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// sy0 | Txxxxx|............|............|............|............|
|
||||
// y_crossing | *xxxxx.......|............|............|............|
|
||||
// | | xxxxx..|............|............|............|
|
||||
// | | /- xx*xxxx........|............|............|
|
||||
// | | dy < | xxxxxx..|............|............|
|
||||
// y_final | | \- | xx*xxx.........|............|
|
||||
// sy1 | | | | xxxxxB...|............|
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// y_bottom +------------+------------+------------+------------+------------+
|
||||
//
|
||||
// goal is to measure the area covered by '.' in each pixel
|
||||
|
||||
// if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
|
||||
// @TODO: maybe test against sy1 rather than y_bottom?
|
||||
if (y_crossing > y_bottom)
|
||||
y_crossing = y_bottom;
|
||||
|
||||
sign = e->direction;
|
||||
// area of the rectangle covered from y0..y_crossing
|
||||
area = sign * (y_crossing-sy0);
|
||||
// area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
|
||||
scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
|
||||
|
||||
step = sign * dy;
|
||||
// area of the rectangle covered from sy0..y_crossing
|
||||
area = sign * (y_crossing-sy0);
|
||||
|
||||
// area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
|
||||
scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
|
||||
|
||||
// check if final y_crossing is blown up; no test case for this
|
||||
if (y_final > y_bottom) {
|
||||
y_final = y_bottom;
|
||||
dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
|
||||
}
|
||||
|
||||
// in second pixel, area covered by line segment found in first pixel
|
||||
// is always a rectangle 1 wide * the height of that line segment; this
|
||||
// is exactly what the variable 'area' stores. it also gets a contribution
|
||||
// from the line segment within it. the THIRD pixel will get the first
|
||||
// pixel's rectangle contribution, the second pixel's rectangle contribution,
|
||||
// and its own contribution. the 'own contribution' is the same in every pixel except
|
||||
// the leftmost and rightmost, a trapezoid that slides down in each pixel.
|
||||
// the second pixel's contribution to the third pixel will be the
|
||||
// rectangle 1 wide times the height change in the second pixel, which is dy.
|
||||
|
||||
step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
|
||||
// which multiplied by 1-pixel-width is how much pixel area changes for each step in x
|
||||
// so the area advances by 'step' every time
|
||||
|
||||
for (x = x1+1; x < x2; ++x) {
|
||||
scanline[x] += area + step/2;
|
||||
scanline[x] += area + step/2; // area of trapezoid is 1*step/2
|
||||
area += step;
|
||||
}
|
||||
y_crossing += dy * (x2 - (x1+1));
|
||||
STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
|
||||
STBTT_assert(sy1 > y_final-0.01f);
|
||||
|
||||
STBTT_assert(STBTT_fabs(area) <= 1.01f);
|
||||
|
||||
scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
|
||||
// area covered in the last pixel is the rectangle from all the pixels to the left,
|
||||
// plus the trapezoid filled by the line segment in this pixel all the way to the right edge
|
||||
scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
|
||||
|
||||
// the rest of the line is filled based on the total height of the line segment in this pixel
|
||||
scanline_fill[x2] += sign * (sy1-sy0);
|
||||
}
|
||||
} else {
|
||||
@ -3178,6 +3232,9 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
||||
// clipping logic. since this does not match the intended use
|
||||
// of this library, we use a different, very slow brute
|
||||
// force implementation
|
||||
// note though that this does happen some of the time because
|
||||
// x_top and x_bottom can be extrapolated at the top & bottom of
|
||||
// the shape and actually lie outside the bounding box
|
||||
int x;
|
||||
for (x=0; x < len; ++x) {
|
||||
// cases:
|
||||
@ -4414,15 +4471,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
|
||||
float y_frac;
|
||||
int winding = 0;
|
||||
|
||||
orig[0] = x;
|
||||
orig[1] = y;
|
||||
|
||||
// make sure y never passes through a vertex of the shape
|
||||
y_frac = (float) STBTT_fmod(y, 1.0f);
|
||||
if (y_frac < 0.01f)
|
||||
y += 0.01f;
|
||||
else if (y_frac > 0.99f)
|
||||
y -= 0.01f;
|
||||
|
||||
orig[0] = x;
|
||||
orig[1] = y;
|
||||
|
||||
// test a ray from (-infinity,y) to (x,y)
|
||||
@ -4484,35 +4540,35 @@ static float stbtt__cuberoot( float x )
|
||||
return (float) STBTT_pow( x,1.0f/3.0f);
|
||||
}
|
||||
|
||||
// x^3 + c*x^2 + b*x + a = 0
|
||||
// x^3 + a*x^2 + b*x + c = 0
|
||||
static int stbtt__solve_cubic(float a, float b, float c, float* r)
|
||||
{
|
||||
float s = -a / 3;
|
||||
float p = b - a*a / 3;
|
||||
float q = a * (2*a*a - 9*b) / 27 + c;
|
||||
float s = -a / 3;
|
||||
float p = b - a*a / 3;
|
||||
float q = a * (2*a*a - 9*b) / 27 + c;
|
||||
float p3 = p*p*p;
|
||||
float d = q*q + 4*p3 / 27;
|
||||
if (d >= 0) {
|
||||
float z = (float) STBTT_sqrt(d);
|
||||
float u = (-q + z) / 2;
|
||||
float v = (-q - z) / 2;
|
||||
u = stbtt__cuberoot(u);
|
||||
v = stbtt__cuberoot(v);
|
||||
r[0] = s + u + v;
|
||||
return 1;
|
||||
} else {
|
||||
float u = (float) STBTT_sqrt(-p/3);
|
||||
float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
|
||||
float m = (float) STBTT_cos(v);
|
||||
float d = q*q + 4*p3 / 27;
|
||||
if (d >= 0) {
|
||||
float z = (float) STBTT_sqrt(d);
|
||||
float u = (-q + z) / 2;
|
||||
float v = (-q - z) / 2;
|
||||
u = stbtt__cuberoot(u);
|
||||
v = stbtt__cuberoot(v);
|
||||
r[0] = s + u + v;
|
||||
return 1;
|
||||
} else {
|
||||
float u = (float) STBTT_sqrt(-p/3);
|
||||
float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
|
||||
float m = (float) STBTT_cos(v);
|
||||
float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
|
||||
r[0] = s + u * 2 * m;
|
||||
r[1] = s - u * (m + n);
|
||||
r[2] = s - u * (m - n);
|
||||
r[0] = s + u * 2 * m;
|
||||
r[1] = s - u * (m + n);
|
||||
r[2] = s - u * (m - n);
|
||||
|
||||
//STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
|
||||
//STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
|
||||
//STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
|
||||
return 3;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4589,18 +4645,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||
for (i=0; i < num_verts; ++i) {
|
||||
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
||||
|
||||
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
|
||||
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (dist2 < min_dist*min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
|
||||
if (verts[i].type == STBTT_vline) {
|
||||
if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
|
||||
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
||||
|
||||
float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (dist2 < min_dist*min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
|
||||
// coarse culling against bbox
|
||||
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
|
||||
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
|
||||
float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
||||
dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
|
||||
STBTT_assert(i != 0);
|
||||
if (dist < min_dist) {
|
||||
// check position along line
|
||||
@ -4627,7 +4682,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||
float ax = x1-x0, ay = y1-y0;
|
||||
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
||||
float mx = x0 - sx, my = y0 - sy;
|
||||
float res[3],px,py,t,it;
|
||||
float res[3] = {0.f,0.f,0.f};
|
||||
float px,py,t,it,dist2;
|
||||
float a_inv = precompute[i];
|
||||
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
|
||||
float a = 3*(ax*bx + ay*by);
|
||||
@ -4654,6 +4710,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||
float d = (mx*ax+my*ay) * a_inv;
|
||||
num = stbtt__solve_cubic(b, c, d, res);
|
||||
}
|
||||
dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
||||
if (dist2 < min_dist*min_dist)
|
||||
min_dist = (float) STBTT_sqrt(dist2);
|
||||
|
||||
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
|
||||
t = res[0], it = 1.0f - t;
|
||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
||||
@ -4913,6 +4973,12 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
|
||||
|
||||
// FULL VERSION HISTORY
|
||||
//
|
||||
// 1.25 (2021-07-11) many fixes
|
||||
// 1.24 (2020-02-05) fix warning
|
||||
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
||||
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||
// 1.21 (2019-02-25) fix warning
|
||||
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
||||
// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
|
||||
// 1.18 (2018-01-29) add missing function
|
||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||
|
1680
thirdparty/sokol/sokol_app.h
vendored
1680
thirdparty/sokol/sokol_app.h
vendored
File diff suppressed because it is too large
Load Diff
327
thirdparty/sokol/sokol_audio.h
vendored
327
thirdparty/sokol/sokol_audio.h
vendored
@ -17,9 +17,6 @@
|
||||
|
||||
SOKOL_DUMMY_BACKEND - use a dummy backend
|
||||
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
||||
SOKOL_LOG(msg) - your own logging function (default: puts(msg))
|
||||
SOKOL_MALLOC(s) - your own malloc() implementation (default: malloc(s))
|
||||
SOKOL_FREE(p) - your own free() implementation (default: free(p))
|
||||
SOKOL_AUDIO_API_DECL- public function declaration prefix (default: extern)
|
||||
SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL
|
||||
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
||||
@ -316,6 +313,8 @@
|
||||
|
||||
"Blob URLs": https://www.html5rocks.com/en/tutorials/workers/basics/
|
||||
|
||||
Also see: https://blog.paul.cx/post/a-wait-free-spsc-ringbuffer-for-the-web/
|
||||
|
||||
THE COREAUDIO BACKEND
|
||||
=====================
|
||||
The CoreAudio backend is selected on macOS and iOS (__APPLE__ is defined).
|
||||
@ -365,6 +364,62 @@
|
||||
header must be present (usually both are installed with some sort
|
||||
of ALSA development package).
|
||||
|
||||
|
||||
MEMORY ALLOCATION OVERRIDE
|
||||
==========================
|
||||
You can override the memory allocation functions at initialization time
|
||||
like this:
|
||||
|
||||
void* my_alloc(size_t size, void* user_data) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void my_free(void* ptr, void* user_data) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
...
|
||||
saudio_setup(&(saudio_desc){
|
||||
// ...
|
||||
.allocator = {
|
||||
.alloc = my_alloc,
|
||||
.free = my_free,
|
||||
.user_data = ...,
|
||||
}
|
||||
});
|
||||
...
|
||||
|
||||
If no overrides are provided, malloc and free will be used.
|
||||
|
||||
This only affects memory allocation calls done by sokol_audio.h
|
||||
itself though, not any allocations in OS libraries.
|
||||
|
||||
Memory allocation will only happen on the same thread where saudio_setup()
|
||||
was called, so you don't need to worry about thread-safety.
|
||||
|
||||
|
||||
LOG FUNCTION OVERRIDE
|
||||
=====================
|
||||
You can override the log function at initialization time like this:
|
||||
|
||||
void my_log(const char* message, void* user_data) {
|
||||
printf("saudio says: \s\n", message);
|
||||
}
|
||||
|
||||
...
|
||||
saudio_setup(&(saudio_desc){
|
||||
// ...
|
||||
.logger = {
|
||||
.log_cb = my_log,
|
||||
.user_data = ...,
|
||||
}
|
||||
});
|
||||
...
|
||||
|
||||
If no overrides are provided, puts will be used on most platforms.
|
||||
On Android, __android_log_write will be used instead.
|
||||
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
|
||||
@ -392,6 +447,7 @@
|
||||
distribution.
|
||||
*/
|
||||
#define SOKOL_AUDIO_INCLUDED (1)
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -412,15 +468,42 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
saudio_allocator
|
||||
|
||||
Used in saudio_desc to provide custom memory-alloc and -free functions
|
||||
to sokol_audio.h. If memory management should be overridden, both the
|
||||
alloc and free function must be provided (e.g. it's not valid to
|
||||
override one function but not the other).
|
||||
*/
|
||||
typedef struct saudio_allocator {
|
||||
void* (*alloc)(size_t size, void* user_data);
|
||||
void (*free)(void* ptr, void* user_data);
|
||||
void* user_data;
|
||||
} saudio_allocator;
|
||||
|
||||
/*
|
||||
saudio_logger
|
||||
|
||||
Used in saudio_desc to provide custom log callbacks to sokol_audio.h.
|
||||
Default behavior is SOKOL_LOG(message).
|
||||
*/
|
||||
typedef struct saudio_logger {
|
||||
void (*log_cb)(const char* message, void* user_data);
|
||||
void* user_data;
|
||||
} saudio_logger;
|
||||
|
||||
typedef struct saudio_desc {
|
||||
int sample_rate; /* requested sample rate */
|
||||
int num_channels; /* number of channels, default: 1 (mono) */
|
||||
int buffer_frames; /* number of frames in streaming buffer */
|
||||
int packet_frames; /* number of frames in a packet */
|
||||
int num_packets; /* number of packets in packet queue */
|
||||
void (*stream_cb)(float* buffer, int num_frames, int num_channels); /* optional streaming callback (no user data) */
|
||||
void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); /*... and with user data */
|
||||
void* user_data; /* optional user data argument for stream_userdata_cb */
|
||||
int sample_rate; // requested sample rate
|
||||
int num_channels; // number of channels, default: 1 (mono)
|
||||
int buffer_frames; // number of frames in streaming buffer
|
||||
int packet_frames; // number of frames in a packet
|
||||
int num_packets; // number of packets in packet queue
|
||||
void (*stream_cb)(float* buffer, int num_frames, int num_channels); // optional streaming callback (no user data)
|
||||
void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); //... and with user data
|
||||
void* user_data; // optional user data argument for stream_userdata_cb
|
||||
saudio_allocator allocator; // optional allocation override functions
|
||||
saudio_logger logger; // optional log override functions
|
||||
} saudio_desc;
|
||||
|
||||
/* setup sokol-audio */
|
||||
@ -458,6 +541,12 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
||||
/*=== IMPLEMENTATION =========================================================*/
|
||||
#ifdef SOKOL_AUDIO_IMPL
|
||||
#define SOKOL_AUDIO_IMPL_INCLUDED (1)
|
||||
|
||||
#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
|
||||
#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use saudio_desc.allocator to override memory allocation functions"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // alloc, free
|
||||
#include <string.h> // memset, memcpy
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
@ -466,24 +555,26 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
||||
#endif
|
||||
#ifndef SOKOL_DEBUG
|
||||
#ifndef NDEBUG
|
||||
#define SOKOL_DEBUG (1)
|
||||
#define SOKOL_DEBUG
|
||||
#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)
|
||||
|
||||
#if !defined(SOKOL_DEBUG)
|
||||
#define SAUDIO_LOG(s)
|
||||
#else
|
||||
#define SAUDIO_LOG(s) _saudio_log(s)
|
||||
#ifndef SOKOL_LOG
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#define SOKOL_LOG(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_AUDIO", s)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define SOKOL_LOG(s) puts(s)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -670,6 +761,9 @@ typedef OSStatus _saudio_OSStatus;
|
||||
#define _saudio_kAudioFormatFlagIsPacked (kAudioFormatFlagIsPacked)
|
||||
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// embedded AudioToolbox declarations
|
||||
typedef uint32_t _saudio_AudioFormatID;
|
||||
@ -745,6 +839,11 @@ extern _saudio_OSStatus AudioQueueAllocateBuffer(_saudio_AudioQueueRef inAQ, uin
|
||||
extern _saudio_OSStatus AudioQueueEnqueueBuffer(_saudio_AudioQueueRef inAQ, _saudio_AudioQueueBufferRef inBuffer, uint32_t inNumPacketDescs, const _saudio_AudioStreamPacketDescription* inPacketDescs);
|
||||
extern _saudio_OSStatus AudioQueueStart(_saudio_AudioQueueRef inAQ, const _saudio_AudioTimeStamp * inStartTime);
|
||||
extern _saudio_OSStatus AudioQueueStop(_saudio_AudioQueueRef inAQ, bool inImmediate);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SAUDIO_OSX_USE_SYSTEM_HEADERS
|
||||
|
||||
typedef struct {
|
||||
@ -893,6 +992,51 @@ _SOKOL_PRIVATE void _saudio_stream_callback(float* buffer, int num_frames, int n
|
||||
}
|
||||
}
|
||||
|
||||
/*=== MEMORY HELPERS ========================================================*/
|
||||
_SOKOL_PRIVATE void _saudio_clear(void* ptr, size_t size) {
|
||||
SOKOL_ASSERT(ptr && (size > 0));
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void* _saudio_malloc(size_t size) {
|
||||
SOKOL_ASSERT(size > 0);
|
||||
void* ptr;
|
||||
if (_saudio.desc.allocator.alloc) {
|
||||
ptr = _saudio.desc.allocator.alloc(size, _saudio.desc.allocator.user_data);
|
||||
}
|
||||
else {
|
||||
ptr = malloc(size);
|
||||
}
|
||||
SOKOL_ASSERT(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void* _saudio_malloc_clear(size_t size) {
|
||||
void* ptr = _saudio_malloc(size);
|
||||
_saudio_clear(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _saudio_free(void* ptr) {
|
||||
if (_saudio.desc.allocator.free) {
|
||||
_saudio.desc.allocator.free(ptr, _saudio.desc.allocator.user_data);
|
||||
}
|
||||
else {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SOKOL_DEBUG)
|
||||
_SOKOL_PRIVATE void _saudio_log(const char* msg) {
|
||||
SOKOL_ASSERT(msg);
|
||||
if (_saudio.desc.logger.log_cb) {
|
||||
_saudio.desc.logger.log_cb(msg, _saudio.desc.logger.user_data);
|
||||
} else {
|
||||
SOKOL_LOG(msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*=== MUTEX IMPLEMENTATION ===================================================*/
|
||||
#if defined(_SAUDIO_NOTHREADS)
|
||||
|
||||
@ -1003,8 +1147,7 @@ _SOKOL_PRIVATE void _saudio_fifo_init(_saudio_fifo_t* fifo, int packet_size, int
|
||||
SOKOL_ASSERT((packet_size > 0) && (num_packets > 0));
|
||||
fifo->packet_size = packet_size;
|
||||
fifo->num_packets = num_packets;
|
||||
fifo->base_ptr = (uint8_t*) SOKOL_MALLOC((size_t)(packet_size * num_packets));
|
||||
SOKOL_ASSERT(fifo->base_ptr);
|
||||
fifo->base_ptr = (uint8_t*) _saudio_malloc((size_t)(packet_size * num_packets));
|
||||
fifo->cur_packet = -1;
|
||||
fifo->cur_offset = 0;
|
||||
_saudio_ring_init(&fifo->read_queue, num_packets);
|
||||
@ -1022,7 +1165,7 @@ _SOKOL_PRIVATE void _saudio_fifo_init(_saudio_fifo_t* fifo, int packet_size, int
|
||||
|
||||
_SOKOL_PRIVATE void _saudio_fifo_shutdown(_saudio_fifo_t* fifo) {
|
||||
SOKOL_ASSERT(fifo->base_ptr);
|
||||
SOKOL_FREE(fifo->base_ptr);
|
||||
_saudio_free(fifo->base_ptr);
|
||||
fifo->base_ptr = 0;
|
||||
fifo->valid = false;
|
||||
_saudio_mutex_destroy(&fifo->mutex);
|
||||
@ -1191,7 +1334,7 @@ _SOKOL_PRIVATE void _saudio_coreaudio_callback(void* user_data, _saudio_AudioQue
|
||||
int num_bytes = (int) buffer->mAudioDataByteSize;
|
||||
if (0 == _saudio_fifo_read(&_saudio.fifo, ptr, num_bytes)) {
|
||||
/* not enough read data available, fill the entire buffer with silence */
|
||||
memset(ptr, 0, (size_t)num_bytes);
|
||||
_saudio_clear(ptr, (size_t)num_bytes);
|
||||
}
|
||||
}
|
||||
AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
|
||||
@ -1213,7 +1356,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
|
||||
/* create an audio queue with fp32 samples */
|
||||
_saudio_AudioStreamBasicDescription fmt;
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
_saudio_clear(&fmt, sizeof(fmt));
|
||||
fmt.mSampleRate = (double) _saudio.sample_rate;
|
||||
fmt.mFormatID = _saudio_kAudioFormatLinearPCM;
|
||||
fmt.mFormatFlags = _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked;
|
||||
@ -1223,16 +1366,16 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
fmt.mBytesPerPacket = fmt.mBytesPerFrame;
|
||||
fmt.mBitsPerChannel = 32;
|
||||
_saudio_OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue);
|
||||
SOKOL_ASSERT((res == 0) && _saudio.backend.ca_audio_queue);
|
||||
SOKOL_ASSERT((res == 0) && _saudio.backend.ca_audio_queue); (void)res;
|
||||
|
||||
/* create 2 audio buffers */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
_saudio_AudioQueueBufferRef buf = NULL;
|
||||
const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame;
|
||||
res = AudioQueueAllocateBuffer(_saudio.backend.ca_audio_queue, buf_byte_size, &buf);
|
||||
SOKOL_ASSERT((res == 0) && buf);
|
||||
SOKOL_ASSERT((res == 0) && buf); (void)res;
|
||||
buf->mAudioDataByteSize = buf_byte_size;
|
||||
memset(buf->mAudioData, 0, buf->mAudioDataByteSize);
|
||||
_saudio_clear(buf->mAudioData, buf->mAudioDataByteSize);
|
||||
AudioQueueEnqueueBuffer(_saudio.backend.ca_audio_queue, buf, 0, NULL);
|
||||
}
|
||||
|
||||
@ -1241,7 +1384,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
|
||||
/* ...and start playback */
|
||||
res = AudioQueueStart(_saudio.backend.ca_audio_queue, NULL);
|
||||
SOKOL_ASSERT(0 == res);
|
||||
SOKOL_ASSERT(0 == res); (void)res;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1284,7 +1427,7 @@ _SOKOL_PRIVATE void* _saudio_alsa_cb(void* param) {
|
||||
else {
|
||||
if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) {
|
||||
/* not enough read data available, fill the entire buffer with silence */
|
||||
memset(_saudio.backend.buffer, 0, (size_t)_saudio.backend.buffer_byte_size);
|
||||
_saudio_clear(_saudio.backend.buffer, (size_t)_saudio.backend.buffer_byte_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1296,7 +1439,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
int dir; uint32_t rate;
|
||||
int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if (rc < 0) {
|
||||
SOKOL_LOG("sokol_audio.h: snd_pcm_open() failed");
|
||||
SAUDIO_LOG("sokol_audio.h: snd_pcm_open() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1309,26 +1452,26 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
snd_pcm_hw_params_any(_saudio.backend.device, params);
|
||||
snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (0 > snd_pcm_hw_params_set_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) {
|
||||
SOKOL_LOG("sokol_audio.h: float samples not supported");
|
||||
SAUDIO_LOG("sokol_audio.h: float samples not supported");
|
||||
goto error;
|
||||
}
|
||||
if (0 > snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, (snd_pcm_uframes_t)_saudio.buffer_frames)) {
|
||||
SOKOL_LOG("sokol_audio.h: requested buffer size not supported");
|
||||
SAUDIO_LOG("sokol_audio.h: requested buffer size not supported");
|
||||
goto error;
|
||||
}
|
||||
if (0 > snd_pcm_hw_params_set_channels(_saudio.backend.device, params, (uint32_t)_saudio.num_channels)) {
|
||||
SOKOL_LOG("sokol_audio.h: requested channel count not supported");
|
||||
SAUDIO_LOG("sokol_audio.h: requested channel count not supported");
|
||||
goto error;
|
||||
}
|
||||
/* let ALSA pick a nearby sampling rate */
|
||||
rate = (uint32_t) _saudio.sample_rate;
|
||||
dir = 0;
|
||||
if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &rate, &dir)) {
|
||||
SOKOL_LOG("sokol_audio.h: snd_pcm_hw_params_set_rate_near() failed");
|
||||
SAUDIO_LOG("sokol_audio.h: snd_pcm_hw_params_set_rate_near() failed");
|
||||
goto error;
|
||||
}
|
||||
if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) {
|
||||
SOKOL_LOG("sokol_audio.h: snd_pcm_hw_params() failed");
|
||||
SAUDIO_LOG("sokol_audio.h: snd_pcm_hw_params() failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1339,12 +1482,11 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
/* allocate the streaming buffer */
|
||||
_saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame;
|
||||
_saudio.backend.buffer_frames = _saudio.buffer_frames;
|
||||
_saudio.backend.buffer = (float*) SOKOL_MALLOC((size_t)_saudio.backend.buffer_byte_size);
|
||||
memset(_saudio.backend.buffer, 0, (size_t)_saudio.backend.buffer_byte_size);
|
||||
_saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size);
|
||||
|
||||
/* create the buffer-streaming start thread */
|
||||
if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_alsa_cb, 0)) {
|
||||
SOKOL_LOG("sokol_audio.h: pthread_create() failed");
|
||||
SAUDIO_LOG("sokol_audio.h: pthread_create() failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1363,7 +1505,7 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
|
||||
pthread_join(_saudio.backend.thread, 0);
|
||||
snd_pcm_drain(_saudio.backend.device);
|
||||
snd_pcm_close(_saudio.backend.device);
|
||||
SOKOL_FREE(_saudio.backend.buffer);
|
||||
_saudio_free(_saudio.backend.buffer);
|
||||
};
|
||||
|
||||
/*=== WASAPI BACKEND IMPLEMENTATION ==========================================*/
|
||||
@ -1419,7 +1561,7 @@ _SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) {
|
||||
else {
|
||||
if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.thread.src_buffer, _saudio.backend.thread.src_buffer_byte_size)) {
|
||||
/* not enough read data available, fill the entire buffer with silence */
|
||||
memset(_saudio.backend.thread.src_buffer, 0, (size_t)_saudio.backend.thread.src_buffer_byte_size);
|
||||
_saudio_clear(_saudio.backend.thread.src_buffer, (size_t)_saudio.backend.thread.src_buffer_byte_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1487,7 +1629,7 @@ _SOKOL_PRIVATE DWORD WINAPI _saudio_wasapi_thread_fn(LPVOID param) {
|
||||
|
||||
_SOKOL_PRIVATE void _saudio_wasapi_release(void) {
|
||||
if (_saudio.backend.thread.src_buffer) {
|
||||
SOKOL_FREE(_saudio.backend.thread.src_buffer);
|
||||
_saudio_free(_saudio.backend.thread.src_buffer);
|
||||
_saudio.backend.thread.src_buffer = 0;
|
||||
}
|
||||
if (_saudio.backend.render_client) {
|
||||
@ -1537,17 +1679,17 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
#endif
|
||||
_saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0);
|
||||
if (0 == _saudio.backend.thread.buffer_end_event) {
|
||||
SOKOL_LOG("sokol_audio wasapi: failed to create buffer_end_event");
|
||||
SAUDIO_LOG("sokol_audio wasapi: failed to create buffer_end_event");
|
||||
goto error;
|
||||
}
|
||||
#if defined(_SAUDIO_UWP)
|
||||
_saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex");
|
||||
if (_saudio.backend.interface_activation_mutex == NULL) {
|
||||
SOKOL_LOG("sokol_audio wasapi: failed to create interface activation mutex");
|
||||
SAUDIO_LOG("sokol_audio wasapi: failed to create interface activation mutex");
|
||||
goto error;
|
||||
}
|
||||
if (FAILED(StringFromIID(_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_Devinterface_Audio_Render), &_saudio.backend.interface_activation_audio_interface_uid_string))) {
|
||||
SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string");
|
||||
SAUDIO_LOG("sokol_audio wasapi: failed to get default audio device ID string");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1561,7 +1703,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
static IActivateAudioInterfaceCompletionHandler completion_handler_interface = { &completion_handler_interface_vtable };
|
||||
|
||||
if (FAILED(ActivateAudioInterfaceAsync(_saudio.backend.interface_activation_audio_interface_uid_string, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), NULL, &completion_handler_interface, &_saudio.backend.interface_activation_operation))) {
|
||||
SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string");
|
||||
SAUDIO_LOG("sokol_audio wasapi: failed to get default audio device ID string");
|
||||
goto error;
|
||||
}
|
||||
while (!(_saudio.backend.audio_client)) {
|
||||
@ -1571,7 +1713,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
}
|
||||
|
||||
if (!(_saudio.backend.interface_activation_success)) {
|
||||
SOKOL_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client");
|
||||
SAUDIO_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1581,14 +1723,14 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator),
|
||||
(void**)&_saudio.backend.device_enumerator)))
|
||||
{
|
||||
SOKOL_LOG("sokol_audio wasapi: failed to create device enumerator");
|
||||
SAUDIO_LOG("sokol_audio wasapi: failed to create device enumerator");
|
||||
goto error;
|
||||
}
|
||||
if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator,
|
||||
eRender, eConsole,
|
||||
&_saudio.backend.device)))
|
||||
{
|
||||
SOKOL_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed");
|
||||
goto error;
|
||||
}
|
||||
if (FAILED(IMMDevice_Activate(_saudio.backend.device,
|
||||
@ -1596,13 +1738,13 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
CLSCTX_ALL, 0,
|
||||
(void**)&_saudio.backend.audio_client)))
|
||||
{
|
||||
SOKOL_LOG("sokol_audio wasapi: device activate failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: device activate failed");
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
WAVEFORMATEXTENSIBLE fmtex;
|
||||
memset(&fmtex, 0, sizeof(fmtex));
|
||||
_saudio_clear(&fmtex, sizeof(fmtex));
|
||||
fmtex.Format.nChannels = (WORD)_saudio.num_channels;
|
||||
fmtex.Format.nSamplesPerSec = (DWORD)_saudio.sample_rate;
|
||||
fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
@ -1625,22 +1767,22 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK|AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
|
||||
dur, 0, (WAVEFORMATEX*)&fmtex, 0)))
|
||||
{
|
||||
SOKOL_LOG("sokol_audio wasapi: audio client initialize failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: audio client initialize failed");
|
||||
goto error;
|
||||
}
|
||||
if (FAILED(IAudioClient_GetBufferSize(_saudio.backend.audio_client, &_saudio.backend.thread.dst_buffer_frames))) {
|
||||
SOKOL_LOG("sokol_audio wasapi: audio client get buffer size failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: audio client get buffer size failed");
|
||||
goto error;
|
||||
}
|
||||
if (FAILED(IAudioClient_GetService(_saudio.backend.audio_client,
|
||||
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioRenderClient),
|
||||
(void**)&_saudio.backend.render_client)))
|
||||
{
|
||||
SOKOL_LOG("sokol_audio wasapi: audio client GetService failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: audio client GetService failed");
|
||||
goto error;
|
||||
}
|
||||
if (FAILED(IAudioClient_SetEventHandle(_saudio.backend.audio_client, _saudio.backend.thread.buffer_end_event))) {
|
||||
SOKOL_LOG("sokol_audio wasapi: audio client SetEventHandle failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: audio client SetEventHandle failed");
|
||||
goto error;
|
||||
}
|
||||
_saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
|
||||
@ -1648,13 +1790,12 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
_saudio.backend.thread.src_buffer_byte_size = _saudio.backend.thread.src_buffer_frames * _saudio.bytes_per_frame;
|
||||
|
||||
/* allocate an intermediate buffer for sample format conversion */
|
||||
_saudio.backend.thread.src_buffer = (float*) SOKOL_MALLOC((size_t)_saudio.backend.thread.src_buffer_byte_size);
|
||||
SOKOL_ASSERT(_saudio.backend.thread.src_buffer);
|
||||
_saudio.backend.thread.src_buffer = (float*) _saudio_malloc((size_t)_saudio.backend.thread.src_buffer_byte_size);
|
||||
|
||||
/* create streaming thread */
|
||||
_saudio.backend.thread.thread_handle = CreateThread(NULL, 0, _saudio_wasapi_thread_fn, 0, 0, 0);
|
||||
if (0 == _saudio.backend.thread.thread_handle) {
|
||||
SOKOL_LOG("sokol_audio wasapi: CreateThread failed");
|
||||
SAUDIO_LOG("sokol_audio wasapi: CreateThread failed");
|
||||
goto error;
|
||||
}
|
||||
return true;
|
||||
@ -1698,7 +1839,7 @@ EMSCRIPTEN_KEEPALIVE int _saudio_emsc_pull(int num_frames) {
|
||||
const int num_bytes = num_frames * _saudio.bytes_per_frame;
|
||||
if (0 == _saudio_fifo_read(&_saudio.fifo, _saudio.backend.buffer, num_bytes)) {
|
||||
/* not enough read data available, fill the entire buffer with silence */
|
||||
memset(_saudio.backend.buffer, 0, (size_t)num_bytes);
|
||||
_saudio_clear(_saudio.backend.buffer, (size_t)num_bytes);
|
||||
}
|
||||
}
|
||||
int res = (int) _saudio.backend.buffer;
|
||||
@ -1723,12 +1864,6 @@ EM_JS(int, saudio_js_init, (int sample_rate, int num_channels, int buffer_size),
|
||||
latencyHint: 'interactive',
|
||||
});
|
||||
}
|
||||
else if (typeof webkitAudioContext !== 'undefined') {
|
||||
Module._saudio_context = new webkitAudioContext({
|
||||
sampleRate: sample_rate,
|
||||
latencyHint: 'interactive',
|
||||
});
|
||||
}
|
||||
else {
|
||||
Module._saudio_context = null;
|
||||
console.log('sokol_audio.h: no WebAudio support');
|
||||
@ -1736,14 +1871,14 @@ EM_JS(int, saudio_js_init, (int sample_rate, int num_channels, int buffer_size),
|
||||
if (Module._saudio_context) {
|
||||
console.log('sokol_audio.h: sample rate ', Module._saudio_context.sampleRate);
|
||||
Module._saudio_node = Module._saudio_context.createScriptProcessor(buffer_size, 0, num_channels);
|
||||
Module._saudio_node.onaudioprocess = function pump_audio(event) {
|
||||
var num_frames = event.outputBuffer.length;
|
||||
var ptr = __saudio_emsc_pull(num_frames);
|
||||
Module._saudio_node.onaudioprocess = (event) => {
|
||||
const num_frames = event.outputBuffer.length;
|
||||
const ptr = __saudio_emsc_pull(num_frames);
|
||||
if (ptr) {
|
||||
var num_channels = event.outputBuffer.numberOfChannels;
|
||||
for (var chn = 0; chn < num_channels; chn++) {
|
||||
var chan = event.outputBuffer.getChannelData(chn);
|
||||
for (var i = 0; i < num_frames; i++) {
|
||||
const num_channels = event.outputBuffer.numberOfChannels;
|
||||
for (let chn = 0; chn < num_channels; chn++) {
|
||||
const chan = event.outputBuffer.getChannelData(chn);
|
||||
for (let i = 0; i < num_frames; i++) {
|
||||
chan[i] = HEAPF32[(ptr>>2) + ((num_channels*i)+chn)]
|
||||
}
|
||||
}
|
||||
@ -1752,7 +1887,7 @@ EM_JS(int, saudio_js_init, (int sample_rate, int num_channels, int buffer_size),
|
||||
Module._saudio_node.connect(Module._saudio_context.destination);
|
||||
|
||||
// in some browsers, WebAudio needs to be activated on a user action
|
||||
var resume_webaudio = function() {
|
||||
const resume_webaudio = () => {
|
||||
if (Module._saudio_context) {
|
||||
if (Module._saudio_context.state === 'suspended') {
|
||||
Module._saudio_context.resume();
|
||||
@ -1771,11 +1906,13 @@ EM_JS(int, saudio_js_init, (int sample_rate, int num_channels, int buffer_size),
|
||||
|
||||
/* shutdown the WebAudioContext and ScriptProcessorNode */
|
||||
EM_JS(void, saudio_js_shutdown, (void), {
|
||||
if (Module._saudio_context !== null) {
|
||||
\x2F\x2A\x2A @suppress {missingProperties} \x2A\x2F
|
||||
const ctx = Module._saudio_context;
|
||||
if (ctx !== null) {
|
||||
if (Module._saudio_node) {
|
||||
Module._saudio_node.disconnect();
|
||||
}
|
||||
Module._saudio_context.close();
|
||||
ctx.close();
|
||||
Module._saudio_context = null;
|
||||
Module._saudio_node = null;
|
||||
}
|
||||
@ -1819,7 +1956,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
_saudio.sample_rate = saudio_js_sample_rate();
|
||||
_saudio.buffer_frames = saudio_js_buffer_frames();
|
||||
const size_t buf_size = (size_t) (_saudio.buffer_frames * _saudio.bytes_per_frame);
|
||||
_saudio.backend.buffer = (uint8_t*) SOKOL_MALLOC(buf_size);
|
||||
_saudio.backend.buffer = (uint8_t*) _saudio_malloc(buf_size);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -1830,7 +1967,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
_SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
|
||||
saudio_js_shutdown();
|
||||
if (_saudio.backend.buffer) {
|
||||
SOKOL_FREE(_saudio.backend.buffer);
|
||||
_saudio_free(_saudio.backend.buffer);
|
||||
_saudio.backend.buffer = 0;
|
||||
}
|
||||
}
|
||||
@ -1904,7 +2041,7 @@ _SOKOL_PRIVATE void _saudio_opensles_fill_buffer(void) {
|
||||
const int src_buffer_byte_size = src_buffer_frames * _saudio.num_channels * (int)sizeof(float);
|
||||
if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.src_buffer, src_buffer_byte_size)) {
|
||||
/* not enough read data available, fill the entire buffer with silence */
|
||||
memset(_saudio.backend.src_buffer, 0x0, (size_t)src_buffer_byte_size);
|
||||
_saudio_clear(_saudio.backend.src_buffer, (size_t)src_buffer_byte_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1919,6 +2056,7 @@ _SOKOL_PRIVATE void SLAPIENTRY _saudio_opensles_play_cb(SLPlayItf player, void *
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void* _saudio_opensles_thread_fn(void* param) {
|
||||
_SOKOL_UNUSED(param);
|
||||
while (!_saudio.backend.thread_stop) {
|
||||
/* get next output buffer, advance, next buffer. */
|
||||
int16_t* out_buffer = _saudio.backend.output_buffers[_saudio.backend.active_buffer];
|
||||
@ -1959,9 +2097,9 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
|
||||
}
|
||||
|
||||
for (int i = 0; i < SAUDIO_NUM_BUFFERS; i++) {
|
||||
SOKOL_FREE(_saudio.backend.output_buffers[i]);
|
||||
_saudio_free(_saudio.backend.output_buffers[i]);
|
||||
}
|
||||
SOKOL_FREE(_saudio.backend.src_buffer);
|
||||
_saudio_free(_saudio.backend.src_buffer);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
@ -1969,29 +2107,25 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
|
||||
for (int i = 0; i < SAUDIO_NUM_BUFFERS; ++i) {
|
||||
const int buffer_size_bytes = (int)sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames;
|
||||
_saudio.backend.output_buffers[i] = (int16_t*) SOKOL_MALLOC((size_t)buffer_size_bytes);
|
||||
SOKOL_ASSERT(_saudio.backend.output_buffers[i]);
|
||||
memset(_saudio.backend.output_buffers[i], 0x0, (size_t)buffer_size_bytes);
|
||||
_saudio.backend.output_buffers[i] = (int16_t*) _saudio_malloc_clear((size_t)buffer_size_bytes);
|
||||
}
|
||||
|
||||
{
|
||||
const int buffer_size_bytes = _saudio.bytes_per_frame * _saudio.buffer_frames;
|
||||
_saudio.backend.src_buffer = (float*) SOKOL_MALLOC((size_t)buffer_size_bytes);
|
||||
SOKOL_ASSERT(_saudio.backend.src_buffer);
|
||||
memset(_saudio.backend.src_buffer, 0x0, (size_t)buffer_size_bytes);
|
||||
_saudio.backend.src_buffer = (float*) _saudio_malloc_clear((size_t)buffer_size_bytes);
|
||||
}
|
||||
|
||||
/* Create engine */
|
||||
const SLEngineOption opts[] = { SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE };
|
||||
const SLEngineOption opts[] = { { SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } };
|
||||
if (slCreateEngine(&_saudio.backend.engine_obj, 1, opts, 0, NULL, NULL ) != SL_RESULT_SUCCESS) {
|
||||
SOKOL_LOG("sokol_audio opensles: slCreateEngine failed");
|
||||
SAUDIO_LOG("sokol_audio opensles: slCreateEngine failed");
|
||||
_saudio_backend_shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
(*_saudio.backend.engine_obj)->Realize(_saudio.backend.engine_obj, SL_BOOLEAN_FALSE);
|
||||
if ((*_saudio.backend.engine_obj)->GetInterface(_saudio.backend.engine_obj, SL_IID_ENGINE, &_saudio.backend.engine) != SL_RESULT_SUCCESS) {
|
||||
SOKOL_LOG("sokol_audio opensles: GetInterface->Engine failed");
|
||||
SAUDIO_LOG("sokol_audio opensles: GetInterface->Engine failed");
|
||||
_saudio_backend_shutdown();
|
||||
return false;
|
||||
}
|
||||
@ -2003,14 +2137,14 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
|
||||
if( (*_saudio.backend.engine)->CreateOutputMix(_saudio.backend.engine, &_saudio.backend.output_mix_obj, 1, ids, req) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
SOKOL_LOG("sokol_audio opensles: CreateOutputMix failed");
|
||||
SAUDIO_LOG("sokol_audio opensles: CreateOutputMix failed");
|
||||
_saudio_backend_shutdown();
|
||||
return false;
|
||||
}
|
||||
(*_saudio.backend.output_mix_obj)->Realize(_saudio.backend.output_mix_obj, SL_BOOLEAN_FALSE);
|
||||
|
||||
if((*_saudio.backend.output_mix_obj)->GetInterface(_saudio.backend.output_mix_obj, SL_IID_VOLUME, &_saudio.backend.output_mix_vol) != SL_RESULT_SUCCESS) {
|
||||
SOKOL_LOG("sokol_audio opensles: GetInterface->OutputMixVol failed");
|
||||
SAUDIO_LOG("sokol_audio opensles: GetInterface->OutputMixVol failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2091,7 +2225,8 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||
SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
||||
SOKOL_ASSERT(!_saudio.valid);
|
||||
SOKOL_ASSERT(desc);
|
||||
memset(&_saudio, 0, sizeof(_saudio));
|
||||
SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free));
|
||||
_saudio_clear(&_saudio, sizeof(_saudio));
|
||||
_saudio.desc = *desc;
|
||||
_saudio.stream_cb = desc->stream_cb;
|
||||
_saudio.stream_userdata_cb = desc->stream_userdata_cb;
|
||||
@ -2108,7 +2243,7 @@ SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
||||
the requested packet size
|
||||
*/
|
||||
if (0 != (_saudio.buffer_frames % _saudio.packet_frames)) {
|
||||
SOKOL_LOG("sokol_audio.h: actual backend buffer size isn't multiple of requested packet size");
|
||||
SAUDIO_LOG("sokol_audio.h: actual backend buffer size isn't multiple of requested packet size");
|
||||
_saudio_backend_shutdown();
|
||||
return;
|
||||
}
|
||||
|
1888
thirdparty/sokol/sokol_gfx.h
vendored
1888
thirdparty/sokol/sokol_gfx.h
vendored
File diff suppressed because it is too large
Load Diff
192
thirdparty/sokol/util/sokol_fontstash.h
vendored
192
thirdparty/sokol/util/sokol_fontstash.h
vendored
@ -28,12 +28,9 @@
|
||||
...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_FONTSTASH_API_DECL - public function declaration prefix (default: extern)
|
||||
SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL
|
||||
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:
|
||||
@ -55,7 +52,10 @@
|
||||
--- 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);
|
||||
FONScontext* ctx = sfons_create(&(sfons_desc_t){
|
||||
.width = atlas_width,
|
||||
.height = atlas_height,
|
||||
});
|
||||
|
||||
Each FONScontext manages one font atlas texture which can hold rasterized
|
||||
glyphs for multiple fonts.
|
||||
@ -88,7 +88,7 @@
|
||||
|
||||
--- finally on application shutdown, call:
|
||||
|
||||
sfons_shutdown()
|
||||
sfons_destroy(FONScontext* ctx)
|
||||
|
||||
before sgl_shutdown() and sg_shutdown()
|
||||
|
||||
@ -96,7 +96,7 @@
|
||||
WHAT HAPPENS UNDER THE HOOD:
|
||||
============================
|
||||
|
||||
sfons_create():
|
||||
FONScontext* sfons_create(const sfons_desc_t* desc)
|
||||
- creates a sokol-gfx shader compatible with sokol-gl
|
||||
- creates an sgl_pipeline object with alpha-blending using
|
||||
this shader
|
||||
@ -122,14 +122,43 @@
|
||||
all calls to fonsDrawText() will be merged into a single draw call
|
||||
as long as all calls use the same FONScontext
|
||||
|
||||
sfons_flush():
|
||||
sfons_flush(FONScontext* ctx):
|
||||
- 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():
|
||||
sfons_destroy(FONScontext* ctx):
|
||||
- destroy the font atlas texture, sgl_pipeline and sg_shader objects
|
||||
|
||||
|
||||
MEMORY ALLOCATION OVERRIDE
|
||||
==========================
|
||||
You can override the memory allocation functions at initialization time
|
||||
like this:
|
||||
|
||||
void* my_alloc(size_t size, void* user_data) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void my_free(void* ptr, void* user_data) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
...
|
||||
FONScontext* fons_context = sfons_create(&(sfons_desc_t){
|
||||
...
|
||||
.allocator = {
|
||||
.alloc = my_alloc,
|
||||
.free = my_free,
|
||||
.user_data = ...,
|
||||
}
|
||||
});
|
||||
...
|
||||
|
||||
If no overrides are provided, malloc and free will be used. Please
|
||||
note that this doesn't affect any memory allocation performed
|
||||
in fontstash.h (unfortunately those are hardwired to malloc/free).
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
zlib/libpng license
|
||||
@ -158,6 +187,7 @@
|
||||
#define SOKOL_FONTSTASH_INCLUDED (1)
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h> // size_t
|
||||
|
||||
#if !defined(SOKOL_GFX_INCLUDED)
|
||||
#error "Please include sokol_gfx.h before sokol_fontstash.h"
|
||||
@ -179,7 +209,30 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SOKOL_FONTSTASH_API_DECL FONScontext* sfons_create(int width, int height, int flags);
|
||||
/*
|
||||
sfonst_allocator_t
|
||||
|
||||
Used in sfons_desc_t to provide custom memory-alloc and -free functions
|
||||
to sokol_fontstash.h. If memory management should be overridden, both the
|
||||
alloc and free function must be provided (e.g. it's not valid to
|
||||
override one function but not the other).
|
||||
|
||||
NOTE that this does not affect memory allocation calls inside
|
||||
fontstash.h
|
||||
*/
|
||||
typedef struct sfons_allocator_t {
|
||||
void* (*alloc)(size_t size, void* user_data);
|
||||
void (*free)(void* ptr, void* user_data);
|
||||
void* user_data;
|
||||
} sfons_allocator_t;
|
||||
|
||||
typedef struct sfons_desc_t {
|
||||
int width; // initial width of font atlas texture (default: 512, must be power of 2)
|
||||
int height; // initial height of font atlas texture (default: 512, must be power of 2)
|
||||
sfons_allocator_t allocator; // optional memory allocation overrides
|
||||
} sfons_desc_t;
|
||||
|
||||
SOKOL_FONTSTASH_API_DECL FONScontext* sfons_create(const sfons_desc_t* desc);
|
||||
SOKOL_FONTSTASH_API_DECL void sfons_destroy(FONScontext* ctx);
|
||||
SOKOL_FONTSTASH_API_DECL void sfons_flush(FONScontext* ctx);
|
||||
SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
@ -192,7 +245,13 @@ SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, ui
|
||||
/*-- IMPLEMENTATION ----------------------------------------------------------*/
|
||||
#ifdef SOKOL_FONTSTASH_IMPL
|
||||
#define SOKOL_FONTSTASH_IMPL_INCLUDED (1)
|
||||
#include <string.h> /* memset, memcpy */
|
||||
|
||||
#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
|
||||
#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sfons_desc_t.allocator to override memory allocation functions"
|
||||
#endif
|
||||
|
||||
#include <string.h> // memset, memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
|
||||
#if !defined(SOKOL_GL_INCLUDED)
|
||||
#error "Please include sokol_gl.h before sokol_fontstash.h"
|
||||
@ -206,26 +265,13 @@ SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, ui
|
||||
#endif
|
||||
#ifndef SOKOL_DEBUG
|
||||
#ifndef NDEBUG
|
||||
#define SOKOL_DEBUG (1)
|
||||
#define SOKOL_DEBUG
|
||||
#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
|
||||
@ -1609,13 +1655,48 @@ static const char* _sfons_fs_source_dummy = "";
|
||||
#endif
|
||||
|
||||
typedef struct _sfons_t {
|
||||
sfons_desc_t desc;
|
||||
sg_shader shd;
|
||||
sgl_pipeline pip;
|
||||
sg_image img;
|
||||
int width, height;
|
||||
int cur_width, cur_height;
|
||||
bool img_dirty;
|
||||
} _sfons_t;
|
||||
|
||||
static void _sfons_clear(void* ptr, size_t size) {
|
||||
SOKOL_ASSERT(ptr && (size > 0));
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
static void* _sfons_malloc(const sfons_allocator_t* allocator, size_t size) {
|
||||
SOKOL_ASSERT(allocator && (size > 0));
|
||||
void* ptr;
|
||||
if (allocator->alloc) {
|
||||
ptr = allocator->alloc(size, allocator->user_data);
|
||||
}
|
||||
else {
|
||||
ptr = malloc(size);
|
||||
}
|
||||
SOKOL_ASSERT(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void* _sfons_malloc_clear(const sfons_allocator_t* allocator, size_t size) {
|
||||
void* ptr = _sfons_malloc(allocator, size);
|
||||
_sfons_clear(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void _sfons_free(const sfons_allocator_t* allocator, void* ptr) {
|
||||
SOKOL_ASSERT(allocator);
|
||||
if (allocator->free) {
|
||||
allocator->free(ptr, allocator->user_data);
|
||||
}
|
||||
else {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1623,7 +1704,7 @@ static int _sfons_render_create(void* user_ptr, int width, int height) {
|
||||
/* 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));
|
||||
_sfons_clear(&shd_desc, sizeof(shd_desc));
|
||||
shd_desc.attrs[0].name = "position";
|
||||
shd_desc.attrs[1].name = "texcoord0";
|
||||
shd_desc.attrs[2].name = "color0";
|
||||
@ -1687,7 +1768,7 @@ static int _sfons_render_create(void* user_ptr, int width, int height) {
|
||||
/* sokol-gl pipeline object */
|
||||
if (sfons->pip.id == SG_INVALID_ID) {
|
||||
sg_pipeline_desc pip_desc;
|
||||
memset(&pip_desc, 0, sizeof(pip_desc));
|
||||
_sfons_clear(&pip_desc, sizeof(pip_desc));
|
||||
pip_desc.shader = sfons->shd;
|
||||
pip_desc.colors[0].blend.enabled = true;
|
||||
pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
|
||||
@ -1700,14 +1781,14 @@ static int _sfons_render_create(void* user_ptr, int width, int height) {
|
||||
sg_destroy_image(sfons->img);
|
||||
sfons->img.id = SG_INVALID_ID;
|
||||
}
|
||||
sfons->width = width;
|
||||
sfons->height = height;
|
||||
sfons->cur_width = width;
|
||||
sfons->cur_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;
|
||||
_sfons_clear(&img_desc, sizeof(img_desc));
|
||||
img_desc.width = sfons->cur_width;
|
||||
img_desc.height = sfons->cur_height;
|
||||
img_desc.min_filter = SG_FILTER_LINEAR;
|
||||
img_desc.mag_filter = SG_FILTER_LINEAR;
|
||||
img_desc.usage = SG_USAGE_DYNAMIC;
|
||||
@ -1759,42 +1840,43 @@ static void _sfons_render_delete(void* user_ptr) {
|
||||
sg_destroy_shader(sfons->shd);
|
||||
sfons->shd.id = SG_INVALID_ID;
|
||||
}
|
||||
SOKOL_FREE(sfons);
|
||||
}
|
||||
|
||||
// NOTE clang analyzer will report a potential memory leak for the call
|
||||
// to SOKOL_MALLOC in the sfons_create() function, this is a false positive
|
||||
// (the freeing happens in _sfons_render_delete()). The following macro
|
||||
// silences the false positive when compilation happens with the analyzer active
|
||||
#if __clang_analyzer__
|
||||
#define _SFONS_CLANG_ANALYZER_SILENCE_POTENTIAL_LEAK_FALSE_POSITIVE(x) SOKOL_FREE(x)
|
||||
#else
|
||||
#define _SFONS_CLANG_ANALYZER_SILENCE_POTENTIAL_LEAK_FALSE_POSITIVE(x)
|
||||
#endif
|
||||
#define _sfons_def(val, def) (((val) == 0) ? (def) : (val))
|
||||
|
||||
SOKOL_API_IMPL FONScontext* sfons_create(int width, int height, int flags) {
|
||||
SOKOL_ASSERT((width > 0) && (height > 0));
|
||||
static sfons_desc_t _sfons_desc_defaults(const sfons_desc_t* desc) {
|
||||
SOKOL_ASSERT(desc);
|
||||
sfons_desc_t res = *desc;
|
||||
res.width = _sfons_def(res.width, 512);
|
||||
res.height = _sfons_def(res.height, 512);
|
||||
return res;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL FONScontext* sfons_create(const sfons_desc_t* desc) {
|
||||
SOKOL_ASSERT(desc);
|
||||
SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free));
|
||||
_sfons_t* sfons = (_sfons_t*) _sfons_malloc_clear(&desc->allocator, sizeof(_sfons_t));
|
||||
sfons->desc = _sfons_desc_defaults(desc);
|
||||
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;
|
||||
_sfons_clear(¶ms, sizeof(params));
|
||||
params.width = sfons->desc.width;
|
||||
params.height = sfons->desc.height;
|
||||
params.flags = FONS_ZERO_TOPLEFT;
|
||||
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;
|
||||
FONScontext* ctx = fonsCreateInternal(¶ms);
|
||||
_SFONS_CLANG_ANALYZER_SILENCE_POTENTIAL_LEAK_FALSE_POSITIVE(sfons);
|
||||
return ctx;
|
||||
return fonsCreateInternal(¶ms);
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) {
|
||||
SOKOL_ASSERT(ctx);
|
||||
_sfons_t* sfons = (_sfons_t*) ctx->params.userPtr;
|
||||
fonsDeleteInternal(ctx);
|
||||
const sfons_allocator_t allocator = sfons->desc.allocator;
|
||||
_sfons_free(&allocator, sfons);
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) {
|
||||
@ -1803,9 +1885,9 @@ SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) {
|
||||
if (sfons->img_dirty) {
|
||||
sfons->img_dirty = false;
|
||||
sg_image_data data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
_sfons_clear(&data, sizeof(data));
|
||||
data.subimage[0][0].ptr = ctx->texData;
|
||||
data.subimage[0][0].size = (size_t) (sfons->width * sfons->height);
|
||||
data.subimage[0][0].size = (size_t) (sfons->cur_width * sfons->cur_height);
|
||||
sg_update_image(sfons->img, &data);
|
||||
}
|
||||
}
|
||||
|
484
thirdparty/sokol/util/sokol_gl.h
vendored
484
thirdparty/sokol/util/sokol_gl.h
vendored
@ -27,12 +27,9 @@
|
||||
...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_GL_API_DECL - public function declaration prefix (default: extern)
|
||||
SOKOL_API_DECL - same as SOKOL_GL_API_DECL
|
||||
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))
|
||||
|
||||
If sokol_gl.h is compiled as a DLL, define the following before
|
||||
@ -382,6 +379,32 @@
|
||||
...if sokol-gl is in an error-state, sgl_draw() will skip any rendering,
|
||||
and reset the error code to SGL_NO_ERROR.
|
||||
|
||||
RENDER LAYERS
|
||||
=============
|
||||
Render layers allow to split sokol-gl rendering into separate draw-command
|
||||
groups which can then be rendered separately in a sokol-gfx draw pass. This
|
||||
allows to mix/interleave sokol-gl rendering with other render operations.
|
||||
|
||||
Layered rendering is controlled through two functions:
|
||||
|
||||
sgl_layer(int layer_id)
|
||||
sgl_draw_layer(int layer_id)
|
||||
|
||||
(and the context-variant sgl_draw_layer(): sgl_context_draw_layer()
|
||||
|
||||
The sgl_layer() function sets the 'current layer', any sokol-gl calls
|
||||
which internally record draw commands will also store the current layer
|
||||
in the draw command, and later in a sokol-gfx render pass, a call
|
||||
to sgl_draw_layer() will only render the draw commands that have
|
||||
a matching layer.
|
||||
|
||||
The default layer is '0', this is active after sokol-gl setup, and
|
||||
is also restored at the start of a new frame (but *not* by calling
|
||||
sgl_defaults()).
|
||||
|
||||
NOTE that calling sgl_draw() is equivalent with sgl_draw_layer(0)
|
||||
(in general you should either use either use sgl_draw() or
|
||||
sgl_draw_layer() in an application, but not both).
|
||||
|
||||
WORKING WITH CONTEXTS:
|
||||
======================
|
||||
@ -466,7 +489,7 @@
|
||||
The only functions which call into sokol_gfx.h are:
|
||||
- sgl_setup()
|
||||
- sgl_shutdown()
|
||||
- sgl_draw()
|
||||
- sgl_draw() (and variants)
|
||||
|
||||
sgl_setup() must be called after initializing sokol-gfx.
|
||||
sgl_shutdown() must be called before shutting down sokol-gfx.
|
||||
@ -511,10 +534,13 @@
|
||||
all pipeline objects) are destroyed
|
||||
- the 3 memory buffers are freed
|
||||
|
||||
sgl_draw():
|
||||
sgl_draw() (and variants)
|
||||
- copy all recorded vertex data into the dynamic sokol-gfx buffer
|
||||
via a call to sg_update_buffer()
|
||||
- for each recorded command:
|
||||
- if the layer number stored in the command doesn't match
|
||||
the layer that's to be rendered, skip to the next
|
||||
command
|
||||
- if it's a viewport command, call sg_apply_viewport()
|
||||
- if it's a scissor-rect command, call sg_apply_scissor_rect()
|
||||
- if it's a draw command:
|
||||
@ -536,10 +562,11 @@
|
||||
A draw command will be merged with the previous command if "no relevant
|
||||
state has changed" since the last sgl_end(), meaning:
|
||||
|
||||
- no calls to sgl_apply_viewport() and sgl_apply_scissor_rect()
|
||||
- no calls to sgl_viewport() and sgl_scissor_rect()
|
||||
- the primitive type hasn't changed
|
||||
- the primitive type isn't a 'strip type' (no line or triangle strip)
|
||||
- the pipeline state object hasn't changed
|
||||
- the current layer hasn't changed
|
||||
- none of the matrices has changed
|
||||
- none of the texture state has changed
|
||||
|
||||
@ -547,6 +574,55 @@
|
||||
to render in the previous draw command will be incremented by the
|
||||
number of vertices in the new draw command.
|
||||
|
||||
MEMORY ALLOCATION OVERRIDE
|
||||
==========================
|
||||
You can override the memory allocation functions at initialization time
|
||||
like this:
|
||||
|
||||
void* my_alloc(size_t size, void* user_data) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void my_free(void* ptr, void* user_data) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
...
|
||||
sgl_setup(&(sgl_desc_t){
|
||||
// ...
|
||||
.allocator = {
|
||||
.alloc = my_alloc,
|
||||
.free = my_free,
|
||||
.user_data = ...;
|
||||
}
|
||||
});
|
||||
...
|
||||
|
||||
If no overrides are provided, malloc and free will be used.
|
||||
|
||||
|
||||
LOG FUNCTION OVERRIDE
|
||||
=====================
|
||||
You can override the log function at initialization time like this:
|
||||
|
||||
void my_log(const char* message, void* user_data) {
|
||||
printf("sgl says: \s\n", message);
|
||||
}
|
||||
|
||||
...
|
||||
sgl_setup(&(sgl_desc_t){
|
||||
// ...
|
||||
.logger = {
|
||||
.log_cb = my_log,
|
||||
.user_data = ...,
|
||||
}
|
||||
});
|
||||
...
|
||||
|
||||
If no overrides are provided, puts will be used on most platforms.
|
||||
On Android, __android_log_write will be used instead.
|
||||
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
zlib/libpng license
|
||||
@ -575,6 +651,7 @@
|
||||
#define SOKOL_GL_INCLUDED (1)
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h> // size_t, offsetof
|
||||
|
||||
#if !defined(SOKOL_GFX_INCLUDED)
|
||||
#error "Please include sokol_gfx.h before sokol_gl.h"
|
||||
@ -634,6 +711,31 @@ typedef struct sgl_context_desc_t {
|
||||
int sample_count;
|
||||
} sgl_context_desc_t;
|
||||
|
||||
/*
|
||||
sgl_allocator_t
|
||||
|
||||
Used in sgl_desc_t to provide custom memory-alloc and -free functions
|
||||
to sokol_gl.h. If memory management should be overridden, both the
|
||||
alloc and free function must be provided (e.g. it's not valid to
|
||||
override one function but not the other).
|
||||
*/
|
||||
typedef struct sgl_allocator_t {
|
||||
void* (*alloc)(size_t size, void* user_data);
|
||||
void (*free)(void* ptr, void* user_data);
|
||||
void* user_data;
|
||||
} sgl_allocator_t;
|
||||
|
||||
/*
|
||||
sgl_logger_t
|
||||
|
||||
Used in sgl_desc_t to provide custom log callbacks to sokol_gl.h.
|
||||
Default behavior is SOKOL_LOG(message).
|
||||
*/
|
||||
typedef struct sgl_logger_t {
|
||||
void (*log_cb)(const char* message, void* user_data);
|
||||
void* user_data;
|
||||
} sgl_logger_t;
|
||||
|
||||
typedef struct sgl_desc_t {
|
||||
int max_vertices; // default: 64k
|
||||
int max_commands; // default: 16k
|
||||
@ -643,6 +745,8 @@ typedef struct sgl_desc_t {
|
||||
sg_pixel_format depth_format;
|
||||
int sample_count;
|
||||
sg_face_winding face_winding; // default: SG_FACEWINDING_CCW
|
||||
sgl_allocator_t allocator; // optional memory allocation overrides (default: malloc/free)
|
||||
sgl_logger_t logger; // optional memory allocation overrides (default: SOKOL_LOG(message))
|
||||
} sgl_desc_t;
|
||||
|
||||
/* the default context handle */
|
||||
@ -663,6 +767,12 @@ SOKOL_GL_API_DECL void sgl_set_context(sgl_context ctx);
|
||||
SOKOL_GL_API_DECL sgl_context sgl_get_context(void);
|
||||
SOKOL_GL_API_DECL sgl_context sgl_default_context(void);
|
||||
|
||||
/* draw recorded commands (call inside a sokol-gfx render pass) */
|
||||
SOKOL_GL_API_DECL void sgl_draw();
|
||||
SOKOL_GL_API_DECL void sgl_context_draw(sgl_context ctx);
|
||||
SOKOL_GL_API_DECL void sgl_draw_layer(int layer_id);
|
||||
SOKOL_GL_API_DECL void sgl_context_draw_layer(sgl_context ctx, int layer_id);
|
||||
|
||||
/* create and destroy pipeline objects */
|
||||
SOKOL_GL_API_DECL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc);
|
||||
SOKOL_GL_API_DECL sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc* desc);
|
||||
@ -677,6 +787,7 @@ SOKOL_GL_API_DECL void sgl_scissor_rectf(float x, float y, float w, float h, boo
|
||||
SOKOL_GL_API_DECL void sgl_enable_texture(void);
|
||||
SOKOL_GL_API_DECL void sgl_disable_texture(void);
|
||||
SOKOL_GL_API_DECL void sgl_texture(sg_image img);
|
||||
SOKOL_GL_API_DECL void sgl_layer(int layer_id);
|
||||
|
||||
/* pipeline stack functions */
|
||||
SOKOL_GL_API_DECL void sgl_load_default_pipeline(void);
|
||||
@ -745,10 +856,6 @@ SOKOL_GL_API_DECL void sgl_v3f_t2f_c4b(float x, float y, float z, float u, float
|
||||
SOKOL_GL_API_DECL void sgl_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba);
|
||||
SOKOL_GL_API_DECL void sgl_end(void);
|
||||
|
||||
/* render recorded commands */
|
||||
SOKOL_GL_API_DECL void sgl_draw();
|
||||
SOKOL_GL_API_DECL void sgl_context_draw(sgl_context ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@ -764,9 +871,13 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline
|
||||
#ifdef SOKOL_GL_IMPL
|
||||
#define SOKOL_GL_IMPL_INCLUDED (1)
|
||||
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <string.h> /* memset */
|
||||
#include <math.h> /* M_PI, sqrtf, sinf, cosf */
|
||||
#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
|
||||
#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sgl_desc_t.allocator to override memory allocation functions"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // malloc/free
|
||||
#include <string.h> // memset
|
||||
#include <math.h> // M_PI, sqrtf, sinf, cosf
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
@ -777,29 +888,28 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline
|
||||
#endif
|
||||
#ifndef SOKOL_DEBUG
|
||||
#ifndef NDEBUG
|
||||
#define SOKOL_DEBUG (1)
|
||||
#define SOKOL_DEBUG
|
||||
#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)
|
||||
|
||||
#if !defined(SOKOL_DEBUG)
|
||||
#define SGL_LOG(s)
|
||||
#else
|
||||
#define SGL_LOG(s) _sgl_log(s)
|
||||
#ifndef SOKOL_LOG
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#define SOKOL_LOG(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_GL", s)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define SOKOL_LOG(s) puts(s)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef SOKOL_UNREACHABLE
|
||||
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
|
||||
#endif
|
||||
|
||||
#define _sgl_def(val, def) (((val) == 0) ? (def) : (val))
|
||||
#define _SGL_INIT_COOKIE (0xABCDABCD)
|
||||
@ -2192,6 +2302,7 @@ typedef union {
|
||||
|
||||
typedef struct {
|
||||
_sgl_command_type_t cmd;
|
||||
int layer_id;
|
||||
_sgl_args_t args;
|
||||
} _sgl_command_t;
|
||||
|
||||
@ -2208,22 +2319,30 @@ typedef struct {
|
||||
typedef struct {
|
||||
_sgl_slot_t slot;
|
||||
sgl_context_desc_t desc;
|
||||
|
||||
int num_vertices;
|
||||
int num_uniforms;
|
||||
int num_commands;
|
||||
int cur_vertex;
|
||||
int cur_uniform;
|
||||
int cur_command;
|
||||
_sgl_vertex_t* vertices;
|
||||
_sgl_uniform_t* uniforms;
|
||||
_sgl_command_t* commands;
|
||||
uint32_t frame_id;
|
||||
uint32_t update_frame_id;
|
||||
struct {
|
||||
int cap;
|
||||
int next;
|
||||
_sgl_vertex_t* ptr;
|
||||
} vertices;
|
||||
struct {
|
||||
int cap;
|
||||
int next;
|
||||
_sgl_uniform_t* ptr;
|
||||
} uniforms;
|
||||
struct {
|
||||
int cap;
|
||||
int next;
|
||||
_sgl_command_t* ptr;
|
||||
} commands;
|
||||
|
||||
/* state tracking */
|
||||
int base_vertex;
|
||||
int vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */
|
||||
sgl_error_t error;
|
||||
bool in_begin;
|
||||
int layer_id;
|
||||
float u, v;
|
||||
uint32_t rgba;
|
||||
float point_size;
|
||||
@ -2266,6 +2385,49 @@ typedef struct {
|
||||
static _sgl_t _sgl;
|
||||
|
||||
/*== PRIVATE FUNCTIONS =======================================================*/
|
||||
static void _sgl_clear(void* ptr, size_t size) {
|
||||
SOKOL_ASSERT(ptr && (size > 0));
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
static void* _sgl_malloc(size_t size) {
|
||||
SOKOL_ASSERT(size > 0);
|
||||
void* ptr;
|
||||
if (_sgl.desc.allocator.alloc) {
|
||||
ptr = _sgl.desc.allocator.alloc(size, _sgl.desc.allocator.user_data);
|
||||
}
|
||||
else {
|
||||
ptr = malloc(size);
|
||||
}
|
||||
SOKOL_ASSERT(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void* _sgl_malloc_clear(size_t size) {
|
||||
void* ptr = _sgl_malloc(size);
|
||||
_sgl_clear(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void _sgl_free(void* ptr) {
|
||||
if (_sgl.desc.allocator.free) {
|
||||
_sgl.desc.allocator.free(ptr, _sgl.desc.allocator.user_data);
|
||||
}
|
||||
else {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SOKOL_DEBUG)
|
||||
static void _sgl_log(const char* msg) {
|
||||
SOKOL_ASSERT(msg);
|
||||
if (_sgl.desc.logger.log_cb) {
|
||||
_sgl.desc.logger.log_cb(msg, _sgl.desc.logger.user_data);
|
||||
} else {
|
||||
SOKOL_LOG(msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _sgl_init_pool(_sgl_pool_t* pool, int num) {
|
||||
SOKOL_ASSERT(pool && (num >= 1));
|
||||
@ -2274,12 +2436,9 @@ static void _sgl_init_pool(_sgl_pool_t* pool, int num) {
|
||||
pool->queue_top = 0;
|
||||
/* generation counters indexable by pool slot index, slot 0 is reserved */
|
||||
size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size;
|
||||
pool->gen_ctrs = (uint32_t*) SOKOL_MALLOC(gen_ctrs_size);
|
||||
SOKOL_ASSERT(pool->gen_ctrs);
|
||||
memset(pool->gen_ctrs, 0, gen_ctrs_size);
|
||||
pool->gen_ctrs = (uint32_t*) _sgl_malloc_clear(gen_ctrs_size);
|
||||
/* it's not a bug to only reserve 'num' here */
|
||||
pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int) * (size_t)num);
|
||||
SOKOL_ASSERT(pool->free_queue);
|
||||
pool->free_queue = (int*) _sgl_malloc_clear(sizeof(int) * (size_t)num);
|
||||
/* never allocate the zero-th pool item since the invalid id is 0 */
|
||||
for (int i = pool->size-1; i >= 1; i--) {
|
||||
pool->free_queue[pool->queue_top++] = i;
|
||||
@ -2289,10 +2448,10 @@ static void _sgl_init_pool(_sgl_pool_t* pool, int num) {
|
||||
static void _sgl_discard_pool(_sgl_pool_t* pool) {
|
||||
SOKOL_ASSERT(pool);
|
||||
SOKOL_ASSERT(pool->free_queue);
|
||||
SOKOL_FREE(pool->free_queue);
|
||||
_sgl_free(pool->free_queue);
|
||||
pool->free_queue = 0;
|
||||
SOKOL_ASSERT(pool->gen_ctrs);
|
||||
SOKOL_FREE(pool->gen_ctrs);
|
||||
_sgl_free(pool->gen_ctrs);
|
||||
pool->gen_ctrs = 0;
|
||||
pool->size = 0;
|
||||
pool->queue_top = 0;
|
||||
@ -2329,10 +2488,10 @@ static void _sgl_pool_free_index(_sgl_pool_t* pool, int slot_index) {
|
||||
|
||||
static void _sgl_reset_context(_sgl_context_t* ctx) {
|
||||
SOKOL_ASSERT(ctx);
|
||||
SOKOL_ASSERT(0 == ctx->vertices);
|
||||
SOKOL_ASSERT(0 == ctx->uniforms);
|
||||
SOKOL_ASSERT(0 == ctx->commands);
|
||||
memset(ctx, 0, sizeof(_sgl_context_t));
|
||||
SOKOL_ASSERT(0 == ctx->vertices.ptr);
|
||||
SOKOL_ASSERT(0 == ctx->uniforms.ptr);
|
||||
SOKOL_ASSERT(0 == ctx->commands.ptr);
|
||||
_sgl_clear(ctx, sizeof(_sgl_context_t));
|
||||
}
|
||||
|
||||
static void _sgl_setup_context_pool(int pool_size) {
|
||||
@ -2340,20 +2499,18 @@ static void _sgl_setup_context_pool(int pool_size) {
|
||||
SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE));
|
||||
_sgl_init_pool(&_sgl.context_pool.pool, pool_size);
|
||||
size_t pool_byte_size = sizeof(_sgl_context_t) * (size_t)_sgl.context_pool.pool.size;
|
||||
_sgl.context_pool.contexts = (_sgl_context_t*) SOKOL_MALLOC(pool_byte_size);
|
||||
SOKOL_ASSERT(_sgl.context_pool.contexts);
|
||||
memset(_sgl.context_pool.contexts, 0, pool_byte_size);
|
||||
_sgl.context_pool.contexts = (_sgl_context_t*) _sgl_malloc_clear(pool_byte_size);
|
||||
}
|
||||
|
||||
static void _sgl_discard_context_pool(void) {
|
||||
SOKOL_ASSERT(0 != _sgl.context_pool.contexts);
|
||||
SOKOL_FREE(_sgl.context_pool.contexts); _sgl.context_pool.contexts = 0;
|
||||
_sgl_free(_sgl.context_pool.contexts); _sgl.context_pool.contexts = 0;
|
||||
_sgl_discard_pool(&_sgl.context_pool.pool);
|
||||
}
|
||||
|
||||
static void _sgl_reset_pipeline(_sgl_pipeline_t* pip) {
|
||||
SOKOL_ASSERT(pip);
|
||||
memset(pip, 0, sizeof(_sgl_pipeline_t));
|
||||
_sgl_clear(pip, sizeof(_sgl_pipeline_t));
|
||||
}
|
||||
|
||||
static void _sgl_setup_pipeline_pool(int pool_size) {
|
||||
@ -2361,14 +2518,12 @@ static void _sgl_setup_pipeline_pool(int pool_size) {
|
||||
SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE));
|
||||
_sgl_init_pool(&_sgl.pip_pool.pool, pool_size);
|
||||
size_t pool_byte_size = sizeof(_sgl_pipeline_t) * (size_t)_sgl.pip_pool.pool.size;
|
||||
_sgl.pip_pool.pips = (_sgl_pipeline_t*) SOKOL_MALLOC(pool_byte_size);
|
||||
SOKOL_ASSERT(_sgl.pip_pool.pips);
|
||||
memset(_sgl.pip_pool.pips, 0, pool_byte_size);
|
||||
_sgl.pip_pool.pips = (_sgl_pipeline_t*) _sgl_malloc_clear(pool_byte_size);
|
||||
}
|
||||
|
||||
static void _sgl_discard_pipeline_pool(void) {
|
||||
SOKOL_ASSERT(0 != _sgl.pip_pool.pips);
|
||||
SOKOL_FREE(_sgl.pip_pool.pips); _sgl.pip_pool.pips = 0;
|
||||
_sgl_free(_sgl.pip_pool.pips); _sgl.pip_pool.pips = 0;
|
||||
_sgl_discard_pool(&_sgl.pip_pool.pool);
|
||||
}
|
||||
|
||||
@ -2510,7 +2665,7 @@ static void _sgl_init_pipeline(sgl_pipeline pip_id, const sg_pipeline_desc* in_d
|
||||
else {
|
||||
pip->pip[i] = sg_make_pipeline(&desc);
|
||||
if (pip->pip[i].id == SG_INVALID_ID) {
|
||||
SOKOL_LOG("sokol_gl.h: failed to create pipeline object");
|
||||
SGL_LOG("sokol_gl.h: failed to create pipeline object");
|
||||
pip->slot.state = SG_RESOURCESTATE_FAILED;
|
||||
}
|
||||
}
|
||||
@ -2524,7 +2679,7 @@ static sgl_pipeline _sgl_make_pipeline(const sg_pipeline_desc* desc, const sgl_c
|
||||
_sgl_init_pipeline(pip_id, desc, ctx_desc);
|
||||
}
|
||||
else {
|
||||
SOKOL_LOG("sokol_gl.h: pipeline pool exhausted!");
|
||||
SGL_LOG("sokol_gl.h: pipeline pool exhausted!");
|
||||
}
|
||||
return pip_id;
|
||||
}
|
||||
@ -2602,39 +2757,45 @@ static sgl_context_desc_t _sgl_context_desc_defaults(const sgl_context_desc_t* d
|
||||
}
|
||||
|
||||
static void _sgl_identity(_sgl_matrix_t*);
|
||||
static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx);
|
||||
static void _sgl_init_context(sgl_context ctx_id, const sgl_context_desc_t* in_desc) {
|
||||
SOKOL_ASSERT((ctx_id.id != SG_INVALID_ID) && in_desc);
|
||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||
SOKOL_ASSERT(ctx);
|
||||
ctx->desc = _sgl_context_desc_defaults(in_desc);
|
||||
// NOTE: frame_id must be non-zero, so that updates trigger in first frame
|
||||
ctx->frame_id = 1;
|
||||
ctx->cur_img = _sgl.def_img;
|
||||
|
||||
// allocate buffers and pools
|
||||
ctx->num_vertices = ctx->desc.max_vertices;
|
||||
ctx->num_commands = ctx->num_uniforms = ctx->desc.max_commands;
|
||||
ctx->vertices = (_sgl_vertex_t*) SOKOL_MALLOC((size_t)ctx->num_vertices * sizeof(_sgl_vertex_t));
|
||||
SOKOL_ASSERT(ctx->vertices);
|
||||
ctx->uniforms = (_sgl_uniform_t*) SOKOL_MALLOC((size_t)ctx->num_uniforms * sizeof(_sgl_uniform_t));
|
||||
SOKOL_ASSERT(ctx->uniforms);
|
||||
ctx->commands = (_sgl_command_t*) SOKOL_MALLOC((size_t)ctx->num_commands * sizeof(_sgl_command_t));
|
||||
SOKOL_ASSERT(ctx->commands);
|
||||
ctx->vertices.cap = ctx->desc.max_vertices;
|
||||
ctx->commands.cap = ctx->uniforms.cap = ctx->desc.max_commands;
|
||||
ctx->vertices.ptr = (_sgl_vertex_t*) _sgl_malloc((size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t));
|
||||
ctx->uniforms.ptr = (_sgl_uniform_t*) _sgl_malloc((size_t)ctx->uniforms.cap * sizeof(_sgl_uniform_t));
|
||||
ctx->commands.ptr = (_sgl_command_t*) _sgl_malloc((size_t)ctx->commands.cap * sizeof(_sgl_command_t));
|
||||
|
||||
// create sokol-gfx resource objects
|
||||
sg_push_debug_group("sokol-gl");
|
||||
|
||||
sg_buffer_desc vbuf_desc;
|
||||
memset(&vbuf_desc, 0, sizeof(vbuf_desc));
|
||||
vbuf_desc.size = (size_t)ctx->num_vertices * sizeof(_sgl_vertex_t);
|
||||
_sgl_clear(&vbuf_desc, sizeof(vbuf_desc));
|
||||
vbuf_desc.size = (size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t);
|
||||
vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER;
|
||||
vbuf_desc.usage = SG_USAGE_STREAM;
|
||||
vbuf_desc.label = "sgl-vertex-buffer";
|
||||
ctx->vbuf = sg_make_buffer(&vbuf_desc);
|
||||
SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id);
|
||||
ctx->bind.vertex_buffers[0] = ctx->vbuf;
|
||||
|
||||
sg_pipeline_desc def_pip_desc;
|
||||
memset(&def_pip_desc, 0, sizeof(def_pip_desc));
|
||||
_sgl_clear(&def_pip_desc, sizeof(def_pip_desc));
|
||||
def_pip_desc.depth.write_enabled = true;
|
||||
ctx->def_pip = _sgl_make_pipeline(&def_pip_desc, &ctx->desc);
|
||||
if (!sg_add_commit_listener(_sgl_make_commit_listener(ctx))) {
|
||||
// FIXME: this should actually result in an invalid context,
|
||||
// fix this when proper error logging/reporting is added
|
||||
SGL_LOG("sokol_gl.h: failed to add sokol-gfx commit listener!");
|
||||
}
|
||||
sg_pop_debug_group();
|
||||
|
||||
// default state
|
||||
@ -2654,7 +2815,7 @@ static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) {
|
||||
_sgl_init_context(ctx_id, desc);
|
||||
}
|
||||
else {
|
||||
SOKOL_LOG("sokol_gl.h: context pool exhausted!");
|
||||
SGL_LOG("sokol_gl.h: context pool exhausted!");
|
||||
}
|
||||
return ctx_id;
|
||||
}
|
||||
@ -2662,21 +2823,21 @@ static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) {
|
||||
static void _sgl_destroy_context(sgl_context ctx_id) {
|
||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||
if (ctx) {
|
||||
SOKOL_ASSERT(ctx->vertices);
|
||||
SOKOL_ASSERT(ctx->uniforms);
|
||||
SOKOL_ASSERT(ctx->commands);
|
||||
SOKOL_ASSERT(ctx->vertices.ptr);
|
||||
SOKOL_ASSERT(ctx->uniforms.ptr);
|
||||
SOKOL_ASSERT(ctx->commands.ptr);
|
||||
|
||||
SOKOL_FREE(ctx->vertices);
|
||||
SOKOL_FREE(ctx->uniforms);
|
||||
SOKOL_FREE(ctx->commands);
|
||||
|
||||
ctx->vertices = 0;
|
||||
ctx->uniforms = 0;
|
||||
ctx->commands = 0;
|
||||
_sgl_free(ctx->vertices.ptr);
|
||||
_sgl_free(ctx->uniforms.ptr);
|
||||
_sgl_free(ctx->commands.ptr);
|
||||
ctx->vertices.ptr = 0;
|
||||
ctx->uniforms.ptr = 0;
|
||||
ctx->commands.ptr = 0;
|
||||
|
||||
sg_push_debug_group("sokol-gl");
|
||||
sg_destroy_buffer(ctx->vbuf);
|
||||
_sgl_destroy_pipeline(ctx->def_pip);
|
||||
sg_remove_commit_listener(_sgl_make_commit_listener(ctx));
|
||||
sg_pop_debug_group();
|
||||
|
||||
_sgl_reset_context(ctx);
|
||||
@ -2684,25 +2845,40 @@ static void _sgl_destroy_context(sgl_context ctx_id) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) {
|
||||
static void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) {
|
||||
ctx->in_begin = true;
|
||||
ctx->base_vertex = ctx->cur_vertex;
|
||||
ctx->base_vertex = ctx->vertices.next;
|
||||
ctx->vtx_count = 0;
|
||||
ctx->cur_prim_type = mode;
|
||||
}
|
||||
|
||||
static void _sgl_rewind(_sgl_context_t* ctx) {
|
||||
ctx->frame_id++;
|
||||
ctx->vertices.next = 0;
|
||||
ctx->uniforms.next = 0;
|
||||
ctx->commands.next = 0;
|
||||
ctx->base_vertex = 0;
|
||||
ctx->cur_vertex = 0;
|
||||
ctx->cur_uniform = 0;
|
||||
ctx->cur_command = 0;
|
||||
ctx->error = SGL_NO_ERROR;
|
||||
ctx->layer_id = 0;
|
||||
ctx->matrix_dirty = true;
|
||||
}
|
||||
|
||||
static inline _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) {
|
||||
if (ctx->cur_vertex < ctx->num_vertices) {
|
||||
return &ctx->vertices[ctx->cur_vertex++];
|
||||
// called from inside sokol-gfx sg_commit()
|
||||
static void _sgl_commit_listener(void* userdata) {
|
||||
_sgl_context_t* ctx = _sgl_lookup_context((uint32_t)(uintptr_t)userdata);
|
||||
if (ctx) {
|
||||
_sgl_rewind(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx) {
|
||||
sg_commit_listener listener = { _sgl_commit_listener, (void*)(uintptr_t)(ctx->slot.id) };
|
||||
return listener;
|
||||
}
|
||||
|
||||
static _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) {
|
||||
if (ctx->vertices.next < ctx->vertices.cap) {
|
||||
return &ctx->vertices.ptr[ctx->vertices.next++];
|
||||
}
|
||||
else {
|
||||
ctx->error = SGL_ERROR_VERTICES_FULL;
|
||||
@ -2710,9 +2886,9 @@ static inline _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) {
|
||||
if (ctx->cur_uniform < ctx->num_uniforms) {
|
||||
return &ctx->uniforms[ctx->cur_uniform++];
|
||||
static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) {
|
||||
if (ctx->uniforms.next < ctx->uniforms.cap) {
|
||||
return &ctx->uniforms.ptr[ctx->uniforms.next++];
|
||||
}
|
||||
else {
|
||||
ctx->error = SGL_ERROR_UNIFORMS_FULL;
|
||||
@ -2720,18 +2896,18 @@ static inline _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline _sgl_command_t* _sgl_prev_command(_sgl_context_t* ctx) {
|
||||
if (ctx->cur_command > 0) {
|
||||
return &ctx->commands[ctx->cur_command - 1];
|
||||
static _sgl_command_t* _sgl_cur_command(_sgl_context_t* ctx) {
|
||||
if (ctx->commands.next > 0) {
|
||||
return &ctx->commands.ptr[ctx->commands.next - 1];
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) {
|
||||
if (ctx->cur_command < ctx->num_commands) {
|
||||
return &ctx->commands[ctx->cur_command++];
|
||||
static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) {
|
||||
if (ctx->commands.next < ctx->commands.cap) {
|
||||
return &ctx->commands.ptr[ctx->commands.next++];
|
||||
}
|
||||
else {
|
||||
ctx->error = SGL_ERROR_COMMANDS_FULL;
|
||||
@ -2739,17 +2915,17 @@ static inline _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t _sgl_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
static uint32_t _sgl_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r);
|
||||
}
|
||||
|
||||
static inline float _sgl_clamp(float v, float lo, float hi) {
|
||||
static float _sgl_clamp(float v, float lo, float hi) {
|
||||
if (v < lo) return lo;
|
||||
else if (v > hi) return hi;
|
||||
else return v;
|
||||
}
|
||||
|
||||
static inline uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) {
|
||||
static uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) {
|
||||
uint8_t r_u8 = (uint8_t) (_sgl_clamp(r, 0.0f, 1.0f) * 255.0f);
|
||||
uint8_t g_u8 = (uint8_t) (_sgl_clamp(g, 0.0f, 1.0f) * 255.0f);
|
||||
uint8_t b_u8 = (uint8_t) (_sgl_clamp(b, 0.0f, 1.0f) * 255.0f);
|
||||
@ -2757,7 +2933,7 @@ static inline uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) {
|
||||
return _sgl_pack_rgbab(r_u8, g_u8, b_u8, a_u8);
|
||||
}
|
||||
|
||||
static inline void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, float v, uint32_t rgba) {
|
||||
static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, float v, uint32_t rgba) {
|
||||
SOKOL_ASSERT(ctx->in_begin);
|
||||
_sgl_vertex_t* vtx;
|
||||
/* handle non-native primitive types */
|
||||
@ -2971,27 +3147,28 @@ static void _sgl_lookat(_sgl_matrix_t* dst,
|
||||
}
|
||||
|
||||
/* current top-of-stack projection matrix */
|
||||
static inline _sgl_matrix_t* _sgl_matrix_projection(_sgl_context_t* ctx) {
|
||||
static _sgl_matrix_t* _sgl_matrix_projection(_sgl_context_t* ctx) {
|
||||
return &ctx->matrix_stack[SGL_MATRIXMODE_PROJECTION][ctx->matrix_tos[SGL_MATRIXMODE_PROJECTION]];
|
||||
}
|
||||
|
||||
/* get top-of-stack modelview matrix */
|
||||
static inline _sgl_matrix_t* _sgl_matrix_modelview(_sgl_context_t* ctx) {
|
||||
static _sgl_matrix_t* _sgl_matrix_modelview(_sgl_context_t* ctx) {
|
||||
return &ctx->matrix_stack[SGL_MATRIXMODE_MODELVIEW][ctx->matrix_tos[SGL_MATRIXMODE_MODELVIEW]];
|
||||
}
|
||||
|
||||
/* get top-of-stack texture matrix */
|
||||
static inline _sgl_matrix_t* _sgl_matrix_texture(_sgl_context_t* ctx) {
|
||||
static _sgl_matrix_t* _sgl_matrix_texture(_sgl_context_t* ctx) {
|
||||
return &ctx->matrix_stack[SGL_MATRIXMODE_TEXTURE][ctx->matrix_tos[SGL_MATRIXMODE_TEXTURE]];
|
||||
}
|
||||
|
||||
/* get pointer to current top-of-stack of current matrix mode */
|
||||
static inline _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) {
|
||||
static _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) {
|
||||
return &ctx->matrix_stack[ctx->cur_matrix_mode][ctx->matrix_tos[ctx->cur_matrix_mode]];
|
||||
}
|
||||
|
||||
// return sg_context_desc_t with patched defaults
|
||||
static sgl_desc_t _sgl_desc_defaults(const sgl_desc_t* desc) {
|
||||
SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free));
|
||||
sgl_desc_t res = *desc;
|
||||
res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES);
|
||||
res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS);
|
||||
@ -3010,7 +3187,7 @@ static void _sgl_setup_common(void) {
|
||||
pixels[i] = 0xFFFFFFFF;
|
||||
}
|
||||
sg_image_desc img_desc;
|
||||
memset(&img_desc, 0, sizeof(img_desc));
|
||||
_sgl_clear(&img_desc, sizeof(img_desc));
|
||||
img_desc.type = SG_IMAGETYPE_2D;
|
||||
img_desc.width = 8;
|
||||
img_desc.height = 8;
|
||||
@ -3025,7 +3202,7 @@ static void _sgl_setup_common(void) {
|
||||
|
||||
// one shader for all contexts
|
||||
sg_shader_desc shd_desc;
|
||||
memset(&shd_desc, 0, sizeof(shd_desc));
|
||||
_sgl_clear(&shd_desc, sizeof(shd_desc));
|
||||
shd_desc.attrs[0].name = "position";
|
||||
shd_desc.attrs[1].name = "texcoord0";
|
||||
shd_desc.attrs[2].name = "color0";
|
||||
@ -3097,18 +3274,26 @@ static bool _sgl_is_default_context(sgl_context ctx_id) {
|
||||
return ctx_id.id == SGL_DEFAULT_CONTEXT.id;
|
||||
}
|
||||
|
||||
static void _sgl_draw(_sgl_context_t* ctx) {
|
||||
static void _sgl_draw(_sgl_context_t* ctx, int layer_id) {
|
||||
SOKOL_ASSERT(ctx);
|
||||
if ((ctx->error == SGL_NO_ERROR) && (ctx->cur_vertex > 0) && (ctx->cur_command > 0)) {
|
||||
if ((ctx->error == SGL_NO_ERROR) && (ctx->vertices.next > 0) && (ctx->commands.next > 0)) {
|
||||
sg_push_debug_group("sokol-gl");
|
||||
|
||||
uint32_t cur_pip_id = SG_INVALID_ID;
|
||||
uint32_t cur_img_id = SG_INVALID_ID;
|
||||
int cur_uniform_index = -1;
|
||||
sg_push_debug_group("sokol-gl");
|
||||
const sg_range range = { ctx->vertices, (size_t)ctx->cur_vertex * sizeof(_sgl_vertex_t) };
|
||||
sg_update_buffer(ctx->vbuf, &range);
|
||||
ctx->bind.vertex_buffers[0] = ctx->vbuf;
|
||||
for (int i = 0; i < ctx->cur_command; i++) {
|
||||
const _sgl_command_t* cmd = &ctx->commands[i];
|
||||
|
||||
if (ctx->update_frame_id != ctx->frame_id) {
|
||||
ctx->update_frame_id = ctx->frame_id;
|
||||
const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sgl_vertex_t) };
|
||||
sg_update_buffer(ctx->vbuf, &range);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ctx->commands.next; i++) {
|
||||
const _sgl_command_t* cmd = &ctx->commands.ptr[i];
|
||||
if (cmd->layer_id != layer_id) {
|
||||
continue;
|
||||
}
|
||||
switch (cmd->cmd) {
|
||||
case SGL_COMMAND_VIEWPORT:
|
||||
{
|
||||
@ -3138,7 +3323,7 @@ static void _sgl_draw(_sgl_context_t* ctx) {
|
||||
cur_img_id = args->img.id;
|
||||
}
|
||||
if (cur_uniform_index != args->uniform_index) {
|
||||
const sg_range ub_range = { &ctx->uniforms[args->uniform_index], sizeof(_sgl_uniform_t) };
|
||||
const sg_range ub_range = { &ctx->uniforms.ptr[args->uniform_index], sizeof(_sgl_uniform_t) };
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &ub_range);
|
||||
cur_uniform_index = args->uniform_index;
|
||||
}
|
||||
@ -3152,12 +3337,11 @@ static void _sgl_draw(_sgl_context_t* ctx) {
|
||||
}
|
||||
sg_pop_debug_group();
|
||||
}
|
||||
_sgl_rewind(ctx);
|
||||
}
|
||||
|
||||
static sgl_context_desc_t _sgl_as_context_desc(const sgl_desc_t* desc) {
|
||||
sgl_context_desc_t ctx_desc;
|
||||
memset(&ctx_desc, 0, sizeof(ctx_desc));
|
||||
_sgl_clear(&ctx_desc, sizeof(ctx_desc));
|
||||
ctx_desc.max_vertices = desc->max_vertices;
|
||||
ctx_desc.max_commands = desc->max_commands;
|
||||
ctx_desc.color_format = desc->color_format;
|
||||
@ -3169,7 +3353,7 @@ static sgl_context_desc_t _sgl_as_context_desc(const sgl_desc_t* desc) {
|
||||
/*== PUBLIC FUNCTIONS ========================================================*/
|
||||
SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) {
|
||||
SOKOL_ASSERT(desc);
|
||||
memset(&_sgl, 0, sizeof(_sgl));
|
||||
_sgl_clear(&_sgl, sizeof(_sgl));
|
||||
_sgl.init_cookie = _SGL_INIT_COOKIE;
|
||||
_sgl.desc = _sgl_desc_defaults(desc);
|
||||
_sgl_setup_pipeline_pool(_sgl.desc.pipeline_pool_size);
|
||||
@ -3234,7 +3418,7 @@ SOKOL_API_IMPL sgl_context sgl_make_context(const sgl_context_desc_t* desc) {
|
||||
SOKOL_API_IMPL void sgl_destroy_context(sgl_context ctx_id) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
if (_sgl_is_default_context(ctx_id)) {
|
||||
SOKOL_LOG("sokol_gl.h: cannot destroy default context");
|
||||
SGL_LOG("sokol_gl.h: cannot destroy default context");
|
||||
return;
|
||||
}
|
||||
_sgl_destroy_context(ctx_id);
|
||||
@ -3360,6 +3544,16 @@ SOKOL_API_IMPL void sgl_defaults(void) {
|
||||
ctx->matrix_dirty = true;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sgl_layer(int layer_id) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
SOKOL_ASSERT(!ctx->in_begin);
|
||||
ctx->layer_id = layer_id;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sgl_viewport(int x, int y, int w, int h, bool origin_top_left) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
@ -3370,6 +3564,7 @@ SOKOL_API_IMPL void sgl_viewport(int x, int y, int w, int h, bool origin_top_lef
|
||||
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
||||
if (cmd) {
|
||||
cmd->cmd = SGL_COMMAND_VIEWPORT;
|
||||
cmd->layer_id = ctx->layer_id;
|
||||
cmd->args.viewport.x = x;
|
||||
cmd->args.viewport.y = y;
|
||||
cmd->args.viewport.w = w;
|
||||
@ -3392,6 +3587,7 @@ SOKOL_API_IMPL void sgl_scissor_rect(int x, int y, int w, int h, bool origin_top
|
||||
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
||||
if (cmd) {
|
||||
cmd->cmd = SGL_COMMAND_SCISSOR_RECT;
|
||||
cmd->layer_id = ctx->layer_id;
|
||||
cmd->args.scissor_rect.x = x;
|
||||
cmd->args.scissor_rect.y = y;
|
||||
cmd->args.scissor_rect.w = w;
|
||||
@ -3506,7 +3702,7 @@ SOKOL_API_IMPL void sgl_end(void) {
|
||||
return;
|
||||
}
|
||||
SOKOL_ASSERT(ctx->in_begin);
|
||||
SOKOL_ASSERT(ctx->cur_vertex >= ctx->base_vertex);
|
||||
SOKOL_ASSERT(ctx->vertices.next >= ctx->base_vertex);
|
||||
ctx->in_begin = false;
|
||||
bool matrix_dirty = ctx->matrix_dirty;
|
||||
if (matrix_dirty) {
|
||||
@ -3517,37 +3713,39 @@ SOKOL_API_IMPL void sgl_end(void) {
|
||||
uni->tm = *_sgl_matrix_texture(ctx);
|
||||
}
|
||||
}
|
||||
/* check if command can be merged with previous command */
|
||||
/* check if command can be merged with current command */
|
||||
sg_pipeline pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type);
|
||||
sg_image img = ctx->texturing_enabled ? ctx->cur_img : _sgl.def_img;
|
||||
_sgl_command_t* prev_cmd = _sgl_prev_command(ctx);
|
||||
_sgl_command_t* cur_cmd = _sgl_cur_command(ctx);
|
||||
bool merge_cmd = false;
|
||||
if (prev_cmd) {
|
||||
if ((prev_cmd->cmd == SGL_COMMAND_DRAW) &&
|
||||
if (cur_cmd) {
|
||||
if ((cur_cmd->cmd == SGL_COMMAND_DRAW) &&
|
||||
(cur_cmd->layer_id == ctx->layer_id) &&
|
||||
(ctx->cur_prim_type != SGL_PRIMITIVETYPE_LINE_STRIP) &&
|
||||
(ctx->cur_prim_type != SGL_PRIMITIVETYPE_TRIANGLE_STRIP) &&
|
||||
!matrix_dirty &&
|
||||
(prev_cmd->args.draw.img.id == img.id) &&
|
||||
(prev_cmd->args.draw.pip.id == pip.id))
|
||||
(cur_cmd->args.draw.img.id == img.id) &&
|
||||
(cur_cmd->args.draw.pip.id == pip.id))
|
||||
{
|
||||
merge_cmd = true;
|
||||
}
|
||||
}
|
||||
if (merge_cmd) {
|
||||
/* draw command can be merged with the previous command */
|
||||
prev_cmd->args.draw.num_vertices += ctx->cur_vertex - ctx->base_vertex;
|
||||
cur_cmd->args.draw.num_vertices += ctx->vertices.next - ctx->base_vertex;
|
||||
}
|
||||
else {
|
||||
/* append a new draw command */
|
||||
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
||||
if (cmd) {
|
||||
SOKOL_ASSERT(ctx->cur_uniform > 0);
|
||||
SOKOL_ASSERT(ctx->uniforms.next > 0);
|
||||
cmd->cmd = SGL_COMMAND_DRAW;
|
||||
cmd->layer_id = ctx->layer_id;
|
||||
cmd->args.draw.img = img;
|
||||
cmd->args.draw.pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type);
|
||||
cmd->args.draw.base_vertex = ctx->base_vertex;
|
||||
cmd->args.draw.num_vertices = ctx->cur_vertex - ctx->base_vertex;
|
||||
cmd->args.draw.uniform_index = ctx->cur_uniform - 1;
|
||||
cmd->args.draw.num_vertices = ctx->vertices.next - ctx->base_vertex;
|
||||
cmd->args.draw.uniform_index = ctx->uniforms.next - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3956,7 +4154,15 @@ SOKOL_API_IMPL void sgl_draw(void) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
if (ctx) {
|
||||
_sgl_draw(ctx);
|
||||
_sgl_draw(ctx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sgl_draw_layer(int layer_id) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
if (ctx) {
|
||||
_sgl_draw(ctx, layer_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3964,7 +4170,15 @@ SOKOL_API_IMPL void sgl_context_draw(sgl_context ctx_id) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||
if (ctx) {
|
||||
_sgl_draw(ctx);
|
||||
_sgl_draw(ctx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL void sgl_context_draw_layer(sgl_context ctx_id, int layer_id) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||
if (ctx) {
|
||||
_sgl_draw(ctx, layer_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
module audio
|
||||
|
||||
import sokol.memory
|
||||
|
||||
$if linux {
|
||||
// provide a nicer error for the user that does not have ALSA installed
|
||||
#include <alsa/asoundlib.h> # Please install the `libasound2-dev` package
|
||||
@ -53,6 +55,21 @@ pub fn (x FnStreamingCBWithUserData) str() string {
|
||||
return '&FnStreamingCBWithUserData{ ${ptr_str(x)} }'
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.saudio_allocator {
|
||||
pub mut:
|
||||
alloc memory.FnAllocatorAlloc
|
||||
free memory.FnAllocatorFree
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.saudio_logger {
|
||||
pub mut:
|
||||
log_cb memory.FnLogCb
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
// only one of `stream_cb` or `stream_userdata_cb` should be used
|
||||
//
|
||||
// default values (internal to sokol C library):
|
||||
@ -64,6 +81,7 @@ pub fn (x FnStreamingCBWithUserData) str() string {
|
||||
// | buffer_frames | 2048 | buffer size in frames, larger is more latency, smaller means higher CPU |
|
||||
// | packet_frames | 128 | push model only, number of frames that will be pushed in each packet |
|
||||
// | num_packets | 64 | for push model only, number of packets in the backend ringbuffer |
|
||||
[typedef]
|
||||
pub struct C.saudio_desc {
|
||||
sample_rate int
|
||||
num_channels int
|
||||
@ -72,7 +90,10 @@ pub struct C.saudio_desc {
|
||||
num_packets int
|
||||
stream_cb FNStreamingCB
|
||||
stream_userdata_cb FnStreamingCBWithUserData
|
||||
user_data voidptr
|
||||
pub mut:
|
||||
user_data voidptr
|
||||
allocator C.saudio_allocator
|
||||
logger C.saudio_logger
|
||||
}
|
||||
|
||||
fn C.saudio_setup(desc &C.saudio_desc)
|
||||
@ -99,6 +120,18 @@ fn C.saudio_push(frames &f32, num_frames int) int
|
||||
|
||||
// setup - setup sokol-audio
|
||||
pub fn setup(desc &C.saudio_desc) {
|
||||
if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.allocator.alloc = memory.salloc
|
||||
desc.allocator.free = memory.sfree
|
||||
desc.allocator.user_data = voidptr(0x100a0d10)
|
||||
}
|
||||
}
|
||||
if desc.logger.log_cb == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.logger.log_cb = memory.slog
|
||||
}
|
||||
}
|
||||
C.saudio_setup(desc)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
module c
|
||||
|
||||
pub const (
|
||||
used_import = 1
|
||||
)
|
||||
pub const used_import = 1
|
||||
|
||||
#flag -I @VEXEROOT/thirdparty/sokol
|
||||
#flag -I @VEXEROOT/thirdparty/sokol/util
|
||||
@ -58,13 +56,6 @@ $if emscripten ? {
|
||||
|
||||
#flag linux -ldl
|
||||
|
||||
$if gcboehm ? {
|
||||
#define SOKOL_MALLOC GC_MALLOC
|
||||
#define SOKOL_CALLOC(n,m) GC_MALLOC((n)*(m))
|
||||
#define SOKOL_REALLOC GC_REALLOC
|
||||
#define SOKOL_FREE GC_FREE
|
||||
}
|
||||
|
||||
// To allow for thirdparty initializing window / acceleration contexts
|
||||
// but still be able to use sokol.gfx e.g. SDL+sokol_gfx
|
||||
$if !no_sokol_app ? {
|
||||
|
@ -3,9 +3,7 @@ module f
|
||||
import fontstash
|
||||
import sokol.c
|
||||
|
||||
pub const (
|
||||
used_import = fontstash.used_import + c.used_import
|
||||
)
|
||||
pub const used_import = fontstash.used_import + c.used_import
|
||||
|
||||
#flag linux -I.
|
||||
|
||||
|
@ -1,19 +1,30 @@
|
||||
module gfx
|
||||
|
||||
import sokol.c
|
||||
import sokol.memory
|
||||
|
||||
pub const (
|
||||
version = 1
|
||||
used_import = c.used_import
|
||||
)
|
||||
pub const version = 1
|
||||
|
||||
// setup and misc functions
|
||||
[inline]
|
||||
pub const used_import = c.used_import
|
||||
|
||||
// setup initialises the SOKOL's gfx library, based on the information passed in `desc`
|
||||
pub fn setup(desc &Desc) {
|
||||
if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.allocator.alloc = memory.salloc
|
||||
desc.allocator.free = memory.sfree
|
||||
desc.allocator.user_data = voidptr(0x1006fec5)
|
||||
}
|
||||
}
|
||||
if desc.logger.log_cb == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.logger.log_cb = memory.slog
|
||||
}
|
||||
}
|
||||
C.sg_setup(desc)
|
||||
}
|
||||
|
||||
[inline]
|
||||
// shutdown tells the SOKOL's gfx library to shutdown, and release the resources it is using
|
||||
pub fn shutdown() {
|
||||
C.sg_shutdown()
|
||||
}
|
||||
|
18
vlib/sokol/gfx/gfx_allocator_and_logger.c.v
Normal file
18
vlib/sokol/gfx/gfx_allocator_and_logger.c.v
Normal file
@ -0,0 +1,18 @@
|
||||
module gfx
|
||||
|
||||
import sokol.memory
|
||||
|
||||
[typedef]
|
||||
pub struct C.sg_allocator {
|
||||
pub mut:
|
||||
alloc memory.FnAllocatorAlloc
|
||||
free memory.FnAllocatorFree
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.sg_logger {
|
||||
pub mut:
|
||||
log_cb memory.FnLogCb
|
||||
user_data voidptr
|
||||
}
|
@ -1,30 +1,25 @@
|
||||
module gfx
|
||||
|
||||
struct C.sg_desc {
|
||||
// C.sg_desc describes
|
||||
pub struct C.sg_desc {
|
||||
pub mut:
|
||||
_start_canary u32
|
||||
buffer_pool_size int
|
||||
image_pool_size int
|
||||
shader_pool_size int
|
||||
pipeline_pool_size int
|
||||
pass_pool_size int
|
||||
context_pool_size int
|
||||
context ContextDesc
|
||||
/*
|
||||
// GL specific
|
||||
gl_force_gles2 bool
|
||||
// Metal-specific
|
||||
mtl_device voidptr
|
||||
mtl_renderpass_descriptor_cb fn() voidptr
|
||||
mtl_drawable_cb fn() voidptr
|
||||
mtl_global_uniform_buffer_size int
|
||||
mtl_sampler_cache_size int
|
||||
// D3D11-specific
|
||||
d3d11_device voidptr
|
||||
d3d11_device_context voidptr
|
||||
d3d11_render_target_view_cb fn() voidptr
|
||||
d3d11_depth_stencil_view_cb fn() voidptr
|
||||
*/
|
||||
_start_canary u32
|
||||
buffer_pool_size int
|
||||
image_pool_size int
|
||||
shader_pool_size int
|
||||
pipeline_pool_size int
|
||||
pass_pool_size int
|
||||
context_pool_size int
|
||||
uniform_buffer_size int
|
||||
staging_buffer_size int
|
||||
sampler_cache_size int
|
||||
max_commit_listeners int
|
||||
disable_validation bool // disable validation layer even in debug mode, useful for tests
|
||||
//
|
||||
allocator C.sg_allocator
|
||||
logger C.sg_logger
|
||||
//
|
||||
context ContextDesc
|
||||
_end_canary u32
|
||||
}
|
||||
|
||||
|
38
vlib/sokol/memory/memory.v
Normal file
38
vlib/sokol/memory/memory.v
Normal file
@ -0,0 +1,38 @@
|
||||
module memory
|
||||
|
||||
pub type FnAllocatorAlloc = fn (size usize, user_data voidptr) voidptr
|
||||
|
||||
pub type FnAllocatorFree = fn (ptr voidptr, user_data voidptr)
|
||||
|
||||
pub type FnLogCb = fn (const_message &char, user_data voidptr)
|
||||
|
||||
// salloc - used in the allocator structs, that the SOKOL libraries use, for allocating new memory blocks
|
||||
pub fn salloc(size usize, user_data voidptr) voidptr {
|
||||
res := unsafe { malloc(int(size)) }
|
||||
$if trace_sokol_memory ? {
|
||||
eprintln('sokol.memory.salloc | user_data: ${user_data:x} | size: ${size:10} | res: ${res:x}')
|
||||
}
|
||||
$if trace_sokol_memory_salloc_backtrace ? {
|
||||
print_backtrace()
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// sfree - used in the allocator structs, that the SOKOL libraries use, for freeing memory
|
||||
pub fn sfree(ptr voidptr, user_data voidptr) {
|
||||
$if trace_sokol_memory ? {
|
||||
eprintln(' sokol.memory.sfree | user_data: ${user_data:x} | ptr: ${ptr:x}')
|
||||
}
|
||||
$if trace_sokol_memory_sfree_backtrace ? {
|
||||
print_backtrace()
|
||||
}
|
||||
unsafe { free(ptr) }
|
||||
}
|
||||
|
||||
pub fn slog(const_message &char, user_data voidptr) {
|
||||
$if trace_sokol_memory ? {
|
||||
C.fprintf(C.stderr, c'sokol.memory.slog | user_data: %p, message: %s\n', user_data,
|
||||
const_message)
|
||||
}
|
||||
C.puts(const_message)
|
||||
}
|
@ -183,6 +183,10 @@ pub enum KeyCode {
|
||||
menu = 348
|
||||
}
|
||||
|
||||
// TouchToolType is an Android specific 'tool type' enum for touch events.
|
||||
// This lets the application check what type of input device was used for touch events.
|
||||
// NOTE: the values must remain in sync with the corresponding Android SDK type, so don't change those.
|
||||
// See https://developer.android.com/reference/android/view/MotionEvent#TOOL_TYPE_UNKNOWN
|
||||
pub enum TouchToolType {
|
||||
unknown
|
||||
finger
|
||||
|
@ -2,6 +2,7 @@
|
||||
module sapp
|
||||
|
||||
import sokol.gfx
|
||||
import sokol.memory
|
||||
|
||||
pub const used_import = gfx.used_import
|
||||
|
||||
@ -180,8 +181,19 @@ pub fn get_clipboard_string() &char {
|
||||
}
|
||||
|
||||
// special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub)
|
||||
[inline]
|
||||
pub fn run(desc &Desc) {
|
||||
if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.allocator.alloc = memory.salloc
|
||||
desc.allocator.free = memory.sfree
|
||||
desc.allocator.user_data = voidptr(0x10005a44)
|
||||
}
|
||||
}
|
||||
if desc.logger.log_cb == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.logger.log_cb = memory.slog
|
||||
}
|
||||
}
|
||||
g_desc = *desc
|
||||
C.sapp_run(desc)
|
||||
}
|
||||
|
18
vlib/sokol/sapp/sapp_allocator_and_logger.c.v
Normal file
18
vlib/sokol/sapp/sapp_allocator_and_logger.c.v
Normal file
@ -0,0 +1,18 @@
|
||||
module sapp
|
||||
|
||||
import sokol.memory
|
||||
|
||||
[typedef]
|
||||
pub struct C.sapp_allocator {
|
||||
pub mut:
|
||||
alloc memory.FnAllocatorAlloc
|
||||
free memory.FnAllocatorFree
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.sapp_logger {
|
||||
pub mut:
|
||||
log_cb memory.FnLogCb
|
||||
user_data voidptr
|
||||
}
|
@ -50,20 +50,20 @@ pub:
|
||||
event_userdata_cb fn (&Event, voidptr)
|
||||
fail_userdata_cb fn (&char, voidptr)
|
||||
|
||||
width int // the preferred width of the window / canvas
|
||||
height int // the preferred height of the window / canvas
|
||||
sample_count int // MSAA sample count
|
||||
swap_interval int // the preferred swap interval (ignored on some platforms)
|
||||
high_dpi bool // whether the rendering canvas is full-resolution on HighDPI displays
|
||||
fullscreen bool // whether the window should be created in fullscreen mode
|
||||
alpha bool // whether the framebuffer should have an alpha channel (ignored on some platforms)
|
||||
window_title &char // the window title as UTF-8 encoded string
|
||||
enable_clipboard bool // enable clipboard access, default is false
|
||||
clipboard_size int // max size of clipboard content in bytes
|
||||
enable_dragndrop bool // enable file dropping (drag'n'drop), default is false
|
||||
max_dropped_files int // max number of dropped files to process (default: 1)
|
||||
max_dropped_file_path_length int // max length in bytes of a dropped UTF-8 file path (default: 2048)
|
||||
icon IconDesc
|
||||
width int // the preferred width of the window / canvas
|
||||
height int // the preferred height of the window / canvas
|
||||
sample_count int // MSAA sample count
|
||||
swap_interval int // the preferred swap interval (ignored on some platforms)
|
||||
high_dpi bool // whether the rendering canvas is full-resolution on HighDPI displays
|
||||
fullscreen bool // whether the window should be created in fullscreen mode
|
||||
alpha bool // whether the framebuffer should have an alpha channel (ignored on some platforms)
|
||||
window_title &char // the window title as UTF-8 encoded string
|
||||
enable_clipboard bool // enable clipboard access, default is false
|
||||
clipboard_size int // max size of clipboard content in bytes
|
||||
enable_dragndrop bool // enable file dropping (drag'n'drop), default is false
|
||||
max_dropped_files int // max number of dropped files to process (default: 1)
|
||||
max_dropped_file_path_length int // max length in bytes of a dropped UTF-8 file path (default: 2048)
|
||||
icon IconDesc // the initial window icon to set
|
||||
// backend-specific options
|
||||
gl_force_gles2 bool // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available
|
||||
win32_console_utf8 bool // if true, set the output console codepage to UTF-8
|
||||
@ -77,6 +77,9 @@ pub:
|
||||
ios_keyboard_resizes_canvas bool // if true, showing the iOS keyboard shrinks the canvas
|
||||
// V patches
|
||||
__v_native_render bool // V patch to allow for native rendering
|
||||
pub mut:
|
||||
allocator C.sapp_allocator // optional memory allocation overrides (default: malloc/free)
|
||||
logger C.sapp_logger // optional log callback overrides (default: SAPP_LOG(message))
|
||||
}
|
||||
|
||||
pub type Desc = C.sapp_desc
|
||||
@ -84,25 +87,25 @@ pub type Desc = C.sapp_desc
|
||||
[typedef]
|
||||
pub struct C.sapp_event {
|
||||
pub:
|
||||
frame_count u64
|
||||
@type EventType
|
||||
key_code KeyCode
|
||||
char_code u32
|
||||
key_repeat bool
|
||||
modifiers u32
|
||||
mouse_button MouseButton
|
||||
mouse_x f32
|
||||
mouse_y f32
|
||||
mouse_dx f32
|
||||
mouse_dy f32
|
||||
scroll_x f32
|
||||
scroll_y f32
|
||||
num_touches int
|
||||
touches [max_touchpoints]TouchPoint
|
||||
window_width int
|
||||
window_height int
|
||||
framebuffer_width int
|
||||
framebuffer_height int
|
||||
frame_count u64 // current frame counter, always valid, useful for checking if two events were issued in the same frame
|
||||
@type EventType // the event type, always valid
|
||||
key_code KeyCode // the virtual key code, only valid in KEY_UP, KEY_DOWN
|
||||
char_code u32 // the UTF-32 character code, only valid in CHAR events
|
||||
key_repeat bool // true if this is a key-repeat event, valid in KEY_UP, KEY_DOWN and CHAR
|
||||
modifiers u32 // current modifier keys, valid in all key-, char- and mouse-events
|
||||
mouse_button MouseButton // mouse button that was pressed or released, valid in MOUSE_DOWN, MOUSE_UP
|
||||
mouse_x f32 // current horizontal mouse position in pixels, always valid except during mouse lock
|
||||
mouse_y f32 // current vertical mouse position in pixels, always valid except during mouse lock
|
||||
mouse_dx f32 // relative horizontal mouse movement since last frame, always valid
|
||||
mouse_dy f32 // relative vertical mouse movement since last frame, always valid
|
||||
scroll_x f32 // horizontal mouse wheel scroll distance, valid in MOUSE_SCROLL events
|
||||
scroll_y f32 // vertical mouse wheel scroll distance, valid in MOUSE_SCROLL events
|
||||
num_touches int // number of valid items in the touches[] array
|
||||
touches [max_touchpoints]TouchPoint // current touch points, valid in TOUCHES_BEGIN, TOUCHES_MOVED, TOUCHES_ENDED
|
||||
window_width int // current window- and framebuffer width in pixels, always valid
|
||||
window_height int // current window- and framebuffer height in pixels, always valid
|
||||
framebuffer_width int // = window_width * dpi_scale
|
||||
framebuffer_height int // = window_height * dpi_scale
|
||||
}
|
||||
|
||||
pub type Event = C.sapp_event
|
||||
@ -114,11 +117,11 @@ pub fn (e &C.sapp_event) str() string {
|
||||
[typedef]
|
||||
pub struct C.sapp_touchpoint {
|
||||
pub:
|
||||
identifier u64
|
||||
pos_x f32
|
||||
pos_y f32
|
||||
tool_type TouchToolType
|
||||
changed bool
|
||||
identifier u64
|
||||
pos_x f32
|
||||
pos_y f32
|
||||
android_tooltype TouchToolType
|
||||
changed bool
|
||||
}
|
||||
|
||||
pub type TouchPoint = C.sapp_touchpoint
|
||||
|
@ -2,13 +2,27 @@ module sfons
|
||||
|
||||
import fontstash
|
||||
import sokol.f
|
||||
import sokol.memory
|
||||
|
||||
// keep v from warning about unused imports
|
||||
const used_import = f.used_import + fontstash.used_import + 1
|
||||
|
||||
// create a new Context/font atlas, for rendering glyphs, given its dimensions `width` and `height`
|
||||
[inline]
|
||||
pub fn create(width int, height int, flags int) &fontstash.Context {
|
||||
return C.sfons_create(width, height, flags)
|
||||
assert is_power_of_two(width)
|
||||
assert is_power_of_two(height)
|
||||
allocator := C.sfons_allocator_t{
|
||||
alloc: memory.salloc
|
||||
free: memory.sfree
|
||||
user_data: voidptr(0x100005f0)
|
||||
}
|
||||
desc := C.sfons_desc_t{
|
||||
width: width
|
||||
height: height
|
||||
allocator: allocator
|
||||
}
|
||||
return C.sfons_create(&desc)
|
||||
}
|
||||
|
||||
[inline]
|
||||
@ -25,3 +39,7 @@ pub fn rgba(r u8, g u8, b u8, a u8) u32 {
|
||||
pub fn flush(ctx &fontstash.Context) {
|
||||
C.sfons_flush(ctx)
|
||||
}
|
||||
|
||||
fn is_power_of_two(x int) bool {
|
||||
return x in [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768]
|
||||
}
|
||||
|
@ -1,8 +1,26 @@
|
||||
module sfons
|
||||
|
||||
import fontstash
|
||||
import sokol.memory
|
||||
|
||||
fn C.sfons_create(width int, height int, flags int) &fontstash.Context
|
||||
[typedef]
|
||||
pub struct C.sfons_allocator_t {
|
||||
pub:
|
||||
alloc memory.FnAllocatorAlloc
|
||||
free memory.FnAllocatorFree
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.sfons_desc_t {
|
||||
pub:
|
||||
width int // initial width of font atlas texture (default: 512, must be power of 2)
|
||||
height int // initial height of font atlas texture (default: 512, must be power of 2)
|
||||
allocator C.sfons_allocator_t // optional memory allocation overrides
|
||||
}
|
||||
|
||||
fn C.sfons_create(desc &C.sfons_desc_t) &fontstash.Context
|
||||
fn C.sfons_destroy(ctx &fontstash.Context)
|
||||
fn C.sfons_rgba(r u8, g u8, b u8, a u8) u32
|
||||
fn C.sfons_flush(ctx &fontstash.Context)
|
||||
|
||||
fn C.sfons_rgba(r u8, g u8, b u8, a u8) u32
|
||||
|
@ -1,19 +1,29 @@
|
||||
module sgl
|
||||
|
||||
import sokol.gfx
|
||||
import sokol.memory
|
||||
|
||||
pub const (
|
||||
version = gfx.version + 1
|
||||
context = Context{0x00010001} // C.SGL_DEFAULT_CONTEXT = { 0x00010001 }
|
||||
)
|
||||
pub const version = gfx.version + 1
|
||||
|
||||
pub const context = Context{0x00010001} // C.SGL_DEFAULT_CONTEXT = { 0x00010001 }
|
||||
|
||||
// setup/shutdown/misc
|
||||
[inline]
|
||||
pub fn setup(desc &Desc) {
|
||||
if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.allocator.alloc = memory.salloc
|
||||
desc.allocator.free = memory.sfree
|
||||
desc.allocator.user_data = voidptr(0x10000561)
|
||||
}
|
||||
}
|
||||
if desc.logger.log_cb == unsafe { nil } {
|
||||
unsafe {
|
||||
desc.logger.log_cb = memory.slog
|
||||
}
|
||||
}
|
||||
C.sgl_setup(desc)
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn shutdown() {
|
||||
C.sgl_shutdown()
|
||||
}
|
||||
|
18
vlib/sokol/sgl/sgl_allocator_and_logger.c.v
Normal file
18
vlib/sokol/sgl/sgl_allocator_and_logger.c.v
Normal file
@ -0,0 +1,18 @@
|
||||
module sgl
|
||||
|
||||
import sokol.memory
|
||||
|
||||
[typedef]
|
||||
pub struct C.sgl_allocator_t {
|
||||
pub mut:
|
||||
alloc memory.FnAllocatorAlloc
|
||||
free memory.FnAllocatorFree
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.sgl_logger_t {
|
||||
pub mut:
|
||||
log_cb memory.FnLogCb
|
||||
user_data voidptr
|
||||
}
|
@ -25,7 +25,7 @@ pub type Context = C.sgl_context
|
||||
pub type ContextDesc = C.sgl_context_desc_t
|
||||
|
||||
[typedef]
|
||||
struct C.sgl_context_desc_t {
|
||||
pub struct C.sgl_context_desc_t {
|
||||
max_vertices int // default: 64k
|
||||
max_commands int // default: 16k
|
||||
color_format gfx.PixelFormat // C.sg_pixel_format
|
||||
@ -36,7 +36,8 @@ struct C.sgl_context_desc_t {
|
||||
pub type Desc = C.sgl_desc_t
|
||||
|
||||
[typedef]
|
||||
struct C.sgl_desc_t {
|
||||
pub struct C.sgl_desc_t {
|
||||
pub:
|
||||
max_vertices int // size for vertex buffer
|
||||
max_commands int // size of uniform- and command-buffers
|
||||
context_pool_size int // max number of contexts (including default context), default: 4
|
||||
@ -45,4 +46,7 @@ struct C.sgl_desc_t {
|
||||
depth_format gfx.PixelFormat // C.sg_pixel_format
|
||||
sample_count int
|
||||
face_winding gfx.FaceWinding // C.sg_face_winding // default front face winding is CCW
|
||||
pub mut:
|
||||
allocator C.sgl_allocator_t // optional memory allocation overrides (default: malloc/free)
|
||||
logger C.sgl_logger_t // optional memory allocation overrides (default: SOKOL_LOG(message))
|
||||
}
|
||||
|
@ -2,4 +2,4 @@ vlib/v/checker/tests/modules/module_with_redeclaration/redeclare_time_structs.v:
|
||||
1 | module module_with_redeclaration
|
||||
| ^
|
||||
2 |
|
||||
3 | pub const used = 1
|
||||
3 | import sokol.memory
|
||||
|
@ -1,6 +1,27 @@
|
||||
module module_with_redeclaration
|
||||
|
||||
import sokol.memory
|
||||
|
||||
pub const used = 1
|
||||
|
||||
struct C.saudio_desc {
|
||||
[typedef]
|
||||
pub struct C.saudio_allocator {
|
||||
pub mut:
|
||||
alloc memory.FnAllocatorAlloc
|
||||
free memory.FnAllocatorFree
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
[typedef]
|
||||
pub struct C.saudio_logger {
|
||||
pub mut:
|
||||
log_cb memory.FnLogCb
|
||||
user_data voidptr
|
||||
}
|
||||
|
||||
struct C.saudio_desc {
|
||||
pub mut:
|
||||
user_data voidptr
|
||||
allocator C.saudio_allocator
|
||||
logger C.saudio_logger
|
||||
}
|
||||
|
@ -1,24 +1,52 @@
|
||||
vlib/sokol/audio/audio.v:86:26: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
84 | fn C.saudio_userdata() voidptr
|
||||
85 |
|
||||
86 | fn C.saudio_query_desc() C.saudio_desc
|
||||
vlib/sokol/audio/audio.v:107:26: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
105 | fn C.saudio_userdata() voidptr
|
||||
106 |
|
||||
107 | fn C.saudio_query_desc() C.saudio_desc
|
||||
| ~~~~~~~~~~~~~
|
||||
87 |
|
||||
88 | fn C.saudio_sample_rate() int
|
||||
vlib/sokol/audio/audio.v:101:19: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
99 |
|
||||
100 | // setup - setup sokol-audio
|
||||
101 | pub fn setup(desc &C.saudio_desc) {
|
||||
108 |
|
||||
109 | fn C.saudio_sample_rate() int
|
||||
vlib/sokol/audio/audio.v:122:19: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
120 |
|
||||
121 | // setup - setup sokol-audio
|
||||
122 | pub fn setup(desc &C.saudio_desc) {
|
||||
| ~~~~~~~~~~~~~~
|
||||
102 | C.saudio_setup(desc)
|
||||
103 | }
|
||||
vlib/sokol/audio/audio.v:121:16: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
119 |
|
||||
120 | // query - return a copy of the original saudio_desc struct
|
||||
121 | pub fn query() C.saudio_desc {
|
||||
123 | if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||
124 | unsafe {
|
||||
vlib/sokol/audio/audio.v:125:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
123 | if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||
124 | unsafe {
|
||||
125 | desc.allocator.alloc = memory.salloc
|
||||
| ~~~~~~~~~
|
||||
126 | desc.allocator.free = memory.sfree
|
||||
127 | desc.allocator.user_data = voidptr(0x100a0d10)
|
||||
vlib/sokol/audio/audio.v:126:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
124 | unsafe {
|
||||
125 | desc.allocator.alloc = memory.salloc
|
||||
126 | desc.allocator.free = memory.sfree
|
||||
| ~~~~~~~~~
|
||||
127 | desc.allocator.user_data = voidptr(0x100a0d10)
|
||||
128 | }
|
||||
vlib/sokol/audio/audio.v:127:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
125 | desc.allocator.alloc = memory.salloc
|
||||
126 | desc.allocator.free = memory.sfree
|
||||
127 | desc.allocator.user_data = voidptr(0x100a0d10)
|
||||
| ~~~~~~~~~
|
||||
128 | }
|
||||
129 | }
|
||||
vlib/sokol/audio/audio.v:132:9: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
130 | if desc.logger.log_cb == unsafe { nil } {
|
||||
131 | unsafe {
|
||||
132 | desc.logger.log_cb = memory.slog
|
||||
| ~~~~~~
|
||||
133 | }
|
||||
134 | }
|
||||
vlib/sokol/audio/audio.v:154:16: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `sokol.audio`
|
||||
152 |
|
||||
153 | // query - return a copy of the original saudio_desc struct
|
||||
154 | pub fn query() C.saudio_desc {
|
||||
| ~~~~~~~~~~~~~
|
||||
122 | return C.saudio_query_desc()
|
||||
123 | }
|
||||
155 | return C.saudio_query_desc()
|
||||
156 | }
|
||||
vlib/v/checker/tests/private_redeclaration_of_C_struct.vv:7:10: error: struct `C.saudio_desc` was declared as private to module `module_with_redeclaration`, so it can not be used inside module `main`
|
||||
5 |
|
||||
6 | fn main() {
|
||||
|
Loading…
Reference in New Issue
Block a user