diff options
Diffstat (limited to 'v_windows/v/examples/sokol/01_cubes/cube.v')
-rw-r--r-- | v_windows/v/examples/sokol/01_cubes/cube.v | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/v_windows/v/examples/sokol/01_cubes/cube.v b/v_windows/v/examples/sokol/01_cubes/cube.v new file mode 100644 index 0000000..c933dbf --- /dev/null +++ b/v_windows/v/examples/sokol/01_cubes/cube.v @@ -0,0 +1,432 @@ +/********************************************************************** +* +* Sokol 3d cube demo +* +* Copyright (c) 2021 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: +* - add instancing +* - add an exampel with shaders +**********************************************************************/ +import gg +import gx +import math +import sokol.sapp +import sokol.gfx +import sokol.sgl + +const ( + win_width = 800 + win_height = 800 + bg_color = gx.white +) + +struct App { +mut: + gg &gg.Context + pip_3d C.sgl_pipeline + texture C.sg_image + init_flag bool + frame_count int + mouse_x int = -1 + mouse_y int = -1 +} + +/****************************************************************************** +* +* Texture functions +* +******************************************************************************/ +fn create_texture(w int, h int, buf &u8) C.sg_image { + sz := w * h * 4 + mut img_desc := C.sg_image_desc{ + 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: &byte(0) + d3d11_texture: 0 + } + // commen if .dynamic is enabled + img_desc.data.subimage[0][0] = C.sg_range{ + ptr: buf + size: size_t(sz) + } + + sg_img := C.sg_make_image(&img_desc) + return sg_img +} + +fn destroy_texture(sg_img C.sg_image) { + C.sg_destroy_image(sg_img) +} + +// Use only if usage: .dynamic is enabled +fn update_text_texture(sg_img C.sg_image, w int, h int, buf &byte) { + sz := w * h * 4 + mut tmp_sbc := C.sg_image_data{} + tmp_sbc.subimage[0][0] = C.sg_range{ + ptr: buf + size: size_t(sz) + } + C.sg_update_image(sg_img, &tmp_sbc) +} + +/****************************************************************************** +* +* Draw functions +* +******************************************************************************/ +fn draw_triangle() { + sgl.defaults() + sgl.begin_triangles() + sgl.v2f_c3b(0.0, 0.5, 255, 0, 0) + sgl.v2f_c3b(-0.5, -0.5, 0, 0, 255) + sgl.v2f_c3b(0.5, -0.5, 0, 255, 0) + sgl.end() +} + +// vertex specification for a cube with colored sides and texture coords +fn cube() { + sgl.begin_quads() + // edge color + sgl.c3f(1.0, 0.0, 0.0) + // edge coord + // x,y,z, texture cord: u,v + sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0) + sgl.v3f_t2f(1.0, 1.0, -1.0, 1.0, 1.0) + sgl.v3f_t2f(1.0, -1.0, -1.0, 1.0, -1.0) + sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0) + sgl.c3f(0.0, 1.0, 0.0) + sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0) + sgl.v3f_t2f(1.0, -1.0, 1.0, 1.0, 1.0) + sgl.v3f_t2f(1.0, 1.0, 1.0, 1.0, -1.0) + sgl.v3f_t2f(-1.0, 1.0, 1.0, -1.0, -1.0) + sgl.c3f(0.0, 0.0, 1.0) + sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0) + sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0) + sgl.v3f_t2f(-1.0, 1.0, -1.0, 1.0, -1.0) + sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0) + sgl.c3f(1.0, 0.5, 0.0) + sgl.v3f_t2f(1.0, -1.0, 1.0, -1.0, 1.0) + sgl.v3f_t2f(1.0, -1.0, -1.0, 1.0, 1.0) + sgl.v3f_t2f(1.0, 1.0, -1.0, 1.0, -1.0) + sgl.v3f_t2f(1.0, 1.0, 1.0, -1.0, -1.0) + sgl.c3f(0.0, 0.5, 1.0) + sgl.v3f_t2f(1.0, -1.0, -1.0, -1.0, 1.0) + sgl.v3f_t2f(1.0, -1.0, 1.0, 1.0, 1.0) + sgl.v3f_t2f(-1.0, -1.0, 1.0, 1.0, -1.0) + sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0) + sgl.c3f(1.0, 0.0, 0.5) + sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0) + sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0) + sgl.v3f_t2f(1.0, 1.0, 1.0, 1.0, -1.0) + sgl.v3f_t2f(1.0, 1.0, -1.0, -1.0, -1.0) + sgl.end() +} + +fn draw_cubes(app App) { + rot := [f32(1.0) * (app.frame_count % 360), 0.5 * f32(app.frame_count % 360)] + // rot := [f32(app.mouse_x), f32(app.mouse_y)] + + sgl.defaults() + sgl.load_pipeline(app.pip_3d) + + sgl.matrix_mode_projection() + sgl.perspective(sgl.rad(45.0), 1.0, 0.1, 100.0) + + sgl.matrix_mode_modelview() + sgl.translate(0.0, 0.0, -12.0) + sgl.rotate(sgl.rad(rot[0]), 1.0, 0.0, 0.0) + sgl.rotate(sgl.rad(rot[1]), 0.0, 1.0, 0.0) + cube() + sgl.push_matrix() + sgl.translate(0.0, 0.0, 3.0) + sgl.scale(0.5, 0.5, 0.5) + sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0) + sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0) + cube() + sgl.push_matrix() + sgl.translate(0.0, 0.0, 3.0) + sgl.scale(0.5, 0.5, 0.5) + sgl.rotate(-3.0 * sgl.rad(2 * rot[0]), 1.0, 0.0, 0.0) + sgl.rotate(3.0 * sgl.rad(2 * rot[1]), 0.0, 0.0, 1.0) + cube() + sgl.pop_matrix() + sgl.pop_matrix() +} + +fn cube_t(r f32, g f32, b f32) { + sgl.begin_quads() + // edge color + sgl.c3f(r, g, b) + // edge coord + // x,y,z, texture cord: u,v + sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0, 0.25) + sgl.v3f_t2f(1.0, 1.0, -1.0, 0.25, 0.25) + sgl.v3f_t2f(1.0, -1.0, -1.0, 0.25, 0.0) + sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0, 0.0) + sgl.c3f(r, g, b) + sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0, 0.25) + sgl.v3f_t2f(1.0, -1.0, 1.0, 0.25, 0.25) + sgl.v3f_t2f(1.0, 1.0, 1.0, 0.25, 0.0) + sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.0, 0.0) + sgl.c3f(r, g, b) + sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0, 0.25) + sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25) + sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.25, 0.0) + sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0, 0.0) + sgl.c3f(r, g, b) + sgl.v3f_t2f(1.0, -1.0, 1.0, 0.0, 0.25) + sgl.v3f_t2f(1.0, -1.0, -1.0, 0.25, 0.25) + sgl.v3f_t2f(1.0, 1.0, -1.0, 0.25, 0.0) + sgl.v3f_t2f(1.0, 1.0, 1.0, 0.0, 0.0) + sgl.c3f(r, g, b) + sgl.v3f_t2f(1.0, -1.0, -1.0, 0.0, 0.25) + sgl.v3f_t2f(1.0, -1.0, 1.0, 0.25, 0.25) + sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.25, 0.0) + sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0, 0.0) + sgl.c3f(r, g, b) + sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0, 0.25) + sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25) + sgl.v3f_t2f(1.0, 1.0, 1.0, 0.25, 0.0) + sgl.v3f_t2f(1.0, 1.0, -1.0, 0.0, 0.0) + sgl.end() +} + +fn draw_texture_cubes(app App) { + rot := [f32(app.mouse_x), f32(app.mouse_y)] + sgl.defaults() + sgl.load_pipeline(app.pip_3d) + + sgl.enable_texture() + sgl.texture(app.texture) + + sgl.matrix_mode_projection() + sgl.perspective(sgl.rad(45.0), 1.0, 0.1, 100.0) + + sgl.matrix_mode_modelview() + sgl.translate(0.0, 0.0, -12.0) + sgl.rotate(sgl.rad(rot[0]), 1.0, 0.0, 0.0) + sgl.rotate(sgl.rad(rot[1]), 0.0, 1.0, 0.0) + cube_t(1, 1, 1) + sgl.push_matrix() + sgl.translate(0.0, 0.0, 3.0) + sgl.scale(0.5, 0.5, 0.5) + sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0) + sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0) + cube_t(1, 1, 1) + sgl.push_matrix() + sgl.translate(0.0, 0.0, 3.0) + sgl.scale(0.5, 0.5, 0.5) + sgl.rotate(-3.0 * sgl.rad(2 * rot[0]), 1.0, 0.0, 0.0) + sgl.rotate(3.0 * sgl.rad(2 * rot[1]), 0.0, 0.0, 1.0) + cube_t(1, 1, 1) + sgl.pop_matrix() + sgl.pop_matrix() + + sgl.disable_texture() +} + +fn cube_field(app App) { + rot := [f32(app.mouse_x), f32(app.mouse_y)] + xyz_sz := f32(2.0) + field_size := 20 + + sgl.defaults() + sgl.load_pipeline(app.pip_3d) + + sgl.enable_texture() + sgl.texture(app.texture) + + sgl.matrix_mode_projection() + sgl.perspective(sgl.rad(45.0), 1.0, 0.1, 200.0) + + sgl.matrix_mode_modelview() + + sgl.translate(field_size, 0.0, -120.0) + sgl.rotate(sgl.rad(rot[0]), 0.0, 1.0, 0.0) + sgl.rotate(sgl.rad(rot[1]), 1.0, 0.0, 0.0) + + // draw field_size*field_size cubes + for y in 0 .. field_size { + for x in 0 .. field_size { + sgl.push_matrix() + z := f32(math.cos(f32(x * 2) / field_size) * math.sin(f32(y * 2) / field_size) * xyz_sz) * (xyz_sz * 5) + sgl.translate(x * xyz_sz, z, y * xyz_sz) + cube_t(f32(f32(x) / field_size), f32(f32(y) / field_size), 1) + sgl.pop_matrix() + } + } + sgl.disable_texture() +} + +fn frame(mut app App) { + ws := gg.window_size_real_pixels() + ratio := f32(ws.width) / ws.height + dw := ws.width + dh := ws.height + ww := int(dh / 3) // not a bug + hh := int(dh / 3) + x0 := int(f32(dw) * 0.05) + // x1 := dw/2 + y0 := 0 + y1 := int(f32(dh) * 0.5) + + app.gg.begin() + // sgl.defaults() + + // 2d triangle + sgl.viewport(x0, y0, ww, hh, true) + draw_triangle() + + // colored cubes with viewport + sgl.viewport(x0, y1, ww, hh, true) + draw_cubes(app) + + // textured cubed with viewport + sgl.viewport(0, int(dh / 5), dw, int(dh * ratio), true) + draw_texture_cubes(app) + + // textured field of cubes with viewport + sgl.viewport(0, int(dh / 5), dw, int(dh * ratio), true) + cube_field(app) + + app.frame_count++ + + app.gg.end() +} + +/****************************************************************************** +* +* Init / Cleanup +* +******************************************************************************/ +fn my_init(mut app App) { + app.init_flag = true + + // 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 := C.sgl_desc_t{ + max_vertices: 50 * 65536 + } + sgl.setup(&sgl_desc) + + // 3d pipeline + mut pipdesc := C.sg_pipeline_desc{} + unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } + + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } + } + pipdesc.colors[0] = color_state + + pipdesc.depth = C.sg_depth_state{ + write_enabled: true + compare: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL) + } + pipdesc.cull_mode = .back + app.pip_3d = sgl.make_pipeline(&pipdesc) + + // create chessboard texture 256*256 RGBA + w := 256 + h := 256 + sz := w * h * 4 + tmp_txt := unsafe { malloc(sz) } + mut i := 0 + for i < sz { + unsafe { + y := (i >> 0x8) >> 5 // 8 cell + x := (i & 0xFF) >> 5 // 8 cell + // upper left corner + if x == 0 && y == 0 { + tmp_txt[i] = byte(0xFF) + tmp_txt[i + 1] = byte(0) + tmp_txt[i + 2] = byte(0) + tmp_txt[i + 3] = byte(0xFF) + } + // low right corner + else if x == 7 && y == 7 { + tmp_txt[i] = byte(0) + tmp_txt[i + 1] = byte(0xFF) + tmp_txt[i + 2] = byte(0) + tmp_txt[i + 3] = byte(0xFF) + } else { + col := if ((x + y) & 1) == 1 { 0xFF } else { 0 } + tmp_txt[i] = byte(col) // red + tmp_txt[i + 1] = byte(col) // green + tmp_txt[i + 2] = byte(col) // blue + tmp_txt[i + 3] = byte(0xFF) // alpha + } + i += 4 + } + } + unsafe { + app.texture = create_texture(w, h, tmp_txt) + free(tmp_txt) + } +} + +fn cleanup(mut app App) { + gfx.shutdown() +} + +/****************************************************************************** +* +* event +* +******************************************************************************/ +fn my_event_manager(mut ev gg.Event, mut app App) { + if ev.typ == .mouse_move { + app.mouse_x = int(ev.mouse_x) + app.mouse_y = int(ev.mouse_y) + } + if ev.typ == .touches_began || ev.typ == .touches_moved { + if ev.num_touches > 0 { + touch_point := ev.touches[0] + app.mouse_x = int(touch_point.pos_x) + app.mouse_y = int(touch_point.pos_y) + } + } +} + +/****************************************************************************** +* +* Main +* +******************************************************************************/ +// is needed for easier diagnostics on windows +[console] +fn main() { + // App init + mut app := &App{ + gg: 0 + } + + app.gg = gg.new_context( + width: win_width + height: win_height + create_window: true + window_title: '3D Cube Demo' + user_data: app + bg_color: bg_color + frame_fn: frame + init_fn: my_init + cleanup_fn: cleanup + event_fn: my_event_manager + ) + + app.gg.run() +} |