Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
## Description
`sokol` is a thin wrapper around [sokol](https://github.com/floooh/sokol),
which in turn is a library of "Simple STB-style cross-platform libraries
for C and C++, written in C.", that provide access to graphics/audio/input
processing.
Each `.h` file in the sokol source code is well-documented as can be seen here:
[sokol_audio.h](https://github.com/floooh/sokol/blob/master/sokol_audio.h)
## Example from `@VEXEROOT/examples/sokol/sounds/simple_sin_tones.v`
```v cgen
import time
import math
import sokol.audio
const sw = time.new_stopwatch()
const sw_start_ms = sw.elapsed().milliseconds()
@[inline]
fn sintone(periods int, frame int, num_frames int) f32 {
return math.sinf(f32(periods) * (2 * math.pi) * f32(frame) / f32(num_frames))
}
fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int) {
ms := sw.elapsed().milliseconds() - sw_start_ms
unsafe {
mut soundbuffer := buffer
for frame := 0; frame < num_frames; frame++ {
for ch := 0; ch < num_channels; ch++ {
idx := frame * num_channels + ch
if ms < 250 {
soundbuffer[idx] = 0.5 * sintone(20, frame, num_frames)
} else if ms < 300 {
soundbuffer[idx] = 0.5 * sintone(25, frame, num_frames)
} else if ms < 1500 {
soundbuffer[idx] *= sintone(22, frame, num_frames)
} else {
soundbuffer[idx] = 0.5 * sintone(25, frame, num_frames)
}
}
}
}
}
fn main() {
audio.setup(
stream_cb: my_audio_stream_callback
)
time.sleep(2000 * time.millisecond)
audio.shutdown()
}
```
## Troubleshooting sokol apps
A common problem, if you draw a lot of primitive elements in the same frame,
is that there is a chance that your program can exceed the maximum
allowed amount of vertices and commands, imposed by `sokol`.
The symptom is that your frame will be suddenly black, after it
becomes more complex.
Sokol's default for vertices is 131072.
Sokol's default for commands is 32768.
To solve that, you can try adding these lines at the top of your program:
`#flag -D_SGL_DEFAULT_MAX_VERTICES=4194304`
`#flag -D_SGL_DEFAULT_MAX_COMMANDS=65536`
You can see an example of that in:
https://github.com/vlang/v/blob/master/examples/gg/examples/gg/many_thousands_of_circles_overriding_max_vertices.v
Another approach to that problem, is to draw everything yourself in a streaming
texture, then upload that streaming texture as a single draw command to the GPU.
You can see an example of that done in:
https://github.com/vlang/v/blob/master/examples/gg/random.v
and in:
https://github.com/vlang/v/blob/master/examples/gg/random_stars.v
A third approach, is to only upload your changing inputs to the GPU, and do all
the calculations and drawing there in shaders.
+229
View File
@@ -0,0 +1,229 @@
module audio
import sokol.memory
$if linux {
// provide a nicer error for the user that does not have ALSA installed
#include <alsa/asoundlib.h> # Please install the `libasound2-dev` package
}
$if openbsd {
$compile_error('sokol/audio not supported on OpenBSD')
}
#flag -I @VEXEROOT/thirdparty/sokol
// FreeBSD requires the audio/alsa-lib to be installed
#flag freebsd -I/usr/local/include
@[use_once]
#define SOKOL_IMPL
#include "sokol_audio.h"
#flag linux -lasound -lpthread
#flag darwin -framework AudioToolbox
#flag windows -lole32
#flag freebsd -L/usr/local/lib
#flag freebsd -lasound
#flag android -laaudio
// callback function for `stream_cb` in [[C.saudio_desc](#C.saudio_desc)] when calling [audio.setup()](#setup)
//
// sokol callback functions run in a separate thread
//
// This function will be called with a reference to the C buffer and the maximum number of frames and channels
// the audio backend is expecting in its buffer.
//
// Terms:
// - *sample* - a 32-bit floating point number from `-1.0` to `+1.0` representing the waveform amplitude at that instant
// - *frame* - one sample for each channel at that instant
//
// To determine the number of samples expected, do `num_frames * num_channels`.
// Then, write up to that many `f32` samples into `buffer` using unsafe operations.
//
// Do not write more data to the buffer than it is requesting, but you may write less. The buffer is initialized with
// zeroes, so unwritten data will result in audio silence.
// Example body: unsafe { C.memcpy(buffer, &samples, samples.len * int(sizeof(f32))) }
// Example body: unsafe { mut b := buffer; for i, sample in samples { b[i] = sample } }
pub type FNStreamingCB = fn (buffer &f32, num_frames int, num_channels int)
// callback function for `stream_userdata_cb` to use in `C.saudio_desc` when calling [audio.setup()](#setup)
// This function operates the same way as [[FNStreamingCB](#FNStreamingCB)] but it passes customizable `user_data` to the
// callback. This is the method to use if your audio data is stored in a struct or array. Identify the
// `user_data` when you call `audio.setup()` and that object will be passed to the callback as the last arg.
// Note: Sokol's callback functions run in a separate thread.
// Example: previously_parsed_wavfile_bytes := [f32(0),0,0,0]; mycallback := fn (buffer &f32, num_frames int, num_channels int, mut sb []f32) {}; mut soundbuffer := []f32{}; soundbuffer << previously_parsed_wavfile_bytes; audio.setup(stream_userdata_cb: mycallback, user_data: soundbuffer.data);
pub type FnStreamingCBWithUserData = fn (buffer &f32, num_frames int, num_channels int, user_data voidptr)
pub fn (x FNStreamingCB) str() string {
return '&FNStreamingCB{ ${ptr_str(x)} }'
}
pub fn (x FnStreamingCBWithUserData) str() string {
return '&FnStreamingCBWithUserData{ ${ptr_str(x)} }'
}
@[typedef]
pub struct C.saudio_allocator {
pub mut:
alloc_fn memory.FnAllocatorAlloc
free_fn memory.FnAllocatorFree
user_data voidptr
}
@[typedef]
pub struct C.saudio_logger {
pub mut:
func memory.FnLogCb
user_data voidptr
}
// only one of `stream_cb` or `stream_userdata_cb` should be used
//
// default values (internal to sokol C library):
//
// | variable | default | note |
// | :----------- | -------: | :--------- |
// | sample_rate | 44100 | higher sample rates take more memory but are higher quality |
// | num_channels | 1 | for stereo sound, this should be 2 |
// | buffer_frames | 2048 | buffer size in frames, larger is more latency, smaller means higher CPU |
// | packet_frames | 128 | push model only, number of frames that will be pushed in each packet |
// | num_packets | 64 | for push model only, number of packets in the backend ringbuffer |
@[params; typedef]
pub struct C.saudio_desc {
pub:
sample_rate int
num_channels int
buffer_frames int
packet_frames int
num_packets int
stream_cb FNStreamingCB
stream_userdata_cb FnStreamingCBWithUserData
pub mut:
user_data voidptr
allocator C.saudio_allocator
logger C.saudio_logger
}
fn C.saudio_setup(const_desc &C.saudio_desc)
fn C.saudio_shutdown()
fn C.saudio_isvalid() bool
fn C.saudio_userdata() voidptr
fn C.saudio_query_desc() C.saudio_desc
fn C.saudio_sample_rate() i32
fn C.saudio_buffer_frames() i32
fn C.saudio_channels() i32
fn C.saudio_suspended() bool
fn C.saudio_expect() i32
fn C.saudio_push(const_frames &f32, num_frames i32) i32
// setup - setup sokol-audio
pub fn setup(desc &C.saudio_desc) {
if desc.allocator.alloc_fn == unsafe { nil } && desc.allocator.free_fn == unsafe { nil } {
unsafe {
desc.allocator.alloc_fn = memory.salloc
desc.allocator.free_fn = memory.sfree
desc.allocator.user_data = voidptr(0x100a0d10)
}
}
if desc.logger.func == unsafe { nil } {
unsafe {
desc.logger.func = memory.slog
}
}
C.saudio_setup(desc)
}
// shutdown - shutdown sokol-audio
pub fn shutdown() {
C.saudio_shutdown()
}
// is_valid - true after setup if audio backend was successfully initialized
pub fn is_valid() bool {
return C.saudio_isvalid()
}
// userdata - return the saudio_desc.user_data pointer
pub fn user_data() voidptr {
return C.saudio_userdata()
}
// query - return a copy of the original saudio_desc struct
pub fn query() C.saudio_desc {
return C.saudio_query_desc()
}
// sample_rate - return the actual sample rate
pub fn sample_rate() int {
return C.saudio_sample_rate()
}
// buffer_frames - return the actual backend buffer size in number of frames
pub fn buffer_frames() int {
return C.saudio_buffer_frames()
}
// channels - return the actual number of channels
pub fn channels() int {
return C.saudio_channels()
}
// suspended returns true if audio context is currently suspended
// (only in WebAudio backend, all other backends return false)
pub fn suspended() bool {
return C.saudio_suspended()
}
// expect - get current number of frames to fill packet queue; use in combination with audio.push
pub fn expect() int {
return C.saudio_expect()
}
// push - push sample frames from main thread, returns number of frames actually pushed
pub fn push(frames &f32, num_frames int) int {
return C.saudio_push(frames, num_frames)
}
// fclamp - helper function to 'clamp' a number to a certain range
// Example: sample := f32(3.14); realsample := audio.fclamp(sample, -1.0, 1.0); assert realsample == 1.0
@[inline]
pub fn fclamp(x f32, flo f32, fhi f32) f32 {
if x > fhi {
return fhi
}
if x < flo {
return flo
}
return x
}
// min - helper function to return the smaller of two numbers
//
// NOTE: math.min returns `f32` values, this returns `int` values
// Example: println(audio.min(1, 5))
pub fn min(x int, y int) int {
if x < y {
return x
}
return y
}
// max - helper function to return the larger of two numbers
//
// NOTE: math.max returns `f32` values, this returns `int` values
// Example: println(audio.max(1, 5))
pub fn max(x int, y int) int {
if x < y {
return y
}
return x
}
+153
View File
@@ -0,0 +1,153 @@
module c
import sokol.memory as _
#flag -I @VEXEROOT/thirdparty/sokol
#flag -I @VEXEROOT/thirdparty/sokol/util
#flag freebsd -I /usr/local/include
#flag darwin -fobjc-arc
// Platform-specific library linking
// X11 is the default on Linux
// Use `-d sokol_wayland` to enable Wayland support
#flag linux -DSOKOL_GLCORE
$if sokol_wayland ? {
#flag linux -lwayland-client -lwayland-egl -lxkbcommon -lxkbcommon-x11 -lEGL -lGL -lpthread -lm -ldl -lX11 -lXi -lXcursor
} $else {
// EGL is used instead of GLX on X11 to get consistent vsync under XWayland.
// GLX vsync is often ignored by XWayland compositors, causing frame pacing
// jitter. EGL honours the swap interval reliably on both native X11 and
// XWayland sessions.
#flag linux -lX11 -lXi -lXcursor -lEGL -lGL -lpthread -lm -ldl
}
#flag freebsd -DSOKOL_GLCORE
#flag freebsd -L/usr/local/lib -lX11 -lGL -lXcursor -lXi
#flag openbsd -DSOKOL_GLCORE
#flag openbsd -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lGL -lXcursor -lXi
#flag windows -DSOKOL_GLCORE
#flag windows -lgdi32
$if windows {
#flag windows -lopengl32
$if msvc {
$if livemain ? {
#define SOKOL_DLL
}
$if sharedlive ? {
#define SOKOL_DLL
}
}
}
// Note that -lm is needed *only* for sokol_gl.h's usage of sqrtf(),
// but without -lm, this fails:
// `v -cc gcc ~/.vmodules/sdl/examples/sdl_opengl_and_sokol/`
// With tcc, this succeeds with or without -lm:
// `v ~/.vmodules/sdl/examples/sdl_opengl_and_sokol/`
$if !tinyc {
#flag linux -lm
}
// METAL
$if macos {
$if darwin_sokol_glcore33 ? {
#flag darwin -DSOKOL_GLCORE -framework OpenGL -framework Cocoa -framework QuartzCore
} $else {
#flag -DSOKOL_METAL
#flag -framework Metal -framework Cocoa -framework MetalKit -framework QuartzCore
}
}
$if ios {
#flag -DSOKOL_METAL
#flag -framework Foundation -framework Metal -framework MetalKit -framework UIKit
}
$if emscripten ? {
#flag -DSOKOL_GLES3
#flag -DSOKOL_NO_ENTRY
#flag -s ERROR_ON_UNDEFINED_SYMBOLS=0
#flag -s USE_WEBGL2
$if !prod {
#flag -s ASSERTIONS=1
}
$if prod {
#flag -s ASSERTIONS=0
}
// See https://emscripten.org/docs/tools_reference/settings_reference.html#modularize
// Note that it makes it impossible to use `v -os wasm32_emscripten -o file.html program.v` , due to:
// https://github.com/emscripten-core/emscripten/issues/7950
// #flag -s MODULARIZE
}
// D3D
//#flag windows -DSOKOL_D3D11
#flag windows -DSOKOL_GLCORE
// for simplicity, all header includes are here because import order matters and we dont have any way
// to ensure import order with V yet
// TODO: should not be defined for android graphic (apk/aab using sokol) builds, but we have no ways to undefine
//#define SOKOL_NO_ENTRY
#flag linux -DSOKOL_NO_ENTRY
#flag darwin -DSOKOL_NO_ENTRY
#flag windows -DSOKOL_NO_ENTRY
#flag windows -DSOKOL_WIN32_FORCE_MAIN
#flag freebsd -DSOKOL_NO_ENTRY
#flag openbsd -DSOKOL_NO_ENTRY
#flag solaris -DSOKOL_NO_ENTRY
// TODO: end
#flag linux -ldl
// To allow for thirdparty initializing window / acceleration contexts
// but still be able to use sokol.gfx e.g. SDL+sokol_gfx
$if !no_sokol_app ? {
$if linux && sokol_wayland ? {
// Enable Wayland on Linux (when explicitly enabled with -d sokol_wayland)
#define SOKOL_WAYLAND
#flag -I@VEXEROOT/thirdparty/sokol
} $else $if linux {
// Explicitly disable Wayland on Linux when not using sokol_wayland
#define SOKOL_DISABLE_WAYLAND
// Force EGL instead of GLX so that eglSwapBuffers provides consistent
// vsync pacing on both native X11 and XWayland sessions.
#define SOKOL_FORCE_EGL
}
$if macos {
$if sharedlive ? {
} $else {
// The live-reload dylib should reuse the host app's sokol_app symbols on macOS.
#define SOKOL_APP_IMPL
}
} $else $if windows {
$if sharedlive ? {
} $else {
// On Windows, the live-reload DLL links back to the host executable's
// import library, so it should not embed its own sokol_app backend.
#define SOKOL_APP_IMPL
}
} $else {
#define SOKOL_APP_IMPL
}
@[use_once]
#include "sokol_app.h"
}
$if windows && sharedlive ? {
} $else {
@[use_once]
#define SOKOL_GFX_IMPL
}
#define SOKOL_NO_DEPRECATED
#include "sokol_gfx.h"
$if windows && sharedlive ? {
} $else {
@[use_once]
#define SOKOL_IMPL
}
#include "util/sokol_gl.h"
#include "sokol_v.post.h"
+12
View File
@@ -0,0 +1,12 @@
module f
import fontstash as _
import sokol.c as _
#flag linux -I.
//#include "ft2build.h"
@[use_once]
#define SOKOL_FONTSTASH_IMPL
#include "util/sokol_fontstash.h"
+386
View File
@@ -0,0 +1,386 @@
module gfx
pub enum Backend {
glcore33
gles3
d3d11
metal_ios
metal_macos
metal_simulator
wgpu
dummy
}
// PixelFormat is C.sg_pixel_format
pub enum PixelFormat as u32 {
_default // value 0 reserved for default-init
none
r8
r8sn
r8ui
r8si
r16
r16sn
r16ui
r16si
r16f
rg8
rg8sn
rg8ui
rg8si
r32ui
r32si
r32f
rg16
rg16sn
rg16ui
rg16si
rg16f
rgba8
srgb8a8
rgba8sn
rgba8ui
rgba8si
bgra8
rgb10a2
rg11b10f
rgb9e5
rg32ui
rg32si
rg32f
rgba16
rgba16sn
rgba16ui
rgba16si
rgba16f
rgba32ui
rgba32si
rgba32f
depth
depth_stencil
bc1_rgba
bc2_rgba
bc3_rgba
bc3_srgba
bc4_r
bc4_rsn
bc5_rg
bc5_rgsn
bc6h_rgbf
bc6h_rgbuf
bc7_rgba
bc7_srgba
pvrtc_rgb_2bpp // deprecated
pvrtc_rgb_4bpp // deprecated
pvrtc_rgba_2bpp // deprecated
pvrtc_rgba_4bpp // deprecated
etc2_rgb8
etc2_srgb8
etc2_rgb8a1
etc2_rgba8
etc2_srgb8a8
eac_r11
eac_r11sn
eac_rg11
eac_rg11sn
astc_4x4_rgba
astc_4x4_srgba
_num
_force_u32 = 0x7FFFFFFF
}
pub enum ResourceState as u32 {
initial
alloc
valid
failed
invalid
_force_u32 = 0x7FFFFFFF
}
pub enum Usage as u32 {
_default // value 0 reserved for default-init
immutable
dynamic
stream
_num
_force_u32 = 0x7FFFFFFF
}
pub enum BufferType as u32 {
_default // value 0 reserved for default-init
vertexbuffer
indexbuffer
storagebuffer
_num
_force_u32 = 0x7FFFFFFF
}
pub enum IndexType as u32 {
_default // value 0 reserved for default-init
none
uint16
uint32
_num
_force_u32 = 0x7FFFFFFF
}
pub enum ImageType as u32 {
_default // value 0 reserved for default-init
_2d
cube
_3d
array
_num
_force_u32 = 0x7FFFFFFF
}
pub enum ImageSampleType as u32 {
_default // value 0 reserved for default-init
float
depth
sint
uint
unfilterable_float
_num
_force_u32 = 0x7FFFFFFF
}
pub enum SamplerType as u32 {
_default
filtering
nonfiltering
comparison
_num
_force_u32 = 0x7FFFFFFF
}
pub enum CubeFace as u32 {
pos_x
neg_x
pos_y
neg_y
pos_z
neg_z
num
_force_u32 = 0x7fffffff
}
pub enum ShaderStage as u32 {
vs
fs
_force_u32 = 0x7FFFFFFF
}
pub enum PrimitiveType as u32 {
_default // value 0 reserved for default-init
points
lines
line_strip
triangles
triangle_strip
_num
_force_u32 = 0x7FFFFFFF
}
pub enum Filter as u32 {
_default // value 0 reserved for default-init
none
nearest
linear
_num
_force_u32 = 0x7fffffff
}
pub enum Wrap as u32 {
_default // value 0 reserved for default-init
repeat // The default wrap mode.
clamp_to_edge
clamp_to_border // not supported on all backends and platforms. To check for support, call sg_query_features(), and check the "clamp_to_border" boolean in the returned sg_features struct. Platforms which don't support SG_WRAP_CLAMP_TO_BORDER will silently fall back to clamp_to_edge without a validation error.
mirrored_repeat
_num
_force_u32 = 0x7FFFFFFF
}
pub enum BorderColor as u32 {
_default // value 0 reserved for default-init
transparent_black
opaque_black
opaque_white
_num
_force_u32 = 0x7FFFFFFF
}
pub enum VertexFormat as u32 {
invalid
float
float2
float3
float4
byte4
byte4n // normalized
ubyte4
ubyte4n
short2
short2n
ushort2n
short4
short4n
ushort4n
uint10_n2
half2
half4
_num
_force_u32 = 0x7FFFFFFF
}
pub enum VertexStep as u32 {
_default // value 0 reserved for default-init
per_vertex
per_instance
_num
_force_u32 = 0x7FFFFFFF
}
pub enum UniformType as u32 {
invalid
float
float2
float3
float4
int
int2
int3
int4
mat4
_num
_force_u32 = 0x7FFFFFFF
}
pub enum CullMode as u32 {
_default // value 0 reserved for default-init
none
front
back
_num
_force_u32 = 0x7FFFFFFF
}
// FaceWindin is C.sg_face_winding
pub enum FaceWinding as u32 {
default // value 0 reserved for default-init
ccw
cw
num
force_u32 = 0x7FFFFFFF
}
pub enum CompareFunc as u32 {
_default // value 0 reserved for default-init
never
less
equal
less_equal
greater
not_equal
greater_equal
always
_num
_force_u32 = 0x7FFFFFFF
}
pub enum StencilOp as u32 {
_default // value 0 reserved for default-init
keep
zero
replace
incr_clamp
decr_clamp
invert
incr_wrap
decr_wrap
_num
_force_u32 = 0x7FFFFFFF
}
pub enum BlendFactor as u32 {
_default // value 0 reserved for default-init
zero
one
src_color
one_minus_src_color
src_alpha
one_minus_src_alpha
dst_color
one_minus_dst_color
dst_alpha
one_minus_dst_alpha
src_alpha_saturated
blend_color
one_minus_blend_color
blend_alpha
one_minus_blend_alpha
_num
_force_u32 = 0x7FFFFFFF
}
pub enum BlendOp as u32 {
_default // value 0 reserved for default-init
add
subtract
reverse_subtract
_num
_force_u32 = 0x7FFFFFFF
}
pub enum ColorMask as u32 {
_default = 0 // value 0 reserved for default-init
none = 0x10 // special value for 'all channels disabled
r = 1
g = 2
rg = 3
b = 4
rb = 5
gb = 6
rgb = 7
a = 8
ra = 9
ga = 0xa
rga = 0xb
ba = 0xc
rba = 0xd
gba = 0xe
rgba = 0xf
_force_u32 = 0x7FFFFFFF
}
pub enum LoadAction as u32 {
_default
clear
load
dontcare
_force_u32 = 0x7FFFFFFF
}
pub enum StoreAction as u32 {
_default
store
dontcare
_force_u32 = 0x7FFFFFFF
}
pub enum UniformLayout as u32 {
uniformlayout_default = 0 // value 0 reserved for default-init
uniformlayout_native // default: layout depends on currently active backend
uniformlayout_std140 // std140: memory layout according to std140
_num
_force_u32 = 0x7FFFFFFF
}
+334
View File
@@ -0,0 +1,334 @@
module gfx
import sokol.c as _
import sokol.memory
pub const version = 1
// setup initialises the SOKOL's gfx library, based on the information passed in `desc`
pub fn setup(desc &Desc) {
if desc.allocator.alloc_fn == unsafe { nil } && desc.allocator.free_fn == unsafe { nil } {
unsafe {
desc.allocator.alloc_fn = memory.salloc
desc.allocator.free_fn = memory.sfree
desc.allocator.user_data = voidptr(0x1006fec5)
}
}
if desc.logger.func == unsafe { nil } {
unsafe {
desc.logger.func = memory.slog
}
}
C.sg_setup(desc)
}
// shutdown tells the SOKOL's gfx library to shutdown, and release the resources it is using
pub fn shutdown() {
C.sg_shutdown()
}
@[inline]
pub fn is_valid() bool {
return C.sg_isvalid()
}
@[inline]
fn ensure_initialized(op string) {
if is_valid() {
return
}
panic('sokol.gfx is not initialized; call gfx.setup(...) before ${op}')
}
@[inline]
pub fn reset_state_cache() {
C.sg_reset_state_cache()
}
// resource creation, destruction and updating
// make_buffer creates a GPU buffer.
// make_buffer requires `gfx.setup(...)` to have completed first.
@[inline]
pub fn make_buffer(desc &BufferDesc) Buffer {
ensure_initialized('gfx.make_buffer(...)')
return C.sg_make_buffer(desc)
}
// make_image creates a GPU image.
// make_image requires `gfx.setup(...)` to have completed first.
@[inline]
pub fn make_image(desc &ImageDesc) Image {
ensure_initialized('gfx.make_image(...)')
return C.sg_make_image(desc)
}
// make_sampler creates a GPU sampler.
// make_sampler requires `gfx.setup(...)` to have completed first.
@[inline]
pub fn make_sampler(desc &SamplerDesc) Sampler {
ensure_initialized('gfx.make_sampler(...)')
return C.sg_make_sampler(desc)
}
// make_shader creates a GPU shader.
// make_shader requires `gfx.setup(...)` to have completed first.
@[inline]
pub fn make_shader(desc &ShaderDesc) Shader {
ensure_initialized('gfx.make_shader(...)')
return C.sg_make_shader(desc)
}
// make_pipeline creates a GPU pipeline.
// make_pipeline requires `gfx.setup(...)` to have completed first.
@[inline]
pub fn make_pipeline(desc &PipelineDesc) Pipeline {
ensure_initialized('gfx.make_pipeline(...)')
return C.sg_make_pipeline(desc)
}
// make_attachments creates an `Attachments` instance from `const_desc`.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
@[inline]
pub fn make_attachments(const_desc &AttachmentsDesc) Attachments {
ensure_initialized('gfx.make_attachments(...)')
return C.sg_make_attachments(const_desc)
}
@[inline]
pub fn destroy_buffer(buf Buffer) {
C.sg_destroy_buffer(buf)
}
@[inline]
pub fn destroy_image(img Image) {
C.sg_destroy_image(img)
}
@[inline]
pub fn destroy_sampler(smp Sampler) {
C.sg_destroy_sampler(smp)
}
@[inline]
pub fn destroy_shader(shd Shader) {
C.sg_destroy_shader(shd)
}
@[inline]
pub fn destroy_pipeline(pip Pipeline) {
C.sg_destroy_pipeline(pip)
}
// destroy_attachments destroys the `atts` `Attachments`
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
@[inline]
pub fn destroy_attachments(atts Attachments) {
C.sg_destroy_attachments(atts)
}
@[inline]
pub fn update_buffer(buf Buffer, data &Range) {
C.sg_update_buffer(buf, data)
}
@[inline]
pub fn update_image(img Image, data &ImageData) {
C.sg_update_image(img, data)
}
@[inline]
pub fn append_buffer(buf Buffer, data &Range) int {
return C.sg_append_buffer(buf, data)
}
@[inline]
pub fn query_buffer_overflow(buf Buffer) bool {
return C.sg_query_buffer_overflow(buf)
}
// rendering functions
// begin_pass begins a rendering pass.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
@[inline]
pub fn begin_pass(const_pass &Pass) {
C.sg_begin_pass(const_pass)
}
@[inline]
pub fn apply_viewport(x int, y int, width int, height int, origin_top_left bool) {
C.sg_apply_viewport(x, y, width, height, origin_top_left)
}
@[inline]
pub fn apply_scissor_rect(x int, y int, width int, height int, origin_top_left bool) {
C.sg_apply_scissor_rect(x, y, width, height, origin_top_left)
}
@[inline]
pub fn apply_pipeline(pip Pipeline) {
C.sg_apply_pipeline(pip)
}
@[inline]
pub fn apply_bindings(bindings &Bindings) {
C.sg_apply_bindings(bindings)
}
@[inline]
pub fn apply_uniforms(stage ShaderStage, ub_index int, data &Range) {
C.sg_apply_uniforms(stage, ub_index, data)
}
@[inline]
pub fn draw(base_element int, num_elements int, num_instances int) {
C.sg_draw(base_element, num_elements, num_instances)
}
@[inline]
pub fn end_pass() {
C.sg_end_pass()
}
@[inline]
pub fn commit() {
C.sg_commit()
}
// getting information
@[inline]
pub fn query_desc() Desc {
return C.sg_query_desc()
}
@[inline]
pub fn query_backend() Backend {
unsafe {
return Backend(C.sg_query_backend())
}
}
@[inline]
pub fn query_features() Features {
return C.sg_query_features()
}
@[inline]
pub fn query_limits() Limits {
return C.sg_query_limits()
}
@[inline]
pub fn query_pixelformat(fmt PixelFormat) PixelFormatInfo {
return C.sg_query_pixelformat(fmt)
}
// get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID)
@[inline]
pub fn query_buffer_state(buf Buffer) ResourceState {
return ResourceState(C.sg_query_buffer_state(buf))
}
@[inline]
pub fn query_image_state(img Image) ResourceState {
return ResourceState(C.sg_query_image_state(img))
}
@[inline]
pub fn query_shader_state(shd Shader) ResourceState {
return ResourceState(C.sg_query_shader_state(shd))
}
@[inline]
pub fn query_pipeline_state(pip Pipeline) ResourceState {
return ResourceState(C.sg_query_pipeline_state(pip))
}
// query_attachments_state returns the current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID)
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
@[inline]
pub fn query_attachments_state(atts Attachments) ResourceState {
return ResourceState(C.sg_query_attachments_state(atts))
}
// get runtime information about a resource
@[inline]
pub fn query_buffer_info(buf Buffer) BufferInfo {
return C.sg_query_buffer_info(buf)
}
@[inline]
pub fn query_image_info(img Image) ImageInfo {
return C.sg_query_image_info(img)
}
@[inline]
pub fn query_shader_info(shd Shader) ShaderInfo {
return C.sg_query_shader_info(shd)
}
@[inline]
pub fn query_pipeline_info(pip Pipeline) PipelineInfo {
return C.sg_query_pipeline_info(pip)
}
// query_attachments_info returns runtime information about the `atts` / `Attachments`.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
@[inline]
pub fn query_attachments_info(atts Attachments) AttachmentsInfo {
return C.sg_query_attachments_info(atts)
}
// get resource creation desc struct with their default values replaced
@[inline]
pub fn query_buffer_defaults(desc &Buffer) BufferDesc {
return C.sg_query_buffer_defaults(unsafe { &BufferDesc(voidptr(desc)) })
}
@[inline]
pub fn query_image_defaults(desc &Image) ImageDesc {
return C.sg_query_image_defaults(unsafe { &ImageDesc(voidptr(desc)) })
}
@[inline]
pub fn query_shader_defaults(desc &Shader) ShaderDesc {
return C.sg_query_shader_defaults(unsafe { &ShaderDesc(voidptr(desc)) })
}
@[inline]
pub fn query_pipeline_defaults(desc &Pipeline) PipelineDesc {
return C.sg_query_pipeline_defaults(unsafe { &PipelineDesc(voidptr(desc)) })
}
// query_attachments_defaults returns `AttachmentsDesc` with default values replaced.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
@[inline]
pub fn query_attachments_defaults(desc &AttachmentsDesc) AttachmentsDesc {
return C.sg_query_attachments_defaults(unsafe { &AttachmentsDesc(voidptr(desc)) })
}
// frame stats
// enable_frame_stats enables the sokol frame statistics.
@[inline]
pub fn enable_frame_stats() {
C.sg_enable_frame_stats()
}
// disable_frame_stats disables the sokol frame statistics.
@[inline]
pub fn disable_frame_stats() {
C.sg_disable_frame_stats()
}
// frame_stats_enabled returns `true` if the sokol frame statistics is enabled.
@[inline]
pub fn frame_stats_enabled() bool {
return C.sg_frame_stats_enabled()
}
// query_frame_stats returns the sokol frame statistics for the current frame.
@[inline]
pub fn query_frame_stats() FrameStats {
return C.sg_query_frame_stats()
}
@@ -0,0 +1,18 @@
module gfx
import sokol.memory
@[typedef]
pub struct C.sg_allocator {
pub mut:
alloc_fn memory.FnAllocatorAlloc = unsafe { nil }
free_fn memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
@[typedef]
pub struct C.sg_logger {
pub mut:
func memory.FnLogCb = unsafe { nil }
user_data voidptr
}
+121
View File
@@ -0,0 +1,121 @@
module gfx
// setup and misc functions
fn C.sg_setup(const_desc &C.sg_desc)
fn C.sg_shutdown()
fn C.sg_isvalid() bool
fn C.sg_reset_state_cache()
fn C.sg_install_trace_hooks(const_trace_hooks &C.sg_trace_hooks) C.sg_trace_hooks
fn C.sg_push_debug_group(const_name &char)
fn C.sg_pop_debug_group()
fn C.sg_add_commit_listener(listener C.sg_commit_listener) bool
fn C.sg_remove_commit_listener(listener C.sg_commit_listener) bool
// resource creation, destruction and updating
fn C.sg_make_buffer(const_desc &C.sg_buffer_desc) C.sg_buffer
fn C.sg_make_image(const_desc &C.sg_image_desc) C.sg_image
fn C.sg_make_sampler(const_desc &C.sg_sampler_desc) C.sg_sampler
fn C.sg_make_shader(const_desc &C.sg_shader_desc) C.sg_shader
fn C.sg_make_pipeline(const_desc &C.sg_pipeline_desc) C.sg_pipeline
fn C.sg_make_attachments(const_desc &C.sg_attachments_desc) C.sg_attachments
fn C.sg_destroy_buffer(buf C.sg_buffer)
fn C.sg_destroy_image(img C.sg_image)
fn C.sg_destroy_sampler(smp C.sg_sampler)
fn C.sg_destroy_shader(shd C.sg_shader)
fn C.sg_destroy_pipeline(pip C.sg_pipeline)
fn C.sg_destroy_attachments(atts C.sg_attachments)
fn C.sg_update_buffer(buf C.sg_buffer, data &C.sg_range)
fn C.sg_update_image(img C.sg_image, data &C.sg_image_data)
fn C.sg_append_buffer(buf C.sg_buffer, data &C.sg_range) i32
fn C.sg_query_buffer_overflow(buf C.sg_buffer) bool
fn C.sg_query_buffer_will_overflow(buf C.sg_buffer, size usize) bool
// rendering functions
fn C.sg_begin_pass(const_pass &C.sg_pass)
fn C.sg_apply_viewport(x i32, y i32, width i32, height i32, origin_top_left bool)
fn C.sg_apply_viewportf(x f32, y f32, width f32, height f32, origin_top_left bool)
fn C.sg_apply_scissor_rect(x i32, y i32, width i32, height i32, origin_top_left bool)
fn C.sg_apply_scissor_rectf(x f32, y f32, width f32, height f32, origin_top_left bool)
fn C.sg_apply_pipeline(pip C.sg_pipeline)
fn C.sg_apply_bindings(bindings &C.sg_bindings)
fn C.sg_apply_uniforms(stage ShaderStage, ub_index i32, const_data &C.sg_range)
fn C.sg_draw(base_element i32, num_elements i32, num_instances i32)
fn C.sg_end_pass()
fn C.sg_commit()
// getting information
fn C.sg_query_desc() C.sg_desc
fn C.sg_query_backend() Backend
fn C.sg_query_features() C.sg_features
fn C.sg_query_limits() C.sg_limits
fn C.sg_query_pixelformat(fmt PixelFormat) C.sg_pixelformat_info
// get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID)
fn C.sg_query_buffer_state(buf C.sg_buffer) ResourceState
fn C.sg_query_image_state(img C.sg_image) ResourceState
fn C.sg_query_sampler_state(smp C.sg_sampler) ResourceState
fn C.sg_query_shader_state(shd C.sg_shader) ResourceState
fn C.sg_query_pipeline_state(pip C.sg_pipeline) ResourceState
fn C.sg_query_attachments_state(atts C.sg_attachments) ResourceState
// get runtime information about a resource
fn C.sg_query_buffer_info(buf C.sg_buffer) C.sg_buffer_info
fn C.sg_query_image_info(img C.sg_image) C.sg_image_info
fn C.sg_query_sampler_info(smp C.sg_sampler) C.sg_sampler_info
fn C.sg_query_shader_info(shd C.sg_shader) C.sg_shader_info
fn C.sg_query_pipeline_info(pip C.sg_pipeline) C.sg_pipeline_info
fn C.sg_query_attachments_info(atts C.sg_attachments) C.sg_attachments_info
// get desc structs matching a specific resource (NOTE that not all creation attributes may be provided)
fn C.sg_query_buffer_desc(buf C.sg_buffer) C.sg_buffer_desc
fn C.sg_query_image_desc(img C.sg_image) C.sg_image_desc
fn C.sg_query_sampler_desc(smp C.sg_sampler) C.sg_sampler_desc
fn C.sg_query_shader_desc(shd C.sg_shader) C.sg_shader_desc
fn C.sg_query_pipeline_desc(pip C.sg_pipeline) C.sg_pipeline_desc
fn C.sg_query_attachments_desc(atts C.sg_attachments) C.sg_attachments_desc
// get resource creation desc struct with their default values replaced
fn C.sg_query_buffer_defaults(const_desc &C.sg_buffer_desc) C.sg_buffer_desc
fn C.sg_query_image_defaults(const_desc &C.sg_image_desc) C.sg_image_desc
fn C.sg_query_sampler_defaults(const_desc &C.sg_sampler_desc) C.sg_sampler_desc
fn C.sg_query_shader_defaults(const_desc &C.sg_shader_desc) C.sg_shader_desc
fn C.sg_query_pipeline_defaults(const_desc &C.sg_pipeline_desc) C.sg_pipeline_desc
fn C.sg_query_attachments_defaults(const_desc &C.sg_attachments_desc) C.sg_attachments_desc
// separate resource allocation and initialization (for async setup)
fn C.sg_alloc_buffer() C.sg_buffer
fn C.sg_alloc_image() C.sg_image
fn C.sg_alloc_sampler() C.sg_sampler
fn C.sg_alloc_shader() C.sg_shader
fn C.sg_alloc_pipeline() C.sg_pipeline
fn C.sg_alloc_attachments() C.sg_attachments
fn C.sg_dealloc_buffer(buf C.sg_buffer)
fn C.sg_dealloc_image(img C.sg_image)
fn C.sg_dealloc_sampler(smp C.sg_sampler)
fn C.sg_dealloc_shader(shd C.sg_shader)
fn C.sg_dealloc_pipeline(pip C.sg_pipeline)
fn C.sg_dealloc_attachments(atts C.sg_attachments)
fn C.sg_init_buffer(buf C.sg_buffer, const_desc &C.sg_buffer_desc)
fn C.sg_init_image(img C.sg_image, const_desc &C.sg_buffer_desc)
fn C.sg_init_sampler(smg C.sg_sampler, const_desc &C.sg_sampler_desc)
fn C.sg_init_shader(shd C.sg_shader, const_desc &C.sg_shader_desc)
fn C.sg_init_pipeline(pip C.sg_pipeline, const_desc &C.sg_pipeline_desc)
fn C.sg_init_attachments(atts C.sg_attachments, const_desc &C.sg_attachments_desc)
fn C.sg_uninit_buffer(buf C.sg_buffer)
fn C.sg_uninit_image(img C.sg_image)
fn C.sg_uninit_sampler(smp C.sg_sampler)
fn C.sg_uninit_shader(shd C.sg_shader)
fn C.sg_uninit_pipeline(pip C.sg_pipeline)
fn C.sg_uninit_attachments(atts C.sg_attachments)
fn C.sg_fail_buffer(buf C.sg_buffer)
fn C.sg_fail_image(img C.sg_image)
fn C.sg_fail_sampler(smp C.sg_sampler)
fn C.sg_fail_shader(shd C.sg_shader)
fn C.sg_fail_pipeline(pip C.sg_pipeline)
fn C.sg_fail_attachments(atts C.sg_attachments)
// frame stats
fn C.sg_enable_frame_stats()
fn C.sg_disable_frame_stats()
fn C.sg_frame_stats_enabled() bool
fn C.sg_query_frame_stats() C.sg_frame_stats
+983
View File
@@ -0,0 +1,983 @@
module gfx
// C.sg_desc describes
pub struct C.sg_desc {
pub mut:
_start_canary u32
buffer_pool_size int
image_pool_size int
sampler_pool_size int
shader_pool_size int
pipeline_pool_size int
attachments_pool_size int
uniform_buffer_size int
max_commit_listeners int
disable_validation bool // disable validation layer even in debug mode, useful for tests
mtl_force_managed_storage_mode bool // for debugging: use Metal managed storage mode for resources even with UMA
mtl_use_command_buffer_with_retained_references bool // Metal: use a managed MTLCommandBuffer which ref-counts used resources
wgpu_disable_bindgroups_cache bool // set to true to disable the WebGPU backend BindGroup cache
wgpu_bindgroups_cache_size int // number of slots in the WebGPU bindgroup cache (must be 2^N)
allocator C.sg_allocator
logger C.sg_logger // optional log function override
environment C.sg_environment
_end_canary u32
}
pub type Desc = C.sg_desc
pub struct C.sg_color_target_state {
pub mut:
pixel_format PixelFormat
write_mask ColorMask
blend BlendState
}
pub type ColorTargetState = C.sg_color_target_state
pub struct C.sg_pipeline_desc {
pub mut:
shader Shader
layout VertexLayoutState
depth DepthState
stencil StencilState
color_count int
colors [4]ColorTargetState // C.SG_MAX_COLOR_ATTACHMENTS
primitive_type PrimitiveType
index_type IndexType
cull_mode CullMode
face_winding FaceWinding
sample_count int
blend_color Color
alpha_to_coverage_enabled bool
label &char = &char(unsafe { nil })
}
pub type PipelineDesc = C.sg_pipeline_desc
pub struct C.sg_pipeline_info {
pub:
slot SlotInfo
}
pub type PipelineInfo = C.sg_pipeline_info
pub struct C.sg_pipeline {
pub:
id u32
}
pub type Pipeline = C.sg_pipeline
pub fn (mut p C.sg_pipeline) free() {
C.sg_destroy_pipeline(*p)
}
pub struct C.sg_attachments {
id u32
}
// Attachments represents data that can be attached to a render pass.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
pub type Attachments = C.sg_attachments
// free frees the resources occupied by the struct
pub fn (mut a C.sg_attachments) free() {
C.sg_destroy_attachments(*a)
}
pub struct C.sg_attachment_desc {
pub mut:
image Image
mip_level int
slice int
}
pub type AttachmentDesc = C.sg_attachment_desc
pub struct C.sg_attachments_desc {
pub mut:
_start_canary u32
colors [4]AttachmentDesc
resolves [4]AttachmentDesc
depth_stencil AttachmentDesc
label &char = unsafe { nil }
_end_canary u32
}
pub type AttachmentsDesc = C.sg_attachments_desc
pub struct C.sg_attachments_info {
pub mut:
slot SlotInfo // resource pool slot info
}
pub type AttachmentsInfo = C.sg_attachments_info
pub struct C.sg_bindings {
pub mut:
_start_canary u32
vertex_buffers [8]Buffer
vertex_buffer_offsets [8]int
index_buffer Buffer
index_buffer_offset int
vs StageBindings
fs StageBindings
_end_canary u32
// vs_images [8]Image // old
// fs_images [8]Image // old
}
pub type Bindings = C.sg_bindings
pub fn (mut b Bindings) set_vert_image(index int, img Image) {
b.vs.images[index] = img
}
pub fn (mut b Bindings) set_frag_image(index int, img Image) {
b.fs.images[index] = img
}
pub fn (b &Bindings) update_vert_buffer(index int, data voidptr, element_size int, element_count int) {
range := Range{
ptr: data
size: usize(element_size * element_count)
}
C.sg_update_buffer(b.vertex_buffers[index], &range)
}
pub fn (b &Bindings) append_vert_buffer(index int, data voidptr, element_size int, element_count int) int {
range := Range{
ptr: data
size: usize(element_size * element_count)
}
return C.sg_append_buffer(b.vertex_buffers[index], &range)
}
pub fn (b &Bindings) update_index_buffer(data voidptr, element_size int, element_count int) {
range := Range{
ptr: data
size: usize(element_size * element_count)
}
C.sg_update_buffer(b.index_buffer, &range)
}
pub fn (b &Bindings) append_index_buffer(data voidptr, element_size int, element_count int) int {
range := Range{
ptr: data
size: usize(element_size * element_count)
}
return C.sg_append_buffer(b.index_buffer, &range)
}
pub struct C.sg_stage_bindings {
pub mut:
images [12]Image
samplers [8]Sampler
storage_buffers [8]Buffer
}
pub type StageBindings = C.sg_stage_bindings
@[heap]
pub struct C.sg_shader_desc {
pub mut:
attrs [16]ShaderAttrDesc
vs ShaderStageDesc
fs ShaderStageDesc
label &char
}
pub type ShaderDesc = C.sg_shader_desc
pub fn (mut desc C.sg_shader_desc) set_vert_src(src string) &ShaderDesc {
desc.vs.source = &char(src.str)
return desc
}
pub fn (mut desc C.sg_shader_desc) set_frag_src(src string) &ShaderDesc {
desc.fs.source = &char(src.str)
return desc
}
pub fn (mut desc C.sg_shader_desc) set_vert_image(index int, name string) &ShaderDesc {
// desc.vs.images[index].name = &char(name.str)
desc.vs.images[index].image_type = ._2d
return desc
}
pub fn (mut desc C.sg_shader_desc) set_frag_image(index int, name string) &ShaderDesc {
// desc.fs.images[index].name = &char(name.str)
desc.fs.images[index].image_type = ._2d
return desc
}
pub fn (mut desc C.sg_shader_desc) set_vert_uniform_block_size(block_index int, size usize) &ShaderDesc {
desc.vs.uniform_blocks[block_index].size = size
return desc
}
pub fn (mut desc C.sg_shader_desc) set_frag_uniform_block_size(block_index int, size usize) &ShaderDesc {
desc.fs.uniform_blocks[block_index].size = size
return desc
}
pub fn (mut desc C.sg_shader_desc) set_vert_uniform(block_index int, uniform_index int, name string, typ UniformType,
array_count int) &ShaderDesc {
desc.vs.uniform_blocks[block_index].uniforms[uniform_index].name = &char(name.str)
desc.vs.uniform_blocks[block_index].uniforms[uniform_index].type = typ
desc.vs.uniform_blocks[block_index].uniforms[uniform_index].array_count = array_count
return desc
}
pub fn (mut desc C.sg_shader_desc) set_frag_uniform(block_index int, uniform_index int, name string, typ UniformType,
array_count int) &ShaderDesc {
desc.fs.uniform_blocks[block_index].uniforms[uniform_index].name = &char(name.str)
desc.fs.uniform_blocks[block_index].uniforms[uniform_index].type = typ
desc.fs.uniform_blocks[block_index].uniforms[uniform_index].array_count = array_count
return desc
}
pub fn (desc &ShaderDesc) make_shader() Shader {
return C.sg_make_shader(desc)
}
pub struct C.sg_shader_attr_desc {
pub mut:
name &char // GLSL vertex attribute name (only required for GLES2)
sem_name &char // HLSL semantic name
sem_index int // HLSL semantic index
}
pub type ShaderAttrDesc = C.sg_shader_attr_desc
pub struct C.sg_shader_stage_desc {
pub mut:
source &char
bytecode Range
entry &char
d3d11_target &char
uniform_blocks [4]ShaderUniformBlockDesc
storage_buffers [8]ShaderStorageBufferDesc
images [12]ShaderImageDesc
samplers [8]ShaderSamplerDesc
image_sampler_pairs [12]ShaderImageSamplerPairDesc
}
pub type ShaderStageDesc = C.sg_shader_stage_desc
pub fn (mut desc ShaderStageDesc) set_image(index int, name string) ShaderStageDesc {
// desc.images[index].name = &char(name.str)
desc.images[index].image_type = ._2d
return *desc
}
pub struct C.sg_shader_uniform_block_desc {
pub mut:
size usize
layout UniformLayout
uniforms [16]ShaderUniformDesc
}
pub type ShaderUniformBlockDesc = C.sg_shader_uniform_block_desc
pub struct C.sg_shader_uniform_desc {
pub mut:
name &char
type UniformType
array_count int
}
pub type ShaderUniformDesc = C.sg_shader_uniform_desc
pub struct C.sg_shader_image_desc {
pub mut:
used bool
multisampled bool
// name &char
image_type ImageType
sample_type ImageSampleType
}
pub type ShaderImageDesc = C.sg_shader_image_desc
pub struct C.sg_shader_storage_buffer_desc {
pub mut:
used bool
readonly bool
}
pub type ShaderStorageBufferDesc = C.sg_shader_storage_buffer_desc
pub struct C.sg_shader_sampler_desc {
pub mut:
used bool
sampler_type SamplerType
}
pub type ShaderSamplerDesc = C.sg_shader_sampler_desc
pub struct C.sg_shader_image_sampler_pair_desc {
pub mut:
used bool
image_slot int
sampler_slot int
glsl_name &char
}
pub type ShaderImageSamplerPairDesc = C.sg_shader_image_sampler_pair_desc
pub struct C.sg_shader_info {
pub:
slot SlotInfo
}
pub type ShaderInfo = C.sg_shader_info
pub struct C.sg_range {
pub mut:
ptr voidptr
size usize
}
pub type Range = C.sg_range
pub struct C.sg_color {
pub mut:
r f32
g f32
b f32
a f32
}
pub type Color = C.sg_color
pub struct C.sg_shader {
pub:
id u32
}
pub type Shader = C.sg_shader
pub fn (mut s Shader) free() {
C.sg_destroy_shader(*s)
}
@[typedef]
pub struct C.sg_frame_stats_gl {
num_bind_buffer u32
num_active_texture u32
num_bind_texture u32
num_bind_sampler u32
num_use_program u32
num_render_state u32
num_vertex_attrib_pointer u32
num_vertex_attrib_divisor u32
num_enable_vertex_attrib_array u32
num_disable_vertex_attrib_array u32
num_uniform u32
}
pub type FrameStatsGL = C.sg_frame_stats_gl
@[typedef]
pub struct C.sg_frame_stats_d3d11_pass {
num_om_set_render_targets u32
num_clear_render_target_view u32
num_clear_depth_stencil_view u32
num_resolve_subresource u32
}
pub type FrameStatsD3D11Pass = C.sg_frame_stats_d3d11_pass
@[typedef]
pub struct C.sg_frame_stats_d3d11_pipeline {
num_rs_set_state u32
num_om_set_depth_stencil_state u32
num_om_set_blend_state u32
num_ia_set_primitive_topology u32
num_ia_set_input_layout u32
num_vs_set_shader u32
num_vs_set_constant_buffers u32
num_ps_set_shader u32
num_ps_set_constant_buffers u32
}
pub type FrameStatsD3D11Pipeline = C.sg_frame_stats_d3d11_pipeline
@[typedef]
pub struct C.sg_frame_stats_d3d11_bindings {
num_ia_set_vertex_buffers u32
num_ia_set_index_buffer u32
num_vs_set_shader_resources u32
num_ps_set_shader_resources u32
num_vs_set_samplers u32
num_ps_set_samplers u32
}
pub type FrameStatsD3D11Bindings = C.sg_frame_stats_d3d11_bindings
@[typedef]
pub struct C.sg_frame_stats_d3d11_uniforms {
num_update_subresource u32
}
pub type FrameStatsD3D11Uniforms = C.sg_frame_stats_d3d11_uniforms
@[typedef]
pub struct C.sg_frame_stats_d3d11_draw {
num_draw_indexed_instanced u32
num_draw_indexed u32
num_draw_instanced u32
num_draw u32
}
pub type FrameStatsD3D11Draw = C.sg_frame_stats_d3d11_draw
@[typedef]
pub struct C.sg_frame_stats_d3d11 {
pass FrameStatsD3D11Pass
pipeline FrameStatsD3D11Pipeline
bindings FrameStatsD3D11Bindings
uniforms FrameStatsD3D11Uniforms
draw FrameStatsD3D11Draw
num_map u32
num_unmap u32
}
pub type FrameStatsD3D11 = C.sg_frame_stats_d3d11
@[typedef]
pub struct C.sg_frame_stats_metal_idpool {
num_added u32
num_released u32
num_garbage_collected u32
}
pub type FrameStatsMetalIdpool = C.sg_frame_stats_metal_idpool
@[typedef]
pub struct C.sg_frame_stats_metal_pipeline {
num_set_blend_color u32
num_set_cull_mode u32
num_set_front_facing_winding u32
num_set_stencil_reference_value u32
num_set_depth_bias u32
num_set_render_pipeline_state u32
num_set_depth_stencil_state u32
}
pub type FrameStatsMetalPipeline = C.sg_frame_stats_metal_pipeline
@[typedef]
pub struct C.sg_frame_stats_metal_bindings {
num_set_vertex_buffer u32
num_set_vertex_texture u32
num_set_vertex_sampler_state u32
num_set_fragment_buffer u32
num_set_fragment_texture u32
num_set_fragment_sampler_state u32
}
pub type FrameStatsMetalBindings = C.sg_frame_stats_metal_bindings
@[typedef]
pub struct C.sg_frame_stats_metal_uniforms {
num_set_vertex_buffer_offset u32
num_set_fragment_buffer_offset u32
}
pub type FrameStatsMetalUniforms = C.sg_frame_stats_metal_uniforms
@[typedef]
pub struct C.sg_frame_stats_metal {
idpool FrameStatsMetalIdpool
pipeline FrameStatsMetalPipeline
bindings FrameStatsMetalBindings
uniforms FrameStatsMetalUniforms
}
pub type FrameStatsMetal = C.sg_frame_stats_metal
@[typedef]
pub struct C.sg_frame_stats_wgpu_uniforms {
num_set_bindgroup u32
size_write_buffer u32
}
pub type FrameStatsWGPUUniforms = C.sg_frame_stats_wgpu_uniforms
@[typedef]
pub struct C.sg_frame_stats_wgpu_bindings {
num_set_vertex_buffer u32
num_skip_redundant_vertex_buffer u32
num_set_index_buffer u32
num_skip_redundant_index_buffer u32
num_create_bindgroup u32
num_discard_bindgroup u32
num_set_bindgroup u32
num_skip_redundant_bindgroup u32
num_bindgroup_cache_hits u32
num_bindgroup_cache_misses u32
num_bindgroup_cache_collisions u32
num_bindgroup_cache_hash_vs_key_mismatch u32
}
pub type FrameStatsWGPUBindings = C.sg_frame_stats_wgpu_bindings
@[typedef]
pub struct C.sg_frame_stats_wgpu {
uniforms FrameStatsWGPUUniforms
bindings FrameStatsWGPUBindings
}
pub type FrameStatsWGPU = C.sg_frame_stats_wgpu
@[typedef]
pub struct C.sg_frame_stats {
frame_index u32 // current frame counter, starts at 0
num_passes u32
num_apply_viewport u32
num_apply_scissor_rect u32
num_apply_pipeline u32
num_apply_bindings u32
num_apply_uniforms u32
num_draw u32
num_update_buffer u32
num_append_buffer u32
num_update_image u32
size_apply_uniforms u32
size_update_buffer u32
size_append_buffer u32
size_update_image u32
gl FrameStatsGL
d3d11 FrameStatsD3D11
metal FrameStatsMetal
wgpu FrameStatsWGPU
}
pub type FrameStats = C.sg_frame_stats
pub struct C.sg_pass_action {
pub mut:
colors [4]ColorAttachmentAction
depth DepthAttachmentAction
stencil StencilAttachmentAction
}
pub type PassAction = C.sg_pass_action
@[typedef]
pub struct C.sg_metal_swapchain {
pub mut:
current_drawable voidptr
depth_stencil_texture voidptr // MTLTexture
msaa_color_texture voidptr // MTLTexture
}
pub type MetalSwapchain = C.sg_metal_swapchain
@[typedef]
pub struct C.sg_d3d11_swapchain {
pub mut:
render_view voidptr // ID3D11RenderTargetView
resolve_view voidptr // ID3D11RenderTargetView
depth_stencil_view voidptr // ID3D11DepthStencilView
}
pub type D3d11Swapchain = C.sg_d3d11_swapchain
@[typedef]
pub struct C.sg_wgpu_swapchain {
pub mut:
render_view voidptr // WGPUTextureView
resolve_view voidptr // WGPUTextureView
depth_stencil_view voidptr // WGPUTextureView
}
pub type WgpuSwapchain = C.sg_wgpu_swapchain
@[typedef]
pub struct C.sg_gl_swapchain {
pub mut:
framebuffer u32
}
pub type GlSwapchain = C.sg_gl_swapchain
@[typedef]
pub struct C.sg_swapchain {
pub mut:
width int
height int
sample_count int
color_format PixelFormat
depth_format PixelFormat
metal MetalSwapchain
d3d11 D3d11Swapchain
wgpu WgpuSwapchain
gl GlSwapchain
}
pub type Swapchain = C.sg_swapchain
@[typedef]
pub struct C.sg_pass {
pub mut:
_start_canary u32
action PassAction
attachments Attachments
swapchain Swapchain
label &char = unsafe { nil }
_end_canary u32
}
pub type Pass = C.sg_pass
pub struct C.sg_buffer_desc {
pub mut:
size usize
type BufferType
usage Usage
data Range
label &char
// backend-specific resources
gl_buffers [2]u32
mtl_buffers [2]voidptr
d3d11_buffer voidptr
wgpu_buffer voidptr
}
pub type BufferDesc = C.sg_buffer_desc
pub struct C.sg_slot_info {
state ResourceState
res_id u32
ctx_id u32
}
pub type SlotInfo = C.sg_slot_info
pub struct C.sg_buffer_info {
pub:
slot SlotInfo
update_frame_index u32
append_frame_index u32
append_pos int
append_overflow bool
num_slots int
active_slot int
}
pub type BufferInfo = C.sg_buffer_info
pub struct C.sg_buffer {
id u32
}
pub type Buffer = C.sg_buffer
pub fn (mut b Buffer) free() {
C.sg_destroy_buffer(*b)
}
pub struct C.sg_image_desc {
pub mut:
type ImageType
render_target bool
width int
height int
num_slices int
num_mipmaps int
usage Usage
pixel_format PixelFormat
sample_count int
// min_filter Filter
// mag_filter Filter
// wrap_u Wrap
// wrap_v Wrap
// wrap_w Wrap
// border_color BorderColor
// max_anisotropy u32
// min_lod f32
// max_lod f32
data ImageData
label &char
// backend-specific resources
gl_textures [2]u32
gl_texture_target u32
mtl_textures [2]voidptr
d3d11_texture voidptr
d3d11_shader_resource_view voidptr
wgpu_texture voidptr
}
pub type ImageDesc = C.sg_image_desc
pub struct C.sg_sampler_desc {
min_filter Filter
mag_filter Filter
mipmap_filter Filter
wrap_u Wrap
wrap_v Wrap
wrap_w Wrap
min_lod f32
max_lod f32
border_color BorderColor
compare CompareFunc
max_anisotropy u32
label &char
// backend-specific resources
gl_sampler u32
mtl_sampler voidptr
d3d11_sampler voidptr
wgpu_sampler voidptr
}
pub type SamplerDesc = C.sg_sampler_desc
pub struct C.sg_image_info {
pub mut:
slot SlotInfo // resource pool slot info
upd_frame_index u32 // frame index of last sg_update_image()
num_slots int // number of renaming-slots for dynamically updated images
active_slot int // currently active write-slot for dynamically updated images
}
pub type ImageInfo = C.sg_image_info
pub struct C.sg_image {
pub mut:
id u32
}
pub type Image = C.sg_image
pub fn (mut i Image) free() {
C.sg_destroy_image(*i)
}
pub struct C.sg_sampler {
pub mut:
id u32
}
pub type Sampler = C.sg_sampler
pub const sg_cubeface_num = 6
pub const sg_max_mipmaps = 16
pub struct C.sg_image_data {
pub mut:
subimage [sg_cubeface_num][sg_max_mipmaps]Range
}
pub type ImageData = C.sg_image_data
pub struct C.sg_features {
pub:
origin_top_left bool // framebuffer and texture origin is in top left corner
image_clamp_to_border bool // border color and clamp-to-border UV-wrap mode is supported
mrt_independent_blend_state bool // multiple-render-target rendering can use per-render-target blend state
mrt_independent_write_mask bool // multiple-render-target rendering can use per-render-target color write masks
storage_buffer bool // storage buffers are supported
}
pub type Features = C.sg_features
pub struct C.sg_limits {
pub:
max_image_size_2d int // max width/height of SG_IMAGETYPE_2D images
max_image_size_cube int // max width/height of SG_IMAGETYPE_CUBE images
max_image_size_3d int // max width/height/depth of SG_IMAGETYPE_3D images
max_image_size_array int // max width/height pf SG_IMAGETYPE_ARRAY images
max_image_array_layers int // max number of layers in SG_IMAGETYPE_ARRAY images
max_vertex_attrs int // <= SG_MAX_VERTEX_ATTRIBUTES (only on some GLES2 impls)
gl_max_vertex_uniform_components int // <= GL_MAX_VERTEX_UNIFORM_COMPONENTS (only on GL backends)
gl_max_combined_texture_image_units int // <= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (only on GL backends)
}
pub type Limits = C.sg_limits
pub struct C.sg_vertex_layout_state {
pub mut:
buffers [8]VertexBufferLayoutState
attrs [16]VertexAttrDesc
}
pub type VertexLayoutState = C.sg_vertex_layout_state
pub struct C.sg_vertex_buffer_layout_state {
pub mut:
stride int
step_func VertexStep
step_rate int
}
pub type VertexBufferLayoutState = C.sg_vertex_buffer_layout_state
pub struct C.sg_vertex_attr_state {
pub mut:
buffer_index int
offset int
format VertexFormat
}
pub type VertexAttrDesc = C.sg_vertex_attr_state
pub struct C.sg_stencil_state {
enabled bool
front StencilFaceState
back StencilFaceState
read_mask u8
write_mask u8
ref u8
}
pub type StencilState = C.sg_stencil_state
pub struct C.sg_depth_state {
pixel_format PixelFormat
compare CompareFunc
write_enabled bool
bias f32
bias_slope_scale f32
bias_clamp f32
}
pub type DepthState = C.sg_depth_state
pub struct C.sg_stencil_face_state {
compare CompareFunc
fail_op StencilOp
depth_fail_op StencilOp
pass_op StencilOp
}
pub type StencilFaceState = C.sg_stencil_face_state
pub struct C.sg_blend_state {
pub mut:
enabled bool
src_factor_rgb BlendFactor
dst_factor_rgb BlendFactor
op_rgb BlendOp
src_factor_alpha BlendFactor
dst_factor_alpha BlendFactor
op_alpha BlendOp
}
pub type BlendState = C.sg_blend_state
pub struct C.sg_color_attachment_action {
pub mut:
load_action LoadAction
store_action StoreAction
clear_value Color
}
pub type ColorAttachmentAction = C.sg_color_attachment_action
/*
pub fn (mut action C.sg_color_attachment_action) set_color_values(r, g, b, a f32) {
action.val[0] = r
action.val[1] = g
action.val[2] = b
action.val[3] = a
}
*/
pub struct C.sg_depth_attachment_action {
pub mut:
load_action LoadAction
store_action StoreAction
clear_value f32
}
pub type DepthAttachmentAction = C.sg_depth_attachment_action
pub struct C.sg_stencil_attachment_action {
pub mut:
load_action LoadAction
store_action StoreAction
clear_value u8
}
pub type StencilAttachmentAction = C.sg_stencil_attachment_action
pub struct C.sg_pixelformat_info {
pub:
sample bool // pixel format can be sampled in shaders
filter bool // pixel format can be sampled with filtering
render bool // pixel format can be used as render target
blend bool // alpha-blending is supported
msaa bool // pixel format can be used as MSAA render target
depth bool // pixel format is a depth format
}
pub type PixelFormatInfo = C.sg_pixelformat_info
@[typedef]
pub struct C.sg_environment_defaults {
pub mut:
color_format PixelFormat
depth_format PixelFormat
sample_count int
}
pub type EnvironmentDefaults = C.sg_environment_defaults
@[typedef]
pub struct C.sg_metal_environment {
pub mut:
device voidptr
}
pub type MetalEnvironment = C.sg_metal_environment
@[typedef]
pub struct C.sg_d3d11_environment {
pub mut:
device voidptr
device_context voidptr
}
pub type D3d11Environment = C.sg_d3d11_environment
@[typedef]
pub struct C.sg_wgpu_environment {
pub mut:
device voidptr
}
pub type WgpuEnvironment = C.sg_wgpu_environment
@[typedef]
pub struct C.sg_environment {
pub mut:
defaults EnvironmentDefaults
metal MetalEnvironment
d3d11 D3d11Environment
wgpu WgpuEnvironment
}
pub type Environment = C.sg_environment
// C.sg_commit_listener is used with sg_add_commit_listener, to add a callback,
// which will be called in sg_commit(). This is useful for libraries building
// on top of sokol-gfx to be notified about when a frame ends (instead of having
// to guess, or add a manual 'new-frame' function).
pub struct C.sg_commit_listener {
pub:
func fn (user_data voidptr)
user_data voidptr
}
pub type CommitListener = C.sg_commit_listener
pub struct C.sg_trace_hooks {}
// pub struct C.sg_resource_state {} enum
pub struct C.sg_sampler_info {}
+29
View File
@@ -0,0 +1,29 @@
// vtest build: !msvc
// vtest flaky: true
// vtest retry: 1
module gfx
import os
fn assert_program_panics(source string, expected string) {
source_path := os.join_path(os.temp_dir(),
'sokol_gfx_make_image_requires_setup_${os.getpid()}.v')
os.write_file(source_path, source) or { panic(err) }
defer {
os.rm(source_path) or {}
}
res := os.execute('${os.quoted_path(@VEXE)} run ${os.quoted_path(source_path)}')
assert res.exit_code != 0, 'expected the test program to fail'
assert res.output.contains(expected), 'expected `${expected}` in `${res.output}`'
}
fn test_make_image_requires_setup() {
assert_program_panics('import sokol.gfx
fn main() {
mut desc := gfx.ImageDesc{}
_ = gfx.make_image(&desc)
}
',
'sokol.gfx is not initialized; call gfx.setup(...) before gfx.make_image(...)')
}
+19
View File
@@ -0,0 +1,19 @@
module gfx
// create_clear_pass_action returns a *clearing* `PassAction` that clears the `Pass`
// with the color defined by the color components `r`ed,`g`reen, `b`lue and `a`lpha.
pub fn create_clear_pass_action(r f32, g f32, b f32, a f32) PassAction {
mut color_action := ColorAttachmentAction{
load_action: .clear
clear_value: Color{
r: r
g: g
b: b
a: a
}
}
// color_action.set_color_values(r, g, b, a)
mut pass_action := PassAction{}
pass_action.colors[0] = color_action
return pass_action
}
+40
View File
@@ -0,0 +1,40 @@
module memory
pub type FnAllocatorAlloc = fn (size usize, user_data voidptr) voidptr
pub type FnAllocatorFree = fn (ptr voidptr, user_data voidptr)
pub type FnLogCb = fn (const_tag &char, log_level u32, log_item_id u32, const_message_or_null &char, line_nr u32, const_filename_or_null &char, user_data voidptr)
// salloc - used in the allocator structs, that the SOKOL libraries use, for allocating new memory blocks
pub fn salloc(size usize, user_data voidptr) voidptr {
res := unsafe { malloc(int(size)) }
$if trace_sokol_memory ? {
eprintln('sokol.memory.salloc | user_data: ${user_data:x} | size: ${size:10} | res: ${res:x}')
}
$if trace_sokol_memory_salloc_backtrace ? {
print_backtrace()
}
return res
}
// sfree - used in the allocator structs, that the SOKOL libraries use, for freeing memory
pub fn sfree(ptr voidptr, user_data voidptr) {
$if trace_sokol_memory ? {
eprintln(' sokol.memory.sfree | user_data: ${user_data:x} | ptr: ${ptr:x}')
}
$if trace_sokol_memory_sfree_backtrace ? {
print_backtrace()
}
unsafe { free(ptr) }
}
fn C.SOKOL_LOG(const_message &char)
pub fn slog(const_tag &char, log_level u32, log_item_id u32, const_message_or_null &char, line_nr u32,
const_filename_or_null &char, user_data voidptr) {
C.fprintf(C.stderr,
c'sokol.memory.slog | user_data: %p, const_tag: %s, level: %d, item_id: %d, fname: %s, line: %d, message: %s\n',
user_data, const_tag, log_level, log_item_id, const_filename_or_null, line_nr,
const_message_or_null)
}
+197
View File
@@ -0,0 +1,197 @@
module sapp
pub enum EventType {
invalid
key_down
key_up
char
mouse_down
mouse_up
mouse_scroll
mouse_move
mouse_enter
mouse_leave
touches_began
touches_moved
touches_ended
touches_cancelled
resized
iconified
restored
focused
unfocused
suspended
resumed
quit_requested
clipboard_pasted
files_dropped
num
}
pub enum MouseButton {
invalid = -1
left = 0
right = 1
middle = 2
}
pub enum MouseCursor {
default = C.SAPP_MOUSECURSOR_DEFAULT
arrow = C.SAPP_MOUSECURSOR_ARROW
ibeam = C.SAPP_MOUSECURSOR_IBEAM
crosshair = C.SAPP_MOUSECURSOR_CROSSHAIR
pointing_hand = C.SAPP_MOUSECURSOR_POINTING_HAND
resize_ew = C.SAPP_MOUSECURSOR_RESIZE_EW
resize_ns = C.SAPP_MOUSECURSOR_RESIZE_NS
resize_nwse = C.SAPP_MOUSECURSOR_RESIZE_NWSE
resize_nesw = C.SAPP_MOUSECURSOR_RESIZE_NESW
resize_all = C.SAPP_MOUSECURSOR_RESIZE_ALL
not_allowed = C.SAPP_MOUSECURSOR_NOT_ALLOWED
}
pub enum Modifier {
shift = 1 //(1<<0)
ctrl = 2 //(1<<1)
alt = 4 //(1<<2)
super = 8 //(1<<3)
lmb = 0x100
rmb = 0x200
mmb = 0x400
}
pub enum KeyCode {
invalid = 0
space = 32
apostrophe = 39 //'
comma = 44 //,
minus = 45 //-
period = 46 //.
slash = 47 ///
_0 = 48
_1 = 49
_2 = 50
_3 = 51
_4 = 52
_5 = 53
_6 = 54
_7 = 55
_8 = 56
_9 = 57
semicolon = 59 //;
equal = 61 //=
a = 65
b = 66
c = 67
d = 68
e = 69
f = 70
g = 71
h = 72
i = 73
j = 74
k = 75
l = 76
m = 77
n = 78
o = 79
p = 80
q = 81
r = 82
s = 83
t = 84
u = 85
v = 86
w = 87
x = 88
y = 89
z = 90
left_bracket = 91 //[
backslash = 92 //\
right_bracket = 93 //]
grave_accent = 96 //`
world_1 = 161 // non-us #1
world_2 = 162 // non-us #2
escape = 256
enter = 257
tab = 258
backspace = 259
insert = 260
delete = 261
right = 262
left = 263
down = 264
up = 265
page_up = 266
page_down = 267
home = 268
end = 269
caps_lock = 280
scroll_lock = 281
num_lock = 282
print_screen = 283
pause = 284
f1 = 290
f2 = 291
f3 = 292
f4 = 293
f5 = 294
f6 = 295
f7 = 296
f8 = 297
f9 = 298
f10 = 299
f11 = 300
f12 = 301
f13 = 302
f14 = 303
f15 = 304
f16 = 305
f17 = 306
f18 = 307
f19 = 308
f20 = 309
f21 = 310
f22 = 311
f23 = 312
f24 = 313
f25 = 314
kp_0 = 320
kp_1 = 321
kp_2 = 322
kp_3 = 323
kp_4 = 324
kp_5 = 325
kp_6 = 326
kp_7 = 327
kp_8 = 328
kp_9 = 329
kp_decimal = 330
kp_divide = 331
kp_multiply = 332
kp_subtract = 333
kp_add = 334
kp_enter = 335
kp_equal = 336
left_shift = 340
left_control = 341
left_alt = 342
left_super = 343
right_shift = 344
right_control = 345
right_alt = 346
right_super = 347
menu = 348
}
// TouchToolType is an Android specific 'tool type' enum for touch events.
// This lets the application check what type of input device was used for touch events.
// NOTE: the values must remain in sync with the corresponding Android SDK type, so don't change those.
// See https://developer.android.com/reference/android/view/MotionEvent#TOOL_TYPE_UNKNOWN
pub enum TouchToolType {
unknown
finger
stylus
mouse
eraser
palm
}
+316
View File
@@ -0,0 +1,316 @@
@[has_globals]
module sapp
import sokol.gfx
import sokol.memory
// Android needs a global reference to `g_desc`
__global g_desc C.sapp_desc
pub fn create_desc() gfx.Desc {
return gfx.Desc{
environment: glue_environment()
image_pool_size: 1000
}
}
// create_default_pass creates a default `gfx.Pass` compatible with `sapp` and `sokol.gfx.begin_pass/1`.
pub fn create_default_pass(action gfx.PassAction) gfx.Pass {
return gfx.Pass{
action: action
swapchain: glue_swapchain()
}
}
// sapp_to_gfx_pixelformat converts an sapp_pixel_format int to a gfx.PixelFormat.
// The sapp and gfx pixel format enums have different integer values, so a direct
// cast is incorrect.
fn sapp_to_gfx_pixelformat(sapp_fmt int) gfx.PixelFormat {
// sapp_pixel_format: _DEFAULT=0, NONE=1, RGBA8=2, SRGB8A8=3, BGRA8=4, SBGRA8=5, DEPTH=6, DEPTH_STENCIL=7
return match sapp_fmt {
1 { gfx.PixelFormat.none }
2 { gfx.PixelFormat.rgba8 }
3 { gfx.PixelFormat.srgb8a8 }
4 { gfx.PixelFormat.bgra8 }
5 { gfx.PixelFormat.bgra8 } // sbgra8 has no gfx equivalent, use bgra8
6 { gfx.PixelFormat.depth }
7 { gfx.PixelFormat.depth_stencil }
else { gfx.PixelFormat.none }
}
}
// glue_environment returns a `gfx.Environment` compatible for use with `sapp` specific `gfx.Pass`es.
// The retuned `gfx.Environment` can be used when rendering via `sapp`.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
pub fn glue_environment() gfx.Environment {
sapp_env := C.sapp_get_environment()
mut env := gfx.Environment{}
unsafe { vmemset(&env, 0, int(sizeof(env))) }
env.defaults.color_format = sapp_to_gfx_pixelformat(sapp_env.defaults.color_format)
env.defaults.depth_format = sapp_to_gfx_pixelformat(sapp_env.defaults.depth_format)
env.defaults.sample_count = sapp_env.defaults.sample_count
$if macos && !darwin_sokol_glcore33 ? {
env.metal.device = sapp_env.metal.device
}
return env
}
// glue_swapchain returns a `gfx.Swapchain` compatible for use with `sapp` specific display/rendering `gfx.Pass`es.
// The retuned `gfx.Swapchain` can be used when rendering via `sapp`.
// See also: documentation at the top of thirdparty/sokol/sokol_gfx.h
pub fn glue_swapchain() gfx.Swapchain {
sapp_sc := C.sapp_get_swapchain()
mut swapchain := gfx.Swapchain{}
unsafe { vmemset(&swapchain, 0, int(sizeof(swapchain))) }
swapchain.width = sapp_sc.width
swapchain.height = sapp_sc.height
swapchain.sample_count = sapp_sc.sample_count
swapchain.color_format = sapp_to_gfx_pixelformat(sapp_sc.color_format)
swapchain.depth_format = sapp_to_gfx_pixelformat(sapp_sc.depth_format)
$if macos && !darwin_sokol_glcore33 ? {
swapchain.metal.current_drawable = sapp_sc.metal.current_drawable
swapchain.metal.depth_stencil_texture = sapp_sc.metal.depth_stencil_texture
swapchain.metal.msaa_color_texture = sapp_sc.metal.msaa_color_texture
} $else {
swapchain.gl.framebuffer = sapp_sc.gl.framebuffer
}
return swapchain
}
// returns true after sokol-app has been initialized
@[inline]
pub fn isvalid() bool {
return C.sapp_isvalid()
}
// returns the current framebuffer width in pixels
@[inline]
pub fn width() int {
return C.sapp_width()
}
// returns the current framebuffer height in pixels
@[inline]
pub fn height() int {
return C.sapp_height()
}
// color_format gets default framebuffer color pixel format
@[inline]
pub fn color_format() int {
return C.sapp_color_format()
}
// depth_format gets default framebuffer depth pixel format
@[inline]
pub fn depth_format() int {
return C.sapp_depth_format()
}
// sample_count gets default framebuffer sample count
@[inline]
pub fn sample_count() int {
return C.sapp_sample_count()
}
// returns true when high_dpi was requested and actually running in a high-dpi scenario
@[inline]
pub fn high_dpi() bool {
return C.sapp_high_dpi()
}
// returns the dpi scaling factor (window pixels to framebuffer pixels)
@[inline]
pub fn dpi_scale() f32 {
return C.sapp_dpi_scale()
}
// show or hide the mobile device onscreen keyboard
@[inline]
pub fn show_keyboard(visible bool) {
C.sapp_show_keyboard(visible)
}
// return true if the mobile device onscreen keyboard is currently shown
@[inline]
pub fn keyboard_shown() bool {
return C.sapp_keyboard_shown()
}
// show or hide the mouse cursor
@[inline]
pub fn show_mouse(visible bool) {
C.sapp_show_mouse(visible)
}
// set mouse cursor
@[inline]
pub fn set_mouse_cursor(cursor MouseCursor) {
C.sapp_set_mouse_cursor(cursor)
}
// show or hide the mouse cursor
@[inline]
pub fn mouse_shown() bool {
return C.sapp_mouse_shown()
}
@[inline]
pub fn lock_mouse(locked bool) {
C.sapp_lock_mouse(locked)
}
@[inline]
pub fn mouse_locked() bool {
return C.sapp_mouse_locked()
}
// return the userdata pointer optionally provided in sapp_desc
@[inline]
pub fn userdata() voidptr {
return C.sapp_userdata()
}
// return a copy of the sapp_desc structure
@[inline]
pub fn query_desc() Desc {
return C.sapp_query_desc()
}
// initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED)
@[inline]
pub fn request_quit() {
C.sapp_request_quit()
}
// cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received)
@[inline]
pub fn cancel_quit() {
C.sapp_cancel_quit()
}
// initiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUESTED)
@[inline]
pub fn quit() {
C.sapp_quit()
}
// call from inside event callback to consume the current event (don't forward to platform)
@[inline]
pub fn consume_event() {
C.sapp_consume_event()
}
// get the current frame counter (for comparison with sapp_event.frame_count)
@[inline]
pub fn frame_count() u64 {
return C.sapp_frame_count()
}
// get an averaged/smoothed frame duration in seconds
@[inline]
pub fn frame_duration() f64 {
return C.sapp_frame_duration()
}
// write string into clipboard
@[inline]
pub fn set_clipboard_string(str &u8) {
C.sapp_set_clipboard_string(&char(str))
}
// read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED)
@[inline]
pub fn get_clipboard_string() &char {
return &char(C.sapp_get_clipboard_string())
}
// special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub)
pub fn run(desc &Desc) {
if desc.allocator.alloc_fn == unsafe { nil } && desc.allocator.free_fn == unsafe { nil } {
unsafe {
desc.allocator.alloc_fn = memory.salloc
desc.allocator.free_fn = memory.sfree
desc.allocator.user_data = voidptr(0x10005a44)
}
}
if desc.logger.func == unsafe { nil } {
unsafe {
desc.logger.func = memory.slog
}
}
g_desc = *desc
C.sapp_run(desc)
}
// HTML5: enable or disable the hardwired "Leave Site?" dialog box
@[inline]
pub fn html5_ask_leave_site(ask bool) {
C.sapp_html5_ask_leave_site(ask)
}
// macOS: get ARC-bridged pointer to macOS NSWindow
@[inline]
pub fn macos_get_window() voidptr {
return voidptr(C.sapp_macos_get_window())
}
// iOS: get ARC-bridged pointer to iOS UIWindow
@[inline]
pub fn ios_get_window() voidptr {
return voidptr(C.sapp_ios_get_window())
}
// Win32: get the HWND window handle
@[inline]
pub fn win32_get_hwnd() voidptr {
return voidptr(C.sapp_win32_get_hwnd())
}
// GL: get framebuffer object
@[inline]
pub fn gl_get_framebuffer() u32 {
return C.sapp_gl_get_framebuffer()
}
// X11: get display handle
@[inline]
pub fn x11_get_display() voidptr {
return voidptr(C.sapp_x11_get_display())
}
// X11: get window handle
@[inline]
pub fn x11_get_window() voidptr {
return voidptr(C.sapp_x11_get_window())
}
// Android: get native activity handle
@[inline]
pub fn android_get_native_activity() voidptr {
return voidptr(C.sapp_android_get_native_activity())
}
// Toggle full screen
@[inline]
pub fn toggle_fullscreen() {
C.sapp_toggle_fullscreen()
}
// Check if full screen rendering
@[inline]
pub fn is_fullscreen() bool {
return C.sapp_is_fullscreen()
}
@[inline]
pub fn get_num_dropped_files() int {
return C.sapp_get_num_dropped_files()
}
@[inline]
pub fn get_dropped_file_path(index int) string {
unsafe {
return cstring_to_vstring(C.sapp_get_dropped_file_path(index))
}
}
@@ -0,0 +1,18 @@
module sapp
import sokol.memory
@[typedef]
pub struct C.sapp_allocator {
pub mut:
alloc_fn memory.FnAllocatorAlloc = unsafe { nil }
free_fn memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
@[typedef]
pub struct C.sapp_logger {
pub mut:
func memory.FnLogCb = unsafe { nil }
user_data voidptr
}
+211
View File
@@ -0,0 +1,211 @@
module sapp
// EGL initialization and teardown.
// Shared between Wayland and X11 backends.
fn sapp_egl_choose_config() EGLConfig {
samples := if g_sapp_state.desc.sample_count > 1 {
EGLint(g_sapp_state.desc.sample_count)
} else {
EGLint(0)
}
alpha_size := if g_sapp_state.desc.alpha { EGLint(8) } else { EGLint(0) }
sample_buffers := if g_sapp_state.desc.sample_count > 1 { EGLint(1) } else { EGLint(0) }
config_attrs := [
egl_surface_type,
egl_window_bit,
egl_renderable_type,
egl_opengl_bit,
egl_red_size,
EGLint(8),
egl_green_size,
EGLint(8),
egl_blue_size,
EGLint(8),
egl_alpha_size,
alpha_size,
egl_depth_size,
EGLint(24),
egl_stencil_size,
EGLint(8),
egl_sample_buffers,
sample_buffers,
egl_samples,
samples,
egl_none,
]!
mut egl_configs := unsafe { [32]EGLConfig{} }
mut config_count := EGLint(0)
if C.eglChooseConfig(g_sapp_state.egl.display, &config_attrs[0], &egl_configs[0], 32, &config_count) == 0
|| config_count == 0 {
eprintln('sokol_app: EGL: no configs found')
return egl_configs[0]
}
mut config := egl_configs[0]
for i in 0 .. int(config_count) {
c := egl_configs[i]
mut r := EGLint(0)
mut g := EGLint(0)
mut b := EGLint(0)
mut a := EGLint(0)
mut d := EGLint(0)
mut s := EGLint(0)
mut n := EGLint(0)
if C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_red_size, &r) != 0
&& C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_green_size, &g) != 0
&& C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_blue_size, &b) != 0
&& C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_alpha_size, &a) != 0
&& C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_depth_size, &d) != 0
&& C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_stencil_size, &s) != 0
&& C.eglGetConfigAttrib(g_sapp_state.egl.display, c, egl_samples, &n) != 0 && r == 8
&& g == 8 && b == 8 && a == alpha_size && d == 24 && s == 8 && n == samples {
config = c
break
}
}
return config
}
fn sapp_egl_create_context(config EGLConfig) {
gl_major := if g_sapp_state.desc.gl.major_version != 0 {
g_sapp_state.desc.gl.major_version
} else {
4
}
gl_minor := if g_sapp_state.desc.gl.minor_version != 0 {
g_sapp_state.desc.gl.minor_version
} else {
1
}
ctx_attrs := [
egl_context_major_version,
EGLint(gl_major),
egl_context_minor_version,
EGLint(gl_minor),
egl_context_opengl_profile_mask,
egl_context_opengl_core_profile_bit,
egl_none,
]!
g_sapp_state.egl.context = C.eglCreateContext(g_sapp_state.egl.display, config, unsafe { nil },
&ctx_attrs[0])
if g_sapp_state.egl.context == unsafe { nil } {
eprintln('sokol_app: EGL: failed to create context')
}
}
fn sapp_egl_create_surface(native_window voidptr) {
config := sapp_egl_choose_config()
g_sapp_state.egl.config = config
g_sapp_state.egl.surface = C.eglCreateWindowSurface(g_sapp_state.egl.display, config,
native_window, unsafe { nil })
if g_sapp_state.egl.surface == unsafe { nil } {
eprintln('sokol_app: EGL: failed to create window surface')
}
if g_sapp_state.egl.context == unsafe { nil } {
sapp_egl_create_context(config)
}
}
fn sapp_egl_make_current() {
if C.eglMakeCurrent(g_sapp_state.egl.display, g_sapp_state.egl.surface,
g_sapp_state.egl.surface, g_sapp_state.egl.context) == 0 {
eprintln('sokol_app: EGL: eglMakeCurrent failed')
}
mut fb := i32(0)
C.glGetIntegerv(gl_framebuffer_binding, &fb)
g_sapp_state.gl.framebuffer = u32(fb)
C.eglSwapInterval(g_sapp_state.egl.display, EGLint(g_sapp_state.swap_interval))
}
$if sokol_wayland ? {
fn sapp_egl_init_wayland() {
if C.eglBindAPI(egl_opengl_api) == 0 {
eprintln('sokol_app: EGL: failed to bind OpenGL API')
}
g_sapp_state.egl.display = C.eglGetDisplay(voidptr(g_sapp_state.wl.display))
if g_sapp_state.egl.display == unsafe { nil } {
eprintln('sokol_app: EGL: failed to get display')
}
mut major := EGLint(0)
mut minor := EGLint(0)
if C.eglInitialize(g_sapp_state.egl.display, &major, &minor) == 0 {
eprintln('sokol_app: EGL: failed to initialize')
}
g_sapp_state.gl.major = int(major)
g_sapp_state.gl.minor = int(minor)
}
}
fn sapp_egl_init_x11() {
if C.eglBindAPI(egl_opengl_api) == 0 {
eprintln('sokol_app: EGL: failed to bind OpenGL API')
}
g_sapp_state.egl.display = C.eglGetDisplay(voidptr(g_sapp_state.x11.display))
if g_sapp_state.egl.display == unsafe { nil } {
eprintln('sokol_app: EGL: failed to get display')
}
mut major := EGLint(0)
mut minor := EGLint(0)
if C.eglInitialize(g_sapp_state.egl.display, &major, &minor) == 0 {
eprintln('sokol_app: EGL: failed to initialize')
}
g_sapp_state.gl.major = int(major)
g_sapp_state.gl.minor = int(minor)
config := sapp_egl_choose_config()
mut visual_id := EGLint(0)
if C.eglGetConfigAttrib(g_sapp_state.egl.display, config, EGLint(0x302E), &visual_id) == 0 {
eprintln('sokol_app: EGL: failed to get native visual ID')
}
mut visual_info_template := C.XVisualInfo{}
visual_info_template.visualid = VisualID(visual_id)
mut num_visuals := 0
visual_info := C.XGetVisualInfo(g_sapp_state.x11.display, visual_id_mask,
&visual_info_template, &num_visuals)
if visual_info == unsafe { nil } {
eprintln('sokol_app: EGL: failed to get visual info')
}
x11_create_window(visual_info.visual, visual_info.depth)
C.XFree(visual_info)
g_sapp_state.egl.surface = C.eglCreateWindowSurface(g_sapp_state.egl.display, config,
EGLNativeWindowType(g_sapp_state.x11.window), unsafe { nil })
if g_sapp_state.egl.surface == unsafe { nil } {
eprintln('sokol_app: EGL: failed to create window surface')
}
sapp_egl_create_context(config)
sapp_egl_make_current()
}
fn sapp_egl_destroy() {
if g_sapp_state.egl.display != unsafe { nil } {
C.eglMakeCurrent(g_sapp_state.egl.display, unsafe { nil }, unsafe { nil }, unsafe { nil })
if g_sapp_state.egl.context != unsafe { nil } {
C.eglDestroyContext(g_sapp_state.egl.display, g_sapp_state.egl.context)
g_sapp_state.egl.context = unsafe { nil }
}
if g_sapp_state.egl.surface != unsafe { nil } {
C.eglDestroySurface(g_sapp_state.egl.display, g_sapp_state.egl.surface)
g_sapp_state.egl.surface = unsafe { nil }
}
C.eglTerminate(g_sapp_state.egl.display)
g_sapp_state.egl.display = unsafe { nil }
}
}
+164
View File
@@ -0,0 +1,164 @@
module sapp
#define SOKOL_VALIDATE_NON_FATAL 1
// returns true after sokol-app has been initialized
fn C.sapp_isvalid() bool
// returns the current framebuffer width in pixels
fn C.sapp_width() i32
fn C.sapp_widthf() f32
// returns the current framebuffer height in pixels
fn C.sapp_height() i32
fn C.sapp_heightf() f32
// get default framebuffer color pixel format
fn C.sapp_color_format() i32
// get default framebuffer depth pixel format
fn C.sapp_depth_format() i32
// get default framebuffer sample count
fn C.sapp_sample_count() i32
// returns true when high_dpi was requested and actually running in a high-dpi scenario
fn C.sapp_high_dpi() bool
// returns the dpi scaling factor (window pixels to framebuffer pixels)
fn C.sapp_dpi_scale() f32
// show or hide the mobile device onscreen keyboard
fn C.sapp_show_keyboard(visible bool)
// return true if the mobile device onscreen keyboard is currently shown
fn C.sapp_keyboard_shown() bool
// Check if full screen rendering
fn C.sapp_is_fullscreen() bool
// Toggle full screen
fn C.sapp_toggle_fullscreen()
// show or hide the mouse cursor
fn C.sapp_show_mouse(visible bool)
// return true if the mouse cursor is shown
fn C.sapp_mouse_shown() bool
// set mouse cursor
fn C.sapp_set_mouse_cursor(cursor MouseCursor)
// get current mouse cursor type
fn C.sapp_get_mouse_cursor() MouseCursor
// bind a custom mouse cursor image to a cursor type, returns the cursor type
fn C.sapp_bind_mouse_cursor_image(cursor MouseCursor, desc &ImageDesc) MouseCursor
// unbind a custom mouse cursor image
fn C.sapp_unbind_mouse_cursor_image(cursor MouseCursor)
// lock or unlock the mouse cursor
fn C.sapp_lock_mouse(locked bool)
// return true if the mouse cursor is locked
fn C.sapp_mouse_locked() bool
// return the userdata pointer optionally provided in sapp_desc
fn C.sapp_userdata() voidptr
// return a copy of the sapp_desc structure
fn C.sapp_query_desc() Desc
// initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED)
fn C.sapp_request_quit()
// cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received)
fn C.sapp_cancel_quit()
// intiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUESTED)
fn C.sapp_quit()
// call from inside event callback to consume the current event (don't forward to platform)
fn C.sapp_consume_event()
// get the current frame counter (for comparison with sapp_event.frame_count)
fn C.sapp_frame_count() u64
// get an averaged/smoothed frame duration in seconds
fn C.sapp_frame_duration() f64
// write string into clipboard
fn C.sapp_set_clipboard_string(const_str &char)
// read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED)
fn C.sapp_get_clipboard_string() &char
// set the window title (only on desktop platforms)
fn C.sapp_set_window_title(&char)
// set the window icon (only on Windows and Linux)
fn C.sapp_set_icon(const_icon_desc &IconDesc)
// Get number of dropped files
fn C.sapp_get_num_dropped_files() i32
// Get the file path of the dropped file
fn C.sapp_get_dropped_file_path(i32) &char
// special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub)
fn C.sapp_run(const_desc &Desc) i32
// get runtime environment information
fn C.sapp_get_environment() Environment
// get current frame's swapchain information (call once per frame!)
fn C.sapp_get_swapchain() Swapchain
// EGL: get EGLDisplay object
fn C.sapp_egl_get_display() voidptr
// EGL: get EGLContext object
fn C.sapp_egl_get_context() voidptr
// HTML5: enable or disable the hardwired "Leave Site?" dialog box
fn C.sapp_html5_ask_leave_site(ask bool)
// HTML5: get byte size of a dropped file
fn C.sapp_html5_get_dropped_file_size(index i32) u32
// macOS: get ARC-bridged pointer to macOS NSWindow
fn C.sapp_macos_get_window() voidptr
// iOS: get ARC-bridged pointer to iOS UIWindow
fn C.sapp_ios_get_window() voidptr
// D3D11: get pointer to IDXGISwapChain object
fn C.sapp_d3d11_get_swap_chain() voidptr
// Win32: get the HWND window handle
fn C.sapp_win32_get_hwnd() voidptr
// GL: get major version
fn C.sapp_gl_get_major_version() i32
// GL: get minor version
fn C.sapp_gl_get_minor_version() i32
// GL: return true if the context is GLES
fn C.sapp_gl_is_gles() bool
// GL: get framebuffer object
fn C.sapp_gl_get_framebuffer() u32
// X11: get Window
fn C.sapp_x11_get_window() voidptr
// X11: get Display
fn C.sapp_x11_get_display() voidptr
// Android: get native activity handle
fn C.sapp_android_get_native_activity() voidptr
// V-specific: read RGBA pixels from the OpenGL framebuffer
fn C.v_sapp_gl_read_rgba_pixels(x i32, y i32, width i32, height i32, pixels charptr)
File diff suppressed because it is too large. Load diff
+62
View File
@@ -0,0 +1,62 @@
module sapp
// Shared state structs for the V sokol_app backends.
// Platform-specific state (SappState, g_sapp_state, SappWayland, SappWin32, etc.)
// lives in sapp_state_linux.v / sapp_state_windows.v respectively.
const ring_num_slots = 256
const max_title_length = 128
const mousecursor_num = 27
// Timing state for frame duration averaging
struct SappTiming {
mut:
last f64
accum f64
avg f64
spike_count int
num int
ring_head int
ring_tail int
ring_buf [ring_num_slots]f64
}
// Mouse state
struct SappMouse {
mut:
x f32
y f32
dx f32
dy f32
shown bool
locked bool
pos_valid bool
current_cursor MouseCursor
}
// Clipboard state
struct SappClipboard {
mut:
enabled bool
buf_size int
buffer &char = unsafe { nil }
}
// Drag and drop state
struct SappDrop {
mut:
enabled bool
max_files int
max_path_length int
num_files int
buf_size int
buffer &char = unsafe { nil }
}
// GL state
struct SappGl {
mut:
framebuffer u32
major int
minor int
}
+430
View File
@@ -0,0 +1,430 @@
@[has_globals]
module sapp
// Linux-specific state structs for the V sokol_app backend.
// Shared state (SappTiming, SappMouse, etc.) is in sapp_state.v.
// X11 and XKB share keypad/navigation keysyms. Keep the stateful keypad mapping in one place so
// Num Lock can flip keypad arrows between navigation keys and keypad digits consistently.
fn linux_translate_navigation_or_keypad_keysym(keysym u32) KeyCode {
return match keysym {
0xff63, 0xff9e { .insert }
0xffff, 0xff9f { .delete }
0xff50, 0xff95 { .home }
0xff57, 0xff9c { .end }
0xff55, 0xff9a { .page_up }
0xff56, 0xff9b { .page_down }
0xff51, 0xff96 { .left }
0xff53, 0xff98 { .right }
0xff52, 0xff97 { .up }
0xff54, 0xff99 { .down }
0xffb0 { .kp_0 }
0xffb1 { .kp_1 }
0xffb2 { .kp_2 }
0xffb3 { .kp_3 }
0xff9d, 0xffb5 { .kp_5 }
0xffb4 { .kp_4 }
0xffb6 { .kp_6 }
0xffb7 { .kp_7 }
0xffb8 { .kp_8 }
0xffb9 { .kp_9 }
0xffac, 0xffae { .kp_decimal }
0xffaf { .kp_divide }
0xffaa { .kp_multiply }
0xffad { .kp_subtract }
0xffab { .kp_add }
0xff8d { .kp_enter }
0xffbd { .kp_equal }
else { .invalid }
}
}
// Wayland-specific state (only compiled when -d sokol_wayland is used)
$if sokol_wayland ? {
struct SappWayland {
mut:
// Core Wayland objects
display &C.wl_display = unsafe { nil }
registry &C.wl_registry = unsafe { nil }
compositor &C.wl_compositor = unsafe { nil }
surface &C.wl_surface = unsafe { nil }
egl_window &C.wl_egl_window = unsafe { nil }
shm &C.wl_shm = unsafe { nil }
// XDG shell
xdg_wm_base &C.xdg_wm_base = unsafe { nil }
xdg_surface &C.xdg_surface = unsafe { nil }
xdg_toplevel &C.xdg_toplevel = unsafe { nil }
// Input
seat &C.wl_seat = unsafe { nil }
pointer &C.wl_pointer = unsafe { nil }
keyboard &C.wl_keyboard = unsafe { nil }
touch &C.wl_touch = unsafe { nil }
seat_version u32
// Pointer constraints
pointer_constraints &C.zwp_pointer_constraints_v1 = unsafe { nil }
locked_pointer &C.zwp_locked_pointer_v1 = unsafe { nil }
relative_pointer_mgr &C.zwp_relative_pointer_manager_v1 = unsafe { nil }
relative_pointer &C.zwp_relative_pointer_v1 = unsafe { nil }
// XKB keyboard handling
xkb_context &C.xkb_context = unsafe { nil }
xkb_keymap &C.xkb_keymap = unsafe { nil }
xkb_state &C.xkb_state = unsafe { nil }
xkb_compose_table &C.xkb_compose_table = unsafe { nil }
xkb_compose_state &C.xkb_compose_state = unsafe { nil }
// Cursor
cursor_shape_manager &C.wp_cursor_shape_manager_v1 = unsafe { nil }
cursor_shape_device &C.wp_cursor_shape_device_v1 = unsafe { nil }
cursor_theme &C.wl_cursor_theme = unsafe { nil }
cursor_default &C.wl_cursor = unsafe { nil }
cursor_surface &C.wl_surface = unsafe { nil }
cursor_size int
// Fractional scale
fractional_scale_mgr &C.wp_fractional_scale_manager_v1 = unsafe { nil }
fractional_scale &C.wp_fractional_scale_v1 = unsafe { nil }
scale_numerator u32
// Viewporter
viewporter &C.wp_viewporter = unsafe { nil }
viewport &C.wp_viewport = unsafe { nil }
// Decorations
decoration_manager &C.zxdg_decoration_manager_v1 = unsafe { nil }
toplevel_decoration &C.zxdg_toplevel_decoration_v1 = unsafe { nil }
// Clipboard / data device
data_device_manager &C.wl_data_device_manager = unsafe { nil }
data_device &C.wl_data_device = unsafe { nil }
data_source &C.wl_data_source = unsafe { nil }
data_offer &C.wl_data_offer = unsafe { nil }
clipboard_string &char = unsafe { nil }
clipboard_size int
// Window state
width int
height int
fb_width int
fb_height int
scale f32 = 1.0
configured bool
closed bool
fullscreen bool
maximized bool
focused bool
// Pointer state
pointer_x f32
pointer_y f32
pointer_enter_serial u32
// Key repeat
key_repeat_rate int = 25
key_repeat_delay int = 600
key_repeat_timer_fd int = -1
key_repeat_keycode u32
}
} $else {
// Dummy struct for non-Wayland builds
struct SappWayland {}
}
// X11 XInput extension state
struct SappXi {
mut:
available bool
major_opcode int
event_base int
error_base int
major int
minor int
}
// X11 XDnD state
struct SappXdnd {
mut:
version i64
source Window
format Atom
xdnd_aware Atom
xdnd_enter Atom
xdnd_position Atom
xdnd_status Atom
xdnd_action_copy Atom
xdnd_drop Atom
xdnd_finished Atom
xdnd_selection Atom
xdnd_type_list Atom
text_uri_list Atom
}
// X11-specific state
struct SappX11 {
mut:
mouse_buttons u8
display &C.Display = unsafe { nil }
screen int
root Window
colormap Colormap
window Window
hidden_cursor Cursor
standard_cursors [mousecursor_num]Cursor
custom_cursors [mousecursor_num]Cursor
window_state int
dpi f32
error_code u8
// X atoms
utf8_string Atom
clipboard_atom Atom
targets Atom
wm_protocols Atom
wm_delete_window Atom
wm_state Atom
net_wm_name Atom
net_wm_icon_name Atom
net_wm_icon Atom
net_wm_state Atom
net_wm_state_fullscreen Atom
// Extensions
xi SappXi
xdnd SappXdnd
// Key repeat tracking (keycodes 0..255)
key_repeat [256]bool
}
// EGL state
struct SappEgl {
mut:
display EGLDisplay
context EGLContext
surface EGLSurface
config EGLConfig
}
// Main application state - Linux version with Wayland/X11/EGL backends
struct SappState {
mut:
desc Desc
valid bool
fullscreen bool
first_frame bool
init_called bool
cleanup_called bool
quit_requested bool
quit_ordered bool
event_consumed bool
html5_ask_leave_site bool
onscreen_keyboard_shown bool
window_width int
window_height int
framebuffer_width int
framebuffer_height int
sample_count int
swap_interval int
dpi_scale f32 = 1.0
frame_count u64
timing SappTiming
event Event
mouse SappMouse
clipboard SappClipboard
drop SappDrop
// Platform-specific state
wl SappWayland
x11 SappX11
egl SappEgl
gl SappGl
// Keycode translation table
keycodes [max_keycodes]KeyCode
// Window title
window_title [max_title_length]u8
// V patch
v_native_render bool
// Custom cursors
custom_cursor_bound [mousecursor_num]bool
}
// The global state instance
__global g_sapp_state = SappState{}
// === Shared helper functions ===
// init_sapp_event initializes an event struct with common fields.
fn init_sapp_event(event_type EventType) {
unsafe { C.memset(&g_sapp_state.event, 0, int(sizeof(g_sapp_state.event))) }
g_sapp_state.event.@type = event_type
g_sapp_state.event.frame_count = g_sapp_state.frame_count
g_sapp_state.event.mouse_button = .invalid
g_sapp_state.event.window_width = g_sapp_state.window_width
g_sapp_state.event.window_height = g_sapp_state.window_height
g_sapp_state.event.framebuffer_width = g_sapp_state.framebuffer_width
g_sapp_state.event.framebuffer_height = g_sapp_state.framebuffer_height
g_sapp_state.event.mouse_x = g_sapp_state.mouse.x
g_sapp_state.event.mouse_y = g_sapp_state.mouse.y
g_sapp_state.event.mouse_dx = g_sapp_state.mouse.dx
g_sapp_state.event.mouse_dy = g_sapp_state.mouse.dy
}
// call_sapp_event dispatches the event to the user's callback.
fn call_sapp_event(e &Event) bool {
if !g_sapp_state.cleanup_called {
if g_sapp_state.desc.event_cb != unsafe { nil } {
g_sapp_state.desc.event_cb(e)
} else if g_sapp_state.desc.event_userdata_cb != unsafe { nil } {
g_sapp_state.desc.event_userdata_cb(e, g_sapp_state.desc.user_data)
}
}
if g_sapp_state.event_consumed {
g_sapp_state.event_consumed = false
return true
}
return false
}
// sapp_call_init calls the user's init callback.
fn sapp_call_init() {
if g_sapp_state.desc.init_cb != unsafe { nil } {
g_sapp_state.desc.init_cb()
} else if g_sapp_state.desc.init_userdata_cb != unsafe { nil } {
g_sapp_state.desc.init_userdata_cb(g_sapp_state.desc.user_data)
}
g_sapp_state.init_called = true
}
// sapp_call_frame calls the user's frame callback.
fn sapp_call_frame() {
if g_sapp_state.desc.frame_cb != unsafe { nil } {
g_sapp_state.desc.frame_cb()
} else if g_sapp_state.desc.frame_userdata_cb != unsafe { nil } {
g_sapp_state.desc.frame_userdata_cb(g_sapp_state.desc.user_data)
}
}
// sapp_call_cleanup calls the user's cleanup callback.
fn sapp_call_cleanup() {
if !g_sapp_state.cleanup_called {
if g_sapp_state.desc.cleanup_cb != unsafe { nil } {
g_sapp_state.desc.cleanup_cb()
} else if g_sapp_state.desc.cleanup_userdata_cb != unsafe { nil } {
g_sapp_state.desc.cleanup_userdata_cb(g_sapp_state.desc.user_data)
}
g_sapp_state.cleanup_called = true
}
}
// sapp_do_frame handles the per-frame logic.
fn sapp_do_frame() {
if g_sapp_state.first_frame {
g_sapp_state.first_frame = false
sapp_call_init()
}
sapp_call_frame()
g_sapp_state.frame_count++
}
// === Timing helpers ===
fn sapp_timing_reset(t &SappTiming) {
unsafe {
mut mt := t
mt.last = 0.0
mt.accum = 0.0
mt.avg = 0.0
mt.spike_count = 0
mt.num = 0
mt.ring_head = 0
mt.ring_tail = 0
}
}
fn sapp_timing_get_avg(t &SappTiming) f64 {
return t.avg
}
// === Drop file helpers ===
fn sapp_dropped_file_path_ptr(index int) &char {
assert g_sapp_state.drop.buffer != unsafe { nil }
assert index >= 0 && index <= g_sapp_state.drop.max_files
offset := index * g_sapp_state.drop.max_path_length
assert offset < g_sapp_state.drop.buf_size
return unsafe { &char(g_sapp_state.drop.buffer + offset) }
}
// === State initialization ===
fn sapp_desc_defaults(desc &Desc) Desc {
mut res := *desc
if res.sample_count == 0 {
res.sample_count = 1
}
if res.swap_interval == 0 {
res.swap_interval = 1
}
if res.gl.major_version == 0 {
res.gl.major_version = 4
res.gl.minor_version = 1
}
if res.clipboard_size == 0 {
res.clipboard_size = 8192
}
if res.max_dropped_files == 0 {
res.max_dropped_files = 1
}
if res.max_dropped_file_path_length == 0 {
res.max_dropped_file_path_length = 2048
}
return res
}
fn sapp_init_state(desc &Desc) {
unsafe { C.memset(&g_sapp_state, 0, int(sizeof(g_sapp_state))) }
g_sapp_state.desc = sapp_desc_defaults(desc)
g_sapp_state.first_frame = true
g_sapp_state.window_width = g_sapp_state.desc.width
g_sapp_state.window_height = g_sapp_state.desc.height
g_sapp_state.framebuffer_width = g_sapp_state.window_width
g_sapp_state.framebuffer_height = g_sapp_state.window_height
g_sapp_state.sample_count = g_sapp_state.desc.sample_count
g_sapp_state.swap_interval = g_sapp_state.desc.swap_interval
g_sapp_state.clipboard.enabled = g_sapp_state.desc.enable_clipboard
if g_sapp_state.clipboard.enabled {
g_sapp_state.clipboard.buf_size = g_sapp_state.desc.clipboard_size
g_sapp_state.clipboard.buffer = unsafe {
&char(C.calloc(1, usize(g_sapp_state.clipboard.buf_size)))
}
}
g_sapp_state.drop.enabled = g_sapp_state.desc.enable_dragndrop
if g_sapp_state.drop.enabled {
g_sapp_state.drop.max_files = g_sapp_state.desc.max_dropped_files
g_sapp_state.drop.max_path_length = g_sapp_state.desc.max_dropped_file_path_length
g_sapp_state.drop.buf_size = g_sapp_state.drop.max_files * g_sapp_state.drop.max_path_length
g_sapp_state.drop.buffer = unsafe { &char(C.calloc(1, usize(g_sapp_state.drop.buf_size))) }
}
// Copy window title
if g_sapp_state.desc.window_title != unsafe { nil }
&& unsafe { C.strlen(g_sapp_state.desc.window_title) } > 0 {
title := g_sapp_state.desc.window_title
mut i := 0
for i < max_title_length - 1 {
ch := unsafe { title[i] }
if ch == 0 {
break
}
g_sapp_state.window_title[i] = u8(ch)
i++
}
g_sapp_state.window_title[i] = 0
} else {
// Default title
g_sapp_state.window_title[0] = `s`
g_sapp_state.window_title[1] = `o`
g_sapp_state.window_title[2] = `k`
g_sapp_state.window_title[3] = `o`
g_sapp_state.window_title[4] = `l`
g_sapp_state.window_title[5] = 0
}
g_sapp_state.dpi_scale = 1.0
g_sapp_state.fullscreen = g_sapp_state.desc.fullscreen
g_sapp_state.mouse.shown = true
}
fn sapp_discard_state() {
if g_sapp_state.clipboard.enabled && g_sapp_state.clipboard.buffer != unsafe { nil } {
unsafe { C.free(g_sapp_state.clipboard.buffer) }
}
if g_sapp_state.drop.enabled && g_sapp_state.drop.buffer != unsafe { nil } {
unsafe { C.free(g_sapp_state.drop.buffer) }
}
}
+318
View File
@@ -0,0 +1,318 @@
module sapp
import sokol.memory
const max_touchpoints = 8
const max_mousebuttons = 3
const max_keycodes = 512
const max_iconimages = 8
@[typedef]
pub struct C.sapp_allocator {
pub mut:
alloc_fn memory.FnAllocatorAlloc = unsafe { nil }
free_fn memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
pub type Allocator = C.sapp_allocator
@[typedef]
pub struct C.sapp_logger {
pub mut:
func memory.FnLogCb = unsafe { nil }
user_data voidptr
}
pub type Logger = C.sapp_logger
// sapp_range is a general pointer/size-pair struct for passing binary blobs into sokol_app.h
@[typedef]
pub struct C.sapp_range {
pub:
ptr voidptr
size usize
}
pub type Range = C.sapp_range
@[typedef]
pub struct C.sapp_image_desc {
pub:
width int
height int
cursor_hotspot_x int
cursor_hotspot_y int
pixels Range
}
pub type ImageDesc = C.sapp_image_desc
@[typedef]
pub struct C.sapp_icon_desc {
pub:
sokol_default bool
images [max_iconimages]ImageDesc
}
pub type IconDesc = C.sapp_icon_desc
@[typedef]
pub struct C.sapp_gl_desc {
pub mut:
major_version int // override GL/GLES major version
minor_version int // override GL/GLES minor version
}
pub type GlDesc = C.sapp_gl_desc
@[typedef]
pub struct C.sapp_win32_desc {
pub:
console_utf8 bool // if true, set the output console codepage to UTF-8
console_create bool // if true, attach stdout/stderr to a new console window
console_attach bool // if true, attach stdout/stderr to parent process
}
pub type Win32Desc = C.sapp_win32_desc
@[typedef]
pub struct C.sapp_html5_desc {
pub:
canvas_selector &char = c'#canvas' // css selector of the HTML5 canvas element, default is "#canvas"
canvas_resize bool // if true, the HTML5 canvas size is set to sapp_desc.width/height
preserve_drawing_buffer bool // HTML5 only: whether to preserve default framebuffer content between frames
premultiplied_alpha bool // HTML5 only: whether the rendered pixels use premultiplied alpha convention
ask_leave_site bool // initial state of the internal html5_ask_leave_site flag
update_document_title bool // if true, update the HTML document.title with sapp_desc.window_title
bubble_mouse_events bool // if true, mouse events will bubble up to the web page
bubble_touch_events bool // same for touch events
bubble_wheel_events bool // same for wheel events
bubble_key_events bool // if true, bubble up *all* key events to browser
bubble_char_events bool // if true, bubble up character events to browser
use_emsc_set_main_loop bool // if true, use emscripten_set_main_loop() instead of emscripten_request_animation_frame_loop()
emsc_set_main_loop_simulate_infinite_loop bool // this will be passed as the simulate_infinite_loop arg to emscripten_set_main_loop()
}
pub type Html5Desc = C.sapp_html5_desc
@[typedef]
pub struct C.sapp_ios_desc {
pub:
keyboard_resizes_canvas bool // if true, showing the iOS keyboard shrinks the canvas
}
pub type IosDesc = C.sapp_ios_desc
// --- environment structs (returned by sapp_get_environment) ---
@[typedef]
pub struct C.sapp_environment_defaults {
pub:
color_format int
depth_format int
sample_count int
}
pub type EnvironmentDefaults = C.sapp_environment_defaults
@[typedef]
pub struct C.sapp_metal_environment {
pub:
device voidptr
}
@[typedef]
pub struct C.sapp_d3d11_environment {
pub:
device voidptr
device_context voidptr
}
@[typedef]
pub struct C.sapp_wgpu_environment {
pub:
device voidptr
}
@[typedef]
pub struct C.sapp_vulkan_environment {
pub:
instance voidptr
physical_device voidptr
device voidptr
queue voidptr
queue_family_index u32
}
pub type MetalEnvironment = C.sapp_metal_environment
pub type D3d11Environment = C.sapp_d3d11_environment
pub type WgpuEnvironment = C.sapp_wgpu_environment
pub type VulkanEnvironment = C.sapp_vulkan_environment
@[typedef]
pub struct C.sapp_environment {
pub:
defaults EnvironmentDefaults
metal MetalEnvironment
d3d11 D3d11Environment
wgpu WgpuEnvironment
vulkan VulkanEnvironment
}
pub type Environment = C.sapp_environment
// --- swapchain structs (returned by sapp_get_swapchain) ---
@[typedef]
pub struct C.sapp_metal_swapchain {
pub:
current_drawable voidptr
depth_stencil_texture voidptr
msaa_color_texture voidptr
}
@[typedef]
pub struct C.sapp_d3d11_swapchain {
pub:
render_view voidptr
resolve_view voidptr
depth_stencil_view voidptr
}
@[typedef]
pub struct C.sapp_wgpu_swapchain {
pub:
render_view voidptr
resolve_view voidptr
depth_stencil_view voidptr
}
@[typedef]
pub struct C.sapp_vulkan_swapchain {
pub:
render_image voidptr
render_view voidptr
resolve_image voidptr
resolve_view voidptr
depth_stencil_image voidptr
depth_stencil_view voidptr
render_finished_semaphore voidptr
present_complete_semaphore voidptr
}
@[typedef]
pub struct C.sapp_gl_swapchain {
pub:
framebuffer u32
}
pub type MetalSwapchain = C.sapp_metal_swapchain
pub type D3d11Swapchain = C.sapp_d3d11_swapchain
pub type WgpuSwapchain = C.sapp_wgpu_swapchain
pub type VulkanSwapchain = C.sapp_vulkan_swapchain
pub type GlSwapchain = C.sapp_gl_swapchain
@[typedef]
pub struct C.sapp_swapchain {
pub:
width int
height int
sample_count int
color_format int
depth_format int
metal MetalSwapchain
d3d11 D3d11Swapchain
wgpu WgpuSwapchain
vulkan VulkanSwapchain
gl GlSwapchain
}
pub type Swapchain = C.sapp_swapchain
@[typedef]
pub struct C.sapp_desc {
pub mut:
// these are the user-provided callbacks without user data
init_cb fn () = unsafe { nil }
frame_cb fn () = unsafe { nil }
cleanup_cb fn () = unsafe { nil }
event_cb fn (&Event) = unsafe { nil } // &sapp_event
user_data voidptr // these are the user-provided callbacks with user data
init_userdata_cb fn (voidptr) = unsafe { nil }
frame_userdata_cb fn (voidptr) = unsafe { nil }
cleanup_userdata_cb fn (voidptr) = unsafe { nil }
event_userdata_cb fn (&Event, voidptr) = unsafe { nil }
width int // the preferred width of the window / canvas
height int // the preferred height of the window / canvas
sample_count int // MSAA sample count
swap_interval int // the preferred swap interval on Windows, macOS, Linux, iOS, and HTML5; Android support is not implemented yet
high_dpi bool // whether the rendering canvas is full-resolution on HighDPI displays
fullscreen bool // whether the window should be created in fullscreen mode
alpha bool // whether the framebuffer should have an alpha channel (ignored on some platforms)
window_title &char // the window title as UTF-8 encoded string
enable_clipboard bool // enable clipboard access, default is false
clipboard_size int // max size of clipboard content in bytes
enable_dragndrop bool // enable file dropping (drag'n'drop), default is false
max_dropped_files int // max number of dropped files to process (default: 1)
max_dropped_file_path_length int // max length in bytes of a dropped UTF-8 file path (default: 2048)
icon IconDesc // the initial window icon to set
allocator Allocator // optional memory allocation overrides (default: malloc/free)
logger Logger // logging callback override (default: NO LOGGING!)
// backend-specific options
gl GlDesc // OpenGL specific options
win32 Win32Desc // Win32 specific options
html5 Html5Desc // HTML5 specific options
ios IosDesc // iOS specific options
// V patches
__v_native_render bool // V patch to allow for native rendering
min_width int // V patch to allow for min window width
min_height int // V patch to allow for min window height
borderless_window bool // V patch to create a window without native decorations when supported
}
pub type Desc = C.sapp_desc
@[typedef]
pub struct C.sapp_event {
pub mut:
frame_count u64 // current frame counter, always valid, useful for checking if two events were issued in the same frame
type EventType // the event type, always valid
key_code KeyCode // the virtual key code, only valid in KEY_UP, KEY_DOWN
char_code u32 // the UTF-32 character code, only valid in CHAR events
key_repeat bool // true if this is a key-repeat event, valid in KEY_UP, KEY_DOWN and CHAR
modifiers u32 // current modifier keys, valid in all key-, char- and mouse-events
mouse_button MouseButton // mouse button that was pressed or released, valid in MOUSE_DOWN, MOUSE_UP
mouse_x f32 // current horizontal mouse position in pixels, always valid except during mouse lock
mouse_y f32 // current vertical mouse position in pixels, always valid except during mouse lock
mouse_dx f32 // relative horizontal mouse movement since last frame, always valid
mouse_dy f32 // relative vertical mouse movement since last frame, always valid
scroll_x f32 // horizontal mouse wheel scroll distance, valid in MOUSE_SCROLL events
scroll_y f32 // vertical mouse wheel scroll distance, valid in MOUSE_SCROLL events
num_touches int // number of valid items in the touches[] array
touches [max_touchpoints]TouchPoint // current touch points, valid in TOUCHES_BEGIN, TOUCHES_MOVED, TOUCHES_ENDED
window_width int // current window- and framebuffer width in pixels, always valid
window_height int // current window- and framebuffer height in pixels, always valid
framebuffer_width int // = window_width * dpi_scale
framebuffer_height int // = window_height * dpi_scale
}
pub type Event = C.sapp_event
pub fn (e &Event) str() string {
return 'evt: frame_count=${e.frame_count}, type=${EventType(e.type)}'
}
@[typedef]
pub struct C.sapp_touchpoint {
pub:
identifier u64
pos_x f32
pos_y f32
android_tooltype TouchToolType
changed bool
}
pub type TouchPoint = C.sapp_touchpoint
+69
View File
@@ -0,0 +1,69 @@
module sapp
import os
import stbi
#define SOKOL_VALIDATE_NON_FATAL 1
// v_sapp_gl_read_rgba_pixels reads pixles from the OpenGL buffer into `pixels`.
fn C.v_sapp_gl_read_rgba_pixels(x int, y int, width int, height int, pixels charptr)
// screenshot takes a screenshot of the current window and
// saves it to `path`. The format is inferred from the extension
// of the file name in `path`.
//
// Supported formats are: `.png`, `.ppm`.
pub fn screenshot(path string) ! {
match os.file_ext(path) {
'.png' {
return screenshot_png(path)
}
'.ppm' {
return screenshot_ppm(path)
}
else {
return error(@MOD + '.' + @FN + ' currently only supports .png and .ppm files.')
}
}
}
// screenshot_ppm takes a screenshot of the current window and
// saves it to `path` as a .ppm file.
@[manualfree]
pub fn screenshot_ppm(path string) ! {
ss := screenshot_window()
write_rgba_to_ppm(path, ss.width, ss.height, 4, ss.pixels)!
unsafe { ss.destroy() }
}
// screenshot_png takes a screenshot of the current window and
// saves it to `path` as a .png file.
@[manualfree]
pub fn screenshot_png(path string) ! {
ss := screenshot_window()
stbi.set_flip_vertically_on_write(true)
stbi.stbi_write_png(path, ss.width, ss.height, 4, ss.pixels, ss.width * 4)!
unsafe { ss.destroy() }
}
// write_rgba_to_ppm writes `pixels` data in RGBA format to PPM3 format.
fn write_rgba_to_ppm(path string, w int, h int, components int, pixels &u8) ! {
mut f_out := os.create(path)!
defer {
f_out.close()
}
f_out.writeln('P3')!
f_out.writeln('${w} ${h}')!
f_out.writeln('255')!
for i := h - 1; i >= 0; i-- {
for j := 0; j < w; j++ {
idx := i * w * components + j * components
unsafe {
r := int(pixels[idx])
g := int(pixels[idx + 1])
b := int(pixels[idx + 2])
f_out.write_string('${r} ${g} ${b} ')!
}
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+42
View File
@@ -0,0 +1,42 @@
module sapp
@[heap]
pub struct Screenshot {
width int
height int
size int
mut:
pixels &u8 = unsafe { nil }
}
@[manualfree]
pub fn screenshot_window() &Screenshot {
img_width := width()
img_height := height()
img_size := img_width * img_height * 4
img_pixels := unsafe { &u8(malloc(img_size)) }
C.v_sapp_gl_read_rgba_pixels(0, 0, img_width, img_height, img_pixels)
return &Screenshot{
width: img_width
height: img_height
size: img_size
pixels: img_pixels
}
}
// free - free *only* the Screenshot pixels.
@[unsafe]
pub fn (mut ss Screenshot) free() {
unsafe {
free(ss.pixels)
ss.pixels = &u8(nil)
}
}
// destroy - free the Screenshot pixels,
// then free the screenshot data structure itself.
@[unsafe]
pub fn (mut ss Screenshot) destroy() {
unsafe { ss.free() }
unsafe { free(ss) }
}
+42
View File
@@ -0,0 +1,42 @@
module sfons
import fontstash
import sokol.f as _
import sokol.memory
// create a new Context/font atlas, for rendering glyphs, given its dimensions `width` and `height`
@[inline]
pub fn create(width int, height int, flags int) &fontstash.Context {
assert is_power_of_two(width)
assert is_power_of_two(height)
allocator := C.sfons_allocator_t{
alloc_fn: memory.salloc
free_fn: memory.sfree
user_data: voidptr(0x100005f0)
}
desc := C.sfons_desc_t{
width: width
height: height
allocator: allocator
}
return C.sfons_create(&desc)
}
@[inline]
pub fn destroy(ctx &fontstash.Context) {
C.sfons_destroy(ctx)
}
@[inline]
pub fn rgba(r u8, g u8, b u8, a u8) u32 {
return C.sfons_rgba(r, g, b, a)
}
@[inline]
pub fn flush(ctx &fontstash.Context) {
C.sfons_flush(ctx)
}
fn is_power_of_two(x int) bool {
return x in [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768]
}
+26
View File
@@ -0,0 +1,26 @@
module sfons
import fontstash
import sokol.memory
@[typedef]
pub struct C.sfons_allocator_t {
pub:
alloc_fn memory.FnAllocatorAlloc = unsafe { nil }
free_fn memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
@[typedef]
pub struct C.sfons_desc_t {
pub:
width int // initial width of font atlas texture (default: 512, must be power of 2)
height int // initial height of font atlas texture (default: 512, must be power of 2)
allocator C.sfons_allocator_t // optional memory allocation overrides
}
fn C.sfons_create(const_desc &C.sfons_desc_t) &fontstash.Context
fn C.sfons_destroy(ctx &fontstash.Context)
fn C.sfons_flush(ctx &fontstash.Context)
fn C.sfons_rgba(r u8, g u8, b u8, a u8) u32
+12
View File
@@ -0,0 +1,12 @@
module sgl
// SglError is C.sgl_error_t
pub enum SglError {
no_error = C.SGL_NO_ERROR // 0
vertices_full = C.SGL_ERROR_VERTICES_FULL
uniforms_full = C.SGL_ERROR_UNIFORMS_FULL
commands_full = C.SGL_ERROR_COMMANDS_FULL
stack_overflow = C.SGL_ERROR_STACK_OVERFLOW
stack_underflow = C.SGL_ERROR_STACK_UNDERFLOW
no_context = C.SGL_ERROR_NO_CONTEXT
}
+443
View File
@@ -0,0 +1,443 @@
module sgl
import sokol.gfx
import sokol.memory
pub const version = gfx.version + 1
pub const context = Context{0x00010001} // C.SGL_DEFAULT_CONTEXT = { 0x00010001 }
// setup/shutdown/misc
pub fn setup(desc &Desc) {
if desc.allocator.alloc_fn == unsafe { nil } && desc.allocator.free_fn == unsafe { nil } {
unsafe {
desc.allocator.alloc_fn = memory.salloc
desc.allocator.free_fn = memory.sfree
desc.allocator.user_data = voidptr(0x10000561)
}
}
if desc.logger.func == unsafe { nil } {
unsafe {
desc.logger.func = memory.slog
}
}
C.sgl_setup(desc)
}
pub fn shutdown() {
C.sgl_shutdown()
}
@[inline]
pub fn error() SglError {
return unsafe { SglError(int(C.sgl_error())) }
}
@[inline]
pub fn context_error(ctx Context) SglError {
return unsafe { SglError(int(C.sgl_context_error(ctx))) }
}
@[inline]
pub fn rad(deg f32) f32 {
return C.sgl_rad(deg)
}
@[inline]
pub fn deg(rad f32) f32 {
return C.sgl_deg(rad)
}
// context functions
@[inline]
pub fn make_context(desc &ContextDesc) Context {
return C.sgl_make_context(desc)
}
@[inline]
pub fn destroy_context(ctx Context) {
C.sgl_destroy_context(ctx)
}
@[inline]
pub fn set_context(ctx Context) {
C.sgl_set_context(ctx)
}
@[inline]
pub fn get_context() Context {
return C.sgl_get_context()
}
@[inline]
pub fn default_context() Context {
return C.sgl_default_context()
}
// create and destroy pipeline objects
@[inline]
pub fn make_pipeline(desc &gfx.PipelineDesc) Pipeline {
return C.sgl_make_pipeline(desc)
}
@[inline]
pub fn context_make_pipeline(ctx Context, desc &gfx.PipelineDesc) Pipeline {
return C.sgl_context_make_pipeline(ctx, desc)
}
@[inline]
pub fn destroy_pipeline(pip Pipeline) {
C.sgl_destroy_pipeline(pip)
}
// render state functions
@[inline]
pub fn defaults() {
C.sgl_defaults()
}
@[inline]
pub fn viewport(x int, y int, w int, h int, origin_top_left bool) {
C.sgl_viewport(x, y, w, h, origin_top_left)
}
@[inline]
pub fn scissor_rect(x int, y int, w int, h int, origin_top_left bool) {
C.sgl_scissor_rect(x, y, w, h, origin_top_left)
}
@[inline]
pub fn scissor_rectf(x f32, y f32, w f32, h f32, origin_top_left bool) {
C.sgl_scissor_rectf(x, y, w, h, origin_top_left)
}
@[inline]
pub fn enable_texture() {
C.sgl_enable_texture()
}
@[inline]
pub fn disable_texture() {
C.sgl_disable_texture()
}
@[inline]
pub fn texture(img gfx.Image, smp gfx.Sampler) {
C.sgl_texture(img, smp)
}
// pipeline stack functions
@[inline]
pub fn load_default_pipeline() {
C.sgl_load_default_pipeline()
}
@[inline]
pub fn default_pipeline() {
C.sgl_load_default_pipeline()
}
@[inline]
pub fn load_pipeline(pip Pipeline) {
C.sgl_load_pipeline(pip)
}
@[inline]
pub fn push_pipeline() {
C.sgl_push_pipeline()
}
@[inline]
pub fn pop_pipeline() {
C.sgl_pop_pipeline()
}
// matrix stack functions
@[inline]
pub fn matrix_mode_modelview() {
C.sgl_matrix_mode_modelview()
}
@[inline]
pub fn matrix_mode_projection() {
C.sgl_matrix_mode_projection()
}
@[inline]
pub fn matrix_mode_texture() {
C.sgl_matrix_mode_texture()
}
@[inline]
pub fn load_identity() {
C.sgl_load_identity()
}
@[inline]
pub fn load_matrix(m []f32) {
C.sgl_load_matrix(m.data)
}
@[inline]
pub fn load_transpose_matrix(m []f32) {
C.sgl_load_transpose_matrix(m.data)
}
@[inline]
pub fn mult_matrix(m []f32) {
C.sgl_mult_matrix(m.data)
}
@[inline]
pub fn mult_transpose_matrix(m []f32) {
C.sgl_mult_transpose_matrix(m.data)
}
@[inline]
pub fn rotate(angle_rad f32, x f32, y f32, z f32) {
C.sgl_rotate(angle_rad, x, y, z)
}
@[inline]
pub fn scale(x f32, y f32, z f32) {
C.sgl_scale(x, y, z)
}
@[inline]
pub fn translate(x f32, y f32, z f32) {
C.sgl_translate(x, y, z)
}
@[inline]
pub fn frustum(l f32, r f32, b f32, t f32, n f32, f f32) {
C.sgl_frustum(l, r, b, t, n, f)
}
@[inline]
pub fn ortho(l f32, r f32, b f32, t f32, n f32, f f32) {
C.sgl_ortho(l, r, b, t, n, f)
}
@[inline]
pub fn perspective(fov_y f32, aspect f32, z_near f32, z_far f32) {
C.sgl_perspective(fov_y, aspect, z_near, z_far)
}
@[inline]
pub fn lookat(eye_x f32, eye_y f32, eye_z f32, center_x f32, center_y f32, center_z f32, up_x f32, up_y f32,
up_z f32) {
C.sgl_lookat(eye_x, eye_y, eye_z, center_x, center_y, center_z, up_x, up_y, up_z)
}
@[inline]
pub fn push_matrix() {
C.sgl_push_matrix()
}
@[inline]
pub fn pop_matrix() {
C.sgl_pop_matrix()
}
// these functions only set the internal 'current texcoord / color' (valid inside or outside begin/end)
@[inline]
pub fn t2f(u f32, v f32) {
C.sgl_t2f(u, v)
}
@[inline]
pub fn c3f(r f32, g f32, b f32) {
C.sgl_c3f(r, g, b)
}
@[inline]
pub fn c4f(r f32, g f32, b f32, a f32) {
C.sgl_c4f(r, g, b, a)
}
@[inline]
pub fn c3b(r u8, g u8, b u8) {
C.sgl_c3b(r, g, b)
}
@[inline]
pub fn c4b(r u8, g u8, b u8, a u8) {
C.sgl_c4b(r, g, b, a)
}
@[inline]
pub fn c1i(rgba u32) {
C.sgl_c1i(rgba)
}
@[inline]
pub fn point_size(s f32) {
C.sgl_point_size(s)
}
// define primitives, each begin/end is one draw command
@[inline]
pub fn begin_points() {
C.sgl_begin_points()
}
@[inline]
pub fn begin_lines() {
C.sgl_begin_lines()
}
@[inline]
pub fn begin_line_strip() {
C.sgl_begin_line_strip()
}
@[inline]
pub fn begin_triangles() {
C.sgl_begin_triangles()
}
@[inline]
pub fn begin_triangle_strip() {
C.sgl_begin_triangle_strip()
}
@[inline]
pub fn begin_quads() {
C.sgl_begin_quads()
}
@[inline]
pub fn v2f(x f32, y f32) {
C.sgl_v2f(x, y)
}
@[inline]
pub fn v3f(x f32, y f32, z f32) {
C.sgl_v3f(x, y, z)
}
@[inline]
pub fn v2f_t2f(x f32, y f32, u f32, v f32) {
C.sgl_v2f_t2f(x, y, u, v)
}
@[inline]
pub fn v3f_t2f(x f32, y f32, z f32, u f32, v f32) {
C.sgl_v3f_t2f(x, y, z, u, v)
}
@[inline]
pub fn v2f_c3f(x f32, y f32, r f32, g f32, b f32) {
C.sgl_v2f_c3f(x, y, r, g, b)
}
@[inline]
pub fn v2f_c3b(x f32, y f32, r u8, g u8, b u8) {
C.sgl_v2f_c3b(x, y, r, g, b)
}
@[inline]
pub fn v2f_c4f(x f32, y f32, r f32, g f32, b f32, a f32) {
C.sgl_v2f_c4f(x, y, r, g, b, a)
}
@[inline]
pub fn v2f_c4b(x f32, y f32, r u8, g u8, b u8, a u8) {
C.sgl_v2f_c4b(x, y, r, g, b, a)
}
@[inline]
pub fn v2f_c1i(x f32, y f32, rgba u32) {
C.sgl_v2f_c1i(x, y, rgba)
}
@[inline]
pub fn v3f_c3f(x f32, y f32, z f32, r f32, g f32, b f32) {
C.sgl_v3f_c3f(x, y, z, r, g, b)
}
@[inline]
pub fn v3f_c3b(x f32, y f32, z f32, r u8, g u8, b u8) {
C.sgl_v3f_c3b(x, y, z, r, g, b)
}
@[inline]
pub fn v3f_c4f(x f32, y f32, z f32, r f32, g f32, b f32, a f32) {
C.sgl_v3f_c4f(x, y, z, r, g, b, a)
}
@[inline]
pub fn v3f_c4b(x f32, y f32, z f32, r u8, g u8, b u8, a u8) {
C.sgl_v3f_c4b(x, y, z, r, g, b, a)
}
@[inline]
pub fn v3f_c1i(x f32, y f32, z f32, rgba u32) {
C.sgl_v3f_c1i(x, y, z, rgba)
}
@[inline]
pub fn v2f_t2f_c3f(x f32, y f32, u f32, v f32, r f32, g f32, b f32) {
C.sgl_v2f_t2f_c3f(x, y, u, v, r, g, b)
}
@[inline]
pub fn v2f_t2f_c3b(x f32, y f32, u f32, v f32, r u8, g u8, b u8) {
C.sgl_v2f_t2f_c3b(x, y, u, v, r, g, b)
}
@[inline]
pub fn v2f_t2f_c4f(x f32, y f32, u f32, v f32, r f32, g f32, b f32, a f32) {
C.sgl_v2f_t2f_c4f(x, y, u, v, r, g, b, a)
}
@[inline]
pub fn v2f_t2f_c4b(x f32, y f32, u f32, v f32, r u8, g u8, b u8, a u8) {
C.sgl_v2f_t2f_c4b(x, y, u, v, r, g, b, a)
}
@[inline]
pub fn v2f_t2f_c1i(x f32, y f32, u f32, v f32, rgba u32) {
C.sgl_v2f_t2f_c1i(x, y, u, v, rgba)
}
@[inline]
pub fn v3f_t2f_c3f(x f32, y f32, z f32, u f32, v f32, r f32, g f32, b f32) {
C.sgl_v3f_t2f_c3f(x, y, z, u, v, r, g, b)
}
@[inline]
pub fn v3f_t2f_c3b(x f32, y f32, z f32, u f32, v f32, r u8, g u8, b u8) {
C.sgl_v3f_t2f_c3b(x, y, z, u, v, r, g, b)
}
@[inline]
pub fn v3f_t2f_c4f(x f32, y f32, z f32, u f32, v f32, r f32, g f32, b f32, a f32) {
C.sgl_v3f_t2f_c4f(x, y, z, u, v, r, g, b, a)
}
@[inline]
pub fn v3f_t2f_c4b(x f32, y f32, z f32, u f32, v f32, r u8, g u8, b u8, a u8) {
C.sgl_v3f_t2f_c4b(x, y, z, u, v, r, g, b, a)
}
@[inline]
pub fn v3f_t2f_c1i(x f32, y f32, z f32, u f32, v f32, rgba u32) {
C.sgl_v3f_t2f_c1i(x, y, z, u, v, rgba)
}
@[inline]
pub fn end() {
C.sgl_end()
}
// render recorded commands
@[inline]
pub fn draw() {
C.sgl_draw()
}
@[inline]
pub fn context_draw(ctx Context) {
C.sgl_context_draw(ctx)
}
@@ -0,0 +1,18 @@
module sgl
import sokol.memory
@[typedef]
pub struct C.sgl_allocator_t {
pub mut:
alloc_fn memory.FnAllocatorAlloc = unsafe { nil }
free_fn memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
@[typedef]
pub struct C.sgl_logger_t {
pub mut:
func memory.FnLogCb = unsafe { nil }
user_data voidptr
}
+103
View File
@@ -0,0 +1,103 @@
module sgl
// setup/shutdown/misc
fn C.sgl_setup(const_desc &C.sgl_desc_t)
fn C.sgl_shutdown()
fn C.sgl_error() SglError
fn C.sgl_context_error(ctx C.sgl_context) SglError
fn C.sgl_rad(deg f32) f32
fn C.sgl_deg(rad f32) f32
// context functions
fn C.sgl_make_context(const_desc &C.sgl_context_desc_t) C.sgl_context
fn C.sgl_destroy_context(ctx C.sgl_context)
fn C.sgl_set_context(ctx C.sgl_context)
fn C.sgl_get_context() C.sgl_context
fn C.sgl_default_context() C.sgl_context
// create and destroy pipeline objects
fn C.sgl_make_pipeline(const_desc &C.sg_pipeline_desc) C.sgl_pipeline
fn C.sgl_context_make_pipeline(ctx C.sgl_context, const_desc &C.sg_pipeline_desc) C.sgl_pipeline
fn C.sgl_destroy_pipeline(pip C.sgl_pipeline)
// render state functions
fn C.sgl_defaults()
fn C.sgl_viewport(x int, y int, w int, h int, origin_top_left bool)
fn C.sgl_viewportf(x f32, y f32, w f32, h f32, origin_top_left bool)
fn C.sgl_scissor_rect(x int, y int, w int, h int, origin_top_left bool)
fn C.sgl_scissor_rectf(x f32, y f32, w f32, h f32, origin_top_left bool)
fn C.sgl_enable_texture()
fn C.sgl_disable_texture()
fn C.sgl_texture(img C.sg_image, sampler C.sg_sampler)
// pipeline stack functions
fn C.sgl_load_default_pipeline()
fn C.sgl_load_pipeline(pip C.sgl_pipeline)
fn C.sgl_push_pipeline()
fn C.sgl_pop_pipeline()
// matrix stack functions
fn C.sgl_matrix_mode_modelview()
fn C.sgl_matrix_mode_projection()
fn C.sgl_matrix_mode_texture()
fn C.sgl_load_identity()
fn C.sgl_load_matrix(m [16]f32)
fn C.sgl_load_transpose_matrix(m [16]f32)
fn C.sgl_mult_matrix(m [16]f32)
fn C.sgl_mult_transpose_matrix(m [16]f32)
fn C.sgl_rotate(angle_rad f32, x f32, y f32, z f32)
fn C.sgl_scale(x f32, y f32, z f32)
fn C.sgl_translate(x f32, y f32, z f32)
fn C.sgl_frustum(l f32, r f32, b f32, t f32, n f32, f f32)
fn C.sgl_ortho(l f32, r f32, b f32, t f32, n f32, f f32)
fn C.sgl_perspective(fov_y f32, aspect f32, z_near f32, z_far f32)
fn C.sgl_lookat(eye_x f32, eye_y f32, eye_z f32, center_x f32, center_y f32, center_z f32, up_x f32, up_y f32,
up_z f32)
fn C.sgl_push_matrix()
fn C.sgl_pop_matrix()
// these functions only set the internal 'current texcoord / color' (valid inside or outside begin/end)
fn C.sgl_t2f(u f32, v f32)
fn C.sgl_c3f(r f32, g f32, b f32)
fn C.sgl_c4f(r f32, g f32, b f32, a f32)
fn C.sgl_c3b(r u8, g u8, b u8)
fn C.sgl_c4b(r u8, g u8, b u8, a u8)
fn C.sgl_c1i(rgba u32)
fn C.sgl_point_size(s f32)
// define primitives, each begin/end is one draw command
fn C.sgl_begin_points()
fn C.sgl_begin_lines()
fn C.sgl_begin_line_strip()
fn C.sgl_begin_triangles()
fn C.sgl_begin_triangle_strip()
fn C.sgl_begin_quads()
fn C.sgl_v2f(x f32, y f32)
fn C.sgl_v3f(x f32, y f32, z f32)
fn C.sgl_v2f_t2f(x f32, y f32, u f32, v f32)
fn C.sgl_v3f_t2f(x f32, y f32, z f32, u f32, v f32)
fn C.sgl_v2f_c3f(x f32, y f32, r f32, g f32, b f32)
fn C.sgl_v2f_c3b(x f32, y f32, r u8, g u8, b u8)
fn C.sgl_v2f_c4f(x f32, y f32, r f32, g f32, b f32, a f32)
fn C.sgl_v2f_c4b(x f32, y f32, r u8, g u8, b u8, a u8)
fn C.sgl_v2f_c1i(x f32, y f32, rgba u32)
fn C.sgl_v3f_c3f(x f32, y f32, z f32, r f32, g f32, b f32)
fn C.sgl_v3f_c3b(x f32, y f32, z f32, r u8, g u8, b u8)
fn C.sgl_v3f_c4f(x f32, y f32, z f32, r f32, g f32, b f32, a f32)
fn C.sgl_v3f_c4b(x f32, y f32, z f32, r u8, g u8, b u8, a u8)
fn C.sgl_v3f_c1i(x f32, y f32, z f32, rgba u32)
fn C.sgl_v2f_t2f_c3f(x f32, y f32, u f32, v f32, r f32, g f32, b f32)
fn C.sgl_v2f_t2f_c3b(x f32, y f32, u f32, v f32, r u8, g u8, b u8)
fn C.sgl_v2f_t2f_c4f(x f32, y f32, u f32, v f32, r f32, g f32, b f32, a f32)
fn C.sgl_v2f_t2f_c4b(x f32, y f32, u f32, v f32, r u8, g u8, b u8, a u8)
fn C.sgl_v2f_t2f_c1i(x f32, y f32, u f32, v f32, rgba u32)
fn C.sgl_v3f_t2f_c3f(x f32, y f32, z f32, u f32, v f32, r f32, g f32, b f32)
fn C.sgl_v3f_t2f_c3b(x f32, y f32, z f32, u f32, v f32, r u8, g u8, b u8)
fn C.sgl_v3f_t2f_c4f(x f32, y f32, z f32, u f32, v f32, r f32, g f32, b f32, a f32)
fn C.sgl_v3f_t2f_c4b(x f32, y f32, z f32, u f32, v f32, r u8, g u8, b u8, a u8)
fn C.sgl_v3f_t2f_c1i(x f32, y f32, z f32, u f32, v f32, rgba u32)
fn C.sgl_end()
// render recorded commands
fn C.sgl_draw()
fn C.sgl_context_draw(ctx C.sgl_context)
+52
View File
@@ -0,0 +1,52 @@
module sgl
import sokol.gfx
@[typedef]
pub struct C.sgl_pipeline {
id u32
}
pub type Pipeline = C.sgl_pipeline
@[typedef]
pub struct C.sgl_context {
id u32
}
pub type Context = C.sgl_context
// ContextDesc
//
// Describes the initialization parameters of a rendering context.
// Creating additional contexts is useful if you want to render
// in separate sokol-gfx passes.
// ContextDesc is sgl_context_desc_t
pub type ContextDesc = C.sgl_context_desc_t
@[typedef]
pub struct C.sgl_context_desc_t {
max_vertices int // default: 64k
max_commands int // default: 16k
color_format gfx.PixelFormat // C.sg_pixel_format
depth_format gfx.PixelFormat // C.sg_pixel_format
sample_count int
}
pub type Desc = C.sgl_desc_t
@[typedef]
pub struct C.sgl_desc_t {
pub:
max_vertices int // size for vertex buffer
max_commands int // size of uniform- and command-buffers
context_pool_size int // max number of contexts (including default context), default: 4
pipeline_pool_size int // size of internal pipeline pool, default: 64
color_format gfx.PixelFormat // C.sg_pixel_format
depth_format gfx.PixelFormat // C.sg_pixel_format
sample_count int
face_winding gfx.FaceWinding // C.sg_face_winding // default front face winding is CCW
pub mut:
allocator C.sgl_allocator_t // optional memory allocation overrides (default: malloc/free)
logger C.sgl_logger_t // optional memory allocation overrides (default: SOKOL_LOG(message))
}
+12
View File
@@ -0,0 +1,12 @@
module sokol
import sokol.c as _
/* pub enum Key {
up = C.SAPP_KEYCODE_UP
left = C.SAPP_KEYCODE_LEFT
right = C.SAPP_KEYCODE_RIGHT
down = C.SAPP_KEYCODE_DOWN
escape = C.SAPP_KEYCODE_ESCAPE
space = C.SAPP_KEYCODE_SPACE
} */