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 {
|
$if macos || linux {
|
||||||
res << Command{
|
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...'
|
label: 'v.c should be buildable with no warnings...'
|
||||||
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
||||||
rmfile: 'v.c'
|
rmfile: 'v.c'
|
||||||
|
|
|
@ -106,6 +106,8 @@ fn gg_frame_fn(user_data voidptr) {
|
||||||
// return
|
// return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.record_frame()
|
||||||
|
|
||||||
if ctx.ui_mode && !ctx.needs_refresh {
|
if ctx.ui_mode && !ctx.needs_refresh {
|
||||||
// Draw 3 more frames after the "stop refresh" command
|
// Draw 3 more frames after the "stop refresh" command
|
||||||
ctx.ticks++
|
ctx.ticks++
|
||||||
|
@ -250,8 +252,8 @@ fn gg_fail_fn(msg &char, user_data voidptr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (gg &Context) run() {
|
pub fn (ctx &Context) run() {
|
||||||
sapp.run(&gg.window)
|
sapp.run(&ctx.window)
|
||||||
}
|
}
|
||||||
|
|
||||||
// quit closes the context window and exits the event loop for it
|
// 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
|
module sapp
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import stbi
|
||||||
|
|
||||||
// v_sapp_gl_read_rgba_pixels reads pixles from the OpenGL buffer into `pixels`.
|
// 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)
|
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.
|
// screenshot takes a screenshot of the current window.
|
||||||
[inline]
|
|
||||||
pub fn screenshot(path string) ? {
|
pub fn screenshot(path string) ? {
|
||||||
if !path.ends_with('.ppm') {
|
if !path.ends_with('.ppm') {
|
||||||
return error(@MOD + '.' + @FN + ' currently only supports .ppm files.')
|
return error(@MOD + '.' + @FN + ' currently only supports .ppm files.')
|
||||||
}
|
}
|
||||||
|
return screenshot_ppm(path)
|
||||||
|
}
|
||||||
|
|
||||||
w := width()
|
// screenshot_ppm takes a screenshot of the current window as a .ppm file
|
||||||
h := height()
|
[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() }
|
||||||
|
}
|
||||||
|
|
||||||
size := w * h * 4 //
|
// screenshot_png takes a screenshot of the current window as a .png file
|
||||||
mut pixels := []byte{len: size, init: 0}
|
[manualfree]
|
||||||
|
pub fn screenshot_png(path string) ? {
|
||||||
C.v_sapp_gl_read_rgba_pixels(0, 0, w, h, pixels.data)
|
ss := screenshot_window()
|
||||||
|
stbi.set_flip_vertically_on_write(true)
|
||||||
// TODO use separate thread for writing the data
|
stbi.stbi_write_png(path, ss.width, ss.height, 4, ss.pixels, ss.width * 4) ?
|
||||||
// TODO use stbi to support more formats
|
unsafe { ss.destroy() }
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_rgba_to_ppm writes `pixels` data in RGBA format to PPM3 format.
|
// 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) ?
|
mut f_out := os.create(path) ?
|
||||||
|
defer {
|
||||||
|
f_out.close()
|
||||||
|
}
|
||||||
f_out.writeln('P3') ?
|
f_out.writeln('P3') ?
|
||||||
f_out.writeln('$w $h') ?
|
f_out.writeln('$w $h') ?
|
||||||
f_out.writeln('255') ?
|
f_out.writeln('255') ?
|
||||||
for i := h - 1; i >= 0; i-- {
|
for i := h - 1; i >= 0; i-- {
|
||||||
for j := 0; j < w; j++ {
|
for j := 0; j < w; j++ {
|
||||||
idx := i * w * components + j * components
|
idx := i * w * components + j * components
|
||||||
r := int(pixels[idx])
|
unsafe {
|
||||||
g := int(pixels[idx + 1])
|
r := int(pixels[idx])
|
||||||
b := int(pixels[idx + 2])
|
g := int(pixels[idx + 1])
|
||||||
f_out.write_string('$r $g $b ') ?
|
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