Initial commit

This commit is contained in:
Martin Felis
2021-11-11 21:22:24 +01:00
commit b78045ffe7
812 changed files with 421882 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
root=true
[**]
indent_style=space
indent_size=4
trim_trailing_whitespace=true
insert_final_newline=true
+223
View File
@@ -0,0 +1,223 @@
name: build_and_test
on: [push, pull_request]
jobs:
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
- name: win64-vstudio-debug
run: |
cd workspace/sokol-samples
python fips build win64-vstudio-debug
- name: win64-vstudio-release
run: |
cd workspace/sokol-samples
python fips build win64-vstudio-release
- name: d3d11-win64-vstudio-debug
run: |
cd workspace/sokol-samples
python fips build d3d11-win64-vstudio-debug
- name: d3d11-win64-vstudio-release
run: |
cd workspace/sokol-samples
python fips build d3d11-win64-vstudio-release
- name: sapp-win64-vstudio-debug
run: |
cd workspace/sokol-samples
python fips build sapp-win64-vstudio-debug
- name: sapp-win64-vstudio-release
run: |
cd workspace/sokol-samples
python fips build sapp-win64-vstudio-release
- name: sapp-d3d11-win64-vstudio-debug
run: |
cd workspace/sokol-samples
python fips build sapp-d3d11-win64-vstudio-debug
- name: sapp-d3d11-win64-vstudio-release
run: |
cd workspace/sokol-samples
python fips build sapp-d3d11-win64-vstudio-release
- name: sokol-test sapp-win64-vstudio-debug
run: |
cd workspace/sokol-samples
python fips run sokol-test sapp-win64-vstudio-debug
mac:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
- name: osx-make-debug
run: |
cd workspace/sokol-samples
python fips build osx-make-debug
- name: osx-make-release
run: |
cd workspace/sokol-samples
python fips build osx-make-release
- name: metal-osx-make-debug
run: |
cd workspace/sokol-samples
python fips build metal-osx-make-debug
- name: metal-osx-make-release
run: |
cd workspace/sokol-samples
python fips build metal-osx-make-release
- name: sapp-metal-osx-make-debug
run: |
cd workspace/sokol-samples
python fips build sapp-metal-osx-make-debug
- name: sapp-metal-osx-make-release
run: |
cd workspace/sokol-samples
python fips build sapp-metal-osx-make-release
- name: sokol-test sapp-metal-osx-make-debug
run: |
cd workspace/sokol-samples
python fips run sokol-test sapp-metal-osx-make-debug
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
- name: ios-xcode-debug
run: |
cd workspace/sokol-samples
python fips build ios-xcode-debug -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
- name: ios-xcode-release
run: |
cd workspace/sokol-samples
python fips build ios-xcode-release -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
- name: metal-ios-xcode-debug
run: |
cd workspace/sokol-samples
python fips build metal-ios-xcode-debug -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
- name: metal-ios-xcode-release
run: |
cd workspace/sokol-samples
python fips build metal-ios-xcode-release -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
- name: sapp-ios-xcode-debug
run: |
cd workspace/sokol-samples
python fips build sapp-ios-xcode-debug -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
- name: sapp-metal-ios-xcode-release
run: |
cd workspace/sokol-samples
python fips build sapp-metal-ios-xcode-debug -- CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
sudo apt-get update
sudo apt-get install libglu1-mesa-dev mesa-common-dev xorg-dev libasound-dev
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
- name: linux-make-debug
run: |
cd workspace/sokol-samples
python fips build linux-make-debug
- name: linux-make-release
run: |
cd workspace/sokol-samples
python fips build linux-make-release
- name: sapp-linux-make-debug
run: |
cd workspace/sokol-samples
python fips build sapp-linux-make-debug
- name: sapp-linux-make-release
run: |
cd workspace/sokol-samples
python fips build sapp-linux-make-release
- name: sapp-linux-make-debug
run: |
cd workspace/sokol-samples
python fips run sokol-test sapp-linux-make-debug
emscripten:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
sudo apt-get install ninja-build
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
python fips emsdk install latest
- name: sapp-webgl2-wasm-ninja-debug
run: |
cd workspace/sokol-samples
python fips build sapp-webgl2-wasm-ninja-debug
- name: sapp-webgl2-wasm-ninja-release
run: |
cd workspace/sokol-samples
python fips build sapp-webgl2-wasm-ninja-release
- name: wasm-ninja-debug
run: |
cd workspace/sokol-samples
python fips make cube-emsc wasm-ninja-debug
- name: wasm-ninja-release
run: |
cd workspace/sokol-samples
python fips make cube-emsc wasm-ninja-release
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '8'
- name: prepare
run: |
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
yes | python fips setup android
- name: sapp-android-make-debug
run: |
cd workspace/sokol-samples
python fips build sapp-android-make-debug
- name: sapp-android-make-release
run: |
cd workspace/sokol-samples
python fips build sapp-android-make-release
uwp:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: prepare
run: |
mkdir workspace
cd workspace
git clone https://github.com/floooh/sokol-samples
cd sokol-samples
- name: sapp-uwp-vstudio-debug
run: |
cd workspace/sokol-samples
python fips build sapp-uwp-vstudio-debug
- name: sapp-uwp-vstudio-release
run: |
cd workspace/sokol-samples
python fips build sapp-uwp-vstudio-release
+6
View File
@@ -0,0 +1,6 @@
.vscode/
#>fips
# this area is managed by fips, do not edit
.fips-*
*.pyc
#<fips
+1131
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
+449
View File
@@ -0,0 +1,449 @@
# Sokol
[![Build Status](https://github.com/floooh/sokol/workflows/build_and_test/badge.svg)](https://github.com/floooh/sokol/actions)
Simple
[STB-style](https://github.com/nothings/stb/blob/master/docs/stb_howto.txt)
cross-platform libraries for C and C++, written in C.
[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**08-Oct-2021** revisited and cleaned up texture compression support in sokol_gfx.h)
## Examples and Related Projects
- [Live Samples](https://floooh.github.io/sokol-html5/index.html) via WASM ([source](https://github.com/floooh/sokol-samples))
- [Doom Shareware](https://floooh.github.io/doom-sokol/) ported to the Sokol headers ([source](https://github.com/floooh/doom-sokol))
- [LearnOpenGL examples ported to sokol-gfx](https://www.geertarien.com/learnopengl-examples-html5/) by @geertarien (cool stuff!)
- [Dear ImGui starterkit](https://github.com/floooh/cimgui-sokol-starterkit) a self-contained starterkit for writing Dear ImGui apps in C.
- [Tiny 8-bit emulators](https://floooh.github.io/tiny8bit/)
- A 'single-file' [Pacman clone in C99](https://github.com/floooh/pacman.c/), also available in [Zig](https://github.com/floooh/pacman.zig/)
- A [Minigolf game](https://mgerdes.github.io/minigolf.html) ([source](https://github.com/mgerdes/minigolf)).
- ['Dealer's Dungeon'](https://dealers-dungeon.com/demo/) ([lower graphics quality](https://dealers-dungeon.com/demo/?q=3),
[source](https://github.com/bqqbarbhg/spear))
- [Command line tools](https://github.com/floooh/sokol-tools) (shader compiler)
- [How to build without a build system](https://github.com/floooh/sokol-samples#how-to-build-without-a-build-system):
useful details for integrating the Sokol headers into your own project with your favourite C/C++ build system
## Core libraries
- [**sokol\_gfx.h**](https://github.com/floooh/sokol/blob/master/sokol_gfx.h): 3D-API wrapper (GL + Metal + D3D11)
- [**sokol\_app.h**](https://github.com/floooh/sokol/blob/master/sokol_app.h): app framework wrapper (entry + window + 3D-context + input)
- [**sokol\_time.h**](https://github.com/floooh/sokol/blob/master/sokol_time.h): time measurement
- [**sokol\_audio.h**](https://github.com/floooh/sokol/blob/master/sokol_audio.h): minimal buffer-streaming audio playback
- [**sokol\_fetch.h**](https://github.com/floooh/sokol/blob/master/sokol_fetch.h): asynchronous data streaming from HTTP and local filesystem
- [**sokol\_args.h**](https://github.com/floooh/sokol/blob/master/sokol_args.h): unified cmdline/URL arg parser for web and native apps
## Utility libraries
- [**sokol\_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h): sokol_gfx.h rendering backend for [Dear ImGui](https://github.com/ocornut/imgui)
- [**sokol\_nuklear.h**](https://github.com/floooh/sokol/blob/master/util/sokol_nuklear.h): sokol_gfx.h rendering backend for [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear)
- [**sokol\_gl.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gl.h): OpenGL 1.x style immediate-mode rendering API on top of sokol_gfx.h
- [**sokol\_fontstash.h**](https://github.com/floooh/sokol/blob/master/util/sokol_fontstash.h): sokol_gl.h rendering backend for [fontstash](https://github.com/memononen/fontstash)
- [**sokol\_gfx\_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gfx_imgui.h): debug-inspection UI for sokol_gfx.h (implemented with Dear ImGui)
- [**sokol\_debugtext.h**](https://github.com/floooh/sokol/blob/master/util/sokol_debugtext.h): a simple text renderer using vintage home computer fonts
- [**sokol\_memtrack.h**](https://github.com/floooh/sokol/blob/master/util/sokol_memtrack.h): easily track memory allocations in sokol headers
- [**sokol\_shape.h**](https://github.com/floooh/sokol/blob/master/util/sokol_shape.h): generate simple shapes and plug them into sokol-gfx resource creation structs
- [**sokol\_color.h**](https://github.com/floooh/sokol/blob/master/util/sokol_color.h): X11 style color constants and functions for creating sg_color objects
## Notes
WebAssembly is a 'first-class citizen', one important motivation for the
Sokol headers is to provide a collection of cross-platform APIs with a
minimal footprint on the web platform while still being useful.
The core headers are standalone and can be used independently from each other.
### Why C:
- easier integration with other languages
- easier integration into other projects
- adds only minimal size overhead to executables
A blog post with more background info: [A Tour of sokol_gfx.h](http://floooh.github.io/2017/07/29/sokol-gfx-tour.html)
# sokol_gfx.h:
- simple, modern wrapper around GLES2/WebGL, GLES3/WebGL2, GL3.3, D3D11 and Metal
- buffers, images, shaders, pipeline-state-objects and render-passes
- does *not* handle window creation or 3D API context initialization
- does *not* provide shader dialect cross-translation (**BUT** there's now an 'official' shader-cross-compiler solution which
seamlessly integrates with sokol_gfx.h and IDEs: [see here for details](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md)
A triangle in C99 with GLFW:
```c
#define SOKOL_IMPL
#define SOKOL_GLCORE33
#include "sokol_gfx.h"
#define GLFW_INCLUDE_NONE
#include "GLFW/glfw3.h"
int main() {
/* create window and GL context via GLFW */
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* w = glfwCreateWindow(640, 480, "Sokol Triangle GLFW", 0, 0);
glfwMakeContextCurrent(w);
glfwSwapInterval(1);
/* setup sokol_gfx */
sg_setup(&(sg_desc){0});
/* a vertex buffer */
const float vertices[] = {
// positions // colors
0.0f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f
};
sg_buffer vbuf = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(vertices)
});
/* a shader */
sg_shader shd = sg_make_shader(&(sg_shader_desc){
.vs.source =
"#version 330\n"
"layout(location=0) in vec4 position;\n"
"layout(location=1) in vec4 color0;\n"
"out vec4 color;\n"
"void main() {\n"
" gl_Position = position;\n"
" color = color0;\n"
"}\n",
.fs.source =
"#version 330\n"
"in vec4 color;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = color;\n"
"}\n"
});
/* a pipeline state object (default render states are fine for triangle) */
sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){
.shader = shd,
.layout = {
.attrs = {
[0].format=SG_VERTEXFORMAT_FLOAT3,
[1].format=SG_VERTEXFORMAT_FLOAT4
}
}
});
/* resource bindings */
sg_bindings bind = {
.vertex_buffers[0] = vbuf
};
/* default pass action (clear to grey) */
sg_pass_action pass_action = {0};
/* draw loop */
while (!glfwWindowShouldClose(w)) {
int cur_width, cur_height;
glfwGetFramebufferSize(w, &cur_width, &cur_height);
sg_begin_default_pass(&pass_action, cur_width, cur_height);
sg_apply_pipeline(pip);
sg_apply_bindings(&bind);
sg_draw(0, 3, 1);
sg_end_pass();
sg_commit();
glfwSwapBuffers(w);
glfwPollEvents();
}
/* cleanup */
sg_shutdown();
glfwTerminate();
return 0;
}
```
# sokol_app.h
A minimal cross-platform application-wrapper library:
- unified application entry
- single window or canvas for 3D rendering
- 3D context initialization
- event-based keyboard, mouse and touch input
- supported platforms: Win32, MacOS, Linux (X11), iOS, WASM, Android, UWP
- supported 3D-APIs: GL3.3 (GLX/WGL), Metal, D3D11, GLES2/WebGL, GLES3/WebGL2
A simple clear-loop sample using sokol_app.h and sokol_gfx.h (does not include
separate sokol.c/.m implementation file which is necessary
to split the Objective-C code from the C code of the sample):
```c
#include "sokol_gfx.h"
#include "sokol_app.h"
#include "sokol_glue.h"
sg_pass_action pass_action;
void init(void) {
sg_setup(&(sg_desc){
.context = sapp_sgcontext()
});
pass_action = (sg_pass_action) {
.colors[0] = { .action=SG_ACTION_CLEAR, .value={1.0f, 0.0f, 0.0f, 1.0f} }
};
}
void frame(void) {
float g = pass_action.colors[0].value.g + 0.01f;
pass_action.colors[0].value.g = (g > 1.0f) ? 0.0f : g;
sg_begin_default_pass(&pass_action, sapp_width(), sapp_height());
sg_end_pass();
sg_commit();
}
void cleanup(void) {
sg_shutdown();
}
sapp_desc sokol_main(int argc, char* argv[]) {
return (sapp_desc){
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.width = 400,
.height = 300,
.window_title = "Clear Sample",
};
}
```
# sokol_audio.h
A minimal audio-streaming API:
- you provide a mono- or stereo-stream of 32-bit float samples which sokol_audio.h forwards into platform-specific backends
- two ways to provide the data:
1. directly fill backend audio buffer from your callback function running in the audio thread
2. alternatively push small packets of audio data from your main loop,
or a separate thread created by you
- platform backends:
- Windows: WASAPI
- macOS/iOS: CoreAudio
- Linux: ALSA
- emscripten: WebAudio + ScriptProcessorNode (doesn't use the emscripten-provided OpenAL or SDL Audio wrappers)
A simple mono square-wave generator using the callback model:
```c
// the sample callback, running in audio thread
static void stream_cb(float* buffer, int num_frames, int num_channels) {
assert(1 == num_channels);
static uint32_t count = 0;
for (int i = 0; i < num_frames; i++) {
buffer[i] = (count++ & (1<<3)) ? 0.5f : -0.5f;
}
}
int main() {
// init sokol-audio with default params
saudio_setup(&(saudio_desc){
.stream_cb = stream_cb
});
// run main loop
...
// shutdown sokol-audio
saudio_shutdown();
return 0;
```
The same code using the push-model
```c
#define BUF_SIZE (32)
int main() {
// init sokol-audio with default params, no callback
saudio_setup(&(saudio_desc){0});
assert(saudio_channels() == 1);
// a small intermediate buffer so we don't need to push
// individual samples, which would be quite inefficient
float buf[BUF_SIZE];
int buf_pos = 0;
uint32_t count = 0;
// push samples from main loop
bool done = false;
while (!done) {
// generate and push audio samples...
int num_frames = saudio_expect();
for (int i = 0; i < num_frames; i++) {
// simple square wave generator
buf[buf_pos++] = (count++ & (1<<3)) ? 0.5f : -0.5f;
if (buf_pos == BUF_SIZE) {
buf_pos = 0;
saudio_push(buf, BUF_SIZE);
}
}
// handle other per-frame stuff...
...
}
// shutdown sokol-audio
saudio_shutdown();
return 0;
}
```
# sokol_fetch.h
Load entire files, or stream data asynchronously over HTTP (emscripten/wasm)
or the local filesystem (all native platforms).
Simple C99 example loading a file into a static buffer:
```c
#include "sokol_fetch.h"
static void response_callback(const sfetch_response*);
#define MAX_FILE_SIZE (1024*1024)
static uint8_t buffer[MAX_FILE_SIZE];
// application init
static void init(void) {
...
// setup sokol-fetch with default config:
sfetch_setup(&(sfetch_desc_t){0});
// start loading a file into a statically allocated buffer:
sfetch_send(&(sfetch_request_t){
.path = "hello_world.txt",
.callback = response_callback
.buffer_ptr = buffer,
.buffer_size = sizeof(buffer)
});
}
// per frame...
static void frame(void) {
...
// need to call sfetch_dowork() once per frame to 'turn the gears':
sfetch_dowork();
...
}
// the response callback is where the interesting stuff happens:
static void response_callback(const sfetch_response_t* response) {
if (response->fetched) {
// data has been loaded into the provided buffer, do something
// with the data...
const void* data = response->buffer_ptr;
uint64_t data_size = response->fetched_size;
}
// the finished flag is set both on success and failure
if (response->failed) {
// oops, something went wrong
switch (response->error_code) {
SFETCH_ERROR_FILE_NOT_FOUND: ...
SFETCH_ERROR_BUFFER_TOO_SMALL: ...
...
}
}
}
// application shutdown
static void shutdown(void) {
...
sfetch_shutdown();
...
}
```
# sokol_time.h:
Simple cross-platform time measurement:
```c
#include "sokol_time.h"
...
/* initialize sokol_time */
stm_setup();
/* take start timestamp */
uint64_t start = stm_now();
...some code to measure...
/* compute elapsed time */
uint64_t elapsed = stm_since(start);
/* convert to time units */
double seconds = stm_sec(elapsed);
double milliseconds = stm_ms(elapsed);
double microseconds = stm_us(elapsed);
double nanoseconds = stm_ns(elapsed);
/* difference between 2 time stamps */
uint64_t start = stm_now();
...
uint64_t end = stm_now();
uint64_t elapsed = stm_diff(end, start);
/* compute a 'lap time' (e.g. for fps) */
uint64_t last_time = 0;
while (!done) {
...render something...
double frame_time_ms = stm_ms(stm_laptime(&last_time));
}
```
# sokol_args.h
Unified argument parsing for web and native apps. Uses argc/argv on native
platforms and the URL query string on the web.
Example URL with one arg:
https://floooh.github.io/tiny8bit/kc85.html?type=kc85_4
The same as command line app:
> kc85 type=kc85_4
Parsed like this:
```c
#include "sokol_args.h"
int main(int argc, char* argv[]) {
sargs_setup(&(sargs_desc){ .argc=argc, .argv=argv });
if (sargs_exists("type")) {
if (sargs_equals("type", "kc85_4")) {
// start as KC85/4
}
else if (sargs_equals("type", "kc85_3")) {
// start as KC85/3
}
else {
// start as KC85/2
}
}
sargs_shutdown();
return 0;
}
```
See the sokol_args.h header for a more complete documentation, and the [Tiny
Emulators](https://floooh.github.io/tiny8bit/) for more interesting usage examples.
+6
View File
@@ -0,0 +1,6 @@
*.json
*.nim
*.zig
__pycache__/
sokol-nim/
sokol-zig/
+36
View File
@@ -0,0 +1,36 @@
## Language Binding Generation Scripts
### Zig
First make sure that clang and python3 are in the path:
```
> clang --version
> python3 --version
```
...on Windows I simply install those with scoop:
```
> scoop install llvm
> scoop install python
```
To update the Zig bindings:
```
> cd sokol/bindgen
> git clone https://github.com/floooh/sokol-zig
> git clone https://github.com/floooh/sokol-nim
> python3 gen_all.py
```
Test and run samples:
```
> cd sokol/bindgen/sokol-zig
> zig build run-clear
> zig build run-triangle
> zig build run-cube
...
```
+27
View File
@@ -0,0 +1,27 @@
import os, gen_nim, gen_zig
tasks = [
[ '../sokol_gfx.h', 'sg_', [] ],
[ '../sokol_app.h', 'sapp_', [] ],
[ '../sokol_time.h', 'stm_', [] ],
[ '../sokol_audio.h', 'saudio_', [] ],
[ '../util/sokol_gl.h', 'sgl_', ['sg_'] ],
[ '../util/sokol_debugtext.h', 'sdtx_', ['sg_'] ],
[ '../util/sokol_shape.h', 'sshape_', ['sg_'] ],
]
# Nim
gen_nim.prepare()
for task in tasks:
c_header_path = task[0]
main_prefix = task[1]
dep_prefixes = task[2]
gen_nim.gen(c_header_path, main_prefix, dep_prefixes)
# Zig
gen_zig.prepare()
for task in tasks:
c_header_path = task[0]
main_prefix = task[1]
dep_prefixes = task[2]
gen_zig.gen(c_header_path, main_prefix, dep_prefixes)
+122
View File
@@ -0,0 +1,122 @@
#-------------------------------------------------------------------------------
# Generate an intermediate representation of a clang AST dump.
#-------------------------------------------------------------------------------
import json, sys, subprocess
def is_api_decl(decl, prefix):
if 'name' in decl:
return decl['name'].startswith(prefix)
elif decl['kind'] == 'EnumDecl':
# an anonymous enum, check if the items start with the prefix
return decl['inner'][0]['name'].lower().startswith(prefix)
else:
return False
def is_dep_decl(decl, dep_prefixes):
for prefix in dep_prefixes:
if is_api_decl(decl, prefix):
return True
return False
def dep_prefix(decl, dep_prefixes):
for prefix in dep_prefixes:
if is_api_decl(decl, prefix):
return prefix
return None
def filter_types(str):
return str.replace('_Bool', 'bool')
def parse_struct(decl):
outp = {}
outp['kind'] = 'struct'
outp['name'] = decl['name']
outp['fields'] = []
for item_decl in decl['inner']:
if item_decl['kind'] != 'FieldDecl':
sys.exit(f"ERROR: Structs must only contain simple fields ({decl['name']})")
item = {}
if 'name' in item_decl:
item['name'] = item_decl['name']
item['type'] = filter_types(item_decl['type']['qualType'])
outp['fields'].append(item)
return outp
def parse_enum(decl):
outp = {}
if 'name' in decl:
outp['kind'] = 'enum'
outp['name'] = decl['name']
needs_value = False
else:
outp['kind'] = 'consts'
needs_value = True
outp['items'] = []
for item_decl in decl['inner']:
if item_decl['kind'] == 'EnumConstantDecl':
item = {}
item['name'] = item_decl['name']
if 'inner' in item_decl:
const_expr = item_decl['inner'][0]
if const_expr['kind'] != 'ConstantExpr':
sys.exit(f"ERROR: Enum values must be a ConstantExpr ({decl['name']})")
if const_expr['valueCategory'] != 'rvalue':
sys.exit(f"ERROR: Enum value ConstantExpr must be 'rvalue' ({decl['name']})")
if not ((len(const_expr['inner']) == 1) and (const_expr['inner'][0]['kind'] == 'IntegerLiteral')):
sys.exit(f"ERROR: Enum value ConstantExpr must have exactly one IntegerLiteral ({decl['name']})")
item['value'] = const_expr['inner'][0]['value']
if needs_value and 'value' not in item:
sys.exit(f"ERROR: anonymous enum items require an explicit value")
outp['items'].append(item)
return outp
def parse_func(decl):
outp = {}
outp['kind'] = 'func'
outp['name'] = decl['name']
outp['type'] = filter_types(decl['type']['qualType'])
outp['params'] = []
if 'inner' in decl:
for param in decl['inner']:
if param['kind'] != 'ParmVarDecl':
print(f"warning: ignoring func {decl['name']} (unsupported parameter type)")
return None
outp_param = {}
outp_param['name'] = param['name']
outp_param['type'] = filter_types(param['type']['qualType'])
outp['params'].append(outp_param)
return outp
def parse_decl(decl):
kind = decl['kind']
if kind == 'RecordDecl':
return parse_struct(decl)
elif kind == 'EnumDecl':
return parse_enum(decl)
elif kind == 'FunctionDecl':
return parse_func(decl)
else:
return None
def clang(csrc_path):
cmd = ['clang', '-Xclang', '-ast-dump=json', '-c' ]
cmd.append(csrc_path)
return subprocess.check_output(cmd)
def gen(header_path, source_path, module, main_prefix, dep_prefixes):
ast = clang(source_path)
inp = json.loads(ast)
outp = {}
outp['module'] = module
outp['prefix'] = main_prefix
outp['dep_prefixes'] = dep_prefixes
outp['decls'] = []
for decl in inp['inner']:
is_dep = is_dep_decl(decl, dep_prefixes)
if is_api_decl(decl, main_prefix) or is_dep:
outp_decl = parse_decl(decl)
if outp_decl is not None:
outp_decl['is_dep'] = is_dep
outp_decl['dep_prefix'] = dep_prefix(decl, dep_prefixes)
outp['decls'].append(outp_decl)
return outp
+562
View File
@@ -0,0 +1,562 @@
#-------------------------------------------------------------------------------
# Read output of gen_json.py and generate Zig language bindings.
#
# Nim coding style:
# - types and constants are PascalCase
# - functions, parameters, and fields are camelCase
#-------------------------------------------------------------------------------
import gen_ir
import json, re, os, shutil
module_names = {
'sg_': 'gfx',
'sapp_': 'app',
'stm_': 'time',
'saudio_': 'audio',
'sgl_': 'gl',
'sdtx_': 'debugtext',
'sshape_': 'shape',
}
c_source_paths = {
'sg_': 'sokol-nim/src/sokol/c/sokol_gfx.c',
'sapp_': 'sokol-nim/src/sokol/c/sokol_app.c',
'stm_': 'sokol-nim/src/sokol/c/sokol_time.c',
'saudio_': 'sokol-nim/src/sokol/c/sokol_audio.c',
'sgl_': 'sokol-nim/src/sokol/c/sokol_gl.c',
'sdtx_': 'sokol-nim/src/sokol/c/sokol_debugtext.c',
'sshape_': 'sokol-nim/src/sokol/c/sokol_shape.c',
}
func_name_ignores = [
'sdtx_printf',
'sdtx_vprintf',
]
func_name_overrides = {
'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
'sgl_deg': 'sgl_as_degrees',
'sgl_rad': 'sgl_as_radians',
}
struct_field_type_overrides = {
'sg_context_desc.color_format': 'int',
'sg_context_desc.depth_format': 'int',
}
prim_types = {
'int': 'int32',
'bool': 'bool',
'char': 'char',
'int8_t': 'int8',
'uint8_t': 'uint8',
'int16_t': 'int16',
'uint16_t': 'uint16',
'int32_t': 'int32',
'uint32_t': 'uint32',
'int64_t': 'int64',
'uint64_t': 'uint64',
'float': 'float32',
'double': 'float64',
'uintptr_t': 'uint',
'intptr_t': 'int',
'size_t': 'int',
}
prim_defaults = {
'int': '0',
'bool': 'false',
'int8_t': '0',
'uint8_t': '0',
'int16_t': '0',
'uint16_t': '0',
'int32_t': '0',
'uint32_t': '0',
'int64_t': '0',
'uint64_t': '0',
'float': '0.0',
'double': '0.0',
'uintptr_t': '0',
'intptr_t': '0',
'size_t': '0'
}
struct_types = []
enum_types = []
enum_items = {}
out_lines = ''
def reset_globals():
global struct_types
global enum_types
global enum_items
global out_lines
struct_types = []
enum_types = []
enum_items = {}
out_lines = ''
re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
def l(s):
global out_lines
out_lines += s + '\n'
def as_nim_prim_type(s):
return prim_types[s]
# prefix_bla_blub(_t) => (dep.)BlaBlub
def as_nim_struct_type(s, prefix):
parts = s.lower().split('_')
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
for part in parts[1:]:
if (part != 't'):
outp += part.capitalize()
return outp
# prefix_bla_blub(_t) => (dep.)BlaBlub
def as_nim_enum_type(s, prefix):
parts = s.lower().split('_')
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
for part in parts[1:]:
if (part != 't'):
outp += part.capitalize()
return outp
# prefix_bla_blub(_t) => (dep.)BlaBlub
def as_nim_const_type(s, prefix):
parts = s.lower().split('_')
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
for part in parts[1:]:
if (part != 't'):
outp += part.capitalize()
return outp
def check_struct_field_type_override(struct_name, field_name, orig_type):
s = f"{struct_name}.{field_name}"
if s in struct_field_type_overrides:
return struct_field_type_overrides[s]
else:
return orig_type
def check_func_name_ignore(func_name):
return func_name in func_name_ignores
def check_func_name_override(func_name):
if func_name in func_name_overrides:
return func_name_overrides[func_name]
else:
return func_name
def trim_prefix(s, prefix):
outp = s;
if outp.lower().startswith(prefix.lower()):
outp = outp[len(prefix):]
return outp
# PREFIX_BLA_BLUB to bla_blub
def as_snake_case(s, prefix = ""):
return trim_prefix(s, prefix).lower()
# prefix_bla_blub => blaBlub
def as_camel_case(s, prefix = ""):
parts = trim_prefix(s, prefix).lower().split('_')
outp = parts[0]
for part in parts[1:]:
outp += part.capitalize()
return outp
# prefix_bla_blub => BlaBlub
def as_pascal_case(s, prefix):
parts = trim_prefix(s, prefix).lower().split('_')
outp = ""
for part in parts:
outp += part.capitalize()
return outp
# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
def as_enum_item_name(s):
outp = s
if outp.startswith('_'):
outp = outp[1:]
parts = outp.lower().split('_')[2:]
outp = ""
for part in parts:
outp += part.capitalize()
if outp[0].isdigit():
outp = 'N' + outp
return outp
def enum_default_item(enum_name):
return enum_items[enum_name][0]
def is_prim_type(s):
return s in prim_types
def is_struct_type(s):
return s in struct_types
def is_enum_type(s):
return s in enum_types
def is_string_ptr(s):
return s == "const char *"
def is_const_void_ptr(s):
return s == "const void *"
def is_void_ptr(s):
return s == "void *"
def is_const_prim_ptr(s):
for prim_type in prim_types:
if s == f"const {prim_type} *":
return True
return False
def is_prim_ptr(s):
for prim_type in prim_types:
if s == f"{prim_type} *":
return True
return False
def is_const_struct_ptr(s):
for struct_type in struct_types:
if s == f"const {struct_type} *":
return True
return False
def is_func_ptr(s):
return '(*)' in s
def is_1d_array_type(s):
return re_1d_array.match(s)
def is_2d_array_type(s):
return re_2d_array.match(s)
def type_default_value(s):
return prim_defaults[s]
def extract_array_type(s):
return s[:s.index('[')].strip()
def extract_array_nums(s):
return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
def extract_ptr_type(s):
tokens = s.split()
if tokens[0] == 'const':
return tokens[1]
else:
return tokens[0]
def as_extern_c_arg_type(arg_type, prefix):
if arg_type == "void":
return "void"
elif is_prim_type(arg_type):
return as_nim_prim_type(arg_type)
elif is_struct_type(arg_type):
return as_nim_struct_type(arg_type, prefix)
elif is_enum_type(arg_type):
return as_nim_enum_type(arg_type, prefix)
elif is_void_ptr(arg_type):
return "pointer"
elif is_const_void_ptr(arg_type):
return "pointer"
elif is_string_ptr(arg_type):
return "cstring"
elif is_const_struct_ptr(arg_type):
return f"ptr {as_nim_struct_type(extract_ptr_type(arg_type), prefix)}"
elif is_prim_ptr(arg_type):
return f"[*c] {as_nim_prim_type(extract_ptr_type(arg_type))}"
elif is_const_prim_ptr(arg_type):
return f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
else:
return '??? (as_extern_c_arg_type)'
def as_nim_arg_type(arg_prefix, arg_type, prefix):
# NOTE: if arg_prefix is None, the result is used as return value
pre = "" if arg_prefix is None else arg_prefix
if arg_type == "void":
if arg_prefix is None:
return "void"
else:
return ""
elif is_prim_type(arg_type):
return pre + as_nim_prim_type(arg_type)
elif is_struct_type(arg_type):
return pre + as_nim_struct_type(arg_type, prefix)
elif is_enum_type(arg_type):
return pre + as_nim_enum_type(arg_type, prefix)
elif is_void_ptr(arg_type):
return pre + "pointer"
elif is_const_void_ptr(arg_type):
return pre + "pointer"
elif is_string_ptr(arg_type):
return pre + "cstring"
elif is_const_struct_ptr(arg_type):
return pre + f"ptr {as_nim_struct_type(extract_ptr_type(arg_type), prefix)}"
elif is_prim_ptr(arg_type):
return pre + f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
elif is_const_prim_ptr(arg_type):
return pre + f"ptr {as_nim_prim_type(extract_ptr_type(arg_type))}"
else:
return arg_prefix + "??? (as_nim_arg_type)"
# get C-style arguments of a function pointer as string
def funcptr_args_c(field_type, prefix):
tokens = field_type[field_type.index('(*)')+4:-1].split(',')
s = ""
n = 0
for token in tokens:
n += 1
arg_type = token.strip()
if s != "":
s += ", "
c_arg = f"a{n}:" + as_extern_c_arg_type(arg_type, prefix)
if (c_arg == "void"):
return ""
else:
s += c_arg
if s == "a1:void":
s = ""
return s
# get C-style result of a function pointer as string
def funcptr_res_c(field_type):
res_type = field_type[:field_type.index('(*)')].strip()
if res_type == 'void':
return ''
elif is_const_void_ptr(res_type):
return ':pointer'
else:
return '???'
def funcdecl_args_c(decl, prefix):
s = ""
for param_decl in decl['params']:
if s != "":
s += ", "
arg_type = param_decl['type']
s += as_extern_c_arg_type(arg_type, prefix)
return s
def funcdecl_args_nim(decl, prefix):
s = ""
for param_decl in decl['params']:
if s != "":
s += ", "
arg_name = param_decl['name']
arg_type = param_decl['type']
s += f"{as_nim_arg_type(f'{arg_name}:', arg_type, prefix)}"
return s
def funcdecl_res_c(decl, prefix):
decl_type = decl['type']
res_type = decl_type[:decl_type.index('(')].strip()
return as_extern_c_arg_type(res_type, prefix)
def funcdecl_res_nim(decl, prefix):
decl_type = decl['type']
res_type = decl_type[:decl_type.index('(')].strip()
nim_res_type = as_nim_arg_type(None, res_type, prefix)
if nim_res_type == "":
nim_res_type = "void"
return nim_res_type
def gen_struct(decl, prefix, use_raw_name=False):
struct_name = decl['name']
nim_type = struct_name if use_raw_name else as_nim_struct_type(struct_name, prefix)
l(f"type {nim_type}* = object")
isPublic = True
for field in decl['fields']:
field_name = field['name']
if field_name == "__pad":
# FIXME: these should be guarded by SOKOL_ZIG_BINDINGS, but aren't?
continue
isPublic = not field_name.startswith("_")
field_name = as_camel_case(field_name, "_")
if field_name == "ptr":
field_name = "source"
if field_name == "ref":
field_name = "`ref`"
if field_name == "type":
field_name = "`type`"
if isPublic:
field_name += "*"
field_type = field['type']
field_type = check_struct_field_type_override(struct_name, field_name, field_type)
if is_prim_type(field_type):
l(f" {field_name}:{as_nim_prim_type(field_type)}")
elif is_struct_type(field_type):
l(f" {field_name}:{as_nim_struct_type(field_type, prefix)}")
elif is_enum_type(field_type):
l(f" {field_name}:{as_nim_enum_type(field_type, prefix)}")
elif is_string_ptr(field_type):
l(f" {field_name}:cstring")
elif is_const_void_ptr(field_type):
l(f" {field_name}:pointer")
elif is_void_ptr(field_type):
l(f" {field_name}:pointer")
elif is_const_prim_ptr(field_type):
l(f" {field_name}:ptr {as_nim_prim_type(extract_ptr_type(field_type))}")
elif is_func_ptr(field_type):
l(f" {field_name}:proc({funcptr_args_c(field_type, prefix)}){funcptr_res_c(field_type)} {{.cdecl.}}")
elif is_1d_array_type(field_type):
array_type = extract_array_type(field_type)
array_nums = extract_array_nums(field_type)
if is_prim_type(array_type) or is_struct_type(array_type):
if is_prim_type(array_type):
nim_type = as_nim_prim_type(array_type)
elif is_struct_type(array_type):
nim_type = as_nim_struct_type(array_type, prefix)
elif is_enum_type(array_type):
nim_type = as_nim_enum_type(array_type, prefix)
else:
nim_type = '??? (array type)'
t0 = f"array[{array_nums[0]}, {nim_type}]"
t0_slice = f"[]const {nim_type}"
t1 = f"[_]{nim_type}"
l(f" {field_name}:{t0}")
elif is_const_void_ptr(array_type):
l(f" {field_name}:array[{array_nums[0]}, pointer]")
else:
l(f"// FIXME: ??? array {field_name}:{field_type} => {array_type} [{array_nums[0]}]")
elif is_2d_array_type(field_type):
array_type = extract_array_type(field_type)
array_nums = extract_array_nums(field_type)
if is_prim_type(array_type):
nim_type = as_nim_prim_type(array_type)
def_val = type_default_value(array_type)
elif is_struct_type(array_type):
nim_type = as_nim_struct_type(array_type, prefix)
def_val = ".{ }"
else:
nim_type = "???"
def_val = "???"
t0 = f"array[{array_nums[0]}, array[{array_nums[1]}, {nim_type}]]"
l(f" {field_name}:{t0}")
else:
l(f"// FIXME: {field_name}:{field_type};")
l("")
def gen_consts(decl, prefix):
l("const")
for item in decl['items']:
l(f" {trim_prefix(item['name'], prefix)}* = {item['value']}")
l("")
def gen_enum(decl, prefix):
item_names_by_value = {}
value = -1
hasForceU32 = False
hasExplicitValues = False
for item in decl['items']:
itemName = item['name']
if itemName.endswith("_FORCE_U32"):
hasForceU32 = True
elif itemName.endswith("_NUM"):
continue
else:
if 'value' in item:
hasExplicitValues = True
value = int(item['value'])
else:
value += 1
item_names_by_value[value] = as_enum_item_name(item['name']);
if hasForceU32:
l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure, size:4.}} = enum")
else:
l(f"type {as_nim_enum_type(decl['name'], prefix)}* {{.pure.}} = enum")
if hasExplicitValues:
# Nim requires explicit enum values to be declared in ascending order
for value in sorted(item_names_by_value):
name = item_names_by_value[value]
l(f" {name} = {value},")
else:
for name in item_names_by_value.values():
l(f" {name},")
l("")
def gen_func_nim(decl, prefix):
c_func_name = decl['name']
nim_func_name = as_camel_case(decl['name'], prefix)
nim_res_type = funcdecl_res_nim(decl, prefix)
l(f"proc {nim_func_name}*({funcdecl_args_nim(decl, prefix)}):{funcdecl_res_nim(decl, prefix)} {{.cdecl, importc:\"{decl['name']}\".}}")
l("")
def pre_parse(inp):
global struct_types
global enum_types
for decl in inp['decls']:
kind = decl['kind']
if kind == 'struct':
struct_types.append(decl['name'])
elif kind == 'enum':
enum_name = decl['name']
enum_types.append(enum_name)
enum_items[enum_name] = []
for item in decl['items']:
enum_items[enum_name].append(as_enum_item_name(item['name']))
def gen_imports(inp, dep_prefixes):
for dep_prefix in dep_prefixes:
dep_module_name = module_names[dep_prefix]
l(f'import {dep_module_name}')
l('')
def gen_module(inp, dep_prefixes):
l('## machine generated, do not edit')
l('')
gen_imports(inp, dep_prefixes)
pre_parse(inp)
prefix = inp['prefix']
for decl in inp['decls']:
if not decl['is_dep']:
kind = decl['kind']
if kind == 'consts':
gen_consts(decl, prefix)
elif kind == 'enum':
gen_enum(decl, prefix)
elif kind == 'struct':
gen_struct(decl, prefix)
elif kind == 'func':
if not check_func_name_ignore(decl['name']):
gen_func_nim(decl, prefix)
def prepare():
print('Generating nim bindings:')
if not os.path.isdir('sokol-nim/src/sokol'):
os.makedirs('sokol-nim/src/sokol')
if not os.path.isdir('sokol-nim/src/sokol/c'):
os.makedirs('sokol-nim/src/sokol/c')
def gen(c_header_path, c_prefix, dep_c_prefixes):
global out_lines
module_name = module_names[c_prefix]
c_source_path = c_source_paths[c_prefix]
print(f' {c_header_path} => {module_name}')
reset_globals()
shutil.copyfile(c_header_path, f'sokol-nim/src/sokol/c/{os.path.basename(c_header_path)}')
ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
gen_module(ir, dep_c_prefixes)
output_path = f"sokol-nim/src/sokol/{ir['module']}.nim"
## some changes for readability
out_lines = out_lines.replace("PixelformatInfo", "PixelFormatInfo")
out_lines = out_lines.replace(" Dontcare,", " DontCare,")
out_lines = out_lines.replace(" Vertexbuffer,", " VertexBuffer,")
out_lines = out_lines.replace(" Indexbuffer,", " IndexBuffer,")
out_lines = out_lines.replace(" N2d,", " Plane,")
out_lines = out_lines.replace(" N3d,", " Volume,")
out_lines = out_lines.replace(" Vs,", " Vertex,")
out_lines = out_lines.replace(" Fs,", " Fragment,")
## include extensions in generated code
l("# Nim-specific API extensions")
l(f"include nim/{ir['module']}")
with open(output_path, 'w', newline='\n') as f_outp:
f_outp.write(out_lines)
+576
View File
@@ -0,0 +1,576 @@
#-------------------------------------------------------------------------------
# Read output of gen_json.py and generate Zig language bindings.
#
# Zig coding style:
# - types are PascalCase
# - functions are camelCase
# - otherwise snake_case
#-------------------------------------------------------------------------------
import gen_ir
import json, re, os, shutil
module_names = {
'sg_': 'gfx',
'sapp_': 'app',
'stm_': 'time',
'saudio_': 'audio',
'sgl_': 'gl',
'sdtx_': 'debugtext',
'sshape_': 'shape',
}
c_source_paths = {
'sg_': 'sokol-zig/src/sokol/c/sokol_gfx.c',
'sapp_': 'sokol-zig/src/sokol/c/sokol_app.c',
'stm_': 'sokol-zig/src/sokol/c/sokol_time.c',
'saudio_': 'sokol-zig/src/sokol/c/sokol_audio.c',
'sgl_': 'sokol-zig/src/sokol/c/sokol_gl.c',
'sdtx_': 'sokol-zig/src/sokol/c/sokol_debugtext.c',
'sshape_': 'sokol-zig/src/sokol/c/sokol_shape.c',
}
name_ignores = [
'sdtx_printf',
'sdtx_vprintf',
'sg_install_trace_hooks',
'sg_trace_hooks',
]
name_overrides = {
'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
'sgl_deg': 'sgl_as_degrees',
'sgl_rad': 'sgl_as_radians'
}
# NOTE: syntax for function results: "func_name.RESULT"
type_overrides = {
'sg_context_desc.color_format': 'int',
'sg_context_desc.depth_format': 'int',
'sg_apply_uniforms.ub_index': 'uint32_t',
'sg_draw.base_element': 'uint32_t',
'sg_draw.num_elements': 'uint32_t',
'sg_draw.num_instances': 'uint32_t',
'sshape_element_range_t.base_element': 'uint32_t',
'sshape_element_range_t.num_elements': 'uint32_t',
'sdtx_font.font_index': 'uint32_t',
}
prim_types = {
'int': 'i32',
'bool': 'bool',
'char': 'u8',
'int8_t': 'i8',
'uint8_t': 'u8',
'int16_t': 'i16',
'uint16_t': 'u16',
'int32_t': 'i32',
'uint32_t': 'u32',
'int64_t': 'i64',
'uint64_t': 'u64',
'float': 'f32',
'double': 'f64',
'uintptr_t': 'usize',
'intptr_t': 'isize',
'size_t': 'usize'
}
prim_defaults = {
'int': '0',
'bool': 'false',
'int8_t': '0',
'uint8_t': '0',
'int16_t': '0',
'uint16_t': '0',
'int32_t': '0',
'uint32_t': '0',
'int64_t': '0',
'uint64_t': '0',
'float': '0.0',
'double': '0.0',
'uintptr_t': '0',
'intptr_t': '0',
'size_t': '0'
}
struct_types = []
enum_types = []
enum_items = {}
out_lines = ''
def reset_globals():
global struct_types
global enum_types
global enum_items
global out_lines
struct_types = []
enum_types = []
enum_items = {}
out_lines = ''
re_1d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]$")
re_2d_array = re.compile("^(?:const )?\w*\s\*?\[\d*\]\[\d*\]$")
def l(s):
global out_lines
out_lines += s + '\n'
def as_zig_prim_type(s):
return prim_types[s]
# prefix_bla_blub(_t) => (dep.)BlaBlub
def as_zig_struct_type(s, prefix):
parts = s.lower().split('_')
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
for part in parts[1:]:
if (part != 't'):
outp += part.capitalize()
return outp
# prefix_bla_blub(_t) => (dep.)BlaBlub
def as_zig_enum_type(s, prefix):
parts = s.lower().split('_')
outp = '' if s.startswith(prefix) else f'{parts[0]}.'
for part in parts[1:]:
if (part != 't'):
outp += part.capitalize()
return outp
def check_type_override(func_or_struct_name, field_or_arg_name, orig_type):
s = f"{func_or_struct_name}.{field_or_arg_name}"
if s in type_overrides:
return type_overrides[s]
else:
return orig_type
def check_name_override(name):
if name in name_overrides:
return name_overrides[name]
else:
return name
def check_name_ignore(name):
return name in name_ignores
# PREFIX_BLA_BLUB to bla_blub
def as_snake_case(s, prefix):
outp = s.lower()
if outp.startswith(prefix):
outp = outp[len(prefix):]
return outp
# prefix_bla_blub => blaBlub
def as_camel_case(s):
parts = s.lower().split('_')[1:]
outp = parts[0]
for part in parts[1:]:
outp += part.capitalize()
return outp
# PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
def as_enum_item_name(s):
outp = s
if outp.startswith('_'):
outp = outp[1:]
parts = outp.split('_')[2:]
outp = '_'.join(parts)
if outp[0].isdigit():
outp = '_' + outp
return outp
def enum_default_item(enum_name):
return enum_items[enum_name][0]
def is_prim_type(s):
return s in prim_types
def is_struct_type(s):
return s in struct_types
def is_enum_type(s):
return s in enum_types
def is_string_ptr(s):
return s == "const char *"
def is_const_void_ptr(s):
return s == "const void *"
def is_void_ptr(s):
return s == "void *"
def is_const_prim_ptr(s):
for prim_type in prim_types:
if s == f"const {prim_type} *":
return True
return False
def is_prim_ptr(s):
for prim_type in prim_types:
if s == f"{prim_type} *":
return True
return False
def is_const_struct_ptr(s):
for struct_type in struct_types:
if s == f"const {struct_type} *":
return True
return False
def is_func_ptr(s):
return '(*)' in s
def is_1d_array_type(s):
return re_1d_array.match(s)
def is_2d_array_type(s):
return re_2d_array.match(s)
def type_default_value(s):
return prim_defaults[s]
def extract_array_type(s):
return s[:s.index('[')].strip()
def extract_array_nums(s):
return s[s.index('['):].replace('[', ' ').replace(']', ' ').split()
def extract_ptr_type(s):
tokens = s.split()
if tokens[0] == 'const':
return tokens[1]
else:
return tokens[0]
def as_extern_c_arg_type(arg_type, prefix):
if arg_type == "void":
return "void"
elif is_prim_type(arg_type):
return as_zig_prim_type(arg_type)
elif is_struct_type(arg_type):
return as_zig_struct_type(arg_type, prefix)
elif is_enum_type(arg_type):
return as_zig_enum_type(arg_type, prefix)
elif is_void_ptr(arg_type):
return "?*c_void"
elif is_const_void_ptr(arg_type):
return "?*const c_void"
elif is_string_ptr(arg_type):
return "[*c]const u8"
elif is_const_struct_ptr(arg_type):
return f"[*c]const {as_zig_struct_type(extract_ptr_type(arg_type), prefix)}"
elif is_prim_ptr(arg_type):
return f"[*c] {as_zig_prim_type(extract_ptr_type(arg_type))}"
elif is_const_prim_ptr(arg_type):
return f"[*c]const {as_zig_prim_type(extract_ptr_type(arg_type))}"
else:
return '??? (as_extern_c_arg_type)'
def as_zig_arg_type(arg_prefix, arg_type, prefix):
# NOTE: if arg_prefix is None, the result is used as return value
pre = "" if arg_prefix is None else arg_prefix
if arg_type == "void":
if arg_prefix is None:
return "void"
else:
return ""
elif is_prim_type(arg_type):
return pre + as_zig_prim_type(arg_type)
elif is_struct_type(arg_type):
return pre + as_zig_struct_type(arg_type, prefix)
elif is_enum_type(arg_type):
return pre + as_zig_enum_type(arg_type, prefix)
elif is_void_ptr(arg_type):
return pre + "?*c_void"
elif is_const_void_ptr(arg_type):
return pre + "?*const c_void"
elif is_string_ptr(arg_type):
return pre + "[:0]const u8"
elif is_const_struct_ptr(arg_type):
# not a bug, pass const structs by value
return pre + f"{as_zig_struct_type(extract_ptr_type(arg_type), prefix)}"
elif is_prim_ptr(arg_type):
return pre + f"* {as_zig_prim_type(extract_ptr_type(arg_type))}"
elif is_const_prim_ptr(arg_type):
return pre + f"*const {as_zig_prim_type(extract_ptr_type(arg_type))}"
else:
return arg_prefix + "??? (as_zig_arg_type)"
# get C-style arguments of a function pointer as string
def funcptr_args_c(field_type, prefix):
tokens = field_type[field_type.index('(*)')+4:-1].split(',')
s = ""
for token in tokens:
arg_type = token.strip()
if s != "":
s += ", "
c_arg = as_extern_c_arg_type(arg_type, prefix)
if (c_arg == "void"):
return ""
else:
s += c_arg
return s
# get C-style result of a function pointer as string
def funcptr_res_c(field_type):
res_type = field_type[:field_type.index('(*)')].strip()
if res_type == 'void':
return 'void'
elif is_const_void_ptr(res_type):
return '?*const c_void'
else:
return '???'
def funcdecl_args_c(decl, prefix):
s = ""
func_name = decl['name']
for param_decl in decl['params']:
if s != "":
s += ", "
param_name = param_decl['name']
param_type = check_type_override(func_name, param_name, param_decl['type'])
s += as_extern_c_arg_type(param_type, prefix)
return s
def funcdecl_args_zig(decl, prefix):
s = ""
func_name = decl['name']
for param_decl in decl['params']:
if s != "":
s += ", "
param_name = param_decl['name']
param_type = check_type_override(func_name, param_name, param_decl['type'])
s += f"{as_zig_arg_type(f'{param_name}: ', param_type, prefix)}"
return s
def funcdecl_result_c(decl, prefix):
func_name = decl['name']
decl_type = decl['type']
result_type = check_type_override(func_name, 'RESULT', decl_type[:decl_type.index('(')].strip())
return as_extern_c_arg_type(result_type, prefix)
def funcdecl_result_zig(decl, prefix):
func_name = decl['name']
decl_type = decl['type']
result_type = check_type_override(func_name, 'RESULT', decl_type[:decl_type.index('(')].strip())
zig_res_type = as_zig_arg_type(None, result_type, prefix)
if zig_res_type == "":
zig_res_type = "void"
return zig_res_type
def gen_struct(decl, prefix, callconvc_funcptrs = True, use_raw_name=False, use_extern=True):
struct_name = decl['name']
zig_type = struct_name if use_raw_name else as_zig_struct_type(struct_name, prefix)
l(f"pub const {zig_type} = {'extern ' if use_extern else ''}struct {{")
for field in decl['fields']:
field_name = field['name']
field_type = field['type']
field_type = check_type_override(struct_name, field_name, field_type)
if is_prim_type(field_type):
l(f" {field_name}: {as_zig_prim_type(field_type)} = {type_default_value(field_type)},")
elif is_struct_type(field_type):
l(f" {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{ }},")
elif is_enum_type(field_type):
l(f" {field_name}: {as_zig_enum_type(field_type, prefix)} = .{enum_default_item(field_type)},")
elif is_string_ptr(field_type):
l(f" {field_name}: [*c]const u8 = null,")
elif is_const_void_ptr(field_type):
l(f" {field_name}: ?*const c_void = null,")
elif is_void_ptr(field_type):
l(f" {field_name}: ?*c_void = null,")
elif is_const_prim_ptr(field_type):
l(f" {field_name}: ?[*]const {as_zig_prim_type(extract_ptr_type(field_type))} = null,")
elif is_func_ptr(field_type):
if callconvc_funcptrs:
l(f" {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_res_c(field_type)} = null,")
else:
l(f" {field_name}: ?fn({funcptr_args_c(field_type, prefix)}) {funcptr_res_c(field_type)} = null,")
elif is_1d_array_type(field_type):
array_type = extract_array_type(field_type)
array_nums = extract_array_nums(field_type)
if is_prim_type(array_type) or is_struct_type(array_type):
if is_prim_type(array_type):
zig_type = as_zig_prim_type(array_type)
def_val = type_default_value(array_type)
elif is_struct_type(array_type):
zig_type = as_zig_struct_type(array_type, prefix)
def_val = '.{}'
elif is_enum_type(array_type):
zig_type = as_zig_enum_type(array_type, prefix)
def_val = '.{}'
else:
zig_type = '??? (array type)'
def_val = '???'
t0 = f"[{array_nums[0]}]{zig_type}"
t0_slice = f"[]const {zig_type}"
t1 = f"[_]{zig_type}"
l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_nums[0]},")
elif is_const_void_ptr(array_type):
l(f" {field_name}: [{array_nums[0]}]?*const c_void = [_]?*const c_void {{ null }} ** {array_nums[0]},")
else:
l(f"// FIXME: ??? array {field_name}: {field_type} => {array_type} [{array_nums[0]}]")
elif is_2d_array_type(field_type):
array_type = extract_array_type(field_type)
array_nums = extract_array_nums(field_type)
if is_prim_type(array_type):
zig_type = as_zig_prim_type(array_type)
def_val = type_default_value(array_type)
elif is_struct_type(array_type):
zig_type = as_zig_struct_type(array_type, prefix)
def_val = ".{ }"
else:
zig_type = "???"
def_val = "???"
t0 = f"[{array_nums[0]}][{array_nums[1]}]{zig_type}"
l(f" {field_name}: {t0} = [_][{array_nums[1]}]{zig_type}{{[_]{zig_type}{{ {def_val} }}**{array_nums[1]}}}**{array_nums[0]},")
else:
l(f"// FIXME: {field_name}: {field_type};")
l("};")
def gen_consts(decl, prefix):
for item in decl['items']:
l(f"pub const {as_snake_case(item['name'], prefix)} = {item['value']};")
def gen_enum(decl, prefix):
l(f"pub const {as_zig_enum_type(decl['name'], prefix)} = enum(i32) {{")
for item in decl['items']:
item_name = as_enum_item_name(item['name'])
if item_name != "FORCE_U32":
if 'value' in item:
l(f" {item_name} = {item['value']},")
else:
l(f" {item_name},")
l("};")
def gen_func_c(decl, prefix):
l(f"pub extern fn {decl['name']}({funcdecl_args_c(decl, prefix)}) {funcdecl_result_c(decl, prefix)};")
def gen_func_zig(decl, prefix):
c_func_name = decl['name']
zig_func_name = as_camel_case(check_name_override(decl['name']))
zig_res_type = funcdecl_result_zig(decl, prefix)
l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
if zig_res_type != 'void':
s = f" return {c_func_name}("
else:
s = f" {c_func_name}("
for i, param_decl in enumerate(decl['params']):
if i > 0:
s += ", "
arg_name = param_decl['name']
arg_type = param_decl['type']
if is_const_struct_ptr(arg_type):
s += f"&{arg_name}"
elif is_string_ptr(arg_type):
s += f"@ptrCast([*c]const u8,{arg_name})"
else:
s += arg_name
s += ");"
l(s)
l("}")
def pre_parse(inp):
global struct_types
global enum_types
for decl in inp['decls']:
kind = decl['kind']
if kind == 'struct':
struct_types.append(decl['name'])
elif kind == 'enum':
enum_name = decl['name']
enum_types.append(enum_name)
enum_items[enum_name] = []
for item in decl['items']:
enum_items[enum_name].append(as_enum_item_name(item['name']))
def gen_imports(inp, dep_prefixes):
for dep_prefix in dep_prefixes:
dep_module_name = module_names[dep_prefix]
l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.zig");')
l('')
def gen_helpers(inp):
if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_']:
l('// helper function to convert "anything" to a Range struct')
l('pub fn asRange(val: anytype) Range {')
l(' const type_info = @typeInfo(@TypeOf(val));')
l(' switch (type_info) {')
l(' .Pointer => {')
l(' switch (type_info.Pointer.size) {')
l(' .One => return .{ .ptr = val, .size = @sizeOf(type_info.Pointer.child) },')
l(' .Slice => return .{ .ptr = val.ptr, .size = @sizeOf(type_info.Pointer.child) * val.len },')
l(' else => @compileError("FIXME: Pointer type!"),')
l(' }')
l(' },')
l(' .Struct, .Array => {')
l(' return .{ .ptr = &val, .size = @sizeOf(@TypeOf(val)) };')
l(' },')
l(' else => {')
l(' @compileError("Cannot convert to range!");')
l(' }')
l(' }')
l('}')
l('')
if inp['prefix'] == 'sdtx_':
l('// std.fmt compatible Writer')
l('pub const Writer = struct {')
l(' pub const Error = error { };')
l(' pub fn writeAll(self: Writer, bytes: []const u8) Error!void {')
l(' _ = self;')
l(' for (bytes) |byte| {')
l(' putc(byte);')
l(' }')
l(' }')
l(' pub fn writeByteNTimes(self: Writer, byte: u8, n: u64) Error!void {')
l(' _ = self;')
l(' var i: u64 = 0;')
l(' while (i < n): (i += 1) {')
l(' putc(byte);')
l(' }')
l(' }')
l('};')
l('// std.fmt-style formatted print')
l('pub fn print(comptime fmt: anytype, args: anytype) void {')
l(' var writer: Writer = .{};')
l(' @import("std").fmt.format(writer, fmt, args) catch {};')
l('}')
l('')
def gen_module(inp, dep_prefixes):
l('// machine generated, do not edit')
l('')
gen_imports(inp, dep_prefixes)
gen_helpers(inp)
pre_parse(inp)
prefix = inp['prefix']
for decl in inp['decls']:
if not decl['is_dep']:
kind = decl['kind']
if kind == 'consts':
gen_consts(decl, prefix)
elif not check_name_ignore(decl['name']):
if kind == 'struct':
gen_struct(decl, prefix)
elif kind == 'enum':
gen_enum(decl, prefix)
elif kind == 'func':
gen_func_c(decl, prefix)
gen_func_zig(decl, prefix)
def prepare():
print('Generating zig bindings:')
if not os.path.isdir('sokol-zig/src/sokol'):
os.makedirs('sokol-zig/src/sokol')
if not os.path.isdir('sokol-zig/src/sokol/c'):
os.makedirs('sokol-zig/src/sokol/c')
def gen(c_header_path, c_prefix, dep_c_prefixes):
module_name = module_names[c_prefix]
c_source_path = c_source_paths[c_prefix]
print(f' {c_header_path} => {module_name}')
reset_globals()
shutil.copyfile(c_header_path, f'sokol-zig/src/sokol/c/{os.path.basename(c_header_path)}')
ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
gen_module(ir, dep_c_prefixes)
output_path = f"sokol-zig/src/sokol/{ir['module']}.zig"
with open(output_path, 'w', newline='\n') as f_outp:
f_outp.write(out_lines)
+2
View File
@@ -0,0 +1,2 @@
exports:
header-dirs: [ ".", "util" ]
+11133
View File
File diff suppressed because it is too large Load Diff
+770
View File
@@ -0,0 +1,770 @@
#if defined(SOKOL_IMPL) && !defined(SOKOL_ARGS_IMPL)
#define SOKOL_ARGS_IMPL
#endif
#ifndef SOKOL_ARGS_INCLUDED
/*
sokol_args.h -- cross-platform key/value arg-parsing for web and native
Project URL: https://github.com/floooh/sokol
Do this:
#define SOKOL_IMPL or
#define SOKOL_ARGS_IMPL
before you include this file in *one* C or C++ file to create the
implementation.
Optionally provide the following defines with your own implementations:
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
SOKOL_LOG(msg) - your own logging functions (default: puts(msg))
SOKOL_CALLOC(n,s) - your own calloc() implementation (default: calloc(n,s))
SOKOL_FREE(p) - your own free() implementation (default: free(p))
SOKOL_ARGS_API_DECL - public function declaration prefix (default: extern)
SOKOL_API_DECL - same as SOKOL_ARGS_API_DECL
SOKOL_API_IMPL - public function implementation prefix (default: -)
If sokol_args.h is compiled as a DLL, define the following before
including the declaration or implementation:
SOKOL_DLL
On Windows, SOKOL_DLL will define SOKOL_ARGS_API_DECL as __declspec(dllexport)
or __declspec(dllimport) as needed.
OVERVIEW
========
sokol_args.h provides a simple unified argument parsing API for WebAssembly and
native apps.
When running as WebAssembly app, arguments are taken from the page URL:
https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc
The same arguments provided to a command line app:
kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc
ARGUMENT FORMATTING
===================
On the web platform, arguments must be formatted as a valid URL query string
with 'percent encoding' used for special characters.
Strings are expected to be UTF-8 encoded (although sokol_args.h doesn't
contain any special UTF-8 handling). See below on how to obtain
UTF-8 encoded argc/argv values on Windows when using WinMain() as
entry point.
On native platforms the following rules must be followed:
Arguments have the general form
key=value
Key/value pairs are separated by 'whitespace', valid whitespace
characters are space and tab.
Whitespace characters in front and after the separating '=' character
are ignored:
key = value
...is the same as
key=value
The 'key' string must be a simple string without escape sequences or whitespace.
Currently 'single keys' without values are not allowed, but may be
in the future.
The 'value' string can be quoted, and quoted value strings can contain
whitespace:
key = 'single-quoted value'
key = "double-quoted value"
Single-quoted value strings can contain double quotes, and vice-versa:
key = 'single-quoted value "can contain double-quotes"'
key = "double-quoted value 'can contain single-quotes'"
Note that correct quoting can be tricky on some shells, since command
shells may remove quotes, unless they're escaped.
Value strings can contain a small selection of escape sequences:
\n - newline
\r - carriage return
\t - tab
\\ - escaped backslash
(more escape codes may be added in the future).
CODE EXAMPLE
============
int main(int argc, char* argv[]) {
// initialize sokol_args with default parameters
sargs_setup(&(sargs_desc){
.argc = argc,
.argv = argv
});
// check if a key exists...
if (sargs_exists("bla")) {
...
}
// get value string for key, if not found, return empty string ""
const char* val0 = sargs_value("bla");
// get value string for key, or default string if key not found
const char* val1 = sargs_value_def("bla", "default_value");
// check if a key matches expected value
if (sargs_equals("type", "kc85_4")) {
...
}
// check if a key's value is "true", "yes" or "on"
if (sargs_boolean("joystick_enabled")) {
...
}
// iterate over keys and values
for (int i = 0; i < sargs_num_args(); i++) {
printf("key: %s, value: %s\n", sargs_key_at(i), sargs_value_at(i));
}
// lookup argument index by key string, will return -1 if key
// is not found, sargs_key_at() and sargs_value_at() will return
// an empty string for invalid indices
int index = sargs_find("bla");
printf("key: %s, value: %s\n", sargs_key_at(index), sargs_value_at(index));
// shutdown sokol-args
sargs_shutdown();
}
WINMAIN AND ARGC / ARGV
=======================
On Windows with WinMain() based apps, getting UTF8-encoded command line
arguments is a bit more complicated:
First call GetCommandLineW(), this returns the entire command line
as UTF-16 string. Then call CommandLineToArgvW(), this parses the
command line string into the usual argc/argv format (but in UTF-16).
Finally convert the UTF-16 strings in argv[] into UTF-8 via
WideCharToMultiByte().
See the function _sapp_win32_command_line_to_utf8_argv() in sokol_app.h
for example code how to do this (if you're using sokol_app.h, it will
already convert the command line arguments to UTF-8 for you of course,
so you can plug them directly into sokol_app.h).
API DOCUMENTATION
=================
void sargs_setup(const sargs_desc* desc)
Initialize sokol_args, desc contains the following configuration
parameters:
int argc - the main function's argc parameter
char** argv - the main function's argv parameter
int max_args - max number of key/value pairs, default is 16
int buf_size - size of the internal string buffer, default is 16384
Note that on the web, argc and argv will be ignored and the arguments
will be taken from the page URL instead.
sargs_setup() will allocate 2 memory chunks: one for keeping track
of the key/value args of size 'max_args*8', and a string buffer
of size 'buf_size'.
void sargs_shutdown(void)
Shutdown sokol-args and free any allocated memory.
bool sargs_isvalid(void)
Return true between sargs_setup() and sargs_shutdown()
bool sargs_exists(const char* key)
Test if a key arg exists.
const char* sargs_value(const char* key)
Return value associated with key. Returns an empty
string ("") if the key doesn't exist.
const char* sargs_value_def(const char* key, const char* default)
Return value associated with key, or the provided default
value if the value doesn't exist.
bool sargs_equals(const char* key, const char* val);
Return true if the value associated with key matches
the 'val' argument.
bool sargs_boolean(const char* key)
Return true if the value string of 'key' is one
of 'true', 'yes', 'on'.
int sargs_find(const char* key)
Find argument by key name and return its index, or -1 if not found.
int sargs_num_args(void)
Return number of key/value pairs.
const char* sargs_key_at(int index)
Return the key name of argument at index. Returns empty string if
is index is outside range.
const char* sargs_value_at(int index)
Return the value of argument at index. Returns empty string
if index is outside range.
TODO
====
- parsing errors?
LICENSE
=======
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#define SOKOL_ARGS_INCLUDED (1)
#include <stdint.h>
#include <stdbool.h>
#if defined(SOKOL_API_DECL) && !defined(SOKOL_ARGS_API_DECL)
#define SOKOL_ARGS_API_DECL SOKOL_API_DECL
#endif
#ifndef SOKOL_ARGS_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_ARGS_IMPL)
#define SOKOL_ARGS_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_ARGS_API_DECL __declspec(dllimport)
#else
#define SOKOL_ARGS_API_DECL extern
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sargs_desc {
int argc;
char** argv;
int max_args;
int buf_size;
} sargs_desc;
/* setup sokol-args */
SOKOL_ARGS_API_DECL void sargs_setup(const sargs_desc* desc);
/* shutdown sokol-args */
SOKOL_ARGS_API_DECL void sargs_shutdown(void);
/* true between sargs_setup() and sargs_shutdown() */
SOKOL_ARGS_API_DECL bool sargs_isvalid(void);
/* test if an argument exists by key name */
SOKOL_ARGS_API_DECL bool sargs_exists(const char* key);
/* get value by key name, return empty string if key doesn't exist */
SOKOL_ARGS_API_DECL const char* sargs_value(const char* key);
/* get value by key name, return provided default if key doesn't exist */
SOKOL_ARGS_API_DECL const char* sargs_value_def(const char* key, const char* def);
/* return true if val arg matches the value associated with key */
SOKOL_ARGS_API_DECL bool sargs_equals(const char* key, const char* val);
/* return true if key's value is "true", "yes" or "on" */
SOKOL_ARGS_API_DECL bool sargs_boolean(const char* key);
/* get index of arg by key name, return -1 if not exists */
SOKOL_ARGS_API_DECL int sargs_find(const char* key);
/* get number of parsed arguments */
SOKOL_ARGS_API_DECL int sargs_num_args(void);
/* get key name of argument at index, or empty string */
SOKOL_ARGS_API_DECL const char* sargs_key_at(int index);
/* get value string of argument at index, or empty string */
SOKOL_ARGS_API_DECL const char* sargs_value_at(int index);
#ifdef __cplusplus
} /* extern "C" */
/* reference-based equivalents for c++ */
inline void sargs_setup(const sargs_desc& desc) { return sargs_setup(&desc); }
#endif
#endif // SOKOL_ARGS_INCLUDED
/*--- IMPLEMENTATION ---------------------------------------------------------*/
#ifdef SOKOL_ARGS_IMPL
#define SOKOL_ARGS_IMPL_INCLUDED (1)
#include <string.h> /* memset, strcmp */
#if defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#endif
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#ifndef SOKOL_DEBUG
#ifndef NDEBUG
#define SOKOL_DEBUG (1)
#endif
#endif
#ifndef SOKOL_ASSERT
#include <assert.h>
#define SOKOL_ASSERT(c) assert(c)
#endif
#if !defined(SOKOL_CALLOC) && !defined(SOKOL_FREE)
#include <stdlib.h>
#endif
#if !defined(SOKOL_CALLOC)
#define SOKOL_CALLOC(n,s) calloc(n,s)
#endif
#if !defined(SOKOL_FREE)
#define SOKOL_FREE(p) free(p)
#endif
#ifndef SOKOL_LOG
#ifdef SOKOL_DEBUG
#include <stdio.h>
#define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
#else
#define SOKOL_LOG(s)
#endif
#endif
#ifndef _SOKOL_PRIVATE
#if defined(__GNUC__) || defined(__clang__)
#define _SOKOL_PRIVATE __attribute__((unused)) static
#else
#define _SOKOL_PRIVATE static
#endif
#endif
#define _sargs_def(val, def) (((val) == 0) ? (def) : (val))
#define _SARGS_MAX_ARGS_DEF (16)
#define _SARGS_BUF_SIZE_DEF (16*1024)
/* parser state */
#define _SARGS_EXPECT_KEY (1<<0)
#define _SARGS_EXPECT_SEP (1<<1)
#define _SARGS_EXPECT_VAL (1<<2)
#define _SARGS_PARSING_KEY (1<<3)
#define _SARGS_PARSING_VAL (1<<4)
#define _SARGS_ERROR (1<<5)
/* a key/value pair struct */
typedef struct {
int key; /* index to start of key string in buf */
int val; /* index to start of value string in buf */
} _sargs_kvp_t;
/* sokol-args state */
typedef struct {
int max_args; /* number of key/value pairs in args array */
int num_args; /* number of valid items in args array */
_sargs_kvp_t* args; /* key/value pair array */
int buf_size; /* size of buffer in bytes */
int buf_pos; /* current buffer position */
char* buf; /* character buffer, first char is reserved and zero for 'empty string' */
bool valid;
uint32_t parse_state;
char quote; /* current quote char, 0 if not in a quote */
bool in_escape; /* currently in an escape sequence */
} _sargs_state_t;
static _sargs_state_t _sargs;
/*== PRIVATE IMPLEMENTATION FUNCTIONS ========================================*/
_SOKOL_PRIVATE void _sargs_putc(char c) {
if ((_sargs.buf_pos+2) < _sargs.buf_size) {
_sargs.buf[_sargs.buf_pos++] = c;
}
}
_SOKOL_PRIVATE const char* _sargs_str(int index) {
SOKOL_ASSERT((index >= 0) && (index < _sargs.buf_size));
return &_sargs.buf[index];
}
/*-- argument parser functions ------------------*/
_SOKOL_PRIVATE void _sargs_expect_key(void) {
_sargs.parse_state = _SARGS_EXPECT_KEY;
}
_SOKOL_PRIVATE bool _sargs_key_expected(void) {
return 0 != (_sargs.parse_state & _SARGS_EXPECT_KEY);
}
_SOKOL_PRIVATE void _sargs_expect_val(void) {
_sargs.parse_state = _SARGS_EXPECT_VAL;
}
_SOKOL_PRIVATE bool _sargs_val_expected(void) {
return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL);
}
_SOKOL_PRIVATE void _sargs_expect_sep(void) {
_sargs.parse_state = _SARGS_EXPECT_SEP;
}
_SOKOL_PRIVATE bool _sargs_any_expected(void) {
return 0 != (_sargs.parse_state & (_SARGS_EXPECT_KEY | _SARGS_EXPECT_VAL | _SARGS_EXPECT_SEP));
}
_SOKOL_PRIVATE bool _sargs_is_separator(char c) {
return c == '=';
}
_SOKOL_PRIVATE bool _sargs_is_quote(char c) {
if (0 == _sargs.quote) {
return (c == '\'') || (c == '"');
}
else {
return c == _sargs.quote;
}
}
_SOKOL_PRIVATE void _sargs_begin_quote(char c) {
_sargs.quote = c;
}
_SOKOL_PRIVATE void _sargs_end_quote(void) {
_sargs.quote = 0;
}
_SOKOL_PRIVATE bool _sargs_in_quotes(void) {
return 0 != _sargs.quote;
}
_SOKOL_PRIVATE bool _sargs_is_whitespace(char c) {
return !_sargs_in_quotes() && ((c == ' ') || (c == '\t'));
}
_SOKOL_PRIVATE void _sargs_start_key(void) {
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
_sargs.parse_state = _SARGS_PARSING_KEY;
_sargs.args[_sargs.num_args].key = _sargs.buf_pos;
}
_SOKOL_PRIVATE void _sargs_end_key(void) {
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
_sargs_putc(0);
_sargs.parse_state = 0;
}
_SOKOL_PRIVATE bool _sargs_parsing_key(void) {
return 0 != (_sargs.parse_state & _SARGS_PARSING_KEY);
}
_SOKOL_PRIVATE void _sargs_start_val(void) {
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
_sargs.parse_state = _SARGS_PARSING_VAL;
_sargs.args[_sargs.num_args].val = _sargs.buf_pos;
}
_SOKOL_PRIVATE void _sargs_end_val(void) {
SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
_sargs_putc(0);
_sargs.num_args++;
_sargs.parse_state = 0;
}
_SOKOL_PRIVATE bool _sargs_is_escape(char c) {
return '\\' == c;
}
_SOKOL_PRIVATE void _sargs_start_escape(void) {
_sargs.in_escape = true;
}
_SOKOL_PRIVATE bool _sargs_in_escape(void) {
return _sargs.in_escape;
}
_SOKOL_PRIVATE char _sargs_escape(char c) {
switch (c) {
case 'n': return '\n';
case 't': return '\t';
case 'r': return '\r';
case '\\': return '\\';
default: return c;
}
}
_SOKOL_PRIVATE void _sargs_end_escape(void) {
_sargs.in_escape = false;
}
_SOKOL_PRIVATE bool _sargs_parsing_val(void) {
return 0 != (_sargs.parse_state & _SARGS_PARSING_VAL);
}
_SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
char c;
while (0 != (c = *src++)) {
if (_sargs_in_escape()) {
c = _sargs_escape(c);
_sargs_end_escape();
}
else if (_sargs_is_escape(c)) {
_sargs_start_escape();
continue;
}
if (_sargs_any_expected()) {
if (!_sargs_is_whitespace(c)) {
/* start of key, value or separator */
if (_sargs_key_expected()) {
/* start of new key */
_sargs_start_key();
}
else if (_sargs_val_expected()) {
/* start of value */
if (_sargs_is_quote(c)) {
_sargs_begin_quote(c);
continue;
}
_sargs_start_val();
}
else {
/* separator */
if (_sargs_is_separator(c)) {
_sargs_expect_val();
continue;
}
}
}
else {
/* skip white space */
continue;
}
}
else if (_sargs_parsing_key()) {
if (_sargs_is_whitespace(c) || _sargs_is_separator(c)) {
/* end of key string */
_sargs_end_key();
if (_sargs_is_separator(c)) {
_sargs_expect_val();
}
else {
_sargs_expect_sep();
}
continue;
}
}
else if (_sargs_parsing_val()) {
if (_sargs_in_quotes()) {
/* when in quotes, whitespace is a normal character
and a matching quote ends the value string
*/
if (_sargs_is_quote(c)) {
_sargs_end_quote();
_sargs_end_val();
_sargs_expect_key();
continue;
}
}
else if (_sargs_is_whitespace(c)) {
/* end of value string (no quotes) */
_sargs_end_val();
_sargs_expect_key();
continue;
}
}
_sargs_putc(c);
}
if (_sargs_parsing_key()) {
_sargs_end_key();
_sargs_expect_sep();
}
else if (_sargs_parsing_val() && !_sargs_in_quotes()) {
_sargs_end_val();
_sargs_expect_key();
}
return true;
}
_SOKOL_PRIVATE bool _sargs_parse_cargs(int argc, const char** argv) {
_sargs_expect_key();
bool retval = true;
for (int i = 1; i < argc; i++) {
retval &= _sargs_parse_carg(argv[i]);
}
_sargs.parse_state = 0;
return retval;
}
/*-- EMSCRIPTEN IMPLEMENTATION -----------------------------------------------*/
#if defined(__EMSCRIPTEN__)
#ifdef __cplusplus
extern "C" {
#endif
EMSCRIPTEN_KEEPALIVE void _sargs_add_kvp(const char* key, const char* val) {
SOKOL_ASSERT(_sargs.valid && key && val);
if (_sargs.num_args >= _sargs.max_args) {
return;
}
/* copy key string */
char c;
_sargs.args[_sargs.num_args].key = _sargs.buf_pos;
const char* ptr = key;
while (0 != (c = *ptr++)) {
_sargs_putc(c);
}
_sargs_putc(0);
/* copy value string */
_sargs.args[_sargs.num_args].val = _sargs.buf_pos;
ptr = val;
while (0 != (c = *ptr++)) {
_sargs_putc(c);
}
_sargs_putc(0);
_sargs.num_args++;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
/* JS function to extract arguments from the page URL */
EM_JS(void, sargs_js_parse_url, (void), {
var params = new URLSearchParams(window.location.search).entries();
for (var p = params.next(); !p.done; p = params.next()) {
var key = p.value[0];
var val = p.value[1];
var res = ccall('_sargs_add_kvp', 'void', ['string','string'], [key,val]);
}
});
#endif /* EMSCRIPTEN */
/*== PUBLIC IMPLEMENTATION FUNCTIONS =========================================*/
SOKOL_API_IMPL void sargs_setup(const sargs_desc* desc) {
SOKOL_ASSERT(desc);
memset(&_sargs, 0, sizeof(_sargs));
_sargs.max_args = _sargs_def(desc->max_args, _SARGS_MAX_ARGS_DEF);
_sargs.buf_size = _sargs_def(desc->buf_size, _SARGS_BUF_SIZE_DEF);
SOKOL_ASSERT(_sargs.buf_size > 8);
_sargs.args = (_sargs_kvp_t*) SOKOL_CALLOC((size_t)_sargs.max_args, sizeof(_sargs_kvp_t));
_sargs.buf = (char*) SOKOL_CALLOC((size_t)_sargs.buf_size, sizeof(char));
/* the first character in buf is reserved and always zero, this is the 'empty string' */
_sargs.buf_pos = 1;
_sargs.valid = true;
/* parse argc/argv */
_sargs_parse_cargs(desc->argc, (const char**) desc->argv);
#if defined(__EMSCRIPTEN__)
/* on emscripten, also parse the page URL*/
sargs_js_parse_url();
#endif
}
SOKOL_API_IMPL void sargs_shutdown(void) {
SOKOL_ASSERT(_sargs.valid);
if (_sargs.args) {
SOKOL_FREE(_sargs.args);
_sargs.args = 0;
}
if (_sargs.buf) {
SOKOL_FREE(_sargs.buf);
_sargs.buf = 0;
}
_sargs.valid = false;
}
SOKOL_API_IMPL bool sargs_isvalid(void) {
return _sargs.valid;
}
SOKOL_API_IMPL int sargs_find(const char* key) {
SOKOL_ASSERT(_sargs.valid && key);
for (int i = 0; i < _sargs.num_args; i++) {
if (0 == strcmp(_sargs_str(_sargs.args[i].key), key)) {
return i;
}
}
return -1;
}
SOKOL_API_IMPL int sargs_num_args(void) {
SOKOL_ASSERT(_sargs.valid);
return _sargs.num_args;
}
SOKOL_API_IMPL const char* sargs_key_at(int index) {
SOKOL_ASSERT(_sargs.valid);
if ((index >= 0) && (index < _sargs.num_args)) {
return _sargs_str(_sargs.args[index].key);
}
else {
/* index 0 is always the empty string */
return _sargs_str(0);
}
}
SOKOL_API_IMPL const char* sargs_value_at(int index) {
SOKOL_ASSERT(_sargs.valid);
if ((index >= 0) && (index < _sargs.num_args)) {
return _sargs_str(_sargs.args[index].val);
}
else {
/* index 0 is always the empty string */
return _sargs_str(0);
}
}
SOKOL_API_IMPL bool sargs_exists(const char* key) {
SOKOL_ASSERT(_sargs.valid && key);
return -1 != sargs_find(key);
}
SOKOL_API_IMPL const char* sargs_value(const char* key) {
SOKOL_ASSERT(_sargs.valid && key);
return sargs_value_at(sargs_find(key));
}
SOKOL_API_IMPL const char* sargs_value_def(const char* key, const char* def) {
SOKOL_ASSERT(_sargs.valid && key && def);
int arg_index = sargs_find(key);
if (-1 != arg_index) {
return sargs_value_at(arg_index);
}
else {
return def;
}
}
SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) {
SOKOL_ASSERT(_sargs.valid && key && val);
return 0 == strcmp(sargs_value(key), val);
}
SOKOL_API_IMPL bool sargs_boolean(const char* key) {
const char* val = sargs_value(key);
return (0 == strcmp("true", val)) ||
(0 == strcmp("yes", val)) ||
(0 == strcmp("on", val));
}
#endif /* SOKOL_ARGS_IMPL */
+2147
View File
File diff suppressed because it is too large Load Diff
+2523
View File
File diff suppressed because it is too large Load Diff
+15732
View File
File diff suppressed because it is too large Load Diff
+137
View File
@@ -0,0 +1,137 @@
#if defined(SOKOL_IMPL) && !defined(SOKOL_GLUE_IMPL)
#define SOKOL_GLUE_IMPL
#endif
#ifndef SOKOL_GLUE_INCLUDED
/*
sokol_glue.h -- glue helper functions for sokol headers
Project URL: https://github.com/floooh/sokol
Do this:
#define SOKOL_IMPL or
#define SOKOL_GLUE_IMPL
before you include this file in *one* C or C++ file to create the
implementation.
...optionally provide the following macros to override defaults:
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
SOKOL_GLUE_API_DECL - public function declaration prefix (default: extern)
SOKOL_API_DECL - same as SOKOL_GLUE_API_DECL
SOKOL_API_IMPL - public function implementation prefix (default: -)
If sokol_glue.h is compiled as a DLL, define the following before
including the declaration or implementation:
SOKOL_DLL
On Windows, SOKOL_DLL will define SOKOL_GLUE_API_DECL as __declspec(dllexport)
or __declspec(dllimport) as needed.
OVERVIEW
========
The sokol core headers should not depend on each other, but sometimes
it's useful to have a set of helper functions as "glue" between
two or more sokol headers.
This is what sokol_glue.h is for. Simply include the header after other
sokol headers (both for the implementation and declaration), and
depending on what headers have been included before, sokol_glue.h
will make available "glue functions".
PROVIDED FUNCTIONS
==================
- if sokol_app.h and sokol_gfx.h is included:
sg_context_desc sapp_sgcontext(void):
Returns an initialized sg_context_desc function initialized
by calling sokol_app.h functions.
LICENSE
=======
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#define SOKOL_GLUE_INCLUDED
#if defined(SOKOL_API_DECL) && !defined(SOKOL_GLUE_API_DECL)
#define SOKOL_GLUE_API_DECL SOKOL_API_DECL
#endif
#ifndef SOKOL_GLUE_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GLUE_IMPL)
#define SOKOL_GLUE_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_GLUE_API_DECL __declspec(dllimport)
#else
#define SOKOL_GLUE_API_DECL extern
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(SOKOL_GFX_INCLUDED) && defined(SOKOL_APP_INCLUDED)
SOKOL_GLUE_API_DECL sg_context_desc sapp_sgcontext(void);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SOKOL_GLUE_INCLUDED */
/*-- IMPLEMENTATION ----------------------------------------------------------*/
#ifdef SOKOL_GLUE_IMPL
#define SOKOL_GLUE_IMPL_INCLUDED (1)
#include <string.h> /* memset */
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#if defined(SOKOL_GFX_INCLUDED) && defined(SOKOL_APP_INCLUDED)
SOKOL_API_IMPL sg_context_desc sapp_sgcontext(void) {
sg_context_desc desc;
memset(&desc, 0, sizeof(desc));
desc.color_format = (sg_pixel_format) sapp_color_format();
desc.depth_format = (sg_pixel_format) sapp_depth_format();
desc.sample_count = sapp_sample_count();
desc.gl.force_gles2 = sapp_gles2();
desc.metal.device = sapp_metal_get_device();
desc.metal.renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor;
desc.metal.drawable_cb = sapp_metal_get_drawable;
desc.d3d11.device = sapp_d3d11_get_device();
desc.d3d11.device_context = sapp_d3d11_get_device_context();
desc.d3d11.render_target_view_cb = sapp_d3d11_get_render_target_view;
desc.d3d11.depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view;
desc.wgpu.device = sapp_wgpu_get_device();
desc.wgpu.render_view_cb = sapp_wgpu_get_render_view;
desc.wgpu.resolve_view_cb = sapp_wgpu_get_resolve_view;
desc.wgpu.depth_stencil_view_cb = sapp_wgpu_get_depth_stencil_view;
return desc;
}
#endif
#endif /* SOKOL_GLUE_IMPL */
+324
View File
@@ -0,0 +1,324 @@
#if defined(SOKOL_IMPL) && !defined(SOKOL_TIME_IMPL)
#define SOKOL_TIME_IMPL
#endif
#ifndef SOKOL_TIME_INCLUDED
/*
sokol_time.h -- simple cross-platform time measurement
Project URL: https://github.com/floooh/sokol
Do this:
#define SOKOL_IMPL or
#define SOKOL_TIME_IMPL
before you include this file in *one* C or C++ file to create the
implementation.
Optionally provide the following defines with your own implementations:
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
SOKOL_TIME_API_DECL - public function declaration prefix (default: extern)
SOKOL_API_DECL - same as SOKOL_TIME_API_DECL
SOKOL_API_IMPL - public function implementation prefix (default: -)
If sokol_time.h is compiled as a DLL, define the following before
including the declaration or implementation:
SOKOL_DLL
On Windows, SOKOL_DLL will define SOKOL_TIME_API_DECL as __declspec(dllexport)
or __declspec(dllimport) as needed.
void stm_setup();
Call once before any other functions to initialize sokol_time
(this calls for instance QueryPerformanceFrequency on Windows)
uint64_t stm_now();
Get current point in time in unspecified 'ticks'. The value that
is returned has no relation to the 'wall-clock' time and is
not in a specific time unit, it is only useful to compute
time differences.
uint64_t stm_diff(uint64_t new, uint64_t old);
Computes the time difference between new and old. This will always
return a positive, non-zero value.
uint64_t stm_since(uint64_t start);
Takes the current time, and returns the elapsed time since start
(this is a shortcut for "stm_diff(stm_now(), start)")
uint64_t stm_laptime(uint64_t* last_time);
This is useful for measuring frame time and other recurring
events. It takes the current time, returns the time difference
to the value in last_time, and stores the current time in
last_time for the next call. If the value in last_time is 0,
the return value will be zero (this usually happens on the
very first call).
uint64_t stm_round_to_common_refresh_rate(uint64_t duration)
This oddly named function takes a measured frame time and
returns the closest "nearby" common display refresh rate frame duration
in ticks. If the input duration isn't close to any common display
refresh rate, the input duration will be returned unchanged as a fallback.
The main purpose of this function is to remove jitter/inaccuracies from
measured frame times, and instead use the display refresh rate as
frame duration.
Use the following functions to convert a duration in ticks into
useful time units:
double stm_sec(uint64_t ticks);
double stm_ms(uint64_t ticks);
double stm_us(uint64_t ticks);
double stm_ns(uint64_t ticks);
Converts a tick value into seconds, milliseconds, microseconds
or nanoseconds. Note that not all platforms will have nanosecond
or even microsecond precision.
Uses the following time measurement functions under the hood:
Windows: QueryPerformanceFrequency() / QueryPerformanceCounter()
MacOS/iOS: mach_absolute_time()
emscripten: performance.now()
Linux+others: clock_gettime(CLOCK_MONOTONIC)
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#define SOKOL_TIME_INCLUDED (1)
#include <stdint.h>
#if defined(SOKOL_API_DECL) && !defined(SOKOL_TIME_API_DECL)
#define SOKOL_TIME_API_DECL SOKOL_API_DECL
#endif
#ifndef SOKOL_TIME_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_TIME_IMPL)
#define SOKOL_TIME_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_TIME_API_DECL __declspec(dllimport)
#else
#define SOKOL_TIME_API_DECL extern
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
SOKOL_TIME_API_DECL void stm_setup(void);
SOKOL_TIME_API_DECL uint64_t stm_now(void);
SOKOL_TIME_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks);
SOKOL_TIME_API_DECL uint64_t stm_since(uint64_t start_ticks);
SOKOL_TIME_API_DECL uint64_t stm_laptime(uint64_t* last_time);
SOKOL_TIME_API_DECL uint64_t stm_round_to_common_refresh_rate(uint64_t frame_ticks);
SOKOL_TIME_API_DECL double stm_sec(uint64_t ticks);
SOKOL_TIME_API_DECL double stm_ms(uint64_t ticks);
SOKOL_TIME_API_DECL double stm_us(uint64_t ticks);
SOKOL_TIME_API_DECL double stm_ns(uint64_t ticks);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // SOKOL_TIME_INCLUDED
/*-- IMPLEMENTATION ----------------------------------------------------------*/
#ifdef SOKOL_TIME_IMPL
#define SOKOL_TIME_IMPL_INCLUDED (1)
#include <string.h> /* memset */
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#ifndef SOKOL_ASSERT
#include <assert.h>
#define SOKOL_ASSERT(c) assert(c)
#endif
#ifndef _SOKOL_PRIVATE
#if defined(__GNUC__) || defined(__clang__)
#define _SOKOL_PRIVATE __attribute__((unused)) static
#else
#define _SOKOL_PRIVATE static
#endif
#endif
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
typedef struct {
uint32_t initialized;
LARGE_INTEGER freq;
LARGE_INTEGER start;
} _stm_state_t;
#elif defined(__APPLE__) && defined(__MACH__)
#include <mach/mach_time.h>
typedef struct {
uint32_t initialized;
mach_timebase_info_data_t timebase;
uint64_t start;
} _stm_state_t;
#elif defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
typedef struct {
uint32_t initialized;
double start;
} _stm_state_t;
#else /* anything else, this will need more care for non-Linux platforms */
#ifdef ESP8266
// On the ESP8266, clock_gettime ignores the first argument and CLOCK_MONOTONIC isn't defined
#define CLOCK_MONOTONIC 0
#endif
#include <time.h>
typedef struct {
uint32_t initialized;
uint64_t start;
} _stm_state_t;
#endif
static _stm_state_t _stm;
/* prevent 64-bit overflow when computing relative timestamp
see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3
*/
#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
_SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom) {
int64_t q = value / denom;
int64_t r = value % denom;
return q * numer + r * numer / denom;
}
#endif
#if defined(__EMSCRIPTEN__)
EM_JS(double, stm_js_perfnow, (void), {
return performance.now();
});
#endif
SOKOL_API_IMPL void stm_setup(void) {
memset(&_stm, 0, sizeof(_stm));
_stm.initialized = 0xABCDABCD;
#if defined(_WIN32)
QueryPerformanceFrequency(&_stm.freq);
QueryPerformanceCounter(&_stm.start);
#elif defined(__APPLE__) && defined(__MACH__)
mach_timebase_info(&_stm.timebase);
_stm.start = mach_absolute_time();
#elif defined(__EMSCRIPTEN__)
_stm.start = stm_js_perfnow();
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
_stm.start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec;
#endif
}
SOKOL_API_IMPL uint64_t stm_now(void) {
SOKOL_ASSERT(_stm.initialized == 0xABCDABCD);
uint64_t now;
#if defined(_WIN32)
LARGE_INTEGER qpc_t;
QueryPerformanceCounter(&qpc_t);
now = (uint64_t) int64_muldiv(qpc_t.QuadPart - _stm.start.QuadPart, 1000000000, _stm.freq.QuadPart);
#elif defined(__APPLE__) && defined(__MACH__)
const uint64_t mach_now = mach_absolute_time() - _stm.start;
now = (uint64_t) int64_muldiv((int64_t)mach_now, (int64_t)_stm.timebase.numer, (int64_t)_stm.timebase.denom);
#elif defined(__EMSCRIPTEN__)
double js_now = stm_js_perfnow() - _stm.start;
SOKOL_ASSERT(js_now >= 0.0);
now = (uint64_t) (js_now * 1000000.0);
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm.start;
#endif
return now;
}
SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) {
if (new_ticks > old_ticks) {
return new_ticks - old_ticks;
}
else {
return 1;
}
}
SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) {
return stm_diff(stm_now(), start_ticks);
}
SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) {
SOKOL_ASSERT(last_time);
uint64_t dt = 0;
uint64_t now = stm_now();
if (0 != *last_time) {
dt = stm_diff(now, *last_time);
}
*last_time = now;
return dt;
}
// first number is frame duration in ns, second number is tolerance in ns,
// the resulting min/max values must not overlap!
static const uint64_t _stm_refresh_rates[][2] = {
{ 16666667, 1000000 }, // 60 Hz: 16.6667 +- 1ms
{ 13888889, 250000 }, // 72 Hz: 13.8889 +- 0.25ms
{ 13333333, 250000 }, // 75 Hz: 13.3333 +- 0.25ms
{ 11764706, 250000 }, // 85 Hz: 11.7647 +- 0.25
{ 11111111, 250000 }, // 90 Hz: 11.1111 +- 0.25ms
{ 10000000, 500000 }, // 100 Hz: 10.0000 +- 0.5ms
{ 8333333, 500000 }, // 120 Hz: 8.3333 +- 0.5ms
{ 6944445, 500000 }, // 144 Hz: 6.9445 +- 0.5ms
{ 4166667, 1000000 }, // 240 Hz: 4.1666 +- 1ms
{ 0, 0 }, // keep the last element always at zero
};
SOKOL_API_IMPL uint64_t stm_round_to_common_refresh_rate(uint64_t ticks) {
uint64_t ns;
int i = 0;
while (0 != (ns = _stm_refresh_rates[i][0])) {
uint64_t tol = _stm_refresh_rates[i][1];
if ((ticks > (ns - tol)) && (ticks < (ns + tol))) {
return ns;
}
i++;
}
// fallthough: didn't fit into any buckets
return ticks;
}
SOKOL_API_IMPL double stm_sec(uint64_t ticks) {
return (double)ticks / 1000000000.0;
}
SOKOL_API_IMPL double stm_ms(uint64_t ticks) {
return (double)ticks / 1000000.0;
}
SOKOL_API_IMPL double stm_us(uint64_t ticks) {
return (double)ticks / 1000.0;
}
SOKOL_API_IMPL double stm_ns(uint64_t ticks) {
return (double)ticks;
}
#endif /* SOKOL_TIME_IMPL */
+500
View File
@@ -0,0 +1,500 @@
#-------------------------------------------------------------------------------
# Generate the sokol_color.h header from a predefined palette
#-------------------------------------------------------------------------------
# LICENSE
# =======
#
# zlib/libpng license
#
# Copyright (c) 2020 Stuart Adams
#
# This software is provided 'as-is', without any express or implied warranty.
# In no event will the authors be held liable for any damages arising from the
# use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software in a
# product, an acknowledgment in the product documentation would be
# appreciated but is not required.
#
# 2. Altered source versions must be plainly marked as such, and must not
# be misrepresented as being the original software.
#
# 3. This notice may not be removed or altered from any source
# distribution.
colors = [
("Alice Blue", 0xF0F8FFFF),
("Antique White", 0xFAEBD7FF),
("Aqua", 0x00FFFFFF),
("Aquamarine", 0x7FFFD4FF),
("Azure", 0xF0FFFFFF),
("Beige", 0xF5F5DCFF),
("Bisque", 0xFFE4C4FF),
("Black", 0x000000FF),
("Blanched Almond", 0xFFEBCDFF),
("Blue", 0x0000FFFF),
("Blue Violet", 0x8A2BE2FF),
("Brown", 0xA52A2AFF),
("Burlywood", 0xDEB887FF),
("Cadet Blue", 0x5F9EA0FF),
("Chartreuse", 0x7FFF00FF),
("Chocolate", 0xD2691EFF),
("Coral", 0xFF7F50FF),
("Cornflower Blue", 0x6495EDFF),
("Cornsilk", 0xFFF8DCFF),
("Crimson", 0xDC143CFF),
("Cyan", 0x00FFFFFF),
("Dark Blue", 0x00008BFF),
("Dark Cyan", 0x008B8BFF),
("Dark Goldenrod", 0xB8860BFF),
("Dark Gray", 0xA9A9A9FF),
("Dark Green", 0x006400FF),
("Dark Khaki", 0xBDB76BFF),
("Dark Magenta", 0x8B008BFF),
("Dark Olive Green", 0x556B2FFF),
("Dark Orange", 0xFF8C00FF),
("Dark Orchid", 0x9932CCFF),
("Dark Red", 0x8B0000FF),
("Dark Salmon", 0xE9967AFF),
("Dark Sea Green", 0x8FBC8FFF),
("Dark Slate Blue", 0x483D8BFF),
("Dark Slate Gray", 0x2F4F4FFF),
("Dark Turquoise", 0x00CED1FF),
("Dark Violet", 0x9400D3FF),
("Deep Pink", 0xFF1493FF),
("Deep Sky Blue", 0x00BFFFFF),
("Dim Gray", 0x696969FF),
("Dodger Blue", 0x1E90FFFF),
("Firebrick", 0xB22222FF),
("Floral White", 0xFFFAF0FF),
("Forest Green", 0x228B22FF),
("Fuchsia", 0xFF00FFFF),
("Gainsboro", 0xDCDCDCFF),
("Ghost White", 0xF8F8FFFF),
("Gold", 0xFFD700FF),
("Goldenrod", 0xDAA520FF),
("Gray", 0xBEBEBEFF),
("Web Gray", 0x808080FF),
("Green", 0x00FF00FF),
("Web Green", 0x008000FF),
("Green Yellow", 0xADFF2FFF),
("Honeydew", 0xF0FFF0FF),
("Hot Pink", 0xFF69B4FF),
("Indian Red", 0xCD5C5CFF),
("Indigo", 0x4B0082FF),
("Ivory", 0xFFFFF0FF),
("Khaki", 0xF0E68CFF),
("Lavender", 0xE6E6FAFF),
("Lavender Blush", 0xFFF0F5FF),
("Lawn Green", 0x7CFC00FF),
("Lemon Chiffon", 0xFFFACDFF),
("Light Blue", 0xADD8E6FF),
("Light Coral", 0xF08080FF),
("Light Cyan", 0xE0FFFFFF),
("Light Goldenrod", 0xFAFAD2FF),
("Light Gray", 0xD3D3D3FF),
("Light Green", 0x90EE90FF),
("Light Pink", 0xFFB6C1FF),
("Light Salmon", 0xFFA07AFF),
("Light Sea Green", 0x20B2AAFF),
("Light Sky Blue", 0x87CEFAFF),
("Light Slate Gray", 0x778899FF),
("Light Steel Blue", 0xB0C4DEFF),
("Light Yellow", 0xFFFFE0FF),
("Lime", 0x00FF00FF),
("Lime Green", 0x32CD32FF),
("Linen", 0xFAF0E6FF),
("Magenta", 0xFF00FFFF),
("Maroon", 0xB03060FF),
("Web Maroon", 0x800000FF),
("Medium Aquamarine", 0x66CDAAFF),
("Medium Blue", 0x0000CDFF),
("Medium Orchid", 0xBA55D3FF),
("Medium Purple", 0x9370DBFF),
("Medium Sea Green", 0x3CB371FF),
("Medium Slate Blue", 0x7B68EEFF),
("Medium Spring Green", 0x00FA9AFF),
("Medium Turquoise", 0x48D1CCFF),
("Medium Violet Red", 0xC71585FF),
("Midnight Blue", 0x191970FF),
("Mint Cream", 0xF5FFFAFF),
("Misty Rose", 0xFFE4E1FF),
("Moccasin", 0xFFE4B5FF),
("Navajo White", 0xFFDEADFF),
("Navy Blue", 0x000080FF),
("Old Lace", 0xFDF5E6FF),
("Olive", 0x808000FF),
("Olive Drab", 0x6B8E23FF),
("Orange", 0xFFA500FF),
("Orange Red", 0xFF4500FF),
("Orchid", 0xDA70D6FF),
("Pale Goldenrod", 0xEEE8AAFF),
("Pale Green", 0x98FB98FF),
("Pale Turquoise", 0xAFEEEEFF),
("Pale Violet Red", 0xDB7093FF),
("Papaya Whip", 0xFFEFD5FF),
("Peach Puff", 0xFFDAB9FF),
("Peru", 0xCD853FFF),
("Pink", 0xFFC0CBFF),
("Plum", 0xDDA0DDFF),
("Powder Blue", 0xB0E0E6FF),
("Purple", 0xA020F0FF),
("Web Purple", 0x800080FF),
("Rebecca Purple", 0x663399FF),
("Red", 0xFF0000FF),
("Rosy Brown", 0xBC8F8FFF),
("Royal Blue", 0x4169E1FF),
("Saddle Brown", 0x8B4513FF),
("Salmon", 0xFA8072FF),
("Sandy Brown", 0xF4A460FF),
("Sea Green", 0x2E8B57FF),
("Seashell", 0xFFF5EEFF),
("Sienna", 0xA0522DFF),
("Silver", 0xC0C0C0FF),
("Sky Blue", 0x87CEEBFF),
("Slate Blue", 0x6A5ACDFF),
("Slate Gray", 0x708090FF),
("Snow", 0xFFFAFAFF),
("Spring Green", 0x00FF7FFF),
("Steel Blue", 0x4682B4FF),
("Tan", 0xD2B48CFF),
("Teal", 0x008080FF),
("Thistle", 0xD8BFD8FF),
("Tomato", 0xFF6347FF),
("Transparent", 0x00000000),
("Turquoise", 0x40E0D0FF),
("Violet", 0xEE82EEFF),
("Wheat", 0xF5DEB3FF),
("White", 0xFFFFFFFF),
("White Smoke", 0xF5F5F5FF),
("Yellow", 0xFFFF00FF),
("Yellow Green", 0x9ACD32FF)
]
header = open("sokol_color.h", "w")
header.write("""#if defined(SOKOL_IMPL) && !defined(SOKOL_COLOR_IMPL)
#define SOKOL_COLOR_IMPL
#endif
#ifndef SOKOL_COLOR_INCLUDED
/*
sokol_color.h -- sg_color utilities
This header was generated by gen_sokol_color.py. Do not modify it.
Project URL: https://github.com/floooh/sokol
Include the following headers before including sokol_color.h:
sokol_gfx.h
FEATURE OVERVIEW
================
sokol_color.h defines preset colors based on the X11 color names,
alongside utility functions to create and modify sg_color objects.
The predefined colors are based on the X11 color names:
https://en.wikipedia.org/wiki/X11_color_names
This palette is useful for prototyping - lots of programmers are familiar with
these colours due to their use in X11, web development and XNA / MonoGame. They
are also handy when you want to reference a familiar color, but don't want to
write it out by hand.
COLORS
======
The palette is defined using static const (or constexpr if you are using a
C++ compiler) objects. These objects use lowercase names:
static SOKOL_COLOR_CONSTEXPR sg_color sg_red = SG_RED;
static SOKOL_COLOR_CONSTEXPR sg_color sg_green = SG_GREEN;
static SOKOL_COLOR_CONSTEXPR sg_color sg_blue = SG_BLUE;
An sg_color preset object like sg_red can be used to initialize
an sg_pass_action:
sg_pass_action pass_action = {
.colors[0] = { .action=SG_ACTION_CLEAR, .value = sg_red }
};
Initializing an object with static storage duration is more complicated
because of C language rules. Technically, a static const is not a
compile-time constant in C. To work around this, the palette is also
defined as a series of brace-enclosed list macro definitions. These
definitions use uppercase names:
#define SG_RED { 1.0f, 0.0f, 0.0f, 1.0f }
#define SG_GREEN { 0.0f, 1.0f, 0.0f, 1.0f }
#define SG_BLUE { 0.0f, 0.0f, 1.0f, 1.0f }
A preset macro like SG_RED can be used to initialize objects with static
storage duration:
static struct {
sg_pass_action pass_action;
} state = {
.pass_action = {
.colors[0] = { .action = SG_ACTION_CLEAR, .value = SG_RED }
}
};
A second set of macro definitions exists for colors packed as 32 bit integer
values. These definitions are also uppercase, but use the _RGBA32 suffix:
#define SG_RED_RGBA32 0xFF0000FF
#define SG_GREEN_RGBA32 0x00FF00FF
#define SG_BLUE_RGBA32 0x0000FFFF
This is useful if your code makes use of packed colors, as sokol_gl.h does for its
internal vertex format:
sgl_begin_triangles();
sgl_v2f_c1i( 0.0f, 0.5f, SG_RED_RGBA32);
sgl_v2f_c1i( 0.5f, -0.5f, SG_GREEN_RGBA32);
sgl_v2f_c1i(-0.5f, -0.5f, SG_BLUE_RGBA32);
sgl_end();
UTILITY FUNCTIONS
=================
Utility functions for creating colours are provided:
- sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Create a sg_color object from separate R, G, B, A bytes.
- sg_make_color_1i(uint32_t rgba)
Create a sg_color object from RGBA bytes packed into a 32-bit unsigned integer.
- sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount)
Linearly interpolate a color.
- sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount)
Linearly interpolate a color. Less efficient but more precise than sg_color_lerp.
- sg_color_multiply(const sg_color* color, float scale)
Multiply each color component by the scale factor.
LICENSE
=======
zlib/libpng license
Copyright (c) 2020 Stuart Adams
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#define SOKOL_COLOR_INCLUDED (1)
#if !defined(SOKOL_GFX_INCLUDED)
#error "Please include sokol_gfx.h before sokol_color.h"
#endif
#if defined(SOKOL_API_DECL) && !defined(SOKOL_GL_API_DECL)
#define SOKOL_COLOR_API_DECL SOKOL_API_DECL
#endif
#ifndef SOKOL_COLOR_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_COLOR_IMPL)
#define SOKOL_COLOR_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_COLOR_API_DECL __declspec(dllimport)
#else
#define SOKOL_COLOR_API_DECL extern
#endif
#endif
#ifdef __cplusplus
#define SOKOL_COLOR_CONSTEXPR constexpr
extern "C" {
#else
#define SOKOL_COLOR_CONSTEXPR const
#endif
SOKOL_COLOR_API_DECL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
SOKOL_COLOR_API_DECL sg_color sg_make_color_1i(uint32_t rgba);
SOKOL_COLOR_API_DECL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount);
SOKOL_COLOR_API_DECL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount);
SOKOL_COLOR_API_DECL sg_color sg_color_multiply(const sg_color* color, float scale);
""")
def unpack_rgba(color):
red = (color & 0xFF000000) >> 24
green = (color & 0xFF0000) >> 16
blue = (color & 0xFF00) >> 8
alpha = (color & 0xFF)
return (red, green, blue, alpha)
def add_documentation(color):
documentation = "/* {name} color {{ R:{r}, G:{g}, B:{b}, A:{a} }} */\n"
rgba = unpack_rgba(color[1])
header.write(documentation.format(
name = color[0], r = rgba[0], g = rgba[1], b = rgba[2], a = rgba[3]))
for color in colors:
add_documentation(color)
init_color = "SG_" + color[0].upper().replace(" ", "_")
init_color_definition = "#define {name} {{ {r}f, {g}f, {b}f, {a}f }}\n"
rgba = unpack_rgba(color[1])
r = rgba[0] / 255
g = rgba[1] / 255
b = rgba[2] / 255
a = rgba[3] / 255
r_text = "{:.1f}".format(r) if r.is_integer() else "{:.9g}".format(r)
g_text = "{:.1f}".format(g) if g.is_integer() else "{:.9g}".format(g)
b_text = "{:.1f}".format(b) if b.is_integer() else "{:.9g}".format(b)
a_text = "{:.1f}".format(a) if a.is_integer() else "{:.9g}".format(a)
header.write(init_color_definition.format(
name = init_color, r = r_text, g = g_text, b = b_text, a = a_text))
header.write("\n")
for color in colors:
add_documentation(color)
init_color = "sg_" + color[0].lower().replace(" ", "_")
init_color_definition = "static SOKOL_COLOR_CONSTEXPR sg_color {name} = {init};\n"
init_color_name = "SG_" + color[0].upper().replace(" ", "_")
header.write(init_color_definition.format(name = init_color, init = init_color_name))
header.write("\n")
for color in colors:
add_documentation(color)
hex_color = "0x{0:08X}".format(color[1])
packed_color = "SG_" + color[0].upper().replace(" ", "_") + "_RGBA32"
packed_color_definition = "#define {name} {rgba}\n"
header.write(packed_color_definition.format(name = packed_color, rgba = hex_color))
header.write("""
#ifdef __cplusplus
} /* extern "C" */
inline sg_color sg_make_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return sg_make_color_4b(r, g, b, a);
}
inline sg_color sg_make_color(uint32_t rgba) {
return sg_make_color_1i(rgba);
}
inline sg_color sg_color_lerp(const sg_color& color_a, const sg_color& color_b, float amount) {
return sg_color_lerp(&color_a, &color_b, amount);
}
inline sg_color sg_color_lerp_precise(const sg_color& color_a, const sg_color& color_b, float amount) {
return sg_color_lerp_precise(&color_a, &color_b, amount);
}
inline sg_color sg_color_multiply(const sg_color& color, float scale) {
return sg_color_multiply(&color, scale);
}
#endif /* __cplusplus */
#endif /* SOKOL_COLOR_INCLUDED */
/*-- IMPLEMENTATION ----------------------------------------------------------*/
#ifdef SOKOL_COLOR_IMPL
#define SOKOL_COLOR_IMPL_INCLUDED (1)
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#ifndef SOKOL_ASSERT
#include <assert.h>
#define SOKOL_ASSERT(c) assert(c)
#endif
static inline float _sg_color_clamp(float v, float low, float high) {
if (v < low) {
return low;
} else if (v > high) {
return high;
}
return v;
}
static inline float _sg_color_lerp(float a, float b, float amount) {
return a + (b - a) * amount;
}
static inline float _sg_color_lerp_precise(float a, float b, float amount) {
return ((1.0f - amount) * a) + (b * amount);
}
SOKOL_API_IMPL sg_color sg_make_color_4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
sg_color result;
result.r = r / 255.0f;
result.g = g / 255.0f;
result.b = b / 255.0f;
result.a = a / 255.0f;
return result;
}
SOKOL_API_IMPL sg_color sg_make_color_1i(uint32_t rgba) {
return sg_make_color_4b(
(uint8_t)(rgba >> 24),
(uint8_t)(rgba >> 16),
(uint8_t)(rgba >> 8),
(uint8_t)(rgba >> 0)
);
}
SOKOL_API_IMPL sg_color sg_color_lerp(const sg_color* color_a, const sg_color* color_b, float amount) {
SOKOL_ASSERT(color_a);
SOKOL_ASSERT(color_b);
amount = _sg_color_clamp(amount, 0.0f, 1.0f);
sg_color result;
result.r = _sg_color_lerp(color_a->r, color_b->r, amount);
result.g = _sg_color_lerp(color_a->g, color_b->g, amount);
result.b = _sg_color_lerp(color_a->b, color_b->b, amount);
result.a = _sg_color_lerp(color_a->a, color_b->a, amount);
return result;
}
SOKOL_API_IMPL sg_color sg_color_lerp_precise(const sg_color* color_a, const sg_color* color_b, float amount) {
SOKOL_ASSERT(color_a);
SOKOL_ASSERT(color_b);
amount = _sg_color_clamp(amount, 0.0f, 1.0f);
sg_color result;
result.r = _sg_color_lerp_precise(color_a->r, color_b->r, amount);
result.g = _sg_color_lerp_precise(color_a->g, color_b->g, amount);
result.b = _sg_color_lerp_precise(color_a->b, color_b->b, amount);
result.a = _sg_color_lerp_precise(color_a->a, color_b->a, amount);
return result;
}
SOKOL_API_IMPL sg_color sg_color_multiply(const sg_color* color, float scale) {
SOKOL_ASSERT(color);
sg_color result;
result.r = color->r * scale;
result.g = color->g * scale;
result.b = color->b * scale;
result.a = color->a * scale;
return result;
}
#endif /* SOKOL_COLOR_IMPL */
""")
+1148
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3934
View File
File diff suppressed because it is too large Load Diff
+2168
View File
File diff suppressed because it is too large Load Diff
+171
View File
@@ -0,0 +1,171 @@
#if defined(SOKOL_IMPL) && !defined(SOKOL_MEMTRACK_IMPL)
#define SOKOL_MEMTRACK_IMPL
#endif
#ifndef SOKOL_MEMTRACK_INCLUDED
/*
sokol_memtrack.h -- memory allocation wrapper to track memory usage
of sokol libraries
Project URL: https://github.com/floooh/sokol
Simply include this file before the sokol header implementation includes
and after the SOKOL_IMPL macro:
#define SOKOL_IMPL
#include "sokol_memtrack.h"
#include "sokol_app.h"
#include "sokol_gfx.h"
...
Optionally provide the following defines with your own implementations:
SOKOL_MEMTRACK_API_DECL - public function declaration prefix (default: extern)
SOKOL_API_DECL - same as SOKOL_MEMTRACK_API_DECL
SOKOL_API_IMPL - public function implementation prefix (default: -)
If sokol_memtrack.h is compiled as a DLL, define the following before
including the declaration or implementation:
SOKOL_DLL
The sokol_memtrack.h header will redirect the macros SOKOL_MALLOC,
SOKOL_FREE and SOKOL_CALLOC to use its own function wrappers which
keep track of number and size of allocations. The wrapper functions
then call the CRT functions malloc(), calloc() or free().
Naturally, only the memory management calls in sokol header code are tracked,
not in underlying APIs such as D3D11 or OpenGL.
To get the current number and overall size of allocations, call:
smemtrack_info_t alloc_info = smemtrack_info();
int num_allocations = info.num_alloc;
int allocation_size = info.num_bytes;
The allocation wrapper functions are *not* thread-safe (which shouldn't
be a problem because the sokol headers don't allocate or deallocate
in threads).
LICENSE
=======
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#define SOKOL_MEMTRACK_INCLUDED (1)
#include <stdint.h>
#if defined(SOKOL_API_DECL) && !defined(SOKOL_MEMTRACK_API_DECL)
#define SOKOL_MEMTRACK_API_DECL SOKOL_API_DECL
#endif
#ifndef SOKOL_MEMTRACK_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_MEMTRACK_IMPL)
#define SOKOL_MEMTRACK_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_MEMTRACK_API_DECL __declspec(dllimport)
#else
#define SOKOL_MEMTRACK_API_DECL extern
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct smemtrack_info_t {
int num_allocs;
int num_bytes;
} smemtrack_info_t;
SOKOL_MEMTRACK_API_DECL smemtrack_info_t smemtrack_info(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SOKOL_MEMTRACK_INCLUDED */
/*=== IMPLEMENTATION =========================================================*/
#ifdef SOKOL_MEMTRACK_IMPL
#define SOKOL_MEMTRACK_IMPL_INCLUDED (1)
#include <stdlib.h> /* malloc, free, calloc */
#include <string.h> /* memset */
#include <stddef.h> /* size_t */
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#ifndef SOKOL_DEBUG
#ifndef NDEBUG
#define SOKOL_DEBUG (1)
#endif
#endif
#ifndef _SOKOL_PRIVATE
#if defined(__GNUC__) || defined(__clang__)
#define _SOKOL_PRIVATE __attribute__((unused)) static
#else
#define _SOKOL_PRIVATE static
#endif
#endif
#define SOKOL_MALLOC(s) _smemtrack_malloc(s)
#define SOKOL_FREE(p) _smemtrack_free(p)
#define SOKOL_CALLOC(n,s) _smemtrack_calloc(n,s)
#define _SMEMTRACK_HEADER_SIZE (16)
static struct {
smemtrack_info_t state;
} _smemtrack;
_SOKOL_PRIVATE void* _smemtrack_malloc(size_t size) {
_smemtrack.state.num_allocs++;
_smemtrack.state.num_bytes += (int) size;
uint8_t* ptr = (uint8_t*) malloc(size + _SMEMTRACK_HEADER_SIZE);
*(size_t*)ptr = size;
return ptr + _SMEMTRACK_HEADER_SIZE;
}
_SOKOL_PRIVATE void _smemtrack_free(void* ptr) {
uint8_t* alloc_ptr = ((uint8_t*)ptr) - _SMEMTRACK_HEADER_SIZE;
size_t size = *(size_t*)alloc_ptr;
_smemtrack.state.num_allocs--;
_smemtrack.state.num_bytes -= (int) size;
free(alloc_ptr);
}
_SOKOL_PRIVATE void* _smemtrack_calloc(size_t num, size_t size) {
size_t mem_size = num * size;
_smemtrack.state.num_allocs++;
_smemtrack.state.num_bytes += (int) mem_size;
uint8_t* ptr = (uint8_t*) malloc(mem_size + _SMEMTRACK_HEADER_SIZE);
memset(ptr + _SMEMTRACK_HEADER_SIZE, 0, mem_size);
*(size_t*)ptr = size;
return ptr + _SMEMTRACK_HEADER_SIZE;
}
SOKOL_API_IMPL smemtrack_info_t smemtrack_info(void) {
return _smemtrack.state;
}
#endif /* SOKOL_MEMTRACK_IMPL */
File diff suppressed because it is too large Load Diff
+1438
View File
File diff suppressed because it is too large Load Diff