examples: cleanup code duplication in examples/sokol/04_multi_shader_glsl/rt_glsl.v, document gg.m4 (#20978)

This commit is contained in:
Delyan Angelov 2024-03-08 11:39:23 +02:00 committed by GitHub
parent 8ddceabb0e
commit 4cf05083ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 173 additions and 459 deletions

View file

@ -1,22 +1,15 @@
/**********************************************************************
*
* Sokol 3d cube multishader demo
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Copyright (c) 2024 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* HOW TO COMPILE SHADERS:
* Run `v shader .` in this directory to compile the shaders.
* For more info and help with shader compilation see `docs.md` and `v help shader`.
*
* TODO:
* - frame counter
**********************************************************************/
import gg
import gg.m4
import gx
// import math
import sokol.sapp
import sokol.gfx
import sokol.sgl
@ -29,27 +22,23 @@ import time
fn C.rt_march_shader_desc(gfx.Backend) &gfx.ShaderDesc
fn C.rt_puppy_shader_desc(gfx.Backend) &gfx.ShaderDesc
const win_width = 800
const win_height = 800
const bg_color = gx.white
const start_ticks = time.ticks()
@[heap]
struct App {
mut:
gg &gg.Context = unsafe { nil }
texture gfx.Image
sampler gfx.Sampler
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
mouse_x int = 502
mouse_y int = 394
mouse_down bool
// glsl
cube_pip_glsl gfx.Pipeline
cube_bind gfx.Bindings
pipe map[string]gfx.Pipeline
bind map[string]gfx.Bindings
// time
ticks i64
}
/******************************************************************************
@ -60,45 +49,22 @@ fn create_texture(w int, h int, buf byteptr) (gfx.Image, gfx.Sampler) {
mut img_desc := gfx.ImageDesc{
width: w
height: h
num_mipmaps: 0
// min_filter: .linear
// mag_filter: .linear
// usage: .dynamic
// wrap_u: .clamp_to_edge
// wrap_v: .clamp_to_edge
label: &u8(0)
d3d11_texture: 0
}
// comment if .dynamic is enabled
img_desc.data.subimage[0][0] = gfx.Range{
ptr: buf
size: usize(sz)
}
sg_img := gfx.make_image(&img_desc)
mut smp_desc := gfx.SamplerDesc{
min_filter: .linear
mag_filter: .linear
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
}
sg_smp := gfx.make_sampler(&smp_desc)
return sg_img, sg_smp
}
// Use only if usage: .dynamic is enabled
fn update_text_texture(sg_img gfx.Image, w int, h int, buf byteptr) {
sz := w * h * 4
mut tmp_sbc := gfx.ImageData{}
tmp_sbc.subimage[0][0] = gfx.Range{
ptr: buf
size: usize(sz)
}
gfx.update_image(sg_img, &tmp_sbc)
}
/******************************************************************************
* Draw functions
******************************************************************************
@ -109,281 +75,108 @@ Cube vertex buffer with packed vertex formats for color and texture coords.
to floating point formats in the vertex shader inputs.
The reason is that D3D11 cannot convert from non-normalized
formats to floating point inputs (only to integer inputs),
and WebGL2 / GLES2 don't support integer vertex shader inputs.
and WebGL2 / GLES2 does not support integer vertex shader inputs.
*/
struct Vertex_t {
x f32
y f32
z f32
color u32
// u u16 // for compatibility with D3D11
// v u16 // for compatibility with D3D11
u f32
v f32
}
// march shader init
fn init_cube_glsl_m(mut app App) {
// cube vertex buffer
// d := u16(32767) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0)
c := u32(0xFFFFFF_FF) // color RGBA8
// vfmt off
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
// vfmt on
const vertices = cube_vertices()
mut vert_buffer_desc := gfx.BufferDesc{
label: c'cube-vertices'
}
unsafe { vmemset(&vert_buffer_desc, 0, int(sizeof(vert_buffer_desc))) }
vert_buffer_desc.size = usize(vertices.len * int(sizeof(Vertex_t)))
fn cube_vertices() []Vertex_t {
// cube vertex buffer
d := f32(1.0)
c := u32(0xFF_FF_FF_FF) // white color RGBA8
// vfmt off
// 6 faces, each defined by 4 vertices:
cube := [
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0}, Vertex_t{ 1.0, -1.0, -1.0, c, d, 0}, Vertex_t{ 1.0, 1.0, -1.0, c, d, d}, Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0}, Vertex_t{ 1.0, -1.0, 1.0, c, d, 0}, Vertex_t{ 1.0, 1.0, 1.0, c, d, d}, Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0}, Vertex_t{-1.0, 1.0, -1.0, c, d, 0}, Vertex_t{-1.0, 1.0, 1.0, c, d, d}, Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0}, Vertex_t{ 1.0, 1.0, -1.0, c, d, 0}, Vertex_t{ 1.0, 1.0, 1.0, c, d, d}, Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0}, Vertex_t{-1.0, -1.0, 1.0, c, d, 0}, Vertex_t{ 1.0, -1.0, 1.0, c, d, d}, Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0}, Vertex_t{-1.0, 1.0, 1.0, c, d, 0}, Vertex_t{ 1.0, 1.0, 1.0, c, d, d}, Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
// vfmt off
return cube
}
fn (mut app App) init_glsl_shader(shader_name string, shader_desc &gfx.ShaderDesc, indices []u16) {
mut vert_buffer_desc := gfx.BufferDesc{}
unsafe { vmemset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) }
vert_buffer_desc.label = c'cube-vertices'
vert_buffer_desc.size = usize(vertices.len) * sizeof(Vertex_t)
vert_buffer_desc.data = gfx.Range{
ptr: vertices.data
size: usize(vertices.len * int(sizeof(Vertex_t)))
size: vert_buffer_desc.size
}
vert_buffer_desc.@type = .vertexbuffer
vbuf := gfx.make_buffer(&vert_buffer_desc)
// create an index buffer for the cube
// vfmt off
indices := [
u16(0), 1, 2, 0, 2, 3,
6 , 5, 4, 7, 6, 4,
8 , 9, 10, 8, 10, 11,
/*
u16(14), 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20,
*/
]
// vfmt on
mut index_buffer_desc := gfx.BufferDesc{
label: c'cube-indices'
}
unsafe { vmemset(&index_buffer_desc, 0, int(sizeof(index_buffer_desc))) }
index_buffer_desc.size = usize(indices.len * int(sizeof(u16)))
mut index_buffer_desc := gfx.BufferDesc{}
unsafe { vmemset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) }
index_buffer_desc.label = c'cube-indices'
index_buffer_desc.size = usize(indices.len) * sizeof(u16)
index_buffer_desc.data = gfx.Range{
ptr: indices.data
size: usize(indices.len * int(sizeof(u16)))
size: index_buffer_desc.size
}
index_buffer_desc.@type = .indexbuffer
ibuf := gfx.make_buffer(&index_buffer_desc)
// create shader
shader := gfx.make_shader(C.rt_march_shader_desc(C.sg_query_backend()))
shader := gfx.make_shader(shader_desc)
mut pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) }
unsafe { vmemset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.label = c'glsl_shader pipeline'
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// vfmt off
// the constants [C.ATTR_vs_m_pos, C.ATTR_vs_m_color0, C.ATTR_vs_m_texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_m_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_m_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_m_pos].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_m_color0].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_m_texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_m_texcoord0].format = .short2n // u,v as u16
// vfmt on
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth = gfx.DepthState{
write_enabled: true
compare: .less_equal
}
pipdesc.cull_mode = .back
pipdesc.label = 'glsl_shader pipeline'.str
mut bind := gfx.Bindings{}
unsafe { vmemset(&bind, 0, int(sizeof(bind))) }
bind.vertex_buffers[0] = vbuf
bind.index_buffer = ibuf
bind.fs.images[C.SLOT_tex] = app.texture
bind.fs.samplers[C.SLOT_smp] = app.sampler
app.bind['march'] = bind
app.pipe['march'] = gfx.make_pipeline(&pipdesc)
println('GLSL March init DONE!')
}
// putty shader init
fn init_cube_glsl_p(mut app App) {
// cube vertex buffer
// d := u16(32767) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0)
c := u32(0xFFFFFF_FF) // color RGBA8
// vfmt off
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
// vfmt off
mut vert_buffer_desc := gfx.BufferDesc{label: c'cube-vertices'}
unsafe { vmemset(&vert_buffer_desc, 0, int(sizeof(vert_buffer_desc))) }
vert_buffer_desc.size = usize(vertices.len * int(sizeof(Vertex_t)))
vert_buffer_desc.data = gfx.Range{
ptr: vertices.data
size: usize(vertices.len * int(sizeof(Vertex_t)))
}
vert_buffer_desc.@type = .vertexbuffer
vbuf := gfx.make_buffer(&vert_buffer_desc)
// create an index buffer for the cube
// vfmt off
indices := [
/*
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
*/
u16(14), 13, 12, 15, 14, 12,
16 , 17, 18, 16, 18, 19,
22 , 21, 20, 23, 22, 20,
]
// vfmt on
mut index_buffer_desc := gfx.BufferDesc{
label: c'cube-indices'
}
unsafe { vmemset(&index_buffer_desc, 0, int(sizeof(index_buffer_desc))) }
index_buffer_desc.size = usize(indices.len * int(sizeof(u16)))
index_buffer_desc.data = gfx.Range{
ptr: indices.data
size: usize(indices.len * int(sizeof(u16)))
}
index_buffer_desc.@type = .indexbuffer
ibuf := gfx.make_buffer(&index_buffer_desc)
// create shader
shader := gfx.make_shader(C.rt_puppy_shader_desc(C.sg_query_backend()))
mut pipdesc := gfx.PipelineDesc{}
unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) }
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// vfmt off
// the constants [C.ATTR_vs_p_pos, C.ATTR_vs_p_color0, C.ATTR_vs_p_texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_p_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_p_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_p_texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_p_texcoord0].format = .short2n // u,v as u16
// vfmt on
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth = gfx.DepthState{
write_enabled: true
compare: .less_equal
}
pipdesc.cull_mode = .back
pipdesc.label = 'glsl_shader pipeline'.str
mut bind := gfx.Bindings{}
unsafe { vmemset(&bind, 0, int(sizeof(bind))) }
unsafe { vmemset(&bind, 0, sizeof(bind)) }
bind.vertex_buffers[0] = vbuf
bind.index_buffer = ibuf
bind.fs.images[C.SLOT_tex] = app.texture
bind.fs.samplers[C.SLOT_smp] = app.sampler
app.bind['puppy'] = bind
app.pipe['puppy'] = gfx.make_pipeline(&pipdesc)
println('GLSL Puppy init DONE!')
}
@[inline]
fn vec4(x f32, y f32, z f32, w f32) m4.Vec4 {
return m4.Vec4{
e: [x, y, z, w]!
}
app.bind[shader_name] = bind
app.pipe[shader_name] = gfx.make_pipeline(&pipdesc)
println('${@FN} for shader `${shader_name}` done.')
}
fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) m4.Mat4 {
proj := m4.perspective(60, w / h, 0.01, 10.0)
view := m4.look_at(vec4(f32(0.0), 0, 6, 0), vec4(f32(0), 0, 0, 0), vec4(f32(0), 1,
0, 0))
view := m4.look_at(m4.vec4(0.0, 0, 6, 0), m4.vec4(0, 0, 0, 0), m4.vec4(0, 1, 0, 0))
view_proj := view * proj
rxm := m4.rotate(m4.rad(rx), vec4(f32(1), 0, 0, 0))
rym := m4.rotate(m4.rad(ry), vec4(f32(0), 1, 0, 0))
rxm := m4.rotate(m4.rad(rx), m4.vec4(1, 0, 0, 0))
rym := m4.rotate(m4.rad(ry), m4.vec4(0, 1, 0, 0))
model := rym * rxm
scale_m := m4.scale(vec4(in_scale, in_scale, in_scale, 1))
scale_m := m4.scale(m4.vec4(in_scale, in_scale, in_scale, 1))
res := (scale_m * model) * view_proj
return res
}
// march triangles draw
fn draw_cube_glsl_m(app App) {
if app.init_flag == false {
return
}
fn (app &App) draw_glsl_shader(shader_name string) {
ws := gg.window_size_real_pixels()
ratio := f32(ws.width) / ws.height
dw := f32(ws.width / 2)
@ -392,8 +185,9 @@ fn draw_cube_glsl_m(app App) {
rot := [f32(app.mouse_y), f32(app.mouse_x)]
tr_matrix := calc_tr_matrices(dw, dh, rot[0], rot[1], 2.3)
gfx.apply_pipeline(app.pipe['march'])
gfx.apply_bindings(app.bind['march'])
// apply the pipeline and bindings
gfx.apply_pipeline(app.pipe[shader_name])
gfx.apply_bindings(app.bind[shader_name])
// Uniforms
// *** vertex shadeer uniforms ***
@ -406,8 +200,7 @@ fn draw_cube_glsl_m(app App) {
gfx.apply_uniforms(.vs, C.SLOT_vs_params_m, &vs_uniforms_range)
// *** fragment shader uniforms ***
time_ticks := f32(time.ticks() - app.ticks) / 1000
// vfmt off
time_ticks := f32(time.ticks() - start_ticks) / 1000
mut tmp_fs_params := [
f32(ws.width),
ws.height * ratio, // x,y resolution to pass to FS
@ -416,60 +209,7 @@ fn draw_cube_glsl_m(app App) {
// app.mouse_x, // mouse x
// ws.height - app.mouse_y*2, // mouse y scaled
time_ticks, // time as f32
app.frame_count, // frame count
0,
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
]!
// vfmt on
fs_uniforms_range := gfx.Range{
ptr: unsafe { &tmp_fs_params }
size: usize(sizeof(tmp_fs_params))
}
gfx.apply_uniforms(.fs, C.SLOT_fs_params_p, &fs_uniforms_range)
// 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw
gfx.draw(0, (3 * 2) * 3, 1)
}
// puppy triangles draw
fn draw_cube_glsl_p(app App) {
if app.init_flag == false {
return
}
ws := gg.window_size_real_pixels()
ratio := f32(ws.width) / ws.height
dw := f32(ws.width / 2)
dh := f32(ws.height / 2)
rot := [f32(app.mouse_y), f32(app.mouse_x)]
tr_matrix := calc_tr_matrices(dw, dh, rot[0], rot[1], 2.3)
// apply the pipeline and bindings
gfx.apply_pipeline(app.pipe['puppy'])
gfx.apply_bindings(app.bind['puppy'])
// Uniforms
// *** vertex shadeer uniforms ***
// passing the view matrix as uniform
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
vs_uniforms_range := gfx.Range{
ptr: &tr_matrix
size: usize(4 * 16)
}
gfx.apply_uniforms(.vs, C.SLOT_vs_params_p, &vs_uniforms_range)
// *** fragment shader uniforms ***
time_ticks := f32(time.ticks() - app.ticks) / 1000
mut tmp_fs_params := [
f32(ws.width),
ws.height * ratio, // x,y resolution to pass to FS
0,
0, // dont send mouse position
// app.mouse_x, // mouse x
// ws.height - app.mouse_y*2, // mouse y scaled
time_ticks, // time as f32
app.frame_count, // frame count
f32(app.gg.frame), // frame count
0,
0, // padding bytes , see "fs_params" struct paddings in rt_glsl.h
]!
@ -483,73 +223,37 @@ fn draw_cube_glsl_p(app App) {
gfx.draw(0, (3 * 2) * 3, 1)
}
fn draw_start_glsl(app App) {
if app.init_flag == false {
fn (mut app App) frame() {
mut pass_action := gfx.PassAction{}
pass_action.colors[0] = gfx.ColorAttachmentAction{
load_action: .clear
clear_value: gfx.Color{b: 0.9}
}
gfx.begin_pass(sapp.create_default_pass(pass_action))
if !app.init_flag {
return
}
ws := gg.window_size_real_pixels()
// ratio := f32(ws.width) / ws.height
// dw := f32(ws.width / 2)
// dh := f32(ws.height / 2)
gfx.apply_viewport(0, 0, ws.width, ws.height, true)
}
fn draw_end_glsl(app App) {
app.draw_glsl_shader('march')
app.draw_glsl_shader('puppy')
gfx.end_pass()
gfx.commit()
}
fn frame(mut app App) {
// clear
mut color_action := gfx.ColorAttachmentAction{
load_action: .clear
clear_value: gfx.Color{
r: 0.0
g: 0.0
b: 0.0
a: 1.0
}
}
mut pass_action := gfx.PassAction{}
pass_action.colors[0] = color_action
pass := sapp.create_default_pass(pass_action)
gfx.begin_pass(&pass)
/*
// glsl cube
if app.frame_count % 1 == 1{
draw_cube_glsl_m(app)
} else {
draw_cube_glsl_p(app)
}
*/
draw_start_glsl(app)
draw_cube_glsl_m(app)
draw_cube_glsl_p(app)
draw_end_glsl(app)
app.frame_count++
}
/******************************************************************************
* Init / Cleanup
******************************************************************************/
fn my_init(mut app App) {
// set max vertices,
// for a large number of the same type of object it is better use the instances!!
desc := sapp.create_desc()
gfx.setup(&desc)
sgl_desc := sgl.Desc{
max_vertices: 50 * 65536
}
sgl.setup(&sgl_desc)
fn (mut app App) on_init() {
// set max vertices, but note, that for a large number of the same type of object it is better use the instances!!
gfx.setup(sapp.create_desc())
sgl.setup(sgl.Desc{max_vertices: 50 * 65536})
// create chessboard texture 256*256 RGBA
w := 256
h := 256
sz := w * h * 4
tmp_txt := unsafe { malloc(sz) }
defer {
unsafe { free(tmp_txt) }
}
mut i := 0
for i < sz {
unsafe {
@ -557,40 +261,48 @@ fn my_init(mut app App) {
x := (i & 0xFF) >> 5 // 8 cell
// upper left corner
if x == 0 && y == 0 {
tmp_txt[i + 0] = u8(0xFF)
tmp_txt[i + 1] = u8(0)
tmp_txt[i + 2] = u8(0)
tmp_txt[i + 3] = u8(0xFF)
tmp_txt[i + 0] = 0xFF
tmp_txt[i + 1] = 0
tmp_txt[i + 2] = 0
tmp_txt[i + 3] = 0xFF
}
// low right corner
else if x == 7 && y == 7 {
tmp_txt[i + 0] = u8(0)
tmp_txt[i + 1] = u8(0xFF)
tmp_txt[i + 2] = u8(0)
tmp_txt[i + 3] = u8(0xFF)
tmp_txt[i + 0] = 0
tmp_txt[i + 1] = 0xFF
tmp_txt[i + 2] = 0
tmp_txt[i + 3] = 0xFF
} else {
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
tmp_txt[i + 0] = u8(col) // red
tmp_txt[i + 1] = u8(col) // green
tmp_txt[i + 2] = u8(col) // blue
tmp_txt[i + 3] = u8(0xFF) // alpha
col := if ((x + y) & 1) == 1 { u8(0xFF) } else { 128 }
tmp_txt[i + 0] = col // red
tmp_txt[i + 1] = col // green
tmp_txt[i + 2] = col // blue
tmp_txt[i + 3] = 0xFF // alpha
}
i += 4
}
}
app.texture, app.sampler = create_texture(w, h, tmp_txt)
unsafe { free(tmp_txt) }
// glsl
init_cube_glsl_m(mut app)
init_cube_glsl_p(mut app)
// vfmt off
app.init_glsl_shader('march', C.rt_march_shader_desc(C.sg_query_backend()), [
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
])
app.init_glsl_shader('puppy', C.rt_puppy_shader_desc(C.sg_query_backend()), [
u16(14), 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20,
])
// vfmt on
app.init_flag = true
}
/******************************************************************************
* events handling
******************************************************************************/
fn my_event_manager(mut ev gg.Event, mut app App) {
fn (mut app App) on_event(ev &gg.Event, x voidptr) {
if ev.typ == .mouse_down {
app.mouse_down = true
}
@ -608,21 +320,19 @@ fn my_event_manager(mut ev gg.Event, mut app App) {
app.mouse_y = int(touch_point.pos_y)
}
}
// eprintln('> app.mouse_x: ${app.mouse_x} | app.mouse_y: ${app.mouse_y}')
}
fn main() {
mut app := &App{}
app.gg = gg.new_context(
width: win_width
height: win_height
create_window: true
width: 800
height: 800
window_title: '3D Dual shader Cube - click and rotate with the mouse'
user_data: app
bg_color: bg_color
frame_fn: frame
init_fn: my_init
event_fn: my_event_manager
frame_fn: app.frame
init_fn: app.on_init
event_fn: app.on_event
)
app.ticks = time.ticks()
app.gg.run()
}

View file

@ -61,7 +61,6 @@ mut:
texture gfx.Image
sampler gfx.Sampler
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
scroll_y int
@ -563,7 +562,6 @@ fn frame(mut app App) {
}
app.gg.end()
app.frame_count++
}
// draw readable text

View file

@ -1,12 +1,8 @@
/**********************************************************************
*
* Simply vector/matrix utility
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Simple vector/matrix utility
* Copyright (c) 2024 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* TODO:
**********************************************************************/
module m4
@ -17,24 +13,28 @@ pub mut:
e [4]f32
}
/*********************************************************************
*
* Utility
*
*********************************************************************/
// str returns a `string` representation of `Vec4`.
pub fn (x Vec4) str() string {
return '|${x.e[0]:-6.3},${x.e[1]:-6.3},${x.e[2]:-6.3},${x.e[3]:-6.3}|'
}
// create a Vec4 function passing x,y,z as parameters. w is set to 1
// vec3 creates a Vec4 value, passing x,y,z as parameters. The w element is set to 1
@[inline]
pub fn vec3(x f32, y f32, z f32) Vec4 {
return Vec4{
e: [x, y, z, 1]!
}
}
// Check if two vector are equal using module precision
// vec4 creates a Vec4 value, based on the x,y,z,w parameters
@[inline]
pub fn vec4(x f32, y f32, z f32, w f32) Vec4 {
return Vec4{
e: [x, y, z, w]!
}
}
// is_equal checks if two vector are equal using the module precision (10e-7)
@[direct_array_access]
pub fn (x Vec4) is_equal(y Vec4) bool {
unsafe {
@ -47,45 +47,44 @@ pub fn (x Vec4) is_equal(y Vec4) bool {
}
}
// Remove all the raw zeros
// clean returns a new vector, based on `x`, but with all the values < precision, set to 0
@[direct_array_access]
pub fn (a Vec4) clean() Vec4 {
mut x := Vec4{}
for c, value in a.e {
pub fn (x Vec4) clean() Vec4 {
mut n := x
for c, value in x.e {
if f32_abs(value) < precision {
x.e[c] = 0
} else {
x.e[c] = value
n.e[c] = 0
}
}
return x
return n
}
// Set all elements to value
// copy sets all elements of `x` to `value`
pub fn (mut x Vec4) copy(value f32) {
x.e = [value, value, value, value]!
}
// Scale the vector using a scalar
// mul_scalar returns the result of multiplying the vector `x`, by the scalar `value`
@[inline]
pub fn (x Vec4) mul_scalar(value f32) Vec4 {
return Vec4{
e: [x.e[0] * value, x.e[1] * value, x.e[2] * value, x.e[3] * value]!
}
}
// Reciprocal of the vector
// inv returns the reciprocal of the vector `x`
pub fn (x Vec4) inv() Vec4 {
return Vec4{
e: [
if x.e[0] != 0 { 1.0 / x.e[0] } else { f32(0) },
if x.e[1] != 0 { 1.0 / x.e[1] } else { f32(0) },
if x.e[2] != 0 { 1.0 / x.e[2] } else { f32(0) },
if x.e[3] != 0 { 1.0 / x.e[3] } else { f32(0) },
if x.e[0] != 0 { 1.0 / x.e[0] } else { 0 },
if x.e[1] != 0 { 1.0 / x.e[1] } else { 0 },
if x.e[2] != 0 { 1.0 / x.e[2] } else { 0 },
if x.e[3] != 0 { 1.0 / x.e[3] } else { 0 },
]!
}
}
// Normalize the vector
// normalize returns a normalized form of the vector `x`
pub fn (x Vec4) normalize() Vec4 {
m := x.mod()
if m == 0 {
@ -101,7 +100,7 @@ pub fn (x Vec4) normalize() Vec4 {
}
}
// Normalize only xyz, w set to 0
// normalize3 returns a normalized form of the vector `x`, where the w element is set to 0
pub fn (x Vec4) normalize3() Vec4 {
m := x.mod3()
if m == 0 {
@ -117,22 +116,23 @@ pub fn (x Vec4) normalize3() Vec4 {
}
}
// Module of the vector xyzw
// mod returns a module of the vector `x`
@[inline]
pub fn (x Vec4) mod() f32 {
return f32(math.sqrt(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2] + x.e[3] * x.e[3]))
return math.sqrtf(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2] + x.e[3] * x.e[3])
}
// Module for 3d vector xyz, w ignored
// mod3 returns a module of the 3d vector `x`, ignoring the value of its w element
@[inline]
pub fn (x Vec4) mod3() f32 {
return f32(math.sqrt(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2]))
return math.sqrtf(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2])
}
/*********************************************************************
*
* Math
*
*********************************************************************/
// Return a zero vector
// zero_v4 returns a zero vector (all elements set to 0)
@[inline]
pub fn zero_v4() Vec4 {
return Vec4{
e: [
@ -144,7 +144,8 @@ pub fn zero_v4() Vec4 {
}
}
// Return all one vector
// one_v4 returns a vector, where all elements are set to 1
@[inline]
pub fn one_v4() Vec4 {
return Vec4{
e: [
@ -156,7 +157,7 @@ pub fn one_v4() Vec4 {
}
}
// Return a blank vector
// blank_v4 returns a vector, where all elements are set to 0, except `w`, which is set to 1
pub fn blank_v4() Vec4 {
return Vec4{
e: [
@ -168,7 +169,8 @@ pub fn blank_v4() Vec4 {
}
}
// Set all elements to value
// set_v4 returns a vector, where all elements are set to `value`
@[inline]
pub fn set_v4(value f32) Vec4 {
return Vec4{
e: [
@ -180,17 +182,17 @@ pub fn set_v4(value f32) Vec4 {
}
}
// Sum of all the elements
// sum returns a sum of all the elements
@[inline]
pub fn (x Vec4) sum() f32 {
return x.e[0] + x.e[1] + x.e[2] + x.e[3]
}
/*********************************************************************
*
* Operators
*
*********************************************************************/
// Addition
// + returns `a` + `b` (corresponding elements are addded)
@[inline]
pub fn (a Vec4) + (b Vec4) Vec4 {
return Vec4{
e: [
@ -202,7 +204,8 @@ pub fn (a Vec4) + (b Vec4) Vec4 {
}
}
// Subtraction
// - returns `a` + `b` (corresponding elements are subtracted)
@[inline]
pub fn (a Vec4) - (b Vec4) Vec4 {
return Vec4{
e: [
@ -214,12 +217,14 @@ pub fn (a Vec4) - (b Vec4) Vec4 {
}
}
// Dot product
// * returns `a` * `b` (corresponding elements are multiplied, then summed), i.e. a dot product
@[inline]
pub fn (a Vec4) * (b Vec4) f32 {
return a.e[0] * b.e[0] + a.e[1] * b.e[1] + a.e[2] * b.e[2] + a.e[3] * b.e[3]
}
// Cross product
// % returns a cross product of the vectors `a` and `b`
@[inline]
pub fn (a Vec4) % (b Vec4) Vec4 {
return Vec4{
e: [
@ -231,7 +236,8 @@ pub fn (a Vec4) % (b Vec4) Vec4 {
}
}
// Components multiplication
// mul_vec4 returns a vectore, where the corresponding `x` and `y` elements are multiplied
@[inline]
pub fn (x Vec4) mul_vec4(y Vec4) Vec4 {
return Vec4{
e: [