AtlatestRepositorysigil-graphics

sigil-graphics / tree / scriptsgen-gl-loader.sh

1#!/bin/sh
2# gen-gl-loader.sh - regenerate src/c/gl_native_loader.h from vendor/sokol/sokol_gfx.h
3#
4# sokol_gfx's GL backend either includes the system GL headers (and links
5# libGL) or, on Win32, carries its own loader: GL types, constants and an
6# X-macro list of every GL function it calls. This script lifts those two
7# blocks out of the vendored header and emits a loader that fills the same
8# function pointers through a caller-supplied proc loader
9# (sigil_desktop_gl_get_proc_address, i.e. glfwGetProcAddress). The result
10# is what SOKOL_EXTERNAL_GL_LOADER expects on every native target, so no
11# GL header is needed to build and no libGL is linked.
13# Run after every sokol_gfx.h bump; the counts below refuse a header whose
14# shape moved. Anchors are patterns, and each extraction is guarded by a
15# line count so a silent no-match cannot produce an empty header.
16set -eu
17cd "$(dirname "$0")/.."
18SRC=vendor/sokol/sokol_gfx.h
19OUT=src/c/gl_native_loader.h
20T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
22# 1. the types + constants block: from the first GL typedef after
23# "#define GL_APIENTRY APIENTRY" to the "#endif" that closes the
24# win32-loader-definitions block
25awk '
26 /#define GL_APIENTRY APIENTRY/ { armed = 1; next }
27 armed && !started && /typedef unsigned int GLenum;/ { started = 1 }
28 started && /^ #endif/ { exit }
29 started { sub(/^ /, ""); print }
30' "$SRC" > "$T/defs.h"
31N1=$(wc -l < "$T/defs.h")
32[ "$N1" -gt 200 ] && [ "$N1" -lt 400 ] || { echo "REFUSING: types+constants block is $N1 lines (expected 200..400)"; exit 1; }
33grep -q '^typedef unsigned int GLenum;' "$T/defs.h" || { echo "REFUSING: no GLenum typedef"; exit 1; }
34tail -1 "$T/defs.h" | grep -q "^#define GL_MAX_IMAGE_UNITS " || { echo "REFUSING: constants block does not end on GL_MAX_IMAGE_UNITS (got: $(tail -1 "$T/defs.h"))"; exit 1; }
36# 2. the X-macro list: the body of _SG_GL_FUNCS, minus the SG_GL_FUNCS_EXT hook
37awk '
38 /^#define _SG_GL_FUNCS \\$/ { started = 1; next }
39 started && /SG_GL_FUNCS_EXT/ { next }
40 started { print; if ($0 !~ /\\$/) exit }
41' "$SRC" | sed 's/_SG_XMACRO(/SIGIL_GL_XMACRO(/' > "$T/funcs.h"
42N2=$(grep -c 'SIGIL_GL_XMACRO(' "$T/funcs.h")
43[ "$N2" -gt 100 ] && [ "$N2" -lt 200 ] || { echo "REFUSING: function list has $N2 entries (expected 100..200)"; exit 1; }
44grep -q 'SIGIL_GL_XMACRO(glGenBuffers,' "$T/funcs.h" || { echo "REFUSING: glGenBuffers not in the function list"; exit 1; }
45# the last line must not end in a backslash (the macro closes there)
46tail -1 "$T/funcs.h" | grep -q '\\$' && { echo "REFUSING: function list did not close"; exit 1; }
49cat <<HDR
50/*
51 * gl_native_loader.h - GL types, constants and entry points for sokol_gfx
52 * without a system GL header or a libGL link.
53 *
54 * GENERATED by scripts/gen-gl-loader.sh from vendor/sokol/sokol_gfx.h
55 * (sokol's own Win32 loader block); do not edit, regenerate after a sokol
56 * bump. Included once, by sokol-graphics.c, ahead of sokol_gfx.h with
57 * SOKOL_EXTERNAL_GL_LOADER defined. Every gl* sokol_gfx calls is a static
58 * function pointer here, filled by sigil_gl_load() through a proc loader
59 * (sigil_desktop_gl_get_proc_address, GLFW's glfwGetProcAddress) once the
60 * window's GL context is current. $N2 functions, $N1 lines of definitions.
61 */
62#ifndef SIGIL_GL_NATIVE_LOADER_H
63#define SIGIL_GL_NATIVE_LOADER_H
65#include <stddef.h>
66#include <stdint.h>
68/* sokol_gfx picks its Apple feature set from TargetConditionals.h, which it
69 * includes itself only when it also includes the system GL headers; with
70 * an external loader that is this header's job, or macOS would be read as
71 * iOS (no base-vertex draws). */
72#if defined(__APPLE__)
73#include <TargetConditionals.h>
74#endif
76#if defined(_WIN32) && !defined(_WIN64)
77#define GL_APIENTRY __stdcall
78#else
79#define GL_APIENTRY
80#endif
82/* The guards the system GL headers use, so a later include of any of them
83 * (glfw3.h without GLFW_INCLUDE_NONE, say) defines nothing twice. */
84#define __gl_h_ 1
85#define __gl32_h_ 1
86#define __gl31_h_ 1
87#define __GL_H__ 1
88#define __glext_h_ 1
89#define __GLEXT_H_ 1
90#define __gltypes_h_ 1
91#define __glcorearb_h_ 1
92#define __gl_glcorearb_h_ 1
94/* sokol_gfx enables its 3.2 / 4.2 / 4.3 code paths on these, as the system
95 * headers (Mesa's glext.h) defined them before; the runtime check on the
96 * context's reported version still gates their use. */
97#define GL_VERSION_3_2 1
98#define GL_VERSION_4_2 1
99#define GL_VERSION_4_3 1
101/* ---- types and constants (from sokol_gfx.h) ---- */
102HDR
103cat "$T/defs.h"
104cat <<MID
106/* ---- the entry points sokol_gfx calls (from sokol_gfx.h) ---- */
107#define SIGIL_GL_FUNCS \\
108MID
109cat "$T/funcs.h"
110cat <<'FTR'
112#define SIGIL_GL_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args;
113SIGIL_GL_FUNCS
114#undef SIGIL_GL_XMACRO
116#define SIGIL_GL_XMACRO(name, ret, args) static PFN_ ## name name;
117SIGIL_GL_FUNCS
118#undef SIGIL_GL_XMACRO
120typedef void *(*sigil_gl_proc_loader)(const char *name);
122/* Fill every pointer through `load`. Returns the number left NULL: entry
123 * points newer than the context (glTextureView on a 4.1 context, the
124 * base-instance draws before 4.2) are expected to be missing and sokol_gfx
125 * only calls them behind its feature checks; glGenBuffers or glGetIntegerv
126 * missing means there is no usable context, and sigil_gl_ready() says so. */
127static int sigil_gl_load(sigil_gl_proc_loader load)
129 int missing = 0;
130#define SIGIL_GL_XMACRO(name, ret, args) \
131 name = (PFN_ ## name)load(#name); if (!name) missing++;
132 SIGIL_GL_FUNCS
133#undef SIGIL_GL_XMACRO
134 return missing;
137static int sigil_gl_ready(void)
139 return glGetIntegerv != NULL && glClearBufferfv != NULL && glGenBuffers != NULL
140 && glCreateShader != NULL && glBindFramebuffer != NULL;
143#endif /* SIGIL_GL_NATIVE_LOADER_H */
144FTR
145} > "$OUT"
146echo "wrote $OUT: $N1 definition lines, $N2 functions, $(wc -l < "$OUT") lines total"