
Simple
STB-style
cross-platform libraries for C and C++, written in C.
# Sokol
[**查看新动态**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**2026年2月20日**: sokol-app ios+macos+metal: 用 CAMetalLayer+CADisplayLink 替换 MTKView)
[](/../../actions/workflows/main.yml) [](/../../actions/workflows/gen_bindings.yml) [](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[](https://github.com/floooh/sokol-rust/actions/workflows/main.yml)[](https://github.com/floooh/sokol-d/actions/workflows/build.yml)[](https://github.com/floooh/sokol-c3/actions/workflows/build.yml)
## 示例与相关项目
- 通过 WASM 查看[在线示例](https://floooh.github.io/sokol-html5/index.html) ([源码](https://github.com/floooh/sokol-samples))
- [Doom Shareware](https://floooh.github.io/doom-sokol/) 移植到 Sokol headers ([源码](https://github.com/floooh/doom-sokol))
- Aras Pranckevičius 创作的 [Everybody Wants to Crank the World](https://aras-p.github.io/demo-pd-cranktheworld/) demo,通过 sokol 移植到 PC/Web ([源码](https://github.com/aras-p/demo-pd-cranktheworld)).
- [sokol_gp.h](https://github.com/edubart/sokol_gp) 一个基于 sokol_gfx.h 的 2D 形状绘制库
- [Dear ImGui starterkit](https://github.com/floooh/cimgui-sokol-starterkit) 一个用于编写 C 语言 Dear ImGui 应用的独立入门套件。
- [qoiview](https://github.com/floooh/qoiview) 一个用于查看新型 QOI 图像文件格式的基础查看器
- [Tiny 8-bit 模拟器](https://floooh.github.io/tiny8bit/)
- 一个“单文件”的 [C99 吃豆人克隆](https://github.com/floooh/pacman.c/),也提供 [Zig](https://github.com/floooh/pacman.zig/) 版本
- [Soluna](https://github.com/cloudwu/soluna),一个由 @cloudwu 开发的用于制作 2D 游戏的 Lua 框架
- [Deep Future](https://github.com/cloudwu/deepfuture):...以及一个使用 Soluna 实现的游戏
- [Solar Storm](https://store.steampowered.com/app/2754920/Solar_Storm/),一款使用 Odin 和 Sokol 构建的回合制科幻炮战游戏,已在 Steam 上发布。
- [Spanking Runners (Samogonki)](https://store.steampowered.com/app/2599800/Spanking_Runners/),在一个明亮且不寻常的世界中进行街机赛车,已在 Steam 上发布。
- [MEG-4](https://bztsrc.gitlab.io/meg4) 一个用 C89 编写的虚拟幻想主机模拟器,已移植到 sokol
- 一个[迷你高尔夫游戏](https://mgerdes.github.io/minigolf.html)([源码](https://github.com/mgerdes/minigolf))。
- [hIghQube](https://github.com/RuiVarela/hIghQube) 一个大量使用 sokol 渲染的游戏 demo
- [Senos](https://github.com/RuiVarela/Senos) 一个使用 sokol 作为后端的音乐应用
- ['Dealer's Dungeon'](https://dealers-dungeon.com/demo/)([低画质模式](https://dealers-dungeon.com/demo/?q=3),
[源码](https://github.com/bqqbarbhg/spear))
- [移植到 sokol-gfx 的 LearnOpenGL 示例 (可能已过时)](https://zeromake.github.io/learnopengl-examples/)([git 仓库](https://github.com/zeromake/learnopengl-examples))
- [命令行工具](https://github.com/floooh/sokol-tools)(shader 编译器)
- [如何在没有构建系统的情况下构建](https://github.com/floooh/sokol-samples#how-to-build-without-a-build-system):
关于如何使用你喜欢的 C/C++ 构建系统将 Sokol headers 集成到你自己的项目中的有用细节
## 核心库
- [**sokol\_gfx.h**](https://github.com/floooh/sokol/blob/master/sokol_gfx.h): 3D-API 封装 (GL/GLES3/WebGL2 + Metal + D3D11 + WebGPU)
- [**sokol\_app.h**](https://github.com/floooh/sokol/blob/master/sokol_app.h): 应用框架封装 (入口 + 窗口 + 3D上下文 + 输入)
- [**sokol\_time.h**](https://github.com/floooh/sokol/blob/master/sokol_time.h): 时间测量
- [**sokol\_audio.h**](https://github.com/floooh/sokol/blob/master/sokol_audio.h): 最小化的缓冲流式音频播放
- [**sokol\_fetch.h**](https://github.com/floooh/sokol/blob/master/sokol_fetch.h): 来自 HTTP 和本地文件系统的异步数据流
- [**sokol\_args.h**](https://github.com/floooh/sokol/blob/master/sokol_args.h): 用于 Web 和原生应用的统一命令行/URL 参数解析器
- [**sokol\_log.h**](https://github.com/floooh/sokol/blob/master/sokol_log.h): 为其他 sokol headers 提供标准的日志回调
## 实用库
- [**sokol\_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h): [Dear ImGui](https://github.com/ocornut/imgui) 的 sokol_gfx.h 渲染后端
- [**sokol\_nuklear.h**](https://github.com/floooh/sokol/blob/master/util/sokol_nuklear.h): [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear) 的 sokol_gfx.h 渲染后端
- [**sokol\_gl.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gl.h): 基于 sokol_gfx.h 的 OpenGL 1.x 风格立即模式渲染 API
- [**sokol\_fontstash.h**](https://github.com/floooh/sokol/blob/master/util/sokol_fontstash.h): [fontstash](https://github.com/memononen/fontstash) 的 sokol_gl.h 渲染后端
- [**sokol\_gfx\_imgui.h**](https://github.com/floooh/sokol/blob/master/util/sokol_gfx_imgui.h): sokol_gfx.h 的调试检查 UI (使用 Dear ImGui 实现)
- [**sokol\_debugtext.h**](https://github.com/floooh/sokol/blob/master/util/sokol_debugtext.h): 一个使用复古家用电脑字体的简单文本渲染器
- [**sokol\_memtrack.h**](https://github.com/floooh/sokol/blob/master/util/sokol_memtrack.h): 轻松跟踪 sokol headers 中的内存分配
- [**sokol\_shape.h**](https://github.com/floooh/sokol/blob/master/util/sokol_shape.h): 生成简单形状并将其插入 sokol-gfx 资源创建结构体
- [**sokol\_color.h**](https://github.com/floooh/sokol/blob/master/util/sokol_color.h): X11 风格的颜色常量和用于创建 sg_color 对象的函数
- [**sokol\_spine.h**](https://github.com/floooh/sokol/blob/master/util/sokol_spine.h): Spine C 运行时 的 sokol 风格封装 (http://en.esotericsoftware.com/spine-in-depth)
## ‘官方’语言绑定
这些会在 C headers 更改时自动更新:
- [sokol-zig](https://github.com/floooh/sokol-zig)
- [sokol-odin](https://github.com/floooh/sokol-odin)
- [sokol-nim](https://github.com/floooh/sokol-nim)
- [sokol-rust](https://github.com/floooh/sokol-rust)
- [sokol-d](https://github.com/floooh/sokol-d)
- [sokol-jai](https://github.com/colinbellino/sokol-jai)
- [sokol-c3](https://github.com/floooh/sokol-c3)
## 说明
WebAssembly 是‘一等公民’,Sokol headers 的一个重要动机是提供一组跨平台 API,在 Web 平台上占用空间最小,但仍然有用。
核心 headers 是独立的,可以彼此独立使用。
### 为什么是 C:
- 更容易与其他语言集成
- 更容易集成到其他项目中
- 仅给可执行文件增加最小的体积开销
一篇包含更多背景信息的博客文章:[sokol_gfx.h 巡礼](http://floooh.github.io/2017/07/29/sokol-gfx-tour.html)
# sokol_gfx.h:
- 简单、现代的 GLES3/WebGL2, GL3.3, D3D11, Metal 和 WebGPU 封装
- buffers, images, shaders, pipeline-state-objects 和 render-passes
- *不*处理窗口创建或 3D API 上下文初始化
- *不*提供 shader 方言交叉翻译 (**但是**现在有一个‘官方’的 shader 交叉编译器解决方案,可以与 sokol_gfx.h 和 IDE 无缝集成:[详见此处](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md)
# sokol_app.h
一个最小的跨平台应用封装库:
- 统一的应用入口
- 用于 3D 渲染的单窗口或画布
- 3D 上下文初始化
- 基于事件的键盘、鼠标和触摸输入
- 支持的平台:Win32, MacOS, Linux (X11), iOS, WASM, Android, UWP
- 支持的 3D-API:GL3.3 (GLX/WGL), Metal, D3D11, GLES3/WebGL2
使用 sokol_gfx.h, sokol_app.h 和 sokol-shdc shader 编译器 (未显示 shader 代码) 的原生 Hello-Triangle:
```
#include "sokol_app.h"
#include "sokol_gfx.h"
#include "sokol_log.h"
#include "sokol_glue.h"
#include "triangle-sapp.glsl.h"
static struct {
sg_pipeline pip;
sg_bindings bind;
sg_pass_action pass_action;
} state;
static void init(void) {
sg_setup(&(sg_desc){
.environment = sglue_environment(),
.logger.func = slog_func,
});
float vertices[] = {
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
};
state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(vertices),
});
state.pip = sg_make_pipeline(&(sg_pipeline_desc){
.shader = sg_make_shader(triangle_shader_desc(sg_query_backend())),
.layout = {
.attrs = {
[ATTR_triangle_position].format = SG_VERTEXFORMAT_FLOAT3,
[ATTR_triangle_color0].format = SG_VERTEXFORMAT_FLOAT4
}
},
});
state.pass_action = (sg_pass_action) {
.colors[0] = { .load_action=SG_LOADACTION_CLEAR, .clear_value={0.0f, 0.0f, 0.0f, 1.0f } }
};
}
void frame(void) {
sg_begin_pass(&(sg_pass){ .action = state.pass_action, .swapchain = sglue_swapchain() });
sg_apply_pipeline(state.pip);
sg_apply_bindings(&state.bind);
sg_draw(0, 3, 1);
sg_end_pass();
sg_commit();
}
void cleanup(void) {
sg_shutdown();
}
sapp_desc sokol_main(int argc, char* argv[]) {
(void)argc; (void)argv;
return (sapp_desc){
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.width = 640,
.height = 480,
.window_title = "Triangle",
.icon.sokol_default = true,
.logger.func = slog_func,
};
}
```
# sokol_audio.h
一个最小的音频流 API:
- 你提供一个 32-bit 浮点样本的单声道或立体声流,sokol_audio.h 将其转发到特定平台的后端
- 两种提供数据的方式:
1. 直接从运行在音频线程中的回调函数填充后端音频缓冲区
2. 或者从你的主循环推送小的音频数据包,
或者由你创建的单独线程
- 平台后端:
- Windows: WASAPI
- macOS/iOS: CoreAudio
- Linux: ALSA
- emscripten: WebAudio + ScriptProcessorNode (不使用 emscripten 提供的 OpenAL 或 SDL Audio 封装)
一个使用回调模型的简单单声道方波发生器:
```
// 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,
.logger.func = slog_func,
});
// run main loop
...
// shutdown sokol-audio
saudio_shutdown();
return 0;
```
使用推送模型的相同代码
```
#define BUF_SIZE (32)
int main() {
// init sokol-audio with default params, no callback
saudio_setup(&(saudio_desc){
.logger.func = slog_func,
});
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
加载整个文件,或通过 HTTP (emscripten/wasm) 或本地文件系统 (所有原生平台) 异步流式传输数据。
加载文件到静态缓冲区的简单 C99 示例:
```
#include "sokol_fetch.h"
#include "sokol_log.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){ .logger.func = slog_func });
// 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:
简单的跨平台时间测量:
```
#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
用于 Web 和原生应用的统一参数解析。在原生平台上使用 argc/argv,在 Web 上使用 URL 查询字符串。
带有一个参数的示例 URL:
https://floooh.github.io/tiny8bit/kc85.html?type=kc85_4
作为命令行应用的相同功能:
像这样解析:
```
#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;
}
```
有关更完整的文档,请参阅 sokol_args.h header,以及 [Tiny Emulators](https://floooh.github.io/tiny8bit/) 以获取更多有趣的使用示例。