From 13ca03a6db3ec9ad75c6189519ff33345c5c1b5f Mon Sep 17 00:00:00 2001 From: James Dansereau <106631954+jkdansereau@users.noreply.github.com> Date: Fri, 21 Aug 2026 14:42:19 -0400 Subject: [PATCH] =?UTF-8?q?PC=20port:=20Phase=202=20=E2=80=94=20real=20thr?= =?UTF-8?q?eads,=20dual-mapped=20DRAM,=20fast3d=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace setjmp/longjmp green threads with real pthreads (8MB stacks); PortQueue side table (mutex+condvar) for OSMesgQueue; dedicated tick thread posts VI retrace + services timers (D24). - Dual-mapped N64 DRAM: one 8MB store at V1 0x70000000 (s32-safe, all game RAM symbols) and V2 0x80000000 (KSEG0 mirror for offset|0x80000000 rebuilds). Windows: CreateFileMappingW + MapViewOfFileEx; POSIX: memfd + MAP_FIXED. dram_syms.s pins cfb_16/_bssSegmentEnd/tlb block (D25). - Address-width shims: PHYS_TO_K0 identity, OS_K0_TO_PHYSICAL = offset from V1 base, OS_PHYSICAL_TO_K0 identity; fast3d seg_addr() remaps small offsets into V2 (D26). - ASLR off (-Wl,--disable-dynamicbase): absolute symbols referenced through pointer-typed externs (.refptr + BASE reloc) must not rebase; startup sanity check on image base 0x140000000 (D27). - osPiStartDma posts its completion message on every path (fixes romReceiveMesg deadlock) (D29). - SEH-free crash handler: raw fault log first, validated manual EBP-chain walk second (-fno-omit-frame-pointer), TerminateProcess; crashDumpThreads via Toolhelp32 for heartbeat hang dumps (D30). - PD fast3d integrated (port/fast3d/), replaces gfxstub.c; real src/sched.c compiled; mainproc runs as a real pthread, host thread pumps SDL events. - Docs: findings D24-D31 + Phase 2 status (section F/G). Current state: boots through bossInitMainthreadData to langInit(), then SIGSEGVs on the first file load — stack frame clobbered by a table of truncated s32 pointers (D31, open). Next: attribute the write with 'set scheduler-locking on' + hardware watchpoint. --- .gitignore | 6 + CMakeLists.txt | 59 +- docs/PCPortResearch.md | 185 ++ port/fast3d/LICENSE.txt | 21 + port/fast3d/gbiex.h | 63 + port/fast3d/gfx_api.h | 68 +- port/fast3d/gfx_cc.cpp | 59 + port/fast3d/gfx_cc.h | 75 + port/fast3d/gfx_opengl.cpp | 1321 +++++++++++ port/fast3d/gfx_opengl.h | 8 + port/fast3d/gfx_pc.cpp | 2830 ++++++++++++++++++++++ port/fast3d/gfx_pc.h | 60 + port/fast3d/gfx_rendering_api.h | 61 + port/fast3d/gfx_screen_config.h | 7 + port/fast3d/gfx_sdl.h | 24 + port/fast3d/gfx_sdl2.cpp | 488 ++++ port/fast3d/gfx_window_manager_api.h | 54 + port/fast3d/glad/glad.c | 1876 +++++++++++++++ port/fast3d/glad/glad.h | 3222 ++++++++++++++++++++++++++ port/fast3d/glad/khrplatform.h | 311 +++ port/include/crash.h | 26 + port/include/dram.h | 13 + port/include/hoststddef.h.in | 8 + port/include/hoststdlib.h.in | 8 + port/include/platform.h | 9 + port/include/system.h | 34 + port/include/video.h | 39 +- port/shim/PR/R4300.h | 31 + port/shim/PR/os.h | 43 + port/shim/stdarg.h | 19 + port/shim/stddef.h | 30 + port/shim/stdlib.h | 20 + port/src/crash.c | 422 +++- port/src/dram.c | 133 ++ port/src/dram_syms.s | 18 + port/src/gesched.c | 110 - port/src/gfxstub.c | 35 - port/src/libultra.c | 856 ++++++- port/src/main.c | 78 +- port/src/n64stubs.c | 36 +- port/src/system.c | 130 +- port/src/video.c | 301 +-- 42 files changed, 12660 insertions(+), 537 deletions(-) create mode 100644 port/fast3d/LICENSE.txt create mode 100644 port/fast3d/gbiex.h create mode 100644 port/fast3d/gfx_cc.cpp create mode 100644 port/fast3d/gfx_cc.h create mode 100644 port/fast3d/gfx_opengl.cpp create mode 100644 port/fast3d/gfx_opengl.h create mode 100644 port/fast3d/gfx_pc.cpp create mode 100644 port/fast3d/gfx_pc.h create mode 100644 port/fast3d/gfx_rendering_api.h create mode 100644 port/fast3d/gfx_screen_config.h create mode 100644 port/fast3d/gfx_sdl.h create mode 100644 port/fast3d/gfx_sdl2.cpp create mode 100644 port/fast3d/gfx_window_manager_api.h create mode 100644 port/fast3d/glad/glad.c create mode 100644 port/fast3d/glad/glad.h create mode 100644 port/fast3d/glad/khrplatform.h create mode 100644 port/include/crash.h create mode 100644 port/include/dram.h create mode 100644 port/include/hoststddef.h.in create mode 100644 port/include/hoststdlib.h.in create mode 100644 port/shim/PR/R4300.h create mode 100644 port/shim/PR/os.h create mode 100644 port/shim/stdarg.h create mode 100644 port/shim/stddef.h create mode 100644 port/shim/stdlib.h create mode 100644 port/src/dram.c create mode 100644 port/src/dram_syms.s delete mode 100644 port/src/gesched.c delete mode 100644 port/src/gfxstub.c diff --git a/.gitignore b/.gitignore index 9f28b4b0..29041e2a 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,9 @@ assets/obseg/em/data/under.seg scripts/local/ scripts/make/local/ scripts/__pycache__/generate_prop_model_c.cpython-310.pyc + +# PC port debug/session artifacts +_run.log +ge007.crash.log +.pi/ +run_out.log diff --git a/CMakeLists.txt b/CMakeLists.txt index cf712532..eaca134e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,23 @@ configure_file( "${CMAKE_SOURCE_DIR}/port/include/hoststring.h.in" "${CMAKE_BINARY_DIR}/port/include/hoststring.h" @ONLY) +# Host path for port/shim/stdlib.h. The N64 include/stdlib.h +# typedefs lldiv_t/ldiv_t, which conflict with the host's when both land in +# one C++ TU (fast3d): MinGW's own sec_api/stdlib_s.h does `#include +# `, which resolves to the N64 header via -I. The shim routes C++ +# TUs to the host header by absolute path (same trick as hoststring.h). +get_filename_component(PORT_HOST_STDLIB_H "${_PORT_GCC_DIR}/../include/stdlib.h" ABSOLUTE) +configure_file( + "${CMAKE_SOURCE_DIR}/port/include/hoststdlib.h.in" + "${CMAKE_BINARY_DIR}/port/include/hoststdlib.h" @ONLY) + +# Host path for port/shim/stddef.h (same reason as stdlib: the N64 +# stub shadows the host header in C++ TUs, hiding max_align_t from cstddef). +get_filename_component(PORT_HOST_STDDDEF_H "${_PORT_GCC_DIR}/../include/stddef.h" ABSOLUTE) +configure_file( + "${CMAKE_SOURCE_DIR}/port/include/hoststddef.h.in" + "${CMAKE_BINARY_DIR}/port/include/hoststddef.h" @ONLY) + # ---------------------------------------------------------------------------- # Compiler definitions & flags # ---------------------------------------------------------------------------- @@ -170,6 +187,11 @@ add_compile_options( -fwrapv -include "versioninfo.h" ) +# Keep frame pointers: dbghelp's StackWalk64 (crash handler + thread dumps) +# cannot read DWARF unwind info on MinGW, so the EBP chain is the only way to +# get a real backtrace of a hung/crashed game thread. +add_compile_options(-fno-omit-frame-pointer) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_options(-Og) endif() @@ -201,6 +223,18 @@ add_compile_options( add_compile_options($<$:-Wno-pointer-sign>) add_compile_options($<$:-Wno-unused-function>) +# ASLR must be OFF: dram_syms.s defines absolute symbols (cfb_16 @ 0x70000000, +# _bssSegmentEnd @ 0x70050000) that the game references through pointer-typed +# externs (src/bondgame.h: `extern u32 *_bssSegmentEnd`). On x86-64/PE, taking +# their address emits a .refptr slot holding the absolute value PLUS a base +# relocation; with ASLR the loader rebases it to runtime_base+0x70050000 = +# garbage. With DYNAMICBASE disabled the image loads at its preferred base +# (0x140000000) and the relocations are no-ops. main.c sanity-checks the load +# base at startup. +if(MINGW) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-dynamicbase") +endif() + # port/shim first: PC-only shadow headers (bondtypes.h, bondconstants.h, # PR/gbi.h) that fix N64-compiler assumptions without touching src/ or # include/. Inert in the N64 build (its Makefile never sees port/shim). @@ -244,7 +278,10 @@ endif() list(APPEND LIBS "${GL_LIBRARY}") if(NOT EXTRA_LIBRARIES) - if(WIN32) + if(MINGW) + # MinGW: pthreads for the real-OS-thread kernel (port/src/libultra.c). + set(EXTRA_LIBRARIES dbghelp -static-libstdc++ pthread) + elseif(WIN32) set(EXTRA_LIBRARIES dbghelp -static-libstdc++) else() set(EXTRA_LIBRARIES stdc++ m dl pthread) @@ -258,7 +295,8 @@ list(APPEND LIBS "${EXTRA_LIBRARIES}") # Port layer (shims + software RSP). file(GLOB_RECURSE SRC_PORT "${CMAKE_SOURCE_DIR}/port/src/*.c") file(GLOB_RECURSE SRC_PORT_CXX "${CMAKE_SOURCE_DIR}/port/src/*.cpp") -file(GLOB_RECURSE SRC_FAST3D "${CMAKE_SOURCE_DIR}/port/fast3d/*.cpp") +file(GLOB_RECURSE SRC_FAST3D "${CMAKE_SOURCE_DIR}/port/fast3d/*.cpp" + "${CMAKE_SOURCE_DIR}/port/fast3d/glad/*.c") # Generated absolute ROM asset symbols for this region (see # scripts/gen_romassets.py). Defines every obseg/ramrom/music label and the @@ -269,6 +307,10 @@ if(NOT EXISTS ${SRC_ROMASSETS}) message(FATAL_ERROR "Missing ${SRC_ROMASSETS} — run: python3 scripts/gen_romassets.py ${ASSET_REGION}") endif() +# Absolute symbols inside the reserved N64-DRAM region (port/src/dram.c): +# cfb_16 (replaces src/cfb.c) and _bssSegmentEnd (mempool start marker). +set(SRC_DRAM_SYMS "${CMAKE_SOURCE_DIR}/port/src/dram_syms.s") + # Game code — compiled unmodified. file(GLOB_RECURSE SRC_GAME "${CMAKE_SOURCE_DIR}/src/game/*.c") @@ -344,21 +386,29 @@ list(PREPEND SRC_ASSETS "${CMAKE_SOURCE_DIR}") # extern decls in bondgame.h / audi.c). # # EXCLUDED (hardware drivers, replaced by port/ shims): -# sched.c crash.c rmon.c usb.c tlb_*.c pi.c vi.c motor.c +# crash.c rmon.c usb.c tlb_*.c pi.c vi.c motor.c # (there is no src/spectrum.c in this decomp) # All of src/libultra/io/*.c and src/libultrare/io/*.c EXCEPT vitbl.c. # motor.c / pfsinit.c / pfsisplug.c are NOT compiled: joy.c calls # osMotorInit/Start/Stop and osPfsInit/osPfsIsPlug only for accessory # (Rumble Pak / Memory Pak) detection, so they are shimmed as no-ops in # port/src/libultra.c (see B2 — saves are EEPROM, not PFS). +# +# sched.c IS compiled (Phase 2): the game's real scheduler runs on the +# cooperative thread kernel; its hardware leaf calls (osSpTaskLoad/StartGo, +# osDpSetNextBuffer, osVi*) are shimmed in port/src/libultra.c, which runs +# the software RSP inline and posts the RSP_DONE/RDP_DONE messages. set(SRC_ENGINE src/init.c + src/sched.c src/audi.c src/snd.c src/music.c src/joy.c src/fr.c - src/cfb.c + # src/cfb.c — cfb_16 now lives at 0x80000000 in the reserved DRAM region + # (port/src/dram_syms.s) so OS_K0_TO_PHYSICAL(cfb_16[0]) is a small offset + # that fast3d can map back; a host-BSS array would truncate to garbage. src/stacks.c src/boss.c src/mema.c @@ -377,6 +427,7 @@ set(SRC ${SRC_GAME} ${SRC_PORT} ${SRC_ROMASSETS} + ${SRC_DRAM_SYMS} ${SRC_PORT_CXX} ${SRC_FAST3D} ${SRC_LIBAUDIO} diff --git a/docs/PCPortResearch.md b/docs/PCPortResearch.md index 8b2185e1..2f5661df 100644 --- a/docs/PCPortResearch.md +++ b/docs/PCPortResearch.md @@ -733,3 +733,188 @@ validation, 12 MB mapped at 0x10000000, window renders for the full test duration. Asset symbol spot-checks against the ROM confirm correct offsets (e.g. music bank BE seqCount=63 @0x419790, first track offset 508 → Mno_music @0x41998C; sfx/instrument banks start with GE's `B1` header). + +### F. Phase 2 runtime findings (threads, DRAM, addresses) + +Phase 2 replaced the Phase-1 demo loop with the real `mainproc()` on real OS +threads, compiled GE's real `src/sched.c`, and brought in PD's fast3d software +RSP (`port/fast3d/`). The boot path now runs: ROM map → DRAM reserve → video +init → mainThread (real pthread) → bossEntry → bossInitMainthreadData through +mempool init, VI init, rspInit, joyInit + controller-init timers, stanInit, +gameInit — and currently dies inside `langInit()` (D31). + +* **D24 — setjmp/longjmp green threads are unusable on MinGW x64.** The first + kernel used setjmp/longjmp context switches; under Windows x64 + MinGW the + longjmp path corrupts FPU/MC state when it interacts with SEH unwinding + (observed: STATUS_DATATYPE_MISALIGNMENT-class crash inside a resumed + "thread" with garbage register state). PD's port does not use setjmp at all. + **Resolved:** `port/src/libultra.c` now runs every game thread as a real + pthread (`PortThread` side table, 8 MB stacks). Message queues keep the N64 + `OSMesgQueue` layout and get a `PortQueue` side table (mutex + condvar, max + 64 queues); all osSendMesg/osRecvMesg paths lock it. A dedicated tick thread + posts one VI retrace per frame (NTSC 60 Hz) and services the software timers + (both OS_MESG_NOBLOCK — the tick thread can never deadlock). `idleThread` is + intercepted by ID and parked; `mainproc` runs as a real pthread so the host + main thread is free to pump SDL/OS events (`videoPumpEvents()` in the host + loop — on Windows WndProc only runs on the window-creating thread). The GL + context is made current on shedThread per frame via + `gfx_sdl_make_context_current()`. Verified live: VI retrace flowing, all 4 + controller-init timers fire, bossmq loop completes. +* **D25 — dual-mapped N64 DRAM region.** Game code needs two incompatible + address forms of the same RAM: `osVirtualToPhysical`/s32 arithmetic wants + live host pointers that fit in a positive s32, while `offset | 0x80000000` + rebuilds (bg.c:3184/3322, propobj.c:8578/8699, title.c:476) want a KSEG0 + view at 0x80000000. **Resolved:** one 8 MB backing store mapped twice — + V1 @ 0x70000000 (all game RAM symbols live here) and V2 @ 0x80000000 + (byte-identical mirror). `port/src/dram.c`: Windows uses + `CreateFileMappingW(INVALID_HANDLE_VALUE,…)` + two `MapViewOfFileEx(…, base)` + calls (the documented kernel32 API that maps a section at an exact address; + `NtMapViewOfSection` fails with STATUS_MEMORY_NOT_ALLOCATED 0xc0000045 and + segfaults on wrong SECTION_INHERIT values — do not retry it); POSIX uses + memfd + two MAP_SHARED|MAP_FIXED mmaps. Both views sanity-checked to alias. + `port/src/dram_syms.s` pins the absolute symbols: `cfb_16` @ 0x70000000 + (0x4B000), `_bssSegmentEnd` @ 0x70050000 (mempool start), tlb block end @ + 0x702F4400 (= page_align_down(0x803AB400) − 93×0x2000, the exact N64 value; + the tlbmanage stub returns it so `mempInit`'s pool size is correct — a NULL + return here made the mempool spin in `while(1)` at src/memp.c:164). +* **D26 — address-width shims (K0 sign-extension).** N64 K0 addresses have bit + 31 set; passing them through s32 parameters sign-extends to invalid x86-64 + pointers. With the dual map, live RAM sits below 0x80000000 so identity is + safe: `port/shim/PR/R4300.h` → `PHYS_TO_K0(x) = (x)`; `port/shim/PR/os.h` → + `OS_K0_TO_PHYSICAL(x) = (u32)((char *)x - 0x70000000)` (GBI w1 words then + carry small offsets) and `OS_PHYSICAL_TO_K0(x) = (x)`. fast3d's `seg_addr()` + (gfx_pc.cpp) resolves both forms: full host pointers pass through, values < + 0x800000 get +0x80000000 (landing in V2). Same remap applied to the + G_MW_SEGMENT handler. +* **D27 — ASLR must be OFF for this exe.** `src/bondgame.h:8` declares + `extern u32 *_bssSegmentEnd;` (pointer type), so `&_bssSegmentEnd` in game + code emits a `.refptr._bssSegmentEnd` slot holding the absolute value with a + BASE relocation. Under ASLR the loader rebases it to runtime_base + + 0x70050000 = garbage, and `mempCheckMemflagTokens` then spins/AVs with + poolAreaStart ≈ 0xF0xxxxxx. (On MIPS `&abs_symbol` is the symbol value + itself; x86-64/PE cannot do that.) **Resolved:** MINGW link flag + `-Wl,--disable-dynamicbase` (note: `--disable-dynamic-base` is NOT + recognized by GNU ld 2.47); the image now loads at its preferred base + 0x140000000 and relocations are no-ops. `main.c` fails loudly at startup if + `sysImageBase() != 0x140000000ul` so any future ASLR regression is a clean + error, not silent DRAM corruption. +* **D28 — ninja stale-object hazard with new shim headers.** If a shim header + did not exist when a .obj was last built, it is absent from that object's + .d dependency file and ninja will NOT rebuild the TU after the header + appears — the old (unshimmed) code silently persists. Observed: boss.c.obj + still contained `or $0x80000000,%eax` (original PHYS_TO_K0) days after the + shim landed. **Rule:** whenever anything under `port/shim/` changes, delete + all `.obj` files and full-rebuild. Verify with `gcc -E` using the exact + ninja flags (`ninja -C build-pc -t commands `) plus objdump of the + rebuilt object. +* **D29 — `osPiStartDma` must post its completion message on every path.** The + N64 PI posts the caller's OSMesgPI to mq when a DMA completes; GE never + inspects the message but always blocks on it (`romReceiveMesg()` → + `osRecvMesg(OS_MESG_BLOCK)` in ramrom.c:44). The shim did the memcpy + synchronously and posted nothing → mainThread deadlocked in the first file + load. **Resolved:** post unconditionally after `piServiceDma()` (also for + skipped/dropped DMAs) with OS_MESG_BLOCK, posting the caller's OSMesgPI. +* **D30 — crash handler without SEH.** MinGW GCC 16 has no `__try`/`__except` + and does not recognize `-fseh-exceptions`, so the unhandled-exception filter + cannot rely on structured exceptions to protect symbolication. **Resolved:** + `port/src/crash.c` phase 1 writes raw fault info (registers, modules) to + `ge007.crash.log` without touching dbghelp (SymInitialize/StackWalk64 can + allocate and re-fault inside the filter); phase 2 does a validated manual + EBP-chain walk (`-fno-omit-frame-pointer` on all TUs; each frame is [saved + RBP, return address], stop if saved_fp ≤ fp or outside thread stack limits). + `TerminateProcess` instead of abort (SIGABRT can re-enter the exception + machinery). `crashDumpThreads()` (Toolhelp32 snapshot + SuspendThread + + GetThreadContext + StackWalk64 per thread) is called from the heartbeat + error dump with TID→name matching; StackWalk64 cannot read DWARF unwind info + on MinGW, so multi-frame traces depend entirely on the EBP chain. Symbols + are recovered offline: `addr2line -e build-pc/ge007.x86_64.exe -f -C + ` (the log's "rel" = address − actual load base). +* **D31 — langInit SIGSEGV: stack frame clobbered by a truncated-pointer table (OPEN).** + After D24–D29, mainThread reaches `langInit()` and dies on the **first** file + load (`_fileNameLoadToBank(LnameX_lookuptable[LGUN][…])` → index 670 → + `fileIndexLoadToBank` → `mempAllocBytesInBank` → `load_resource`). Crash + signature: RIP = 0x140330003 (inside `.bss`, in `g_Props`), RSP only ~0xD8 + below langInit's entry RSP (a *shallow* chain — the stack pointer itself is + fine), and the frame region above load_resource's return address is filled + with 8-byte slots `{u32, 0x00000001}` where each u32 is the **low 32 bits of + a live .bss pointer**, alternating between `g_Props` (0x14033xxxx) and + `resource_lookup_data_array` (0x14034xxxx). The crash is a `ret` popping one + of these truncated pointers as the return address (observed RIP equals the + table value exactly, high word 0x00000001). Something in the load chain is + storing 64-bit pointers into s32/int storage (fine on 32-bit MIPS, + truncating on x86-64) and that storage overlaps a live frame. + + Established facts (all under gdb, `gdb -batch -ex "handle SIGSEGV stop"`): + * All arguments at `load_resource` entry are valid: ptrdata=0x702aa400 + (mempool), srcfile->hw_address=0x108ed250, rom_size=0x720, source= + 0x702f3ce0. `romCopy` (PI shim memcpy) completes. + * `zlib_inflate()` itself **completes normally** (`finish` → returns 0, + rz_wp=3872; the RZ stream is plain deflate after a 2-byte header, so + endianness is not an issue in the bitstream). At its entry rz_outbuf = + ptrdata ✓, rz_inbuf = source+2 ✓, and the huft table base (tl) sits inside + load_resource's 8 KB local `buffer` (rz_hlist). + * **Not** a huft-table overflow: max observed `rz_hufts` = 797 entries × + 4 B (`struct huft {u8 e; u8 b; union{u16 n; struct huft *t} v;}`) = 3188 B + < 8448 B buffer. + * Ruled out by code inspection: `mempAddEntryOfSizeToBank` (only touches + pool pos/prevpos), `fileGetIndex` (reads only), `decompressdata` epilogue + (returns rz_wp). + * `load_resource` prologue: `push rbp/rdi/rsi/rbx; mov $0x2128,%eax; + call ___chkstk_ms; sub %rax,%rsp; lea 0x80(%rsp),%rbp` — RBP is a **fake + frame pointer** (RSP+0x80); the real return address is at [RBP+0x20E8]. + The compiler reuses pushed-register slots as locals (verified: the saved- + rbx slot [RBP+0x20D0] legitimately receives `buffer+12`). Watchpoints on + RBP-relative offsets are therefore easy to misplace — compute from entry + RSP instead. + * Hardware watchpoint on the real retaddr slot (set at the first + instruction, where [RSP] = retaddr): first write changes it from a valid + .text return address to **`buffer+12`** (a pointer into load_resource's + own local array), reported RIP at the prologue boundary (`push %rdi`) — + i.e. either a concurrent write by another thread (hardware watchpoints are + global) or an 8-byte-attributed access. A `thread apply all bt` at that + moment showed every other game thread parked (RtlUserThreadStart / sleep + syscalls; gdb could not unwind their stacks further), so the writer is not + yet identified. + + Next steps: re-run the watchpoint with **`set scheduler-locking on`** + (only mainThread runs → any hit is its own) to attribute the write to an + exact instruction; if it is load_resource's own spill, that is a GCC + miscompilation → compile ob.c at -O0/-Og or add a PORT-gated hook. Also try + multiple watchpoints on consecutive slots to catch a sequential table fill + mid-flight, and grep the disassembly of the whole chain for stores through + s32-typed pointers (`movl …(%reg)` where %reg holds a truncated pointer). + +### G. Phase 2 status (current) + +Done: PD fast3d integrated (`port/fast3d/`, replaces the deleted gfxstub.c); +GE's real `src/sched.c` compiled (shedThread runs `__scMain`); real pthread +kernel (D24); dual-mapped DRAM + address shims (D25/D26); ASLR off with startup +sanity check (D27); PI completion messages (D29); SEH-free crash handler with +thread dumps (D30). The process now boots, maps the ROM, opens the window, +runs `mainproc()` → `bossInitMainthreadData` through controller init / timers / +mempool / VI / rsp / stan / game init — and SIGSEGVs inside `langInit()`'s +first file load (D31). No frames rendered yet. + +Reference — the file-load chain (for D31 debugging): +`langInit` (language.c:230) loads 7 text banks via +`_fileNameLoadToBank(LnameX_lookuptable[bank][j_text_trigger], …, 0x100, +MEMPOOL_PERMANENT)` → `fileGetIndex` (strcmp over file_resource_table) → +`fileIndexLoadToBank(index, …)` (ob.c:216): if poolRemaining==0 take +`mempGetBankSizeLeft(bank)`; `ptrdata = mempAllocBytesInBank(…)`; hw_address +nonzero → `load_resource(ptrdata, poolRemaining, &file_resource_table[index], +&resource_lookup_data_array[index])` (ob.c:37): `source = (ptrdata + bytes) − +((rom_size+7)&−8)`; `romCopy(source, hw_address, rom_size)`; +`decompressdata(source, ptrdata, buffer)` with `u8 buffer[0x2100]` on the +stack → sets rz_inbuf=source+2 / rz_outbuf=ptrdata / rz_hlist=buffer → +`zlib_inflate()` (src/game/zlib.c:668). rom_size for index 670 = 0x720, +decompressed size = 3872 (0xF20). `file_resource_table` is compiled +(`assets/obseg/file_resource_table.inc.c`) with hw_address = cart addresses; +rom_size = adjacent-marker differences computed in obInit. + +Debugging techniques that worked: gdb **launch** mode (`gdb -batch -ex +"handle SIGSEGV stop" -ex run …` — attach fails with error 87); breakpoint +chains through init functions to bracket the crash; `finish` to let a suspect +function complete and inspect its return; hardware watchpoints on exact stack +slots (compute offsets from entry RSP, not RBP — see D31); `addr2line` for +offline symbolication; objdump + `gcc -E` with exact ninja flags to verify +shim expansion in compiled code. diff --git a/port/fast3d/LICENSE.txt b/port/fast3d/LICENSE.txt new file mode 100644 index 00000000..2857b7ea --- /dev/null +++ b/port/fast3d/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Emill, MaikelChan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/port/fast3d/gbiex.h b/port/fast3d/gbiex.h new file mode 100644 index 00000000..03c22d8c --- /dev/null +++ b/port/fast3d/gbiex.h @@ -0,0 +1,63 @@ +/* + * GE adaptation header for fast3d (see docs/PCPortResearch.md). + * + * fast3d was written against Perfect Dark's extended GBI set + * (pd_port/src/include/gbiex.h + PD's include/PR/gbi.h). GoldenEye shares the + * same Rare "Indy" engine family but its extension header is + * include/gbi_extension.h, which defines G_TRI4 (0xb1) and GE's custom + * combine/RM modes — but NOT the PD-specific opcodes below. + * + * GE never emits the PD-only opcodes (its RSP ucode is rsp/graphics/gmain.s, + * which has no handling for them), so the corresponding dispatch cases in + * gfx_pc.cpp are dead code for this port; they only need to COMPILE. The + * values mirror PD's gbiex.h exactly so that if a ROM ever does emit one, + * behaviour matches the sibling port rather than hitting the fatal "unknown + * opcode" path. + * + * G_COL (7) is "new in PD": GE fills vertex colours directly in Vtx.cn[] + * and its ucode has no colour-table DMA, so that case is dead here too. + */ +#ifndef FAST3D_GBIEX_H +#define FAST3D_GBIEX_H + +#include +#include "include/gbi_extension.h" /* G_TRI4 (0xb1), GE's own extensions */ + +/* PD extension opcodes (pd_port/src/include/gbiex.h). */ +#define G_COL 7 /* vertex colour DMA — PD-only */ +#define G_SETFB_EXT 0x21 +#define G_SETTIMG_FB_EXT 0x23 +#define G_INVALTEXCACHE_EXT 0x34 +#define G_TEXRECT_WIDE_EXT 0x37 +#define G_FILLRECT_WIDE_EXT 0x38 +#define G_SETGRAYSCALE_EXT 0x39 +#define G_EXTRAGEOMETRYMODE_EXT 0x3a +#define G_SETINTENSITY_EXT 0x40 +#define G_COPYFB_EXT 0x41 +#define G_IMAGERECT_EXT 0x42 +#define G_RDPFLUSH_EXT 0x43 +#define G_CLEAR_DEPTH_EXT 0x44 +#define G_SETSUBPIXELOFFSET_EXT 0x45 + +/* Extra geometry/aspect bits used by the PD ucode (dead for GE). */ +#define G_ASPECT_LEFT_EXT 0x00000010 +#define G_ASPECT_RIGHT_EXT 0x00000020 +#define G_ASPECT_WIDE_EXT 0x00000040 +#define G_ASPECT_CENTER_EXT (G_ASPECT_LEFT_EXT | G_ASPECT_RIGHT_EXT) +#define G_ASPECT_MODE_EXT (G_ASPECT_CENTER_EXT | G_ASPECT_WIDE_EXT) +#define G_NO_CLIPPING_EXT 0x00000100 +#define G_MODULATE_EXT 0x00000200 +#define G_TF_BLUR_EXT (1 << G_MDSFT_TEXTFILT) + +/* Big-endian read helpers (pd_port/src/include/platform.h). The host is + * little-endian, so a "BE" value in ROM data must be byte-swapped. */ +#if defined(__GNUC__) || defined(__clang__) +#define PD_BSWAP16(x) __builtin_bswap16(x) +#define PD_BSWAP32(x) __builtin_bswap32(x) +#else +#error "Implement PD_BSWAP macros for your compiler." +#endif +#define PD_BE16(x) PD_BSWAP16(x) +#define PD_BE32(x) PD_BSWAP32(x) + +#endif /* FAST3D_GBIEX_H */ diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 4e52a4c7..327aa835 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -1,29 +1,18 @@ #ifndef GFX_API_H #define GFX_API_H -/* - * Public API for the software RSP (fast3d). - * - * This is the interface the rest of the port (video.c / gesched.c) uses to - * drive the RSP. It mirrors the PD port's port/fast3d/gfx_api.h. - * - * STATUS: scaffolding — the implementation (gfx_pc.cpp etc.) is brought in - * during Phase 2 by adapting the PD fast3d. See port/fast3d/README.md. - */ - #ifndef __cplusplus #include #include #endif -#include +#include "gfx_rendering_api.h" +#include "gfx_window_manager_api.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct GfxRenderingAPI; -struct GfxWindowManagerAPI; +struct XYWidthHeight { + int16_t x, y; + uint32_t width, height; +}; struct GfxDimensions { float internal_mul; @@ -34,33 +23,36 @@ struct GfxDimensions { struct GfxInitSettings { struct GfxWindowManagerAPI *wapi; struct GfxRenderingAPI *rapi; - /* window title / size / fullscreen / etc. — see PD gfx_window_manager_api.h */ - const char *title; - uint32_t width, height; - int fullscreen; - int vsync; + struct GfxWindowInitSettings window_settings; }; -/* Current draw-area dimensions (before any scaling). */ -extern struct GfxDimensions gfx_current_dimensions; +extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window +extern struct GfxDimensions + gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable) +extern struct XYWidthHeight + gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner +extern uint32_t gfx_msaa_level; +extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game +extern float gfx_current_native_aspect; // The aspect ratio of the above mode +extern bool gfx_framebuffers_enabled; +extern bool gfx_detail_textures_enabled; void gfx_init(const struct GfxInitSettings *settings); void gfx_destroy(void); - -/* Frame boundary. */ +struct GfxRenderingAPI* gfx_get_current_rendering_api(void); void gfx_start_frame(void); +void gfx_run(Gfx* commands); void gfx_end_frame(void); +void gfx_set_target_fps(int); +void gfx_set_texture_filter(enum FilteringMode mode); +void gfx_set_mipmap_filter(enum MipmapFilteringMode mode); +void gfx_texture_cache_clear(void); +void gfx_texture_cache_delete(const uint8_t *orig_addr); +void gfx_texture_cache_delete_range(const uint8_t *start, const uint8_t *end); +int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize); +void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale, int autoresize); +void gfx_set_framebuffer(int fb, float noise_scale) ; +void gfx_reset_framebuffer(void); +void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back); -/* Run the RSP over a display list (the core of the emulation). */ -void gfx_run(Gfx *commands); - -/* Options. */ -void gfx_set_target_fps(int fps); -void gfx_set_texture_filter(int mode); -void gfx_set_mipmap_filter(int mode); - -#ifdef __cplusplus -} #endif - -#endif /* GFX_API_H */ diff --git a/port/fast3d/gfx_cc.cpp b/port/fast3d/gfx_cc.cpp new file mode 100644 index 00000000..6aaaa655 --- /dev/null +++ b/port/fast3d/gfx_cc.cpp @@ -0,0 +1,59 @@ +#include "gfx_cc.h" + +void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features) { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 4; k++) { + cc_features->c[i][j][k] = (shader_id0 >> (i * 32 + j * 16 + k * 4)) & 0xf; + } + } + } + + cc_features->opt_alpha = (shader_id1 & SHADER_OPT_ALPHA) != 0; + cc_features->opt_fog = (shader_id1 & SHADER_OPT_FOG) != 0; + cc_features->opt_texture_edge = (shader_id1 & SHADER_OPT_TEXTURE_EDGE) != 0; + cc_features->opt_noise = (shader_id1 & SHADER_OPT_NOISE) != 0; + cc_features->opt_2cyc = (shader_id1 & SHADER_OPT_2CYC) != 0; + cc_features->opt_alpha_threshold = (shader_id1 & SHADER_OPT_ALPHA_THRESHOLD) != 0; + cc_features->opt_invisible = (shader_id1 & SHADER_OPT_INVISIBLE) != 0; + cc_features->opt_grayscale = (shader_id1 & SHADER_OPT_GRAYSCALE) != 0; + cc_features->opt_blur = (shader_id1 & SHADER_OPT_BLUR) != 0; + + cc_features->clamp[0][0] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_S); + cc_features->clamp[0][1] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_T); + cc_features->clamp[1][0] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_S); + cc_features->clamp[1][1] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_T); + + cc_features->used_textures[0] = false; + cc_features->used_textures[1] = false; + cc_features->num_inputs = 0; + + for (int c = 0; c < 2; c++) { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 4; j++) { + if (cc_features->c[c][i][j] >= SHADER_INPUT_1 && cc_features->c[c][i][j] <= SHADER_INPUT_7) { + if (cc_features->c[c][i][j] > cc_features->num_inputs) { + cc_features->num_inputs = cc_features->c[c][i][j]; + } + } + if (cc_features->c[c][i][j] == SHADER_TEXEL0 || cc_features->c[c][i][j] == SHADER_TEXEL0A) { + cc_features->used_textures[0] = true; + } + if (cc_features->c[c][i][j] == SHADER_TEXEL1 || cc_features->c[c][i][j] == SHADER_TEXEL1A) { + cc_features->used_textures[1] = true; + } + } + } + } + + for (int c = 0; c < 2; c++) { + cc_features->do_single[c][0] = cc_features->c[c][0][2] == SHADER_0; + cc_features->do_single[c][1] = cc_features->c[c][1][2] == SHADER_0; + cc_features->do_multiply[c][0] = cc_features->c[c][0][1] == SHADER_0 && cc_features->c[c][0][3] == SHADER_0; + cc_features->do_multiply[c][1] = cc_features->c[c][1][1] == SHADER_0 && cc_features->c[c][1][3] == SHADER_0; + cc_features->do_mix[c][0] = cc_features->c[c][0][1] == cc_features->c[c][0][3]; + cc_features->do_mix[c][1] = cc_features->c[c][1][1] == cc_features->c[c][1][3]; + cc_features->color_alpha_same[c] = + ((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff); + } +} diff --git a/port/fast3d/gfx_cc.h b/port/fast3d/gfx_cc.h new file mode 100644 index 00000000..5fd4797c --- /dev/null +++ b/port/fast3d/gfx_cc.h @@ -0,0 +1,75 @@ +#ifndef GFX_CC_H +#define GFX_CC_H + +#include +#include + +#ifdef __cplusplus +#include +#endif + +enum { + SHADER_0, + SHADER_INPUT_1, + SHADER_INPUT_2, + SHADER_INPUT_3, + SHADER_INPUT_4, + SHADER_INPUT_5, + SHADER_INPUT_6, + SHADER_INPUT_7, + SHADER_TEXEL0, + SHADER_TEXEL0A, + SHADER_TEXEL1, + SHADER_TEXEL1A, + SHADER_1, + SHADER_COMBINED, + SHADER_NOISE, + SHADER_LOD_FRAC, +}; + +#define SHADER_OPT_ALPHA (1 << 0) +#define SHADER_OPT_FOG (1 << 1) +#define SHADER_OPT_TEXTURE_EDGE (1 << 2) +#define SHADER_OPT_NOISE (1 << 3) +#define SHADER_OPT_2CYC (1 << 4) +#define SHADER_OPT_ALPHA_THRESHOLD (1 << 5) +#define SHADER_OPT_INVISIBLE (1 << 6) +#define SHADER_OPT_GRAYSCALE (1 << 7) +#define SHADER_OPT_TEXEL0_CLAMP_S (1 << 8) +#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9) +#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10) +#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11) +#define SHADER_OPT_BLUR (1 << 12) + +struct ColorCombinerKey { + uint64_t combine_mode; + uint64_t options; + auto operator<=>(const ColorCombinerKey&) const = default; +}; + +#define SHADER_MAX_TEXTURES 2 +#define SHADER_FIRST_TEXTURE 0 + +struct CCFeatures { + uint8_t c[2][2][4]; + bool opt_alpha; + bool opt_fog; + bool opt_texture_edge; + bool opt_noise; + bool opt_2cyc; + bool opt_alpha_threshold; + bool opt_invisible; + bool opt_grayscale; + bool opt_blur; + bool used_textures[2]; + bool clamp[2][2]; + int num_inputs; + bool do_single[2][2]; + bool do_multiply[2][2]; + bool do_mix[2][2]; + bool color_alpha_same[2]; +}; + +void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features); + +#endif diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp new file mode 100644 index 00000000..db5cfbfc --- /dev/null +++ b/port/fast3d/gfx_opengl.cpp @@ -0,0 +1,1321 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include + +#ifndef _LANGUAGE_C +#define _LANGUAGE_C +#endif +#include + +#include "glad/glad.h" + +#include "gfx_cc.h" +#include "gfx_rendering_api.h" +#include "gfx_pc.h" + +using namespace std; + +struct ShaderProgram { + GLuint opengl_program_id; + uint8_t num_inputs; + bool used_textures[SHADER_MAX_TEXTURES]; + uint8_t num_floats; + GLint attrib_locations[16]; + uint8_t attrib_sizes[16]; + uint8_t num_attribs; + GLint frame_count_location; + GLint noise_scale_location; + GLint three_point_filter_locations[2]; +}; + +struct Framebuffer { + uint32_t width, height; + bool has_depth_buffer; + uint32_t msaa_level; + bool invert_y; + + GLuint fbo, clrbuf, clrbuf_msaa, rbo; +}; + +static std::map, struct ShaderProgram> shader_program_pool; +static GLuint opengl_vbo; +static GLuint opengl_vao; +static bool current_depth_mask; + +static uint32_t frame_count; + +static std::vector framebuffers; +static size_t current_framebuffer; +static float current_noise_scale; +static int current_anisotropy_level; +static FilteringMode current_filter_mode = FILTER_LINEAR; +static MipmapFilteringMode current_mipmap_filter_mode = MIPMAP_LINEAR; +static bool current_textures_linear_filter[2] = {false, false}; + +static int gl_glsl_version = 130; +static char gl_glsl_version_str[16] = "130"; +static GLenum gl_mirror_clamp = GL_MIRROR_CLAMP_TO_EDGE; +static bool gl_es = false; +static bool gl_core_profile = false; + +static int gfx_opengl_get_max_texture_size() { + GLint max_texture_size; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + return max_texture_size; +} + +static const char* gfx_opengl_get_name() { + return "OpenGL"; +} + +static struct GfxClipParameters gfx_opengl_get_clip_parameters(void) { + return { false, framebuffers[current_framebuffer].invert_y }; +} + +static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram* prg) { + size_t num_floats = prg->num_floats; + size_t pos = 0; + + for (int i = 0; i < prg->num_attribs; i++) { + if (prg->attrib_locations[i] >= 0) { + glEnableVertexAttribArray(prg->attrib_locations[i]); + glVertexAttribPointer(prg->attrib_locations[i], prg->attrib_sizes[i], GL_FLOAT, GL_FALSE, + num_floats * sizeof(float), (void*)(pos * sizeof(float))); + } + pos += prg->attrib_sizes[i]; + } +} + +static void gfx_opengl_set_uniforms(struct ShaderProgram* prg) { + if (prg->frame_count_location >= 0) { + glUniform1i(prg->frame_count_location, frame_count); + } + if (prg->noise_scale_location >= 0) { + glUniform1f(prg->noise_scale_location, current_noise_scale); + } + if (prg->three_point_filter_locations[0] >= 0) { + glUniform1i(prg->three_point_filter_locations[0], current_textures_linear_filter[0]); + } + if (prg->three_point_filter_locations[1] >= 0) { + glUniform1i(prg->three_point_filter_locations[1], current_textures_linear_filter[1]); + } +} + +static void gfx_opengl_unload_shader(struct ShaderProgram* old_prg) { + if (old_prg != NULL) { + for (int i = 0; i < old_prg->num_attribs; i++) { + if (old_prg->attrib_locations[i] >= 0) { + glDisableVertexAttribArray(old_prg->attrib_locations[i]); + } + } + } +} + +static void gfx_opengl_load_shader(struct ShaderProgram* new_prg) { + // if (!new_prg) return; + glUseProgram(new_prg->opengl_program_id); + gfx_opengl_vertex_array_set_attribs(new_prg); + gfx_opengl_set_uniforms(new_prg); +} + +static void append_str(char* buf, size_t* len, const char* str) { + while (*str != '\0') { + buf[(*len)++] = *str++; + } +} + +static void append_line(char* buf, size_t* len, const char* str) { + while (*str != '\0') { + buf[(*len)++] = *str++; + } + buf[(*len)++] = '\n'; +} + +#define RAND_NOISE "((random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + 1.0) / 2.0)" + +static const char* shader_item_to_str(uint32_t item, bool with_alpha, bool only_alpha, bool inputs_have_alpha, + bool hint_single_element) { + if (!only_alpha) { + switch (item) { + case SHADER_0: + return with_alpha ? "vec4(0.0, 0.0, 0.0, 0.0)" : "vec3(0.0, 0.0, 0.0)"; + case SHADER_1: + return with_alpha ? "vec4(1.0, 1.0, 1.0, 1.0)" : "vec3(1.0, 1.0, 1.0)"; + case SHADER_INPUT_1: + return with_alpha || !inputs_have_alpha ? "vInput1" : "vInput1.rgb"; + case SHADER_INPUT_2: + return with_alpha || !inputs_have_alpha ? "vInput2" : "vInput2.rgb"; + case SHADER_INPUT_3: + return with_alpha || !inputs_have_alpha ? "vInput3" : "vInput3.rgb"; + case SHADER_INPUT_4: + return with_alpha || !inputs_have_alpha ? "vInput4" : "vInput4.rgb"; + case SHADER_TEXEL0: + return with_alpha ? "texVal0" : "texVal0.rgb"; + case SHADER_TEXEL0A: + return hint_single_element ? "texVal0.a" + : (with_alpha ? "vec4(texVal0.a, texVal0.a, texVal0.a, texVal0.a)" + : "vec3(texVal0.a, texVal0.a, texVal0.a)"); + case SHADER_TEXEL1A: + return hint_single_element ? "texVal1.a" + : (with_alpha ? "vec4(texVal1.a, texVal1.a, texVal1.a, texVal1.a)" + : "vec3(texVal1.a, texVal1.a, texVal1.a)"); + case SHADER_TEXEL1: + return with_alpha ? "texVal1" : "texVal1.rgb"; + case SHADER_COMBINED: + return with_alpha ? "texel" : "texel.rgb"; + case SHADER_NOISE: + return with_alpha ? "vec4(" RAND_NOISE ", " RAND_NOISE ", " RAND_NOISE ", " RAND_NOISE ")" + : "vec3(" RAND_NOISE ", " RAND_NOISE ", " RAND_NOISE ")"; + } + } else { + switch (item) { + case SHADER_0: + return "0.0"; + case SHADER_1: + return "1.0"; + case SHADER_INPUT_1: + return "vInput1.a"; + case SHADER_INPUT_2: + return "vInput2.a"; + case SHADER_INPUT_3: + return "vInput3.a"; + case SHADER_INPUT_4: + return "vInput4.a"; + case SHADER_TEXEL0: + return "texVal0.a"; + case SHADER_TEXEL0A: + return "texVal0.a"; + case SHADER_TEXEL1A: + return "texVal1.a"; + case SHADER_TEXEL1: + return "texVal1.a"; + case SHADER_COMBINED: + return "texel.a"; + case SHADER_NOISE: + return RAND_NOISE; + } + } + return ""; +} + +#undef RAND_NOISE + +static void append_formula(char* buf, size_t* len, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, + bool with_alpha, bool only_alpha, bool opt_alpha) { + if (do_single) { + append_str(buf, len, shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false)); + } else if (do_multiply) { + append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, " * "); + append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true)); + } else if (do_mix) { + append_str(buf, len, "mix("); + append_str(buf, len, shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, ", "); + append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, ", "); + append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true)); + append_str(buf, len, ")"); + } else { + append_str(buf, len, "("); + append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, " - "); + append_str(buf, len, shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, ") * "); + append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true)); + append_str(buf, len, " + "); + append_str(buf, len, shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false)); + } +} + +static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shader_id0, uint32_t shader_id1) { + struct CCFeatures cc_features = { 0 }; + gfx_cc_get_features(shader_id0, shader_id1, &cc_features); + + char vs_buf[2048]; + char fs_buf[8192]; + size_t vs_len = 0; + size_t fs_len = 0; + size_t num_floats = 4; + + // Vertex shader + + vs_len += sprintf(vs_buf + vs_len, "#version %s\n", gl_glsl_version_str); + + if (gl_es) { + append_line(vs_buf, &vs_len, "precision mediump float;"); + } + + if (gl_glsl_version >= 130) { + append_line(vs_buf, &vs_len, "#define INPUT in"); + append_line(vs_buf, &vs_len, "#define OUTPUT out"); + } else { + append_line(vs_buf, &vs_len, "#define INPUT attribute"); + append_line(vs_buf, &vs_len, "#define OUTPUT varying"); + } + + append_line(vs_buf, &vs_len, "INPUT vec4 aVtxPos;"); + + for (int i = 0; i < 2; i++) { + if (cc_features.used_textures[i]) { + vs_len += sprintf(vs_buf + vs_len, "INPUT vec2 aTexCoord%d;\n", i); + vs_len += sprintf(vs_buf + vs_len, "OUTPUT vec2 vTexCoord%d;\n", i); + num_floats += 2; + for (int j = 0; j < 2; j++) { + if (cc_features.clamp[i][j]) { + vs_len += sprintf(vs_buf + vs_len, "INPUT float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + vs_len += sprintf(vs_buf + vs_len, "OUTPUT float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + num_floats += 1; + } + } + } + } + if (cc_features.opt_fog) { + append_line(vs_buf, &vs_len, "INPUT vec4 aFog;"); + append_line(vs_buf, &vs_len, "OUTPUT vec4 vFog;"); + num_floats += 4; + } + + if (cc_features.opt_grayscale) { + append_line(vs_buf, &vs_len, "INPUT vec4 aGrayscaleColor;"); + append_line(vs_buf, &vs_len, "OUTPUT vec4 vGrayscaleColor;"); + num_floats += 4; + } + + for (int i = 0; i < cc_features.num_inputs; i++) { + vs_len += sprintf(vs_buf + vs_len, "INPUT vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + vs_len += sprintf(vs_buf + vs_len, "OUTPUT vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + num_floats += cc_features.opt_alpha ? 4 : 3; + } + + append_line(vs_buf, &vs_len, "void main() {"); + for (int i = 0; i < 2; i++) { + if (cc_features.used_textures[i]) { + vs_len += sprintf(vs_buf + vs_len, " vTexCoord%d = aTexCoord%d;\n", i, i); + for (int j = 0; j < 2; j++) { + if (cc_features.clamp[i][j]) { + vs_len += sprintf(vs_buf + vs_len, " vTexClamp%s%d = aTexClamp%s%d;\n", j == 0 ? "S" : "T", i, + j == 0 ? "S" : "T", i); + } + } + } + } + if (cc_features.opt_fog) { + append_line(vs_buf, &vs_len, " vFog = aFog;"); + } + if (cc_features.opt_grayscale) { + append_line(vs_buf, &vs_len, " vGrayscaleColor = aGrayscaleColor;"); + } + for (int i = 0; i < cc_features.num_inputs; i++) { + vs_len += sprintf(vs_buf + vs_len, " vInput%d = aInput%d;\n", i + 1, i + 1); + } + + append_line(vs_buf, &vs_len, " gl_Position = aVtxPos;"); + if (!GLAD_GL_ARB_depth_clamp) { + // HACK: workaround for no GL_DEPTH_CLAMP + append_line(vs_buf, &vs_len, " gl_Position.z *= 0.3f;"); + } + append_line(vs_buf, &vs_len, "}"); + + // Fragment shader + + fs_len += sprintf(fs_buf + fs_len, "#version %s\n", gl_glsl_version_str); + + if (gl_es) { + append_line(fs_buf, &fs_len, "precision mediump float;"); + } + + if (gl_glsl_version >= 130) { + append_line(fs_buf, &fs_len, "#define INPUT in"); + append_line(fs_buf, &fs_len, "#define OUTPUT_COLOR outColor"); + append_line(fs_buf, &fs_len, "#define SAMPLE_TEX(tex, uv) texture(tex, uv)"); + } else { + append_line(fs_buf, &fs_len, "#define INPUT varying"); + append_line(fs_buf, &fs_len, "#define OUTPUT_COLOR gl_FragColor"); + append_line(fs_buf, &fs_len, "#define SAMPLE_TEX(tex, uv) texture2D(tex, uv)"); + } + + // Reference approach to color wrapping as per GLideN64 + // Return wrapped value of x in interval [low, high) + append_line(fs_buf, &fs_len, "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low)"); + + append_line(fs_buf, &fs_len, "#define TEX_OFFSET(tex, uv, texSize, off) SAMPLE_TEX(tex, uv - (off)/texSize)"); + + // append_line(fs_buf, &fs_len, "precision mediump float;"); + for (int i = 0; i < 2; i++) { + if (cc_features.used_textures[i]) { + fs_len += sprintf(fs_buf + fs_len, "INPUT vec2 vTexCoord%d;\n", i); + for (int j = 0; j < 2; j++) { + if (cc_features.clamp[i][j]) { + fs_len += sprintf(fs_buf + fs_len, "INPUT float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + } + } + } + } + if (cc_features.opt_fog) { + append_line(fs_buf, &fs_len, "INPUT vec4 vFog;"); + } + if (cc_features.opt_grayscale) { + append_line(fs_buf, &fs_len, "INPUT vec4 vGrayscaleColor;"); + } + for (int i = 0; i < cc_features.num_inputs; i++) { + fs_len += sprintf(fs_buf + fs_len, "INPUT vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + } + + if (cc_features.used_textures[0]) { + append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;"); + if (current_filter_mode == FILTER_THREE_POINT) + append_line(fs_buf, &fs_len, "uniform int three_point_filter0;"); + } + if (cc_features.used_textures[1]) { + append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;"); + if (current_filter_mode == FILTER_THREE_POINT) + append_line(fs_buf, &fs_len, "uniform int three_point_filter1;"); + } + + append_line(fs_buf, &fs_len, "uniform int frame_count;"); + append_line(fs_buf, &fs_len, "uniform float noise_scale;"); + + append_line(fs_buf, &fs_len, "float random(in vec3 value) {"); + append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));"); + append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);"); + append_line(fs_buf, &fs_len, "}"); + + if (current_filter_mode == FILTER_THREE_POINT) { + append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {"); + append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));"); + append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);"); + append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(tex, texCoord, texSize, offset);"); + append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(tex, texCoord, texSize, vec2(offset.x - sign(offset.x), offset.y));"); + append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(tex, texCoord, texSize, vec2(offset.x, offset.y - sign(offset.y)));"); + append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);"); + append_line(fs_buf, &fs_len, "}"); + } + + if (cc_features.opt_blur) { + // blur filter, used for menu backgrounds + // used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it + // used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers + + if (current_filter_mode == FILTER_THREE_POINT) + append_line(fs_buf, &fs_len, "lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 texSize, in int three_point_filter) {"); + else + append_line(fs_buf, &fs_len, "lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 texSize) {"); + + append_line(fs_buf, &fs_len, " lowp vec4 cw = vec4(0.0);"); + append_line(fs_buf, &fs_len, " for (int i = 0; i < 16; ++i) {"); + append_line(fs_buf, &fs_len, " vec2 xy = vec2(float(i & 3), float(i >> 2));"); + append_line(fs_buf, &fs_len, " lowp float w = 0.009947 - length(xy) * 0.001;"); + append_line(fs_buf, &fs_len, " vec2 scaled_uv = uv + (vec2(-1.5) + xy) / texSize;"); + + if (current_filter_mode == FILTER_THREE_POINT) + append_line(fs_buf, &fs_len, " lowp vec4 tex = mix(SAMPLE_TEX(t, scaled_uv), filter3point(t, scaled_uv, texSize), three_point_filter);"); + else + append_line(fs_buf, &fs_len, " lowp vec4 tex = SAMPLE_TEX(t, scaled_uv);"); + + append_line(fs_buf, &fs_len, " cw += vec4(tex.rgb * w, w);"); + append_line(fs_buf, &fs_len, " }"); + append_line(fs_buf, &fs_len, " return vec4(cw.rgb / cw.a, 1.0);"); + append_line(fs_buf, &fs_len, "}"); + } else { + if (current_filter_mode == FILTER_THREE_POINT) { + append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize, in int three_point_filter) {"); + append_line(fs_buf, &fs_len, " return mix(SAMPLE_TEX(tex, uv), filter3point(tex, uv, texSize), three_point_filter);"); + append_line(fs_buf, &fs_len, "}"); + } else { + append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); + append_line(fs_buf, &fs_len, " return SAMPLE_TEX(tex, uv);"); + append_line(fs_buf, &fs_len, "}"); + } + } + + if (gl_glsl_version >= 130) { + append_line(fs_buf, &fs_len, "out vec4 outColor;"); + } + + append_line(fs_buf, &fs_len, "void main() {"); + + for (int i = 0; i < 2; i++) { + if (cc_features.used_textures[i]) { + bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1]; + + fs_len += sprintf(fs_buf + fs_len, " vec2 texSize%d = vec2(textureSize(uTex%d, 0));\n", i, i); + + if (!s && !t) { + fs_len += sprintf(fs_buf + fs_len, " vec2 vTexCoordAdj%d = vTexCoord%d;\n", i, i); + } else { + if (s && t) { + fs_len += sprintf(fs_buf + fs_len, + " vec2 vTexCoordAdj%d = clamp(vTexCoord%d, 0.5 / texSize%d, " + "vec2(vTexClampS%d, vTexClampT%d));\n", + i, i, i, i, i); + } else if (s) { + fs_len += sprintf(fs_buf + fs_len, + " vec2 vTexCoordAdj%d = vec2(clamp(vTexCoord%d.s, 0.5 / " + "texSize%d.s, vTexClampS%d), vTexCoord%d.t);\n", + i, i, i, i, i); + } else { + fs_len += sprintf(fs_buf + fs_len, + " vec2 vTexCoordAdj%d = vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, " + "0.5 / texSize%d.t, vTexClampT%d));\n", + i, i, i, i, i); + } + } + + if (current_filter_mode == FILTER_THREE_POINT) + fs_len += sprintf(fs_buf + fs_len, " vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d, three_point_filter%d);\n", i, i, i, i, i); + else + fs_len += sprintf(fs_buf + fs_len, " vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i); + } + } + + append_line(fs_buf, &fs_len, cc_features.opt_alpha ? " vec4 texel;" : " vec3 texel;"); + for (int c = 0; c < (cc_features.opt_2cyc ? 2 : 1); c++) { + append_str(fs_buf, &fs_len, " texel = "); + if (!cc_features.color_alpha_same[c] && cc_features.opt_alpha) { + append_str(fs_buf, &fs_len, "vec4("); + append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][0], + cc_features.do_multiply[c][0], cc_features.do_mix[c][0], false, false, true); + append_str(fs_buf, &fs_len, ", "); + append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][1], + cc_features.do_multiply[c][1], cc_features.do_mix[c][1], true, true, true); + append_str(fs_buf, &fs_len, ")"); + } else { + append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][0], + cc_features.do_multiply[c][0], cc_features.do_mix[c][0], cc_features.opt_alpha, false, + cc_features.opt_alpha); + } + append_line(fs_buf, &fs_len, ";"); + + if (c == 0) { + append_line(fs_buf, &fs_len, " texel = WRAP(texel, -1.01, 1.01);"); + } + } + + append_line(fs_buf, &fs_len, " texel = WRAP(texel, -0.51, 1.51);"); + append_line(fs_buf, &fs_len, " texel = clamp(texel, 0.0, 1.0);"); + // TODO discard if alpha is 0? + if (cc_features.opt_fog) { + if (cc_features.opt_alpha) { + append_line(fs_buf, &fs_len, " texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a);"); + } else { + append_line(fs_buf, &fs_len, " texel = mix(texel, vFog.rgb, vFog.a);"); + } + } + + if (cc_features.opt_texture_edge && cc_features.opt_alpha) { + append_line(fs_buf, &fs_len, " if (texel.a > 0.19) texel.a = 1.0; else discard;"); + } + + if (cc_features.opt_alpha && cc_features.opt_noise) { + append_line(fs_buf, &fs_len, + " texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + " + "texel.a, 0.0, 1.0));"); + } + + if (cc_features.opt_grayscale) { + append_line(fs_buf, &fs_len, " float intensity = (texel.r + texel.g + texel.b) / 3.0;"); + append_line(fs_buf, &fs_len, " vec3 new_texel = vGrayscaleColor.rgb * intensity;"); + append_line(fs_buf, &fs_len, " texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a);"); + } + + if (cc_features.opt_alpha) { + if (cc_features.opt_alpha_threshold) { + append_line(fs_buf, &fs_len, " if (texel.a < 8.0 / 256.0) discard;"); + } + if (cc_features.opt_invisible) { + append_line(fs_buf, &fs_len, " texel.a = 0.0;"); + } + + append_line(fs_buf, &fs_len, " OUTPUT_COLOR = texel;"); + } else { + append_line(fs_buf, &fs_len, " OUTPUT_COLOR = vec4(texel, 1.0);"); + } + + append_line(fs_buf, &fs_len, "}"); + + vs_buf[vs_len] = '\0'; + fs_buf[fs_len] = '\0'; + + const GLchar* sources[2] = { vs_buf, fs_buf }; + const GLint lengths[2] = { (GLint)vs_len, (GLint)fs_len }; + GLint success; + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &sources[0], &lengths[0]); + glCompileShader(vertex_shader); + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); + if (!success) { + GLint max_length = 1024; + glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length); + char error_log[1024]; + glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]); + sysLogPrintf(LOG_ERROR, "Failed to compile this vertex shader (ID %llx, %x):\n%s", shader_id0, shader_id1, vs_buf); + sysFatalError("Vertex shader compilation failed:\n%s", error_log); + } + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &sources[1], &lengths[1]); + glCompileShader(fragment_shader); + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); + if (!success) { + GLint max_length = 1024; + glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length); + char error_log[1024]; + glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]); + sysLogPrintf(LOG_ERROR, "Failed to compile this fragment shader (ID %llx, %x):\n%s", shader_id0, shader_id1, fs_buf); + sysFatalError("Fragment shader compilation failed:\n%s", error_log); + } + + GLuint shader_program = glCreateProgram(); + glAttachShader(shader_program, vertex_shader); + glAttachShader(shader_program, fragment_shader); + glLinkProgram(shader_program); + + glDetachShader(shader_program, vertex_shader); + glDetachShader(shader_program, fragment_shader); + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + + size_t cnt = 0; + + struct ShaderProgram* prg = &shader_program_pool[make_pair(shader_id0, shader_id1)]; + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aVtxPos"); + prg->attrib_sizes[cnt] = 4; + ++cnt; + + for (int i = 0; i < 2; i++) { + if (cc_features.used_textures[i]) { + char name[32]; + sprintf(name, "aTexCoord%d", i); + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, name); + prg->attrib_sizes[cnt] = 2; + ++cnt; + + for (int j = 0; j < 2; j++) { + if (cc_features.clamp[i][j]) { + sprintf(name, "aTexClamp%s%d", j == 0 ? "S" : "T", i); + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, name); + prg->attrib_sizes[cnt] = 1; + ++cnt; + } + } + } + } + + if (cc_features.opt_fog) { + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aFog"); + prg->attrib_sizes[cnt] = 4; + ++cnt; + } + + if (cc_features.opt_grayscale) { + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aGrayscaleColor"); + prg->attrib_sizes[cnt] = 4; + ++cnt; + } + + for (int i = 0; i < cc_features.num_inputs; i++) { + char name[16]; + sprintf(name, "aInput%d", i + 1); + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, name); + prg->attrib_sizes[cnt] = cc_features.opt_alpha ? 4 : 3; + ++cnt; + } + + prg->opengl_program_id = shader_program; + prg->num_inputs = cc_features.num_inputs; + prg->used_textures[0] = cc_features.used_textures[0]; + prg->used_textures[1] = cc_features.used_textures[1]; + prg->num_floats = num_floats; + prg->num_attribs = cnt; + + glUseProgram(shader_program); + + if (cc_features.used_textures[0]) { + GLint sampler_location = glGetUniformLocation(shader_program, "uTex0"); + glUniform1i(sampler_location, 0); + } + if (cc_features.used_textures[1]) { + GLint sampler_location = glGetUniformLocation(shader_program, "uTex1"); + glUniform1i(sampler_location, 1); + } + + prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count"); + prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale"); + prg->three_point_filter_locations[0] = glGetUniformLocation(shader_program, "three_point_filter0"); + prg->three_point_filter_locations[1] = glGetUniformLocation(shader_program, "three_point_filter1"); + + gfx_opengl_load_shader(prg); + + return prg; +} + +static struct ShaderProgram* gfx_opengl_lookup_shader(uint64_t shader_id0, uint32_t shader_id1) { + auto it = shader_program_pool.find(make_pair(shader_id0, shader_id1)); + return it == shader_program_pool.end() ? nullptr : &it->second; +} + +static void gfx_opengl_shader_get_info(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]) { + *num_inputs = prg->num_inputs; + used_textures[0] = prg->used_textures[0]; + used_textures[1] = prg->used_textures[1]; +} + +static void gfx_opengl_clear_shaders(void) { + glUseProgram(0); + for (auto& pair : shader_program_pool) { + glDeleteProgram(pair.second.opengl_program_id); + } + shader_program_pool.clear(); +} + +static GLuint gfx_opengl_new_texture(void) { + GLuint ret; + glGenTextures(1, &ret); + return ret; +} + +static void gfx_opengl_delete_texture(uint32_t texID) { + glDeleteTextures(1, &texID); +} + +static void gfx_opengl_select_texture(int tile, GLuint texture_id, bool linear_filter) { + glActiveTexture(GL_TEXTURE0 + tile); + glBindTexture(GL_TEXTURE_2D, texture_id); + + current_textures_linear_filter[tile] = linear_filter; +} + +static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height, bool gen_mipmaps) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); + if (gen_mipmaps || current_filter_mode == FILTER_THREE_POINT) { + glGenerateMipmap(GL_TEXTURE_2D); + } +} + +static uint32_t gfx_cm_to_opengl(uint32_t val) { + switch (val) { + case G_TX_NOMIRROR | G_TX_CLAMP: + return GL_CLAMP_TO_EDGE; + case G_TX_MIRROR | G_TX_WRAP: + return GL_MIRRORED_REPEAT; + case G_TX_MIRROR | G_TX_CLAMP: + return gl_mirror_clamp; + case G_TX_NOMIRROR | G_TX_WRAP: + return GL_REPEAT; + } + return 0; +} + +static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt, bool mipmaps) { + const GLint min_filters[3][3] = { + // MIPMAP_DISABLED MIPMAP_NEAREST MIPMAP_LINEAR + { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR }, // FILTER_NONE + { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR }, // FILTER_BILINEAR + { GL_NEAREST, GL_NEAREST, GL_NEAREST }, // FILTER_THREE_POINT + }; + + mipmaps = mipmaps && (current_mipmap_filter_mode != MIPMAP_DISABLED); + const int mip_idx = mipmaps ? current_mipmap_filter_mode : 0; + const GLint min_filter = linear_filter ? min_filters[current_filter_mode][mip_idx] : GL_NEAREST; + const GLint max_filter = linear_filter && (current_filter_mode == FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST; + + glActiveTexture(GL_TEXTURE0 + tile); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, max_filter); + + if (mipmaps) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, current_anisotropy_level); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt)); +} + +static void gfx_opengl_set_depth_mode(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode) { + if (depth_test) { + glEnable(GL_DEPTH_TEST); + glDepthMask(depth_update ? GL_TRUE : GL_FALSE); + current_depth_mask = depth_update; + + if (depth_compare) { + switch (zmode) { + case ZMODE_INTER: + glDepthFunc(GL_LEQUAL); + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0, 0); + break; + + case ZMODE_OPA: + case ZMODE_XLU: + if (depth_source_prim) { + glDepthFunc(GL_LEQUAL); + } else { + glDepthFunc(GL_LESS); + } + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0, 0); + break; + + case ZMODE_DEC: + glDepthFunc(GL_LEQUAL); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-2, -2); + break; + } + } else { + glDepthFunc(GL_ALWAYS); + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0, 0); + } + } else { + glDisable(GL_DEPTH_TEST); + } +} + +static void gfx_opengl_set_depth_range(float znear, float zfar) { + if (glDepthRangef) { + glDepthRangef(znear, zfar); + } else { + glDepthRange(znear, zfar); + } +} + +static void gfx_opengl_set_viewport(int x, int y, int width, int height) { + glViewport(x, y, width, height); +} + +static void gfx_opengl_set_scissor(int x, int y, int width, int height) { + glScissor(x, y, width, height); +} + +static void gfx_opengl_set_use_alpha(bool use_alpha, bool modulate) { + if (use_alpha) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } + if (modulate) { + glBlendFunc(GL_DST_COLOR, GL_ZERO); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } +} + +static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { + // printf("flushing %d tris\n", buf_vbo_num_tris); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris); +} + +typedef void (APIENTRY *DEBUGPROC)(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *message, + const void *userParam); + +static void APIENTRY gl_debug(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *msg, const void *p) { + sysLogPrintf(LOG_WARNING, "GL: (%05x) %s", id, msg); +} + +static void gfx_opengl_enable_debug(void) { + if (GLAD_GL_KHR_debug) { + glEnable(GL_DEBUG_OUTPUT); + } + if (glDebugMessageControl != NULL) { + // enable everything except some specific spam messages + const GLuint disable[] = { + 0x20061, /* "Framebuffer detailed info" */ + 0x20071 /* "Buffer detailed info" */ + }; + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, 2, disable, GL_FALSE); + } + if (glDebugMessageCallback != NULL) { + glDebugMessageCallback(gl_debug, NULL); + } +} + +static bool gfx_opengl_supports_framebuffers(void) { + if (GLVersion.major > 2) { + // GL3.0+ supports everything we need, but we'll still check it for sanity + return (glad_glFramebufferRenderbuffer && glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample); + } + if (GLAD_GL_ARB_framebuffer_object) { + // some implementations might be missing these + return (glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample); + } + if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) { + // sanity check + return (glad_glFramebufferRenderbuffer && glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample); + } + // nothing + return false; +} + +static bool gfx_opengl_supports_shaders(void) { + if (GLVersion.major > 2) { + // should support GLSL130+ + return true; + } + + // check supported GLSL version + const char *ver = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION); + if (ver) { + int maj = 0, min = 0; + sscanf(ver, "%d.%d", &maj, &min); + if (maj > 1 || (maj == 1 && min > 20)) { + // above 120, should be fine + return true; + } + } + + // check for extension that adds textureSize + return GLAD_GL_EXT_gpu_shader4; +} + +static void gfx_opengl_log_info(void) { + const char *version = (const char *)glGetString(GL_VERSION); + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *glsl_version = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION); + sysLogPrintf(LOG_NOTE, "GL: version: %s", version ? version : "unknown"); + sysLogPrintf(LOG_NOTE, "GL: vendor: %s", vendor ? vendor : "unknown"); + sysLogPrintf(LOG_NOTE, "GL: renderer: %s", renderer ? renderer : "unknown"); + sysLogPrintf(LOG_NOTE, "GL: GLSL version: %s", glsl_version ? glsl_version : "unknown"); + sysLogPrintf(LOG_NOTE, "GL: ARB_framebuffer_object: %s", gfx_opengl_supports_framebuffers() ? "yes" : "no"); + sysLogPrintf(LOG_NOTE, "GL: ARB_depth_clamp: %s", GLAD_GL_ARB_depth_clamp ? "yes" : "no"); + sysLogPrintf(LOG_NOTE, "GL: ARB_texture_mirror_clamp_to_edge: %s", GLAD_GL_ARB_texture_mirror_clamp_to_edge ? "yes" : "no"); +} + +static void *gl_load_proc(const char *name) { + void *ret = SDL_GL_GetProcAddress(name); + if (ret) { + return ret; + } + + // try with postfixes + static const char *post[] = { "ARB", "EXT" }; + char tmp[256] = { 0 }; + for (size_t i = 0; i < sizeof(post) / sizeof(*post); ++i) { + snprintf(tmp, sizeof(tmp), "%s%s", name, post[i]); + ret = SDL_GL_GetProcAddress(tmp); + if (ret) { + return ret; + } + } + + sysLogPrintf(LOG_ERROR, "GL: could not find function: %s", name); + + return NULL; +} + +static void gfx_opengl_init_extensions(void) { + // patch up some extension values and pointers + if (!GLAD_GL_ARB_depth_clamp) { + if (GLAD_GL_EXT_depth_clamp || GLAD_GL_NV_depth_clamp) { + GLAD_GL_ARB_depth_clamp = 1; + } else if (!gl_es && GLVersion.major >= 3) { + // GL3.2+ should have depth_clamp as part of the spec, but some devices don't report it for some reason + GLAD_GL_ARB_depth_clamp = (GLVersion.major > 3 || (GLVersion.major == 3 && GLVersion.minor >= 2)); + } + } + + if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) { + GLAD_GL_ARB_texture_mirror_clamp_to_edge = GLAD_GL_EXT_texture_mirror_clamp_to_edge; + } + + if (GLVersion.major < 3 && !GLAD_GL_ARB_framebuffer_object) { + if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) { + // because of the way glad works we'll have to copy the pointers over + glad_glGenFramebuffers = glad_glGenFramebuffersEXT; + glad_glGenRenderbuffers = glad_glGenRenderbuffersEXT; + glad_glDeleteFramebuffers = glad_glDeleteFramebuffersEXT; + glad_glDeleteRenderbuffers = glad_glDeleteRenderbuffersEXT; + glad_glBindFramebuffer = glad_glBindFramebufferEXT; + glad_glBindRenderbuffer = glad_glBindRenderbufferEXT; + glad_glFramebufferRenderbuffer = glad_glFramebufferRenderbufferEXT; + glad_glFramebufferTexture2D = glad_glFramebufferTexture2DEXT; + glad_glRenderbufferStorage = glad_glRenderbufferStorageEXT; + glad_glRenderbufferStorageMultisample = glad_glRenderbufferStorageMultisampleEXT; + glad_glBlitFramebuffer = glad_glBlitFramebufferEXT; + } + } +} + +static void gfx_opengl_init(void) { + if (!gladLoadGLLoader(gl_load_proc) || glGetString == NULL || glEnable == NULL) { + sysFatalError("Could not load OpenGL.\nReported SDL error: %s", SDL_GetError()); + } + + // check if we're using ES or core, which have more limited feature sets + int val = 0; + SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &val); + gl_core_profile = (val == SDL_GL_CONTEXT_PROFILE_CORE); + gl_es = (val == SDL_GL_CONTEXT_PROFILE_ES); + + gfx_opengl_init_extensions(); + + if (sysArgCheck("--debug-gl")) { + gfx_opengl_enable_debug(); + // dump version info as early as possible + gfx_opengl_log_info(); + } + + if (GLVersion.major < 2 || (GLVersion.major == 2 && GLVersion.minor < 1)) { + const char *ver = (const char *)glGetString(GL_VERSION); + sysFatalError("Could not load OpenGL 2.1.\nReported version: %d.%d (%s)", + GLVersion.major, GLVersion.minor, ver ? ver : "unknown"); + } + + if (!gfx_opengl_supports_shaders()) { + sysLogPrintf(LOG_WARNING, "GL: GLSL 1.30 may be unsupported"); + // maybe replace this with sysFatalError, though the GLSL compiler will cause that later anyway + } + + if (!gfx_framebuffers_enabled) { + sysLogPrintf(LOG_WARNING, "GL: framebuffer effects disabled by user"); + } else if (!gfx_opengl_supports_framebuffers()) { + sysLogPrintf(LOG_WARNING, "GL: GL_ARB_framebuffer_object unsupported, framebuffer effects disabled"); + gfx_framebuffers_enabled = false; + } + + if ((GLVersion.major < 4 || GLVersion.minor < 4) && !GLAD_GL_ARB_texture_mirror_clamp_to_edge) { + // GL_MIRROR_CLAMP_TO_EDGE unsupported + gl_mirror_clamp = GL_MIRRORED_REPEAT; + } + + // determine GLSL version + if (gl_es) { + // ES has its own numbering scheme, but it should support 300 even on 3.1 and 3.2 + gl_glsl_version = 300; + snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d es", gl_glsl_version); + } else if (!gl_core_profile) { + // in compat profile we can just request the lowest possible + gl_glsl_version = 130; + snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d", gl_glsl_version); + } else { + // otherwise we have to pick a specific version + if (GLVersion.major == 3 && GLVersion.minor == 2) { + // 3.2core is the earliest core version and it follows the old numbering scheme + gl_glsl_version = 150; + } else { + // 3.3+ follow the new numbering scheme + gl_glsl_version = GLVersion.major * 100 + GLVersion.minor * 10; + } + snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d core", gl_glsl_version); + } + sysLogPrintf(LOG_NOTE, "GL: using GLSL version %s", gl_glsl_version_str); + + glGenBuffers(1, &opengl_vbo); + glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); + + if (gl_core_profile || gl_es) { + // warn user that funny things can happen + sysLogPrintf(LOG_WARNING, "GL: using core profile or ES, watch out for errors"); + // core/es will explode if we don't use a VAO for our VBO + glGenVertexArrays(1, &opengl_vao); + glBindVertexArray(opengl_vao); + } + + if (GLAD_GL_ARB_depth_clamp) { + glEnable(GL_DEPTH_CLAMP); + } + glDepthFunc(GL_LEQUAL); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + framebuffers.resize(1); // for the default screen buffer +} + +static void gfx_opengl_on_resize(void) { +} + +static void gfx_opengl_start_frame(void) { + frame_count++; +} + +static void gfx_opengl_end_frame(void) { + glFlush(); +} + +static void gfx_opengl_finish_render(void) { +} + +static int gfx_opengl_create_framebuffer() { + size_t i = framebuffers.size(); + framebuffers.resize(i + 1); + + GLuint clrbuf; + glGenTextures(1, &clrbuf); + glBindTexture(GL_TEXTURE_2D, clrbuf); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + framebuffers[i].clrbuf = clrbuf; + + if (!gfx_framebuffers_enabled) { + return i; + } + + GLuint clrbuf_msaa; + glGenRenderbuffers(1, &clrbuf_msaa); + framebuffers[i].clrbuf_msaa = clrbuf_msaa; + + GLuint rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1, 1); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + framebuffers[i].rbo = rbo; + + GLuint fbo; + glGenFramebuffers(1, &fbo); + framebuffers[i].fbo = fbo; + + return i; +} + +static void gfx_opengl_update_framebuffer_parameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, + bool opengl_invert_y, bool render_target, bool has_depth_buffer, + bool can_extract_depth) { + Framebuffer& fb = framebuffers[fb_id]; + + width = max(width, 1U); + height = max(height, 1U); + + if (gfx_framebuffers_enabled) { + glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo); + + if (fb_id != 0) { + if (fb.width != width || fb.height != height || fb.msaa_level != msaa_level) { + if (msaa_level <= 1) { + glBindTexture(GL_TEXTURE_2D, fb.clrbuf); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.clrbuf, 0); + } else { + glBindRenderbuffer(GL_RENDERBUFFER, fb.clrbuf_msaa); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, GL_RGB8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fb.clrbuf_msaa); + } + } + + if (has_depth_buffer && + (fb.width != width || fb.height != height || fb.msaa_level != msaa_level || !fb.has_depth_buffer)) { + glBindRenderbuffer(GL_RENDERBUFFER, fb.rbo); + if (msaa_level <= 1) { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + } else { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, GL_DEPTH24_STENCIL8, width, height); + } + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + + if (!fb.has_depth_buffer && has_depth_buffer) { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.rbo); + } else if (fb.has_depth_buffer && !has_depth_buffer) { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + } + } + } else { + has_depth_buffer = false; + } + + fb.width = width; + fb.height = height; + fb.has_depth_buffer = has_depth_buffer; + fb.msaa_level = msaa_level; + fb.invert_y = opengl_invert_y; +} + +bool gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) { + if (gfx_framebuffers_enabled && fb_id < (int)framebuffers.size()) { + Framebuffer& fb = framebuffers[fb_id]; + if (noise_scale != 0.0f) { + current_noise_scale = 1.0f / noise_scale; + } + glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo); + current_framebuffer = fb_id; + return true; + } else { + return false; + } +} + +void gfx_opengl_clear_framebuffer(bool clear_color, bool clear_depth) { + glDisable(GL_SCISSOR_TEST); + + GLbitfield mask = 0; + if (clear_color) { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + mask |= GL_COLOR_BUFFER_BIT; + } + if (clear_depth) { + glDepthMask(GL_TRUE); + mask |= GL_DEPTH_BUFFER_BIT; + } + glClear(mask); + if (clear_depth) { + glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE); + } + + glEnable(GL_SCISSOR_TEST); +} + +void gfx_opengl_resolve_msaa_color_buffer(int fb_id_target, int fb_id_source) { + if (!gfx_framebuffers_enabled) { + return; + } + + Framebuffer& fb_dst = framebuffers[fb_id_target]; + Framebuffer& fb_src = framebuffers[fb_id_source]; + glDisable(GL_SCISSOR_TEST); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_dst.fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_src.fbo); + glBlitFramebuffer(0, 0, fb_src.width, fb_src.height, 0, 0, fb_dst.width, fb_dst.height, GL_COLOR_BUFFER_BIT, + GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, current_framebuffer); + glEnable(GL_SCISSOR_TEST); +} + +void* gfx_opengl_get_framebuffer_texture_id(int fb_id) { + return (void*)(uintptr_t)framebuffers[fb_id].clrbuf; +} + +void gfx_opengl_select_texture_fb(int fb_id) { + // glDisable(GL_DEPTH_TEST); + glActiveTexture(GL_TEXTURE0 + 0); + glBindTexture(GL_TEXTURE_2D, framebuffers[fb_id].clrbuf); + + current_textures_linear_filter[0] = true; +} + +void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back) { + if (!gfx_framebuffers_enabled || fb_dst >= (int)framebuffers.size() || fb_src >= (int)framebuffers.size()) { + return; + } + + const Framebuffer& src = framebuffers[fb_src]; + const Framebuffer& dst = framebuffers[fb_dst]; + + int srcX0, srcY0, srcX1, srcY1; + int dstX0, dstY0, dstX1, dstY1; + + dstX0 = dstY0 = 0; + dstX1 = dst.width; + dstY1 = dst.height; + + if (left >= 0 && top >= 0) { + // unscaled rect copy + srcX0 = left; + srcY0 = top; + srcX1 = left + dst.width; + srcY1 = top + dst.height; + } else { + // scaled full copy + srcX0 = 0; + srcY0 = 0; + srcX1 = src.width; + srcY1 = src.height; + } + + glDisable(GL_SCISSOR_TEST); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, src.fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst.fbo); + + if (flip_y) { + // flip the dst rect to mirror the image vertically + std::swap(dstY0, dstY1); + } + + if (fb_src == 0) { + // GLES does not support GL_FRONT here + glReadBuffer((use_back || gl_es) ? GL_BACK : GL_FRONT); + } else { + glReadBuffer(GL_COLOR_ATTACHMENT0); + } + + glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[current_framebuffer].fbo); + + glReadBuffer(GL_BACK); + + glEnable(GL_SCISSOR_TEST); +} + +void gfx_opengl_set_texture_filter(FilteringMode mode) { + current_filter_mode = mode; +} + +FilteringMode gfx_opengl_get_texture_filter(void) { + return current_filter_mode; +} + +void gfx_opengl_set_mipmap_filter(MipmapFilteringMode mode) { + current_mipmap_filter_mode = mode; +} + +static int gfx_opengl_get_max_anisotropy_level() { + GLfloat max_aniso_level; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso_level); + return (int)max_aniso_level; +} + +static void gfx_opengl_set_anisotropy_level(int level) { + current_anisotropy_level = level; +} + +struct GfxRenderingAPI gfx_opengl_api = { + gfx_opengl_get_name, + gfx_opengl_get_max_texture_size, + gfx_opengl_get_clip_parameters, + gfx_opengl_unload_shader, + gfx_opengl_load_shader, + gfx_opengl_create_and_load_new_shader, + gfx_opengl_lookup_shader, + gfx_opengl_shader_get_info, + gfx_opengl_clear_shaders, + gfx_opengl_new_texture, + gfx_opengl_select_texture, + gfx_opengl_upload_texture, + gfx_opengl_set_sampler_parameters, + gfx_opengl_set_depth_mode, + gfx_opengl_set_depth_range, + gfx_opengl_set_viewport, + gfx_opengl_set_scissor, + gfx_opengl_set_use_alpha, + gfx_opengl_draw_triangles, + gfx_opengl_init, + gfx_opengl_on_resize, + gfx_opengl_start_frame, + gfx_opengl_end_frame, + gfx_opengl_finish_render, + gfx_opengl_create_framebuffer, + gfx_opengl_update_framebuffer_parameters, + gfx_opengl_start_draw_to_framebuffer, + gfx_opengl_copy_framebuffer, + gfx_opengl_clear_framebuffer, + gfx_opengl_resolve_msaa_color_buffer, + gfx_opengl_get_framebuffer_texture_id, + gfx_opengl_select_texture_fb, + gfx_opengl_delete_texture, + gfx_opengl_set_texture_filter, + gfx_opengl_get_texture_filter, + gfx_opengl_set_mipmap_filter, + gfx_opengl_set_anisotropy_level, + gfx_opengl_get_max_anisotropy_level +}; diff --git a/port/fast3d/gfx_opengl.h b/port/fast3d/gfx_opengl.h new file mode 100644 index 00000000..95be897a --- /dev/null +++ b/port/fast3d/gfx_opengl.h @@ -0,0 +1,8 @@ +#ifndef GFX_OPENGL_H +#define GFX_OPENGL_H + +#include "gfx_rendering_api.h" + +extern struct GfxRenderingAPI gfx_opengl_api; + +#endif diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp new file mode 100644 index 00000000..8580f7f0 --- /dev/null +++ b/port/fast3d/gfx_pc.cpp @@ -0,0 +1,2830 @@ +#define NOMINMAX + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _LANGUAGE_C +#define _LANGUAGE_C +#endif +#include +#include "gbiex.h" /* GE's G_TRI4 + PD extension opcodes (see header) */ + +#include "platform.h" + +#include "gfx_pc.h" +#include "gfx_cc.h" +#include "gfx_window_manager_api.h" +#include "gfx_rendering_api.h" +#include "gfx_screen_config.h" + +uintptr_t gfxFramebuffer; + +#define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1)) + +#define SUPPORT_CHECK(x) assert(x) + +// SCALE_M_N: upscale/downscale M-bit integer to N-bit +#define SCALE_5_8(VAL_) (((VAL_)*0xFF) / 0x1F) +#define SCALE_8_5(VAL_) ((((VAL_) + 4) * 0x1F) / 0xFF) +#define SCALE_4_8(VAL_) ((VAL_)*0x11) +#define SCALE_8_4(VAL_) ((VAL_) / 0x11) +#define SCALE_3_8(VAL_) ((VAL_)*0x24) +#define SCALE_8_3(VAL_) ((VAL_) / 0x24) + +// SCREEN_WIDTH and SCREEN_HEIGHT are defined in the headerfile +#define HALF_SCREEN_WIDTH (SCREEN_WIDTH / 2.f) +#define HALF_SCREEN_HEIGHT (SCREEN_HEIGHT / 2.f) + +#define RATIO_X (gfx_current_dimensions.width / (float)SCREEN_WIDTH) +#define RATIO_Y (gfx_current_dimensions.height / (float)SCREEN_HEIGHT) + +#define MAX_BUFFERED 256 +#define MAX_LIGHTS 4 +#define MAX_VERTICES 128 +#define MAX_VERTEX_COLORS 64 + +#define TEXTURE_CACHE_MAX_SIZE 1024 + +#define C0(pos, width) ((cmd->words.w0 >> (pos)) & ((1U << width) - 1)) +#define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1)) + +struct RGBA { + uint8_t r, g, b, a; +}; + +struct NormalColor { + union { + struct { uint8_t r, g, b, a; }; + struct { int8_t x, y, z, w; }; + }; +}; + +struct LoadedVertex { + float x, y, z, w; + float u, v; + struct RGBA color; + uint8_t fog; + uint8_t clip_rej; +}; + +static struct { + TextureCacheMap map; + std::list lru; + std::vector free_texture_ids; +} gfx_texture_cache; + +struct ColorCombiner { + uint64_t shader_id0; + uint32_t shader_id1; + bool used_textures[2]; + struct ShaderProgram* prg[16]; + uint8_t shader_input_mapping[2][7]; +}; + +static std::map color_combiner_pool; +static std::map::iterator prev_combiner = color_combiner_pool.end(); + +static uint8_t* tex_upload_buffer = nullptr; + +static struct RSP { + float modelview_matrix_stack[11][4][4]; + uint8_t modelview_matrix_stack_size; + + float MP_matrix[4][4]; + float P_matrix[4][4]; + + Light_t lookat[2]; + bool lookat_enabled; + + Light_t current_lights[MAX_LIGHTS + 1]; + float current_lights_coeffs[MAX_LIGHTS][3]; + float current_lookat_coeffs[2][3]; // lookat_x, lookat_y + uint8_t current_num_lights; // includes ambient light + bool lights_changed; + + uint32_t geometry_mode; + int16_t fog_mul, fog_offset; + + uint32_t extra_geometry_mode; + + uint32_t aspect_mode; + float aspect_ofs; + float aspect_scale; + + struct { + // U0.16 + uint16_t s, t; + } texture_scaling_factor; + + struct LoadedVertex loaded_vertices[MAX_VERTICES + 4]; + + const struct NormalColor *vertex_colors; //[MAX_VERTEX_COLORS]; +} rsp; + +struct RawTexMetadata { + uint16_t width, height; + float h_byte_scale = 1, v_pixel_scale = 1; +}; + +struct LoadedTexture { + const uint8_t* addr; + uint32_t orig_size_bytes; + uint32_t full_size_bytes; // full_image_line_size_bytes * height + uint32_t size_bytes; // line_size_bytes * height + uint32_t full_image_line_size_bytes; + uint32_t line_size_bytes; + uint32_t tex_flags; + struct RawTexMetadata raw_tex_metadata; +}; + +static struct RDP { + uint16_t palette[256]; + const uint8_t* palette_addrs[2]; + uint32_t palette_fmt; + struct { + const uint8_t* addr; + uint8_t siz; + uint32_t width; + uint32_t tex_flags; + struct RawTexMetadata raw_tex_metadata; + } texture_to_load; + struct { + uint8_t fmt; + uint8_t siz; + uint8_t cms, cmt; + uint8_t shifts, shiftt; + uint16_t uls, ult, lrs, lrt; // U10.2 + uint16_t width, height; // in texels + uint16_t tmem; // 0-511, in 64-bit word units + uint32_t line_size_bytes; + uint8_t palette; + } texture_tile[8]; + LoadedTexture loaded_texture[512]; // for each tmem location + bool textures_changed[2]; + + uint8_t first_tile_index; + uint8_t tex_min_lod; + uint8_t tex_max_lod; + + uint32_t other_mode_l, other_mode_h; + uint64_t combine_mode; + bool grayscale; + bool tex_lod; + bool tex_detail; + + uint8_t prim_lod_fraction; + struct RGBA env_color, prim_color, fog_color, fill_color, grayscale_color; + struct XYWidthHeight viewport, scissor; + bool viewport_or_scissor_changed; + void* z_buf_address; + void* color_image_address; + + int16_t subpixel_ofs_x; + int16_t subpixel_ofs_y; +} rdp; + +static struct RenderingState { + uint8_t depth_mode; + bool alpha_blend; + bool modulate; + struct XYWidthHeight viewport, scissor; + struct ShaderProgram* shader_program; + TextureCacheNode* textures[SHADER_MAX_TEXTURES]; +} rendering_state; + +struct GfxDimensions gfx_current_window_dimensions; +int32_t gfx_current_window_position_x; +int32_t gfx_current_window_position_y; +struct GfxDimensions gfx_current_dimensions; +static struct GfxDimensions gfx_prev_dimensions; +struct XYWidthHeight gfx_current_game_window_viewport; +struct XYWidthHeight gfx_current_native_viewport; +float gfx_current_native_aspect = 4.f / 3.f; +bool gfx_framebuffers_enabled = true; +bool gfx_detail_textures_enabled = true; + +static bool game_renders_to_framebuffer; +static int game_framebuffer; +static int game_framebuffer_msaa_resolved; + +uint32_t gfx_msaa_level = 1; + +static bool dropped_frame; + +static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx +static size_t buf_vbo_len; +static size_t buf_vbo_num_tris; + +static struct GfxWindowManagerAPI* gfx_wapi; +static struct GfxRenderingAPI* gfx_rapi; + +static uintptr_t segmentPointers[16]; + +struct FBInfo { + uint32_t orig_width, orig_height; + uint32_t applied_width, applied_height; + bool upscale, autoresize; +}; + +static bool fbActive = 0; +static std::map::iterator active_fb; +static std::map framebuffers; + +static constexpr float clampf(const float x, const float min, const float max) { + return (x < min) ? min : (x > max) ? max : x; +} + +static void gfx_flush(void) { + if (buf_vbo_len > 0) { + gfx_rapi->draw_triangles(buf_vbo, buf_vbo_len, buf_vbo_num_tris); + buf_vbo_len = 0; + buf_vbo_num_tris = 0; + } +} + +static struct ShaderProgram* gfx_lookup_or_create_shader_program(uint64_t shader_id0, uint32_t shader_id1) { + struct ShaderProgram* prg = gfx_rapi->lookup_shader(shader_id0, shader_id1); + if (prg == NULL) { + gfx_rapi->unload_shader(rendering_state.shader_program); + prg = gfx_rapi->create_and_load_new_shader(shader_id0, shader_id1); + rendering_state.shader_program = prg; + } + return prg; +} + +static const char* ccmux_to_string(uint32_t ccmux) { + static const char* const tbl[] = { + "G_CCMUX_COMBINED", + "G_CCMUX_TEXEL0", + "G_CCMUX_TEXEL1", + "G_CCMUX_PRIMITIVE", + "G_CCMUX_SHADE", + "G_CCMUX_ENVIRONMENT", + "G_CCMUX_1", + "G_CCMUX_COMBINED_ALPHA", + "G_CCMUX_TEXEL0_ALPHA", + "G_CCMUX_TEXEL1_ALPHA", + "G_CCMUX_PRIMITIVE_ALPHA", + "G_CCMUX_SHADE_ALPHA", + "G_CCMUX_ENV_ALPHA", + "G_CCMUX_LOD_FRACTION", + "G_CCMUX_PRIM_LOD_FRAC", + "G_CCMUX_K5", + }; + if (ccmux > 15) { + return "G_CCMUX_0"; + + } else { + return tbl[ccmux]; + } +} + +static const char* acmux_to_string(uint32_t acmux) { + static const char* const tbl[] = { + "G_ACMUX_COMBINED or G_ACMUX_LOD_FRACTION", + "G_ACMUX_TEXEL0", + "G_ACMUX_TEXEL1", + "G_ACMUX_PRIMITIVE", + "G_ACMUX_SHADE", + "G_ACMUX_ENVIRONMENT", + "G_ACMUX_1 or G_ACMUX_PRIM_LOD_FRAC", + "G_ACMUX_0", + }; + return tbl[acmux]; +} + +static void gfx_generate_cc(struct ColorCombiner* comb, const ColorCombinerKey& key) { + bool is_2cyc = (key.options & (uint64_t)SHADER_OPT_2CYC) != 0; + + uint8_t c[2][2][4] = { { { 0 } } }; + uint64_t shader_id0 = 0; + uint32_t shader_id1 = key.options; + uint8_t shader_input_mapping[2][7] = { { 0 } }; + bool used_textures[2] = { false, false }; + for (int i = 0; i < 2 && (i == 0 || is_2cyc); i++) { + uint32_t rgb_a = (key.combine_mode >> (i * 28)) & 0xf; + uint32_t rgb_b = (key.combine_mode >> (i * 28 + 4)) & 0xf; + uint32_t rgb_c = (key.combine_mode >> (i * 28 + 8)) & 0x1f; + uint32_t rgb_d = (key.combine_mode >> (i * 28 + 13)) & 7; + uint32_t alpha_a = (key.combine_mode >> (i * 28 + 16)) & 7; + uint32_t alpha_b = (key.combine_mode >> (i * 28 + 16 + 3)) & 7; + uint32_t alpha_c = (key.combine_mode >> (i * 28 + 16 + 6)) & 7; + uint32_t alpha_d = (key.combine_mode >> (i * 28 + 16 + 9)) & 7; + + if (rgb_a >= 8) { + rgb_a = G_CCMUX_0; + } + if (rgb_b >= 8) { + rgb_b = G_CCMUX_0; + } + if (rgb_c >= 16) { + rgb_c = G_CCMUX_0; + } + if (rgb_d == 7) { + rgb_d = G_CCMUX_0; + } + + if (rgb_a == rgb_b || rgb_c == G_CCMUX_0) { + // Normalize + rgb_a = G_CCMUX_0; + rgb_b = G_CCMUX_0; + rgb_c = G_CCMUX_0; + } + if (alpha_a == alpha_b || alpha_c == G_ACMUX_0) { + // Normalize + alpha_a = G_ACMUX_0; + alpha_b = G_ACMUX_0; + alpha_c = G_ACMUX_0; + } + if (i == 1) { + if (rgb_a != G_CCMUX_COMBINED && rgb_b != G_CCMUX_COMBINED && rgb_c != G_CCMUX_COMBINED && + rgb_d != G_CCMUX_COMBINED) { + // First cycle RGB not used, so clear it away + c[0][0][0] = c[0][0][1] = c[0][0][2] = c[0][0][3] = G_CCMUX_0; + } + if (rgb_c != G_CCMUX_COMBINED_ALPHA && alpha_a != G_ACMUX_COMBINED && alpha_b != G_ACMUX_COMBINED && + alpha_d != G_ACMUX_COMBINED) { + // First cycle ALPHA not used, so clear it away + c[0][1][0] = c[0][1][1] = c[0][1][2] = c[0][1][3] = G_ACMUX_0; + } + } + + c[i][0][0] = rgb_a; + c[i][0][1] = rgb_b; + c[i][0][2] = rgb_c; + c[i][0][3] = rgb_d; + c[i][1][0] = alpha_a; + c[i][1][1] = alpha_b; + c[i][1][2] = alpha_c; + c[i][1][3] = alpha_d; + } + if (!is_2cyc) { + for (int i = 0; i < 2; i++) { + for (int k = 0; k < 4; k++) { + c[1][i][k] = i == 0 ? G_CCMUX_0 : G_ACMUX_0; + } + } + } + { + uint8_t input_number[32] = { 0 }; + int next_input_number = SHADER_INPUT_1; + for (int i = 0; i < 2 && (i == 0 || is_2cyc); i++) { + for (int j = 0; j < 4; j++) { + uint32_t val = 0; + switch (c[i][0][j]) { + case G_CCMUX_0: + val = SHADER_0; + break; + case G_CCMUX_1: + val = SHADER_1; + break; + case G_CCMUX_TEXEL0: + val = SHADER_TEXEL0; + used_textures[0] = true; + break; + case G_CCMUX_TEXEL1: + val = SHADER_TEXEL1; + used_textures[1] = true; + break; + case G_CCMUX_TEXEL0_ALPHA: + val = SHADER_TEXEL0A; + used_textures[0] = true; + break; + case G_CCMUX_TEXEL1_ALPHA: + val = SHADER_TEXEL1A; + used_textures[1] = true; + break; + case G_CCMUX_NOISE: + val = SHADER_NOISE; + break; + case G_CCMUX_PRIMITIVE: + case G_CCMUX_PRIMITIVE_ALPHA: + case G_CCMUX_PRIM_LOD_FRAC: + case G_CCMUX_SHADE: + case G_CCMUX_SHADE_ALPHA: + case G_CCMUX_ENVIRONMENT: + case G_CCMUX_ENV_ALPHA: + case G_CCMUX_LOD_FRACTION: + if (input_number[c[i][0][j]] == 0) { + shader_input_mapping[0][next_input_number - 1] = c[i][0][j]; + input_number[c[i][0][j]] = next_input_number++; + } + val = input_number[c[i][0][j]]; + break; + case G_CCMUX_COMBINED: + val = SHADER_COMBINED; + break; + default: + sysLogPrintf(LOG_WARNING, "Unsupported ccmux: %d", c[i][0][j]); + break; + } + shader_id0 |= (uint64_t)val << (i * 32 + j * 4); + } + } + } + { + uint8_t input_number[16] = { 0 }; + int next_input_number = SHADER_INPUT_1; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 4; j++) { + uint32_t val = 0; + switch (c[i][1][j]) { + case G_ACMUX_0: + val = SHADER_0; + break; + case G_ACMUX_TEXEL0: + val = SHADER_TEXEL0; + used_textures[0] = true; + break; + case G_ACMUX_TEXEL1: + val = SHADER_TEXEL1; + used_textures[1] = true; + break; + case G_ACMUX_LOD_FRACTION: + // case G_ACMUX_COMBINED: same numerical value + if (j != 2) { + val = SHADER_COMBINED; + break; + } + c[i][1][j] = G_CCMUX_LOD_FRACTION; + [[fallthrough]]; // for G_ACMUX_LOD_FRACTION + case G_ACMUX_1: + // case G_ACMUX_PRIM_LOD_FRAC: same numerical value + if (j != 2) { + val = SHADER_1; + break; + } + [[fallthrough]]; // for G_ACMUX_PRIM_LOD_FRAC + case G_ACMUX_PRIMITIVE: + case G_ACMUX_SHADE: + case G_ACMUX_ENVIRONMENT: + if (input_number[c[i][1][j]] == 0) { + shader_input_mapping[1][next_input_number - 1] = c[i][1][j]; + input_number[c[i][1][j]] = next_input_number++; + } + val = input_number[c[i][1][j]]; + break; + } + shader_id0 |= (uint64_t)val << (i * 32 + 16 + j * 4); + } + } + } + comb->shader_id0 = shader_id0; + comb->shader_id1 = shader_id1; + comb->used_textures[0] = used_textures[0]; + comb->used_textures[1] = used_textures[1]; + // comb->prg = gfx_lookup_or_create_shader_program(shader_id0, shader_id1); + memcpy(comb->shader_input_mapping, shader_input_mapping, sizeof(shader_input_mapping)); +} + +static struct ColorCombiner* gfx_lookup_or_create_color_combiner(const ColorCombinerKey& key) { + if (prev_combiner != color_combiner_pool.end() && prev_combiner->first == key) { + return &prev_combiner->second; + } + + prev_combiner = color_combiner_pool.find(key); + if (prev_combiner != color_combiner_pool.end()) { + return &prev_combiner->second; + } + gfx_flush(); + prev_combiner = color_combiner_pool.insert(std::make_pair(key, ColorCombiner())).first; + gfx_generate_cc(&prev_combiner->second, key); + return &prev_combiner->second; +} + +void gfx_texture_cache_clear() { + gfx_flush(); + for (const auto& entry : gfx_texture_cache.map) { + gfx_texture_cache.free_texture_ids.push_back(entry.second.texture_id); + } + gfx_texture_cache.map.clear(); + gfx_texture_cache.lru.clear(); + rdp.textures_changed[0] = rdp.textures_changed[1] = true; + memset(rendering_state.textures, 0, sizeof(rendering_state.textures)); +} + +static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) { + TextureCacheMap::iterator it = gfx_texture_cache.map.find(key); + TextureCacheNode** n = &rendering_state.textures[i]; + + if (it != gfx_texture_cache.map.end()) { + gfx_rapi->select_texture(i, it->second.texture_id, it->second.linear_filter); + *n = &*it; + gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, + it->second.lru_location); // move to back + return true; + } + + if (gfx_texture_cache.map.size() >= TEXTURE_CACHE_MAX_SIZE) { + // Remove the texture that was least recently used + it = gfx_texture_cache.lru.front().it; + gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id); + gfx_texture_cache.map.erase(it); + gfx_texture_cache.lru.pop_front(); + } + + uint32_t texture_id; + if (!gfx_texture_cache.free_texture_ids.empty()) { + texture_id = gfx_texture_cache.free_texture_ids.back(); + gfx_texture_cache.free_texture_ids.pop_back(); + } else { + texture_id = gfx_rapi->new_texture(); + } + + it = gfx_texture_cache.map.insert(std::make_pair(key, TextureCacheValue())).first; + TextureCacheNode* node = &*it; + node->second.texture_id = texture_id; + node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it }); + + gfx_rapi->select_texture(i, texture_id, false); + gfx_rapi->set_sampler_parameters(i, false, 0, 0, rdp.tex_lod); + *n = node; + return false; +} + +void gfx_texture_cache_delete(const uint8_t* orig_addr) { + gfx_flush(); + + for (int i = 0; i < 2; ++i) { + if (rendering_state.textures[i] && rendering_state.textures[i]->first.texture_addr == orig_addr) { + rdp.textures_changed[i] = true; + rendering_state.textures[i] = nullptr; + } + } + + while (gfx_texture_cache.map.bucket_count() > 0) { + TextureCacheKey key = { orig_addr, { 0 }, 0, 0 }; // bucket index only depends on the address + size_t bucket = gfx_texture_cache.map.bucket(key); + bool again = false; + for (auto it = gfx_texture_cache.map.begin(bucket); it != gfx_texture_cache.map.end(bucket); ++it) { + if (it->first.texture_addr == orig_addr) { + gfx_texture_cache.lru.erase(it->second.lru_location); + gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id); + gfx_texture_cache.map.erase(it->first); + again = true; + break; + } + } + if (!again) { + break; + } + } +} + +void gfx_texture_cache_delete_range(const uint8_t* start, const uint8_t* end) { + gfx_flush(); + + for (int i = 0; i < 2; ++i) { + if (rendering_state.textures[i] + && rendering_state.textures[i]->first.texture_addr >= start + && rendering_state.textures[i]->first.texture_addr < end) { + rdp.textures_changed[i] = true; + rendering_state.textures[i] = nullptr; + } + } + + for (auto it = gfx_texture_cache.map.begin(); it != gfx_texture_cache.map.end(); ) { + if (it->first.texture_addr >= start && it->first.texture_addr < end) { + gfx_texture_cache.lru.erase(it->second.lru_location); + gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id); + it = gfx_texture_cache.map.erase(it); + } else { + ++it; + } + } +} + +static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + // SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + // TODO: this trips in some places with a garbage size in full_image_line_size_bytes + // probably wherever framebuffer effects are used + + uint8_t *dest = tex_upload_buffer; + for (uint32_t i = 0; i < size_bytes / 2; i++, dest += 4) { + const uint16_t col16 = (addr[2 * i] << 8) | addr[2 * i + 1]; + const uint8_t a = col16 & 1; + const uint8_t r = col16 >> 11; + const uint8_t g = (col16 >> 6) & 0x1f; + const uint8_t b = (col16 >> 1) & 0x1f; + dest[0] = SCALE_5_8(r); + dest[1] = SCALE_5_8(g); + dest[2] = SCALE_5_8(b); + dest[3] = a ? 255 : 0; + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; + const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); +} + +static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + uint32_t *dest = (uint32_t *)tex_upload_buffer; + const uint32_t *src = (const uint32_t *)addr; + for (uint32_t i = 0; i < size_bytes; i += 4, ++dest, ++src) { + *dest = PD_BE32(*src); + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; + const uint32_t height = (size_bytes / 2) / rdp.texture_tile[tile].line_size_bytes; + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, addr, width, height); +} + +static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + uint8_t *dest = tex_upload_buffer; + for (uint32_t i = 0; i < size_bytes * 2; i++, dest += 4) { + const uint8_t byte = addr[i / 2]; + const uint8_t part = (byte >> (4 - (i % 2) * 4)) & 0xf; + const uint8_t intensity = part >> 1; + const uint8_t alpha = part & 1; + const uint8_t c = SCALE_3_8(intensity); + dest[0] = c; + dest[1] = c; + dest[2] = c; + dest[3] = alpha ? 255 : 0; + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2; + const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); +} + +static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + uint8_t *dest = tex_upload_buffer; + for (uint32_t i = 0; i < size_bytes; i++, dest += 4) { + const uint8_t intensity = SCALE_4_8(addr[i] >> 4); + const uint8_t alpha = SCALE_4_8(addr[i] & 0xf); + dest[0] = intensity; + dest[1] = intensity; + dest[2] = intensity; + dest[3] = alpha; + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes; + const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); +} + +static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + uint8_t *dest = tex_upload_buffer; + for (uint32_t i = 0; i < size_bytes / 2; i++, dest += 4) { + const uint8_t intensity = addr[2 * i]; + const uint8_t alpha = addr[2 * i + 1]; + dest[0] = intensity; + dest[1] = intensity; + dest[2] = intensity; + dest[3] = alpha; + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; + const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); +} + +static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + uint8_t *dest = tex_upload_buffer; + for (uint32_t i = 0; i < size_bytes * 2; i++, dest += 4) { + const uint8_t byte = addr[i / 2]; + const uint8_t part = (byte >> (4 - (i % 2) * 4)) & 0xf; + const uint8_t intensity = SCALE_4_8(part); + dest[0] = intensity; + dest[1] = intensity; + dest[2] = intensity; + dest[3] = intensity; + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2; + const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); +} + +static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + uint8_t *dest = tex_upload_buffer; + for (uint32_t i = 0; i < size_bytes; i++, dest += 4) { + const uint8_t intensity = addr[i]; + dest[0] = intensity; + dest[1] = intensity; + dest[2] = intensity; + dest[3] = intensity; + } + + const uint32_t width = rdp.texture_tile[tile].line_size_bytes; + const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); +} + +static inline void palette_to_rgba32(const uint16_t palentry, uint8_t *rgba32_buf) { + if (rdp.palette_fmt == G_TT_IA16) { + const uint8_t intensity = (palentry & 0xff); + const uint8_t alpha = palentry >> 8; + rgba32_buf[0] = intensity; + rgba32_buf[1] = intensity; + rgba32_buf[2] = intensity; + rgba32_buf[3] = alpha; + } else { + // assume G_TT_RGBA16 + const uint8_t a = palentry & 1; + const uint8_t r = palentry >> 11; + const uint8_t g = (palentry >> 6) & 0x1f; + const uint8_t b = (palentry >> 1) & 0x1f; + rgba32_buf[0] = SCALE_5_8(r); + rgba32_buf[1] = SCALE_5_8(g); + rgba32_buf[2] = SCALE_5_8(b); + rgba32_buf[3] = a ? 255 : 0; + } +} + +static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + const uint32_t pal_idx = rdp.texture_tile[tile].palette; // 0-15 + const uint16_t* palette = (const uint16_t *)(rdp.palette + pal_idx * 16); // 16 pixel entries, 16 bits each + SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); + + for (uint32_t i = 0; i < size_bytes * 2; i++) { + const uint8_t byte = addr[i / 2]; + const uint8_t idx = (byte >> (4 - (i % 2) * 4)) & 0xf; + palette_to_rgba32(palette[idx], tex_upload_buffer +4 * i); + } + + uint32_t result_line_size = rdp.texture_tile[tile].line_size_bytes; + if (metadata->h_byte_scale != 1) { + result_line_size *= metadata->h_byte_scale; + } + + const uint32_t width = result_line_size * 2; + const uint32_t height = size_bytes / result_line_size; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); +} + +static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; + const uint32_t full_image_line_size_bytes = + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; + + for (uint32_t i = 0, j = 0; i < size_bytes; j += full_image_line_size_bytes - line_size_bytes) { + for (uint32_t k = 0; k < line_size_bytes; i++, k++, j++) { + const uint8_t idx = addr[j]; + palette_to_rgba32(rdp.palette[idx], tex_upload_buffer + 4 * i); + } + } + + uint32_t result_line_size = rdp.texture_tile[tile].line_size_bytes; + if (metadata->h_byte_scale != 1) { + result_line_size *= metadata->h_byte_scale; + } + + const uint32_t width = result_line_size; + const uint32_t height = size_bytes / result_line_size; + + gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps); +} + +static void import_texture(int i, int tile, bool importReplacement) { + LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; + const uint8_t fmt = rdp.texture_tile[tile].fmt; + const uint8_t siz = rdp.texture_tile[tile].siz; + const uint32_t tex_flags = loaded_texture.tex_flags; + const uint8_t palette_index = rdp.texture_tile[tile].palette; + + if ((rdp.tex_lod && tile >= rdp.first_tile_index + rdp.tex_detail) || !loaded_texture.addr) { + // set up miplevel 0; also acts as a catch-all for when .addr is NULL because my texture loader sucks + loaded_texture.addr = rdp.texture_to_load.addr; + loaded_texture.line_size_bytes = rdp.texture_tile[tile].line_size_bytes; + loaded_texture.full_image_line_size_bytes = rdp.texture_tile[tile].line_size_bytes; + loaded_texture.full_size_bytes = loaded_texture.full_image_line_size_bytes * rdp.texture_tile[tile].height; + loaded_texture.size_bytes = loaded_texture.line_size_bytes * rdp.texture_tile[tile].height; + if (siz == G_IM_SIZ_32b) { + // HACK: fixup 32-bit LODed texture height + loaded_texture.size_bytes <<= 1; + loaded_texture.full_size_bytes <<= 1; + } + loaded_texture.orig_size_bytes = loaded_texture.size_bytes; + } + + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* orig_addr = loaded_texture.addr; + SUPPORT_CHECK(orig_addr); + + TextureCacheKey key; + if (fmt == G_IM_FMT_CI) { + key = { orig_addr, { rdp.palette_addrs[0], rdp.palette_addrs[1] }, fmt, siz, palette_index }; + } else { + key = { orig_addr, {}, fmt, siz, palette_index }; + } + + if (gfx_texture_cache_lookup(i, key)) { + return; + } + + if (fmt == G_IM_FMT_RGBA) { + if (siz == G_IM_SIZ_16b) { + import_texture_rgba16(tile, loaded_texture, rdp.tex_lod); + } else if (siz == G_IM_SIZ_32b) { + import_texture_rgba32(tile, loaded_texture, rdp.tex_lod); + } else { + sysFatalError("Bad size for RGBA texture in tile %d: %02x", tile, siz); + } + } else if (fmt == G_IM_FMT_IA) { + if (siz == G_IM_SIZ_4b) { + import_texture_ia4(tile, loaded_texture, rdp.tex_lod); + } else if (siz == G_IM_SIZ_8b) { + import_texture_ia8(tile, loaded_texture, rdp.tex_lod); + } else if (siz == G_IM_SIZ_16b) { + import_texture_ia16(tile, loaded_texture, rdp.tex_lod); + } else { + sysFatalError("Bad size for IA texture in tile %d: %02x", tile, siz); + } + } else if (fmt == G_IM_FMT_CI) { + if (siz == G_IM_SIZ_4b) { + import_texture_ci4(tile, loaded_texture, rdp.tex_lod); + } else if (siz == G_IM_SIZ_8b) { + import_texture_ci8(tile, loaded_texture, rdp.tex_lod); + } else { + sysFatalError("Bad size for CI texture in tile %d: %02x", tile, siz); + } + } else if (fmt == G_IM_FMT_I) { + if (siz == G_IM_SIZ_4b) { + import_texture_i4(tile, loaded_texture, rdp.tex_lod); + } else if (siz == G_IM_SIZ_8b) { + import_texture_i8(tile, loaded_texture, rdp.tex_lod); + } else { + sysFatalError("Bad size for I texture in tile %d: %02x", tile, siz); + } + } else { + sysFatalError("Bad texture format in tile %d: %02x %02x", tile, fmt, siz); + } +} + +static void gfx_normalize_vector(float v[3]) { + float s = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] /= s; + v[1] /= s; + v[2] /= s; +} + +static void gfx_transposed_matrix_mul(float res[3], const float a[3], const float b[4][4]) { + res[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2]; + res[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2]; + res[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2]; +} + +static void calculate_normal_dir(const Light_t* light, float coeffs[3]) { + const float light_dir[3] = { light->dir[0] / 127.f, light->dir[1] / 127.f, light->dir[2] / 127.f }; + + gfx_transposed_matrix_mul(coeffs, light_dir, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1]); + gfx_normalize_vector(coeffs); +} + +static void calculate_normal_dir(const struct NormalColor *vcn, float coeffs[3]) { + const float light_dir[3] = { vcn->x / 127.f, vcn->y / 127.f, vcn->z / 127.f }; + + gfx_transposed_matrix_mul(coeffs, light_dir, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1]); + gfx_normalize_vector(coeffs); +} + +static void gfx_matrix_mul(float res[4][4], const float a[4][4], const float b[4][4]) { + float tmp[4][4]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + tmp[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j] + a[i][3] * b[3][j]; + } + } + memcpy(res, tmp, sizeof(tmp)); +} + +static void gfx_sp_matrix(uint8_t parameters, const int32_t* addr) { + float matrix[4][4]; + +#ifndef GBI_FLOATS + // Original GBI where fixed point matrices are used + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j += 2) { + int32_t int_part = addr[i * 2 + j / 2]; + uint32_t frac_part = addr[8 + i * 2 + j / 2]; + matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f; + matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f; + } + } +#else + // For a modified GBI where fixed point values are replaced with floats + memcpy(matrix, addr, sizeof(matrix)); +#endif + + if (parameters & G_MTX_PROJECTION) { + if (parameters & G_MTX_LOAD) { + memcpy(rsp.P_matrix, matrix, sizeof(matrix)); + } else { + gfx_matrix_mul(rsp.P_matrix, matrix, rsp.P_matrix); + } + } else { // G_MTX_MODELVIEW + if ((parameters & G_MTX_PUSH) && rsp.modelview_matrix_stack_size < 11) { + ++rsp.modelview_matrix_stack_size; + memcpy(rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], + rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 2], sizeof(matrix)); + } + if (parameters & G_MTX_LOAD) { + memcpy(rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], matrix, sizeof(matrix)); + } else { + gfx_matrix_mul(rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], matrix, + rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1]); + } + rsp.lights_changed = 1; + } + gfx_matrix_mul(rsp.MP_matrix, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], rsp.P_matrix); +} + +static void gfx_sp_pop_matrix(uint32_t count) { + while (count--) { + if (rsp.modelview_matrix_stack_size > 0) { + --rsp.modelview_matrix_stack_size; + if (rsp.modelview_matrix_stack_size > 0) { + gfx_matrix_mul(rsp.MP_matrix, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], + rsp.P_matrix); + } + } + } +} + +static float gfx_adjust_x_for_aspect_ratio(float x, float w = 1.f) { + if (fbActive) { + return x; + } else { + return (rsp.aspect_ofs * w + x) * rsp.aspect_scale / gfx_current_dimensions.aspect_ratio; + } +} + +static void gfx_adjust_width_height_for_scale(uint32_t& width, uint32_t& height) { + width = std::round(width * RATIO_Y); + height = std::round(height * RATIO_Y); + if (width == 0) { + width = 1; + } + if (height == 0) { + height = 1; + } +} + +static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx* vertices) { + SUPPORT_CHECK(n_vertices <= MAX_VERTICES); + + for (size_t i = 0; i < n_vertices; i++, dest_index++) { + const Vtx* v = &vertices[i]; + struct LoadedVertex* d = &rsp.loaded_vertices[dest_index]; + + /* GE's Vtx layout (include/PR/gbi.h): ob[] position, tc[] texture + * coords, and the last 4 bytes are either RGBA (Vtx_t.cn) or a + * normal + alpha (Vtx_tn.n/a). Unlike PD there is no G_COL colour + * table: colours/normals live in the vertex itself. */ + float x = v->v.ob[0] * rsp.MP_matrix[0][0] + v->v.ob[1] * rsp.MP_matrix[1][0] + v->v.ob[2] * rsp.MP_matrix[2][0] + rsp.MP_matrix[3][0]; + float y = v->v.ob[0] * rsp.MP_matrix[0][1] + v->v.ob[1] * rsp.MP_matrix[1][1] + v->v.ob[2] * rsp.MP_matrix[2][1] + rsp.MP_matrix[3][1]; + float z = v->v.ob[0] * rsp.MP_matrix[0][2] + v->v.ob[1] * rsp.MP_matrix[1][2] + v->v.ob[2] * rsp.MP_matrix[2][2] + rsp.MP_matrix[3][2]; + float w = v->v.ob[0] * rsp.MP_matrix[0][3] + v->v.ob[1] * rsp.MP_matrix[1][3] + v->v.ob[2] * rsp.MP_matrix[2][3] + rsp.MP_matrix[3][3]; + + x = gfx_adjust_x_for_aspect_ratio(x, w); + + short U = v->v.tc[0] * rsp.texture_scaling_factor.s >> 16; + short V = v->v.tc[1] * rsp.texture_scaling_factor.t >> 16; + + struct NormalColor vcn_data; + if (rsp.geometry_mode & G_LIGHTING) { + /* Lit vertices carry their normal in the last 3 bytes. */ + vcn_data.x = (int8_t)v->n.n[0]; + vcn_data.y = (int8_t)v->n.n[1]; + vcn_data.z = (int8_t)v->n.n[2]; + vcn_data.a = v->n.a; + } else { + vcn_data.r = v->v.cn[0]; + vcn_data.g = v->v.cn[1]; + vcn_data.b = v->v.cn[2]; + vcn_data.a = v->v.cn[3]; + } + const struct NormalColor *vcn = &vcn_data; + + if (rsp.geometry_mode & G_LIGHTING) { + if (rsp.lights_changed) { + for (int i = 0; i < rsp.current_num_lights - 1; i++) { + calculate_normal_dir(&rsp.current_lights[i], rsp.current_lights_coeffs[i]); + } + if (rsp.lookat_enabled) { + calculate_normal_dir(&rsp.lookat[0], rsp.current_lookat_coeffs[0]); + calculate_normal_dir(&rsp.lookat[1], rsp.current_lookat_coeffs[1]); + } + rsp.lights_changed = false; + } + + int r = rsp.current_lights[rsp.current_num_lights - 1].col[0]; + int g = rsp.current_lights[rsp.current_num_lights - 1].col[1]; + int b = rsp.current_lights[rsp.current_num_lights - 1].col[2]; + + for (int i = 0; i < rsp.current_num_lights - 1; i++) { + float intensity = 0; + intensity += vcn->x * rsp.current_lights_coeffs[i][0]; + intensity += vcn->y * rsp.current_lights_coeffs[i][1]; + intensity += vcn->z * rsp.current_lights_coeffs[i][2]; + intensity /= 127.0f; + if (intensity > 0.0f) { + r += intensity * rsp.current_lights[i].col[0]; + g += intensity * rsp.current_lights[i].col[1]; + b += intensity * rsp.current_lights[i].col[2]; + } + } + + d->color.r = r > 255 ? 255 : r; + d->color.g = g > 255 ? 255 : g; + d->color.b = b > 255 ? 255 : b; + + if (rsp.geometry_mode & G_TEXTURE_GEN) { + float dotx = 0, doty = 0; + if (rsp.lookat_enabled) { + dotx += vcn->x * rsp.current_lookat_coeffs[0][0]; + dotx += vcn->y * rsp.current_lookat_coeffs[0][1]; + dotx += vcn->z * rsp.current_lookat_coeffs[0][2]; + doty += vcn->x * rsp.current_lookat_coeffs[1][0]; + doty += vcn->y * rsp.current_lookat_coeffs[1][1]; + doty += vcn->z * rsp.current_lookat_coeffs[1][2]; + dotx /= 127.0f; + doty /= 127.0f; + } else { + float tvcn[3]; + calculate_normal_dir(vcn, tvcn); + dotx = tvcn[0]; + doty = tvcn[1]; + } + + dotx = clampf(dotx, -1.0f, 1.0f); + doty = clampf(doty, -1.0f, 1.0f); + + if (rsp.geometry_mode & G_TEXTURE_GEN_LINEAR) { + // Not sure exactly what formula we should use to get accurate values + /*dotx = (2.906921f * dotx * dotx + 1.36114f) * dotx; + doty = (2.906921f * doty * doty + 1.36114f) * doty; + dotx = (dotx + 1.0f) / 4.0f; + doty = (doty + 1.0f) / 4.0f;*/ + dotx = acosf(-dotx) /* M_PI */ / 4.0f; + doty = acosf(-doty) /* M_PI */ / 4.0f; + } else { + dotx = (dotx + 1.0f) / 4.0f; + doty = (doty + 1.0f) / 4.0f; + } + + U = (int32_t)(dotx * rsp.texture_scaling_factor.s); + V = (int32_t)(doty * rsp.texture_scaling_factor.t); + } + } else { + d->color.r = vcn->r; + d->color.g = vcn->g; + d->color.b = vcn->b; + } + + d->u = U; + d->v = V; + + // trivial clip rejection + d->clip_rej = 0; + if (x < -w) { + d->clip_rej |= 1; // CLIP_LEFT + } + if (x > w) { + d->clip_rej |= 2; // CLIP_RIGHT + } + if (y < -w) { + d->clip_rej |= 4; // CLIP_BOTTOM + } + if (y > w) { + d->clip_rej |= 8; // CLIP_TOP + } + // if (z < -w) d->clip_rej |= 16; // CLIP_NEAR + if (z > w) { + d->clip_rej |= 32; // CLIP_FAR + } + + d->x = x; + d->y = y; + d->z = z; + d->w = w; + + if (rsp.geometry_mode & G_FOG) { + if (fabsf(w) < 0.001f) { + // To avoid division by zero + w = 0.001f; + } + + float winv = 1.0f / w; + if (winv < 0.0f) { + winv = std::numeric_limits::max(); + } + + float fog_z = z * winv * rsp.fog_mul + rsp.fog_offset; + d->fog = clampf(fog_z, 0.f, 255.f); + } else { + d->fog = rdp.fog_color.a; + } + + d->color.a = vcn->a; // can be required for SHADE_ALPHA even if fog is enabled + } +} + +static void gfx_sp_modify_vertex(uint16_t vtx_idx, uint8_t where, uint32_t val) { + SUPPORT_CHECK(where == G_MWO_POINT_ST); + + int16_t s = (int16_t)(val >> 16); + int16_t t = (int16_t)val; + + struct LoadedVertex* v = &rsp.loaded_vertices[vtx_idx]; + v->u = s; + v->v = t; +} + +static inline int gfx_lod_tile_offset(const int i) { + if (gfx_detail_textures_enabled) + return ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i); + return (rdp.tex_lod ? rdp.tex_detail : i); +} + +static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bool is_rect) { + struct LoadedVertex* v1 = &rsp.loaded_vertices[vtx1_idx]; + struct LoadedVertex* v2 = &rsp.loaded_vertices[vtx2_idx]; + struct LoadedVertex* v3 = &rsp.loaded_vertices[vtx3_idx]; + struct LoadedVertex* v_arr[3] = { v1, v2, v3 }; + + if ((rsp.extra_geometry_mode & G_NO_CLIPPING_EXT) == 0) { + if (v1->clip_rej & v2->clip_rej & v3->clip_rej) { + // The whole triangle lies outside the visible area + return; + } + } + + if ((rsp.geometry_mode & G_CULL_BOTH) != 0) { + float dx1 = v1->x / (v1->w) - v2->x / (v2->w); + float dy1 = v1->y / (v1->w) - v2->y / (v2->w); + float dx2 = v3->x / (v3->w) - v2->x / (v2->w); + float dy2 = v3->y / (v3->w) - v2->y / (v2->w); + float cross = dx1 * dy2 - dy1 * dx2; + + if ((v1->w < 0) ^ (v2->w < 0) ^ (v3->w < 0)) { + // If one vertex lies behind the eye, negating cross will give the correct result. + // If all vertices lie behind the eye, the triangle will be rejected anyway. + cross = -cross; + } + + // If inverted culling is requested, negate the cross + // if ((rsp.extra_geometry_mode & G_EX_INVERT_CULLING) == 1) { + // cross = -cross; + // } + + switch (rsp.geometry_mode & G_CULL_BOTH) { + case G_CULL_FRONT: + if (cross <= 0) { + return; + } + break; + case G_CULL_BACK: + if (cross >= 0) { + return; + } + break; + case G_CULL_BOTH: + // Why is this even an option? + return; + } + } + + bool depth_test = ((rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER || (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM) && + ((rdp.other_mode_h & G_CYC_1CYCLE) == G_CYC_1CYCLE || (rdp.other_mode_h & G_CYC_2CYCLE) == G_CYC_2CYCLE); + bool depth_update = (rdp.other_mode_l & Z_UPD) == Z_UPD; + bool depth_compare = (rdp.other_mode_l & Z_CMP) == Z_CMP; + bool depth_source_prim = (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM /* && gDP.primDepth.z == 1.0f */; + uint16_t zmode = rdp.other_mode_l & ZMODE_DEC; + uint8_t depth_mode = (depth_test ? 1 : 0) | (depth_update ? 2 : 0) | (depth_compare ? 4 : 0) | (depth_source_prim ? 8 : 0) | (zmode >> 6); + + if (depth_mode != rendering_state.depth_mode) { + gfx_flush(); + gfx_rapi->set_depth_mode(depth_test, depth_update, depth_compare, depth_source_prim, zmode); + rendering_state.depth_mode = depth_mode; + } + + if (rdp.viewport_or_scissor_changed) { + if (memcmp(&rdp.viewport, &rendering_state.viewport, sizeof(rdp.viewport)) != 0) { + gfx_flush(); + gfx_rapi->set_viewport(rdp.viewport.x, rdp.viewport.y, rdp.viewport.width, rdp.viewport.height); + rendering_state.viewport = rdp.viewport; + } + if (memcmp(&rdp.scissor, &rendering_state.scissor, sizeof(rdp.scissor)) != 0) { + gfx_flush(); + gfx_rapi->set_scissor(rdp.scissor.x, rdp.scissor.y, rdp.scissor.width, rdp.scissor.height); + rendering_state.scissor = rdp.scissor; + } + rdp.viewport_or_scissor_changed = false; + } + + uint64_t cc_options = 0; + bool use_alpha = + (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20) && (rdp.other_mode_l & (3 << 16)) == (G_BL_1MA << 16); + const bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG); + const bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA; + const bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER; + const bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE; + const bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD; + const bool invisible = (rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20); + const bool use_grayscale = rdp.grayscale; + const bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0; + const bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT; + + if (texture_edge) { + use_alpha = true; + } + + if (use_alpha) { + cc_options |= (uint64_t)SHADER_OPT_ALPHA; + } + if (use_fog) { + cc_options |= (uint64_t)SHADER_OPT_FOG; + } + if (texture_edge) { + cc_options |= (uint64_t)SHADER_OPT_TEXTURE_EDGE; + } + if (use_noise) { + cc_options |= (uint64_t)SHADER_OPT_NOISE; + } + if (use_2cyc) { + cc_options |= (uint64_t)SHADER_OPT_2CYC; + } + if (alpha_threshold) { + cc_options |= (uint64_t)SHADER_OPT_ALPHA_THRESHOLD; + } + if (invisible) { + cc_options |= (uint64_t)SHADER_OPT_INVISIBLE; + } + if (use_grayscale) { + cc_options |= (uint64_t)SHADER_OPT_GRAYSCALE; + } + if (use_blur) { + cc_options |= (uint64_t)SHADER_OPT_BLUR; + } + + // If we are not using alpha, clear the alpha components of the combiner as they have no effect + if (!use_alpha) { + cc_options &= ~((0xfff << 16) | ((uint64_t)0xfff << 44)); + } + + ColorCombinerKey key; + key.combine_mode = rdp.combine_mode; + key.options = cc_options; + + ColorCombiner* comb = gfx_lookup_or_create_color_combiner(key); + + uint32_t tm = 0; + uint32_t tex_width[2], tex_height[2], tex_width2[2], tex_height2[2]; + + for (int i = 0; i < 2; i++) { + // TODO: fix this; for now just ignore smaller mips + const uint32_t tile = rdp.first_tile_index + gfx_lod_tile_offset(i); + if (comb->used_textures[i]) { + if (rdp.textures_changed[i]) { + gfx_flush(); + import_texture(i, tile, false); + rdp.textures_changed[i] = false; + } + + uint8_t cms = rdp.texture_tile[tile].cms; + uint8_t cmt = rdp.texture_tile[tile].cmt; + + uint32_t tex_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem].orig_size_bytes; + uint32_t line_size = rdp.texture_tile[tile].line_size_bytes; + + if (line_size == 0) { + line_size = 1; + } + + tex_height[i] = tex_size_bytes / line_size; + switch (rdp.texture_tile[tile].siz) { + case G_IM_SIZ_4b: + line_size <<= 1; + break; + case G_IM_SIZ_8b: + break; + case G_IM_SIZ_16b: + line_size /= G_IM_SIZ_16b_LINE_BYTES; + break; + case G_IM_SIZ_32b: + line_size /= G_IM_SIZ_32b_LINE_BYTES; // this is 2! + tex_height[i] /= 2; + break; + } + tex_width[i] = line_size; + + tex_width2[i] = (rdp.texture_tile[tile].lrs - rdp.texture_tile[tile].uls + 4) / 4; + tex_height2[i] = (rdp.texture_tile[tile].lrt - rdp.texture_tile[tile].ult + 4) / 4; + + uint32_t tex_width1 = tex_width[i] << (cms & G_TX_MIRROR); + uint32_t tex_height1 = tex_height[i] << (cmt & G_TX_MIRROR); + + if ((cms & G_TX_CLAMP) && ((cms & G_TX_MIRROR) || tex_width1 != tex_width2[i])) { + tm |= 1 << 2 * i; + cms &= ~G_TX_CLAMP; + } + if ((cmt & G_TX_CLAMP) && ((cmt & G_TX_MIRROR) || tex_height1 != tex_height2[i])) { + tm |= 1 << (2 * i + 1); + cmt &= ~G_TX_CLAMP; + } + + if (rendering_state.textures[i]) { + bool linear_filter = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) != G_TF_POINT; + if (linear_filter != rendering_state.textures[i]->second.linear_filter || + cms != rendering_state.textures[i]->second.cms || cmt != rendering_state.textures[i]->second.cmt) { + gfx_flush(); + gfx_rapi->set_sampler_parameters(i, linear_filter, cms, cmt, rdp.tex_lod); + rendering_state.textures[i]->second.linear_filter = linear_filter; + rendering_state.textures[i]->second.cms = cms; + rendering_state.textures[i]->second.cmt = cmt; + } + } + } + } + + struct ShaderProgram* prg = comb->prg[tm]; + if (prg == NULL) { + comb->prg[tm] = prg = + gfx_lookup_or_create_shader_program(comb->shader_id0, comb->shader_id1 | (tm * SHADER_OPT_TEXEL0_CLAMP_S)); + } + if (prg != rendering_state.shader_program) { + gfx_flush(); + gfx_rapi->unload_shader(rendering_state.shader_program); + gfx_rapi->load_shader(prg); + rendering_state.shader_program = prg; + } + if (use_alpha != rendering_state.alpha_blend || use_modulate != rendering_state.modulate) { + gfx_flush(); + gfx_rapi->set_use_alpha(use_alpha, use_modulate); + rendering_state.alpha_blend = use_alpha; + rendering_state.modulate = use_modulate; + } + uint8_t num_inputs; + bool used_textures[2]; + + gfx_rapi->shader_get_info(prg, &num_inputs, used_textures); + + struct GfxClipParameters clip_parameters = gfx_rapi->get_clip_parameters(); + + for (int i = 0; i < 3; i++) { + float z = v_arr[i]->z, w = v_arr[i]->w; + if (clip_parameters.z_is_from_0_to_1) { + z = (z + w) / 2.0f; + } + + buf_vbo[buf_vbo_len++] = v_arr[i]->x; + buf_vbo[buf_vbo_len++] = clip_parameters.invert_y ? -v_arr[i]->y : v_arr[i]->y; + buf_vbo[buf_vbo_len++] = z; + buf_vbo[buf_vbo_len++] = w; + + for (int t = 0; t < 2; t++) { + if (!used_textures[t]) { + continue; + } + + // TODO: fix this; for now just ignore smaller mips + const uint32_t tile = gfx_lod_tile_offset(t); + + float u = v_arr[i]->u / 32.0f; + float v = v_arr[i]->v / 32.0f; + + int shifts = rdp.texture_tile[rdp.first_tile_index + tile].shifts; + int shiftt = rdp.texture_tile[rdp.first_tile_index + tile].shiftt; + if (shifts != 0) { + if (shifts <= 10) { + u /= 1 << shifts; + } else { + u *= 1 << (16 - shifts); + } + } + if (shiftt != 0) { + if (shiftt <= 10) { + v /= 1 << shiftt; + } else { + v *= 1 << (16 - shiftt); + } + } + + u -= rdp.texture_tile[rdp.first_tile_index + tile].uls / 4.0f; + v -= rdp.texture_tile[rdp.first_tile_index + tile].ult / 4.0f; + + if (!is_rect) { + if (!(rdp.other_mode_h & G_TP_PERSP)) { + u *= 0.5f; + v *= 0.5f; + } + + if ((rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) != G_TF_POINT) { + // Linear filter adds 0.5f to the coordinates + u += 0.5f; + v += 0.5f; + } + } + + buf_vbo[buf_vbo_len++] = u / tex_width[t]; + buf_vbo[buf_vbo_len++] = v / tex_height[t]; + + bool clampS = tm & (1 << 2 * t); + bool clampT = tm & (1 << (2 * t + 1)); + + if (clampS) { + buf_vbo[buf_vbo_len++] = (tex_width2[t] - 0.5f) / tex_width[t]; + } + if (clampT) { + buf_vbo[buf_vbo_len++] = (tex_height2[t] - 0.5f) / tex_height[t]; + } + } + + if (use_fog) { + buf_vbo[buf_vbo_len++] = rdp.fog_color.r / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.fog_color.g / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.fog_color.b / 255.0f; + buf_vbo[buf_vbo_len++] = v_arr[i]->fog / 255.0f; // fog factor + } + + if (use_grayscale) { + buf_vbo[buf_vbo_len++] = rdp.grayscale_color.r / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.grayscale_color.g / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.grayscale_color.b / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.grayscale_color.a / 255.0f; // lerp interpolation factor (not alpha) + } + + for (int j = 0; j < num_inputs; j++) { + struct RGBA* color = 0; + struct RGBA tmp = { 0 }; + for (int k = 0; k < 1 + (use_alpha ? 1 : 0); k++) { + switch (comb->shader_input_mapping[k][j]) { + // Note: CCMUX constants and ACMUX constants used here have same value, which is why this works + // (except LOD fraction). + case G_CCMUX_PRIMITIVE: + color = &rdp.prim_color; + break; + case G_CCMUX_SHADE: + color = &v_arr[i]->color; + break; + case G_CCMUX_SHADE_ALPHA: + tmp.r = tmp.g = tmp.b = v_arr[i]->color.a; + color = &tmp; + break; + case G_CCMUX_ENVIRONMENT: + color = &rdp.env_color; + break; + case G_CCMUX_PRIMITIVE_ALPHA: { + tmp.r = tmp.g = tmp.b = rdp.prim_color.a; + color = &tmp; + break; + } + case G_CCMUX_ENV_ALPHA: { + tmp.r = tmp.g = tmp.b = rdp.env_color.a; + color = &tmp; + break; + } + case G_CCMUX_PRIM_LOD_FRAC: { + tmp.r = tmp.g = tmp.b = rdp.prim_lod_fraction; + color = &tmp; + break; + } + case G_CCMUX_LOD_FRACTION: { + if (rdp.other_mode_h & G_TL_LOD) { + // HACK: very roughly eyeballed based on the carpets in Defection + // this is actually supposed to be calculated per pixel + const float distance_frac = std::max(0.f, std::min(w / 1024.f, 1.f)); + tmp.r = tmp.g = tmp.b = tmp.a = (0.7f + distance_frac * 0.3f) * 255.f; + } else { + tmp.r = tmp.g = tmp.b = tmp.a = 255; + } + color = &tmp; + break; + } + case G_ACMUX_PRIM_LOD_FRAC: + tmp.a = rdp.prim_lod_fraction; + color = &tmp; + break; + default: + memset(&tmp, 0, sizeof(tmp)); + color = &tmp; + break; + } + if (k == 0) { + buf_vbo[buf_vbo_len++] = color->r / 255.0f; + buf_vbo[buf_vbo_len++] = color->g / 255.0f; + buf_vbo[buf_vbo_len++] = color->b / 255.0f; + } else { + buf_vbo[buf_vbo_len++] = color->a / 255.0f; + } + } + } + } + + if (++buf_vbo_num_tris == MAX_BUFFERED) { + gfx_flush(); + } +} + +static inline void gfx_sp_tri4(Gfx *cmd) { + // the game issues gSPTri2 for quads, which uses G_TRI4 with 2 empty triangles + uint8_t x = C1(0, 4); + uint8_t y = C1(4, 4); + uint8_t z = C0(0, 4); + + if(x || y || z) { + gfx_sp_tri1(x, y, z, false); + } + + x = C1(8, 4); + y = C1(12, 4); + z = C0(4, 4); + + if (x || y || z) { + gfx_sp_tri1(x, y, z, false); + } + + x = C1(16, 4); + y = C1(20, 4); + z = C0(8, 4); + + if (x || y || z) { + gfx_sp_tri1(x, y, z, false); + } + + x = C1(24, 4); + y = C1(28, 4); + z = C0(12, 4); + + if (x || y || z) { + gfx_sp_tri1(x, y, z, false); + } +} + +static void gfx_sp_geometry_mode(uint32_t clear, uint32_t set) { + rsp.geometry_mode &= ~clear; + rsp.geometry_mode |= set; +} + +static inline void gfx_update_aspect_mode(void) { + const uint32_t side = rsp.aspect_mode & G_ASPECT_CENTER_EXT; + + rsp.aspect_scale = rsp.aspect_mode ? gfx_current_native_aspect : gfx_current_window_dimensions.aspect_ratio; + + if (side == G_ASPECT_LEFT_EXT) { + rsp.aspect_ofs = 1.f - gfx_current_dimensions.aspect_ratio / gfx_current_native_aspect; + } else if (side == G_ASPECT_RIGHT_EXT) { + rsp.aspect_ofs = gfx_current_dimensions.aspect_ratio / gfx_current_native_aspect - 1.f; + } else { + rsp.aspect_ofs = 0.f; + } + + if (side && (rsp.aspect_mode & G_ASPECT_WIDE_EXT)) { + constexpr float c = 16.f / 9.f; + if (gfx_current_dimensions.aspect_ratio > c) { + rsp.aspect_ofs *= c / gfx_current_dimensions.aspect_ratio; + } + } +} + +static void gfx_sp_extra_geometry_mode(uint32_t clear, uint32_t set) { + rsp.extra_geometry_mode &= ~clear; + rsp.extra_geometry_mode |= set; + rsp.aspect_mode = (rsp.extra_geometry_mode & G_ASPECT_MODE_EXT); + gfx_update_aspect_mode(); +} + +static void gfx_adjust_viewport_or_scissor(XYWidthHeight* area, bool preserve_aspect = false) { + // HACK: assume all target framebuffers have the same aspect + // Use floor/ceil to ensure scissor fully contains the logical region + // and prevents sub-pixel gaps at viewport edges + float x1 = area->x * RATIO_X; + float y1 = (SCREEN_HEIGHT - area->y) * RATIO_Y; + float x2 = (area->x + area->width) * RATIO_X; + float y2 = (SCREEN_HEIGHT - area->y + area->height) * RATIO_Y; + + area->x = std::floor(x1); + area->y = std::floor(y1); + area->width = std::ceil(x2) - area->x; + area->height = std::ceil(y2) - area->y; + + if (preserve_aspect) { + // preserve native aspect ratio + const float ratio = gfx_current_native_aspect / gfx_current_dimensions.aspect_ratio; + const float midx = gfx_current_dimensions.width * 0.5f; + area->x = midx + (area->x - midx) * ratio; + area->x += rsp.aspect_ofs * gfx_current_dimensions.width * 0.5f; + area->width *= ratio; + } + + if (!game_renders_to_framebuffer || + (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && + gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) { + area->x += gfx_current_game_window_viewport.x; + area->y += gfx_current_window_dimensions.height - + (gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height); + } +} + +static void gfx_calc_and_set_viewport(const Vp_t* viewport) { + // 2 bits fraction + float width = 2.0f * viewport->vscale[0] / 4.0f; + float height = 2.0f * viewport->vscale[1] / 4.0f; + float x = (viewport->vtrans[0] / 4.0f) - width / 2.0f; + float y = ((viewport->vtrans[1] / 4.0f) + height / 2.0f); + + rdp.viewport.x = x; + rdp.viewport.y = y; + rdp.viewport.width = width; + rdp.viewport.height = height; + + gfx_adjust_viewport_or_scissor(&rdp.viewport); + + rdp.viewport_or_scissor_changed = true; +} + +static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) { + switch (index) { + case G_MV_VIEWPORT: + gfx_calc_and_set_viewport((const Vp_t*)data); + break; + case G_MV_LOOKATY: + case G_MV_LOOKATX: + // I think this is only really used for guLookAtReflect + index = !((index - G_MV_LOOKATY) / 2); + rsp.lookat[index] = ((const Light *)data)->l; + rsp.lookat_enabled = (index == 0) || (rsp.lookat[1].dir[0] || rsp.lookat[1].dir[1]); + rsp.lights_changed = true; + break; + case G_MV_L0: + case G_MV_L1: + case G_MV_L2: + // NOTE: reads out of bounds if it is an ambient light + memcpy(rsp.current_lights + (index - G_MV_L0) / 2, data, sizeof(Light_t)); + break; + } +} + +static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) { + switch (index) { + case G_MW_NUMLIGHT: + // Ambient light is included + // The 31th bit is a flag that lights should be recalculated + rsp.current_num_lights = (data - 0x80000000U) / 32; + rsp.lights_changed = 1; + break; + case G_MW_FOG: + rsp.fog_mul = (int16_t)(data >> 16); + rsp.fog_offset = (int16_t)data; + break; + case G_MW_SEGMENT: + // GE registers segment bases as OS_K0_TO_PHYSICAL(ptr); store the + // live host pointer so seg_addr() resolves seg+offset correctly. + segmentPointers[(offset >> 2) & 0xff] = (data < 0x800000) ? (data + 0x80000000) : data; + break; + } +} + +static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on) { + rsp.texture_scaling_factor.s = sc; + rsp.texture_scaling_factor.t = tc; + rdp.tex_max_lod = level; + if (rdp.first_tile_index != tile) { + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + rdp.first_tile_index = tile; + } +} + +static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry) { + float x = ulx / 4.0f; + float y = lry / 4.0f; + float width = (lrx - ulx) / 4.0f; + float height = (lry - uly) / 4.0f; + + rdp.scissor.x = x; + rdp.scissor.y = y; + rdp.scissor.width = width; + rdp.scissor.height = height; + + gfx_adjust_viewport_or_scissor(&rdp.scissor, rsp.aspect_mode != 0); + + rdp.viewport_or_scissor_changed = true; +} + +static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, uint32_t tex_flags, const void* addr) { + rdp.texture_to_load.addr = (const uint8_t*)addr; + rdp.texture_to_load.siz = size; + rdp.texture_to_load.width = width; + rdp.texture_to_load.tex_flags = tex_flags; +} + +static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette, + uint32_t cmt, uint32_t maskt, uint32_t shiftt, uint32_t cms, uint32_t masks, + uint32_t shifts) { + // OTRTODO: + // SUPPORT_CHECK(tmem == 0 || tmem == 256); + static uint32_t max_tmem = 0; + if (cms == G_TX_WRAP && masks == G_TX_NOMASK) { + cms = G_TX_CLAMP; + } + if (cmt == G_TX_WRAP && maskt == G_TX_NOMASK) { + cmt = G_TX_CLAMP; + } + + if (fmt == G_IM_FMT_RGBA && siz < G_IM_SIZ_16b) { + // HACK: sometimes the game will submit G_IM_FMT_RGBA, G_IM_SIZ_8b/4b, intending it to read as CI8/CI4 with RGBA16 palette + fmt = G_IM_FMT_CI; + } else if (fmt == G_IM_FMT_IA && siz == G_IM_SIZ_32b) { + // HACK: ... and sometimes it submits this, apparently intending it to be I8 + fmt = G_IM_FMT_I; + siz = G_IM_SIZ_8b; + } + + rdp.texture_tile[tile].palette = palette; // palette should set upper 4 bits of color index in 4b mode + rdp.texture_tile[tile].fmt = fmt; + rdp.texture_tile[tile].siz = siz; + rdp.texture_tile[tile].cms = cms; + rdp.texture_tile[tile].cmt = cmt; + rdp.texture_tile[tile].shifts = shifts; + rdp.texture_tile[tile].shiftt = shiftt; + rdp.texture_tile[tile].line_size_bytes = line * 8; + rdp.texture_tile[tile].tmem = tmem; + + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; +} + +static void gfx_dp_set_tile_size(uint8_t tile, uint16_t uls, uint16_t ult, uint16_t lrs, uint16_t lrt) { + rdp.texture_tile[tile].uls = uls; + rdp.texture_tile[tile].ult = ult; + rdp.texture_tile[tile].lrs = lrs; + rdp.texture_tile[tile].lrt = lrt; + rdp.texture_tile[tile].width = (lrs - uls + 4) / 4; + rdp.texture_tile[tile].height = (lrt - ult + 4) / 4; + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; +} + +static void gfx_dp_load_tlut(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) { + // SUPPORT_CHECK(tile == G_TX_LOADTILE); + SUPPORT_CHECK(rdp.texture_to_load.siz == G_IM_SIZ_16b); + SUPPORT_CHECK(rdp.texture_tile[tile].tmem >= 256); + + rdp.texture_tile[tile].uls = uls; + rdp.texture_tile[tile].ult = ult; + rdp.texture_tile[tile].lrs = lrs; + rdp.texture_tile[tile].lrt = lrt; + + const uint32_t width = (lrs - uls + 1); + const uint32_t height = (lrt - ult + 1); + const uint32_t pitch = rdp.texture_to_load.width + 1; + const uint32_t count = width * height; + const uint16_t *base = (const uint16_t *)rdp.texture_to_load.addr + pitch * ult + uls; + + if (rdp.texture_tile[tile].tmem == 256) { + rdp.palette_addrs[0] = (const uint8_t *)base; + if (count >= 256) { + rdp.palette_addrs[1] = (const uint8_t *)(base + 128); + } + } else { + rdp.palette_addrs[1] = (const uint8_t *)base; + } + + const uint32_t palofs = rdp.texture_tile[tile].tmem - 256; + SUPPORT_CHECK(palofs + count <= 256); + + const uint16_t *src = base; + uint16_t *dst = rdp.palette + palofs; + for (uint32_t i = 0; i < count; ++i) { + *dst++ = PD_BE16(*src++); + } + + rdp.textures_changed[0] = rdp.textures_changed[1] = true; +} + +static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t dxt) { + // SUPPORT_CHECK(tile == G_TX_LOADTILE); + SUPPORT_CHECK(uls == 0); + SUPPORT_CHECK(ult == 0); + + // The lrs field rather seems to be number of pixels to load + uint32_t orig_size_bytes = (lrs + 1) << rdp.texture_to_load.siz >> 1; + uint32_t size_bytes = orig_size_bytes; + if (rdp.texture_to_load.raw_tex_metadata.h_byte_scale != 1 || + rdp.texture_to_load.raw_tex_metadata.v_pixel_scale != 1) { + size_bytes *= rdp.texture_to_load.raw_tex_metadata.h_byte_scale; + size_bytes *= rdp.texture_to_load.raw_tex_metadata.v_pixel_scale; + } + + LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; + loaded_texture.orig_size_bytes = orig_size_bytes; + loaded_texture.size_bytes = size_bytes; + loaded_texture.full_size_bytes = size_bytes; + loaded_texture.line_size_bytes = size_bytes; + loaded_texture.full_image_line_size_bytes = size_bytes; + loaded_texture.tex_flags = rdp.texture_to_load.tex_flags; + loaded_texture.raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata; + loaded_texture.addr = rdp.texture_to_load.addr; + + rdp.textures_changed[0] = rdp.textures_changed[1] = true; +} + +static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) { + SUPPORT_CHECK(tile == G_TX_LOADTILE); + + uint32_t offset_x = uls >> G_TEXTURE_IMAGE_FRAC; + uint32_t offset_y = ult >> G_TEXTURE_IMAGE_FRAC; + uint32_t tile_width = ((lrs - uls) >> G_TEXTURE_IMAGE_FRAC) + 1; + uint32_t tile_height = ((lrt - ult) >> G_TEXTURE_IMAGE_FRAC) + 1; + uint32_t full_image_width = rdp.texture_to_load.width + 1; + + uint32_t offset_x_in_bytes = offset_x << rdp.texture_to_load.siz >> 1; + uint32_t tile_line_size_bytes = tile_width << rdp.texture_to_load.siz >> 1; + uint32_t full_image_line_size_bytes = full_image_width << rdp.texture_to_load.siz >> 1; + + uint32_t orig_size_bytes = tile_line_size_bytes * tile_height; + uint32_t size_bytes = orig_size_bytes; + uint32_t start_offset_bytes = full_image_line_size_bytes * offset_y + offset_x_in_bytes; + + float h_byte_scale = rdp.texture_to_load.raw_tex_metadata.h_byte_scale; + float v_pixel_scale = rdp.texture_to_load.raw_tex_metadata.v_pixel_scale; + + if (h_byte_scale != 1 || v_pixel_scale != 1) { + start_offset_bytes = h_byte_scale * (v_pixel_scale * offset_y * full_image_line_size_bytes + offset_x_in_bytes); + size_bytes *= h_byte_scale * v_pixel_scale; + full_image_line_size_bytes *= h_byte_scale; + tile_line_size_bytes *= h_byte_scale; + } + + LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; + loaded_texture.orig_size_bytes = orig_size_bytes; + loaded_texture.size_bytes = size_bytes; + loaded_texture.full_size_bytes = full_image_line_size_bytes * tile_height; + loaded_texture.full_image_line_size_bytes = full_image_line_size_bytes; + loaded_texture.line_size_bytes = tile_line_size_bytes; + loaded_texture.tex_flags = rdp.texture_to_load.tex_flags; + loaded_texture.raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata; + loaded_texture.addr = rdp.texture_to_load.addr + start_offset_bytes; + + rdp.texture_tile[tile].uls = uls; + rdp.texture_tile[tile].ult = ult; + rdp.texture_tile[tile].lrs = lrs; + rdp.texture_tile[tile].lrt = lrt; + rdp.texture_tile[tile].width = ((lrs - uls) >> G_TEXTURE_IMAGE_FRAC) + 1; + rdp.texture_tile[tile].height = ((lrt - ult) >> G_TEXTURE_IMAGE_FRAC) + 1; + + rdp.textures_changed[0] = rdp.textures_changed[1] = true; +} + +static void gfx_dp_set_combine_mode(uint32_t rgb, uint32_t alpha, uint32_t rgb_cyc2, uint32_t alpha_cyc2) { + rdp.combine_mode = rgb | (alpha << 16) | ((uint64_t)rgb_cyc2 << 28) | ((uint64_t)alpha_cyc2 << 44); +} + +static inline uint32_t color_comb(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + return (a & 0xf) | ((b & 0xf) << 4) | ((c & 0x1f) << 8) | ((d & 7) << 13); +} + +static inline uint32_t alpha_comb(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + return (a & 7) | ((b & 7) << 3) | ((c & 7) << 6) | ((d & 7) << 9); +} + +static void gfx_dp_set_grayscale_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.grayscale_color.r = r; + rdp.grayscale_color.g = g; + rdp.grayscale_color.b = b; + rdp.grayscale_color.a = a; +} + +static void gfx_dp_set_env_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.env_color.r = r; + rdp.env_color.g = g; + rdp.env_color.b = b; + rdp.env_color.a = a; +} + +static void gfx_dp_set_prim_color(uint8_t m, uint8_t l, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.prim_lod_fraction = l; + rdp.prim_color.r = r; + rdp.prim_color.g = g; + rdp.prim_color.b = b; + rdp.prim_color.a = a; + rdp.fill_color.r = r; + rdp.fill_color.g = g; + rdp.fill_color.b = b; + rdp.fill_color.a = a; + rdp.tex_min_lod = m; + +} + +static void gfx_dp_set_fog_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.fog_color.r = r; + rdp.fog_color.g = g; + rdp.fog_color.b = b; + rdp.fog_color.a = a; +} + +static void gfx_dp_set_fill_color(uint32_t packed_color) { + uint16_t col16 = (uint16_t)packed_color; + uint32_t r = col16 >> 11; + uint32_t g = (col16 >> 6) & 0x1f; + uint32_t b = (col16 >> 1) & 0x1f; + uint32_t a = col16 & 1; + rdp.fill_color.r = SCALE_5_8(r); + rdp.fill_color.g = SCALE_5_8(g); + rdp.fill_color.b = SCALE_5_8(b); + rdp.fill_color.a = a * 255; +} + +static void gfx_dp_set_subpixel_offset(int16_t x, int16_t y) { + rdp.subpixel_ofs_x = x; + rdp.subpixel_ofs_y = y; +} + +static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { + uint32_t saved_other_mode_h = rdp.other_mode_h; + uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); + + if (cycle_type == G_CYC_COPY) { + rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT; + } + + ulx += rdp.subpixel_ofs_x; + lrx += rdp.subpixel_ofs_x; + uly += rdp.subpixel_ofs_y; + lry += rdp.subpixel_ofs_y; + + // U10.2 coordinates + float ulxf = ulx; + float ulyf = uly; + float lrxf = lrx; + float lryf = lry; + + ulxf = ulxf / (4.0f * HALF_SCREEN_WIDTH) - 1.0f; + ulyf = -(ulyf / (4.0f * HALF_SCREEN_HEIGHT)) + 1.0f; + lrxf = lrxf / (4.0f * HALF_SCREEN_WIDTH) - 1.0f; + lryf = -(lryf / (4.0f * HALF_SCREEN_HEIGHT)) + 1.0f; + + ulxf = gfx_adjust_x_for_aspect_ratio(ulxf); + lrxf = gfx_adjust_x_for_aspect_ratio(lrxf); + + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; + struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; + struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; + struct LoadedVertex* ur = &rsp.loaded_vertices[MAX_VERTICES + 3]; + + ul->x = ulxf; + ul->y = ulyf; + ul->z = -1.0f; + ul->w = 1.0f; + + ll->x = ulxf; + ll->y = lryf; + ll->z = -1.0f; + ll->w = 1.0f; + + lr->x = lrxf; + lr->y = lryf; + lr->z = -1.0f; + lr->w = 1.0f; + + ur->x = lrxf; + ur->y = ulyf; + ur->z = -1.0f; + ur->w = 1.0f; + + // The coordinates for texture rectangle shall bypass the viewport setting + struct XYWidthHeight default_viewport = { 0, (int16_t)SCREEN_HEIGHT, (uint32_t)SCREEN_WIDTH, (uint32_t)SCREEN_HEIGHT }; + struct XYWidthHeight viewport_saved = rdp.viewport; + uint32_t geometry_mode_saved = rsp.geometry_mode; + + gfx_adjust_viewport_or_scissor(&default_viewport); + + rdp.viewport = default_viewport; + rdp.viewport_or_scissor_changed = true; + rsp.geometry_mode = 0; + + gfx_sp_tri1(MAX_VERTICES + 0, MAX_VERTICES + 1, MAX_VERTICES + 3, true); + gfx_sp_tri1(MAX_VERTICES + 1, MAX_VERTICES + 2, MAX_VERTICES + 3, true); + + rsp.geometry_mode = geometry_mode_saved; + rdp.viewport = viewport_saved; + rdp.viewport_or_scissor_changed = true; + + if (cycle_type == G_CYC_COPY) { + rdp.other_mode_h = saved_other_mode_h; + } +} + +static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls, + int16_t ult, int16_t dsdx, int16_t dtdy, bool flip) { + uint64_t saved_combine_mode = rdp.combine_mode; + if ((rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_COPY) { + // Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels + // Divide by 4 to get 1 instead + dsdx >>= 2; + + // Color combiner is turned off in copy mode + gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_TEXEL0), alpha_comb(0, 0, 0, G_ACMUX_TEXEL0), 0, 0); + + // Per documentation one extra pixel is added in this modes to each edge + lrx += 1 << 2; + lry += 1 << 2; + } + + // uls and ult are S10.5 + // dsdx and dtdy are S5.10 + // lrx, lry, ulx, uly are U10.2 + // lrs, lrt are S10.5 + + const int16_t width = flip ? lry - uly : lrx - ulx; + const int16_t height = flip ? lrx - ulx : lry - uly; + const float lrs = ((uls << 7) + dsdx * width) >> 7; + const float lrt = ((ult << 7) + dtdy * height) >> 7; + + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; + struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; + struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; + struct LoadedVertex* ur = &rsp.loaded_vertices[MAX_VERTICES + 3]; + ul->u = uls; + ul->v = ult; + lr->u = lrs; + lr->v = lrt; + if (!flip) { + ll->u = uls; + ll->v = lrt; + ur->u = lrs; + ur->v = ult; + } else { + ll->u = lrs; + ll->v = ult; + ur->u = uls; + ur->v = lrt; + } + + uint8_t saved_tile = rdp.first_tile_index; + if (saved_tile != tile) { + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } + rdp.first_tile_index = tile; + + gfx_draw_rectangle(ulx, uly, lrx, lry); + if (saved_tile != tile) { + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } + rdp.first_tile_index = saved_tile; + rdp.combine_mode = saved_combine_mode; +} + +static void gfx_dp_image_rectangle(int32_t tile, int32_t w, int32_t h, + int32_t ulx, int32_t uly, int16_t uls, int16_t ult, + int32_t lrx, int32_t lry, int16_t lrs, int16_t lrt) { + uint64_t saved_combine_mode = rdp.combine_mode; + + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; + struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; + struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; + struct LoadedVertex* ur = &rsp.loaded_vertices[MAX_VERTICES + 3]; + ul->u = uls * 32; + ul->v = ult * 32; + lr->u = lrs * 32; + lr->v = lrt * 32; + ll->u = uls * 32; + ll->v = lrt * 32; + ur->u = lrs * 32; + ur->v = ult * 32; + + // ensure we have the correct texture size + rdp.texture_tile[tile].line_size_bytes = w << rdp.texture_tile[tile].siz >> 1; + rdp.texture_tile[tile].width = w; + rdp.texture_tile[tile].height = h; + rdp.texture_tile[tile].cms = 0; + rdp.texture_tile[tile].cmt = 0; + rdp.texture_tile[tile].shifts = 0; + rdp.texture_tile[tile].shiftt = 0; + auto& loadtex = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; + loadtex.full_image_line_size_bytes = loadtex.line_size_bytes = rdp.texture_tile[tile].line_size_bytes; + loadtex.size_bytes = loadtex.orig_size_bytes = loadtex.full_size_bytes = loadtex.line_size_bytes * h; + + uint8_t saved_tile = rdp.first_tile_index; + if (saved_tile != tile) { + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } + rdp.first_tile_index = tile; + + gfx_draw_rectangle(ulx, uly, lrx, lry); + if (saved_tile != tile) { + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } + rdp.first_tile_index = saved_tile; + + rdp.combine_mode = saved_combine_mode; +} + +static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { + if (rdp.color_image_address == rdp.z_buf_address) { + // Don't clear Z buffer here since we already did it with glClear + return; + } + uint32_t mode = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); + + // OTRTODO: This is a bit of a hack for widescreen screen fades, but it'll work for now... + if (ulx == 0 && uly == 0 && lrx == 319 * 4 && lry == 239 * 4) { + ulx = -1024; + uly = -1024; + lrx = 2048; + lry = 2048; + } + + if (mode == G_CYC_COPY || mode == G_CYC_FILL) { + // Per documentation one extra pixel is added in this modes to each edge + lrx += 1 << 2; + lry += 1 << 2; + } + + for (int i = MAX_VERTICES; i < MAX_VERTICES + 4; i++) { + struct LoadedVertex* v = &rsp.loaded_vertices[i]; + v->color = rdp.fill_color; + } + + uint64_t saved_combine_mode = rdp.combine_mode; + + if (mode == G_CYC_FILL) { + gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_SHADE), alpha_comb(0, 0, 0, G_ACMUX_SHADE), 0, 0); + } + + gfx_draw_rectangle(ulx, uly, lrx, lry); + rdp.combine_mode = saved_combine_mode; +} + +static void gfx_dp_set_z_image(void* z_buf_address) { + rdp.z_buf_address = z_buf_address; +} + +static void gfx_dp_set_color_image(uint32_t format, uint32_t size, uint32_t width, void* address) { + rdp.color_image_address = address; +} + +static void gfx_sp_set_other_mode(uint32_t shift, uint32_t num_bits, uint64_t mode) { + uint64_t mask = (((uint64_t)1 << num_bits) - 1) << shift; + uint64_t om = rdp.other_mode_l | ((uint64_t)rdp.other_mode_h << 32); + om = (om & ~mask) | mode; + rdp.other_mode_l = (uint32_t)om; + rdp.other_mode_h = (uint32_t)(om >> 32); + rdp.palette_fmt = rdp.other_mode_h & (3U << G_MDSFT_TEXTLUT); + rdp.tex_lod = (rdp.other_mode_h & G_TL_LOD) != 0; + rdp.tex_detail = (rdp.other_mode_h & (2U << G_MDSFT_TEXTDETAIL)) == G_TD_DETAIL; +} + +static void gfx_sp_set_vertex_colors(uint32_t count, const struct NormalColor *vcn) { + // common sense dictates that we should copy the colors as the command is supposed to do, + // but it actually doesn't seem to matter + // SUPPORT_CHECK(count <= sizeof(rsp.vertex_colors) / sizeof(rsp.vertex_colors[0])); + // for (uint32_t i = 0; i < count; ++i) { + // rsp.vertex_colors[i] = vcn[i]; + // } + rsp.vertex_colors = vcn; +} + +static void gfx_dp_set_other_mode(uint32_t h, uint32_t l) { + rdp.other_mode_h = h; + rdp.other_mode_l = l; +} + +static inline void *seg_addr(uintptr_t w1) { + // all segmented addresses have the least significant bit set + if (w1 & 1) { + // seg 0 is reserved and doesn't count here + const uintptr_t seg = (w1 & 0x0f000000) >> 24; + if (seg && segmentPointers[seg]) { + const uintptr_t addr = (w1 & 0x00fffffe); + return (void *)(segmentPointers[seg] + addr); + } + } + // GE passes OS_K0_TO_PHYSICAL(ptr) == ptr - 0x80000000 for RAM that lives + // in the reserved N64-DRAM region (port/src/dram.c); map it back. The + // region is 8 MB, so any offset below 0x800000 came from there. + if (w1 < 0x800000) { + return (void *)(w1 + 0x80000000); + } + return (void *)w1; +} + +uintptr_t clearMtx; + +static void gfx_run_dl(Gfx* cmd) { + // puts("dl"); + int dummy = 0; + char dlName[128]; + const char* fileName; + + Gfx* dListStart = cmd; + uint64_t ourHash = -1; + + for (;;) { + uint32_t opcode = cmd->words.w0 >> 24; + // gfx_print_cmd(cmd); + switch (opcode) { + // RSP commands: + case G_NOOP: /* 0xc0. GE's gbi_extension.h also names this slot + G_SETTEX (gsSPUseTexture); the game never emits it + (finding B1), so treating it as a no-op is safe. */ + break; + case G_MTX: { + gfx_sp_matrix(C0(16, 8), (const int32_t*)seg_addr(cmd->words.w1)); + break; + } + case (uint8_t)G_POPMTX: + gfx_sp_pop_matrix(1); + break; + case G_MOVEMEM: + gfx_sp_movemem(C0(16, 8), 0, seg_addr(cmd->words.w1)); + break; + case (uint8_t)G_MOVEWORD: + gfx_sp_moveword(C0(0, 8), C0(8, 16), cmd->words.w1); + break; + case (uint8_t)G_TEXTURE: + gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(0, 8)); + break; + case G_VTX: + gfx_sp_vertex(C0(0, 16) / sizeof(Vtx), C0(16, 4), (const Vtx*)seg_addr(cmd->words.w1)); + break; + case G_DL: + if (C0(16, 1) == 0) { + // Push return address + Gfx* subGFX = (Gfx*)seg_addr(cmd->words.w1); + + if (subGFX != nullptr) { + gfx_run_dl(subGFX); + } + } else { + cmd = (Gfx*)seg_addr(cmd->words.w1); + --cmd; // increase after break + } + break; + case (uint8_t)G_ENDDL: + return; + case (uint8_t)G_SETGEOMETRYMODE: + gfx_sp_geometry_mode(0, cmd->words.w1); + break; + case (uint8_t)G_CLEARGEOMETRYMODE: + gfx_sp_geometry_mode(cmd->words.w1, 0); + break; + case G_EXTRAGEOMETRYMODE_EXT: + gfx_sp_extra_geometry_mode(~C0(0, 24), cmd->words.w1); + break; + case (uint8_t)G_TRI1: + gfx_sp_tri1(C1(16, 8) / 10, C1(8, 8) / 10, C1(0, 8) / 10, false); + break; + case (uint8_t)G_TRI4: + gfx_sp_tri4(cmd); + break; + case (uint8_t)G_SETOTHERMODE_L: + gfx_sp_set_other_mode(C0(8, 8), C0(0, 8), cmd->words.w1); + break; + case (uint8_t)G_SETOTHERMODE_H: + gfx_sp_set_other_mode(C0(8, 8) + 32, C0(0, 8), (uint64_t)cmd->words.w1 << 32); + break; + case G_COL: + gfx_sp_set_vertex_colors(C0(0, 16) / 4, (NormalColor *)seg_addr(cmd->words.w1)); + break; + + // RDP Commands: + case G_SETTIMG: { + gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), 0, seg_addr(cmd->words.w1)); + break; + } + case G_SETTIMG_FB_EXT: + gfx_flush(); + gfx_rapi->select_texture_fb(cmd->words.w1); + rdp.textures_changed[0] = false; + rdp.textures_changed[1] = false; + break; + case G_SETGRAYSCALE_EXT: + rdp.grayscale = cmd->words.w1; + break; + case G_LOADBLOCK: + gfx_dp_load_block(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_LOADTILE: + gfx_dp_load_tile(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_SETTILE: + gfx_dp_set_tile(C0(21, 3), C0(19, 2), C0(9, 9), C0(0, 9), C1(24, 3), C1(20, 4), C1(18, 2), C1(14, 4), + C1(10, 4), C1(8, 2), C1(4, 4), C1(0, 4)); + break; + case G_SETTILESIZE: + gfx_dp_set_tile_size(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_LOADTLUT: + gfx_dp_load_tlut(C1(24, 3), C0(14, 10), C0(2, 10), C1(14, 10), C1(2, 10)); + break; + case G_SETENVCOLOR: + gfx_dp_set_env_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETPRIMCOLOR: + gfx_dp_set_prim_color(C0(8, 8), C0(0, 8), C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETFOGCOLOR: + gfx_dp_set_fog_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETFILLCOLOR: + gfx_dp_set_fill_color(cmd->words.w1); + break; + case G_SETINTENSITY_EXT: + gfx_dp_set_grayscale_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETCOMBINE: + gfx_dp_set_combine_mode(color_comb(C0(20, 4), C1(28, 4), C0(15, 5), C1(15, 3)), + alpha_comb(C0(12, 3), C1(12, 3), C0(9, 3), C1(9, 3)), + color_comb(C0(5, 4), C1(24, 4), C0(0, 5), C1(6, 3)), + alpha_comb(C1(21, 3), C1(3, 3), C1(18, 3), C1(0, 3))); + break; + // G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard + // G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1 + case G_SETSUBPIXELOFFSET_EXT: { + gfx_dp_set_subpixel_offset(C0(0, 16), C1(0, 16)); + break; + } + case G_TEXRECT: + case G_TEXRECTFLIP: { + int32_t lrx, lry, tile, ulx, uly; + uint32_t uls, ult, dsdx, dtdy; + lrx = C0(12, 12); + lry = C0(0, 12); + tile = C1(24, 3); + ulx = C1(12, 12); + uly = C1(0, 12); + ++cmd; + uls = C1(16, 16); + ult = C1(0, 16); + ++cmd; + dsdx = C1(16, 16); + dtdy = C1(0, 16); + gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP); + break; + } + case G_FILLRECT: + gfx_dp_fill_rectangle(C1(12, 12), C1(0, 12), C0(12, 12), C0(0, 12)); + break; + case G_FILLRECT_WIDE_EXT: { + int32_t lrx, lry, ulx, uly; + lrx = (int32_t)(C0(0, 24) << 8) >> 8; + lry = (int32_t)(C1(0, 24) << 8) >> 8; + ++cmd; + ulx = (int32_t)(C0(0, 24) << 8) >> 8; + uly = (int32_t)(C1(0, 24) << 8) >> 8; + gfx_dp_fill_rectangle(ulx, uly, lrx, lry); + break; + } + case G_TEXRECT_WIDE_EXT: { + int32_t lrx, lry, tile, ulx, uly; + uint32_t uls, ult, dsdx, dtdy; + bool flip; + lrx = (int32_t)((C0(0, 24) << 8)) >> 8; + lry = (int32_t)((C1(0, 24) << 8)) >> 8; + tile = C1(24, 3); + flip = C1(27, 1); + ++cmd; + ulx = (int32_t)((C0(0, 24) << 8)) >> 8; + uly = (int32_t)((C1(0, 24) << 8)) >> 8; + ++cmd; + uls = C0(16, 16); + ult = C0(0, 16); + dsdx = C1(16, 16); + dtdy = C1(0, 16); + gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, flip); + break; + } + case G_IMAGERECT_EXT: { + int16_t tile, iw, ih; + int16_t x0, y0, s0, t0; + int16_t x1, y1, s1, t1; + tile = C0(0, 3); + iw = C1(16, 16); + ih = C1(0, 16); + ++cmd; + x0 = C0(16, 16); + y0 = C0(0, 16); + s0 = C1(16, 16); + t0 = C1(0, 16); + ++cmd; + x1 = C0(16, 16); + y1 = C0(0, 16); + s1 = C1(16, 16); + t1 = C1(0, 16); + gfx_dp_image_rectangle(tile, iw, ih, x0, y0, s0, t0, x1, y1, s1, t1); + break; + } + case G_SETSCISSOR: + gfx_dp_set_scissor(C1(24, 2), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_SETZIMG: + gfx_dp_set_z_image(seg_addr(cmd->words.w1)); + break; + case G_SETCIMG: + gfx_dp_set_color_image(C0(21, 3), C0(19, 2), C0(0, 11), seg_addr(cmd->words.w1)); + break; + case G_SETFB_EXT: + gfx_flush(); + if (cmd->words.w1) { + // don't care about noise here + gfx_set_framebuffer(cmd->words.w1, 1.f); + fbActive = true; + } else { + gfx_reset_framebuffer(); + fbActive = false; + } + break; + case G_COPYFB_EXT: + gfx_copy_framebuffer(C0(11, 11), C0(0, 11), (int16_t)C1(16, 16), (int16_t)C1(0, 16), C0(22, 1)); + break; + case G_RDPSETOTHERMODE: + gfx_dp_set_other_mode(C0(0, 24), cmd->words.w1); + break; + case G_INVALTEXCACHE_EXT: + if (cmd->words.w1) { + gfx_texture_cache_delete((const uint8_t *)seg_addr(cmd->words.w1)); + } else { + gfx_texture_cache_clear(); + } + break; + case (uint8_t)G_RDPHALF_1: + case (uint8_t)G_RDPHALF_2: + case (uint8_t)G_RDPHALF_CONT: + // on N64 skyRender uses these to render some types of skies and skybox water + // by issuing low-level ucode commands G_TRI_FILL and G_TRI_SHADE_TXTR + // the port renders the sky in a different manner + break; + case G_RDPFLUSH_EXT: + gfx_flush(); + break; + case G_CLEAR_DEPTH_EXT: + gfx_flush(); + gfx_rapi->clear_framebuffer(false, true); + break; + case G_RDPPIPESYNC: + case G_RDPFULLSYNC: + case G_RDPLOADSYNC: + case G_RDPTILESYNC: + break; + default: + sysFatalError("Unknown GBI opcode 0x%02x at %p.\nw0 %08x\nw1 %08x", opcode, cmd, cmd->words.w0, cmd->words.w1); + break; + } + ++cmd; + } +} + +static void gfx_sp_reset() { + rsp.modelview_matrix_stack_size = 1; + rsp.current_num_lights = 2; + rsp.lights_changed = true; +} + +extern "C" void gfx_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) { + gfx_wapi->get_dimensions(width, height, posX, posY); +} + +extern "C" void gfx_init(const GfxInitSettings *settings) { + gfx_wapi = settings->wapi; + gfx_rapi = settings->rapi; + gfx_wapi->init(&settings->window_settings); + gfx_rapi->init(); + gfx_rapi->update_framebuffer_parameters(0, settings->window_settings.width, settings->window_settings.height, 1, false, true, true, true); + gfx_current_dimensions.internal_mul = 1; + gfx_current_game_window_viewport.width = gfx_current_dimensions.width = settings->window_settings.width; + gfx_current_game_window_viewport.height = gfx_current_dimensions.height = settings->window_settings.height; + game_framebuffer = gfx_rapi->create_framebuffer(); + game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer(); + + if (gfx_msaa_level > 1 && !gfx_framebuffers_enabled) { + sysLogPrintf(LOG_WARNING, "F3D: MSAA set to %d, but framebuffers are not available; disabling", gfx_msaa_level); + gfx_msaa_level = 1; + } + + for (int i = 0; i < 16; i++) { + segmentPointers[i] = 0; + } + + if (tex_upload_buffer == nullptr) { + // We cap texture max to 8k, because why would you need more? + int max_tex_size = std::min(8192, gfx_rapi->get_max_texture_size()); + tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4); + } + + rsp.lookat[0].dir[0] = rsp.lookat[1].dir[1] = 0x7F; + rsp.current_lookat_coeffs[0][0] = rsp.current_lookat_coeffs[1][1] = 1.f; + rsp.lookat_enabled = true; +} + +extern "C" void gfx_destroy(void) { + // TODO: should also destroy rapi and wapi, and any other resources acquired in fast3d + + // Texture cache and loaded textures store references to Resources which need to be unreferenced. + gfx_texture_cache_clear(); +} + +extern "C" struct GfxRenderingAPI* gfx_get_current_rendering_api(void) { + return gfx_rapi; +} + +extern "C" void gfx_start_frame(void) { + gfx_wapi->handle_events(); + gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height, + &gfx_current_window_position_x, &gfx_current_window_position_y); + + if (gfx_current_window_dimensions.height == 0) { + // Avoid division by zero + gfx_current_window_dimensions.height = 1; + } + + gfx_current_window_dimensions.aspect_ratio = (float)gfx_current_window_dimensions.width / gfx_current_window_dimensions.height; + + gfx_current_dimensions = gfx_current_window_dimensions; + + gfx_current_game_window_viewport.width = gfx_current_dimensions.width; + gfx_current_game_window_viewport.height = gfx_current_dimensions.height; + + if (gfx_current_dimensions.height != gfx_prev_dimensions.height) { + for (auto& fb : framebuffers) { + uint32_t width, height, msaa; + if (fb.second.autoresize) { + if (fb.second.upscale) { + width = fb.second.orig_width; + height = fb.second.orig_height; + gfx_adjust_width_height_for_scale(width, height); + } else { + // assume this is a fullscreen fb + width = gfx_current_dimensions.width; + height = gfx_current_dimensions.height; + } + if (width != fb.second.applied_width || height != fb.second.applied_height) { + gfx_rapi->update_framebuffer_parameters(fb.first, width, height, 1, true, true, true, true); + fb.second.applied_width = width; + fb.second.applied_height = height; + } + } + } + } + gfx_prev_dimensions = gfx_current_dimensions; + + bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || + gfx_current_dimensions.height != gfx_current_game_window_viewport.height; + if (gfx_framebuffers_enabled && (different_size || gfx_msaa_level > 1)) { + game_renders_to_framebuffer = true; + if (different_size) { + gfx_rapi->update_framebuffer_parameters(game_framebuffer, gfx_current_dimensions.width, + gfx_current_dimensions.height, gfx_msaa_level, true, true, true, + true); + } else { + // MSAA framebuffer needs to be resolved to an equally sized target when complete, which must therefore + // match the window size + gfx_rapi->update_framebuffer_parameters(game_framebuffer, gfx_current_window_dimensions.width, + gfx_current_window_dimensions.height, gfx_msaa_level, false, true, + true, true); + } + if (gfx_msaa_level > 1 && different_size) { + gfx_rapi->update_framebuffer_parameters(game_framebuffer_msaa_resolved, gfx_current_dimensions.width, + gfx_current_dimensions.height, 1, false, false, false, false); + } + } else { + game_renders_to_framebuffer = false; + } + + fbActive = 0; + + // update aspect scale and offset + gfx_update_aspect_mode(); +} + +uint32_t num_dls = 0; + +extern "C" void gfx_run(Gfx* commands) { + ++num_dls; + gfx_sp_reset(); + + // puts("New frame"); + + if (!gfx_wapi->start_frame()) { + dropped_frame = true; + return; + } + dropped_frame = false; + + gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, + gfx_current_window_dimensions.height, 1, false, true, true, + !game_renders_to_framebuffer); + gfx_rapi->start_frame(); + gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, + (float)gfx_current_dimensions.height / SCREEN_HEIGHT); + gfx_rapi->clear_framebuffer(true, false); + rdp.viewport_or_scissor_changed = true; + rendering_state.viewport = {}; + rendering_state.scissor = {}; + gfx_run_dl(commands); + gfx_flush(); + gfxFramebuffer = 0; + + if (game_renders_to_framebuffer) { + gfx_rapi->start_draw_to_framebuffer(0, 1); + gfx_rapi->clear_framebuffer(true, true); + + if (gfx_msaa_level > 1) { + bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || + gfx_current_dimensions.height != gfx_current_game_window_viewport.height; + + if (different_size) { + gfx_rapi->resolve_msaa_color_buffer(game_framebuffer_msaa_resolved, game_framebuffer); + gfxFramebuffer = (uintptr_t)gfx_rapi->get_framebuffer_texture_id(game_framebuffer_msaa_resolved); + } else { + gfx_rapi->resolve_msaa_color_buffer(0, game_framebuffer); + } + } else { + gfxFramebuffer = (uintptr_t)gfx_rapi->get_framebuffer_texture_id(game_framebuffer); + } + } + + gfx_rapi->end_frame(); + gfx_wapi->swap_buffers_begin(); +} + +extern "C" void gfx_end_frame(void) { + if (!dropped_frame) { + gfx_rapi->finish_render(); + gfx_wapi->swap_buffers_end(); + } +} + +extern "C" void gfx_set_target_fps(int fps) { + gfx_wapi->set_target_fps(fps); +} + +extern "C" void reset_texture_state() { + gfx_texture_cache_clear(); + if (rendering_state.shader_program) { + gfx_rapi->unload_shader(rendering_state.shader_program); + rendering_state.shader_program = nullptr; + } + gfx_rapi->clear_shaders(); + color_combiner_pool.clear(); + prev_combiner = color_combiner_pool.end(); +} + +extern "C" void gfx_set_texture_filter(enum FilteringMode mode) { + reset_texture_state(); + gfx_rapi->set_texture_filter(mode); +} + +extern "C" void gfx_set_mipmap_filter(enum MipmapFilteringMode mode) { + reset_texture_state(); + gfx_rapi->set_mipmap_filter(mode); +} + +extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) { + int fb = gfx_rapi->create_framebuffer(); + gfx_resize_framebuffer(fb, width, height, upscale, autoresize); + return fb; +} + +extern "C" void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale, int autoresize) { + uint32_t orig_width, orig_height; + + if (width && height) { + // user-specified size + orig_width = width; + orig_height = height; + if (upscale) { + gfx_adjust_width_height_for_scale(width, height); + } + gfx_rapi->update_framebuffer_parameters(fb, width, height, 1, true, true, true, true); + } else { + // same size as main fb + orig_width = width = gfx_current_dimensions.width; + orig_height = height = gfx_current_dimensions.height; + upscale = false; + autoresize = true; + gfx_rapi->update_framebuffer_parameters(fb, width, height, 1, true, true, true, true); + } + + framebuffers[fb] = { orig_width, orig_height, width, height, (bool)upscale, (bool)autoresize }; +} + +extern "C" void gfx_set_framebuffer(int fb, float noise_scale) { + gfx_rapi->start_draw_to_framebuffer(fb, noise_scale); + gfx_rapi->clear_framebuffer(true, true); + active_fb = framebuffers.find(fb); +} + +extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back) { + const bool is_main_fb = (fb_src == 0); + + if (is_main_fb) { + if (left > 0 && top > 0) { + // upscale the position + left = left * gfx_current_dimensions.width / gfx_current_native_viewport.width; + top = top * gfx_current_dimensions.height / gfx_current_native_viewport.height; + // flip Y + top = gfx_current_dimensions.height - top - 1; + } + if (use_back && gfx_msaa_level > 1) { + // read from the framebuffer we've been rendering to + fb_src = game_framebuffer; + } + } + + gfx_rapi->copy_framebuffer(fb_dst, fb_src, left, top, is_main_fb, (bool)use_back); +} + +extern "C" void gfx_reset_framebuffer(void) { + gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT); + active_fb = framebuffers.end(); +} diff --git a/port/fast3d/gfx_pc.h b/port/fast3d/gfx_pc.h new file mode 100644 index 00000000..0ca55152 --- /dev/null +++ b/port/fast3d/gfx_pc.h @@ -0,0 +1,60 @@ +#ifndef GFX_PC_H +#define GFX_PC_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "system.h" + +#define SCREEN_WIDTH ((int32_t)gfx_current_native_viewport.width) +#define SCREEN_HEIGHT ((int32_t)gfx_current_native_viewport.height) + +extern uintptr_t gfxFramebuffer; + +struct GfxRenderingAPI; +struct GfxWindowManagerAPI; + +struct TextureCacheKey { + const uint8_t* texture_addr; + const uint8_t* palette_addrs[2]; + uint8_t fmt, siz; + uint8_t palette_index; + + bool operator==(const TextureCacheKey&) const noexcept = default; + + struct Hasher { + size_t operator()(const TextureCacheKey& key) const noexcept { + uintptr_t addr = (uintptr_t)key.texture_addr; + return (size_t)(addr ^ (addr >> 5)); + } + }; +}; + +typedef std::unordered_map TextureCacheMap; +typedef std::pair TextureCacheNode; + +struct TextureCacheValue { + uint32_t texture_id; + uint8_t cms, cmt; + bool linear_filter; + + std::list::iterator lru_location; +}; + +struct TextureCacheMapIter { + TextureCacheMap::iterator it; +}; + +extern "C" { + +#include "gfx_api.h" + +} + +#endif diff --git a/port/fast3d/gfx_rendering_api.h b/port/fast3d/gfx_rendering_api.h new file mode 100644 index 00000000..d21b3f75 --- /dev/null +++ b/port/fast3d/gfx_rendering_api.h @@ -0,0 +1,61 @@ +#ifndef GFX_RENDERING_API_H +#define GFX_RENDERING_API_H + +#include +#include +#include + +struct ShaderProgram; + +struct GfxClipParameters { + bool z_is_from_0_to_1; + bool invert_y; +}; + +enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT }; +enum MipmapFilteringMode { MIPMAP_DISABLED, MIPMAP_NEAREST, MIPMAP_LINEAR }; + +struct GfxRenderingAPI { + const char* (*get_name)(void); + int (*get_max_texture_size)(void); + struct GfxClipParameters (*get_clip_parameters)(void); + void (*unload_shader)(struct ShaderProgram* old_prg); + void (*load_shader)(struct ShaderProgram* new_prg); + struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1); + struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1); + void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]); + void (*clear_shaders)(void); + uint32_t (*new_texture)(void); + void (*select_texture)(int tile, uint32_t texture_id, bool linear_filter); + void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height, bool gen_mipmaps); + void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt, bool mipmaps); + void (*set_depth_mode)(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode); + void (*set_depth_range)(float znear, float zfar); + void (*set_viewport)(int x, int y, int width, int height); + void (*set_scissor)(int x, int y, int width, int height); + void (*set_use_alpha)(bool use_alpha, bool modulate); + void (*draw_triangles)(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris); + void (*init)(void); + void (*on_resize)(void); + void (*start_frame)(void); + void (*end_frame)(void); + void (*finish_render)(void); + int (*create_framebuffer)(); + void (*update_framebuffer_parameters)(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, + bool opengl_invert_y, bool render_target, bool has_depth_buffer, + bool can_extract_depth); + bool (*start_draw_to_framebuffer)(int fb_id, float noise_scale); + void (*copy_framebuffer)(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back); + void (*clear_framebuffer)(bool clear_color, bool clear_depth); + void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source); + void* (*get_framebuffer_texture_id)(int fb_id); + void (*select_texture_fb)(int fb_id); + void (*delete_texture)(uint32_t texID); + void (*set_texture_filter)(enum FilteringMode mode); + enum FilteringMode (*get_texture_filter)(void); + void (*set_mipmap_filter)(enum MipmapFilteringMode mode); + void (*set_anisotropy_level)(int); + int (*get_max_anisotropy_level)(void); +}; + +#endif diff --git a/port/fast3d/gfx_screen_config.h b/port/fast3d/gfx_screen_config.h new file mode 100644 index 00000000..5b933f85 --- /dev/null +++ b/port/fast3d/gfx_screen_config.h @@ -0,0 +1,7 @@ +#ifndef GFX_SCREEN_CONFIG_H +#define GFX_SCREEN_CONFIG_H + +#define DESIRED_SCREEN_WIDTH 640 +#define DESIRED_SCREEN_HEIGHT 480 + +#endif diff --git a/port/fast3d/gfx_sdl.h b/port/fast3d/gfx_sdl.h new file mode 100644 index 00000000..f9133471 --- /dev/null +++ b/port/fast3d/gfx_sdl.h @@ -0,0 +1,24 @@ +#ifndef GFX_SDL_H +#define GFX_SDL_H + +#include "gfx_window_manager_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct GfxWindowManagerAPI gfx_sdl; + +/* Make the window's GL context current on the calling thread (rendering + * runs on the game's scheduler thread, not the thread that created it). */ +void gfx_sdl_make_context_current(void); + +/* Refresh the cached drawable size after a window resize (called by the + * host thread's event pump). */ +void gfx_sdl_update_cached_size(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp new file mode 100644 index 00000000..8e813377 --- /dev/null +++ b/port/fast3d/gfx_sdl2.cpp @@ -0,0 +1,488 @@ +#include +#include +#include + +#include "platform.h" +#include "system.h" + +#include "gfx_window_manager_api.h" +#include "gfx_screen_config.h" + +static SDL_Window* wnd; +static SDL_GLContext ctx; +static SDL_Renderer* renderer; +static int sdl_to_lus_table[512]; +static bool vsync_enabled = true; +// OTRTODO: These are redundant. Info can be queried from SDL. +static int window_width = DESIRED_SCREEN_WIDTH; +static int window_height = DESIRED_SCREEN_HEIGHT; +static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP; +static bool fullscreen_state; +static bool maximized_state; +static bool is_running = true; +static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen); + +// GE port: frame pacing is owned by the cooperative thread kernel's vsync +// tick (libultra.c posts one VI retrace per frame at the console rate), so +// fast3d's internal busy-wait sync is disabled to avoid double-pacing. The +// GL swap still honors display vsync (vsync_enabled below). +static int target_fps = 0; +static uint64_t previous_time; +static uint64_t qpc_freq; + +#define FRAME_INTERVAL_US_NUMERATOR 1000000 +#define FRAME_INTERVAL_US_DENOMINATOR (target_fps) + +static int32_t gfx_sdl_get_maximized_state(void) { + return (int32_t)maximized_state; +} + +static int32_t gfx_sdl_get_fullscreen_state(void) { + return (int32_t)fullscreen_state; +} + +static int32_t gfx_sdl_get_fullscreen_flag_mode(void) { + return fullscreen_flag == SDL_WINDOW_FULLSCREEN_DESKTOP ? 0 : 1; +} + +static void gfx_sdl_set_fullscreen_flag(int32_t mode) { + switch (mode) { + case 0: { + fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP; + } break; + case 1: { + fullscreen_flag = SDL_WINDOW_FULLSCREEN; + } break; + } +} + +static void set_fullscreen(bool on, bool call_callback) { + fullscreen_state = on; + SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0); + if (call_callback && on_fullscreen_changed_callback) { + on_fullscreen_changed_callback(on); + } +} + +static void set_maximize_window(bool on) { + maximized_state = on; + if (on) { + SDL_MaximizeWindow(wnd); + } else { + SDL_RestoreWindow (wnd); + } +} + +static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) { + int display_in_use = SDL_GetWindowDisplayIndex(wnd); + + SDL_DisplayMode mode; + SDL_GetCurrentDisplayMode(display_in_use, &mode); + *refresh_rate = mode.refresh_rate; +} + +static void gfx_sdl_init(const struct GfxWindowInitSettings *set) { + window_width = set->width; + window_height = set->height; + +#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED + if (!set->allow_hidpi) { + // HiDPI control, if available + SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1"); +#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS) + // if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows + SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor"); +#endif + } +#endif + + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + sysFatalError("Could not init SDL:\n%s", SDL_GetError()); + } + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + if (sysArgCheck("--debug-gl")) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + } + + int posX = set->x; + int posY = set->y; + int display_in_use = SDL_GetWindowDisplayIndex(wnd); + if (display_in_use < 0) { // Fallback to default if out of bounds + posX = SDL_WINDOWPOS_UNDEFINED; + posY = SDL_WINDOWPOS_UNDEFINED; + } + + if (set->centered) { + SDL_DisplayMode mode = {}; + SDL_GetCurrentDisplayMode(0, &mode); + posX = mode.w / 2 - window_width / 2; + posY = mode.h / 2 - window_height / 2; + } + + if (set->fullscreen_is_exclusive) { + fullscreen_flag = SDL_WINDOW_FULLSCREEN; + } + + // we will unhide the window once the GL context is successfully created + Uint32 flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL; + + // if fullscreen was requested, start the window in fullscreen right away + if (set->fullscreen) { + flags |= fullscreen_flag; + fullscreen_state = true; + } + + if (set->maximized) { + flags |= SDL_WINDOW_MAXIMIZED; + maximized_state = true; + } + +#ifdef SDL_WINDOW_ALLOW_HIGHDPI + if (set->allow_hidpi) { + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + } +#endif + + // ideally we need 3.0 compat + // if that doesn't work, try 3.2 core in case we're on mac, 2.1 compat as a last resort + static u32 glver[][3] = { + { 0, 0, 0 }, // for command line override + { 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 3.0: default, has all the features required + { 4, 1, SDL_GL_CONTEXT_PROFILE_CORE }, // 4.1core: macs only have core profile and this is the latest + { 3, 2, SDL_GL_CONTEXT_PROFILE_CORE }, // 3.2core: older macs will only have this at best + { 3, 0, SDL_GL_CONTEXT_PROFILE_ES }, // es3: don't really support ES properly, but we can try + { 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 2.1: absolute last resort, will still require GLSL130 as an extension + }; + + u32 verstart = 1; + const u32 verend = sizeof(glver) / sizeof(*glver); + const char *verstr = sysArgGetString("--gl-version"); + if (verstr && *verstr) { + // user override + glver[0][2] = strstr(verstr, "core") ? SDL_GL_CONTEXT_PROFILE_CORE : + (strstr(verstr, "es") ? SDL_GL_CONTEXT_PROFILE_ES : + SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]); + if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) { + verstart = 0; + } + } + + ctx = NULL; + u32 vmin = 0, vmaj = 0, vprof = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; + const char *vprofstr = ""; + for (u32 i = verstart; i < verend && !ctx; ++i) { + vmaj = glver[i][0]; + vmin = glver[i][1]; + vprof = glver[i][2]; + vprofstr = (vprof == SDL_GL_CONTEXT_PROFILE_CORE ? "core" : + (vprof == SDL_GL_CONTEXT_PROFILE_ES ? "es" : "")); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, vmaj); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, vmin); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, vprof); + + wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags); + if (!wnd) { + sysLogPrintf(LOG_WARNING, "SDL: could not open SDL window for GL%d.%d%s:\n%s", vmaj, vmin, vprofstr, SDL_GetError()); + continue; + } + + ctx = SDL_GL_CreateContext(wnd); + if (!ctx) { + sysLogPrintf(LOG_WARNING, "SDL: could not create GL%d.%d%s context: %s", vmaj, vmin, vprofstr, SDL_GetError()); + SDL_DestroyWindow(wnd); + wnd = nullptr; + } + } + + if (!wnd || !ctx) { + sysFatalError("Could not open SDL window with an OpenGL context of any supported version:\n%s", SDL_GetError()); + } else { + sysLogPrintf(LOG_NOTE, "SDL: created GL%d.%d%s context", vmaj, vmin, vprofstr); + } + + SDL_GL_MakeCurrent(wnd, ctx); + SDL_GL_SetSwapInterval(1); + + SDL_ShowWindow(wnd); + + qpc_freq = SDL_GetPerformanceFrequency(); +} + +static void gfx_sdl_close(void) { + is_running = false; +} + +static void gfx_sdl_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) { + on_fullscreen_changed_callback = on_fullscreen_changed; +} + +static void gfx_sdl_set_fullscreen(bool enable) { + set_fullscreen(enable, true); +} + +static void gfx_sdl_set_fullscreen_exclusive(bool enable) { + const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; + if (fullscreen_flag != newflag) { + fullscreen_flag = newflag; + // reset fullscreen to take new value into account if it already is in fullscreen + if (fullscreen_state) { + fullscreen_state = false; + set_fullscreen(enable, true); + } + } +} + +static void gfx_sdl_set_maximize_window(bool enable) { + set_maximize_window(enable); +} + +static void gfx_sdl_set_cursor_visibility(bool visible) { + if (visible) { + SDL_ShowCursor(SDL_ENABLE); + } else { + SDL_ShowCursor(SDL_DISABLE); + } +} + +static void get_centered_positions_native(int32_t width, int32_t height, int32_t *posX, int32_t *posY) { + const int disp_idx = SDL_GetWindowDisplayIndex(wnd); + SDL_DisplayMode mode = {}; + SDL_GetDesktopDisplayMode(disp_idx, &mode); + *posX = mode.w / 2 - width / 2; + *posY = mode.h / 2 - height / 2; +} + +static void gfx_sdl_get_centered_positions(int32_t width, int32_t height, int32_t *posX, int32_t *posY) { + const int disp_idx = SDL_GetWindowDisplayIndex(wnd); + SDL_DisplayMode mode = {}; + SDL_GetCurrentDisplayMode(disp_idx, &mode); + *posX = mode.w / 2 - width / 2; + *posY = mode.h / 2 - height / 2; +} + +static void gfx_sdl_set_closest_resolution(int32_t width, int32_t height, bool should_center) { + const SDL_DisplayMode mode = {.w = width, .h = height}; + const int disp_idx = SDL_GetWindowDisplayIndex(wnd); + SDL_DisplayMode closest = {}; + if (SDL_GetClosestDisplayMode(disp_idx, &mode, &closest)) { + SDL_SetWindowDisplayMode(wnd, &closest); + SDL_SetWindowSize(wnd, closest.w, closest.h); + if (should_center) { + int32_t posX = 0; + int32_t posY = 0; + get_centered_positions_native(closest.w, closest.h, &posX, &posY); + SDL_SetWindowPosition(wnd, posX, posY); + } + } +} + +static void gfx_sdl_set_dimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) { + SDL_SetWindowSize(wnd, width, height); + SDL_SetWindowPosition(wnd, posX, posY); +} + +static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) { + SDL_GL_GetDrawableSize(wnd, static_cast((void*)width), static_cast((void*)height)); + SDL_GetWindowPosition(wnd, static_cast(posX), static_cast(posY)); +} + +static void gfx_sdl_handle_events(void) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT)) { + // alt-enter received, switch fullscreen state + set_fullscreen(!fullscreen_state, true); + } else if (event.key.keysym.sym == SDLK_ESCAPE) { + // GE's own menus use the keyboard; ESC on an empty event + // queue is our quit key (matches the Phase 1 demo loop). + exit(0); + } + break; + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); + if (!fullscreen_state) { + maximized_state = SDL_GetWindowFlags(wnd) & SDL_WINDOW_MAXIMIZED ? true : false; + } + } else if (event.window.event == SDL_WINDOWEVENT_CLOSE && + event.window.windowID == SDL_GetWindowID(wnd)) { + // We listen specifically for main window close because closing main window + // on macOS does not trigger SDL_Quit. + exit(0); + } + break; + case SDL_QUIT: + exit(0); + break; + } + } +} + +/* The window/context are created on the host main thread, but the game's + * scheduler thread (shedThread) does all rendering. Make the context current + * there before each frame. extern "C": called from C (port/src/video.c). */ +extern "C" void gfx_sdl_make_context_current(void) { + if (wnd && ctx) { + SDL_GL_MakeCurrent(wnd, ctx); + } +} + +/* The host thread owns SDL event pumping (see videoPumpEvents); when it sees + * a window resize it calls this to refresh the cached drawable size that + * fast3d uses for scaling. */ +extern "C" void gfx_sdl_update_cached_size(void) { + if (wnd) { + SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); + } +} + +static bool gfx_sdl_start_frame(void) { + return true; +} + +static uint64_t qpc_to_100ns(uint64_t qpc) { + return qpc / qpc_freq * 10000000 + qpc % qpc_freq * 10000000 / qpc_freq; +} + +static inline void sync_framerate_with_timer(void) { + uint64_t t; + t = qpc_to_100ns(SDL_GetPerformanceCounter()); + + const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR; + int64_t left = next - t; + // We want to exit a bit early, so we can busy-wait the rest to never miss the deadline + left -= 15000UL; + if (left > 0) { + sysSleep(left); + } + + do { + sysCpuRelax(); + t = qpc_to_100ns(SDL_GetPerformanceCounter()); + } while ((int64_t)t < next); + + t = qpc_to_100ns(SDL_GetPerformanceCounter()); + if (left > 0 && t - next < 10000) { + // In case it takes some time for the application to wake up after sleep, + // or inaccurate timer, + // don't let that slow down the framerate. + t = next; + } + previous_time = t; +} + +static void gfx_sdl_swap_buffers_begin(void) { + if (target_fps) { + sync_framerate_with_timer(); + } + SDL_GL_SwapWindow(wnd); +} + +static void gfx_sdl_swap_buffers_end(void) { + +} + +static double gfx_sdl_get_time(void) { + return SDL_GetPerformanceCounter() / (double)qpc_freq; +} + +static int32_t gfx_sdl_get_target_fps(void) { + return target_fps; +} + +static void gfx_sdl_set_target_fps(int fps) { + target_fps = fps; +} + +static bool gfx_sdl_can_disable_vsync(void) { + return true; +} + +static void *gfx_sdl_get_window_handle(void) { + return (void *)wnd; +} + +static void gfx_sdl_set_window_title(const char *title) { + SDL_SetWindowTitle(wnd, title); +} + +static int gfx_sdl_get_swap_interval(void) { + return SDL_GL_GetSwapInterval(); +} + +static bool gfx_sdl_set_swap_interval(int interval) { + const bool success = SDL_GL_SetSwapInterval(interval) >= 0; + vsync_enabled = success && (interval != 0); + if (!success) { + sysLogPrintf(LOG_WARNING, "SDL: failed to set vsync %d: %s", interval, SDL_GetError()); + } + return success; +} + +int gfx_sdl_get_display_mode(int modenum, int *out_w, int *out_h) { + const int display_in_use = SDL_GetWindowDisplayIndex(wnd); + SDL_DisplayMode sdlmode; + if (SDL_GetDisplayMode(display_in_use, modenum, &sdlmode) == 0) { + *out_w = sdlmode.w; + *out_h = sdlmode.h; + return 1; + } + return 0; +} + +int gfx_sdl_get_current_display_mode(int *out_w, int *out_h) { + const int display_in_use = SDL_GetWindowDisplayIndex(wnd); + SDL_DisplayMode sdlmode; + if (SDL_GetCurrentDisplayMode(display_in_use, &sdlmode) == 0) { + *out_w = sdlmode.w; + *out_h = sdlmode.h; + return 1; + } + return 0; +} + +int gfx_sdl_get_num_display_modes(void) { + const int display_in_use = SDL_GetWindowDisplayIndex(wnd); + return SDL_GetNumDisplayModes(display_in_use); +} + +struct GfxWindowManagerAPI gfx_sdl = { + gfx_sdl_init, + gfx_sdl_close, + gfx_sdl_get_display_mode, + gfx_sdl_get_current_display_mode, + gfx_sdl_get_num_display_modes, + gfx_sdl_get_fullscreen_state, + gfx_sdl_set_fullscreen_changed_callback, + gfx_sdl_set_fullscreen, + gfx_sdl_set_fullscreen_exclusive, + gfx_sdl_set_fullscreen_flag, + gfx_sdl_get_fullscreen_flag_mode, + gfx_sdl_get_maximized_state, + gfx_sdl_set_maximize_window, + gfx_sdl_get_active_window_refresh_rate, + gfx_sdl_set_cursor_visibility, + gfx_sdl_set_closest_resolution, + gfx_sdl_set_dimensions, + gfx_sdl_get_dimensions, + gfx_sdl_get_centered_positions, + gfx_sdl_handle_events, + gfx_sdl_start_frame, + gfx_sdl_swap_buffers_begin, + gfx_sdl_swap_buffers_end, + gfx_sdl_get_time, + gfx_sdl_get_target_fps, + gfx_sdl_set_target_fps, + gfx_sdl_can_disable_vsync, + gfx_sdl_get_window_handle, + gfx_sdl_set_window_title, + gfx_sdl_get_swap_interval, + gfx_sdl_set_swap_interval, +}; diff --git a/port/fast3d/gfx_window_manager_api.h b/port/fast3d/gfx_window_manager_api.h new file mode 100644 index 00000000..d10fc45c --- /dev/null +++ b/port/fast3d/gfx_window_manager_api.h @@ -0,0 +1,54 @@ +#ifndef GFX_WINDOW_MANAGER_API_H +#define GFX_WINDOW_MANAGER_API_H + +#include +#include + +struct GfxWindowInitSettings { + const char *title; + uint32_t width; + uint32_t height; + int32_t x; + int32_t y; + bool fullscreen; + bool fullscreen_is_exclusive; + bool maximized; + bool centered; + bool allow_hidpi; +}; + +struct GfxWindowManagerAPI { + void (*init)(const struct GfxWindowInitSettings *settings); + void (*close)(void); + int (*get_display_mode)(int modenum, int *out_w, int *out_h); + int (*get_current_display_mode)(int *out_w, int *out_h); + int (*get_num_display_modes)(void); + int32_t (*get_fullscreen_state)(void); + void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen)); + void (*set_fullscreen)(bool enable); + void (*set_fullscreen_exclusive)(bool exc); + void (*set_fullscreen_flag)(int32_t mode); + int32_t (*get_fullscreen_flag_mode)(void); + int32_t (*get_maximized_state)(void); + void (*set_maximize)(bool enable); + void (*get_active_window_refresh_rate)(uint32_t* refresh_rate); + void (*set_cursor_visibility)(bool visible); + void (*set_closest_resolution)(int32_t width, int32_t height, bool should_center); + void (*set_dimensions)(uint32_t width, uint32_t height, int32_t posX, int32_t posY); + void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY); + void (*get_centered_positions)(int32_t width, int32_t height, int32_t *posX, int32_t *posY); + void (*handle_events)(void); + bool (*start_frame)(void); + void (*swap_buffers_begin)(void); + void (*swap_buffers_end)(void); + double (*get_time)(void); // For debug + int32_t (*get_target_fps)(void); + void (*set_target_fps)(int fps); + bool (*can_disable_vsync)(void); + void *(*get_window_handle)(void); + void (*set_window_title)(const char *); + int (*get_swap_interval)(void); + bool (*set_swap_interval)(int); +}; + +#endif diff --git a/port/fast3d/glad/glad.c b/port/fast3d/glad/glad.c new file mode 100644 index 00000000..02b14db1 --- /dev/null +++ b/port/fast3d/glad/glad.c @@ -0,0 +1,1876 @@ +/* + + OpenGL, OpenGL ES loader generated by glad 0.1.36 on Wed Oct 8 13:10:56 2025. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=4.1, gles2=3.0 + Profile: core + Extensions: + GL_APPLE_framebuffer_multisample, + GL_ARB_depth_clamp, + GL_ARB_framebuffer_object, + GL_ARB_texture_filter_anisotropic, + GL_ARB_texture_mirror_clamp_to_edge, + GL_ARB_vertex_array_object, + GL_EXT_depth_clamp, + GL_EXT_framebuffer_blit, + GL_EXT_framebuffer_multisample, + GL_EXT_framebuffer_object, + GL_EXT_gpu_shader4, + GL_EXT_texture_filter_anisotropic, + GL_EXT_texture_mirror_clamp_to_edge, + GL_KHR_debug, + GL_NV_depth_clamp, + GL_NV_framebuffer_multisample + Loader: False + Local files: True + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="core" --api="gl=4.1,gles2=3.0" --generator="c" --spec="gl" --no-loader --local-files --extensions="GL_APPLE_framebuffer_multisample,GL_ARB_depth_clamp,GL_ARB_framebuffer_object,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_vertex_array_object,GL_EXT_depth_clamp,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_mirror_clamp_to_edge,GL_KHR_debug,GL_NV_depth_clamp,GL_NV_framebuffer_multisample" + Online: + https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.1&api=gles2%3D3.0&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_texture_filter_anisotropic&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_vertex_array_object&extensions=GL_EXT_depth_clamp&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_mirror_clamp_to_edge&extensions=GL_KHR_debug&extensions=GL_NV_depth_clamp&extensions=GL_NV_framebuffer_multisample +*/ + +#include +#include +#include +#include "glad.h" + +struct gladGLversionStruct GLVersion = { 0, 0 }; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < num_exts_i; index++) { + const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp); + + char *local_str = (char*)malloc((len+1) * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); + } + exts_i[index] = local_str; + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + int index; + for(index = 0; index < num_exts_i; index++) { + free((char *)exts_i[index]); + } + free((void *)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + if(exts_i == NULL) return 0; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(exts_i[index] != NULL && strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_VERSION_1_0 = 0; +int GLAD_GL_VERSION_1_1 = 0; +int GLAD_GL_VERSION_1_2 = 0; +int GLAD_GL_VERSION_1_3 = 0; +int GLAD_GL_VERSION_1_4 = 0; +int GLAD_GL_VERSION_1_5 = 0; +int GLAD_GL_VERSION_2_0 = 0; +int GLAD_GL_VERSION_2_1 = 0; +int GLAD_GL_VERSION_3_0 = 0; +int GLAD_GL_VERSION_3_1 = 0; +int GLAD_GL_VERSION_3_2 = 0; +int GLAD_GL_VERSION_3_3 = 0; +int GLAD_GL_VERSION_4_0 = 0; +int GLAD_GL_VERSION_4_1 = 0; +int GLAD_GL_ES_VERSION_2_0 = 0; +int GLAD_GL_ES_VERSION_3_0 = 0; +PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; +PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; +PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; +PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL; +PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL; +PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; +PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; +PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; +PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; +PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; +PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL; +PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDISABLEIPROC glad_glDisablei = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; +PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; +PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL; +PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLENABLEIPROC glad_glEnablei = NULL; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; +PFNGLENDQUERYPROC glad_glEndQuery = NULL; +PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; +PFNGLFENCESYNCPROC glad_glFenceSync = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL; +PFNGLGENQUERIESPROC glad_glGenQueries = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL; +PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL; +PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; +PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL; +PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; +PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL; +PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL; +PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL; +PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; +PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; +PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; +PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; +PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; +PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; +PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL; +PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL; +PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL; +PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; +PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL; +PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL; +PFNGLISQUERYPROC glad_glIsQuery = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSAMPLERPROC glad_glIsSampler = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISSYNCPROC glad_glIsSync = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLLOGICOPPROC glad_glLogicOp = NULL; +PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; +PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; +PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; +PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; +PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; +PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; +PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; +PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL; +PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; +PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; +PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; +PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; +PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL; +PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL; +PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL; +PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; +PFNGLPOINTSIZEPROC glad_glPointSize = NULL; +PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; +PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL; +PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL; +PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL; +PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL; +PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL; +PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL; +PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL; +PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL; +PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL; +PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL; +PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL; +PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL; +PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL; +PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL; +PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL; +PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL; +PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL; +PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL; +PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL; +PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL; +PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL; +PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL; +PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL; +PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL; +PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL; +PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL; +PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL; +PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL; +PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL; +PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL; +PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL; +PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL; +PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL; +PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL; +PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; +PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; +PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; +PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; +PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; +PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; +PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; +PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; +PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; +PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL; +PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL; +PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL; +PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; +PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; +PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; +PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; +PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; +PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; +PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; +PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; +PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; +PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL; +PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL; +PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; +PFNGLUNIFORM1DPROC glad_glUniform1d = NULL; +PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; +PFNGLUNIFORM2DPROC glad_glUniform2d = NULL; +PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; +PFNGLUNIFORM3DPROC glad_glUniform3d = NULL; +PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; +PFNGLUNIFORM4DPROC glad_glUniform4d = NULL; +PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; +PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; +PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; +PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; +PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; +PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; +PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; +PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; +PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; +PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL; +PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL; +PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL; +PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL; +PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL; +PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL; +PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL; +PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL; +PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL; +PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; +PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; +PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; +PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; +PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; +PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; +PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; +PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; +PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL; +PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL; +PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; +PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; +PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL; +PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL; +PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL; +PFNGLWAITSYNCPROC glad_glWaitSync = NULL; +int GLAD_GL_APPLE_framebuffer_multisample = 0; +int GLAD_GL_ARB_depth_clamp = 0; +int GLAD_GL_ARB_framebuffer_object = 0; +int GLAD_GL_ARB_texture_filter_anisotropic = 0; +int GLAD_GL_ARB_texture_mirror_clamp_to_edge = 0; +int GLAD_GL_ARB_vertex_array_object = 0; +int GLAD_GL_EXT_depth_clamp = 0; +int GLAD_GL_EXT_framebuffer_blit = 0; +int GLAD_GL_EXT_framebuffer_multisample = 0; +int GLAD_GL_EXT_framebuffer_object = 0; +int GLAD_GL_EXT_gpu_shader4 = 0; +int GLAD_GL_EXT_texture_filter_anisotropic = 0; +int GLAD_GL_EXT_texture_mirror_clamp_to_edge = 0; +int GLAD_GL_KHR_debug = 0; +int GLAD_GL_NV_depth_clamp = 0; +int GLAD_GL_NV_framebuffer_multisample = 0; +PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL; +PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL; +PFNGLGETUNIFORMUIVEXTPROC glad_glGetUniformuivEXT = NULL; +PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT = NULL; +PFNGLGETFRAGDATALOCATIONEXTPROC glad_glGetFragDataLocationEXT = NULL; +PFNGLUNIFORM1UIEXTPROC glad_glUniform1uiEXT = NULL; +PFNGLUNIFORM2UIEXTPROC glad_glUniform2uiEXT = NULL; +PFNGLUNIFORM3UIEXTPROC glad_glUniform3uiEXT = NULL; +PFNGLUNIFORM4UIEXTPROC glad_glUniform4uiEXT = NULL; +PFNGLUNIFORM1UIVEXTPROC glad_glUniform1uivEXT = NULL; +PFNGLUNIFORM2UIVEXTPROC glad_glUniform2uivEXT = NULL; +PFNGLUNIFORM3UIVEXTPROC glad_glUniform3uivEXT = NULL; +PFNGLUNIFORM4UIVEXTPROC glad_glUniform4uivEXT = NULL; +PFNGLVERTEXATTRIBI1IEXTPROC glad_glVertexAttribI1iEXT = NULL; +PFNGLVERTEXATTRIBI2IEXTPROC glad_glVertexAttribI2iEXT = NULL; +PFNGLVERTEXATTRIBI3IEXTPROC glad_glVertexAttribI3iEXT = NULL; +PFNGLVERTEXATTRIBI4IEXTPROC glad_glVertexAttribI4iEXT = NULL; +PFNGLVERTEXATTRIBI1UIEXTPROC glad_glVertexAttribI1uiEXT = NULL; +PFNGLVERTEXATTRIBI2UIEXTPROC glad_glVertexAttribI2uiEXT = NULL; +PFNGLVERTEXATTRIBI3UIEXTPROC glad_glVertexAttribI3uiEXT = NULL; +PFNGLVERTEXATTRIBI4UIEXTPROC glad_glVertexAttribI4uiEXT = NULL; +PFNGLVERTEXATTRIBI1IVEXTPROC glad_glVertexAttribI1ivEXT = NULL; +PFNGLVERTEXATTRIBI2IVEXTPROC glad_glVertexAttribI2ivEXT = NULL; +PFNGLVERTEXATTRIBI3IVEXTPROC glad_glVertexAttribI3ivEXT = NULL; +PFNGLVERTEXATTRIBI4IVEXTPROC glad_glVertexAttribI4ivEXT = NULL; +PFNGLVERTEXATTRIBI1UIVEXTPROC glad_glVertexAttribI1uivEXT = NULL; +PFNGLVERTEXATTRIBI2UIVEXTPROC glad_glVertexAttribI2uivEXT = NULL; +PFNGLVERTEXATTRIBI3UIVEXTPROC glad_glVertexAttribI3uivEXT = NULL; +PFNGLVERTEXATTRIBI4UIVEXTPROC glad_glVertexAttribI4uivEXT = NULL; +PFNGLVERTEXATTRIBI4BVEXTPROC glad_glVertexAttribI4bvEXT = NULL; +PFNGLVERTEXATTRIBI4SVEXTPROC glad_glVertexAttribI4svEXT = NULL; +PFNGLVERTEXATTRIBI4UBVEXTPROC glad_glVertexAttribI4ubvEXT = NULL; +PFNGLVERTEXATTRIBI4USVEXTPROC glad_glVertexAttribI4usvEXT = NULL; +PFNGLVERTEXATTRIBIPOINTEREXTPROC glad_glVertexAttribIPointerEXT = NULL; +PFNGLGETVERTEXATTRIBIIVEXTPROC glad_glGetVertexAttribIivEXT = NULL; +PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT = NULL; +PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL; +PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL; +PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL; +PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL; +PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL; +PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL; +PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL; +PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL; +PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL; +PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL; +PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; +PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; +PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; +PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; +PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL; +PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL; +PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL; +PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL; +PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL; +PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL; +PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL; +PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC glad_glRenderbufferStorageMultisampleAPPLE = NULL; +PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC glad_glResolveMultisampleFramebufferAPPLE = NULL; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC glad_glRenderbufferStorageMultisampleNV = NULL; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_VERSION_3_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_1) return; + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); + glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); +} +static void load_GL_VERSION_3_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_2) return; + glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); + glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); + glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); + glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); + glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void load_GL_VERSION_3_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_3) return; + glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed"); + glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex"); + glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); + glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); + glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); + glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); + glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); + glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); + glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); + glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); + glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); + glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); + glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); + glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); + glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); + glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); + glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter"); + glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v"); + glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v"); + glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); + glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui"); + glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv"); + glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui"); + glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv"); + glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui"); + glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv"); + glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui"); + glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv"); + glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui"); + glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv"); + glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui"); + glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv"); + glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui"); + glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv"); + glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui"); + glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv"); + glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui"); + glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv"); + glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui"); + glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv"); + glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui"); + glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv"); + glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui"); + glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv"); + glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui"); + glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv"); + glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui"); + glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv"); + glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui"); + glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv"); + glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui"); + glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv"); + glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui"); + glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv"); + glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui"); + glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv"); + glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); + glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); +} +static void load_GL_VERSION_4_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_4_0) return; + glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load("glMinSampleShading"); + glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load("glBlendEquationi"); + glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load("glBlendEquationSeparatei"); + glad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load("glBlendFunci"); + glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load("glBlendFuncSeparatei"); + glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load("glDrawArraysIndirect"); + glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load("glDrawElementsIndirect"); + glad_glUniform1d = (PFNGLUNIFORM1DPROC)load("glUniform1d"); + glad_glUniform2d = (PFNGLUNIFORM2DPROC)load("glUniform2d"); + glad_glUniform3d = (PFNGLUNIFORM3DPROC)load("glUniform3d"); + glad_glUniform4d = (PFNGLUNIFORM4DPROC)load("glUniform4d"); + glad_glUniform1dv = (PFNGLUNIFORM1DVPROC)load("glUniform1dv"); + glad_glUniform2dv = (PFNGLUNIFORM2DVPROC)load("glUniform2dv"); + glad_glUniform3dv = (PFNGLUNIFORM3DVPROC)load("glUniform3dv"); + glad_glUniform4dv = (PFNGLUNIFORM4DVPROC)load("glUniform4dv"); + glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC)load("glUniformMatrix2dv"); + glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC)load("glUniformMatrix3dv"); + glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC)load("glUniformMatrix4dv"); + glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC)load("glUniformMatrix2x3dv"); + glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC)load("glUniformMatrix2x4dv"); + glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC)load("glUniformMatrix3x2dv"); + glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC)load("glUniformMatrix3x4dv"); + glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC)load("glUniformMatrix4x2dv"); + glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC)load("glUniformMatrix4x3dv"); + glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC)load("glGetUniformdv"); + glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)load("glGetSubroutineUniformLocation"); + glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC)load("glGetSubroutineIndex"); + glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)load("glGetActiveSubroutineUniformiv"); + glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)load("glGetActiveSubroutineUniformName"); + glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC)load("glGetActiveSubroutineName"); + glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC)load("glUniformSubroutinesuiv"); + glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC)load("glGetUniformSubroutineuiv"); + glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC)load("glGetProgramStageiv"); + glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load("glPatchParameteri"); + glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC)load("glPatchParameterfv"); + glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load("glBindTransformFeedback"); + glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load("glDeleteTransformFeedbacks"); + glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load("glGenTransformFeedbacks"); + glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load("glIsTransformFeedback"); + glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load("glPauseTransformFeedback"); + glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load("glResumeTransformFeedback"); + glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)load("glDrawTransformFeedback"); + glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)load("glDrawTransformFeedbackStream"); + glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC)load("glBeginQueryIndexed"); + glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC)load("glEndQueryIndexed"); + glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC)load("glGetQueryIndexediv"); +} +static void load_GL_VERSION_4_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_4_1) return; + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); + glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load("glGetProgramBinary"); + glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load("glProgramBinary"); + glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri"); + glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load("glUseProgramStages"); + glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load("glActiveShaderProgram"); + glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load("glCreateShaderProgramv"); + glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load("glBindProgramPipeline"); + glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load("glDeleteProgramPipelines"); + glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load("glGenProgramPipelines"); + glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load("glIsProgramPipeline"); + glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load("glGetProgramPipelineiv"); + glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri"); + glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load("glProgramUniform1i"); + glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load("glProgramUniform1iv"); + glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load("glProgramUniform1f"); + glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load("glProgramUniform1fv"); + glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC)load("glProgramUniform1d"); + glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC)load("glProgramUniform1dv"); + glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load("glProgramUniform1ui"); + glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load("glProgramUniform1uiv"); + glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load("glProgramUniform2i"); + glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load("glProgramUniform2iv"); + glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load("glProgramUniform2f"); + glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load("glProgramUniform2fv"); + glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC)load("glProgramUniform2d"); + glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC)load("glProgramUniform2dv"); + glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load("glProgramUniform2ui"); + glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load("glProgramUniform2uiv"); + glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load("glProgramUniform3i"); + glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load("glProgramUniform3iv"); + glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load("glProgramUniform3f"); + glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load("glProgramUniform3fv"); + glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC)load("glProgramUniform3d"); + glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC)load("glProgramUniform3dv"); + glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load("glProgramUniform3ui"); + glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load("glProgramUniform3uiv"); + glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load("glProgramUniform4i"); + glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load("glProgramUniform4iv"); + glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load("glProgramUniform4f"); + glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load("glProgramUniform4fv"); + glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC)load("glProgramUniform4d"); + glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC)load("glProgramUniform4dv"); + glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load("glProgramUniform4ui"); + glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load("glProgramUniform4uiv"); + glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load("glProgramUniformMatrix2fv"); + glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load("glProgramUniformMatrix3fv"); + glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load("glProgramUniformMatrix4fv"); + glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC)load("glProgramUniformMatrix2dv"); + glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC)load("glProgramUniformMatrix3dv"); + glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC)load("glProgramUniformMatrix4dv"); + glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load("glProgramUniformMatrix2x3fv"); + glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load("glProgramUniformMatrix3x2fv"); + glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load("glProgramUniformMatrix2x4fv"); + glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load("glProgramUniformMatrix4x2fv"); + glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load("glProgramUniformMatrix3x4fv"); + glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load("glProgramUniformMatrix4x3fv"); + glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)load("glProgramUniformMatrix2x3dv"); + glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)load("glProgramUniformMatrix3x2dv"); + glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)load("glProgramUniformMatrix2x4dv"); + glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)load("glProgramUniformMatrix4x2dv"); + glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)load("glProgramUniformMatrix3x4dv"); + glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)load("glProgramUniformMatrix4x3dv"); + glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load("glValidateProgramPipeline"); + glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load("glGetProgramPipelineInfoLog"); + glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC)load("glVertexAttribL1d"); + glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC)load("glVertexAttribL2d"); + glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC)load("glVertexAttribL3d"); + glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC)load("glVertexAttribL4d"); + glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC)load("glVertexAttribL1dv"); + glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC)load("glVertexAttribL2dv"); + glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC)load("glVertexAttribL3dv"); + glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC)load("glVertexAttribL4dv"); + glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)load("glVertexAttribLPointer"); + glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC)load("glGetVertexAttribLdv"); + glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)load("glViewportArrayv"); + glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC)load("glViewportIndexedf"); + glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC)load("glViewportIndexedfv"); + glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC)load("glScissorArrayv"); + glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC)load("glScissorIndexed"); + glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC)load("glScissorIndexedv"); + glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)load("glDepthRangeArrayv"); + glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC)load("glDepthRangeIndexed"); + glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC)load("glGetFloati_v"); + glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC)load("glGetDoublei_v"); +} +static void load_GL_ARB_framebuffer_object(GLADloadproc load) { + if(!GLAD_GL_ARB_framebuffer_object) return; + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); +} +static void load_GL_ARB_vertex_array_object(GLADloadproc load) { + if(!GLAD_GL_ARB_vertex_array_object) return; + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_EXT_framebuffer_blit(GLADloadproc load) { + if(!GLAD_GL_EXT_framebuffer_blit) return; + glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC)load("glBlitFramebufferEXT"); +} +static void load_GL_EXT_framebuffer_multisample(GLADloadproc load) { + if(!GLAD_GL_EXT_framebuffer_multisample) return; + glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)load("glRenderbufferStorageMultisampleEXT"); +} +static void load_GL_EXT_framebuffer_object(GLADloadproc load) { + if(!GLAD_GL_EXT_framebuffer_object) return; + glad_glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)load("glIsRenderbufferEXT"); + glad_glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)load("glBindRenderbufferEXT"); + glad_glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)load("glDeleteRenderbuffersEXT"); + glad_glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)load("glGenRenderbuffersEXT"); + glad_glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)load("glRenderbufferStorageEXT"); + glad_glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)load("glGetRenderbufferParameterivEXT"); + glad_glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)load("glIsFramebufferEXT"); + glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)load("glBindFramebufferEXT"); + glad_glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)load("glDeleteFramebuffersEXT"); + glad_glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)load("glGenFramebuffersEXT"); + glad_glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)load("glCheckFramebufferStatusEXT"); + glad_glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)load("glFramebufferTexture1DEXT"); + glad_glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)load("glFramebufferTexture2DEXT"); + glad_glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)load("glFramebufferTexture3DEXT"); + glad_glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)load("glFramebufferRenderbufferEXT"); + glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT"); + glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT"); +} +static void load_GL_EXT_gpu_shader4(GLADloadproc load) { + if(!GLAD_GL_EXT_gpu_shader4) return; + glad_glGetUniformuivEXT = (PFNGLGETUNIFORMUIVEXTPROC)load("glGetUniformuivEXT"); + glad_glBindFragDataLocationEXT = (PFNGLBINDFRAGDATALOCATIONEXTPROC)load("glBindFragDataLocationEXT"); + glad_glGetFragDataLocationEXT = (PFNGLGETFRAGDATALOCATIONEXTPROC)load("glGetFragDataLocationEXT"); + glad_glUniform1uiEXT = (PFNGLUNIFORM1UIEXTPROC)load("glUniform1uiEXT"); + glad_glUniform2uiEXT = (PFNGLUNIFORM2UIEXTPROC)load("glUniform2uiEXT"); + glad_glUniform3uiEXT = (PFNGLUNIFORM3UIEXTPROC)load("glUniform3uiEXT"); + glad_glUniform4uiEXT = (PFNGLUNIFORM4UIEXTPROC)load("glUniform4uiEXT"); + glad_glUniform1uivEXT = (PFNGLUNIFORM1UIVEXTPROC)load("glUniform1uivEXT"); + glad_glUniform2uivEXT = (PFNGLUNIFORM2UIVEXTPROC)load("glUniform2uivEXT"); + glad_glUniform3uivEXT = (PFNGLUNIFORM3UIVEXTPROC)load("glUniform3uivEXT"); + glad_glUniform4uivEXT = (PFNGLUNIFORM4UIVEXTPROC)load("glUniform4uivEXT"); + glad_glVertexAttribI1iEXT = (PFNGLVERTEXATTRIBI1IEXTPROC)load("glVertexAttribI1iEXT"); + glad_glVertexAttribI2iEXT = (PFNGLVERTEXATTRIBI2IEXTPROC)load("glVertexAttribI2iEXT"); + glad_glVertexAttribI3iEXT = (PFNGLVERTEXATTRIBI3IEXTPROC)load("glVertexAttribI3iEXT"); + glad_glVertexAttribI4iEXT = (PFNGLVERTEXATTRIBI4IEXTPROC)load("glVertexAttribI4iEXT"); + glad_glVertexAttribI1uiEXT = (PFNGLVERTEXATTRIBI1UIEXTPROC)load("glVertexAttribI1uiEXT"); + glad_glVertexAttribI2uiEXT = (PFNGLVERTEXATTRIBI2UIEXTPROC)load("glVertexAttribI2uiEXT"); + glad_glVertexAttribI3uiEXT = (PFNGLVERTEXATTRIBI3UIEXTPROC)load("glVertexAttribI3uiEXT"); + glad_glVertexAttribI4uiEXT = (PFNGLVERTEXATTRIBI4UIEXTPROC)load("glVertexAttribI4uiEXT"); + glad_glVertexAttribI1ivEXT = (PFNGLVERTEXATTRIBI1IVEXTPROC)load("glVertexAttribI1ivEXT"); + glad_glVertexAttribI2ivEXT = (PFNGLVERTEXATTRIBI2IVEXTPROC)load("glVertexAttribI2ivEXT"); + glad_glVertexAttribI3ivEXT = (PFNGLVERTEXATTRIBI3IVEXTPROC)load("glVertexAttribI3ivEXT"); + glad_glVertexAttribI4ivEXT = (PFNGLVERTEXATTRIBI4IVEXTPROC)load("glVertexAttribI4ivEXT"); + glad_glVertexAttribI1uivEXT = (PFNGLVERTEXATTRIBI1UIVEXTPROC)load("glVertexAttribI1uivEXT"); + glad_glVertexAttribI2uivEXT = (PFNGLVERTEXATTRIBI2UIVEXTPROC)load("glVertexAttribI2uivEXT"); + glad_glVertexAttribI3uivEXT = (PFNGLVERTEXATTRIBI3UIVEXTPROC)load("glVertexAttribI3uivEXT"); + glad_glVertexAttribI4uivEXT = (PFNGLVERTEXATTRIBI4UIVEXTPROC)load("glVertexAttribI4uivEXT"); + glad_glVertexAttribI4bvEXT = (PFNGLVERTEXATTRIBI4BVEXTPROC)load("glVertexAttribI4bvEXT"); + glad_glVertexAttribI4svEXT = (PFNGLVERTEXATTRIBI4SVEXTPROC)load("glVertexAttribI4svEXT"); + glad_glVertexAttribI4ubvEXT = (PFNGLVERTEXATTRIBI4UBVEXTPROC)load("glVertexAttribI4ubvEXT"); + glad_glVertexAttribI4usvEXT = (PFNGLVERTEXATTRIBI4USVEXTPROC)load("glVertexAttribI4usvEXT"); + glad_glVertexAttribIPointerEXT = (PFNGLVERTEXATTRIBIPOINTEREXTPROC)load("glVertexAttribIPointerEXT"); + glad_glGetVertexAttribIivEXT = (PFNGLGETVERTEXATTRIBIIVEXTPROC)load("glGetVertexAttribIivEXT"); + glad_glGetVertexAttribIuivEXT = (PFNGLGETVERTEXATTRIBIUIVEXTPROC)load("glGetVertexAttribIuivEXT"); +} +static void load_GL_KHR_debug(GLADloadproc load) { + if(!GLAD_GL_KHR_debug) return; + glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl"); + glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert"); + glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback"); + glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog"); + glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup"); + glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup"); + glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel"); + glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel"); + glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel"); + glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel"); + glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); + glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC)load("glDebugMessageControlKHR"); + glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC)load("glDebugMessageInsertKHR"); + glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC)load("glDebugMessageCallbackKHR"); + glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC)load("glGetDebugMessageLogKHR"); + glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC)load("glPushDebugGroupKHR"); + glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC)load("glPopDebugGroupKHR"); + glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC)load("glObjectLabelKHR"); + glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC)load("glGetObjectLabelKHR"); + glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC)load("glObjectPtrLabelKHR"); + glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC)load("glGetObjectPtrLabelKHR"); + glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC)load("glGetPointervKHR"); +} +static int find_extensionsGL(void) { + if (!get_exts()) return 0; + GLAD_GL_ARB_depth_clamp = has_ext("GL_ARB_depth_clamp"); + GLAD_GL_ARB_framebuffer_object = has_ext("GL_ARB_framebuffer_object"); + GLAD_GL_ARB_texture_filter_anisotropic = has_ext("GL_ARB_texture_filter_anisotropic"); + GLAD_GL_ARB_texture_mirror_clamp_to_edge = has_ext("GL_ARB_texture_mirror_clamp_to_edge"); + GLAD_GL_ARB_vertex_array_object = has_ext("GL_ARB_vertex_array_object"); + GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit"); + GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample"); + GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object"); + GLAD_GL_EXT_gpu_shader4 = has_ext("GL_EXT_gpu_shader4"); + GLAD_GL_EXT_texture_filter_anisotropic = has_ext("GL_EXT_texture_filter_anisotropic"); + GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); + GLAD_GL_NV_depth_clamp = has_ext("GL_NV_depth_clamp"); + free_exts(); + return 1; +} + +static void find_coreGL(void) { + + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; + GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; + GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4; + GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4; + if (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 1)) { + max_loaded_major = 4; + max_loaded_minor = 1; + } +} + +int gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + load_GL_VERSION_3_3(load); + load_GL_VERSION_4_0(load); + load_GL_VERSION_4_1(load); + + if (!find_extensionsGL()) return 0; + load_GL_ARB_framebuffer_object(load); + load_GL_ARB_vertex_array_object(load); + load_GL_EXT_framebuffer_blit(load); + load_GL_EXT_framebuffer_multisample(load); + load_GL_EXT_framebuffer_object(load); + load_GL_EXT_gpu_shader4(load); + load_GL_KHR_debug(load); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + +static void load_GL_ES_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_ES_VERSION_2_0) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static void load_GL_ES_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_ES_VERSION_3_0) return; + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); + glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); + glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); + glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); + glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); + glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); + glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); + glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); + glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); + glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); + glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); + glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load("glBindTransformFeedback"); + glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load("glDeleteTransformFeedbacks"); + glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load("glGenTransformFeedbacks"); + glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load("glIsTransformFeedback"); + glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load("glPauseTransformFeedback"); + glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load("glResumeTransformFeedback"); + glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load("glGetProgramBinary"); + glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load("glProgramBinary"); + glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri"); + glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load("glInvalidateFramebuffer"); + glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load("glInvalidateSubFramebuffer"); + glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load("glTexStorage2D"); + glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load("glTexStorage3D"); + glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load("glGetInternalformativ"); +} +static void load_GL_APPLE_framebuffer_multisample(GLADloadproc load) { + if(!GLAD_GL_APPLE_framebuffer_multisample) return; + glad_glRenderbufferStorageMultisampleAPPLE = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC)load("glRenderbufferStorageMultisampleAPPLE"); + glad_glResolveMultisampleFramebufferAPPLE = (PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC)load("glResolveMultisampleFramebufferAPPLE"); +} +static void load_GL_NV_framebuffer_multisample(GLADloadproc load) { + if(!GLAD_GL_NV_framebuffer_multisample) return; + glad_glRenderbufferStorageMultisampleNV = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC)load("glRenderbufferStorageMultisampleNV"); +} +static int find_extensionsGLES2(void) { + if (!get_exts()) return 0; + GLAD_GL_APPLE_framebuffer_multisample = has_ext("GL_APPLE_framebuffer_multisample"); + GLAD_GL_EXT_depth_clamp = has_ext("GL_EXT_depth_clamp"); + GLAD_GL_EXT_texture_filter_anisotropic = has_ext("GL_EXT_texture_filter_anisotropic"); + GLAD_GL_EXT_texture_mirror_clamp_to_edge = has_ext("GL_EXT_texture_mirror_clamp_to_edge"); + GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); + GLAD_GL_NV_framebuffer_multisample = has_ext("GL_NV_framebuffer_multisample"); + free_exts(); + return 1; +} + +static void find_coreGLES2(void) { + + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_ES_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 0)) { + max_loaded_major = 3; + max_loaded_minor = 0; + } +} + +int gladLoadGLES2Loader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGLES2(); + load_GL_ES_VERSION_2_0(load); + load_GL_ES_VERSION_3_0(load); + + if (!find_extensionsGLES2()) return 0; + load_GL_APPLE_framebuffer_multisample(load); + load_GL_KHR_debug(load); + load_GL_NV_framebuffer_multisample(load); + return GLVersion.major != 0 || GLVersion.minor != 0; +} + diff --git a/port/fast3d/glad/glad.h b/port/fast3d/glad/glad.h new file mode 100644 index 00000000..2d2ed8bb --- /dev/null +++ b/port/fast3d/glad/glad.h @@ -0,0 +1,3222 @@ +/* + + OpenGL, OpenGL ES loader generated by glad 0.1.36 on Wed Oct 8 13:10:56 2025. + + Language/Generator: C/C++ + Specification: gl + APIs: gl=4.1, gles2=3.0 + Profile: core + Extensions: + GL_APPLE_framebuffer_multisample, + GL_ARB_depth_clamp, + GL_ARB_framebuffer_object, + GL_ARB_texture_filter_anisotropic, + GL_ARB_texture_mirror_clamp_to_edge, + GL_ARB_vertex_array_object, + GL_EXT_depth_clamp, + GL_EXT_framebuffer_blit, + GL_EXT_framebuffer_multisample, + GL_EXT_framebuffer_object, + GL_EXT_gpu_shader4, + GL_EXT_texture_filter_anisotropic, + GL_EXT_texture_mirror_clamp_to_edge, + GL_KHR_debug, + GL_NV_depth_clamp, + GL_NV_framebuffer_multisample + Loader: False + Local files: True + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="core" --api="gl=4.1,gles2=3.0" --generator="c" --spec="gl" --no-loader --local-files --extensions="GL_APPLE_framebuffer_multisample,GL_ARB_depth_clamp,GL_ARB_framebuffer_object,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_vertex_array_object,GL_EXT_depth_clamp,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_gpu_shader4,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_mirror_clamp_to_edge,GL_KHR_debug,GL_NV_depth_clamp,GL_NV_framebuffer_multisample" + Online: + https://glad.dav1d.de/#profile=core&language=c&specification=gl&api=gl%3D4.1&api=gles2%3D3.0&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_texture_filter_anisotropic&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_vertex_array_object&extensions=GL_EXT_depth_clamp&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_mirror_clamp_to_edge&extensions=GL_KHR_debug&extensions=GL_NV_depth_clamp&extensions=GL_NV_framebuffer_multisample +*/ + + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl_h_ +#error OpenGL header already included, remove this include, glad already provides it +#endif +#define __gl_h_ + +#ifdef __gl2_h_ +#error OpenGL ES 2 header already included, remove this include, glad already provides it +#endif +#define __gl2_h_ + +#ifdef __gl3_h_ +#error OpenGL ES 3 header already included, remove this include, glad already provides it +#endif +#define __gl3_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define APIENTRY __stdcall +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(_WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI struct gladGLversionStruct GLVersion; +GLAPI int gladLoadGLLoader(GLADloadproc); + +GLAPI int gladLoadGLES2Loader(GLADloadproc); + +#include "khrplatform.h" +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +typedef khronos_intptr_t GLintptr; +typedef khronos_intptr_t GLintptrARB; +typedef khronos_ssize_t GLsizeiptr; +typedef khronos_ssize_t GLsizeiptrARB; +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (APIENTRY *GLVULKANPROCNV)(void); +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_REPEAT 0x2901 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DOUBLE 0x140A +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_QUADS 0x0007 +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(void); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(void); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +GLAPI int GLAD_GL_VERSION_3_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); +GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); +GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +#endif +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +GLAPI int GLAD_GL_VERSION_3_2; +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); +GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); +GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); +GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); +GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); +GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +#endif +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +GLAPI int GLAD_GL_VERSION_3_3; +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; +#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; +#define glGetFragDataIndex glad_glGetFragDataIndex +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers); +GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers; +#define glGenSamplers glad_glGenSamplers +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers); +GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; +#define glDeleteSamplers glad_glDeleteSamplers +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); +GLAPI PFNGLISSAMPLERPROC glad_glIsSampler; +#define glIsSampler glad_glIsSampler +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); +GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler; +#define glBindSampler glad_glBindSampler +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); +GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; +#define glSamplerParameteri glad_glSamplerParameteri +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param); +GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; +#define glSamplerParameteriv glad_glSamplerParameteriv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); +GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; +#define glSamplerParameterf glad_glSamplerParameterf +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; +#define glSamplerParameterfv glad_glSamplerParameterfv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param); +GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; +#define glSamplerParameterIiv glad_glSamplerParameterIiv +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param); +GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; +#define glSamplerParameterIuiv glad_glSamplerParameterIuiv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params); +GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; +#define glGetSamplerParameteriv glad_glGetSamplerParameteriv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params); +GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; +#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params); +GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; +#define glGetSamplerParameterfv glad_glGetSamplerParameterfv +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params); +GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; +#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); +GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter; +#define glQueryCounter glad_glQueryCounter +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params); +GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; +#define glGetQueryObjecti64v glad_glGetQueryObjecti64v +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params); +GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; +#define glGetQueryObjectui64v glad_glGetQueryObjectui64v +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); +GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; +#define glVertexAttribDivisor glad_glVertexAttribDivisor +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; +#define glVertexAttribP1ui glad_glVertexAttribP1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; +#define glVertexAttribP1uiv glad_glVertexAttribP1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; +#define glVertexAttribP2ui glad_glVertexAttribP2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; +#define glVertexAttribP2uiv glad_glVertexAttribP2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; +#define glVertexAttribP3ui glad_glVertexAttribP3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; +#define glVertexAttribP3uiv glad_glVertexAttribP3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; +#define glVertexAttribP4ui glad_glVertexAttribP4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; +#define glVertexAttribP4uiv glad_glVertexAttribP4uiv +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui; +#define glVertexP2ui glad_glVertexP2ui +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value); +GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; +#define glVertexP2uiv glad_glVertexP2uiv +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui; +#define glVertexP3ui glad_glVertexP3ui +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value); +GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; +#define glVertexP3uiv glad_glVertexP3uiv +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); +GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui; +#define glVertexP4ui glad_glVertexP4ui +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value); +GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; +#define glVertexP4uiv glad_glVertexP4uiv +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; +#define glTexCoordP1ui glad_glTexCoordP1ui +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; +#define glTexCoordP1uiv glad_glTexCoordP1uiv +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; +#define glTexCoordP2ui glad_glTexCoordP2ui +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; +#define glTexCoordP2uiv glad_glTexCoordP2uiv +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; +#define glTexCoordP3ui glad_glTexCoordP3ui +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; +#define glTexCoordP3uiv glad_glTexCoordP3uiv +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; +#define glTexCoordP4ui glad_glTexCoordP4ui +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; +#define glTexCoordP4uiv glad_glTexCoordP4uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; +#define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; +#define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; +#define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; +#define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; +#define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; +#define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); +GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; +#define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); +GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; +#define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv +typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); +GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui; +#define glNormalP3ui glad_glNormalP3ui +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords); +GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; +#define glNormalP3uiv glad_glNormalP3uiv +typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui; +#define glColorP3ui glad_glColorP3ui +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color); +GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv; +#define glColorP3uiv glad_glColorP3uiv +typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui; +#define glColorP4ui glad_glColorP4ui +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color); +GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv; +#define glColorP4uiv glad_glColorP4uiv +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); +GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; +#define glSecondaryColorP3ui glad_glSecondaryColorP3ui +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color); +GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; +#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv +#endif +#ifndef GL_VERSION_4_0 +#define GL_VERSION_4_0 1 +GLAPI int GLAD_GL_VERSION_4_0; +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC)(GLfloat value); +GLAPI PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading; +#define glMinSampleShading glad_glMinSampleShading +typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode); +GLAPI PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi; +#define glBlendEquationi glad_glBlendEquationi +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei; +#define glBlendEquationSeparatei glad_glBlendEquationSeparatei +typedef void (APIENTRYP PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst); +GLAPI PFNGLBLENDFUNCIPROC glad_glBlendFunci; +#define glBlendFunci glad_glBlendFunci +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei; +#define glBlendFuncSeparatei glad_glBlendFuncSeparatei +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect); +GLAPI PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect; +#define glDrawArraysIndirect glad_glDrawArraysIndirect +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect); +GLAPI PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect; +#define glDrawElementsIndirect glad_glDrawElementsIndirect +typedef void (APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x); +GLAPI PFNGLUNIFORM1DPROC glad_glUniform1d; +#define glUniform1d glad_glUniform1d +typedef void (APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y); +GLAPI PFNGLUNIFORM2DPROC glad_glUniform2d; +#define glUniform2d glad_glUniform2d +typedef void (APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLUNIFORM3DPROC glad_glUniform3d; +#define glUniform3d glad_glUniform3d +typedef void (APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLUNIFORM4DPROC glad_glUniform4d; +#define glUniform4d glad_glUniform4d +typedef void (APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLUNIFORM1DVPROC glad_glUniform1dv; +#define glUniform1dv glad_glUniform1dv +typedef void (APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLUNIFORM2DVPROC glad_glUniform2dv; +#define glUniform2dv glad_glUniform2dv +typedef void (APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLUNIFORM3DVPROC glad_glUniform3dv; +#define glUniform3dv glad_glUniform3dv +typedef void (APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLUNIFORM4DVPROC glad_glUniform4dv; +#define glUniform4dv glad_glUniform4dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv; +#define glUniformMatrix2dv glad_glUniformMatrix2dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv; +#define glUniformMatrix3dv glad_glUniformMatrix3dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv; +#define glUniformMatrix4dv glad_glUniformMatrix4dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv; +#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv; +#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv; +#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv; +#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv; +#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv; +#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv +typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble *params); +GLAPI PFNGLGETUNIFORMDVPROC glad_glGetUniformdv; +#define glGetUniformdv glad_glGetUniformdv +typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar *name); +GLAPI PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation; +#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation +typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar *name); +GLAPI PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex; +#define glGetSubroutineIndex glad_glGetSubroutineIndex +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv; +#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName; +#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName; +#define glGetActiveSubroutineName glad_glGetActiveSubroutineName +typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint *indices); +GLAPI PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv; +#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv +typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint *params); +GLAPI PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv; +#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv +typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint *values); +GLAPI PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv; +#define glGetProgramStageiv glad_glGetProgramStageiv +typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value); +GLAPI PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri; +#define glPatchParameteri glad_glPatchParameteri +typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat *values); +GLAPI PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv; +#define glPatchParameterfv glad_glPatchParameterfv +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id); +GLAPI PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback; +#define glBindTransformFeedback glad_glBindTransformFeedback +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint *ids); +GLAPI PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks; +#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids); +GLAPI PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks; +#define glGenTransformFeedbacks glad_glGenTransformFeedbacks +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id); +GLAPI PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback; +#define glIsTransformFeedback glad_glIsTransformFeedback +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void); +GLAPI PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback; +#define glPauseTransformFeedback glad_glPauseTransformFeedback +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void); +GLAPI PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback; +#define glResumeTransformFeedback glad_glResumeTransformFeedback +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id); +GLAPI PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback; +#define glDrawTransformFeedback glad_glDrawTransformFeedback +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream); +GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream; +#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream +typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id); +GLAPI PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed; +#define glBeginQueryIndexed glad_glBeginQueryIndexed +typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index); +GLAPI PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed; +#define glEndQueryIndexed glad_glEndQueryIndexed +typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv; +#define glGetQueryIndexediv glad_glGetQueryIndexediv +#endif +#ifndef GL_VERSION_4_1 +#define GL_VERSION_4_1 1 +GLAPI int GLAD_GL_VERSION_4_1; +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void); +GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +#define glReleaseShaderCompiler glad_glReleaseShaderCompiler +typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary; +#define glShaderBinary glad_glShaderBinary +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d); +GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GLAPI PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary; +#define glGetProgramBinary glad_glGetProgramBinary +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI PFNGLPROGRAMBINARYPROC glad_glProgramBinary; +#define glProgramBinary glad_glProgramBinary +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); +GLAPI PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri; +#define glProgramParameteri glad_glProgramParameteri +typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages; +#define glUseProgramStages glad_glUseProgramStages +typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program); +GLAPI PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram; +#define glActiveShaderProgram glad_glActiveShaderProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const*strings); +GLAPI PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv; +#define glCreateShaderProgramv glad_glCreateShaderProgramv +typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline); +GLAPI PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline; +#define glBindProgramPipeline glad_glBindProgramPipeline +typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint *pipelines); +GLAPI PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines; +#define glDeleteProgramPipelines glad_glDeleteProgramPipelines +typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines); +GLAPI PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines; +#define glGenProgramPipelines glad_glGenProgramPipelines +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline); +GLAPI PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline; +#define glIsProgramPipeline glad_glIsProgramPipeline +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv; +#define glGetProgramPipelineiv glad_glGetProgramPipelineiv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0); +GLAPI PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i; +#define glProgramUniform1i glad_glProgramUniform1i +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv; +#define glProgramUniform1iv glad_glProgramUniform1iv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0); +GLAPI PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f; +#define glProgramUniform1f glad_glProgramUniform1f +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv; +#define glProgramUniform1fv glad_glProgramUniform1fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0); +GLAPI PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d; +#define glProgramUniform1d glad_glProgramUniform1d +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv; +#define glProgramUniform1dv glad_glProgramUniform1dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0); +GLAPI PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui; +#define glProgramUniform1ui glad_glProgramUniform1ui +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv; +#define glProgramUniform1uiv glad_glProgramUniform1uiv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1); +GLAPI PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i; +#define glProgramUniform2i glad_glProgramUniform2i +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv; +#define glProgramUniform2iv glad_glProgramUniform2iv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f; +#define glProgramUniform2f glad_glProgramUniform2f +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv; +#define glProgramUniform2fv glad_glProgramUniform2fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d; +#define glProgramUniform2d glad_glProgramUniform2d +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv; +#define glProgramUniform2dv glad_glProgramUniform2dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui; +#define glProgramUniform2ui glad_glProgramUniform2ui +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv; +#define glProgramUniform2uiv glad_glProgramUniform2uiv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i; +#define glProgramUniform3i glad_glProgramUniform3i +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv; +#define glProgramUniform3iv glad_glProgramUniform3iv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f; +#define glProgramUniform3f glad_glProgramUniform3f +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv; +#define glProgramUniform3fv glad_glProgramUniform3fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d; +#define glProgramUniform3d glad_glProgramUniform3d +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv; +#define glProgramUniform3dv glad_glProgramUniform3dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui; +#define glProgramUniform3ui glad_glProgramUniform3ui +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv; +#define glProgramUniform3uiv glad_glProgramUniform3uiv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i; +#define glProgramUniform4i glad_glProgramUniform4i +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv; +#define glProgramUniform4iv glad_glProgramUniform4iv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f; +#define glProgramUniform4f glad_glProgramUniform4f +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv; +#define glProgramUniform4fv glad_glProgramUniform4fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d; +#define glProgramUniform4d glad_glProgramUniform4d +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv; +#define glProgramUniform4dv glad_glProgramUniform4dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui; +#define glProgramUniform4ui glad_glProgramUniform4ui +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv; +#define glProgramUniform4uiv glad_glProgramUniform4uiv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv; +#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv; +#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv; +#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv; +#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv; +#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv; +#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv; +#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv; +#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv; +#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv; +#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv; +#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv; +#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv; +#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv; +#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv; +#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv; +#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv; +#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv; +#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline); +GLAPI PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline; +#define glValidateProgramPipeline glad_glValidateProgramPipeline +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog; +#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x); +GLAPI PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d; +#define glVertexAttribL1d glad_glVertexAttribL1d +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y); +GLAPI PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d; +#define glVertexAttribL2d glad_glVertexAttribL2d +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d; +#define glVertexAttribL3d glad_glVertexAttribL3d +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d; +#define glVertexAttribL4d glad_glVertexAttribL4d +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv; +#define glVertexAttribL1dv glad_glVertexAttribL1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv; +#define glVertexAttribL2dv glad_glVertexAttribL2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv; +#define glVertexAttribL3dv glad_glVertexAttribL3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble *v); +GLAPI PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv; +#define glVertexAttribL4dv glad_glVertexAttribL4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer; +#define glVertexAttribLPointer glad_glVertexAttribLPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble *params); +GLAPI PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv; +#define glGetVertexAttribLdv glad_glGetVertexAttribLdv +typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat *v); +GLAPI PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv; +#define glViewportArrayv glad_glViewportArrayv +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf; +#define glViewportIndexedf glad_glViewportIndexedf +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv; +#define glViewportIndexedfv glad_glViewportIndexedfv +typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint *v); +GLAPI PFNGLSCISSORARRAYVPROC glad_glScissorArrayv; +#define glScissorArrayv glad_glScissorArrayv +typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed; +#define glScissorIndexed glad_glScissorIndexed +typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint *v); +GLAPI PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv; +#define glScissorIndexedv glad_glScissorIndexedv +typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble *v); +GLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv; +#define glDepthRangeArrayv glad_glDepthRangeArrayv +typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f); +GLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed; +#define glDepthRangeIndexed glad_glDepthRangeIndexed +typedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data); +GLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v; +#define glGetFloati_v glad_glGetFloati_v +typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble *data); +GLAPI PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v; +#define glGetDoublei_v glad_glGetDoublei_v +#endif +#ifndef GL_ES_VERSION_2_0 +#define GL_ES_VERSION_2_0 1 +GLAPI int GLAD_GL_ES_VERSION_2_0; +#endif +#ifndef GL_ES_VERSION_3_0 +#define GL_ES_VERSION_3_0 1 +GLAPI int GLAD_GL_ES_VERSION_3_0; +typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments); +GLAPI PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer; +#define glInvalidateFramebuffer glad_glInvalidateFramebuffer +typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer; +#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer +typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D; +#define glTexStorage2D glad_glTexStorage2D +typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D; +#define glTexStorage3D glad_glTexStorage3D +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); +GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ; +#define glGetInternalformativ glad_glGetInternalformativ +#endif +#define GL_INDEX 0x8222 +#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define GL_INT_SAMPLER_2D_EXT 0x8DCA +#define GL_INT_SAMPLER_3D_EXT 0x8DCB +#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 +#define GL_DEBUG_SOURCE_API_KHR 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A +#define GL_DEBUG_SOURCE_OTHER_KHR 0x824B +#define GL_DEBUG_TYPE_ERROR_KHR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 +#define GL_DEBUG_TYPE_OTHER_KHR 0x8251 +#define GL_DEBUG_TYPE_MARKER_KHR 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D +#define GL_BUFFER_KHR 0x82E0 +#define GL_SHADER_KHR 0x82E1 +#define GL_PROGRAM_KHR 0x82E2 +#define GL_VERTEX_ARRAY_KHR 0x8074 +#define GL_QUERY_KHR 0x82E3 +#define GL_PROGRAM_PIPELINE_KHR 0x82E4 +#define GL_SAMPLER_KHR 0x82E6 +#define GL_MAX_LABEL_LENGTH_KHR 0x82E8 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 +#define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 +#define GL_DEBUG_OUTPUT_KHR 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 +#define GL_STACK_OVERFLOW_KHR 0x0503 +#define GL_STACK_UNDERFLOW_KHR 0x0504 +#define GL_DISPLAY_LIST 0x82E7 +#define GL_DEPTH_CLAMP_NV 0x864F +#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56 +#define GL_MAX_SAMPLES_APPLE 0x8D57 +#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA +#define GL_DEPTH_CLAMP_EXT 0x864F +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_RENDERBUFFER_SAMPLES_NV 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV 0x8D56 +#define GL_MAX_SAMPLES_NV 0x8D57 +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +GLAPI int GLAD_GL_ARB_depth_clamp; +#endif +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +GLAPI int GLAD_GL_ARB_framebuffer_object; +#endif +#ifndef GL_ARB_texture_filter_anisotropic +#define GL_ARB_texture_filter_anisotropic 1 +GLAPI int GLAD_GL_ARB_texture_filter_anisotropic; +#endif +#ifndef GL_ARB_texture_mirror_clamp_to_edge +#define GL_ARB_texture_mirror_clamp_to_edge 1 +GLAPI int GLAD_GL_ARB_texture_mirror_clamp_to_edge; +#endif +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +GLAPI int GLAD_GL_ARB_vertex_array_object; +#endif +#ifndef GL_EXT_framebuffer_blit +#define GL_EXT_framebuffer_blit 1 +GLAPI int GLAD_GL_EXT_framebuffer_blit; +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI PFNGLBLITFRAMEBUFFEREXTPROC glad_glBlitFramebufferEXT; +#define glBlitFramebufferEXT glad_glBlitFramebufferEXT +#endif +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +GLAPI int GLAD_GL_EXT_framebuffer_multisample; +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT; +#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT +#endif +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +GLAPI int GLAD_GL_EXT_framebuffer_object; +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFEREXTPROC glad_glIsRenderbufferEXT; +#define glIsRenderbufferEXT glad_glIsRenderbufferEXT +typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFEREXTPROC glad_glBindRenderbufferEXT; +#define glBindRenderbufferEXT glad_glBindRenderbufferEXT +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSEXTPROC glad_glDeleteRenderbuffersEXT; +#define glDeleteRenderbuffersEXT glad_glDeleteRenderbuffersEXT +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSEXTPROC glad_glGenRenderbuffersEXT; +#define glGenRenderbuffersEXT glad_glGenRenderbuffersEXT +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT; +#define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glad_glGetRenderbufferParameterivEXT; +#define glGetRenderbufferParameterivEXT glad_glGetRenderbufferParameterivEXT +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFEREXTPROC glad_glIsFramebufferEXT; +#define glIsFramebufferEXT glad_glIsFramebufferEXT +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFEREXTPROC glad_glBindFramebufferEXT; +#define glBindFramebufferEXT glad_glBindFramebufferEXT +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSEXTPROC glad_glDeleteFramebuffersEXT; +#define glDeleteFramebuffersEXT glad_glDeleteFramebuffersEXT +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSEXTPROC glad_glGenFramebuffersEXT; +#define glGenFramebuffersEXT glad_glGenFramebuffersEXT +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glad_glCheckFramebufferStatusEXT; +#define glCheckFramebufferStatusEXT glad_glCheckFramebufferStatusEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glad_glFramebufferTexture1DEXT; +#define glFramebufferTexture1DEXT glad_glFramebufferTexture1DEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glad_glFramebufferTexture2DEXT; +#define glFramebufferTexture2DEXT glad_glFramebufferTexture2DEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT; +#define glFramebufferTexture3DEXT glad_glFramebufferTexture3DEXT +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT; +#define glFramebufferRenderbufferEXT glad_glFramebufferRenderbufferEXT +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT; +#define glGetFramebufferAttachmentParameterivEXT glad_glGetFramebufferAttachmentParameterivEXT +typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT; +#define glGenerateMipmapEXT glad_glGenerateMipmapEXT +#endif +#ifndef GL_EXT_gpu_shader4 +#define GL_EXT_gpu_shader4 1 +GLAPI int GLAD_GL_EXT_gpu_shader4; +typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC)(GLuint program, GLint location, GLuint *params); +GLAPI PFNGLGETUNIFORMUIVEXTPROC glad_glGetUniformuivEXT; +#define glGetUniformuivEXT glad_glGetUniformuivEXT +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC)(GLuint program, GLuint color, const GLchar *name); +GLAPI PFNGLBINDFRAGDATALOCATIONEXTPROC glad_glBindFragDataLocationEXT; +#define glBindFragDataLocationEXT glad_glBindFragDataLocationEXT +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETFRAGDATALOCATIONEXTPROC glad_glGetFragDataLocationEXT; +#define glGetFragDataLocationEXT glad_glGetFragDataLocationEXT +typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC)(GLint location, GLuint v0); +GLAPI PFNGLUNIFORM1UIEXTPROC glad_glUniform1uiEXT; +#define glUniform1uiEXT glad_glUniform1uiEXT +typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC)(GLint location, GLuint v0, GLuint v1); +GLAPI PFNGLUNIFORM2UIEXTPROC glad_glUniform2uiEXT; +#define glUniform2uiEXT glad_glUniform2uiEXT +typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI PFNGLUNIFORM3UIEXTPROC glad_glUniform3uiEXT; +#define glUniform3uiEXT glad_glUniform3uiEXT +typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI PFNGLUNIFORM4UIEXTPROC glad_glUniform4uiEXT; +#define glUniform4uiEXT glad_glUniform4uiEXT +typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM1UIVEXTPROC glad_glUniform1uivEXT; +#define glUniform1uivEXT glad_glUniform1uivEXT +typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM2UIVEXTPROC glad_glUniform2uivEXT; +#define glUniform2uivEXT glad_glUniform2uivEXT +typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM3UIVEXTPROC glad_glUniform3uivEXT; +#define glUniform3uivEXT glad_glUniform3uivEXT +typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC)(GLint location, GLsizei count, const GLuint *value); +GLAPI PFNGLUNIFORM4UIVEXTPROC glad_glUniform4uivEXT; +#define glUniform4uivEXT glad_glUniform4uivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC)(GLuint index, GLint x); +GLAPI PFNGLVERTEXATTRIBI1IEXTPROC glad_glVertexAttribI1iEXT; +#define glVertexAttribI1iEXT glad_glVertexAttribI1iEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC)(GLuint index, GLint x, GLint y); +GLAPI PFNGLVERTEXATTRIBI2IEXTPROC glad_glVertexAttribI2iEXT; +#define glVertexAttribI2iEXT glad_glVertexAttribI2iEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC)(GLuint index, GLint x, GLint y, GLint z); +GLAPI PFNGLVERTEXATTRIBI3IEXTPROC glad_glVertexAttribI3iEXT; +#define glVertexAttribI3iEXT glad_glVertexAttribI3iEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI PFNGLVERTEXATTRIBI4IEXTPROC glad_glVertexAttribI4iEXT; +#define glVertexAttribI4iEXT glad_glVertexAttribI4iEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC)(GLuint index, GLuint x); +GLAPI PFNGLVERTEXATTRIBI1UIEXTPROC glad_glVertexAttribI1uiEXT; +#define glVertexAttribI1uiEXT glad_glVertexAttribI1uiEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC)(GLuint index, GLuint x, GLuint y); +GLAPI PFNGLVERTEXATTRIBI2UIEXTPROC glad_glVertexAttribI2uiEXT; +#define glVertexAttribI2uiEXT glad_glVertexAttribI2uiEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI PFNGLVERTEXATTRIBI3UIEXTPROC glad_glVertexAttribI3uiEXT; +#define glVertexAttribI3uiEXT glad_glVertexAttribI3uiEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI PFNGLVERTEXATTRIBI4UIEXTPROC glad_glVertexAttribI4uiEXT; +#define glVertexAttribI4uiEXT glad_glVertexAttribI4uiEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI1IVEXTPROC glad_glVertexAttribI1ivEXT; +#define glVertexAttribI1ivEXT glad_glVertexAttribI1ivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI2IVEXTPROC glad_glVertexAttribI2ivEXT; +#define glVertexAttribI2ivEXT glad_glVertexAttribI2ivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI3IVEXTPROC glad_glVertexAttribI3ivEXT; +#define glVertexAttribI3ivEXT glad_glVertexAttribI3ivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC)(GLuint index, const GLint *v); +GLAPI PFNGLVERTEXATTRIBI4IVEXTPROC glad_glVertexAttribI4ivEXT; +#define glVertexAttribI4ivEXT glad_glVertexAttribI4ivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI1UIVEXTPROC glad_glVertexAttribI1uivEXT; +#define glVertexAttribI1uivEXT glad_glVertexAttribI1uivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI2UIVEXTPROC glad_glVertexAttribI2uivEXT; +#define glVertexAttribI2uivEXT glad_glVertexAttribI2uivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI3UIVEXTPROC glad_glVertexAttribI3uivEXT; +#define glVertexAttribI3uivEXT glad_glVertexAttribI3uivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC)(GLuint index, const GLuint *v); +GLAPI PFNGLVERTEXATTRIBI4UIVEXTPROC glad_glVertexAttribI4uivEXT; +#define glVertexAttribI4uivEXT glad_glVertexAttribI4uivEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC)(GLuint index, const GLbyte *v); +GLAPI PFNGLVERTEXATTRIBI4BVEXTPROC glad_glVertexAttribI4bvEXT; +#define glVertexAttribI4bvEXT glad_glVertexAttribI4bvEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC)(GLuint index, const GLshort *v); +GLAPI PFNGLVERTEXATTRIBI4SVEXTPROC glad_glVertexAttribI4svEXT; +#define glVertexAttribI4svEXT glad_glVertexAttribI4svEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC)(GLuint index, const GLubyte *v); +GLAPI PFNGLVERTEXATTRIBI4UBVEXTPROC glad_glVertexAttribI4ubvEXT; +#define glVertexAttribI4ubvEXT glad_glVertexAttribI4ubvEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC)(GLuint index, const GLushort *v); +GLAPI PFNGLVERTEXATTRIBI4USVEXTPROC glad_glVertexAttribI4usvEXT; +#define glVertexAttribI4usvEXT glad_glVertexAttribI4usvEXT +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBIPOINTEREXTPROC glad_glVertexAttribIPointerEXT; +#define glVertexAttribIPointerEXT glad_glVertexAttribIPointerEXT +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIIVEXTPROC glad_glGetVertexAttribIivEXT; +#define glGetVertexAttribIivEXT glad_glGetVertexAttribIivEXT +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC)(GLuint index, GLenum pname, GLuint *params); +GLAPI PFNGLGETVERTEXATTRIBIUIVEXTPROC glad_glGetVertexAttribIuivEXT; +#define glGetVertexAttribIuivEXT glad_glGetVertexAttribIuivEXT +#endif +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +GLAPI int GLAD_GL_EXT_texture_filter_anisotropic; +#endif +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +GLAPI int GLAD_GL_KHR_debug; +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; +#define glDebugMessageControl glad_glDebugMessageControl +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; +#define glDebugMessageInsert glad_glDebugMessageInsert +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; +#define glDebugMessageCallback glad_glDebugMessageCallback +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; +#define glGetDebugMessageLog glad_glGetDebugMessageLog +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; +#define glPushDebugGroup glad_glPushDebugGroup +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void); +GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; +#define glPopDebugGroup glad_glPopDebugGroup +typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel; +#define glObjectLabel glad_glObjectLabel +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; +#define glGetObjectLabel glad_glGetObjectLabel +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; +#define glObjectPtrLabel glad_glObjectPtrLabel +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; +#define glGetObjectPtrLabel glad_glGetObjectPtrLabel +typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params); +GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv; +#define glGetPointerv glad_glGetPointerv +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; +#define glDebugMessageControlKHR glad_glDebugMessageControlKHR +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; +#define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void *userParam); +GLAPI PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; +#define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; +#define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; +#define glPushDebugGroupKHR glad_glPushDebugGroupKHR +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC)(void); +GLAPI PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; +#define glPopDebugGroupKHR glad_glPopDebugGroupKHR +typedef void (APIENTRYP PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; +#define glObjectLabelKHR glad_glObjectLabelKHR +typedef void (APIENTRYP PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; +#define glGetObjectLabelKHR glad_glGetObjectLabelKHR +typedef void (APIENTRYP PFNGLOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei length, const GLchar *label); +GLAPI PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; +#define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; +#define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR +typedef void (APIENTRYP PFNGLGETPOINTERVKHRPROC)(GLenum pname, void **params); +GLAPI PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; +#define glGetPointervKHR glad_glGetPointervKHR +#endif +#ifndef GL_NV_depth_clamp +#define GL_NV_depth_clamp 1 +GLAPI int GLAD_GL_NV_depth_clamp; +#endif +#ifndef GL_APPLE_framebuffer_multisample +#define GL_APPLE_framebuffer_multisample 1 +GLAPI int GLAD_GL_APPLE_framebuffer_multisample; +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC glad_glRenderbufferStorageMultisampleAPPLE; +#define glRenderbufferStorageMultisampleAPPLE glad_glRenderbufferStorageMultisampleAPPLE +typedef void (APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC)(void); +GLAPI PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC glad_glResolveMultisampleFramebufferAPPLE; +#define glResolveMultisampleFramebufferAPPLE glad_glResolveMultisampleFramebufferAPPLE +#endif +#ifndef GL_EXT_depth_clamp +#define GL_EXT_depth_clamp 1 +GLAPI int GLAD_GL_EXT_depth_clamp; +#endif +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +GLAPI int GLAD_GL_EXT_texture_filter_anisotropic; +#endif +#ifndef GL_EXT_texture_mirror_clamp_to_edge +#define GL_EXT_texture_mirror_clamp_to_edge 1 +GLAPI int GLAD_GL_EXT_texture_mirror_clamp_to_edge; +#endif +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +GLAPI int GLAD_GL_KHR_debug; +#endif +#ifndef GL_NV_framebuffer_multisample +#define GL_NV_framebuffer_multisample 1 +GLAPI int GLAD_GL_NV_framebuffer_multisample; +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLENVPROC glad_glRenderbufferStorageMultisampleNV; +#define glRenderbufferStorageMultisampleNV glad_glRenderbufferStorageMultisampleNV +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/fast3d/glad/khrplatform.h b/port/fast3d/glad/khrplatform.h new file mode 100644 index 00000000..01646449 --- /dev/null +++ b/port/fast3d/glad/khrplatform.h @@ -0,0 +1,311 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/port/include/crash.h b/port/include/crash.h new file mode 100644 index 00000000..ee8b3df5 --- /dev/null +++ b/port/include/crash.h @@ -0,0 +1,26 @@ +#ifndef PORT_CRASH_H +#define PORT_CRASH_H + +/* + * Crash handler: installs an unhandled-exception filter (Windows) or signal + * handlers (POSIX) that print a symbolicated backtrace and write + * ge007.crash.log, then abort. Call crashInit() before running game code. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void crashInit(void); +void crashShutdown(void); + +/* Unwind every thread in the process and log a short symbolicated + * backtrace for each (labelled via tids/names when known). For diagnosing + * hangs: call from the kernel heartbeat. */ +void crashDumpThreads(const unsigned long *tids, const char **names, int count); + +#ifdef __cplusplus +} +#endif + +#endif /* PORT_CRASH_H */ diff --git a/port/include/dram.h b/port/include/dram.h new file mode 100644 index 00000000..47ea87ad --- /dev/null +++ b/port/include/dram.h @@ -0,0 +1,13 @@ +#ifndef PORT_DRAM_H +#define PORT_DRAM_H + +/* + * Reserve the N64-DRAM region: one 8 MB backing store mapped at BOTH + * 0x70000000 (s32-safe "virtual" view, where game RAM symbols live) and + * 0x80000000 (KSEG0 mirror). See port/src/dram.c. Must be called before any + * game thread runs; the absolute symbols in port/src/dram_syms.s point into + * the V1 view. + */ +void *dramReserve(void); + +#endif /* PORT_DRAM_H */ diff --git a/port/include/hoststddef.h.in b/port/include/hoststddef.h.in new file mode 100644 index 00000000..27f33cb1 --- /dev/null +++ b/port/include/hoststddef.h.in @@ -0,0 +1,8 @@ +#ifndef PORT_HOSTSTDDDEF_H +#define PORT_HOSTSTDDDEF_H +/* Generated by CMake from hoststddef.h.in — do not edit. + * Includes the HOST by absolute path so that port/shim/stddef.h + * can bypass the N64 include/stddef.h (an empty stub whose guard otherwise + * prevents the host header's max_align_t/size_t from reaching C++ TUs). */ +#include "@PORT_HOST_STDDDEF_H@" +#endif diff --git a/port/include/hoststdlib.h.in b/port/include/hoststdlib.h.in new file mode 100644 index 00000000..53f13114 --- /dev/null +++ b/port/include/hoststdlib.h.in @@ -0,0 +1,8 @@ +#ifndef PORT_HOSTSTDLIB_H +#define PORT_HOSTSTDLIB_H +/* Generated by CMake from hoststdlib.h.in — do not edit. + * Includes the HOST by absolute path so that port/shim/stdlib.h + * can bypass the N64 include/stdlib.h (whose lldiv_t/ldiv_t typedefs clash + * with the host's in C++ TUs). See docs/PCPortResearch.md §11. */ +#include "@PORT_HOST_STDLIB_H@" +#endif diff --git a/port/include/platform.h b/port/include/platform.h index 3fc2e19a..3a4c6c0d 100644 --- a/port/include/platform.h +++ b/port/include/platform.h @@ -31,6 +31,14 @@ #define PLATFORM_64BIT 1 #endif +#if defined(_M_IX86) || defined(__i386__) + #define PLATFORM_X86 1 +#elif defined(_M_X64) || defined(__x86_64__) + #define PLATFORM_X86_64 1 +#elif defined(__aarch64__) + #define PLATFORM_ARM 1 +#endif + /* Constructor attribute: run before main(). */ #if defined(_MSC_VER) #define PD_CONSTRUCTOR @@ -44,6 +52,7 @@ enum LogLevel { LOG_ERROR = 0, LOG_WARNING, + LOG_NOTE, LOG_INFO, LOG_DEBUG, }; diff --git a/port/include/system.h b/port/include/system.h index 41c5ce33..bc830dbf 100644 --- a/port/include/system.h +++ b/port/include/system.h @@ -17,6 +17,12 @@ extern "C" { /* Monotonic microseconds since an arbitrary origin. */ uint64_t sysGetMicroseconds(void); + +/* + * Base address the executable was loaded at (for turning runtime addresses + * into file offsets for addr2line; ASLR moves the image on Windows). + */ +uintptr_t sysImageBase(void); /* Wall-clock seconds since the epoch (for timestamps). */ int64_t sysGetTime(void); /* Sleep for the given number of microseconds. */ @@ -27,6 +33,13 @@ void sysSleep(uint32_t micros); void sysLogPrintf(enum LogLevel level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +/* + * Print a fatal error message and terminate the process. Used by fast3d for + * unrecoverable conditions (bad Gfx command, OOM in the texture cache, ...). + */ +void sysFatalError(const char *fmt, ...) + __attribute__((format(printf, 1, 2))) __attribute__((noreturn)); + /* --- Paths -------------------------------------------------------------- */ /* @@ -38,10 +51,31 @@ const char *sysResolvePath(const char *path); /* Return the directory containing the executable. */ const char *sysGetExeDir(void); +/* --- Command line ------------------------------------------------------- */ + +/* Store the host argv (call once from main). */ +void sysSetArgs(int argc, char **argv); +/* Nonzero if the given argument (e.g. "--debug-gl") was passed. */ +int sysArgCheck(const char *arg); +/* Value following the given argument on the command line, or NULL. */ +const char *sysArgGetString(const char *arg); + +/* --- CPU ---------------------------------------------------------------- */ + +/* Briefly yield/relax the CPU (busy-wait hint). Used by fast3d's frame sync. */ +void sysCpuRelax(void); + /* --- Lifecycle ---------------------------------------------------------- */ void sysExit(int code); +/* + * Start the cooperative thread kernel (green threads + vsync tick). Call + * once from main() before running any game code; after this, blocking + * osRecvMesg() calls in the game suspend/resume threads. + */ +void portKernelInit(void); + #ifdef __cplusplus } #endif diff --git a/port/include/video.h b/port/include/video.h index be5d458c..8da5cf5c 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -2,14 +2,16 @@ #define PORT_VIDEO_H /* - * Video: SDL2 window + OpenGL context + frame pacing. - * Modelled on the PD port's port/include/video.h. + * Video: SDL2 window + OpenGL context + frame pacing, on top of fast3d's + * window-manager / rendering APIs (port/fast3d). * - * The game's VI (osViSetMode / osViVSyncCallback / osViWaitVSync) is mapped - * onto this layer. The software RSP (fast3d) renders into the GL context that - * this layer owns. + * The game's VI (osViSetMode / osViSwapBuffer / ...) is mapped onto this + * layer by the libultra shims; the software RSP (fast3d) renders into the GL + * context owned here. */ +#include + #include #include @@ -21,24 +23,27 @@ extern "C" { int videoInit(void); void videoDestroy(void); -/* Frame boundary hooks, driven by the port scheduler (gesched.c). */ +/* Frame boundary hooks, driven by the SP task shim (libultra.c). These run + * on the game's scheduler thread. */ void videoStartFrame(void); void videoSubmitCommands(Gfx *cmds); /* runs the software RSP on the list */ void videoEndFrame(void); -/* Pump window events; returns 1 when the app should quit. Used by the - * Phase 1 demo loop until the scheduler owns the frame boundary. */ -int videoHandleEvents(void); +/* Host-thread SDL event pump: keeps the window responsive (Windows only + * dispatches messages to the creating thread) and handles quit. Called in a + * loop from main(). Exits the process on QUIT/ESC/close. */ +void videoPumpEvents(void); -/* VSync / framerate control. */ -void videoSetVsync(int enabled); -void videoSetFramerateLimit(int fps); /* 0 = unlimited */ +/* The game's native video mode (NTSC 640x480, PAL 640x400). fast3d scales + * N64 screen coordinates into window pixels using this. */ +void videoUpdateNativeResolution(s32 w, s32 h); +s32 videoGetNativeWidth(void); +s32 videoGetNativeHeight(void); -/* Window state queries (kept in sync with the options menu). */ -int videoGetFullscreen(void); -void videoSetFullscreen(int enabled); -int videoGetMaximize(void); -void videoSetMaximize(int enabled); +/* Offscreen framebuffers (fast3d GL FBOs) + texture cache control. */ +s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize); +void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top); +void videoResetTextureCache(void); /* Current FPS (measured). */ float videoGetFPS(void); diff --git a/port/shim/PR/R4300.h b/port/shim/PR/R4300.h new file mode 100644 index 00000000..0e8eeac5 --- /dev/null +++ b/port/shim/PR/R4300.h @@ -0,0 +1,31 @@ +/* + * PC port shim for PR/R4300.h (see docs/PCPortResearch.md). + * + * On the N64, PHYS_TO_K0 turns a physical address into a KSEG0 virtual + * address by OR'ing in 0x80000000. On the PC port the game's working RAM + * lives in the s32-safe DRAM view at 0x70000000 (see port/src/dram.c): + * addresses with bit 31 set would sign-extend to invalid pointers when they + * pass through s32 parameters (e.g. mempCheckMemflagTokens in src/memp.c). + * The KSEG0 view at 0x80000000 still exists as a byte-identical mirror for + * code that rebuilds pointers with `offset | 0x80000000`, and "physical" + * addresses are offsets from the V1 base (see the PR/os.h shim). + * + * So PHYS_TO_K0 is the identity here: its argument is already a live host + * pointer in the V1 view. + * + * Inert in the N64 build (no -DPORT): pure pass-through. + */ +#ifndef _PORT_SHIM_R4300_H_ +#define _PORT_SHIM_R4300_H_ + +#if defined(PORT) +# include "include/PR/R4300.h" + +# undef PHYS_TO_K0 +# define PHYS_TO_K0(x) ((u32)(x)) /* identity: V1 view is already virtual */ + +#else +# include +#endif + +#endif /* _PORT_SHIM_R4300_H_ */ diff --git a/port/shim/PR/os.h b/port/shim/PR/os.h new file mode 100644 index 00000000..2a4f4976 --- /dev/null +++ b/port/shim/PR/os.h @@ -0,0 +1,43 @@ +/* + * PC port shim for PR/os.h — DRAM address conversions (see docs/PCPortResearch.md). + * + * The game's working RAM lives in the s32-safe DRAM view at 0x70000000 + * ("V1"), with a byte-identical KSEG0 mirror at 0x80000000 ("V2"); see + * port/src/dram.c. Addresses with bit 31 set sign-extend to invalid + * pointers through s32 parameters (src/memp.c), so live pointers must stay + * in V1, while `offset | 0x80000000` rebuilds (src/game/bg.c) must land in + * V2. The two views share one backing store, so both are the same data. + * + * "Physical" addresses in GBI words and ROM data are therefore OFFSETS FROM + * THE V1 BASE, and the conversions become: + * + * OS_K0_TO_PHYSICAL(x) = (u32)((char *)x - 0x70000000) + * small offset P; fast3d's seg_addr() resolves it with +0x80000000, + * landing in V2. `P | 0x80000000` (bg.c et al.) also lands in V2. + * OS_PHYSICAL_TO_K0(x) = x (identity) + * Callers pass EITHER live V1 pointers (bondview2.c, front.c) — which + * then go into GBI words as full addresses that fast3d passes through + * — OR small physical offsets, which fast3d remaps to V2. Both forms + * resolve correctly. + * osVirtualToPhysical / osPhysicalToVirtual stay the identity (port/src/ + * libultra.c): V1 addresses are already live host pointers < 4 GB. + * + * Inert in the N64 build (no -DPORT): pure pass-through. + */ +#ifndef _PORT_SHIM_OS_H_ +#define _PORT_SHIM_OS_H_ + +#if defined(PORT) +# include "include/PR/os.h" + +# undef OS_K0_TO_PHYSICAL +# define OS_K0_TO_PHYSICAL(x) ((u32)((char *)(x) - 0x70000000)) + +# undef OS_PHYSICAL_TO_K0 +# define OS_PHYSICAL_TO_K0(x) ((void *)(x)) + +#else +# include +#endif + +#endif /* _PORT_SHIM_OS_H_ */ diff --git a/port/shim/stdarg.h b/port/shim/stdarg.h new file mode 100644 index 00000000..962bd243 --- /dev/null +++ b/port/shim/stdarg.h @@ -0,0 +1,19 @@ +/* + * PC port shim for . + * + * The N64 decomp's include/stdarg.h does `#include ` (the console + * dev-kit convenience: one header pulls in all of libultra). On the PC that + * means any HOST header that internally includes (SDL_stdinc.h, + * parts of MinGW's own headers, ...) drags PR/os.h into the middle of host + * header parsing. If MinGW's has already run (it defines the + * `errno` macro), PR/os.h's controller structs — which have fields literally + * named `errno` — fail to parse ("field '_errno' declared as a function"). + * + * Parse the N64 header with the errno macro suppressed; restore it after. + * Inert in the N64 build (port/shim is not on its include path). + */ + +#pragma push_macro("errno") +#undef errno +#include "include/stdarg.h" +#pragma pop_macro("errno") diff --git a/port/shim/stddef.h b/port/shim/stddef.h new file mode 100644 index 00000000..fe0d0a40 --- /dev/null +++ b/port/shim/stddef.h @@ -0,0 +1,30 @@ +/* + * PC port shim for . + * + * The N64 decomp ships an essentially empty include/stddef.h (just its + * `_STDDEF_H_` guard). In C game code that is harmless. In C++ TUs (fast3d) + * it shadows the host header, so libstdc++'s never sees the host's + * max_align_t/size_t and fails to compile. Route C++ TUs to the host header + * by absolute path (generated hoststddef.h — same trick as + * port/shim/string.h / port/shim/stdlib.h). + * + * Inert in the N64 build (port/shim is not on its include path). + */ +#if defined(__cplusplus) +/* MinGW's does: + * #define __need_wint_t + * #define __need_wchar_t + * #include + * and never undefs the __need_* macros. stddef.h then refuses to run its + * main body (which defines max_align_t) for the rest of the TU, breaking + * libstdc++'s . Clear the poison before pulling in the host header. + */ +#undef __need_wchar_t +#undef __need_size_t +#undef __need_ptrdiff_t +#undef __need_NULL +#undef __need_wint_t +#include "hoststddef.h" +#else +#include "include/stddef.h" +#endif diff --git a/port/shim/stdlib.h b/port/shim/stdlib.h new file mode 100644 index 00000000..9ef24236 --- /dev/null +++ b/port/shim/stdlib.h @@ -0,0 +1,20 @@ +/* + * PC port shim for . + * + * The N64 decomp ships include/stdlib.h (a libc stub: lldiv_t/ldiv_t typedefs + * + a couple of prototypes). C game code gets it, exactly as on the console. + * + * In C++ TUs (fast3d) it must NOT be used: MinGW's own headers pull in the + * host through their include chains (sec_api/stdlib_s.h does + * `#include `, which resolves to the N64 header via -I), and the + * lldiv_t/ldiv_t typedefs then conflict with the host's. The shim routes C++ + * TUs to the host header by absolute path (generated hoststdlib.h, same + * trick as port/shim/string.h — see docs/PCPortResearch.md §11 D12). + * + * Inert in the N64 build (port/shim is not on its include path). + */ +#if defined(__cplusplus) +#include "hoststdlib.h" +#else +#include "include/stdlib.h" +#endif diff --git a/port/src/crash.c b/port/src/crash.c index c29377ee..2bc183ac 100644 --- a/port/src/crash.c +++ b/port/src/crash.c @@ -1,26 +1,420 @@ /* * Crash handler / stack traces. * - * Catches signals (SIGSEGV etc.) and prints a backtrace + the game's state, - * to make the inevitable porting crashes debuggable. + * Catches access violations (Windows) / fatal signals (POSIX) and prints a + * backtrace with file:line info (build with -g; MinGW emits PDBs so symbols + * resolve), to make the inevitable porting crashes debuggable. * - * Modelled on the PD port's port/src/crash.c (~360 lines). - * - * STATUS: scaffolding stub — implement during Phase 1. + * Adapted from the PD port's port/src/crash.c. */ -#include -#include +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif -#include "platform.h" +#include +#include +#include + +#include #include "system.h" +#include "platform.h" +#include "crash.h" + +#define CRASH_LOG_FNAME "ge007.crash.log" +#define CRASH_MAX_MSG 8192 +#define CRASH_MAX_SYM 256 +#define CRASH_MAX_FRAMES 32 +#define CRASH_MSG(...) \ + if (msglen < CRASH_MAX_MSG) msglen += snprintf(msg + msglen, CRASH_MAX_MSG - msglen, __VA_ARGS__) + +#if defined(PLATFORM_WINDOWS) + +#include +#include +#include +#include +#include + +static LPTOP_LEVEL_EXCEPTION_FILTER prevExFilter; + +static void *crashGetModuleBase(const void *addr) +{ + HMODULE h = NULL; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &h); + return (void *)h; +} + +/* + * Phase 1 — raw crash info, NO dbghelp. Every call here is a plain Win32 + * query; nothing allocates or walks memory, so this cannot re-fault even if + * the heap or a stack is corrupted. Written to console + file BEFORE any + * risky symbolication. + */ +static void crashStackTraceRaw(char *msg, PEXCEPTION_POINTERS exinfo) +{ + CONTEXT context = *exinfo->ContextRecord; + DWORD msglen = 0; + + CRASH_MSG("EXCEPTION: 0x%08lx\n", exinfo->ExceptionRecord->ExceptionCode); +#if defined(PLATFORM_X86_64) + CRASH_MSG("PC: %p (Rip=%p Rsp=%p Rbp=%p)\n", + exinfo->ExceptionRecord->ExceptionAddress, + (void *)context.Rip, (void *)context.Rsp, (void *)context.Rbp); + /* FPU state: for STATUS_FLOATING_POINT_* we want to know whether the + * exception masks were actually cleared (MxCsr bits 7..10 / x87 CW + * mask bits) or this is a stale status bit. */ + CRASH_MSG("MxCsr=0x%08lx x87CW=0x%04x x87SW=0x%04x\n", + (unsigned long)context.MxCsr, + (unsigned)(context.FloatSave.ControlWord & 0xffff), + (unsigned)(context.FloatSave.StatusWord & 0xffff)); + PVOID low = NULL, high = NULL; + if (GetCurrentThreadStackLimits(low, high)) { + CRASH_MSG("thread stack: %p..%p Rsp=%p used=%llu bytes\n", + low, high, (void *)context.Rsp, + (unsigned long long)((uintptr_t)high - (uintptr_t)context.Rsp)); + } +#else + CRASH_MSG("PC: %p\n", exinfo->ExceptionRecord->ExceptionAddress); +#endif + CRASH_MSG("MODULE: [%p]\n", crashGetModuleBase(exinfo->ExceptionRecord->ExceptionAddress)); + CRASH_MSG("MAIN MODULE: [%p]\n", crashGetModuleBase(crashInit)); +} + +/* + * Phase 2 — backtrace by walking the EBP chain manually. The build keeps + * frame pointers (-fno-omit-frame-pointer), so every frame is a pair of + * qwords at RBP: [saved RBP, return address]. No dbghelp, no allocation: + * each pointer is validated against the thread's stack bounds BEFORE being + * dereferenced, and the chain must strictly ascend (x64 stacks grow down), + * so a corrupted chain terminates instead of re-faulting. Addresses are + * symbolicated offline with addr2line when needed. + */ +static void crashStackTraceSym(char *msg, PEXCEPTION_POINTERS exinfo) +{ + CONTEXT context = *exinfo->ContextRecord; + DWORD msglen = 0; + +#if defined(PLATFORM_X86_64) + PVOID low = NULL, high = NULL; + if (!GetCurrentThreadStackLimits(low, high)) { + snprintf(msg, CRASH_MAX_MSG, "\nBACKTRACE: (no stack limits)\n"); + return; + } + + uintptr_t fp = context.Rbp; + int i = 0; + CRASH_MSG("\nBACKTRACE:\n#00: %p (crash PC)\n", exinfo->ExceptionRecord->ExceptionAddress); + + while (i < CRASH_MAX_FRAMES - 1) { + /* The frame record must live inside the committed stack. */ + if (fp < (uintptr_t)low || fp > (uintptr_t)high) break; + + const uintptr_t *frame = (const uintptr_t *)fp; + const uintptr_t saved_fp = frame[0]; + const uintptr_t ret_addr = frame[1]; + + CRASH_MSG("#%02d: %p", i + 1, (void *)ret_addr); + const uintptr_t modbase = (uintptr_t)crashGetModuleBase((void *)ret_addr); + if (modbase) { + CRASH_MSG(" [%p]+%llx", (void *)modbase, + (unsigned long long)(ret_addr - modbase)); + } + CRASH_MSG("\n"); + + /* Chain must ascend; stop on the first frame that doesn't. */ + if (saved_fp <= fp || saved_fp > (uintptr_t)high) break; + fp = saved_fp; + ++i; + } + if (i == CRASH_MAX_FRAMES - 1) { + CRASH_MSG("...\n"); + } +#else + snprintf(msg, CRASH_MAX_MSG, "\nBACKTRACE: not implemented on this arch\n"); +#endif +} + +static void crashWriteLog(const char *msg, int append) +{ + FILE *f = fopen(CRASH_LOG_FNAME, append ? "ab" : "wb"); + if (f) { + if (!append) fprintf(f, "Crash!\n\n"); + fprintf(f, "%s", msg); + fclose(f); + } +} + +/* + * Thread dump: unwind every thread in this process and print a short + * backtrace for each, labelled with the game-thread name when known. + * Called from the kernel heartbeat when no frame has rendered for a while, + * so a hang shows WHERE every thread is stuck instead of as silence. + * + * tids/names: parallel arrays (may be NULL/0). Threads not in the list are + * labelled by TID only. Uses SuspendThread + GetThreadContext + StackWalk64; + * each thread is resumed before the next is touched, so a hang in one walk + * cannot wedge the others. + */ +void crashDumpThreads(const unsigned long *tids, const char **names, int count) +{ + HANDLE process = GetCurrentProcess(); + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (snap == INVALID_HANDLE_VALUE) return; + + /* Function symbols only — line tables are slow to load and the dump + * prints function+offset, which is enough to find a hang. */ + SymSetOptions(SymGetOptions() | SYMOPT_DEBUG); + SymInitialize(process, NULL, TRUE); + + THREADENTRY32 te; + te.dwSize = sizeof(te); + if (!Thread32First(snap, &te)) { + CloseHandle(snap); + return; + } + + do { + if (te.th32OwnerProcessID != GetCurrentProcessId()) continue; + + char label[64] = "?"; + int matched = 0; + for (int i = 0; i < count; ++i) { + if (tids && tids[i] == te.th32ThreadID) { + snprintf(label, sizeof(label), "%s", names ? names[i] : "?"); + matched = 1; + break; + } + } + /* When a specific thread list is given, skip everything else — + * walking ~20 system threads with symbol resolution is slow and + * buries the interesting frames. */ + if (count > 0 && !matched) continue; + + HANDLE hth = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, te.th32ThreadID); + if (!hth) continue; + + CONTEXT ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_FULL; + DWORD susps = SuspendThread(hth); + if (susps != (DWORD)-1 && GetThreadContext(hth, &ctx)) { + sysLogPrintf(LOG_ERROR, " [thread %lu '%s']", te.th32ThreadID, label); + +#if defined(PLATFORM_X86_64) + STACKFRAME64 sf; + memset(&sf, 0, sizeof(sf)); + sf.AddrPC.Offset = ctx.Rip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrFrame.Offset = ctx.Rbp; + sf.AddrFrame.Mode = AddrModeFlat; + sf.AddrStack.Offset = ctx.Rsp; + sf.AddrStack.Mode = AddrModeFlat; + + char symbuf[sizeof(SYMBOL_INFO) + CRASH_MAX_SYM * sizeof(TCHAR)]; + PSYMBOL_INFO sym = (PSYMBOL_INFO)symbuf; + sym->SizeOfStruct = sizeof(*sym); + sym->MaxNameLen = CRASH_MAX_SYM; + DWORD64 disp64 = 0; + + for (int i = 0; i < 8; ++i) { + if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, process, hth, &sf, &ctx, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL)) + break; + if (sym->SizeOfStruct == 0) { + sym->SizeOfStruct = sizeof(*sym); + sym->MaxNameLen = CRASH_MAX_SYM; + } + const char *where = "?"; + if (SymFromAddr(process, sf.AddrPC.Offset, &disp64, sym)) { + static char linebuf[CRASH_MAX_FRAMES][512]; + snprintf(linebuf[i % CRASH_MAX_FRAMES], sizeof(linebuf[0]), "%s+%llx", + sym->Name, (unsigned long long)disp64); + where = linebuf[i % CRASH_MAX_FRAMES]; + } + sysLogPrintf(LOG_ERROR, " #%d %p %s", i, + (void *)(uintptr_t)sf.AddrPC.Offset, where); + } +#endif + } + ResumeThread(hth); + CloseHandle(hth); + } while (Thread32Next(snap, &te)); + + CloseHandle(snap); + SymCleanup(process); +} + +static LONG __stdcall crashHandler(PEXCEPTION_POINTERS exinfo) +{ + char msg[CRASH_MAX_MSG + 1] = { 0 }; + + if (IsDebuggerPresent()) { + if (prevExFilter) { + return prevExFilter(exinfo); + } + return EXCEPTION_CONTINUE_EXECUTION; + } + + /* Phase 1: raw info, guaranteed to survive. */ + crashStackTraceRaw(msg, exinfo); + sysLogPrintf(LOG_ERROR, "FATAL: %s", msg); + fflush(stderr); + fflush(stdout); + crashWriteLog(msg, 0); + + /* Phase 2: EBP-chain backtrace (validated reads only — see + * crashStackTraceSym). The raw data is already on disk either way. */ + { + char sym[CRASH_MAX_MSG + 1] = { 0 }; + crashStackTraceSym(sym, exinfo); + if (sym[0]) { + sysLogPrintf(LOG_ERROR, "%s", sym); + crashWriteLog(sym, 1); + } + } + + /* Terminate directly — abort() raises SIGABRT which can re-enter the + * exception machinery while we are already inside it. */ + TerminateProcess(GetCurrentProcess(), exinfo->ExceptionRecord->ExceptionCode); + return EXCEPTION_CONTINUE_EXECUTION; +} + +#elif defined(PLATFORM_LINUX) + +#include +#include +#include +#include +#include +#include +#include + +static struct sigaction prevSigAction; + +static void *crashGetModuleBase(const void *addr) +{ + Dl_info info; + if (dladdr(addr, &info)) { + return info.dli_fbase; + } + return NULL; +} + +static void crashStackTrace(char *msg, int sig, void *pc) +{ + unsigned msglen = 0; + void *frames[CRASH_MAX_FRAMES] = { NULL }; + + const int nframes = backtrace(frames, CRASH_MAX_FRAMES); + if (nframes <= 0) { + CRASH_MSG("no information\n"); + return; + } + + char **strings = backtrace_symbols(frames, nframes); + + CRASH_MSG("SIGNAL: %d\n", sig); + CRASH_MSG("PC: "); + if (pc) { + CRASH_MSG("%p\n", pc); + } else if (strings) { + CRASH_MSG("%s\n", strings[0]); + } else { + CRASH_MSG("%p\n", frames[0]); + } + + CRASH_MSG("MODULE: %p\n", crashGetModuleBase(frames[0])); + CRASH_MSG("MAIN MODULE: %p\n", crashGetModuleBase(crashInit)); + CRASH_MSG("\nBACKTRACE:\n"); + + int i; + for (i = 0; i < nframes; ++i) { + CRASH_MSG("#%02d: ", i); + if (strings && strings[i]) { + CRASH_MSG("%s\n", strings[i]); + } else { + CRASH_MSG("%p\n", frames[i]); + } + } + + if (i == CRASH_MAX_FRAMES) { + CRASH_MSG("...\n"); + } else if (i <= 1) { + CRASH_MSG("no information\n"); + } + + free(strings); +} + +static void crashHandler(int sig, siginfo_t *siginfo, void *ctx) +{ + char msg[CRASH_MAX_MSG + 1] = { 0 }; + + void *pc = NULL; + if (ctx) { + ucontext_t *ucontext = (ucontext_t *)ctx; +#ifdef PLATFORM_X86 + pc = (void *)ucontext->uc_mcontext.gregs[REG_EIP]; +#elif defined(PLATFORM_X86_64) + pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP]; +#endif + } + + sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p SIGNAL=%d", pc, sig); + + fflush(stderr); + fflush(stdout); + + crashStackTrace(msg, sig, pc); + + { + FILE *f = fopen(CRASH_LOG_FNAME, "wb"); + if (f) { + fprintf(f, "Crash!\n\n%s", msg); + fclose(f); + } + } + + sysFatalError("Crash!\n\n%s", msg); +} + +#endif /* PLATFORM_WINDOWS / PLATFORM_LINUX */ + +int g_CrashEnabled = 0; void crashInit(void) { - /* TODO(Phase 1): - * - install signal handlers (SIGSEGV, SIGFPE, SIGILL, SIGBUS) - * - on crash: print backtrace (dbghelp on Windows, backtrace() on POSIX) - * - dump relevant game state (current level, frame, etc.) - */ - sysLogPrintf(LOG_INFO, "crashInit: TODO (Phase 1)"); +#if defined(PLATFORM_WINDOWS) + SetErrorMode(SEM_FAILCRITICALERRORS); + prevExFilter = SetUnhandledExceptionFilter(crashHandler); + g_CrashEnabled = 1; +#elif defined(PLATFORM_LINUX) + struct sigaction sigact = { 0 }; + sigact.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigact.sa_sigaction = crashHandler; + sigaction(SIGSEGV, &sigact, &prevSigAction); + sigaction(SIGABRT, &sigact, &prevSigAction); + sigaction(SIGBUS, &sigact, &prevSigAction); + sigaction(SIGILL, &sigact, &prevSigAction); + g_CrashEnabled = 1; +#endif +} + +void crashShutdown(void) +{ + if (!g_CrashEnabled) { + return; + } +#if defined(PLATFORM_WINDOWS) + if (prevExFilter) { + SetUnhandledExceptionFilter(prevExFilter); + } +#elif defined(PLATFORM_LINUX) + sigaction(SIGSEGV, &prevSigAction, NULL); + sigaction(SIGABRT, &prevSigAction, NULL); + sigaction(SIGBUS, &prevSigAction, NULL); + sigaction(SIGILL, &prevSigAction, NULL); +#endif + g_CrashEnabled = 0; } diff --git a/port/src/dram.c b/port/src/dram.c new file mode 100644 index 00000000..9d2b7efb --- /dev/null +++ b/port/src/dram.c @@ -0,0 +1,133 @@ +/* + * dram.c — a slice of N64 "DRAM" in host memory, mapped twice. + * + * GE's game code mixes two address conventions that cannot both hold on an + * x64 host with a single mapping: + * + * 1. Pointers that pass through s32 (e.g. mempCheckMemflagTokens(s32, s32) + * in src/memp.c). Any address with bit 31 set sign-extends to an + * invalid 0xffffffffXXXXXXXX pointer when stored back into a u8*. + * => the game's working RAM must live BELOW 0x80000000. + * + * 2. "Physical" addresses that the game ORs with 0x80000000 to make them + * dereferenceable (e.g. `texnum = *((u16 *)(temp.word | 0x80000000))` + * in src/game/bg.c, where temp.word is a GBI w1 value produced by + * OS_K0_TO_PHYSICAL). => a KSEG0 view at 0x80000000 must exist and + * mirror the working RAM. + * + * The port therefore maps ONE 8 MB section at two addresses: + * + * V1 @ 0x70000000 "virtual" view — s32-safe; ALL game RAM symbols live + * here (cfb_16, _bssSegmentEnd/mempool start, tlbBlock/ + * mempool end). Mempool pointers etc. are 0x70xxxxxx: + * positive as s32, safe through every 32-bit path. + * V2 @ 0x80000000 KSEG0 view — byte-identical mirror of V1 (same section + * backing), for code that rebuilds pointers with + * `offset | 0x80000000`. + * + * The port-side header shims (port/shim/PR/R4300.h, port/shim/PR/os.h) make + * the conversion macros consistent with this layout: + * PHYS_TO_K0(x) = x (identity) + * OS_K0_TO_PHYSICAL(x) = (u32)((char*)x - V1_BASE) (small offset) + * so GBI w1 words carry small offsets that fast3d's seg_addr() resolves by + * adding 0x80000000 (landing in V2, same data), and osVirtualToPhysical(x) + * stays the identity (V1 addresses are already live host pointers < 4 GB). + * + * Layout (NTSC US .stacks sits at 0x803AB400, MAPPING_TABLE_COUNT=93 pages, + * so the N64 tlb block is 0x803AB400 - 93*0x2000 = 0x802F4400 — kept as the + * mempool end for fidelity): + * + * +0x000000 cfb_16 (2 x 320x240x2 = 0x4B000, from src/cfb.c) + * +0x050000 _bssSegmentEnd -> mempool start (boss.c:217) + * ... game heap (mempools / dyn / audio buffers) + * +0x2F4400 tlb block -> mempool end (tlbmanageGetTlbAllocatedBlock) + * +0x800000 end of region (8 MB, like an 8-MB-RAM N64) + */ + +#include "platform.h" +#include "system.h" + +#if defined(PLATFORM_WINDOWS) +#include +#else +#define _GNU_SOURCE /* memfd_create — must precede all system headers */ +#include +#include +#endif + +#define DRAM_V1_BASE 0x70000000UL /* s32-safe "virtual" view */ +#define DRAM_K0_BASE 0x80000000UL /* KSEG0 mirror view */ +#define DRAM_SIZE 0x00800000UL /* 8 MB */ + +void *dramReserve(void) +{ +#if defined(PLATFORM_WINDOWS) + /* One anonymous section, two views at fixed addresses. */ + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + HANDLE hSec = CreateFileMappingW(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, + (DWORD)(DRAM_SIZE >> 32), + (DWORD)(DRAM_SIZE & 0xFFFFFFFF), NULL); + if (!hSec) { + sysFatalError("dram: CreateFileMapping failed (%lu)", GetLastError()); + } + + void *v1 = MapViewOfFileEx(hSec, FILE_MAP_ALL_ACCESS, 0, 0, DRAM_SIZE, + (void *)DRAM_V1_BASE); + if (v1 != (void *)DRAM_V1_BASE) { + sysFatalError("dram: could not map DRAM at %p (err %lu)", + (void *)DRAM_V1_BASE, GetLastError()); + } + + void *v2 = MapViewOfFileEx(hSec, FILE_MAP_ALL_ACCESS, 0, 0, DRAM_SIZE, + (void *)DRAM_K0_BASE); + if (v2 != (void *)DRAM_K0_BASE) { + sysFatalError("dram: could not map KSEG0 mirror at %p (err %lu)", + (void *)DRAM_K0_BASE, GetLastError()); + } + + /* Sanity: the views must alias the same backing store. */ + ((volatile char *)v1)[0] = 0x5A; + if (((volatile char *)v2)[0] != 0x5A) { + sysFatalError("dram: V1/V2 views do not share a backing store"); + } + ((volatile char *)v1)[0] = 0; + + CloseHandle(hSec); + return v1; +#else + /* memfd + two MAP_SHARED mmaps = one backing store, two views. */ + int fd = memfd_create("ge007_dram", 0); + if (fd < 0) { + sysFatalError("dram: memfd_create failed"); + } + if (ftruncate(fd, DRAM_SIZE) != 0) { + sysFatalError("dram: ftruncate failed"); + } + + void *v1 = mmap((void *)DRAM_V1_BASE, DRAM_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0); + if (v1 == MAP_FAILED || v1 != (void *)DRAM_V1_BASE) { + sysFatalError("dram: could not map DRAM at %p", (void *)DRAM_V1_BASE); + } + + void *v2 = mmap((void *)DRAM_K0_BASE, DRAM_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0); + if (v2 == MAP_FAILED || v2 != (void *)DRAM_K0_BASE) { + sysFatalError("dram: could not map KSEG0 mirror at %p", + (void *)DRAM_K0_BASE); + } + + ((volatile char *)v1)[0] = 0x5A; + if (((volatile char *)v2)[0] != 0x5A) { + sysFatalError("dram: V1/V2 views do not share a backing store"); + } + ((volatile char *)v1)[0] = 0; + + close(fd); + return v1; +#endif +} diff --git a/port/src/dram_syms.s b/port/src/dram_syms.s new file mode 100644 index 00000000..b9253113 --- /dev/null +++ b/port/src/dram_syms.s @@ -0,0 +1,18 @@ +/* + * dram_syms.s — absolute symbols inside the "virtual" (s32-safe) DRAM view. + * See port/src/dram.c: one 8 MB backing store is mapped at BOTH 0x70000000 + * (V1, where these live) and 0x80000000 (V2, the KSEG0 mirror). These are + * committed host addresses, so they are live pointers on the PC. + * + * cfb_16 replaces src/cfb.c (excluded from the build): the two + * 320x240x16-bit framebuffers, 0x4B000 bytes total. + * _bssSegmentEnd end-of-.bss marker; boss.c:217 starts the mempools at + * PHYS_TO_K0(osVirtualToPhysical(&_bssSegmentEnd)). + */ +.section .data + +.global cfb_16 +.set cfb_16, 0x70000000 + +.global _bssSegmentEnd +.set _bssSegmentEnd, 0x70050000 diff --git a/port/src/gesched.c b/port/src/gesched.c deleted file mode 100644 index 12bd3a73..00000000 --- a/port/src/gesched.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Port RCP scheduler. - * - * Replaces the hardware task submission in src/sched.c. On the N64, - * __scExec() hands a gfx/audio task to the RSP via osSpTaskLoad/StartGo. - * Here, instead of writing RSP registers, we: - * - gfx task: call videoSubmitCommands(display_list) -> the software RSP - * - audio task: feed the mixed buffer to the audio layer - * and reproduce the gfx/audio interleaving + VSync pacing the game expects. - * - * Modelled on the PD port's port/src/pdsched.c (~405 lines). - * - * STATUS: scaffolding stub — implement during Phase 2. - * - * NOTE: GE's src/sched.c has speed-graph / profiling hooks - * (speedgraphMarkerHandler) and a slightly different task model than PD. - * Reproduce the exact gfx/audio/VSync behaviour; see - * docs/PCPortResearch.md §9.3. - */ - -#include -#include -#include - -#include "sched.h" -#include "fr.h" /* NUM_VIDEO_FRAME_BUFFERS */ - -#include "platform.h" -#include "video.h" -#include "audio.h" -#include "system.h" - -/* - * Scheduler globals (normally defined in src/sched.c, which is EXCLUDED from - * the PC build). init.c's schedulerInitThread() references os_scheduler and - * gfxClient, so the port provides them here (matching src/sched.c:70-71). - */ -OSSched os_scheduler; -OSScClient gfxClient[3]; - -/* - * Scheduler/VI globals (normally defined in src/sched.c, EXCLUDED). fr.c - * references these; the port provides them so it links. Values are the - * sched.c initializers. - */ -s32 g_schedViCurrentFrameBuffer = 0; -s32 g_ViChangeVideoModes[NUM_VIDEO_FRAME_BUFFERS] = {0, 0}; -OSViMode g_ViModes[NUM_VIDEO_FRAME_BUFFERS]; -OSViMode *g_ViModePtrs[NUM_VIDEO_FRAME_BUFFERS]; - -/* - * Performance counters (normally in src/sched.c). speed_graph.c reads them - * via get_counters(). - */ -static u32 g_DisplayPerformanceCounters[4]; // clock, cmc, pipe, tmem -u32 *get_counters(void) { return g_DisplayPerformanceCounters; } - -/* Debug stderr control (normally in src/sched.c). boss.c calls it. */ -void permit_stderr(u32 flag) { (void)flag; } - -/* - * Scheduler API (declared in sched.h, normally defined in src/sched.c which - * is EXCLUDED from the PC build). The port provides these so engine code that - * calls osCreateScheduler/osScAddClient/osScGetCmdQ links. The real work — - * driving the software RSP per frame — happens in geschedRunFrame(). - */ -void osCreateScheduler(OSSched *s, void *stack, u8 mode, u32 numFields) -{ - /* TODO(Phase 2): initialise the port scheduler state in *s. */ - (void)s; (void)stack; (void)mode; (void)numFields; - sysLogPrintf(LOG_INFO, "osCreateScheduler: TODO (Phase 2)"); -} -void osScAddClient(OSSched *s, OSScClient *c, OSMesgQueue *msgQ, OSScClient *next) -{ - /* TODO(Phase 2): register a gfx/audio client. */ - (void)s; (void)c; (void)msgQ; (void)next; -} -void osScRemoveClient(OSSched *s, OSScClient *c) -{ - (void)s; (void)c; -} -OSMesgQueue *osScGetCmdQ(OSSched *s) -{ - /* TODO(Phase 2): return the scheduler's command queue. */ - (void)s; - return NULL; -} - -void geschedInit(void) -{ - /* TODO(Phase 2): set up the scheduler + gfx client, mirroring - * schedulerInitThread() in src/init.c but with the port's frame hooks. */ - sysLogPrintf(LOG_INFO, "geschedInit: TODO (Phase 2)"); -} - -/* - * Per-frame driver. Called by the main loop (or the VI vsync callback shim). - * Sequence (mirrors PD's pdsched.c): - * videoStartFrame() - * ... game builds the display list ... - * videoSubmitCommands(cmds) - * videoEndFrame() - */ -void geschedRunFrame(void *displayList) -{ - videoStartFrame(); - videoSubmitCommands((Gfx *)displayList); - audioEndFrame(); - videoEndFrame(); -} diff --git a/port/src/gfxstub.c b/port/src/gfxstub.c deleted file mode 100644 index 987d85fa..00000000 --- a/port/src/gfxstub.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Software-RSP placeholder (Phase 2). - * - * port/fast3d/ currently contains only the API header (gfx_api.h); the real - * implementation arrives in Phase 2 by adapting the PD port's fast3d. video.c - * calls these entry points, so they must exist to link. Every function is a - * no-op: frames are submitted and dropped until the RSP emulator lands. - * - * DELETE THIS FILE when the real fast3d sources are added (they define the - * same symbols; keeping both would be a duplicate-definition link error). - */ - -#include -#include - -#include - -/* port/fast3d is not on the include path; use the relative form. */ -#include "../fast3d/gfx_api.h" - -struct GfxDimensions gfx_current_dimensions = { - 1.0f, /* internal_mul */ - 640, 480, /* width, height */ - 1.5f, /* aspect_ratio */ -}; - -void gfx_init(const struct GfxInitSettings *settings) { (void)settings; } -void gfx_destroy(void) {} -void gfx_start_frame(void) {} -void gfx_end_frame(void) {} -void gfx_run(Gfx *commands) { (void)commands; } - -void gfx_set_target_fps(int fps) { (void)fps; } -void gfx_set_texture_filter(int mode) { (void)mode; } -void gfx_set_mipmap_filter(int mode) { (void)mode; } diff --git a/port/src/libultra.c b/port/src/libultra.c index 291b7e6a..1c23eef2 100644 --- a/port/src/libultra.c +++ b/port/src/libultra.c @@ -1,26 +1,45 @@ /* - * libultra OS shims for the PC port. + * libultra OS shims for the PC port, plus the cooperative thread kernel. * - * The game code calls the libultra OS API (threads, message queues, timers, - * VI, PI, SI, SP, AI, cache, memory). On the PC none of that hardware exists, - * so this file provides single-threaded / host-backed implementations. + * The game code calls the libultra OS API (threads, message queues, VI, PI, + * SI, SP, AI, cache, memory). On the PC none of that hardware exists: * - * Modelled on the PD port's port/src/libultra.c (~490 lines). That file is the - * reference implementation to adapt; this stub marks the surface area. + * - Threads are REAL host threads (pthreads). The N64 OS is a preemptive + * priority scheduler, so this is both faithful and robust: blocking + * osRecvMesg() waits on a per-queue condition variable. (An earlier + * setjmp/longjmp green-thread kernel corrupted FPU state across longjmps + * on Windows x64/MinGW — synthetic STATUS_FLOATING_POINT_INVALID_OPERATION + * crashes at PC=0; see docs/PCPortResearch.md.) + * - RSP tasks (osSpTaskStartGo) run the software RSP (fast3d) inline and + * post the RSP_DONE / RDP_DONE messages sched.c waits for. + * - VI retrace is a vsync-paced tick posted by a dedicated kernel thread, + * once per frame at the console's frame rate. + * - Controllers are filled from the keyboard in osContStartQuery(). * - * STATUS: scaffolding stub — implement during Phase 1 (OS core) and Phase 2 - * (SP/VI), Phase 3 (AI/SI). + * Modelled on the PD port's port/src/libultra.c. */ +/* NOTE: no here — angle-bracket form would resolve to the game's + * src/sched.h (it is on the include path), not MinGW's. osYieldThread uses a + * short sleep instead of sched_yield(). */ +#include #include #include #include +#include + +/* N64 headers declare struct fields named `errno`; the C macro (pulled in + * by pthread.h/sched.h -> errno.h) must not be active while they parse. */ +#pragma push_macro("errno") +#undef errno #include #include #include #include #include +#include +#pragma pop_macro("errno") #include "platform.h" #include "system.h" @@ -29,6 +48,14 @@ #include "input.h" #include "fs.h" #include "romdata.h" +#include "crash.h" + +#if defined(PLATFORM_WINDOWS) +#include /* GetCurrentThreadId for thread-dump labels */ +#endif + +/* fast3d (C++): the software RSP entry point. */ +extern void gfx_run(Gfx *commands); /* ------------------------------------------------------------------------ */ /* Globals the game expects to exist (normally set by osInitialize). */ @@ -52,14 +79,8 @@ s32 osViClock = 0; /* Time */ /* ------------------------------------------------------------------------ */ -/* - * The R4300 "SP timer" is a free-running counter. Map it to the host clock. - * The PD port scales host microseconds into the N64 counter domain so that - * osGetTime()-based timing in the game behaves correctly. - */ OSTime osGetTime(void) { - /* TODO(Phase 1): scale sysGetMicroseconds() into the N64 counter domain. */ return (OSTime)sysGetMicroseconds(); } @@ -69,120 +90,493 @@ u32 osGetCount(void) } /* ------------------------------------------------------------------------ */ -/* Threads — single-threaded: create/start are no-ops, the "main" thread is */ -/* the host thread. The game's scheduler drives everything cooperatively. */ +/* Real-OS-thread kernel */ +/* ------------------------------------------------------------------------ + * + * Each game thread becomes a real pthread with its own 8 MB stack (the N64 + * gave each thread a dedicated sp_* stack; sharing one host stack across + * green threads is what broke the setjmp design). Message queues carry a + * side-table entry with a mutex + condition variable: osRecvMesg(BLOCK) + * waits on it, osSendMesg() signals it. A dedicated tick thread paces the + * VI retrace message and services software timers. + */ + +#define PORT_MAX_THREADS 16 +#define PORT_MAX_QUEUES 64 +#define PORT_THREAD_STACK (8u * 1024u * 1024u) + +typedef struct PortThread { + OSThread *os; /* game-visible thread object */ + OSId id; + void (*entry)(void *); + void *arg; + pthread_t th; + unsigned long tid; /* OS thread id (thread dumps) */ + int started; /* osStartThread called */ + int exited; /* entry returned / stopped / parked (idle) */ +} PortThread; + +static PortThread g_pt[PORT_MAX_THREADS]; + +/* Side table: OSMesgQueue* -> lock/cond. The game's OSMesgQueue struct has a + * fixed N64 layout, so the synchronization state lives here instead. */ +typedef struct PortQueue { + OSMesgQueue *os; + pthread_mutex_t lock; + pthread_cond_t cond; + int loggedFirstBlock; /* heartbeat aid: log each queue's first blocker */ +} PortQueue; + +static PortQueue g_pq[PORT_MAX_QUEUES]; +static int g_pqCount = 0; + +/* Heartbeat: if no frame has rendered for a while, dump thread + queue + * states so a hang shows up in the log instead of as a silent + * "Not Responding" window. */ +static uint64_t g_lastFrameUs = 0; +static uint64_t g_lastHeartbeatUs = 0; +static int g_framesRendered = 0; + +/* Forward decls: the VI retrace registration lives further down. */ +static OSMesgQueue *g_viRetraceMQ = NULL; +static OSMesg g_viRetraceMsg = 0; + +/* Vsync tick state: one VI retrace message per FRAME, at the console's + * frame rate (the N64 VI interrupt fires once per frame; GE calls + * osViSetEvent with NUM_FIELDS=1, i.e. "every retrace"). */ +static uint64_t g_nextTickUs = 0; +static uint32_t g_tickIntervalUs = 1000000 / 60; /* NTSC frame rate */ + +static PortThread *portFind(OSThread *t) +{ + for (int i = 0; i < PORT_MAX_THREADS; ++i) { + if (g_pt[i].os == t) return &g_pt[i]; + } + return NULL; +} + +static PortQueue *portQueueGet(OSMesgQueue *mq); +static void portPostVIEvent(void); +static void portServiceTimers(void); +static uint64_t portNextTimerUs(void); + +static void portHeartbeatCheck(void) +{ + uint64_t now = sysGetMicroseconds(); + if (now - g_lastFrameUs > 3000000 && now - g_lastHeartbeatUs > 2000000) { + g_lastHeartbeatUs = now; + sysLogPrintf(LOG_ERROR, + "kernel heartbeat: no frame rendered for %llu ms (frames=%d); state:", + (unsigned long long)(now - g_lastFrameUs), g_framesRendered); + for (int i = 0; i < PORT_MAX_THREADS; ++i) { + PortThread *t = &g_pt[i]; + if (!t->os) continue; + sysLogPrintf(LOG_ERROR, + " T%d(id=%d) os=%p entry_rel=%p started=%d exited=%d", + i, (int)t->id, (void *)t->os, + (void *)((uintptr_t)t->entry - sysImageBase()), + t->started, t->exited); + } + for (int i = 0; i < g_pqCount; ++i) { + OSMesgQueue *mq = g_pq[i].os; + if (!mq) continue; + sysLogPrintf(LOG_ERROR, + " mq=%p valid=%d/%d first=%d", + (void *)mq, mq->validCount, mq->msgCount, mq->first); + } + sysLogPrintf(LOG_ERROR, + " viRetraceMQ=%p msg=%llu tickInterval=%u us", + (void *)g_viRetraceMQ, + (unsigned long long)g_viRetraceMsg, g_tickIntervalUs); + + /* Where is every thread actually stuck? Unwind them all. */ + /* Indexed by game OSId (thread_config.h): RMON=0 IDLE=1 SCHED=2 + * MAIN=3 AUDI=4 TLB=5. */ + static const char *threadNames[6] = { + "rmonThread", "idleThread", "shedThread", + "mainThread", "audioThread", "tlbThread" + }; + unsigned long tids[PORT_MAX_THREADS]; + const char *names[PORT_MAX_THREADS]; + int n = 0; + for (int i = 0; i < PORT_MAX_THREADS && n < PORT_MAX_THREADS; ++i) { + if (g_pt[i].os && g_pt[i].started && !g_pt[i].exited) { + tids[n] = g_pt[i].tid; + names[n] = threadNames[g_pt[i].id >= 0 && g_pt[i].id < 6 ? g_pt[i].id : 3]; + ++n; + } + } + crashDumpThreads(tids, names, n); + } +} + +/* Dedicated pacemaker: posts the VI retrace message once per frame and + * services software timers. Runs forever on its own pthread so pacing + * continues no matter which game threads are blocked where. */ +static void *portTickThread(void *arg) +{ + (void)arg; + for (;;) { + uint64_t now = sysGetMicroseconds(); + if (!g_nextTickUs) g_nextTickUs = now + g_tickIntervalUs; + + /* Sleep until the earlier of the next tick and a due timer, in + * small chunks (simple, portable, accurate enough for 16.7 ms). */ + uint64_t wake = g_nextTickUs; + uint64_t tnext = portNextTimerUs(); + if (tnext < wake) wake = tnext; + while ((now = sysGetMicroseconds()) < wake) { + uint64_t chunk = wake - now; + if (chunk > 4000) chunk = 4000; + sysSleep((uint32_t)chunk); + } + + now = sysGetMicroseconds(); + if (now >= g_nextTickUs) { + g_nextTickUs += g_tickIntervalUs; + if (g_nextTickUs <= now) g_nextTickUs = now + g_tickIntervalUs; + portPostVIEvent(); + } + portServiceTimers(); + portHeartbeatCheck(); + } + return NULL; +} + +/* Call once from main() before running game code. */ +void portKernelInit(void) +{ + memset(g_pt, 0, sizeof(g_pt)); + g_pqCount = 0; + /* Anchor the heartbeat clock so the first check doesn't compare against + * epoch 0 (the host QPC has a large absolute offset). */ + g_lastFrameUs = sysGetMicroseconds(); + g_lastHeartbeatUs = g_lastFrameUs; + + if (osTvType == OS_TV_MPAL || osTvType == OS_TV_PAL) { + g_tickIntervalUs = 1000000 / 50; /* PAL: 50 frames/s -> 20ms */ + } else { + g_tickIntervalUs = 1000000 / 60; /* NTSC: 60 frames/s -> ~16.7ms */ + } + + pthread_t th; + if (pthread_create(&th, NULL, portTickThread, NULL) != 0) { + sysFatalError("portKernelInit: pthread_create(tick) failed"); + } + pthread_detach(th); +} + /* ------------------------------------------------------------------------ */ +/* Threads */ +/* ------------------------------------------------------------------------ */ + +/* pthread entry wrapper. */ +static void *portThreadWrapper(void *arg) +{ + PortThread *pt = (PortThread *)arg; + +#if defined(PLATFORM_WINDOWS) + pt->tid = GetCurrentThreadId(); +#else + pt->tid = (unsigned long)pthread_self(); +#endif + + /* The N64 idle thread is an infinite no-yield loop (idleproc). On the + * host it would just burn a core and nothing depends on it running, so + * park it instead. */ + if (pt->id == 1 /* IDLE_THREAD_ID */) { + pt->exited = 1; + for (;;) sysSleep(1000000); + return NULL; + } + + pt->entry(pt->arg); + pt->exited = 1; + if (pt->os) pt->os->state = OS_STATE_STOPPED; + return NULL; +} void osCreateThread(OSThread *t, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri prio) { - (void)entry; (void)arg; (void)sp; (void)prio; - if (t) { t->id = id; t->state = OS_STATE_STOPPED; } + PortThread *pt = NULL; + (void)sp; /* each host thread gets its own stack */ + for (int i = 0; i < PORT_MAX_THREADS; ++i) { + if (!g_pt[i].os) { pt = &g_pt[i]; break; } + } + if (!pt) { + sysFatalError("osCreateThread: out of port thread slots"); + return; + } + + memset(pt, 0, sizeof(*pt)); + pt->os = t; + pt->id = id; + pt->entry = entry; + pt->arg = arg; + + t->id = id; + t->priority = prio; + t->state = OS_STATE_STOPPED; } -void osStartThread(OSThread *t) { if (t) t->state = OS_STATE_RUNNING; } -void osStopThread(OSThread *t) { if (t) t->state = OS_STATE_STOPPED; } -void osDestroyThread(OSThread *t) { if (t) t->id = 0; } -void osYieldThread(void) { /* cooperative: nothing to do */ } -OSPri osGetThreadPri(OSThread *t) { (void)t; return 0; } -void osSetThreadPri(OSThread *t, OSPri prio) { (void)t; (void)prio; } +void osStartThread(OSThread *t) +{ + PortThread *pt = portFind(t); + if (!pt || pt->started) return; + pt->started = 1; + t->state = OS_STATE_RUNNABLE; + + pthread_attr_t attr; + int rc; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, PORT_THREAD_STACK); + rc = pthread_create(&pt->th, &attr, portThreadWrapper, pt); + pthread_attr_destroy(&attr); + if (rc != 0) { + sysFatalError("osStartThread: pthread_create failed (%d)", rc); + } +} + +void osStopThread(OSThread *t) +{ + PortThread *pt = portFind(t); + if (!pt) return; + /* A host thread cannot be killed mid-flight; mark it and let the entry + * run to completion (game code only stops threads at quiescent points). */ + pt->exited = 1; + t->state = OS_STATE_STOPPED; +} + +void osDestroyThread(OSThread *t) +{ + PortThread *pt = portFind(t); + if (!pt) return; + pt->os = NULL; + t->id = 0; +} + +void osYieldThread(void) +{ + /* GE rarely yields explicitly; a 1 ms sleep is a fine host equivalent + * (sched_yield() would need MinGW's , which the game's own + * src/sched.h shadows on the include path). */ + sysSleep(1); +} + +OSPri osGetThreadPri(OSThread *t) +{ + return t ? t->priority : 0; +} + +void osSetThreadPri(OSThread *t, OSPri prio) +{ + if (t) t->priority = prio; +} /* ------------------------------------------------------------------------ */ -/* Message queues — used by the scheduler / VI / controller callbacks. */ -/* Implement a simple ring buffer; see PD port for the exact semantics. */ +/* Message queues */ /* ------------------------------------------------------------------------ */ +static PortQueue *portQueueGet(OSMesgQueue *mq) +{ + for (int i = 0; i < g_pqCount; ++i) { + if (g_pq[i].os == mq) return &g_pq[i]; + } + if (g_pqCount >= PORT_MAX_QUEUES) { + sysFatalError("portQueueGet: out of port queue slots"); + } + PortQueue *pq = &g_pq[g_pqCount++]; + pq->os = mq; + pthread_mutex_init(&pq->lock, NULL); + pthread_cond_init(&pq->cond, NULL); + pq->loggedFirstBlock = 0; + return pq; +} + void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *first, s32 count) { - /* TODO(Phase 1): allocate + init ring buffer. */ - (void)mq; (void)first; (void)count; + memset(mq, 0, sizeof(*mq)); + mq->msg = first; + mq->msgCount = count; + (void)portQueueGet(mq); /* register lock/cond */ } + OSMesg osDequeueMesg(OSMesgQueue *mq) { - /* TODO(Phase 1) */ - (void)mq; - return NULL; + PortQueue *pq = portQueueGet(mq); + pthread_mutex_lock(&pq->lock); + OSMesg m = NULL; + if (mq->validCount > 0) { + m = mq->msg[mq->first]; + mq->first = (mq->first + 1) % mq->msgCount; + --mq->validCount; + pthread_cond_signal(&pq->cond); + } + pthread_mutex_unlock(&pq->lock); + return m; } + OSMesg osMesgQueueLast(OSMesgQueue *mq) { - /* TODO(Phase 1) */ - (void)mq; - return NULL; + PortQueue *pq = portQueueGet(mq); + pthread_mutex_lock(&pq->lock); + OSMesg m = (mq->validCount > 0) + ? mq->msg[(mq->first + mq->validCount - 1) % mq->msgCount] + : NULL; + pthread_mutex_unlock(&pq->lock); + return m; } + void osEnqueueMesg(OSMesgQueue *mq, OSMesg msg) { - /* TODO(Phase 1) */ - (void)mq; (void)msg; + PortQueue *pq = portQueueGet(mq); + pthread_mutex_lock(&pq->lock); + if (mq->validCount < mq->msgCount) { + mq->msg[(mq->first + mq->validCount) % mq->msgCount] = msg; + ++mq->validCount; + pthread_cond_signal(&pq->cond); + } + pthread_mutex_unlock(&pq->lock); } -/* - * High-level message API — the one the game actually uses (osSendMesg in 13 - * files, osRecvMesg in 26). The PD port's libultra.c defines these; in the - * single-threaded port they are largely no-ops / immediate, but the scheduler - * and audio code rely on the semantics, so implement them properly in Phase 1. - */ s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flag) { - /* TODO(Phase 1): enqueue msg; return 0 on success. */ - (void)mq; (void)msg; (void)flag; + PortQueue *pq = portQueueGet(mq); + pthread_mutex_lock(&pq->lock); + while (mq->validCount >= mq->msgCount) { + if (flag != OS_MESG_BLOCK) { + pthread_mutex_unlock(&pq->lock); + return -1; + } + pthread_cond_wait(&pq->cond, &pq->lock); + } + mq->msg[(mq->first + mq->validCount) % mq->msgCount] = msg; + ++mq->validCount; + pthread_cond_signal(&pq->cond); + pthread_mutex_unlock(&pq->lock); return 0; } + s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flag) { - /* TODO(Phase 1): dequeue into *msg; return 0 on success, -1 if empty. */ - (void)mq; (void)msg; (void)flag; + PortQueue *pq = portQueueGet(mq); + pthread_mutex_lock(&pq->lock); + while (mq->validCount == 0) { + if (flag != OS_MESG_BLOCK) { + pthread_mutex_unlock(&pq->lock); + return -1; + } + /* Log each queue's first blocking call site (the return address is + * the caller); symbolicate with addr2line to find where in game code + * this wait happens. */ + if (!pq->loggedFirstBlock) { + pq->loggedFirstBlock = 1; + void *ra = __builtin_return_address(0); + sysLogPrintf(LOG_NOTE, "first block on mq=%p from %p (rel %p)", + (void *)mq, ra, + (void *)((uintptr_t)ra - sysImageBase())); + } + pthread_cond_wait(&pq->cond, &pq->lock); + } + OSMesg m = mq->msg[mq->first]; + mq->first = (mq->first + 1) % mq->msgCount; + --mq->validCount; + if (msg) *msg = m; + pthread_cond_signal(&pq->cond); + pthread_mutex_unlock(&pq->lock); return 0; } -void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg) -{ - /* TODO(Phase 1) */ - (void)e; (void)mq; (void)msg; -} /* ------------------------------------------------------------------------ */ -/* VI (video) — map onto the port video layer. */ +/* Events (osSetEventMesg: "interrupt" -> message queue mapping) */ /* ------------------------------------------------------------------------ */ +typedef struct { + OSMesgQueue *mq; + OSMesg msg; + int used; +} PortEvent; + +static PortEvent g_events[16]; + +void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg) +{ + if (e < 16) { + g_events[e].mq = mq; + g_events[e].msg = msg; + g_events[e].used = 1; + } +} + +static void portPostEvent(OSId e) +{ + PortEvent *ev = &g_events[e]; + if (ev->used && ev->mq) { + osSendMesg(ev->mq, ev->msg, OS_MESG_NOBLOCK); + } +} + +/* ------------------------------------------------------------------------ */ +/* VI (video) — retrace pacing + framebuffer bookkeeping */ +/* ------------------------------------------------------------------------ */ + +static int g_viBlack = 1; /* start black, like the N64 VI */ + +void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount) +{ + (void)retraceCount; + g_viRetraceMQ = mq; + g_viRetraceMsg = msg; +} + +static void portPostVIEvent(void) +{ + if (g_viRetraceMQ) { + osSendMesg(g_viRetraceMQ, g_viRetraceMsg, OS_MESG_NOBLOCK); + } +} + void osViSetMode(OSViMode *vm) { - /* TODO(Phase 2): translate the requested mode into a window/GL viewport. */ - (void)vm; + if (!vm) return; + u32 w = vm->comRegs.width; + int pal = (vm->comRegs.ctrl & OS_VI_BIT_PAL) != 0; + s32 h = pal ? 400 : 480; /* visible height for LAN1 modes */ + if (w > 640) w = 640; + videoUpdateNativeResolution((s32)w, h); } + void osViSetSpecialFeatures(u32 f) { (void)f; } void osViVSyncCallback(OSMesgQueue *mq, OSMesg msg) { - /* TODO(Phase 2): the port scheduler calls this each frame. */ + /* Legacy VI sync hook; retrace comes from osViSetEvent instead. */ (void)mq; (void)msg; } -void osViWaitVSync(void) -{ - /* TODO(Phase 2): block until the next vsync (frame pacing). */ -} +void osViWaitVSync(void) { /* pacing is handled by the kernel tick */ } void osViSetSync(OSMesgQueue *mq, OSMesg msg) { (void)mq; (void)msg; } -void osViBlack(u8 active) -{ - /* TODO(Phase 2): if active, clear the screen (see PD port). */ - (void)active; -} +void osViBlack(u8 active) { g_viBlack = active; (void)g_viBlack; } void osViSetYScale(f32 value) { (void)value; } void osViSetXScale(f32 value) { (void)value; } -void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount) -{ (void)mq; (void)msg; (void)retraceCount; } -/* Per-mode VI scale tables. Defined in vi.c on N64 (excluded); fr.c computes - * and stores the values at runtime, so zero-init is safe until then. */ -f32 g_ViXScales[2] = { 0.0f, 0.0f }; -f32 g_ViYScales[2] = { 0.0f, 0.0f }; +/* __scTaskReady() requires these to compare equal, otherwise no gfx task + * ever runs. The software RSP draws straight into the GL back buffer, so a + * single constant "framebuffer" is all that's needed. */ +static u32 g_dummyFramebuffer = 0x1; +void *osViGetCurrentFramebuffer(void) { return &g_dummyFramebuffer; } +void *osViGetNextFramebuffer(void) { return &g_dummyFramebuffer; } + +/* The frame was already presented by videoEndFrame() inside + * osSpTaskStartGo(); nothing to do here. */ +void osViSwapBuffer(void *fb) { (void)fb; } +void osViRepeatLine(u8 line) { (void)line; } /* ------------------------------------------------------------------------ */ -/* AI (audio) — map onto the port audio layer. */ +/* AI (audio) — map onto the port audio layer. Phase 3. */ /* ------------------------------------------------------------------------ */ s32 osAiSetFrequency(u32 hz) { - /* TODO(Phase 3): store the output rate; audio.c uses it. - * Return the requested rate, as the N64 implementation reports the - * frequency actually set. */ return (s32)hz; } s32 osAiSetNextBuffer(void *buf, u32 size) @@ -204,10 +598,10 @@ void osAiSetConvert(u32 convert) { (void)convert; } /* * PI DMA is synchronous on the PC: romdata.c maps the .z64 at the N64 cart - * base (0x10000000), so an OS_READ from a cart address is a plain memcpy and - * the "completion" is already delivered by the time we return. The game's - * romReceiveMesg()/osRecvMesg() after every romCopy() is therefore satisfied - * trivially (see the message-queue shims below). + * base (0x10000000), so an OS_READ from a cart address is a plain memcpy. + * The N64 PI hardware posts the caller's OSMesgPI to the message queue on + * completion; osPiStartDma() below replicates that, because the game blocks + * in romReceiveMesg()/osRecvMesg() after every romCopy(). */ static void piServiceDma(s32 direction, u32 srcPA, void *dstVA, u32 size) { @@ -224,7 +618,7 @@ static void piServiceDma(s32 direction, u32 srcPA, void *dstVA, u32 size) memcpy(dstVA, (const void *)(uintptr_t)srcPA, size); } else { /* OS_WRITE: the game never writes the cart (saves go to EEPROM via - * osEeprom*, shimmed separately). Log once-style and drop. */ + * osEeprom*, shimmed separately). Log and drop. */ sysLogPrintf(LOG_WARNING, "osPiStartDma: cart write dropped (src=0x%08X size=0x%X)", srcPA, size); @@ -236,7 +630,13 @@ s32 osPiStartDma(OSIoMesg *mesg, s32 prio, s32 direction, u32 addr, void *buf, u32 size, OSMesgQueue *mq) { piServiceDma(direction, addr, buf, size); - (void)mesg; (void)prio; (void)mq; + (void)prio; + /* Post the completion message exactly like the PI hardware would — + * even when the DMA was skipped/dropped above, so callers never + * deadlock in osRecvMesg(). */ + if (mq) { + osSendMesg(mq, mesg ? (OSMesg)mesg : (OSMesg)1, OS_MESG_BLOCK); + } return 1; /* done */ } s32 osPiRawStartDma(s32 direction, u32 srcPA, void *dstVA, u32 size) @@ -250,7 +650,7 @@ u32 osPiGetStatus(void) { return 0; } /* not busy */ * PI device register read (normally src/libultra/io, EXCLUDED). token.c uses * it to read the cartridge token string. On the PC there is no cartridge * token register; return 0 (no token) so the game proceeds with an empty - * token. TODO(Phase 1): optionally back with a value from the ROM/config. + * token. */ s32 osPiReadIo(u32 devAddr, u32 *data) { @@ -260,41 +660,121 @@ s32 osPiReadIo(u32 devAddr, u32 *data) } /* ------------------------------------------------------------------------ */ -/* SI (controller / eeprom / mempak) — map onto input + file-backed saves. */ +/* SI (controller) — keyboard-backed. */ /* ------------------------------------------------------------------------ */ +/* errno is a macro in C (errno.h); the N64 structs have an `errno` field. + * Undefine it for this section and restore it afterwards. */ +#pragma push_macro("errno") +#undef errno + +static OSContStatus g_contStatus[MAXCONTROLLERS]; +static OSContPad g_contPad[MAXCONTROLLERS]; +static u8 g_contConnected = 0x1; /* controller 0 connected */ + +/* Keyboard -> N64 pad for controller 0: + * A: Z / Space B: X Start: Enter + * Z trigger: LCtrl C-stick: arrows D-pad: WASD + */ +static void contSnapshotFromKeyboard(void) +{ + /* SDL2: the keyboard state array is indexed by SCANCODE (512 entries). + * Non-ASCII SDLK_* constants carry a 0x40000000 flag (SDLK_UP == + * 0x40000052), so they must be masked to the scancode value before use + * as an index — indexing with the raw constant reads ~1 GB past the + * array and faults. */ +#define K(key) keys[(key) & 0xFFFF] + const uint8_t *keys = SDL_GetKeyboardState(NULL); + u16 button = 0; + s8 sx = 0, sy = 0; + + if (!keys) return; /* SDL not ready yet (first frames before videoInit) + * — leave the previous frame's pad state in place. */ + + if (K(SDLK_z) || K(SDLK_SPACE)) button |= CONT_A; + if (K(SDLK_x)) button |= CONT_B; + if (K(SDLK_LCTRL)) button |= CONT_G; /* Z trigger */ + if (K(SDLK_RETURN)) button |= CONT_START; + + /* C-stick (arrows) — GE's movement stick. */ + if (K(SDLK_UP)) sy = -80; + if (K(SDLK_DOWN)) sy = 80; + if (K(SDLK_LEFT)) sx = -80; + if (K(SDLK_RIGHT)) sx = 80; + + /* D-pad (WASD) — separate from the C-stick. */ + if (K(SDLK_w)) button |= CONT_UP; + if (K(SDLK_s)) button |= CONT_DOWN; + if (K(SDLK_a)) button |= CONT_LEFT; + if (K(SDLK_d)) button |= CONT_RIGHT; +#undef K + + g_contStatus[0].type = CONT_TYPE_NORMAL; + g_contStatus[0].status = 0; + g_contStatus[0].errno = 0; + /* The pad is kept in a parallel array; joy.c copies it via + * osContGetReadData(). */ + g_contPad[0].button = button; + g_contPad[0].stick_x = sx; + g_contPad[0].stick_y = sy; + g_contPad[0].errno = 0; + + for (int i = 1; i < MAXCONTROLLERS; ++i) { + g_contStatus[i].type = 0; + g_contStatus[i].status = 0; + g_contStatus[i].errno = CONT_NO_RESPONSE_ERROR; + g_contPad[i].button = 0; + g_contPad[i].stick_x = 0; + g_contPad[i].stick_y = 0; + g_contPad[i].errno = CONT_NO_RESPONSE_ERROR; + } +} + +#pragma pop_macro("errno") + s32 osContInit(OSMesgQueue *mesgq, u8 *bitpattern, OSContStatus *data) { - /* TODO(Phase 3): report inputGetNumControllers() as connected. */ - (void)mesgq; (void)bitpattern; (void)data; + (void)data; /* the game passes its own array; osContGetQuery fills it */ + if (bitpattern) *bitpattern = g_contConnected; return 0; } -s32 osContStartReadData(OSMesgQueue *mesgq) -{ - /* TODO(Phase 3): snapshot the current SDL input into the controller buf. */ - (void)mesgq; - return 0; -} -s32 osContStartQuery(OSMesgQueue *mq) -{ - /* TODO(Phase 3) */ - (void)mq; - return 0; -} -void osContGetQuery(OSContStatus *status) -{ - /* TODO(Phase 3): fill status for each connected controller. */ - (void)status; -} -void osContGetReadData(OSContPad *pad) -{ - /* TODO(Phase 3): fill pad from the current SDL input snapshot. */ - (void)pad; -} -/* EEPROM: back with a file in the data dir (see B2 — saves are EEPROM-based). - * TODO(Phase 4): see docs/PCPortResearch.md §7. */ -s32 osEepromProbe(OSMesgQueue *mq) { (void)mq; return 0; } +s32 osContStartReadData(OSMesgQueue *mesgq) +{ + contSnapshotFromKeyboard(); + /* Complete immediately: post the SI "done" message so a blocking + * osRecvMesg() right after (joy.c) returns at once. */ + if (mesgq) osSendMesg(mesgq, NULL, OS_MESG_NOBLOCK); + return 0; +} + +s32 osContStartQuery(OSMesgQueue *mq) +{ + contSnapshotFromKeyboard(); + if (mq) osSendMesg(mq, NULL, OS_MESG_NOBLOCK); + return 0; +} + +void osContGetQuery(OSContStatus *status) +{ + memcpy(status, g_contStatus, sizeof(g_contStatus)); +} + +void osContGetReadData(OSContPad *pad) +{ + *pad = g_contPad[0]; +} + +s32 osContReset(OSMesgQueue *mq, OSContStatus *status) +{ + (void)mq; + if (status) memcpy(status, g_contStatus, sizeof(g_contStatus)); + return 0; +} + +/* EEPROM: file-backed saves land in Phase 4. For now report "no eeprom" + * so the game proceeds without save functionality. */ +s32 osEepromProbe(OSMesgQueue *mq) { (void)mq; return -1; } s32 osEepromRead(OSMesgQueue *mq, u8 addr, u8 *buf) { (void)mq; (void)addr; (void)buf; return 0; } s32 osEepromWrite(OSMesgQueue *mq, u8 addr, u8 *buf) @@ -304,9 +784,7 @@ s32 osEepromLongRead(OSMesgQueue *mq, u8 addr, u8 *buf, int nbytes) s32 osEepromLongWrite(OSMesgQueue *mq, u8 addr, u8 *buf, int nbytes) { (void)mq; (void)addr; (void)buf; (void)nbytes; return 0; } -/* Memory Pak (PFS) + Rumble Pak (motor): accessory detection only (see B2). - * The PC has no Memory Pak; report "not plugged in" so the game proceeds - * without rumble/mempak. TODO(Phase 4): optionally back PFS with a file. */ +/* Memory Pak (PFS) + Rumble Pak (motor): no accessories on the PC. */ s32 osPfsInit(OSMesgQueue *queue, OSPfs *pfs, int channel) { (void)queue; (void)pfs; (void)channel; return PFS_ERR_NOPACK; } s32 osPfsIsPlug(OSMesgQueue *queue, u8 *pattern) @@ -317,25 +795,63 @@ s32 osMotorStart(OSPfs *pfs) { (void)pfs; return -1; } s32 osMotorStop(OSPfs *pfs) { (void)pfs; return -1; } /* ------------------------------------------------------------------------ */ -/* SP (RSP) — the port scheduler (gesched.c) drives the software RSP, so */ -/* these are mostly no-ops / bookkeeping. See gesched.c. */ +/* SP (RSP) — runs the software RSP inline, then posts the done messages */ +/* that sched.c's __scMain waits for. */ /* ------------------------------------------------------------------------ */ -void osSpTaskLoad(OSTask *t) { (void)t; /* handled by gesched.c */ } -void osSpTaskStartGo(OSTask *t) { (void)t; /* handled by gesched.c */ } -void osSpTaskYield(void) { /* handled by gesched.c */ } +void osSpTaskLoad(OSTask *t) { (void)t; /* nothing to load on the host */ } + +void osSpTaskStartGo(OSTask *t) +{ + if (t->t.type == M_AUDTASK) { + /* Phase 3: execute the audio ucode against t->t.data_ptr (an Acmd + * list). For now the task simply completes; libaudio's amMain still + * runs its per-frame bookkeeping. */ + } else { + /* Graphics task: run the software RSP on the display list. */ + uint64_t t0 = sysGetMicroseconds(); + videoStartFrame(); + gfx_run((Gfx *)t->t.data_ptr); + videoEndFrame(); + g_lastFrameUs = sysGetMicroseconds(); + if (++g_framesRendered <= 5 || (g_framesRendered % 300) == 0) + sysLogPrintf(LOG_NOTE, "frame %d rendered in %llu us", + g_framesRendered, + (unsigned long long)(sysGetMicroseconds() - t0)); + } + + portPostEvent(OS_EVENT_SP); + if (t->t.type != M_AUDTASK) { + /* A gfx task is also its own DP task (sp == dp in __scExec): the + * DP "finishes" right after the RSP. */ + portPostEvent(OS_EVENT_DP); + } +} + +void osSpTaskYield(void) { /* no cooperative RSP on the host */ } +OSYieldResult osSpTaskYielded(OSTask *t) { (void)t; return 0; } void osSpFlush(void) { /* no-op */ } void osSpSetFifo(void *fifo, int size, int flags) { (void)fifo; (void)size; (void)flags; } void *osSpGetFifo(void) { return NULL; } int osSpTaskDone(void) { return 1; } /* ------------------------------------------------------------------------ */ -/* RDP — bypassed (the software RSP emits GL directly). No-ops. */ +/* RDP — bypassed (the software RSP emits GL directly). */ /* ------------------------------------------------------------------------ */ void osDpSetStatus(u32 status) { (void)status; } u32 osDpGetStatus(void) { return 0; } -s32 osDpSetNextBuffer(void *buf, u64 size) { (void)buf; (void)size; return 1; } +s32 osDpSetNextBuffer(void *buf, u64 size) +{ + /* DP-only task: "rendering" is done by the time the RSP finished. */ + (void)buf; (void)size; + portPostEvent(OS_EVENT_DP); + return 1; +} +void osDpGetCounters(u32 *counters) +{ + if (counters) memset(counters, 0, sizeof(u32) * 4); +} /* ------------------------------------------------------------------------ */ /* Cache — no-op on the host (no split I/D cache to manage). */ @@ -375,15 +891,101 @@ u32 __osSetFpcCsr(u32 csr) { (void)csr; return 0; } void osUnmapTLB(int index) { (void)index; } /* ------------------------------------------------------------------------ */ -/* Timers / interrupts */ -/* ------------------------------------------------------------------------ */ +/* Timers / interrupts */ +/* ------------------------------------------------------------------------ + * + * Software timers. bossInitMainthreadData() paces controller init with a + * one-shot 100 ms osSetTimer()/osRecvMesg() pair, so timers must actually + * fire. They are serviced by the kernel tick thread: portServiceTimers() + * posts due messages and portNextTimerUs() lets the tick thread shorten its + * sleep to the earliest deadline. + */ + +#define PORT_MAX_TIMERS 8 + +typedef struct PortTimer { + OSTimer *os; + uint64_t fireUs; /* absolute deadline (sysGetMicroseconds domain) */ + uint32_t periodUs; /* 0 = one-shot */ + int active; +} PortTimer; + +static PortTimer g_ptimers[PORT_MAX_TIMERS]; + +/* cycles -> microseconds at the RSP counter rate. Inverse of + * OS_USEC_TO_CYCLES(). */ +static uint64_t portCyclesToUs(OSTime cycles) +{ + return (uint64_t)((double)cycles * 1000000.0 / (double)osClockRate); +} -/* Timers: the port runs a single-threaded loop; timers are serviced by the - * scheduler. TODO(Phase 1): wire to the port's frame clock. */ int osSetTimer(OSTimer *timer, OSTime start, OSTime period, OSMesgQueue *mq, OSMesg msg) -{ (void)timer; (void)start; (void)period; (void)mq; (void)msg; return 0; } -int osStopTimer(OSTimer *timer) { (void)timer; return 0; } +{ + PortTimer *pt = NULL; + int i; + + timer->interval = period; + timer->value = start; + timer->mq = mq; + timer->msg = msg; + + for (i = 0; i < PORT_MAX_TIMERS; ++i) { + if (g_ptimers[i].os == timer) { pt = &g_ptimers[i]; break; } + if (!g_ptimers[i].active && !pt) pt = &g_ptimers[i]; + } + if (!pt) return -1; + + pt->os = timer; + pt->active = 1; + pt->periodUs = (uint32_t)portCyclesToUs(period); + pt->fireUs = sysGetMicroseconds() + portCyclesToUs(start); + sysLogPrintf(LOG_NOTE, "timer set: t=%p start=%lluus period=%uus mq=%p", + (void *)timer, (unsigned long long)portCyclesToUs(start), + pt->periodUs, (void *)mq); + return 0; +} + +int osStopTimer(OSTimer *timer) +{ + int i; + for (i = 0; i < PORT_MAX_TIMERS; ++i) { + if (g_ptimers[i].os == timer) { + g_ptimers[i].active = 0; + return 0; + } + } + return -1; +} + +static void portServiceTimers(void) +{ + uint64_t now = sysGetMicroseconds(); + int i; + for (i = 0; i < PORT_MAX_TIMERS; ++i) { + PortTimer *pt = &g_ptimers[i]; + if (!pt->active) continue; + while (pt->fireUs <= now) { + sysLogPrintf(LOG_NOTE, "timer fire: t=%p mq=%p", + (void *)pt->os, (void *)pt->os->mq); + osSendMesg(pt->os->mq, pt->os->msg, OS_MESG_NOBLOCK); + if (!pt->periodUs) { pt->active = 0; break; } + pt->fireUs += pt->periodUs; + } + } +} + +/* Earliest timer deadline, or UINT64_MAX. */ +static uint64_t portNextTimerUs(void) +{ + uint64_t earliest = ~0ull; + int i; + for (i = 0; i < PORT_MAX_TIMERS; ++i) { + PortTimer *pt = &g_ptimers[i]; + if (pt->active && pt->fireUs < earliest) earliest = pt->fireUs; + } + return earliest; +} /* Interrupt mask: no hardware interrupts on the PC. */ OSIntMask osSetIntMask(OSIntMask mask) { (void)mask; return 0; } @@ -403,8 +1005,8 @@ void viDebugRemoved(void) } void viInit(void) { - /* VI init (normally src/vi.c, EXCLUDED). boss.c calls it during startup. - * TODO(Phase 2): initialise the port video layer here. */ + /* VI init (normally src/vi.c, EXCLUDED). The port video layer is + * already up by the time the game calls this. */ } /* VI debug message queue (normally src/vi.c, EXCLUDED). fr.c references it. */ diff --git a/port/src/main.c b/port/src/main.c index 80b58bf6..e0e11171 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -5,43 +5,49 @@ * On the PC we: * 1. set up system / config / fs / rom * 2. load the ROM and map it at the cart base (0x10000000) - * 3. init video (SDL2 + GL), audio, input - * 4. hand control to the game's mainproc() / bossEntry() - * - * Modelled on the PD port's port/src/main.c. - * - * STATUS: Phase 1 — ROM loads and maps, a window opens and clears each frame. - * Step 4 (mainproc) is deferred until the software RSP (fast3d) and the - * scheduler can service the game's rendering/audio threads; see - * docs/PCPortResearch.md. + * 3. init video (SDL2 + GL via fast3d), audio, input + * 4. start the thread kernel and run the game's mainproc() as a real OS + * thread (it IS the N64 mainThread) — which runs bossEntry(), the real + * game loop. The game's own scheduler (src/sched.c) drives frames; see + * docs/PCPortResearch.md. + * 5. the host main thread then owns SDL event pumping for the lifetime of + * the process (Windows only dispatches window messages to the creating + * thread, and every game thread can be blocked on a queue). */ #include #include #include +#include #include "platform.h" #include "system.h" #include "config.h" #include "fs.h" #include "romdata.h" +#include "dram.h" #include "video.h" #include "audio.h" #include "input.h" #include "mixer.h" +#include "crash.h" +#include "thread_config.h" /* Defined in the game (src/init.c). The port calls into the real game entry. */ extern void mainproc(void *args); +extern OSThread mainThread; /* src/init.c:75 */ int main(int argc, char **argv) { - (void)argc; - (void)argv; + sysSetArgs(argc, argv); sysLogPrintf(LOG_INFO, "GoldenEye 007 PC port starting " "(%s, %s)", GE007_ROMID, GE007_VERSION_HASH); + /* Crash handler first, so any failure below is debuggable. */ + crashInit(); + /* 1. Platform + config + filesystem. */ configLoad(); @@ -52,6 +58,25 @@ int main(int argc, char **argv) return 1; } + /* 2a. Sanity: the image MUST have loaded at its preferred base. + * dram_syms.s absolute symbols are referenced through pointer-typed + * externs, which on x86-64/PE become .refptr slots with BASE + * relocations. The build disables ASLR (--disable-dynamic-base) so the + * loader loads at 0x140000000 and those relocations are no-ops; if we + * ever got relocated, every such slot would be silently corrupted. + * Fail loudly instead. */ + if (sysImageBase() != 0x140000000ul) { + sysLogPrintf(LOG_ERROR, + "image loaded at %p, expected preferred base 0x140000000; " + "absolute DRAM symbols would be corrupted (ASLR must be off)", + (void *)sysImageBase()); + return 1; + } + + /* 2b. Reserve the N64-DRAM region: s32-safe view @ 0x70000000 (cfb_16, + * mempools) + KSEG0 mirror @ 0x80000000 (see port/src/dram.c). */ + dramReserve(); + /* 3. Video / audio / input. */ if (videoInit() != 0) { sysLogPrintf(LOG_ERROR, "videoInit failed"); @@ -61,27 +86,24 @@ int main(int argc, char **argv) mixerInit(); inputInit(); - /* 4. Phase 1 demo loop: clear colour until the RSP/scheduler can drive - * real frames (Phase 2). Press ESC or close the window to quit. - * - * When fast3d lands, replace this with mainproc(NULL) — defined in - * src/init.c (compiled for the PC; see A3 in docs/PCPortResearch.md). - * init.c's N64-only init() is never called; its hardware deps are - * stubbed in port/src/n64stubs.c and the libultra OS calls are shimmed - * in port/src/libultra.c. - */ - sysLogPrintf(LOG_INFO, "Phase 1: ROM mapped at 0x%08X (%u bytes); " - "demo loop running — ESC to quit", + /* 4. Run the game. mainproc() runs as the N64 mainThread (a real OS + * thread with its own stack); it creates the rmon/idle/scheduler/ + * audio threads and never returns in practice. */ + sysLogPrintf(LOG_INFO, "ROM mapped at 0x%08X (%u bytes); starting game", (unsigned)0x10000000, romdataGetRomSize()); + portKernelInit(); + osCreateThread(&mainThread, MAIN_THREAD_ID, &mainproc, NULL, NULL, + MAIN_THREAD_PRIORITY); + osStartThread(&mainThread); + + /* 5. Host thread: pump SDL events until the window is closed / ESC. + * videoPumpEvents() exits the process on quit. */ for (;;) { - if (videoHandleEvents()) - break; - videoStartFrame(); - videoSubmitCommands(NULL); /* no-op until fast3d lands */ - videoEndFrame(); + videoPumpEvents(); + sysSleep(8); } - /* Clean up. */ + /* Unreachable in practice; clean up if we ever get here. */ inputDestroy(); mixerDestroy(); audioDestroy(); diff --git a/port/src/n64stubs.c b/port/src/n64stubs.c index 9f8fba2f..03d9f33b 100644 --- a/port/src/n64stubs.c +++ b/port/src/n64stubs.c @@ -21,6 +21,7 @@ #include #include +#include #include /* --- Segment start/end getters (normally linker-script symbols) --------- */ @@ -44,8 +45,11 @@ u32 get_inflateSegmentRomEnd(void) { return 0; } * What remains here are pure-RAM segment symbols that have no ROM presence: * the host's own .bss/.csegment ends and the N64 vaddr markers (only used by * the never-run N64 boot path on the PC). + * + * _bssSegmentEnd is NOT here: it is an ABSOLUTE symbol in dram_syms.s + * (0x70050000, inside the s32-safe DRAM view — boss.c starts the mempools + * at PHYS_TO_K0(osVirtualToPhysical(&_bssSegmentEnd)); see port/src/dram.c). */ -u32 *_bssSegmentEnd = NULL; u32 *_csegmentSegmentStart = NULL; u32 *_csegmentSegmentEnd = NULL; u32 *_inflateSegmentVaddrStart = NULL; @@ -71,7 +75,15 @@ void resolve_TLBaddress_for_InvalidHit(void) { /* no-op */ } /* * tlb_manage.c is excluded (it manages the N64's 64-entry TLB for on-demand * ROM segment loading). boss.c still calls two of its functions from - * bossInitMainthreadData(); inert on the PC. + * bossInitMainthreadData(). + * + * tlbmanageGetTlbAllocatedBlock() is NOT inert: boss.c:218 uses it as the + * END of the mempool area (mempCheckMemflagTokens(start, block - start)). + * On the N64 it is page_align_down(&sp_boot) - MAPPING_TABLE_COUNT*PAGE_SIZE + * = 0x803AB400 - 93*0x2000 = 0x802F4400 (US .stacks). We keep that exact + * OFFSET (+0x2F4400 from the DRAM base) but express it in the s32-safe V1 + * view (see dram.c): 0x70000000 + 0x2F4400 = 0x702F4400, so [start, block) + * is live host memory and survives the s32 paths in src/memp.c. */ void tlbmanageEstablishManagementTable(void) { /* no-op */ } void tlbmanageResetCurrentEntriesCount(void) { /* no-op */ } @@ -79,7 +91,10 @@ void tlbmanageTranslateLoadRomFromTlbAddress(u32 address) { (void)address; } -u8 (*tlbmanageGetTlbAllocatedBlock(void))[TLB_BLOCK_SIZE] { return NULL; } +u8 (*tlbmanageGetTlbAllocatedBlock(void))[TLB_BLOCK_SIZE] +{ + return (u8 (*)[TLB_BLOCK_SIZE])0x702F4400; +} /* --- K&R libc helpers (IDO provided these; the host libc does not) ------- */ /* Signatures mirror include/PR/os.h:983 / include/bstring.h exactly. */ @@ -121,3 +136,18 @@ void osSyncPrintf(const char *fmt, ...) vfprintf(stderr, fmt, ap); va_end(ap); } + +/* --- VI manager (src/libultrare/io/vimgr.c, not built for PC) ----------- */ +/* sched.c's osCreateScheduler() calls osCreateViManager(OS_PRIORITY_VIMGR). */ +/* The N64 VI manager thread serviced video interrupts; on the port the */ +/* cooperative kernel posts the retrace message itself (port/src/libultra.c), */ +/* so this is a no-op. */ +void osCreateViManager(OSPri pri) { (void)pri; } + +/* --- Crash screen (src/crash.c, not built for PC) ------------------------ */ +/* src/crash.c is the game's TLB-fault diagnostics + rmon-driven crash */ +/* screen renderer. It depends on rmon and the N64 exception path, neither of */ +/* which exists here; real host faults are caught by port/src/crash.c instead.*/ +/* sched.c only calls this for the debug stderr overlay (off at boot), so a */ +/* no-op is safe. */ +void crashRenderFrame(u16 *buffer) { (void)buffer; } diff --git a/port/src/system.c b/port/src/system.c index 0534104c..b4363cc6 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -1,9 +1,7 @@ /* * Platform primitives: time, logging, paths, exit. * - * Modelled on the PD port's port/src/system.c (~315 lines). - * - * STATUS: scaffolding stub — implement during Phase 1. + * Modelled on the PD port's port/src/system.c. */ #include @@ -20,40 +18,72 @@ #include #include #else + #define _POSIX_C_SOURCE 199309L #include + #include #endif #include "system.h" /* --- Time --------------------------------------------------------------- */ +#if defined(PLATFORM_WINDOWS) +static LARGE_INTEGER g_qpcFreq; +#endif + uint64_t sysGetMicroseconds(void) { - /* TODO(Phase 1): use a monotonic clock. - * - Windows: QueryPerformanceCounter - * - POSIX: clock_gettime(CLOCK_MONOTONIC) - */ +#if defined(PLATFORM_WINDOWS) + static int inited = 0; + LARGE_INTEGER c; + if (!inited) { + QueryPerformanceFrequency(&g_qpcFreq); + inited = 1; + } + QueryPerformanceCounter(&c); + return (uint64_t)((double)c.QuadPart * 1000000.0 / (double)g_qpcFreq.QuadPart); +#else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000ull + (uint64_t)(ts.tv_nsec / 1000); +#endif +} + +uintptr_t sysImageBase(void) +{ +#if defined(PLATFORM_WINDOWS) + return (uintptr_t)GetModuleHandleW(NULL); +#else + /* TODO: parse /proc/self/maps for the first executable mapping. */ return 0; +#endif } int64_t sysGetTime(void) { - /* TODO(Phase 1): wall clock (time(NULL)). */ - return 0; + return (int64_t)time(NULL); } void sysSleep(uint32_t micros) { - /* TODO(Phase 1): Sleep() / usleep(). */ - (void)micros; +#if defined(PLATFORM_WINDOWS) + Sleep((DWORD)((micros + 999) / 1000)); +#else + struct timespec req; + req.tv_sec = micros / 1000000u; + req.tv_nsec = (long)(micros % 1000000u) * 1000L; + while (nanosleep(&req, &req) != 0) { /* EINTR: keep sleeping the rest */ + } +#endif } /* --- Logging ------------------------------------------------------------ */ void sysLogPrintf(enum LogLevel level, const char *fmt, ...) { - static const char *tags[] = { "ERROR", "WARN ", "INFO ", "DEBUG" }; + static const char *tags[] = { "ERROR", "WARN ", "NOTE ", "INFO ", "DEBUG" }; va_list ap; + if ((int)level >= 5) level = LOG_DEBUG; fprintf(stderr, "[%s] ", tags[level]); va_start(ap, fmt); vfprintf(stderr, fmt, ap); @@ -61,17 +91,83 @@ void sysLogPrintf(enum LogLevel level, const char *fmt, ...) fprintf(stderr, "\n"); } +void sysFatalError(const char *fmt, ...) +{ + va_list ap; + fflush(stdout); + fflush(stderr); + fprintf(stderr, "[FATAL] "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + fflush(stderr); + abort(); +} + +/* --- Command line ------------------------------------------------------- */ + +static int g_argc = 0; +static char **g_argv = NULL; + +void sysSetArgs(int argc, char **argv) +{ + g_argc = argc; + g_argv = argv; +} + +int sysArgCheck(const char *arg) +{ + for (int i = 1; i < g_argc; ++i) { + if (g_argv[i] && strcmp(g_argv[i], arg) == 0) + return 1; + } + return 0; +} + +const char *sysArgGetString(const char *arg) +{ + for (int i = 1; i < g_argc; ++i) { + if (g_argv[i] && strcmp(g_argv[i], arg) == 0) { + if (i + 1 < g_argc) + return g_argv[i + 1]; + } + } + return NULL; +} + +/* --- CPU ---------------------------------------------------------------- */ + +#if defined(PLATFORM_WINDOWS) + #define PORT_DO_YIELD() YieldProcessor() +#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) + #include + #define PORT_DO_YIELD() _mm_pause() +#else + #define PORT_DO_YIELD() do { } while (0) +#endif + +void sysCpuRelax(void) +{ + PORT_DO_YIELD(); +} + /* --- Paths -------------------------------------------------------------- */ static char exeDir[512] = "."; const char *sysGetExeDir(void) { - /* TODO(Phase 1): resolve the executable's directory. - * - Windows: GetModuleFileName - * - Linux: readlink /proc/self/exe - * - macOS: _NSGetExecutablePath - */ +#if defined(PLATFORM_WINDOWS) + if (exeDir[0] == '.' && exeDir[1] == 0) { + DWORD n = GetModuleFileNameA(NULL, exeDir, sizeof(exeDir) - 1); + if (n) { + char *slash = strrchr(exeDir, '\\'); + if (slash) + *slash = 0; + } + } +#endif return exeDir; } diff --git a/port/src/video.c b/port/src/video.c index b7db91ce..c0da09e2 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -1,198 +1,211 @@ /* - * Video: SDL2 window + OpenGL context + frame pacing. + * Video: SDL2 window + OpenGL context + frame pacing on top of fast3d. * - * Owns the GL context that the software RSP (fast3d) renders into. Drives the - * frame boundary hooks called by the port scheduler (gesched.c). + * The window itself lives in port/fast3d/gfx_sdl2.cpp (the wapi backend); + * this file wires the rendering API up, owns frame boundaries and FPS stats, + * and exposes the small surface the libultra VI shims need. * - * Phase 1: real window + GL context + clear colour, driven by the demo loop - * in main.c. gfx_* entry points are still the no-ops in gfxstub.c until the - * PD-derived fast3d lands (Phase 2); videoStartFrame/EndFrame do the GL work - * directly so a visible frame exists before that. + * Modelled on the PD port's port/src/video.c (slimmed: no options menu). */ -#include -#include +#include +#include +#include + +#include +#include #include "platform.h" #include "system.h" -#include "config.h" #include "video.h" -/* fast3d entry points (see port/fast3d/gfx_api.h). */ -extern void gfx_init(const void *settings); -extern void gfx_destroy(void); -extern void gfx_start_frame(void); -extern void gfx_run(void *commands); -extern void gfx_end_frame(void); +#include "../fast3d/gfx_api.h" +#include "../fast3d/gfx_sdl.h" +#include "../fast3d/gfx_opengl.h" -static int initDone = 0; -static int vidVsync = 1; -static int vidFpsLimit = 0; -static int vidFullscreen = 0; -static int vidMaximize = 0; +/* GE's internal resolution: NTSC LAN1 is 640x480; PAL LAN1 shows a + * 640x400 area. The window opens at the native size (1:1) by default. */ +#ifdef REFRESH_PAL +#define GE_NATIVE_W 640 +#define GE_NATIVE_H 400 +#else +#define GE_NATIVE_W 640 +#define GE_NATIVE_H 480 +#endif -static SDL_Window *vidWindow = NULL; -static SDL_GLContext vidGL = NULL; +static struct GfxWindowManagerAPI *wmAPI; +static struct GfxRenderingAPI *renderingAPI; +static int initDone = 0; -/* FPS accounting. */ -static uint64_t fpsLastTick = 0; -static int fpsFrames = 0; -static float fpsValue = 0.0f; +static u32 frames = 0; +static double fpsWindowStart = 0.0; +static int fpsNumFrames = 0; +static float vidAvgFPS = 0.f; int videoInit(void) { - if (initDone) - return 0; + wmAPI = &gfx_sdl; + renderingAPI = &gfx_opengl_api; - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - sysLogPrintf(LOG_ERROR, "videoInit: SDL_Init failed: %s", - SDL_GetError()); - return -1; - } + gfx_current_native_viewport.width = GE_NATIVE_W; + gfx_current_native_viewport.height = GE_NATIVE_H; + gfx_current_native_aspect = (float)GE_NATIVE_W / (float)GE_NATIVE_H; + gfx_framebuffers_enabled = true; + gfx_detail_textures_enabled = false; + gfx_msaa_level = 1; - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - /* fast3d will want a modern context once it lands; 3.0 core is the floor - * the PD port targets. */ - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + struct GfxInitSettings set = { + .wapi = wmAPI, + .rapi = renderingAPI, + .window_settings = { + .title = "GoldenEye 007", + .width = GE_NATIVE_W, + .height = GE_NATIVE_H, + .x = 100, + .y = 100, + .fullscreen = false, + .fullscreen_is_exclusive = false, + .maximized = false, + .centered = true, + .allow_hidpi = false, + }, + }; - int w = 640, h = 480; /* GE's internal resolution (NTSC) */ - Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - if (vidFullscreen) - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + gfx_init(&set); - vidWindow = SDL_CreateWindow("GoldenEye 007 (PC port)", - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, w, h, flags); - if (!vidWindow) { - sysLogPrintf(LOG_ERROR, "videoInit: SDL_CreateWindow failed: %s", - SDL_GetError()); - return -1; - } - if (vidMaximize) - SDL_MaximizeWindow(vidWindow); + /* VSync on; fast3d paces the window itself. */ + wmAPI->set_swap_interval(1); - vidGL = SDL_GL_CreateContext(vidWindow); - if (!vidGL) { - sysLogPrintf(LOG_ERROR, "videoInit: SDL_GL_CreateContext failed: %s", - SDL_GetError()); - return -1; - } - SDL_GL_MakeCurrent(vidWindow, vidGL); - SDL_GL_SetSwapInterval(vidVsync ? 1 : 0); + gfx_set_texture_filter(FILTER_LINEAR); + gfx_set_mipmap_filter(MIPMAP_LINEAR); - /* Phase 1 clear colour: dark blue-grey so the window is visibly alive. */ - glClearColor(0.10f, 0.12f, 0.16f, 1.0f); - glViewport(0, 0, w, h); - - /* fast3d hooks (no-ops until Phase 2). */ - gfx_init(NULL); - - fpsLastTick = sysGetMicroseconds(); initDone = 1; - sysLogPrintf(LOG_INFO, "videoInit: %dx%d window + GL context up", w, h); + sysLogPrintf(LOG_INFO, "video: %dx%d window (native %dx%d)", + (int)gfx_current_dimensions.width, (int)gfx_current_dimensions.height, + GE_NATIVE_W, GE_NATIVE_H); return 0; } void videoDestroy(void) { - if (!initDone) - return; - gfx_destroy(); - if (vidGL) { - SDL_GL_DeleteContext(vidGL); - vidGL = NULL; + if (initDone) { + gfx_destroy(); + initDone = 0; } - if (vidWindow) { - SDL_DestroyWindow(vidWindow); - vidWindow = NULL; - } - SDL_Quit(); - initDone = 0; -} - -/* - * Pump window events. Returns 1 when the app should quit (window close or - * ESC). Called by the demo loop until the port scheduler owns the frame - * boundary (Phase 2). - */ -int videoHandleEvents(void) -{ - SDL_Event e; - while (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT) - return 1; - if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) - return 1; - } - return 0; } void videoStartFrame(void) { - if (!initDone) + if (!initDone) { return; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + /* Rendering runs on the game's scheduler thread; the GL context was + * created on the host main thread. */ + gfx_sdl_make_context_current(); gfx_start_frame(); } +/* + * Host-thread SDL event pump. + * + * On Windows, window messages are only dispatched when the thread that + * CREATED the window pumps them — and every game thread can be blocked on a + * message queue at any time. So the host main thread (which created the + * window in videoInit) must keep pumping; otherwise the window goes + * "Not Responding" and ESC/close never arrive. fast3d's own handle_events + * (which runs during rendering) remains as a backstop. + */ +void videoPumpEvents(void) +{ + if (!initDone) { + return; + } + SDL_Event ev; + while (SDL_PollEvent(&ev)) { + switch (ev.type) { + case SDL_QUIT: + sysLogPrintf(LOG_INFO, "video: quit requested"); + exit(0); + break; + case SDL_KEYDOWN: + if (ev.key.keysym.sym == SDLK_ESCAPE) { + sysLogPrintf(LOG_INFO, "video: ESC -> quit"); + exit(0); + } + break; + case SDL_WINDOWEVENT: + if (ev.window.event == SDL_WINDOWEVENT_CLOSE) { + sysLogPrintf(LOG_INFO, "video: window closed"); + exit(0); + } else if (ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + gfx_sdl_update_cached_size(); + } + break; + default: + break; + } + } +} + void videoSubmitCommands(Gfx *cmds) { - if (initDone) - gfx_run(cmds); + if (!initDone) { + return; + } + gfx_run(cmds); } void videoEndFrame(void) { - if (!initDone) + if (!initDone) { return; + } gfx_end_frame(); - if (vidWindow) - SDL_GL_SwapWindow(vidWindow); - /* FPS accounting. */ - fpsFrames++; - uint64_t now = sysGetMicroseconds(); - if (now - fpsLastTick >= 1000000) { - fpsValue = (float)fpsFrames * 1000000.0f / (float)(now - fpsLastTick); - fpsFrames = 0; - fpsLastTick = now; + ++frames; + ++fpsNumFrames; + + double now = wmAPI->get_time(); + if (fpsWindowStart == 0.0) { + fpsWindowStart = now; + } + if (now - fpsWindowStart >= 1.0) { + vidAvgFPS = (float)(fpsNumFrames / (now - fpsWindowStart)); + fpsNumFrames = 0; + fpsWindowStart = now; } } -void videoSetVsync(int enabled) +float videoGetFPS(void) { - vidVsync = enabled; - if (initDone && vidWindow) - SDL_GL_SetSwapInterval(vidVsync ? 1 : 0); + return vidAvgFPS; } -void videoSetFramerateLimit(int fps) { vidFpsLimit = fps; /* TODO Phase 2 */ } -int videoGetFullscreen(void) { return vidFullscreen; } -void videoSetFullscreen(int enabled) -{ - vidFullscreen = enabled; - if (initDone && vidWindow) - SDL_SetWindowFullscreen(vidWindow, - enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); -} -int videoGetMaximize(void) { return vidMaximize; } -void videoSetMaximize(int enabled) -{ - vidMaximize = enabled; - if (initDone && vidWindow) { - if (enabled) - SDL_MaximizeWindow(vidWindow); - else - SDL_RestoreWindow(vidWindow); - } -} -float videoGetFPS(void) { return fpsValue; } -PD_CONSTRUCTOR static void videoConfigInit(void) +void videoUpdateNativeResolution(s32 w, s32 h) { - configRegisterInt("Video.Vsync", &vidVsync, 0, 1); - configRegisterInt("Video.FramerateLimit", &vidFpsLimit, 0, 240); - configRegisterInt("Video.Fullscreen", &vidFullscreen, 0, 1); - configRegisterInt("Video.Maximize", &vidMaximize, 0, 1); + if (w <= 0 || h <= 0) { + return; + } + gfx_current_native_viewport.width = w; + gfx_current_native_viewport.height = h; + gfx_current_native_aspect = (float)w / (float)h; +} + +s32 videoGetNativeWidth(void) { return gfx_current_native_viewport.width; } +s32 videoGetNativeHeight(void) { return gfx_current_native_viewport.height; } + +s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize) +{ + return gfx_create_framebuffer(w, h, upscale, autoresize); +} + +void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top) +{ + /* assume immediate copies always read the front buffer */ + gfx_copy_framebuffer(dst, src, left, top, false); +} + +void videoResetTextureCache(void) +{ + gfx_texture_cache_clear(); }