gg: support `VGG_STOP_AT_FRAME=120 VGG_SCREENSHOT_FOLDER=. VGG_SCREENSHOT_FRAMES=10,20,30 ./v -d gg_record run examples/gg/bezier_anim.v` (#12767)
parent
85f3372a32
commit
0021fbbaa9
|
@ -181,7 +181,7 @@ fn get_all_commands() []Command {
|
|||
}
|
||||
$if macos || linux {
|
||||
res << Command{
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror -I "$vroot/thirdparty/stdatomic/nix" v.c -lpthread && rm -rf a.out'
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror -I "$vroot/thirdparty/stdatomic/nix" v.c -lpthread -lm && rm -rf a.out'
|
||||
label: 'v.c should be buildable with no warnings...'
|
||||
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
||||
rmfile: 'v.c'
|
||||
|
|
|
@ -106,6 +106,8 @@ fn gg_frame_fn(user_data voidptr) {
|
|||
// return
|
||||
}
|
||||
|
||||
ctx.record_frame()
|
||||
|
||||
if ctx.ui_mode && !ctx.needs_refresh {
|
||||
// Draw 3 more frames after the "stop refresh" command
|
||||
ctx.ticks++
|
||||
|
@ -250,8 +252,8 @@ fn gg_fail_fn(msg &char, user_data voidptr) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (gg &Context) run() {
|
||||
sapp.run(&gg.window)
|
||||
pub fn (ctx &Context) run() {
|
||||
sapp.run(&ctx.window)
|
||||
}
|
||||
|
||||
// quit closes the context window and exits the event loop for it
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
module gg
|
||||
|
||||
import os
|
||||
import sokol.sapp
|
||||
|
||||
[heap]
|
||||
pub struct SSRecorderSettings {
|
||||
pub mut:
|
||||
stop_at_frame i64 = -1
|
||||
screenshot_frames []u64
|
||||
screenshot_folder string
|
||||
screenshot_prefix string
|
||||
}
|
||||
|
||||
const recorder_settings = new_gg_recorder_settings()
|
||||
|
||||
fn new_gg_recorder_settings() &SSRecorderSettings {
|
||||
$if gg_record ? {
|
||||
stop_frame := os.getenv_opt('VGG_STOP_AT_FRAME') or { '-1' }.i64()
|
||||
frames := os.getenv('VGG_SCREENSHOT_FRAMES').split_any(',').map(it.u64())
|
||||
folder := os.getenv('VGG_SCREENSHOT_FOLDER')
|
||||
prefix := os.join_path_single(folder, os.file_name(os.executable()).all_before('.') + '_')
|
||||
return &SSRecorderSettings{
|
||||
stop_at_frame: stop_frame
|
||||
screenshot_frames: frames
|
||||
screenshot_folder: folder
|
||||
screenshot_prefix: prefix
|
||||
}
|
||||
} $else {
|
||||
return &SSRecorderSettings{}
|
||||
}
|
||||
}
|
||||
|
||||
[if gg_record ?]
|
||||
pub fn (mut ctx Context) record_frame() {
|
||||
if ctx.frame in gg.recorder_settings.screenshot_frames {
|
||||
screenshot_file_path := '$gg.recorder_settings.screenshot_prefix${ctx.frame}.png'
|
||||
$if gg_record_trace ? {
|
||||
eprintln('>>> screenshoting $screenshot_file_path')
|
||||
}
|
||||
sapp.screenshot_png(screenshot_file_path) or { panic(err) }
|
||||
}
|
||||
if ctx.frame == gg.recorder_settings.stop_at_frame {
|
||||
$if gg_record_trace ? {
|
||||
eprintln('>>> exiting at frame $ctx.frame')
|
||||
}
|
||||
exit(0)
|
||||
}
|
||||
}
|
|
@ -1,50 +1,54 @@
|
|||
module sapp
|
||||
|
||||
import os
|
||||
import stbi
|
||||
|
||||
// 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.
|
||||
[inline]
|
||||
pub fn screenshot(path string) ? {
|
||||
if !path.ends_with('.ppm') {
|
||||
return error(@MOD + '.' + @FN + ' currently only supports .ppm files.')
|
||||
}
|
||||
|
||||
w := width()
|
||||
h := height()
|
||||
|
||||
size := w * h * 4 //
|
||||
mut pixels := []byte{len: size, init: 0}
|
||||
|
||||
C.v_sapp_gl_read_rgba_pixels(0, 0, w, h, pixels.data)
|
||||
|
||||
// TODO use separate thread for writing the data
|
||||
// TODO use stbi to support more formats
|
||||
// stbi.write_png(path, w, h, components, pixels.data, 3 * w)
|
||||
// stbi.write_tga(path, w, h, components, pixels.data)
|
||||
write_rgba_to_ppm(path, w, h, 4, pixels) ?
|
||||
|
||||
unsafe {
|
||||
pixels.free()
|
||||
return screenshot_ppm(path)
|
||||
}
|
||||
|
||||
// screenshot_ppm takes a screenshot of the current window 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 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 []byte) ? {
|
||||
fn write_rgba_to_ppm(path string, w int, h int, components int, pixels &byte) ? {
|
||||
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 ') ?
|
||||
}
|
||||
}
|
||||
f_out.close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
module sapp
|
||||
|
||||
[heap]
|
||||
pub struct Screenshot {
|
||||
width int
|
||||
height int
|
||||
size int
|
||||
mut:
|
||||
pixels &byte
|
||||
}
|
||||
|
||||
[manualfree]
|
||||
pub fn screenshot_window() &Screenshot {
|
||||
img_width := width()
|
||||
img_height := height()
|
||||
img_size := img_width * img_height * 4
|
||||
img_pixels := unsafe { &byte(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 = &byte(0)
|
||||
}
|
||||
}
|
||||
|
||||
// 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) }
|
||||
}
|
Loading…
Reference in New Issue