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
|
258
thirdparty/fontstash/stb_truetype.h
vendored
258
thirdparty/fontstash/stb_truetype.h
vendored
@ -1,5 +1,5 @@
|
|||||||
// stb_truetype.h - v1.24 - public domain
|
// stb_truetype.h - v1.26 - public domain
|
||||||
// authored from 2009-2020 by Sean Barrett / RAD Game Tools
|
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
|
||||||
//
|
//
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
//
|
//
|
||||||
@ -58,6 +58,8 @@
|
|||||||
//
|
//
|
||||||
// VERSION HISTORY
|
// 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.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.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.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
||||||
@ -270,8 +272,8 @@
|
|||||||
//// SAMPLE PROGRAMS
|
//// 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
|
#if 0
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
||||||
#include "stb_truetype.h"
|
#include "stb_truetype.h"
|
||||||
@ -297,6 +299,8 @@ void my_stbtt_initfont(void)
|
|||||||
void my_stbtt_print(float x, float y, char *text)
|
void my_stbtt_print(float x, float y, char *text)
|
||||||
{
|
{
|
||||||
// assume orthographic projection with units = screen pixels, origin at top left
|
// 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);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glBindTexture(GL_TEXTURE_2D, ftex);
|
glBindTexture(GL_TEXTURE_2D, ftex);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
@ -304,10 +308,10 @@ void my_stbtt_print(float x, float y, char *text)
|
|||||||
if (*text >= 32 && *text < 128) {
|
if (*text >= 32 && *text < 128) {
|
||||||
stbtt_aligned_quad q;
|
stbtt_aligned_quad q;
|
||||||
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
|
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.s0,q.t0); glVertex2f(q.x0,q.y0);
|
||||||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
|
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
|
||||||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
|
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
|
||||||
glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
|
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
|
||||||
}
|
}
|
||||||
++text;
|
++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);
|
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
||||||
// frees the data allocated above
|
// 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_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);
|
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
|
||||||
// fills svg with the character's SVG data.
|
// 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;
|
search += 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
stbtt_uint16 offset, start;
|
stbtt_uint16 offset, start, last;
|
||||||
stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
|
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);
|
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;
|
return 0;
|
||||||
|
|
||||||
offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
|
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);
|
if (comp_verts) STBTT_free(comp_verts, info->userdata);
|
||||||
return 0;
|
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));
|
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
|
||||||
if (vertices) STBTT_free(vertices, info->userdata);
|
if (vertices) STBTT_free(vertices, info->userdata);
|
||||||
vertices = tmp;
|
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);
|
subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
|
||||||
has_subrs = 1;
|
has_subrs = 1;
|
||||||
}
|
}
|
||||||
// fallthrough
|
// FALLTHROUGH
|
||||||
case 0x1D: // callgsubr
|
case 0x1D: // callgsubr
|
||||||
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
|
||||||
v = (int) s[--sp];
|
v = (int) s[--sp];
|
||||||
@ -2239,7 +2244,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
|
if (b0 != 255 && b0 != 28 && b0 < 32)
|
||||||
return STBTT__CSERR("reserved operator");
|
return STBTT__CSERR("reserved operator");
|
||||||
|
|
||||||
// push immediate
|
// push immediate
|
||||||
@ -2384,7 +2389,7 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph
|
|||||||
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);
|
stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
|
||||||
switch(coverageFormat) {
|
switch (coverageFormat) {
|
||||||
case 1: {
|
case 1: {
|
||||||
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
|
||||||
|
|
||||||
@ -2405,7 +2410,8 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
|
||||||
@ -2429,12 +2435,10 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
|||||||
return startCoverageIndex + glyph - strawStart;
|
return startCoverageIndex + glyph - strawStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: return -1; // unsupported
|
||||||
// There are no other cases.
|
|
||||||
STBTT_assert(0);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -2443,7 +2447,7 @@ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyp
|
|||||||
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
||||||
{
|
{
|
||||||
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
|
||||||
switch(classDefFormat)
|
switch (classDefFormat)
|
||||||
{
|
{
|
||||||
case 1: {
|
case 1: {
|
||||||
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
|
||||||
@ -2452,9 +2456,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
|||||||
|
|
||||||
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
|
||||||
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
|
||||||
|
break;
|
||||||
classDefTable = classDef1ValueArray + 2 * glyphCount;
|
}
|
||||||
} break;
|
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
|
||||||
@ -2476,17 +2479,15 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
|
|||||||
else
|
else
|
||||||
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
classDefTable = classRangeRecords + 6 * classRangeCount;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
// There are no other cases.
|
|
||||||
STBTT_assert(0);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
default:
|
||||||
|
return -1; // Unsupported definition type, return an error.
|
||||||
|
}
|
||||||
|
|
||||||
|
// "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 to STBTT_assert(x) if you want to break on unimplemented formats.
|
||||||
@ -2498,7 +2499,7 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||||||
stbtt_uint8 *lookupList;
|
stbtt_uint8 *lookupList;
|
||||||
stbtt_uint16 lookupCount;
|
stbtt_uint16 lookupCount;
|
||||||
stbtt_uint8 *data;
|
stbtt_uint8 *data;
|
||||||
stbtt_int32 i;
|
stbtt_int32 i, sti;
|
||||||
|
|
||||||
if (!info->gpos) return 0;
|
if (!info->gpos) return 0;
|
||||||
|
|
||||||
@ -2518,9 +2519,9 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||||||
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
stbtt_uint16 lookupType = ttUSHORT(lookupTable);
|
||||||
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
|
||||||
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
stbtt_uint8 *subTableOffsets = lookupTable + 6;
|
||||||
switch(lookupType) {
|
if (lookupType != 2) // Pair Adjustment Positioning Subtable
|
||||||
case 2: { // Pair Adjustment Positioning Subtable
|
continue;
|
||||||
stbtt_int32 sti;
|
|
||||||
for (sti=0; sti<subTableCount; sti++) {
|
for (sti=0; sti<subTableCount; sti++) {
|
||||||
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
|
||||||
stbtt_uint8 *table = lookupTable + subtableOffset;
|
stbtt_uint8 *table = lookupTable + subtableOffset;
|
||||||
@ -2535,20 +2536,15 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||||||
int straw, needle;
|
int straw, needle;
|
||||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||||
|
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||||
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
stbtt_int32 valueRecordPairSizeInBytes = 2;
|
||||||
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
|
||||||
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
|
||||||
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
stbtt_uint8 *pairValueTable = table + pairPosOffset;
|
||||||
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
|
||||||
stbtt_uint8 *pairValueArray = pairValueTable + 2;
|
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;
|
|
||||||
|
|
||||||
STBTT_assert(coverageIndex < pairSetCount);
|
if (coverageIndex >= pairSetCount) return 0;
|
||||||
STBTT__NOTUSED(pairSetCount);
|
|
||||||
|
|
||||||
needle=glyph2;
|
needle=glyph2;
|
||||||
r=pairValueCount-1;
|
r=pairValueCount-1;
|
||||||
@ -2571,12 +2567,15 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||||||
return xAdvance;
|
return xAdvance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} else
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
|
||||||
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
|
||||||
|
if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
|
||||||
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
|
||||||
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
|
||||||
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
|
||||||
@ -2584,36 +2583,24 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
|||||||
|
|
||||||
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
stbtt_uint16 class1Count = ttUSHORT(table + 12);
|
||||||
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
stbtt_uint16 class2Count = ttUSHORT(table + 14);
|
||||||
STBTT_assert(glyph1class < class1Count);
|
stbtt_uint8 *class1Records, *class2Records;
|
||||||
STBTT_assert(glyph2class < class2Count);
|
stbtt_int16 xAdvance;
|
||||||
|
|
||||||
// TODO: Support more formats.
|
if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
|
||||||
STBTT_GPOS_TODO_assert(valueFormat1 == 4);
|
if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
|
||||||
if (valueFormat1 != 4) return 0;
|
|
||||||
STBTT_GPOS_TODO_assert(valueFormat2 == 0);
|
|
||||||
if (valueFormat2 != 0) return 0;
|
|
||||||
|
|
||||||
if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
|
class1Records = table + 16;
|
||||||
stbtt_uint8 *class1Records = table + 16;
|
class2Records = class1Records + 2 * (glyph1class * class2Count);
|
||||||
stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
|
xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
||||||
stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
|
|
||||||
return xAdvance;
|
return xAdvance;
|
||||||
}
|
} else
|
||||||
} break;
|
return 0;
|
||||||
|
|
||||||
default: {
|
|
||||||
// There are no other cases.
|
|
||||||
STBTT_assert(0);
|
|
||||||
break;
|
break;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO: Implement other stuff.
|
return 0; // Unsupported position format
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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)
|
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;
|
float y_bottom = y_top+1;
|
||||||
@ -3129,13 +3133,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
|
|||||||
float height;
|
float height;
|
||||||
// simple case, only spans one pixel
|
// simple case, only spans one pixel
|
||||||
int x = (int) x_top;
|
int x = (int) x_top;
|
||||||
height = sy1 - sy0;
|
height = (sy1 - sy0) * e->direction;
|
||||||
STBTT_assert(x >= 0 && x < len);
|
STBTT_assert(x >= 0 && x < len);
|
||||||
scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
|
scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
|
||||||
scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
|
scanline_fill[x] += height; // everything right of this pixel is filled
|
||||||
} else {
|
} else {
|
||||||
int x,x1,x2;
|
int x,x1,x2;
|
||||||
float y_crossing, step, sign, area;
|
float y_crossing, y_final, step, sign, area;
|
||||||
// covers 2+ pixels
|
// covers 2+ pixels
|
||||||
if (x_top > x_bottom) {
|
if (x_top > x_bottom) {
|
||||||
// flip scanline vertically; signed area is the same
|
// 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;
|
dy = -dy;
|
||||||
t = x0, x0 = xb, xb = t;
|
t = x0, x0 = xb, xb = t;
|
||||||
}
|
}
|
||||||
|
STBTT_assert(dy >= 0);
|
||||||
|
STBTT_assert(dx >= 0);
|
||||||
|
|
||||||
x1 = (int) x_top;
|
x1 = (int) x_top;
|
||||||
x2 = (int) x_bottom;
|
x2 = (int) x_bottom;
|
||||||
// compute intersection with y axis at x1+1
|
// 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;
|
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) {
|
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;
|
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);
|
// 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 * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
|
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);
|
scanline_fill[x2] += sign * (sy1-sy0);
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// clipping logic. since this does not match the intended use
|
||||||
// of this library, we use a different, very slow brute
|
// of this library, we use a different, very slow brute
|
||||||
// force implementation
|
// 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;
|
int x;
|
||||||
for (x=0; x < len; ++x) {
|
for (x=0; x < len; ++x) {
|
||||||
// cases:
|
// cases:
|
||||||
@ -4414,15 +4471,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
|
|||||||
float y_frac;
|
float y_frac;
|
||||||
int winding = 0;
|
int winding = 0;
|
||||||
|
|
||||||
orig[0] = x;
|
|
||||||
orig[1] = y;
|
|
||||||
|
|
||||||
// make sure y never passes through a vertex of the shape
|
// make sure y never passes through a vertex of the shape
|
||||||
y_frac = (float) STBTT_fmod(y, 1.0f);
|
y_frac = (float) STBTT_fmod(y, 1.0f);
|
||||||
if (y_frac < 0.01f)
|
if (y_frac < 0.01f)
|
||||||
y += 0.01f;
|
y += 0.01f;
|
||||||
else if (y_frac > 0.99f)
|
else if (y_frac > 0.99f)
|
||||||
y -= 0.01f;
|
y -= 0.01f;
|
||||||
|
|
||||||
|
orig[0] = x;
|
||||||
orig[1] = y;
|
orig[1] = y;
|
||||||
|
|
||||||
// test a ray from (-infinity,y) to (x,y)
|
// test a ray from (-infinity,y) to (x,y)
|
||||||
@ -4484,7 +4540,7 @@ static float stbtt__cuberoot( float x )
|
|||||||
return (float) STBTT_pow( x,1.0f/3.0f);
|
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)
|
static int stbtt__solve_cubic(float a, float b, float c, float* r)
|
||||||
{
|
{
|
||||||
float s = -a / 3;
|
float s = -a / 3;
|
||||||
@ -4589,18 +4645,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
|||||||
for (i=0; i < num_verts; ++i) {
|
for (i=0; i < num_verts; ++i) {
|
||||||
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
|
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
|
if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
|
||||||
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
|
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)
|
if (dist2 < min_dist*min_dist)
|
||||||
min_dist = (float) STBTT_sqrt(dist2);
|
min_dist = (float) STBTT_sqrt(dist2);
|
||||||
|
|
||||||
if (verts[i].type == STBTT_vline) {
|
|
||||||
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
|
|
||||||
|
|
||||||
// coarse culling against bbox
|
// coarse culling against bbox
|
||||||
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
|
//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)
|
// 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);
|
STBTT_assert(i != 0);
|
||||||
if (dist < min_dist) {
|
if (dist < min_dist) {
|
||||||
// check position along line
|
// 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 ax = x1-x0, ay = y1-y0;
|
||||||
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
|
||||||
float mx = x0 - sx, my = y0 - sy;
|
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];
|
float a_inv = precompute[i];
|
||||||
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
|
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);
|
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;
|
float d = (mx*ax+my*ay) * a_inv;
|
||||||
num = stbtt__solve_cubic(b, c, d, res);
|
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) {
|
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
|
||||||
t = res[0], it = 1.0f - t;
|
t = res[0], it = 1.0f - t;
|
||||||
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
|
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
|
// 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.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
|
||||||
// 1.18 (2018-01-29) add missing function
|
// 1.18 (2018-01-29) add missing function
|
||||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||||
|
1630
thirdparty/sokol/sokol_app.h
vendored
1630
thirdparty/sokol/sokol_app.h
vendored
File diff suppressed because it is too large
Load Diff
325
thirdparty/sokol/sokol_audio.h
vendored
325
thirdparty/sokol/sokol_audio.h
vendored
@ -17,9 +17,6 @@
|
|||||||
|
|
||||||
SOKOL_DUMMY_BACKEND - use a dummy backend
|
SOKOL_DUMMY_BACKEND - use a dummy backend
|
||||||
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
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_AUDIO_API_DECL- public function declaration prefix (default: extern)
|
||||||
SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL
|
SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL
|
||||||
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
||||||
@ -316,6 +313,8 @@
|
|||||||
|
|
||||||
"Blob URLs": https://www.html5rocks.com/en/tutorials/workers/basics/
|
"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
|
||||||
=====================
|
=====================
|
||||||
The CoreAudio backend is selected on macOS and iOS (__APPLE__ is defined).
|
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
|
header must be present (usually both are installed with some sort
|
||||||
of ALSA development package).
|
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
|
LICENSE
|
||||||
=======
|
=======
|
||||||
|
|
||||||
@ -392,6 +447,7 @@
|
|||||||
distribution.
|
distribution.
|
||||||
*/
|
*/
|
||||||
#define SOKOL_AUDIO_INCLUDED (1)
|
#define SOKOL_AUDIO_INCLUDED (1)
|
||||||
|
#include <stddef.h> // size_t
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -412,15 +468,42 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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 {
|
typedef struct saudio_desc {
|
||||||
int sample_rate; /* requested sample rate */
|
int sample_rate; // requested sample rate
|
||||||
int num_channels; /* number of channels, default: 1 (mono) */
|
int num_channels; // number of channels, default: 1 (mono)
|
||||||
int buffer_frames; /* number of frames in streaming buffer */
|
int buffer_frames; // number of frames in streaming buffer
|
||||||
int packet_frames; /* number of frames in a packet */
|
int packet_frames; // number of frames in a packet
|
||||||
int num_packets; /* number of packets in packet queue */
|
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_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 (*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 */
|
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;
|
} saudio_desc;
|
||||||
|
|
||||||
/* setup sokol-audio */
|
/* setup sokol-audio */
|
||||||
@ -458,6 +541,12 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|||||||
/*=== IMPLEMENTATION =========================================================*/
|
/*=== IMPLEMENTATION =========================================================*/
|
||||||
#ifdef SOKOL_AUDIO_IMPL
|
#ifdef SOKOL_AUDIO_IMPL
|
||||||
#define SOKOL_AUDIO_IMPL_INCLUDED (1)
|
#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 <string.h> // memset, memcpy
|
||||||
#include <stddef.h> // size_t
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
@ -466,24 +555,26 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
|
|||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_DEBUG
|
#ifndef SOKOL_DEBUG
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define SOKOL_DEBUG (1)
|
#define SOKOL_DEBUG
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_ASSERT
|
#ifndef SOKOL_ASSERT
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define SOKOL_ASSERT(c) assert(c)
|
#define SOKOL_ASSERT(c) assert(c)
|
||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_MALLOC
|
|
||||||
#include <stdlib.h>
|
#if !defined(SOKOL_DEBUG)
|
||||||
#define SOKOL_MALLOC(s) malloc(s)
|
#define SAUDIO_LOG(s)
|
||||||
#define SOKOL_FREE(p) free(p)
|
#else
|
||||||
#endif
|
#define SAUDIO_LOG(s) _saudio_log(s)
|
||||||
#ifndef SOKOL_LOG
|
#ifndef SOKOL_LOG
|
||||||
#ifdef SOKOL_DEBUG
|
#if defined(__ANDROID__)
|
||||||
#include <stdio.h>
|
#include <android/log.h>
|
||||||
#define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
|
#define SOKOL_LOG(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_AUDIO", s)
|
||||||
#else
|
#else
|
||||||
#define SOKOL_LOG(s)
|
#include <stdio.h>
|
||||||
|
#define SOKOL_LOG(s) puts(s)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -670,6 +761,9 @@ typedef OSStatus _saudio_OSStatus;
|
|||||||
#define _saudio_kAudioFormatFlagIsPacked (kAudioFormatFlagIsPacked)
|
#define _saudio_kAudioFormatFlagIsPacked (kAudioFormatFlagIsPacked)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
// embedded AudioToolbox declarations
|
// embedded AudioToolbox declarations
|
||||||
typedef uint32_t _saudio_AudioFormatID;
|
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 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 AudioQueueStart(_saudio_AudioQueueRef inAQ, const _saudio_AudioTimeStamp * inStartTime);
|
||||||
extern _saudio_OSStatus AudioQueueStop(_saudio_AudioQueueRef inAQ, bool inImmediate);
|
extern _saudio_OSStatus AudioQueueStop(_saudio_AudioQueueRef inAQ, bool inImmediate);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // SAUDIO_OSX_USE_SYSTEM_HEADERS
|
#endif // SAUDIO_OSX_USE_SYSTEM_HEADERS
|
||||||
|
|
||||||
typedef struct {
|
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 ===================================================*/
|
/*=== MUTEX IMPLEMENTATION ===================================================*/
|
||||||
#if defined(_SAUDIO_NOTHREADS)
|
#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));
|
SOKOL_ASSERT((packet_size > 0) && (num_packets > 0));
|
||||||
fifo->packet_size = packet_size;
|
fifo->packet_size = packet_size;
|
||||||
fifo->num_packets = num_packets;
|
fifo->num_packets = num_packets;
|
||||||
fifo->base_ptr = (uint8_t*) SOKOL_MALLOC((size_t)(packet_size * num_packets));
|
fifo->base_ptr = (uint8_t*) _saudio_malloc((size_t)(packet_size * num_packets));
|
||||||
SOKOL_ASSERT(fifo->base_ptr);
|
|
||||||
fifo->cur_packet = -1;
|
fifo->cur_packet = -1;
|
||||||
fifo->cur_offset = 0;
|
fifo->cur_offset = 0;
|
||||||
_saudio_ring_init(&fifo->read_queue, num_packets);
|
_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_PRIVATE void _saudio_fifo_shutdown(_saudio_fifo_t* fifo) {
|
||||||
SOKOL_ASSERT(fifo->base_ptr);
|
SOKOL_ASSERT(fifo->base_ptr);
|
||||||
SOKOL_FREE(fifo->base_ptr);
|
_saudio_free(fifo->base_ptr);
|
||||||
fifo->base_ptr = 0;
|
fifo->base_ptr = 0;
|
||||||
fifo->valid = false;
|
fifo->valid = false;
|
||||||
_saudio_mutex_destroy(&fifo->mutex);
|
_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;
|
int num_bytes = (int) buffer->mAudioDataByteSize;
|
||||||
if (0 == _saudio_fifo_read(&_saudio.fifo, ptr, num_bytes)) {
|
if (0 == _saudio_fifo_read(&_saudio.fifo, ptr, num_bytes)) {
|
||||||
/* not enough read data available, fill the entire buffer with silence */
|
/* 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);
|
AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
|
||||||
@ -1213,7 +1356,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
|
|
||||||
/* create an audio queue with fp32 samples */
|
/* create an audio queue with fp32 samples */
|
||||||
_saudio_AudioStreamBasicDescription fmt;
|
_saudio_AudioStreamBasicDescription fmt;
|
||||||
memset(&fmt, 0, sizeof(fmt));
|
_saudio_clear(&fmt, sizeof(fmt));
|
||||||
fmt.mSampleRate = (double) _saudio.sample_rate;
|
fmt.mSampleRate = (double) _saudio.sample_rate;
|
||||||
fmt.mFormatID = _saudio_kAudioFormatLinearPCM;
|
fmt.mFormatID = _saudio_kAudioFormatLinearPCM;
|
||||||
fmt.mFormatFlags = _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked;
|
fmt.mFormatFlags = _saudio_kLinearPCMFormatFlagIsFloat | _saudio_kAudioFormatFlagIsPacked;
|
||||||
@ -1223,16 +1366,16 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
fmt.mBytesPerPacket = fmt.mBytesPerFrame;
|
fmt.mBytesPerPacket = fmt.mBytesPerFrame;
|
||||||
fmt.mBitsPerChannel = 32;
|
fmt.mBitsPerChannel = 32;
|
||||||
_saudio_OSStatus res = AudioQueueNewOutput(&fmt, _saudio_coreaudio_callback, 0, NULL, NULL, 0, &_saudio.backend.ca_audio_queue);
|
_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 */
|
/* create 2 audio buffers */
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
_saudio_AudioQueueBufferRef buf = NULL;
|
_saudio_AudioQueueBufferRef buf = NULL;
|
||||||
const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame;
|
const uint32_t buf_byte_size = (uint32_t)_saudio.buffer_frames * fmt.mBytesPerFrame;
|
||||||
res = AudioQueueAllocateBuffer(_saudio.backend.ca_audio_queue, buf_byte_size, &buf);
|
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;
|
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);
|
AudioQueueEnqueueBuffer(_saudio.backend.ca_audio_queue, buf, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1241,7 +1384,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
|
|
||||||
/* ...and start playback */
|
/* ...and start playback */
|
||||||
res = AudioQueueStart(_saudio.backend.ca_audio_queue, NULL);
|
res = AudioQueueStart(_saudio.backend.ca_audio_queue, NULL);
|
||||||
SOKOL_ASSERT(0 == res);
|
SOKOL_ASSERT(0 == res); (void)res;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1284,7 +1427,7 @@ _SOKOL_PRIVATE void* _saudio_alsa_cb(void* param) {
|
|||||||
else {
|
else {
|
||||||
if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) {
|
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 */
|
/* 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 dir; uint32_t rate;
|
||||||
int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
SOKOL_LOG("sokol_audio.h: snd_pcm_open() failed");
|
SAUDIO_LOG("sokol_audio.h: snd_pcm_open() failed");
|
||||||
return false;
|
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_any(_saudio.backend.device, params);
|
||||||
snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
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)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (0 > snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, (snd_pcm_uframes_t)_saudio.buffer_frames)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (0 > snd_pcm_hw_params_set_channels(_saudio.backend.device, params, (uint32_t)_saudio.num_channels)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
/* let ALSA pick a nearby sampling rate */
|
/* let ALSA pick a nearby sampling rate */
|
||||||
rate = (uint32_t) _saudio.sample_rate;
|
rate = (uint32_t) _saudio.sample_rate;
|
||||||
dir = 0;
|
dir = 0;
|
||||||
if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &rate, &dir)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1339,12 +1482,11 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
/* allocate the streaming buffer */
|
/* allocate the streaming buffer */
|
||||||
_saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame;
|
_saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame;
|
||||||
_saudio.backend.buffer_frames = _saudio.buffer_frames;
|
_saudio.backend.buffer_frames = _saudio.buffer_frames;
|
||||||
_saudio.backend.buffer = (float*) SOKOL_MALLOC((size_t)_saudio.backend.buffer_byte_size);
|
_saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size);
|
||||||
memset(_saudio.backend.buffer, 0, (size_t)_saudio.backend.buffer_byte_size);
|
|
||||||
|
|
||||||
/* create the buffer-streaming start thread */
|
/* create the buffer-streaming start thread */
|
||||||
if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_alsa_cb, 0)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1363,7 +1505,7 @@ _SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
|
|||||||
pthread_join(_saudio.backend.thread, 0);
|
pthread_join(_saudio.backend.thread, 0);
|
||||||
snd_pcm_drain(_saudio.backend.device);
|
snd_pcm_drain(_saudio.backend.device);
|
||||||
snd_pcm_close(_saudio.backend.device);
|
snd_pcm_close(_saudio.backend.device);
|
||||||
SOKOL_FREE(_saudio.backend.buffer);
|
_saudio_free(_saudio.backend.buffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*=== WASAPI BACKEND IMPLEMENTATION ==========================================*/
|
/*=== WASAPI BACKEND IMPLEMENTATION ==========================================*/
|
||||||
@ -1419,7 +1561,7 @@ _SOKOL_PRIVATE void _saudio_wasapi_fill_buffer(void) {
|
|||||||
else {
|
else {
|
||||||
if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.thread.src_buffer, _saudio.backend.thread.src_buffer_byte_size)) {
|
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 */
|
/* 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) {
|
_SOKOL_PRIVATE void _saudio_wasapi_release(void) {
|
||||||
if (_saudio.backend.thread.src_buffer) {
|
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;
|
_saudio.backend.thread.src_buffer = 0;
|
||||||
}
|
}
|
||||||
if (_saudio.backend.render_client) {
|
if (_saudio.backend.render_client) {
|
||||||
@ -1537,17 +1679,17 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
#endif
|
#endif
|
||||||
_saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0);
|
_saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0);
|
||||||
if (0 == _saudio.backend.thread.buffer_end_event) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
#if defined(_SAUDIO_UWP)
|
#if defined(_SAUDIO_UWP)
|
||||||
_saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex");
|
_saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex");
|
||||||
if (_saudio.backend.interface_activation_mutex == NULL) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (FAILED(StringFromIID(_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_Devinterface_Audio_Render), &_saudio.backend.interface_activation_audio_interface_uid_string))) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1561,7 +1703,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
static IActivateAudioInterfaceCompletionHandler completion_handler_interface = { &completion_handler_interface_vtable };
|
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))) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
while (!(_saudio.backend.audio_client)) {
|
while (!(_saudio.backend.audio_client)) {
|
||||||
@ -1571,7 +1713,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(_saudio.backend.interface_activation_success)) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1581,14 +1723,14 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator),
|
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator),
|
||||||
(void**)&_saudio.backend.device_enumerator)))
|
(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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator,
|
if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator,
|
||||||
eRender, eConsole,
|
eRender, eConsole,
|
||||||
&_saudio.backend.device)))
|
&_saudio.backend.device)))
|
||||||
{
|
{
|
||||||
SOKOL_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed");
|
SAUDIO_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (FAILED(IMMDevice_Activate(_saudio.backend.device,
|
if (FAILED(IMMDevice_Activate(_saudio.backend.device,
|
||||||
@ -1596,13 +1738,13 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
CLSCTX_ALL, 0,
|
CLSCTX_ALL, 0,
|
||||||
(void**)&_saudio.backend.audio_client)))
|
(void**)&_saudio.backend.audio_client)))
|
||||||
{
|
{
|
||||||
SOKOL_LOG("sokol_audio wasapi: device activate failed");
|
SAUDIO_LOG("sokol_audio wasapi: device activate failed");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WAVEFORMATEXTENSIBLE fmtex;
|
WAVEFORMATEXTENSIBLE fmtex;
|
||||||
memset(&fmtex, 0, sizeof(fmtex));
|
_saudio_clear(&fmtex, sizeof(fmtex));
|
||||||
fmtex.Format.nChannels = (WORD)_saudio.num_channels;
|
fmtex.Format.nChannels = (WORD)_saudio.num_channels;
|
||||||
fmtex.Format.nSamplesPerSec = (DWORD)_saudio.sample_rate;
|
fmtex.Format.nSamplesPerSec = (DWORD)_saudio.sample_rate;
|
||||||
fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
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,
|
AUDCLNT_STREAMFLAGS_EVENTCALLBACK|AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
|
||||||
dur, 0, (WAVEFORMATEX*)&fmtex, 0)))
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (FAILED(IAudioClient_GetBufferSize(_saudio.backend.audio_client, &_saudio.backend.thread.dst_buffer_frames))) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (FAILED(IAudioClient_GetService(_saudio.backend.audio_client,
|
if (FAILED(IAudioClient_GetService(_saudio.backend.audio_client,
|
||||||
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioRenderClient),
|
_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioRenderClient),
|
||||||
(void**)&_saudio.backend.render_client)))
|
(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;
|
goto error;
|
||||||
}
|
}
|
||||||
if (FAILED(IAudioClient_SetEventHandle(_saudio.backend.audio_client, _saudio.backend.thread.buffer_end_event))) {
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
_saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
|
_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;
|
_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 */
|
/* 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);
|
_saudio.backend.thread.src_buffer = (float*) _saudio_malloc((size_t)_saudio.backend.thread.src_buffer_byte_size);
|
||||||
SOKOL_ASSERT(_saudio.backend.thread.src_buffer);
|
|
||||||
|
|
||||||
/* create streaming thread */
|
/* create streaming thread */
|
||||||
_saudio.backend.thread.thread_handle = CreateThread(NULL, 0, _saudio_wasapi_thread_fn, 0, 0, 0);
|
_saudio.backend.thread.thread_handle = CreateThread(NULL, 0, _saudio_wasapi_thread_fn, 0, 0, 0);
|
||||||
if (0 == _saudio.backend.thread.thread_handle) {
|
if (0 == _saudio.backend.thread.thread_handle) {
|
||||||
SOKOL_LOG("sokol_audio wasapi: CreateThread failed");
|
SAUDIO_LOG("sokol_audio wasapi: CreateThread failed");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
const int num_bytes = num_frames * _saudio.bytes_per_frame;
|
||||||
if (0 == _saudio_fifo_read(&_saudio.fifo, _saudio.backend.buffer, num_bytes)) {
|
if (0 == _saudio_fifo_read(&_saudio.fifo, _saudio.backend.buffer, num_bytes)) {
|
||||||
/* not enough read data available, fill the entire buffer with silence */
|
/* 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;
|
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',
|
latencyHint: 'interactive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (typeof webkitAudioContext !== 'undefined') {
|
|
||||||
Module._saudio_context = new webkitAudioContext({
|
|
||||||
sampleRate: sample_rate,
|
|
||||||
latencyHint: 'interactive',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
Module._saudio_context = null;
|
Module._saudio_context = null;
|
||||||
console.log('sokol_audio.h: no WebAudio support');
|
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) {
|
if (Module._saudio_context) {
|
||||||
console.log('sokol_audio.h: sample rate ', Module._saudio_context.sampleRate);
|
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 = Module._saudio_context.createScriptProcessor(buffer_size, 0, num_channels);
|
||||||
Module._saudio_node.onaudioprocess = function pump_audio(event) {
|
Module._saudio_node.onaudioprocess = (event) => {
|
||||||
var num_frames = event.outputBuffer.length;
|
const num_frames = event.outputBuffer.length;
|
||||||
var ptr = __saudio_emsc_pull(num_frames);
|
const ptr = __saudio_emsc_pull(num_frames);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
var num_channels = event.outputBuffer.numberOfChannels;
|
const num_channels = event.outputBuffer.numberOfChannels;
|
||||||
for (var chn = 0; chn < num_channels; chn++) {
|
for (let chn = 0; chn < num_channels; chn++) {
|
||||||
var chan = event.outputBuffer.getChannelData(chn);
|
const chan = event.outputBuffer.getChannelData(chn);
|
||||||
for (var i = 0; i < num_frames; i++) {
|
for (let i = 0; i < num_frames; i++) {
|
||||||
chan[i] = HEAPF32[(ptr>>2) + ((num_channels*i)+chn)]
|
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);
|
Module._saudio_node.connect(Module._saudio_context.destination);
|
||||||
|
|
||||||
// in some browsers, WebAudio needs to be activated on a user action
|
// 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) {
|
||||||
if (Module._saudio_context.state === 'suspended') {
|
if (Module._saudio_context.state === 'suspended') {
|
||||||
Module._saudio_context.resume();
|
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 */
|
/* shutdown the WebAudioContext and ScriptProcessorNode */
|
||||||
EM_JS(void, saudio_js_shutdown, (void), {
|
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) {
|
if (Module._saudio_node) {
|
||||||
Module._saudio_node.disconnect();
|
Module._saudio_node.disconnect();
|
||||||
}
|
}
|
||||||
Module._saudio_context.close();
|
ctx.close();
|
||||||
Module._saudio_context = null;
|
Module._saudio_context = null;
|
||||||
Module._saudio_node = null;
|
Module._saudio_node = null;
|
||||||
}
|
}
|
||||||
@ -1819,7 +1956,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
_saudio.sample_rate = saudio_js_sample_rate();
|
_saudio.sample_rate = saudio_js_sample_rate();
|
||||||
_saudio.buffer_frames = saudio_js_buffer_frames();
|
_saudio.buffer_frames = saudio_js_buffer_frames();
|
||||||
const size_t buf_size = (size_t) (_saudio.buffer_frames * _saudio.bytes_per_frame);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1830,7 +1967,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
|||||||
_SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
|
_SOKOL_PRIVATE void _saudio_backend_shutdown(void) {
|
||||||
saudio_js_shutdown();
|
saudio_js_shutdown();
|
||||||
if (_saudio.backend.buffer) {
|
if (_saudio.backend.buffer) {
|
||||||
SOKOL_FREE(_saudio.backend.buffer);
|
_saudio_free(_saudio.backend.buffer);
|
||||||
_saudio.backend.buffer = 0;
|
_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);
|
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)) {
|
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 */
|
/* 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_PRIVATE void* _saudio_opensles_thread_fn(void* param) {
|
||||||
|
_SOKOL_UNUSED(param);
|
||||||
while (!_saudio.backend.thread_stop) {
|
while (!_saudio.backend.thread_stop) {
|
||||||
/* get next output buffer, advance, next buffer. */
|
/* get next output buffer, advance, next buffer. */
|
||||||
int16_t* out_buffer = _saudio.backend.output_buffers[_saudio.backend.active_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++) {
|
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) {
|
_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) {
|
for (int i = 0; i < SAUDIO_NUM_BUFFERS; ++i) {
|
||||||
const int buffer_size_bytes = (int)sizeof(int16_t) * _saudio.num_channels * _saudio.buffer_frames;
|
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);
|
_saudio.backend.output_buffers[i] = (int16_t*) _saudio_malloc_clear((size_t)buffer_size_bytes);
|
||||||
SOKOL_ASSERT(_saudio.backend.output_buffers[i]);
|
|
||||||
memset(_saudio.backend.output_buffers[i], 0x0, (size_t)buffer_size_bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const int buffer_size_bytes = _saudio.bytes_per_frame * _saudio.buffer_frames;
|
const int buffer_size_bytes = _saudio.bytes_per_frame * _saudio.buffer_frames;
|
||||||
_saudio.backend.src_buffer = (float*) SOKOL_MALLOC((size_t)buffer_size_bytes);
|
_saudio.backend.src_buffer = (float*) _saudio_malloc_clear((size_t)buffer_size_bytes);
|
||||||
SOKOL_ASSERT(_saudio.backend.src_buffer);
|
|
||||||
memset(_saudio.backend.src_buffer, 0x0, (size_t)buffer_size_bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create engine */
|
/* 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) {
|
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();
|
_saudio_backend_shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*_saudio.backend.engine_obj)->Realize(_saudio.backend.engine_obj, SL_BOOLEAN_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) {
|
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();
|
_saudio_backend_shutdown();
|
||||||
return false;
|
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)
|
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();
|
_saudio_backend_shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
(*_saudio.backend.output_mix_obj)->Realize(_saudio.backend.output_mix_obj, SL_BOOLEAN_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) {
|
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_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
||||||
SOKOL_ASSERT(!_saudio.valid);
|
SOKOL_ASSERT(!_saudio.valid);
|
||||||
SOKOL_ASSERT(desc);
|
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.desc = *desc;
|
||||||
_saudio.stream_cb = desc->stream_cb;
|
_saudio.stream_cb = desc->stream_cb;
|
||||||
_saudio.stream_userdata_cb = desc->stream_userdata_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
|
the requested packet size
|
||||||
*/
|
*/
|
||||||
if (0 != (_saudio.buffer_frames % _saudio.packet_frames)) {
|
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();
|
_saudio_backend_shutdown();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
1788
thirdparty/sokol/sokol_gfx.h
vendored
1788
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:
|
...optionally provide the following macros to override defaults:
|
||||||
|
|
||||||
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
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_FONTSTASH_API_DECL - public function declaration prefix (default: extern)
|
||||||
SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL
|
SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL
|
||||||
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
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))
|
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
|
||||||
|
|
||||||
Include the following headers before including sokol_fontstash.h:
|
Include the following headers before including sokol_fontstash.h:
|
||||||
@ -55,7 +52,10 @@
|
|||||||
--- Create at least one fontstash context with sfons_create() (this replaces
|
--- Create at least one fontstash context with sfons_create() (this replaces
|
||||||
glfonsCreate() from fontstash.h's example GL renderer:
|
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
|
Each FONScontext manages one font atlas texture which can hold rasterized
|
||||||
glyphs for multiple fonts.
|
glyphs for multiple fonts.
|
||||||
@ -88,7 +88,7 @@
|
|||||||
|
|
||||||
--- finally on application shutdown, call:
|
--- finally on application shutdown, call:
|
||||||
|
|
||||||
sfons_shutdown()
|
sfons_destroy(FONScontext* ctx)
|
||||||
|
|
||||||
before sgl_shutdown() and sg_shutdown()
|
before sgl_shutdown() and sg_shutdown()
|
||||||
|
|
||||||
@ -96,7 +96,7 @@
|
|||||||
WHAT HAPPENS UNDER THE HOOD:
|
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 a sokol-gfx shader compatible with sokol-gl
|
||||||
- creates an sgl_pipeline object with alpha-blending using
|
- creates an sgl_pipeline object with alpha-blending using
|
||||||
this shader
|
this shader
|
||||||
@ -122,14 +122,43 @@
|
|||||||
all calls to fonsDrawText() will be merged into a single draw call
|
all calls to fonsDrawText() will be merged into a single draw call
|
||||||
as long as all calls use the same FONScontext
|
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
|
- this will call sg_update_image() on the font atlas texture
|
||||||
if fontstash.h has added any rasterized glyphs since the last
|
if fontstash.h has added any rasterized glyphs since the last
|
||||||
frame
|
frame
|
||||||
|
|
||||||
sfons_shutdown():
|
sfons_destroy(FONScontext* ctx):
|
||||||
- destroy the font atlas texture, sgl_pipeline and sg_shader objects
|
- 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
|
LICENSE
|
||||||
=======
|
=======
|
||||||
zlib/libpng license
|
zlib/libpng license
|
||||||
@ -158,6 +187,7 @@
|
|||||||
#define SOKOL_FONTSTASH_INCLUDED (1)
|
#define SOKOL_FONTSTASH_INCLUDED (1)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
#if !defined(SOKOL_GFX_INCLUDED)
|
#if !defined(SOKOL_GFX_INCLUDED)
|
||||||
#error "Please include sokol_gfx.h before sokol_fontstash.h"
|
#error "Please include sokol_gfx.h before sokol_fontstash.h"
|
||||||
@ -179,7 +209,30 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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_destroy(FONScontext* ctx);
|
||||||
SOKOL_FONTSTASH_API_DECL void sfons_flush(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);
|
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 ----------------------------------------------------------*/
|
/*-- IMPLEMENTATION ----------------------------------------------------------*/
|
||||||
#ifdef SOKOL_FONTSTASH_IMPL
|
#ifdef SOKOL_FONTSTASH_IMPL
|
||||||
#define SOKOL_FONTSTASH_IMPL_INCLUDED (1)
|
#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)
|
#if !defined(SOKOL_GL_INCLUDED)
|
||||||
#error "Please include sokol_gl.h before sokol_fontstash.h"
|
#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
|
#endif
|
||||||
#ifndef SOKOL_DEBUG
|
#ifndef SOKOL_DEBUG
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define SOKOL_DEBUG (1)
|
#define SOKOL_DEBUG
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_ASSERT
|
#ifndef SOKOL_ASSERT
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define SOKOL_ASSERT(c) assert(c)
|
#define SOKOL_ASSERT(c) assert(c)
|
||||||
#endif
|
#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
|
#ifndef SOKOL_UNREACHABLE
|
||||||
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
|
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
|
||||||
#endif
|
#endif
|
||||||
@ -1609,13 +1655,48 @@ static const char* _sfons_fs_source_dummy = "";
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct _sfons_t {
|
typedef struct _sfons_t {
|
||||||
|
sfons_desc_t desc;
|
||||||
sg_shader shd;
|
sg_shader shd;
|
||||||
sgl_pipeline pip;
|
sgl_pipeline pip;
|
||||||
sg_image img;
|
sg_image img;
|
||||||
int width, height;
|
int cur_width, cur_height;
|
||||||
bool img_dirty;
|
bool img_dirty;
|
||||||
} _sfons_t;
|
} _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) {
|
static int _sfons_render_create(void* user_ptr, int width, int height) {
|
||||||
SOKOL_ASSERT(user_ptr && (width > 8) && (height > 8));
|
SOKOL_ASSERT(user_ptr && (width > 8) && (height > 8));
|
||||||
_sfons_t* sfons = (_sfons_t*) user_ptr;
|
_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 */
|
/* sokol-gl compatible shader which treats RED channel as alpha */
|
||||||
if (sfons->shd.id == SG_INVALID_ID) {
|
if (sfons->shd.id == SG_INVALID_ID) {
|
||||||
sg_shader_desc shd_desc;
|
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[0].name = "position";
|
||||||
shd_desc.attrs[1].name = "texcoord0";
|
shd_desc.attrs[1].name = "texcoord0";
|
||||||
shd_desc.attrs[2].name = "color0";
|
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 */
|
/* sokol-gl pipeline object */
|
||||||
if (sfons->pip.id == SG_INVALID_ID) {
|
if (sfons->pip.id == SG_INVALID_ID) {
|
||||||
sg_pipeline_desc pip_desc;
|
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.shader = sfons->shd;
|
||||||
pip_desc.colors[0].blend.enabled = true;
|
pip_desc.colors[0].blend.enabled = true;
|
||||||
pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
|
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);
|
sg_destroy_image(sfons->img);
|
||||||
sfons->img.id = SG_INVALID_ID;
|
sfons->img.id = SG_INVALID_ID;
|
||||||
}
|
}
|
||||||
sfons->width = width;
|
sfons->cur_width = width;
|
||||||
sfons->height = height;
|
sfons->cur_height = height;
|
||||||
|
|
||||||
SOKOL_ASSERT(sfons->img.id == SG_INVALID_ID);
|
SOKOL_ASSERT(sfons->img.id == SG_INVALID_ID);
|
||||||
sg_image_desc img_desc;
|
sg_image_desc img_desc;
|
||||||
memset(&img_desc, 0, sizeof(img_desc));
|
_sfons_clear(&img_desc, sizeof(img_desc));
|
||||||
img_desc.width = sfons->width;
|
img_desc.width = sfons->cur_width;
|
||||||
img_desc.height = sfons->height;
|
img_desc.height = sfons->cur_height;
|
||||||
img_desc.min_filter = SG_FILTER_LINEAR;
|
img_desc.min_filter = SG_FILTER_LINEAR;
|
||||||
img_desc.mag_filter = SG_FILTER_LINEAR;
|
img_desc.mag_filter = SG_FILTER_LINEAR;
|
||||||
img_desc.usage = SG_USAGE_DYNAMIC;
|
img_desc.usage = SG_USAGE_DYNAMIC;
|
||||||
@ -1759,42 +1840,43 @@ static void _sfons_render_delete(void* user_ptr) {
|
|||||||
sg_destroy_shader(sfons->shd);
|
sg_destroy_shader(sfons->shd);
|
||||||
sfons->shd.id = SG_INVALID_ID;
|
sfons->shd.id = SG_INVALID_ID;
|
||||||
}
|
}
|
||||||
SOKOL_FREE(sfons);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE clang analyzer will report a potential memory leak for the call
|
#define _sfons_def(val, def) (((val) == 0) ? (def) : (val))
|
||||||
// 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
|
|
||||||
|
|
||||||
SOKOL_API_IMPL FONScontext* sfons_create(int width, int height, int flags) {
|
static sfons_desc_t _sfons_desc_defaults(const sfons_desc_t* desc) {
|
||||||
SOKOL_ASSERT((width > 0) && (height > 0));
|
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;
|
FONSparams params;
|
||||||
_sfons_t* sfons = (_sfons_t*) SOKOL_MALLOC(sizeof(_sfons_t));
|
_sfons_clear(¶ms, sizeof(params));
|
||||||
memset(sfons, 0, sizeof(_sfons_t));
|
params.width = sfons->desc.width;
|
||||||
memset(¶ms, 0, sizeof(params));
|
params.height = sfons->desc.height;
|
||||||
params.width = width;
|
params.flags = FONS_ZERO_TOPLEFT;
|
||||||
params.height = height;
|
|
||||||
params.flags = (unsigned char) flags;
|
|
||||||
params.renderCreate = _sfons_render_create;
|
params.renderCreate = _sfons_render_create;
|
||||||
params.renderResize = _sfons_render_resize;
|
params.renderResize = _sfons_render_resize;
|
||||||
params.renderUpdate = _sfons_render_update;
|
params.renderUpdate = _sfons_render_update;
|
||||||
params.renderDraw = _sfons_render_draw;
|
params.renderDraw = _sfons_render_draw;
|
||||||
params.renderDelete = _sfons_render_delete;
|
params.renderDelete = _sfons_render_delete;
|
||||||
params.userPtr = sfons;
|
params.userPtr = sfons;
|
||||||
FONScontext* ctx = fonsCreateInternal(¶ms);
|
return fonsCreateInternal(¶ms);
|
||||||
_SFONS_CLANG_ANALYZER_SILENCE_POTENTIAL_LEAK_FALSE_POSITIVE(sfons);
|
|
||||||
return ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) {
|
SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) {
|
||||||
SOKOL_ASSERT(ctx);
|
SOKOL_ASSERT(ctx);
|
||||||
|
_sfons_t* sfons = (_sfons_t*) ctx->params.userPtr;
|
||||||
fonsDeleteInternal(ctx);
|
fonsDeleteInternal(ctx);
|
||||||
|
const sfons_allocator_t allocator = sfons->desc.allocator;
|
||||||
|
_sfons_free(&allocator, sfons);
|
||||||
}
|
}
|
||||||
|
|
||||||
SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) {
|
SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) {
|
||||||
@ -1803,9 +1885,9 @@ SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) {
|
|||||||
if (sfons->img_dirty) {
|
if (sfons->img_dirty) {
|
||||||
sfons->img_dirty = false;
|
sfons->img_dirty = false;
|
||||||
sg_image_data data;
|
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].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);
|
sg_update_image(sfons->img, &data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
480
thirdparty/sokol/util/sokol_gl.h
vendored
480
thirdparty/sokol/util/sokol_gl.h
vendored
@ -27,12 +27,9 @@
|
|||||||
...optionally provide the following macros to override defaults:
|
...optionally provide the following macros to override defaults:
|
||||||
|
|
||||||
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
|
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_GL_API_DECL - public function declaration prefix (default: extern)
|
||||||
SOKOL_API_DECL - same as SOKOL_GL_API_DECL
|
SOKOL_API_DECL - same as SOKOL_GL_API_DECL
|
||||||
SOKOL_API_IMPL - public function implementation prefix (default: -)
|
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))
|
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
|
||||||
|
|
||||||
If sokol_gl.h is compiled as a DLL, define the following before
|
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,
|
...if sokol-gl is in an error-state, sgl_draw() will skip any rendering,
|
||||||
and reset the error code to SGL_NO_ERROR.
|
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:
|
WORKING WITH CONTEXTS:
|
||||||
======================
|
======================
|
||||||
@ -466,7 +489,7 @@
|
|||||||
The only functions which call into sokol_gfx.h are:
|
The only functions which call into sokol_gfx.h are:
|
||||||
- sgl_setup()
|
- sgl_setup()
|
||||||
- sgl_shutdown()
|
- sgl_shutdown()
|
||||||
- sgl_draw()
|
- sgl_draw() (and variants)
|
||||||
|
|
||||||
sgl_setup() must be called after initializing sokol-gfx.
|
sgl_setup() must be called after initializing sokol-gfx.
|
||||||
sgl_shutdown() must be called before shutting down sokol-gfx.
|
sgl_shutdown() must be called before shutting down sokol-gfx.
|
||||||
@ -511,10 +534,13 @@
|
|||||||
all pipeline objects) are destroyed
|
all pipeline objects) are destroyed
|
||||||
- the 3 memory buffers are freed
|
- the 3 memory buffers are freed
|
||||||
|
|
||||||
sgl_draw():
|
sgl_draw() (and variants)
|
||||||
- copy all recorded vertex data into the dynamic sokol-gfx buffer
|
- copy all recorded vertex data into the dynamic sokol-gfx buffer
|
||||||
via a call to sg_update_buffer()
|
via a call to sg_update_buffer()
|
||||||
- for each recorded command:
|
- 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 viewport command, call sg_apply_viewport()
|
||||||
- if it's a scissor-rect command, call sg_apply_scissor_rect()
|
- if it's a scissor-rect command, call sg_apply_scissor_rect()
|
||||||
- if it's a draw command:
|
- if it's a draw command:
|
||||||
@ -536,10 +562,11 @@
|
|||||||
A draw command will be merged with the previous command if "no relevant
|
A draw command will be merged with the previous command if "no relevant
|
||||||
state has changed" since the last sgl_end(), meaning:
|
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 hasn't changed
|
||||||
- the primitive type isn't a 'strip type' (no line or triangle strip)
|
- the primitive type isn't a 'strip type' (no line or triangle strip)
|
||||||
- the pipeline state object hasn't changed
|
- the pipeline state object hasn't changed
|
||||||
|
- the current layer hasn't changed
|
||||||
- none of the matrices has changed
|
- none of the matrices has changed
|
||||||
- none of the texture state 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
|
to render in the previous draw command will be incremented by the
|
||||||
number of vertices in the new draw command.
|
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
|
LICENSE
|
||||||
=======
|
=======
|
||||||
zlib/libpng license
|
zlib/libpng license
|
||||||
@ -575,6 +651,7 @@
|
|||||||
#define SOKOL_GL_INCLUDED (1)
|
#define SOKOL_GL_INCLUDED (1)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h> // size_t, offsetof
|
||||||
|
|
||||||
#if !defined(SOKOL_GFX_INCLUDED)
|
#if !defined(SOKOL_GFX_INCLUDED)
|
||||||
#error "Please include sokol_gfx.h before sokol_gl.h"
|
#error "Please include sokol_gfx.h before sokol_gl.h"
|
||||||
@ -634,6 +711,31 @@ typedef struct sgl_context_desc_t {
|
|||||||
int sample_count;
|
int sample_count;
|
||||||
} sgl_context_desc_t;
|
} 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 {
|
typedef struct sgl_desc_t {
|
||||||
int max_vertices; // default: 64k
|
int max_vertices; // default: 64k
|
||||||
int max_commands; // default: 16k
|
int max_commands; // default: 16k
|
||||||
@ -643,6 +745,8 @@ typedef struct sgl_desc_t {
|
|||||||
sg_pixel_format depth_format;
|
sg_pixel_format depth_format;
|
||||||
int sample_count;
|
int sample_count;
|
||||||
sg_face_winding face_winding; // default: SG_FACEWINDING_CCW
|
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;
|
} sgl_desc_t;
|
||||||
|
|
||||||
/* the default context handle */
|
/* 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_get_context(void);
|
||||||
SOKOL_GL_API_DECL sgl_context sgl_default_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 */
|
/* 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_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);
|
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_enable_texture(void);
|
||||||
SOKOL_GL_API_DECL void sgl_disable_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_texture(sg_image img);
|
||||||
|
SOKOL_GL_API_DECL void sgl_layer(int layer_id);
|
||||||
|
|
||||||
/* pipeline stack functions */
|
/* pipeline stack functions */
|
||||||
SOKOL_GL_API_DECL void sgl_load_default_pipeline(void);
|
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_v3f_t2f_c1i(float x, float y, float z, float u, float v, uint32_t rgba);
|
||||||
SOKOL_GL_API_DECL void sgl_end(void);
|
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
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|
||||||
@ -764,9 +871,13 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline
|
|||||||
#ifdef SOKOL_GL_IMPL
|
#ifdef SOKOL_GL_IMPL
|
||||||
#define SOKOL_GL_IMPL_INCLUDED (1)
|
#define SOKOL_GL_IMPL_INCLUDED (1)
|
||||||
|
|
||||||
#include <stddef.h> /* offsetof */
|
#if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
|
||||||
#include <string.h> /* memset */
|
#error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sgl_desc_t.allocator to override memory allocation functions"
|
||||||
#include <math.h> /* M_PI, sqrtf, sinf, cosf */
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h> // malloc/free
|
||||||
|
#include <string.h> // memset
|
||||||
|
#include <math.h> // M_PI, sqrtf, sinf, cosf
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846264338327
|
#define M_PI 3.14159265358979323846264338327
|
||||||
@ -777,28 +888,27 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline
|
|||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_DEBUG
|
#ifndef SOKOL_DEBUG
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define SOKOL_DEBUG (1)
|
#define SOKOL_DEBUG
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_ASSERT
|
#ifndef SOKOL_ASSERT
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define SOKOL_ASSERT(c) assert(c)
|
#define SOKOL_ASSERT(c) assert(c)
|
||||||
#endif
|
#endif
|
||||||
#ifndef SOKOL_MALLOC
|
|
||||||
#include <stdlib.h>
|
#if !defined(SOKOL_DEBUG)
|
||||||
#define SOKOL_MALLOC(s) malloc(s)
|
#define SGL_LOG(s)
|
||||||
#define SOKOL_FREE(p) free(p)
|
#else
|
||||||
#endif
|
#define SGL_LOG(s) _sgl_log(s)
|
||||||
#ifndef SOKOL_LOG
|
#ifndef SOKOL_LOG
|
||||||
#ifdef SOKOL_DEBUG
|
#if defined(__ANDROID__)
|
||||||
#include <stdio.h>
|
#include <android/log.h>
|
||||||
#define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
|
#define SOKOL_LOG(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_GL", s)
|
||||||
#else
|
#else
|
||||||
#define SOKOL_LOG(s)
|
#include <stdio.h>
|
||||||
|
#define SOKOL_LOG(s) puts(s)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
#ifndef SOKOL_UNREACHABLE
|
|
||||||
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _sgl_def(val, def) (((val) == 0) ? (def) : (val))
|
#define _sgl_def(val, def) (((val) == 0) ? (def) : (val))
|
||||||
@ -2192,6 +2302,7 @@ typedef union {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
_sgl_command_type_t cmd;
|
_sgl_command_type_t cmd;
|
||||||
|
int layer_id;
|
||||||
_sgl_args_t args;
|
_sgl_args_t args;
|
||||||
} _sgl_command_t;
|
} _sgl_command_t;
|
||||||
|
|
||||||
@ -2208,22 +2319,30 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
_sgl_slot_t slot;
|
_sgl_slot_t slot;
|
||||||
sgl_context_desc_t desc;
|
sgl_context_desc_t desc;
|
||||||
|
uint32_t frame_id;
|
||||||
int num_vertices;
|
uint32_t update_frame_id;
|
||||||
int num_uniforms;
|
struct {
|
||||||
int num_commands;
|
int cap;
|
||||||
int cur_vertex;
|
int next;
|
||||||
int cur_uniform;
|
_sgl_vertex_t* ptr;
|
||||||
int cur_command;
|
} vertices;
|
||||||
_sgl_vertex_t* vertices;
|
struct {
|
||||||
_sgl_uniform_t* uniforms;
|
int cap;
|
||||||
_sgl_command_t* commands;
|
int next;
|
||||||
|
_sgl_uniform_t* ptr;
|
||||||
|
} uniforms;
|
||||||
|
struct {
|
||||||
|
int cap;
|
||||||
|
int next;
|
||||||
|
_sgl_command_t* ptr;
|
||||||
|
} commands;
|
||||||
|
|
||||||
/* state tracking */
|
/* state tracking */
|
||||||
int base_vertex;
|
int base_vertex;
|
||||||
int vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */
|
int vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */
|
||||||
sgl_error_t error;
|
sgl_error_t error;
|
||||||
bool in_begin;
|
bool in_begin;
|
||||||
|
int layer_id;
|
||||||
float u, v;
|
float u, v;
|
||||||
uint32_t rgba;
|
uint32_t rgba;
|
||||||
float point_size;
|
float point_size;
|
||||||
@ -2266,6 +2385,49 @@ typedef struct {
|
|||||||
static _sgl_t _sgl;
|
static _sgl_t _sgl;
|
||||||
|
|
||||||
/*== PRIVATE FUNCTIONS =======================================================*/
|
/*== 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) {
|
static void _sgl_init_pool(_sgl_pool_t* pool, int num) {
|
||||||
SOKOL_ASSERT(pool && (num >= 1));
|
SOKOL_ASSERT(pool && (num >= 1));
|
||||||
@ -2274,12 +2436,9 @@ static void _sgl_init_pool(_sgl_pool_t* pool, int num) {
|
|||||||
pool->queue_top = 0;
|
pool->queue_top = 0;
|
||||||
/* generation counters indexable by pool slot index, slot 0 is reserved */
|
/* generation counters indexable by pool slot index, slot 0 is reserved */
|
||||||
size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size;
|
size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size;
|
||||||
pool->gen_ctrs = (uint32_t*) SOKOL_MALLOC(gen_ctrs_size);
|
pool->gen_ctrs = (uint32_t*) _sgl_malloc_clear(gen_ctrs_size);
|
||||||
SOKOL_ASSERT(pool->gen_ctrs);
|
|
||||||
memset(pool->gen_ctrs, 0, gen_ctrs_size);
|
|
||||||
/* it's not a bug to only reserve 'num' here */
|
/* it's not a bug to only reserve 'num' here */
|
||||||
pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int) * (size_t)num);
|
pool->free_queue = (int*) _sgl_malloc_clear(sizeof(int) * (size_t)num);
|
||||||
SOKOL_ASSERT(pool->free_queue);
|
|
||||||
/* never allocate the zero-th pool item since the invalid id is 0 */
|
/* never allocate the zero-th pool item since the invalid id is 0 */
|
||||||
for (int i = pool->size-1; i >= 1; i--) {
|
for (int i = pool->size-1; i >= 1; i--) {
|
||||||
pool->free_queue[pool->queue_top++] = 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) {
|
static void _sgl_discard_pool(_sgl_pool_t* pool) {
|
||||||
SOKOL_ASSERT(pool);
|
SOKOL_ASSERT(pool);
|
||||||
SOKOL_ASSERT(pool->free_queue);
|
SOKOL_ASSERT(pool->free_queue);
|
||||||
SOKOL_FREE(pool->free_queue);
|
_sgl_free(pool->free_queue);
|
||||||
pool->free_queue = 0;
|
pool->free_queue = 0;
|
||||||
SOKOL_ASSERT(pool->gen_ctrs);
|
SOKOL_ASSERT(pool->gen_ctrs);
|
||||||
SOKOL_FREE(pool->gen_ctrs);
|
_sgl_free(pool->gen_ctrs);
|
||||||
pool->gen_ctrs = 0;
|
pool->gen_ctrs = 0;
|
||||||
pool->size = 0;
|
pool->size = 0;
|
||||||
pool->queue_top = 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) {
|
static void _sgl_reset_context(_sgl_context_t* ctx) {
|
||||||
SOKOL_ASSERT(ctx);
|
SOKOL_ASSERT(ctx);
|
||||||
SOKOL_ASSERT(0 == ctx->vertices);
|
SOKOL_ASSERT(0 == ctx->vertices.ptr);
|
||||||
SOKOL_ASSERT(0 == ctx->uniforms);
|
SOKOL_ASSERT(0 == ctx->uniforms.ptr);
|
||||||
SOKOL_ASSERT(0 == ctx->commands);
|
SOKOL_ASSERT(0 == ctx->commands.ptr);
|
||||||
memset(ctx, 0, sizeof(_sgl_context_t));
|
_sgl_clear(ctx, sizeof(_sgl_context_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sgl_setup_context_pool(int pool_size) {
|
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));
|
SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE));
|
||||||
_sgl_init_pool(&_sgl.context_pool.pool, 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;
|
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);
|
_sgl.context_pool.contexts = (_sgl_context_t*) _sgl_malloc_clear(pool_byte_size);
|
||||||
SOKOL_ASSERT(_sgl.context_pool.contexts);
|
|
||||||
memset(_sgl.context_pool.contexts, 0, pool_byte_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sgl_discard_context_pool(void) {
|
static void _sgl_discard_context_pool(void) {
|
||||||
SOKOL_ASSERT(0 != _sgl.context_pool.contexts);
|
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);
|
_sgl_discard_pool(&_sgl.context_pool.pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sgl_reset_pipeline(_sgl_pipeline_t* pip) {
|
static void _sgl_reset_pipeline(_sgl_pipeline_t* pip) {
|
||||||
SOKOL_ASSERT(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) {
|
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));
|
SOKOL_ASSERT((pool_size > 0) && (pool_size < _SGL_MAX_POOL_SIZE));
|
||||||
_sgl_init_pool(&_sgl.pip_pool.pool, 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;
|
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);
|
_sgl.pip_pool.pips = (_sgl_pipeline_t*) _sgl_malloc_clear(pool_byte_size);
|
||||||
SOKOL_ASSERT(_sgl.pip_pool.pips);
|
|
||||||
memset(_sgl.pip_pool.pips, 0, pool_byte_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sgl_discard_pipeline_pool(void) {
|
static void _sgl_discard_pipeline_pool(void) {
|
||||||
SOKOL_ASSERT(0 != _sgl.pip_pool.pips);
|
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);
|
_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 {
|
else {
|
||||||
pip->pip[i] = sg_make_pipeline(&desc);
|
pip->pip[i] = sg_make_pipeline(&desc);
|
||||||
if (pip->pip[i].id == SG_INVALID_ID) {
|
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;
|
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);
|
_sgl_init_pipeline(pip_id, desc, ctx_desc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SOKOL_LOG("sokol_gl.h: pipeline pool exhausted!");
|
SGL_LOG("sokol_gl.h: pipeline pool exhausted!");
|
||||||
}
|
}
|
||||||
return pip_id;
|
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 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) {
|
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);
|
SOKOL_ASSERT((ctx_id.id != SG_INVALID_ID) && in_desc);
|
||||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||||
SOKOL_ASSERT(ctx);
|
SOKOL_ASSERT(ctx);
|
||||||
ctx->desc = _sgl_context_desc_defaults(in_desc);
|
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;
|
ctx->cur_img = _sgl.def_img;
|
||||||
|
|
||||||
// allocate buffers and pools
|
// allocate buffers and pools
|
||||||
ctx->num_vertices = ctx->desc.max_vertices;
|
ctx->vertices.cap = ctx->desc.max_vertices;
|
||||||
ctx->num_commands = ctx->num_uniforms = ctx->desc.max_commands;
|
ctx->commands.cap = ctx->uniforms.cap = ctx->desc.max_commands;
|
||||||
ctx->vertices = (_sgl_vertex_t*) SOKOL_MALLOC((size_t)ctx->num_vertices * sizeof(_sgl_vertex_t));
|
ctx->vertices.ptr = (_sgl_vertex_t*) _sgl_malloc((size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t));
|
||||||
SOKOL_ASSERT(ctx->vertices);
|
ctx->uniforms.ptr = (_sgl_uniform_t*) _sgl_malloc((size_t)ctx->uniforms.cap * sizeof(_sgl_uniform_t));
|
||||||
ctx->uniforms = (_sgl_uniform_t*) SOKOL_MALLOC((size_t)ctx->num_uniforms * sizeof(_sgl_uniform_t));
|
ctx->commands.ptr = (_sgl_command_t*) _sgl_malloc((size_t)ctx->commands.cap * sizeof(_sgl_command_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);
|
|
||||||
|
|
||||||
// create sokol-gfx resource objects
|
// create sokol-gfx resource objects
|
||||||
sg_push_debug_group("sokol-gl");
|
sg_push_debug_group("sokol-gl");
|
||||||
|
|
||||||
sg_buffer_desc vbuf_desc;
|
sg_buffer_desc vbuf_desc;
|
||||||
memset(&vbuf_desc, 0, sizeof(vbuf_desc));
|
_sgl_clear(&vbuf_desc, sizeof(vbuf_desc));
|
||||||
vbuf_desc.size = (size_t)ctx->num_vertices * sizeof(_sgl_vertex_t);
|
vbuf_desc.size = (size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t);
|
||||||
vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER;
|
vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER;
|
||||||
vbuf_desc.usage = SG_USAGE_STREAM;
|
vbuf_desc.usage = SG_USAGE_STREAM;
|
||||||
vbuf_desc.label = "sgl-vertex-buffer";
|
vbuf_desc.label = "sgl-vertex-buffer";
|
||||||
ctx->vbuf = sg_make_buffer(&vbuf_desc);
|
ctx->vbuf = sg_make_buffer(&vbuf_desc);
|
||||||
SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id);
|
SOKOL_ASSERT(SG_INVALID_ID != ctx->vbuf.id);
|
||||||
|
ctx->bind.vertex_buffers[0] = ctx->vbuf;
|
||||||
|
|
||||||
sg_pipeline_desc def_pip_desc;
|
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;
|
def_pip_desc.depth.write_enabled = true;
|
||||||
ctx->def_pip = _sgl_make_pipeline(&def_pip_desc, &ctx->desc);
|
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();
|
sg_pop_debug_group();
|
||||||
|
|
||||||
// default state
|
// default state
|
||||||
@ -2654,7 +2815,7 @@ static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) {
|
|||||||
_sgl_init_context(ctx_id, desc);
|
_sgl_init_context(ctx_id, desc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SOKOL_LOG("sokol_gl.h: context pool exhausted!");
|
SGL_LOG("sokol_gl.h: context pool exhausted!");
|
||||||
}
|
}
|
||||||
return ctx_id;
|
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) {
|
static void _sgl_destroy_context(sgl_context ctx_id) {
|
||||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
SOKOL_ASSERT(ctx->vertices);
|
SOKOL_ASSERT(ctx->vertices.ptr);
|
||||||
SOKOL_ASSERT(ctx->uniforms);
|
SOKOL_ASSERT(ctx->uniforms.ptr);
|
||||||
SOKOL_ASSERT(ctx->commands);
|
SOKOL_ASSERT(ctx->commands.ptr);
|
||||||
|
|
||||||
SOKOL_FREE(ctx->vertices);
|
_sgl_free(ctx->vertices.ptr);
|
||||||
SOKOL_FREE(ctx->uniforms);
|
_sgl_free(ctx->uniforms.ptr);
|
||||||
SOKOL_FREE(ctx->commands);
|
_sgl_free(ctx->commands.ptr);
|
||||||
|
ctx->vertices.ptr = 0;
|
||||||
ctx->vertices = 0;
|
ctx->uniforms.ptr = 0;
|
||||||
ctx->uniforms = 0;
|
ctx->commands.ptr = 0;
|
||||||
ctx->commands = 0;
|
|
||||||
|
|
||||||
sg_push_debug_group("sokol-gl");
|
sg_push_debug_group("sokol-gl");
|
||||||
sg_destroy_buffer(ctx->vbuf);
|
sg_destroy_buffer(ctx->vbuf);
|
||||||
_sgl_destroy_pipeline(ctx->def_pip);
|
_sgl_destroy_pipeline(ctx->def_pip);
|
||||||
|
sg_remove_commit_listener(_sgl_make_commit_listener(ctx));
|
||||||
sg_pop_debug_group();
|
sg_pop_debug_group();
|
||||||
|
|
||||||
_sgl_reset_context(ctx);
|
_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->in_begin = true;
|
||||||
ctx->base_vertex = ctx->cur_vertex;
|
ctx->base_vertex = ctx->vertices.next;
|
||||||
ctx->vtx_count = 0;
|
ctx->vtx_count = 0;
|
||||||
ctx->cur_prim_type = mode;
|
ctx->cur_prim_type = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sgl_rewind(_sgl_context_t* ctx) {
|
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->base_vertex = 0;
|
||||||
ctx->cur_vertex = 0;
|
|
||||||
ctx->cur_uniform = 0;
|
|
||||||
ctx->cur_command = 0;
|
|
||||||
ctx->error = SGL_NO_ERROR;
|
ctx->error = SGL_NO_ERROR;
|
||||||
|
ctx->layer_id = 0;
|
||||||
ctx->matrix_dirty = true;
|
ctx->matrix_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) {
|
// called from inside sokol-gfx sg_commit()
|
||||||
if (ctx->cur_vertex < ctx->num_vertices) {
|
static void _sgl_commit_listener(void* userdata) {
|
||||||
return &ctx->vertices[ctx->cur_vertex++];
|
_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 {
|
else {
|
||||||
ctx->error = SGL_ERROR_VERTICES_FULL;
|
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) {
|
static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) {
|
||||||
if (ctx->cur_uniform < ctx->num_uniforms) {
|
if (ctx->uniforms.next < ctx->uniforms.cap) {
|
||||||
return &ctx->uniforms[ctx->cur_uniform++];
|
return &ctx->uniforms.ptr[ctx->uniforms.next++];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ctx->error = SGL_ERROR_UNIFORMS_FULL;
|
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) {
|
static _sgl_command_t* _sgl_cur_command(_sgl_context_t* ctx) {
|
||||||
if (ctx->cur_command > 0) {
|
if (ctx->commands.next > 0) {
|
||||||
return &ctx->commands[ctx->cur_command - 1];
|
return &ctx->commands.ptr[ctx->commands.next - 1];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) {
|
static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) {
|
||||||
if (ctx->cur_command < ctx->num_commands) {
|
if (ctx->commands.next < ctx->commands.cap) {
|
||||||
return &ctx->commands[ctx->cur_command++];
|
return &ctx->commands.ptr[ctx->commands.next++];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ctx->error = SGL_ERROR_COMMANDS_FULL;
|
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);
|
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;
|
if (v < lo) return lo;
|
||||||
else if (v > hi) return hi;
|
else if (v > hi) return hi;
|
||||||
else return v;
|
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 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 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);
|
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);
|
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);
|
SOKOL_ASSERT(ctx->in_begin);
|
||||||
_sgl_vertex_t* vtx;
|
_sgl_vertex_t* vtx;
|
||||||
/* handle non-native primitive types */
|
/* handle non-native primitive types */
|
||||||
@ -2971,27 +3147,28 @@ static void _sgl_lookat(_sgl_matrix_t* dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* current top-of-stack projection matrix */
|
/* 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]];
|
return &ctx->matrix_stack[SGL_MATRIXMODE_PROJECTION][ctx->matrix_tos[SGL_MATRIXMODE_PROJECTION]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get top-of-stack modelview matrix */
|
/* 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]];
|
return &ctx->matrix_stack[SGL_MATRIXMODE_MODELVIEW][ctx->matrix_tos[SGL_MATRIXMODE_MODELVIEW]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get top-of-stack texture matrix */
|
/* 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]];
|
return &ctx->matrix_stack[SGL_MATRIXMODE_TEXTURE][ctx->matrix_tos[SGL_MATRIXMODE_TEXTURE]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get pointer to current top-of-stack of current matrix mode */
|
/* 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 &ctx->matrix_stack[ctx->cur_matrix_mode][ctx->matrix_tos[ctx->cur_matrix_mode]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// return sg_context_desc_t with patched defaults
|
// return sg_context_desc_t with patched defaults
|
||||||
static sgl_desc_t _sgl_desc_defaults(const sgl_desc_t* desc) {
|
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;
|
sgl_desc_t res = *desc;
|
||||||
res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES);
|
res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES);
|
||||||
res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS);
|
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;
|
pixels[i] = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
sg_image_desc img_desc;
|
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.type = SG_IMAGETYPE_2D;
|
||||||
img_desc.width = 8;
|
img_desc.width = 8;
|
||||||
img_desc.height = 8;
|
img_desc.height = 8;
|
||||||
@ -3025,7 +3202,7 @@ static void _sgl_setup_common(void) {
|
|||||||
|
|
||||||
// one shader for all contexts
|
// one shader for all contexts
|
||||||
sg_shader_desc shd_desc;
|
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[0].name = "position";
|
||||||
shd_desc.attrs[1].name = "texcoord0";
|
shd_desc.attrs[1].name = "texcoord0";
|
||||||
shd_desc.attrs[2].name = "color0";
|
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;
|
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);
|
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_pip_id = SG_INVALID_ID;
|
||||||
uint32_t cur_img_id = SG_INVALID_ID;
|
uint32_t cur_img_id = SG_INVALID_ID;
|
||||||
int cur_uniform_index = -1;
|
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) };
|
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);
|
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];
|
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) {
|
switch (cmd->cmd) {
|
||||||
case SGL_COMMAND_VIEWPORT:
|
case SGL_COMMAND_VIEWPORT:
|
||||||
{
|
{
|
||||||
@ -3138,7 +3323,7 @@ static void _sgl_draw(_sgl_context_t* ctx) {
|
|||||||
cur_img_id = args->img.id;
|
cur_img_id = args->img.id;
|
||||||
}
|
}
|
||||||
if (cur_uniform_index != args->uniform_index) {
|
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);
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &ub_range);
|
||||||
cur_uniform_index = args->uniform_index;
|
cur_uniform_index = args->uniform_index;
|
||||||
}
|
}
|
||||||
@ -3152,12 +3337,11 @@ static void _sgl_draw(_sgl_context_t* ctx) {
|
|||||||
}
|
}
|
||||||
sg_pop_debug_group();
|
sg_pop_debug_group();
|
||||||
}
|
}
|
||||||
_sgl_rewind(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static sgl_context_desc_t _sgl_as_context_desc(const sgl_desc_t* desc) {
|
static sgl_context_desc_t _sgl_as_context_desc(const sgl_desc_t* desc) {
|
||||||
sgl_context_desc_t ctx_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_vertices = desc->max_vertices;
|
||||||
ctx_desc.max_commands = desc->max_commands;
|
ctx_desc.max_commands = desc->max_commands;
|
||||||
ctx_desc.color_format = desc->color_format;
|
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 ========================================================*/
|
/*== PUBLIC FUNCTIONS ========================================================*/
|
||||||
SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) {
|
SOKOL_API_IMPL void sgl_setup(const sgl_desc_t* desc) {
|
||||||
SOKOL_ASSERT(desc);
|
SOKOL_ASSERT(desc);
|
||||||
memset(&_sgl, 0, sizeof(_sgl));
|
_sgl_clear(&_sgl, sizeof(_sgl));
|
||||||
_sgl.init_cookie = _SGL_INIT_COOKIE;
|
_sgl.init_cookie = _SGL_INIT_COOKIE;
|
||||||
_sgl.desc = _sgl_desc_defaults(desc);
|
_sgl.desc = _sgl_desc_defaults(desc);
|
||||||
_sgl_setup_pipeline_pool(_sgl.desc.pipeline_pool_size);
|
_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_API_IMPL void sgl_destroy_context(sgl_context ctx_id) {
|
||||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||||
if (_sgl_is_default_context(ctx_id)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
_sgl_destroy_context(ctx_id);
|
_sgl_destroy_context(ctx_id);
|
||||||
@ -3360,6 +3544,16 @@ SOKOL_API_IMPL void sgl_defaults(void) {
|
|||||||
ctx->matrix_dirty = true;
|
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_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);
|
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
_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);
|
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
cmd->cmd = SGL_COMMAND_VIEWPORT;
|
cmd->cmd = SGL_COMMAND_VIEWPORT;
|
||||||
|
cmd->layer_id = ctx->layer_id;
|
||||||
cmd->args.viewport.x = x;
|
cmd->args.viewport.x = x;
|
||||||
cmd->args.viewport.y = y;
|
cmd->args.viewport.y = y;
|
||||||
cmd->args.viewport.w = w;
|
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);
|
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
cmd->cmd = SGL_COMMAND_SCISSOR_RECT;
|
cmd->cmd = SGL_COMMAND_SCISSOR_RECT;
|
||||||
|
cmd->layer_id = ctx->layer_id;
|
||||||
cmd->args.scissor_rect.x = x;
|
cmd->args.scissor_rect.x = x;
|
||||||
cmd->args.scissor_rect.y = y;
|
cmd->args.scissor_rect.y = y;
|
||||||
cmd->args.scissor_rect.w = w;
|
cmd->args.scissor_rect.w = w;
|
||||||
@ -3506,7 +3702,7 @@ SOKOL_API_IMPL void sgl_end(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SOKOL_ASSERT(ctx->in_begin);
|
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;
|
ctx->in_begin = false;
|
||||||
bool matrix_dirty = ctx->matrix_dirty;
|
bool matrix_dirty = ctx->matrix_dirty;
|
||||||
if (matrix_dirty) {
|
if (matrix_dirty) {
|
||||||
@ -3517,37 +3713,39 @@ SOKOL_API_IMPL void sgl_end(void) {
|
|||||||
uni->tm = *_sgl_matrix_texture(ctx);
|
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_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;
|
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;
|
bool merge_cmd = false;
|
||||||
if (prev_cmd) {
|
if (cur_cmd) {
|
||||||
if ((prev_cmd->cmd == SGL_COMMAND_DRAW) &&
|
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_LINE_STRIP) &&
|
||||||
(ctx->cur_prim_type != SGL_PRIMITIVETYPE_TRIANGLE_STRIP) &&
|
(ctx->cur_prim_type != SGL_PRIMITIVETYPE_TRIANGLE_STRIP) &&
|
||||||
!matrix_dirty &&
|
!matrix_dirty &&
|
||||||
(prev_cmd->args.draw.img.id == img.id) &&
|
(cur_cmd->args.draw.img.id == img.id) &&
|
||||||
(prev_cmd->args.draw.pip.id == pip.id))
|
(cur_cmd->args.draw.pip.id == pip.id))
|
||||||
{
|
{
|
||||||
merge_cmd = true;
|
merge_cmd = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (merge_cmd) {
|
if (merge_cmd) {
|
||||||
/* draw command can be merged with the previous command */
|
/* 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 {
|
else {
|
||||||
/* append a new draw command */
|
/* append a new draw command */
|
||||||
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
_sgl_command_t* cmd = _sgl_next_command(ctx);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
SOKOL_ASSERT(ctx->cur_uniform > 0);
|
SOKOL_ASSERT(ctx->uniforms.next > 0);
|
||||||
cmd->cmd = SGL_COMMAND_DRAW;
|
cmd->cmd = SGL_COMMAND_DRAW;
|
||||||
|
cmd->layer_id = ctx->layer_id;
|
||||||
cmd->args.draw.img = img;
|
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.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.base_vertex = ctx->base_vertex;
|
||||||
cmd->args.draw.num_vertices = ctx->cur_vertex - ctx->base_vertex;
|
cmd->args.draw.num_vertices = ctx->vertices.next - ctx->base_vertex;
|
||||||
cmd->args.draw.uniform_index = ctx->cur_uniform - 1;
|
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);
|
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||||
if (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);
|
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||||
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
_sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id);
|
||||||
if (ctx) {
|
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
|
module audio
|
||||||
|
|
||||||
|
import sokol.memory
|
||||||
|
|
||||||
$if linux {
|
$if linux {
|
||||||
// provide a nicer error for the user that does not have ALSA installed
|
// provide a nicer error for the user that does not have ALSA installed
|
||||||
#include <alsa/asoundlib.h> # Please install the `libasound2-dev` package
|
#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)} }'
|
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
|
// only one of `stream_cb` or `stream_userdata_cb` should be used
|
||||||
//
|
//
|
||||||
// default values (internal to sokol C library):
|
// 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 |
|
// | 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 |
|
// | 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 |
|
// | num_packets | 64 | for push model only, number of packets in the backend ringbuffer |
|
||||||
|
[typedef]
|
||||||
pub struct C.saudio_desc {
|
pub struct C.saudio_desc {
|
||||||
sample_rate int
|
sample_rate int
|
||||||
num_channels int
|
num_channels int
|
||||||
@ -72,7 +90,10 @@ pub struct C.saudio_desc {
|
|||||||
num_packets int
|
num_packets int
|
||||||
stream_cb FNStreamingCB
|
stream_cb FNStreamingCB
|
||||||
stream_userdata_cb FnStreamingCBWithUserData
|
stream_userdata_cb FnStreamingCBWithUserData
|
||||||
|
pub mut:
|
||||||
user_data voidptr
|
user_data voidptr
|
||||||
|
allocator C.saudio_allocator
|
||||||
|
logger C.saudio_logger
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.saudio_setup(desc &C.saudio_desc)
|
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
|
// setup - setup sokol-audio
|
||||||
pub fn setup(desc &C.saudio_desc) {
|
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)
|
C.saudio_setup(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
module c
|
module c
|
||||||
|
|
||||||
pub const (
|
pub const used_import = 1
|
||||||
used_import = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
#flag -I @VEXEROOT/thirdparty/sokol
|
#flag -I @VEXEROOT/thirdparty/sokol
|
||||||
#flag -I @VEXEROOT/thirdparty/sokol/util
|
#flag -I @VEXEROOT/thirdparty/sokol/util
|
||||||
@ -58,13 +56,6 @@ $if emscripten ? {
|
|||||||
|
|
||||||
#flag linux -ldl
|
#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
|
// To allow for thirdparty initializing window / acceleration contexts
|
||||||
// but still be able to use sokol.gfx e.g. SDL+sokol_gfx
|
// but still be able to use sokol.gfx e.g. SDL+sokol_gfx
|
||||||
$if !no_sokol_app ? {
|
$if !no_sokol_app ? {
|
||||||
|
@ -3,9 +3,7 @@ module f
|
|||||||
import fontstash
|
import fontstash
|
||||||
import sokol.c
|
import sokol.c
|
||||||
|
|
||||||
pub const (
|
pub const used_import = fontstash.used_import + c.used_import
|
||||||
used_import = fontstash.used_import + c.used_import
|
|
||||||
)
|
|
||||||
|
|
||||||
#flag linux -I.
|
#flag linux -I.
|
||||||
|
|
||||||
|
@ -1,19 +1,30 @@
|
|||||||
module gfx
|
module gfx
|
||||||
|
|
||||||
import sokol.c
|
import sokol.c
|
||||||
|
import sokol.memory
|
||||||
|
|
||||||
pub const (
|
pub const version = 1
|
||||||
version = 1
|
|
||||||
used_import = c.used_import
|
|
||||||
)
|
|
||||||
|
|
||||||
// setup and misc functions
|
pub const used_import = c.used_import
|
||||||
[inline]
|
|
||||||
|
// setup initialises the SOKOL's gfx library, based on the information passed in `desc`
|
||||||
pub fn setup(desc &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)
|
C.sg_setup(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
// shutdown tells the SOKOL's gfx library to shutdown, and release the resources it is using
|
||||||
pub fn shutdown() {
|
pub fn shutdown() {
|
||||||
C.sg_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,6 +1,7 @@
|
|||||||
module gfx
|
module gfx
|
||||||
|
|
||||||
struct C.sg_desc {
|
// C.sg_desc describes
|
||||||
|
pub struct C.sg_desc {
|
||||||
pub mut:
|
pub mut:
|
||||||
_start_canary u32
|
_start_canary u32
|
||||||
buffer_pool_size int
|
buffer_pool_size int
|
||||||
@ -9,22 +10,16 @@ pub mut:
|
|||||||
pipeline_pool_size int
|
pipeline_pool_size int
|
||||||
pass_pool_size int
|
pass_pool_size int
|
||||||
context_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
|
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
|
|
||||||
*/
|
|
||||||
_end_canary u32
|
_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
|
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 {
|
pub enum TouchToolType {
|
||||||
unknown
|
unknown
|
||||||
finger
|
finger
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
module sapp
|
module sapp
|
||||||
|
|
||||||
import sokol.gfx
|
import sokol.gfx
|
||||||
|
import sokol.memory
|
||||||
|
|
||||||
pub const used_import = gfx.used_import
|
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)
|
// special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub)
|
||||||
[inline]
|
|
||||||
pub fn run(desc &Desc) {
|
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
|
g_desc = *desc
|
||||||
C.sapp_run(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
|
||||||
|
}
|
@ -63,7 +63,7 @@ pub:
|
|||||||
enable_dragndrop bool // enable file dropping (drag'n'drop), default is false
|
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_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)
|
max_dropped_file_path_length int // max length in bytes of a dropped UTF-8 file path (default: 2048)
|
||||||
icon IconDesc
|
icon IconDesc // the initial window icon to set
|
||||||
// backend-specific options
|
// backend-specific options
|
||||||
gl_force_gles2 bool // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available
|
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
|
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
|
ios_keyboard_resizes_canvas bool // if true, showing the iOS keyboard shrinks the canvas
|
||||||
// V patches
|
// V patches
|
||||||
__v_native_render bool // V patch to allow for native rendering
|
__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
|
pub type Desc = C.sapp_desc
|
||||||
@ -84,25 +87,25 @@ pub type Desc = C.sapp_desc
|
|||||||
[typedef]
|
[typedef]
|
||||||
pub struct C.sapp_event {
|
pub struct C.sapp_event {
|
||||||
pub:
|
pub:
|
||||||
frame_count u64
|
frame_count u64 // current frame counter, always valid, useful for checking if two events were issued in the same frame
|
||||||
@type EventType
|
@type EventType // the event type, always valid
|
||||||
key_code KeyCode
|
key_code KeyCode // the virtual key code, only valid in KEY_UP, KEY_DOWN
|
||||||
char_code u32
|
char_code u32 // the UTF-32 character code, only valid in CHAR events
|
||||||
key_repeat bool
|
key_repeat bool // true if this is a key-repeat event, valid in KEY_UP, KEY_DOWN and CHAR
|
||||||
modifiers u32
|
modifiers u32 // current modifier keys, valid in all key-, char- and mouse-events
|
||||||
mouse_button MouseButton
|
mouse_button MouseButton // mouse button that was pressed or released, valid in MOUSE_DOWN, MOUSE_UP
|
||||||
mouse_x f32
|
mouse_x f32 // current horizontal mouse position in pixels, always valid except during mouse lock
|
||||||
mouse_y f32
|
mouse_y f32 // current vertical mouse position in pixels, always valid except during mouse lock
|
||||||
mouse_dx f32
|
mouse_dx f32 // relative horizontal mouse movement since last frame, always valid
|
||||||
mouse_dy f32
|
mouse_dy f32 // relative vertical mouse movement since last frame, always valid
|
||||||
scroll_x f32
|
scroll_x f32 // horizontal mouse wheel scroll distance, valid in MOUSE_SCROLL events
|
||||||
scroll_y f32
|
scroll_y f32 // vertical mouse wheel scroll distance, valid in MOUSE_SCROLL events
|
||||||
num_touches int
|
num_touches int // number of valid items in the touches[] array
|
||||||
touches [max_touchpoints]TouchPoint
|
touches [max_touchpoints]TouchPoint // current touch points, valid in TOUCHES_BEGIN, TOUCHES_MOVED, TOUCHES_ENDED
|
||||||
window_width int
|
window_width int // current window- and framebuffer width in pixels, always valid
|
||||||
window_height int
|
window_height int // current window- and framebuffer height in pixels, always valid
|
||||||
framebuffer_width int
|
framebuffer_width int // = window_width * dpi_scale
|
||||||
framebuffer_height int
|
framebuffer_height int // = window_height * dpi_scale
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Event = C.sapp_event
|
pub type Event = C.sapp_event
|
||||||
@ -117,7 +120,7 @@ pub:
|
|||||||
identifier u64
|
identifier u64
|
||||||
pos_x f32
|
pos_x f32
|
||||||
pos_y f32
|
pos_y f32
|
||||||
tool_type TouchToolType
|
android_tooltype TouchToolType
|
||||||
changed bool
|
changed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,13 +2,27 @@ module sfons
|
|||||||
|
|
||||||
import fontstash
|
import fontstash
|
||||||
import sokol.f
|
import sokol.f
|
||||||
|
import sokol.memory
|
||||||
|
|
||||||
// keep v from warning about unused imports
|
// keep v from warning about unused imports
|
||||||
const used_import = f.used_import + fontstash.used_import + 1
|
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]
|
[inline]
|
||||||
pub fn create(width int, height int, flags int) &fontstash.Context {
|
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]
|
[inline]
|
||||||
@ -25,3 +39,7 @@ pub fn rgba(r u8, g u8, b u8, a u8) u32 {
|
|||||||
pub fn flush(ctx &fontstash.Context) {
|
pub fn flush(ctx &fontstash.Context) {
|
||||||
C.sfons_flush(ctx)
|
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
|
module sfons
|
||||||
|
|
||||||
import fontstash
|
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_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_flush(ctx &fontstash.Context)
|
||||||
|
|
||||||
|
fn C.sfons_rgba(r u8, g u8, b u8, a u8) u32
|
||||||
|
@ -1,19 +1,29 @@
|
|||||||
module sgl
|
module sgl
|
||||||
|
|
||||||
import sokol.gfx
|
import sokol.gfx
|
||||||
|
import sokol.memory
|
||||||
|
|
||||||
pub const (
|
pub const version = gfx.version + 1
|
||||||
version = gfx.version + 1
|
|
||||||
context = Context{0x00010001} // C.SGL_DEFAULT_CONTEXT = { 0x00010001 }
|
pub const context = Context{0x00010001} // C.SGL_DEFAULT_CONTEXT = { 0x00010001 }
|
||||||
)
|
|
||||||
|
|
||||||
// setup/shutdown/misc
|
// setup/shutdown/misc
|
||||||
[inline]
|
|
||||||
pub fn setup(desc &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(0x10000561)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if desc.logger.log_cb == unsafe { nil } {
|
||||||
|
unsafe {
|
||||||
|
desc.logger.log_cb = memory.slog
|
||||||
|
}
|
||||||
|
}
|
||||||
C.sgl_setup(desc)
|
C.sgl_setup(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
|
||||||
pub fn shutdown() {
|
pub fn shutdown() {
|
||||||
C.sgl_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
|
pub type ContextDesc = C.sgl_context_desc_t
|
||||||
|
|
||||||
[typedef]
|
[typedef]
|
||||||
struct C.sgl_context_desc_t {
|
pub struct C.sgl_context_desc_t {
|
||||||
max_vertices int // default: 64k
|
max_vertices int // default: 64k
|
||||||
max_commands int // default: 16k
|
max_commands int // default: 16k
|
||||||
color_format gfx.PixelFormat // C.sg_pixel_format
|
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
|
pub type Desc = C.sgl_desc_t
|
||||||
|
|
||||||
[typedef]
|
[typedef]
|
||||||
struct C.sgl_desc_t {
|
pub struct C.sgl_desc_t {
|
||||||
|
pub:
|
||||||
max_vertices int // size for vertex buffer
|
max_vertices int // size for vertex buffer
|
||||||
max_commands int // size of uniform- and command-buffers
|
max_commands int // size of uniform- and command-buffers
|
||||||
context_pool_size int // max number of contexts (including default context), default: 4
|
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
|
depth_format gfx.PixelFormat // C.sg_pixel_format
|
||||||
sample_count int
|
sample_count int
|
||||||
face_winding gfx.FaceWinding // C.sg_face_winding // default front face winding is CCW
|
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
|
1 | module module_with_redeclaration
|
||||||
| ^
|
| ^
|
||||||
2 |
|
2 |
|
||||||
3 | pub const used = 1
|
3 | import sokol.memory
|
||||||
|
@ -1,6 +1,27 @@
|
|||||||
module module_with_redeclaration
|
module module_with_redeclaration
|
||||||
|
|
||||||
|
import sokol.memory
|
||||||
|
|
||||||
pub const used = 1
|
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`
|
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`
|
||||||
84 | fn C.saudio_userdata() voidptr
|
105 | fn C.saudio_userdata() voidptr
|
||||||
85 |
|
106 |
|
||||||
86 | fn C.saudio_query_desc() C.saudio_desc
|
107 | fn C.saudio_query_desc() C.saudio_desc
|
||||||
| ~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~
|
||||||
87 |
|
108 |
|
||||||
88 | fn C.saudio_sample_rate() int
|
109 | 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`
|
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`
|
||||||
99 |
|
120 |
|
||||||
100 | // setup - setup sokol-audio
|
121 | // setup - setup sokol-audio
|
||||||
101 | pub fn setup(desc &C.saudio_desc) {
|
122 | pub fn setup(desc &C.saudio_desc) {
|
||||||
| ~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~
|
||||||
102 | C.saudio_setup(desc)
|
123 | if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||||
103 | }
|
124 | unsafe {
|
||||||
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`
|
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`
|
||||||
119 |
|
123 | if desc.allocator.alloc == unsafe { nil } && desc.allocator.free == unsafe { nil } {
|
||||||
120 | // query - return a copy of the original saudio_desc struct
|
124 | unsafe {
|
||||||
121 | pub fn query() C.saudio_desc {
|
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()
|
155 | return C.saudio_query_desc()
|
||||||
123 | }
|
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`
|
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 |
|
5 |
|
||||||
6 | fn main() {
|
6 | fn main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user