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

+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) }
}