examples: add examples/gg/random.v demonstrating how to stream images/pixels

pull/10566/head
Delyan Angelov 2021-06-24 17:45:14 +03:00
parent 4bfe76123a
commit b2391424d9
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
5 changed files with 135 additions and 5 deletions

View File

@ -0,0 +1,63 @@
import gg
import time
const pwidth = 800
const pheight = 600
const pbytes = 4
struct AppState {
mut:
gg &gg.Context = 0
istream_idx int
pixels [pwidth][pheight]u32
}
[direct_array_access]
fn (mut state AppState) update() {
mut rcolor := u64(state.gg.frame)
for {
for x in 0 .. pwidth {
for y in 0 .. pheight {
rcolor = rcolor * 1664525 + 1013904223
state.pixels[x][y] = u32(rcolor & 0x0000_0000_FFFF_FFFF) | 0x1010AFFF
}
}
time.sleep(33 * time.millisecond)
}
}
fn (mut state AppState) draw() {
mut istream_image := state.gg.get_cached_image_by_idx(state.istream_idx)
istream_image.update_pixel_data(&state.pixels)
size := gg.window_size()
state.gg.draw_image(0, 0, size.width, size.height, istream_image)
}
// gg callbacks:
fn graphics_init(mut state AppState) {
state.istream_idx = state.gg.new_streaming_image(pwidth, pheight, pbytes)
}
fn graphics_frame(mut state AppState) {
state.gg.begin()
state.draw()
state.gg.end()
}
fn main() {
mut state := &AppState{}
state.gg = gg.new_context(
width: 800
height: 600
create_window: true
window_title: 'Random Static'
init_fn: graphics_init
frame_fn: graphics_frame
user_data: state
)
go state.update()
state.gg.run()
}

View File

@ -16,6 +16,10 @@ pub fn ptr_str(ptr voidptr) string {
return buf1 return buf1
} }
pub fn (x size_t) str() string {
return u64(x).str()
}
pub fn (cptr &char) str() string { pub fn (cptr &char) str() string {
return u64(cptr).hex() return u64(cptr).hex()
} }

View File

@ -241,8 +241,10 @@ fn gg_init_sokol_window(user_data voidptr) {
} }
for i in 0 .. g.image_cache.len { for i in 0 .. g.image_cache.len {
if g.image_cache[i].simg.id == 0 {
g.image_cache[i].init_sokol_image() g.image_cache[i].init_sokol_image()
} }
}
} }
fn gg_frame_fn(user_data voidptr) { fn gg_frame_fn(user_data voidptr) {

View File

@ -4,7 +4,7 @@ module gg
// import gx // import gx
// import sokol.sapp // import sokol.sapp
// import sokol.gfx import sokol.gfx
import os import os
import sokol import sokol
import sokol.sgl import sokol.sgl
@ -153,6 +153,17 @@ pub fn (mut ctx Context) create_image_from_byte_array(b []byte) Image {
return ctx.create_image_from_memory(b.data, b.len) return ctx.create_image_from_memory(b.data, b.len)
} }
pub fn (mut ctx Context) cache_image(img Image) int {
ctx.image_cache << img
image_idx := ctx.image_cache.len - 1
ctx.image_cache[image_idx].id = image_idx
return image_idx
}
pub fn (mut ctx Context) get_cached_image_by_idx(image_idx int) &Image {
return &ctx.image_cache[image_idx]
}
pub fn (mut img Image) init_sokol_image() &Image { pub fn (mut img Image) init_sokol_image() &Image {
// println('\n init sokol image $img.path ok=$img.simg_ok') // println('\n init sokol image $img.path ok=$img.simg_ok')
mut img_desc := C.sg_image_desc{ mut img_desc := C.sg_image_desc{
@ -161,7 +172,7 @@ pub fn (mut img Image) init_sokol_image() &Image {
num_mipmaps: 0 num_mipmaps: 0
wrap_u: .clamp_to_edge wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge wrap_v: .clamp_to_edge
label: &char(0) label: img.path.str
d3d11_texture: 0 d3d11_texture: 0
} }
img_desc.data.subimage[0][0] = C.sg_range{ img_desc.data.subimage[0][0] = C.sg_range{
@ -174,6 +185,53 @@ pub fn (mut img Image) init_sokol_image() &Image {
return img return img
} }
// new_streaming_image returns a cached `image_idx` of a special image, that
// can be updated *each frame* by calling: gg.update_pixel_data(image_idx, buf)
// ... where buf is a pointer to the actual pixel data for the image.
// NB: you still need to call app.gg.draw_image after that, to actually draw it.
pub fn (mut ctx Context) new_streaming_image(w int, h int, channels int) int {
mut img := Image{}
img.width = w
img.height = h
img.nr_channels = channels // 4 bytes per pixel for .rgba8, see pixel_format
mut img_desc := C.sg_image_desc{
width: img.width
height: img.height
pixel_format: .rgba8
num_slices: 1
num_mipmaps: 1
usage: .stream
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
min_filter: .linear
mag_filter: .linear
label: img.path.str
}
// Sokol requires that streamed images have NO .ptr/.size initially:
img_desc.data.subimage[0][0] = C.sg_range{
ptr: 0
size: size_t(0)
}
img.simg = C.sg_make_image(&img_desc)
img.simg_ok = true
img.ok = true
img_idx := ctx.cache_image(img)
return img_idx
}
// update_pixel_data is a helper for working with image streams (i.e. images,
// that are updated dynamically by the CPU on each frame)
pub fn (mut ctx Context) update_pixel_data(cached_image_idx int, buf &byte) {
ctx.get_cached_image_by_idx(cached_image_idx).update_pixel_data(buf)
}
pub fn (mut img Image) update_pixel_data(buf &byte) {
mut data := C.sg_image_data{}
data.subimage[0][0].ptr = buf
data.subimage[0][0].size = size_t(img.width * img.height * img.nr_channels)
gfx.update_image(img.simg, &data)
}
// draw_image_with_config takes in a config that details how the // draw_image_with_config takes in a config that details how the
// provided image should be drawn onto the screen // provided image should be drawn onto the screen
pub fn (ctx &Context) draw_image_with_config(config DrawImageConfig) { pub fn (ctx &Context) draw_image_with_config(config DrawImageConfig) {

View File

@ -396,10 +396,13 @@ pub fn (i C.sg_image) free() {
C.sg_destroy_image(i) C.sg_destroy_image(i)
} }
pub const sg_cubeface_num = 6
pub const sg_max_mipmaps = 16
pub struct C.sg_image_data { pub struct C.sg_image_data {
pub mut: pub mut:
// subimage [C.SG_CUBEFACE_NUM][C.SG_MAX_MIPMAPS]C.sg_range subimage [sg_cubeface_num][sg_max_mipmaps]C.sg_range
subimage [6][16]C.sg_range
} }
pub struct C.sg_features { pub struct C.sg_features {