sync with fwk

main
Dominik Madarász 2023-09-27 08:49:59 +02:00
parent a4869085a4
commit d029777c9d
76 changed files with 6080 additions and 2082 deletions

View File

@ -372,7 +372,7 @@ set other=
set v4k=yes
set hello=no
set demos=no
set extras=no
set lab=no
set editor=no
set vis=no
set proj=no
@ -402,12 +402,12 @@ set run=no
if "%1"=="nov4k" set "v4k=no" && goto loop
if "%1"=="nodemos" set "demos=no" && goto loop
if "%1"=="demos" set "demos=yes" && set "hello=no" && goto loop
if "%1"=="extras" set "extras=yes" && set "hello=no" && goto loop
if "%1"=="lab" set "lab=yes" && set "hello=no" && goto loop
if "%1"=="noeditor" set "editor=no" && goto loop
if "%1"=="hello" set "hello=yes" && goto loop
if "%1"=="editor" set "editor=yes" && set "v4k=no" && set "hello=no"&& goto loop
if "%1"=="run" set "run=yes" && goto loop
if "%1"=="all" set "v4k=yes" && set "demos=yes" && set "extras=yes" && set "editor=yes" && set "hello=yes" && goto loop
if "%1"=="all" set "v4k=yes" && set "demos=yes" && set "lab=yes" && set "editor=yes" && set "hello=yes" && goto loop
if "%1"=="tcc" set "cc=%1" && goto loop
if "%1"=="cl" set "cc=%1" && goto loop
@ -646,8 +646,8 @@ if "!demos!"=="yes" (
!echo! 07-network && !cc! !o! 07-network.exe demos\07-network.c !import! !args! || set rc=1
)
rem extras
if "!extras!"=="yes" (
rem lab
if "!lab!"=="yes" (
for %%f in ("demos\99-*") do (
!echo! %%~nf && !cc! !o! %%~nf.exe demos\%%~nf.c !import! !args! || set rc=1
)

9
demos/00-loop.c 100644
View File

@ -0,0 +1,9 @@
#include "v4k.h" // Minimal C sample
int main() {
window_create(75.0, 0); // 75% size, no extra flags
while( window_swap() && !input(KEY_ESC) ) { // game loop
puts("hello V4K from C!");
}
}

View File

@ -25,4 +25,7 @@ int main() {
end;
end;
));
// script test (lua)
script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" );
}

View File

@ -2,8 +2,8 @@
// - rlyeh, public domain.
//
// Compile with:
// `make demos\00-ui.c` (windows)
// `sh MAKE.bat demos/00-ui.c` (linux, osx)
// `make demos\01-ui.c` (windows)
// `sh MAKE.bat demos/01-ui.c` (linux, osx)
#include "v4k.h"
@ -19,7 +19,7 @@ int main() {
window_fps_lock(app_target_fps);
// load video
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB );
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_LOOP );
// app loop
while( window_swap() ) {

159
demos/01-demo2d.c 100644
View File

@ -0,0 +1,159 @@
// 2d demo: window, audio, camera, font, tiled, render, fx, spritesheet, input, ui. @todo: spine
// - rlyeh, public domain.
//
// Compile with:
// `make demos\01-demo2d.c` (windows)
// `sh MAKE.bat demos/01-demo2d.c` (linux, osx)
#include "v4k.h"
void demo_kids(vec3 offs) {
// init
static texture_t kids; do_once kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
static vec3 pos[2] = {{490,362},{442,362}}, vel[2] = {0};
static int row[2] = {0,3}, frame[2] = {0};
static int inputs[2][4] = {{KEY_W,KEY_A,KEY_S,KEY_D},{KEY_UP,KEY_LEFT,KEY_DOWN,KEY_RIGHT}};
// move
for( int i = 0; i < countof(pos); ++i ) {
vel[i].x = input(inputs[i][3]) - input(inputs[i][1]);
vel[i].y = input(inputs[i][2]) - input(inputs[i][0]);
pos[i].x = fmod(pos[i].x + vel[i].x, window_width() + 128);
pos[i].y = fmod(pos[i].y + vel[i].y, window_height() + 128);
frame[i] += vel[i].x || vel[i].y;
}
// render
for( int i = 0; i < countof(pos); ++i ) {
int col = frame[i] / 10, num_frame = row[i] * 4 + col % 4; // 4x4 tilesheet
float position[3] = {pos[i].x,pos[i].y,pos[i].y}, offset[2]={0,0}, scale[2]={0.5,0.5};
float spritesheet[3]={num_frame,4,4};
sprite_sheet(kids,
spritesheet, // num_frame in a 4x4 spritesheet
position, 0, // position(x,y,depth:sort-by-Y), angle
offset, scale, // offset(x,y), scale(x,y)
false, WHITE, false // is_additive, tint color, resolution-independent
);
}
}
void demo_hud() {
// draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
static texture_t inputs; do_once inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
float position[3] = {window_width() - tile_w, window_height() - tile_h, window_height() }; // position in screen-coordinates (x,y,z-index)
sprite_sheet(inputs, spritesheet, position, 0/*deg*/, offset, scale, false, WHITE, 1);
}
int main() {
// window (80% sized, MSAA x4 flag)
window_create(80.0, WINDOW_MSAA4);
window_title(__FILE__);
// tiled map
tiled_t tmx = tiled(vfs_read("castle.tmx"));
// tmx.parallax = true;
// spine model
//spine_t *spn = spine("goblins.json", "goblins.atlas", 0);
// camera 2d
camera_t cam = camera();
cam.position = vec3(window_width()/2, window_height()/2, 3); // at(CX,CY) zoom(x3)
camera_enable(&cam);
// audio (both clips & streams)
audio_t clip1 = audio_clip( "coin.wav" );
audio_t clip2 = audio_clip( "pew.sfxr" );
audio_t stream1 = audio_stream( "larry.mid" );
audio_t stream2 = audio_stream( "waterworld-map.fur" );
audio_t BGM = stream1;
audio_play(BGM, 0);
// font config: faces (6 max) and colors (10 max)
#define FONT_CJK FONT_FACE3
#define FONT_YELLOW FONT_COLOR2
#define FONT_LIME FONT_COLOR3
font_face(FONT_CJK, "mplus-1p-medium.ttf", 48.f, FONT_JP|FONT_2048); // CJK|FONT_2048|FONT_OVERSAMPLE_Y);
font_color(FONT_YELLOW, RGB4(255,255,0,255));
font_color(FONT_LIME, RGB4(128,255,0,255));
// fx: load all post fx files in all subdirs. enable a few filters by default
fx_load("fx**.fs");
fx_enable(fx_find("fxCRT2.fs"), 1);
fx_enable(fx_find("fxGrain.fs"), 1);
fx_enable(fx_find("fxContrast.fs"), 1);
fx_enable(fx_find("fxVignette.fs"), 1);
// demo loop
while (window_swap() && !input_down(KEY_ESC)) {
// handle input
if( input_down(KEY_F5) ) window_reload();
if( input_down(KEY_F11) ) window_fullscreen( !window_has_fullscreen() );
// camera panning (x,y) & zooming (z)
if( !ui_hover() && !ui_active() ) {
if( input(MOUSE_L) ) cam.position.x += input_diff(MOUSE_X);
if( input(MOUSE_L) ) cam.position.y += input_diff(MOUSE_Y);
cam.position.z += input_diff(MOUSE_W) * 0.1;
}
// apply post-fxs from here
fx_begin();
profile("Rendering") {
vec3 center = add3(cam.position,vec3(-window_width()/1,-window_height()/2,0));
// render tiled map
tiled_render(tmx, center);
//
demo_kids(vec3(0,0,1));
demo_hud();
// render spine model
// spine_animate(spn, !window_has_pause() * window_delta());
// spine_render(spn, vec3(cam.position.x, cam.position.y, 1), true );
// sprite_flush();
}
// subtitle sample
font_print(
FONT_BOTTOM FONT_CENTER
FONT_CJK FONT_H1
FONT_YELLOW "私はガラスを食べられます。" FONT_LIME "それは私を傷つけません。\n"
);
// post-fxs end here
fx_end();
// ui
if( ui_panel("Audio", 0)) {
static float bgm = 1, sfx = 1, master = 1;
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
if( ui_label2_toolbar("BGM: Track #1", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream1, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Track #2", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream2, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(clip1, 0);
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(clip2, 0);
ui_panel_end();
}
if( ui_panel("Tiled", 0)) {
ui_float("Zoom in", &cam.position.z);
tiled_ui(&tmx);
ui_panel_end();
}
/*if( ui_panel("Spine", 0)) {
spine_ui(spn);
ui_panel_end();
}*/
}
}
// this demo supersedes following old sources:
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-audio.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-font.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-spine.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-sprite.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-tiled.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-tilemap.c

View File

@ -1,7 +1,7 @@
#include "v4k.h"
int main() {
window_create(0.75, WINDOW_MSAA8);
window_create(75.0, WINDOW_MSAA8);
// style: our aliases
#define FONT_REGULAR FONT_FACE1
@ -24,11 +24,11 @@ int main() {
#define FONT_TINY FONT_H6
// style: atlas size, unicode ranges and font faces (up to 6 faces)
font_face(FONT_REGULAR, "Carlito-Regular.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
font_face(FONT_ITALIC, "Carlito-Italic.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
font_face(FONT_BOLD, "Carlito-Bold.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
font_face(FONT_REGULAR, "B612""-Regular.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
font_face(FONT_ITALIC, "B612""-Italic.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
font_face(FONT_BOLD, "B612""-Bold.ttf", 48.f, FONT_EU|FONT_AR|FONT_RU|FONT_2048);
font_face(FONT_JAPANESE, "mplus-1p-medium.ttf", 48.f, FONT_JP|FONT_2048); // CJK|FONT_2048|FONT_OVERSAMPLE_Y);
font_face(FONT_MONOSPACE, "Inconsolata-Regular.ttf", 24.f, FONT_EU|FONT_512);
font_face(FONT_MONOSPACE, "B612Mono""-Regular.ttf", 24.f, FONT_EU|FONT_512);
// style: colors (up to 10 colors)
font_color(FONT_GRAY, RGB4(100,100,100,255));

View File

@ -1,167 +1,218 @@
// sprite demo: window, audio, camera, font, tiled, render, fx, spritesheet, input, ui. @todo: finish spine
// - rlyeh, public domain.
// sprite routines
// - rlyeh,
//
// Compile with:
// `make demos\01-sprite.c` (windows)
// `sh MAKE.bat demos/01-sprite.c` (linux, osx)
// credits: original lovely demo by rxi (MIT License).
// see https://github.com/rxi/autobatch/tree/master/demo/cats
#include "v4k.h"
void demo_kids(vec3 offs) {
texture_t kids, catImage, shadowImage, inputs;
int NUM_SPRITES = 100, NUM_SPRITES_CHANGED = 1;
typedef struct Cat {
int cat, flip;
double x, y;
double vx, vy;
double animSpeed;
double moveTimer;
double elapsed;
} Cat;
void demo_cats() {
static array(Cat) cats = 0;
// init
static texture_t kids; do_once kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
static vec3 pos[2] = {{490,362},{442,362}}, vel[2] = {0};
static int row[2] = {0,3}, frame[2] = {0};
static int inputs[2][4] = {{KEY_W,KEY_A,KEY_S,KEY_D},{KEY_UP,KEY_LEFT,KEY_DOWN,KEY_RIGHT}};
if( NUM_SPRITES_CHANGED ) {
NUM_SPRITES_CHANGED = 0;
array_resize(cats, NUM_SPRITES); int i = 0;
for each_array_ptr(cats, Cat, c) {
randset(i++);
c->x = randf() * window_width();
c->y = randf() * window_height();
c->vx = c->vy = 0;
c->cat = randi(0, 4);
c->flip = randf() < 0.5;
c->animSpeed = 0.8 + randf() * 0.3;
c->moveTimer = 0;
c->elapsed = 0;
}
}
// move
for( int i = 0; i < countof(pos); ++i ) {
vel[i].x = input(inputs[i][3]) - input(inputs[i][1]);
vel[i].y = input(inputs[i][2]) - input(inputs[i][0]);
pos[i].x = fmod(pos[i].x + vel[i].x, window_width() + 128);
pos[i].y = fmod(pos[i].y + vel[i].y, window_height() + 128);
frame[i] += vel[i].x || vel[i].y;
const float dt = 1/120.f;
const int appw = window_width(), apph = window_height();
enum { yscale = 1 };
for( int i = 0; i < NUM_SPRITES; ++i ) {
Cat *c = &cats[i];
// Add velocity to position //and wrap to screen
c->x += yscale * c->vx * dt; // % ;
c->y += yscale * c->vy * dt; // % (int)window_height();
if( c->x < 0 ) c->x += appw; else if( c->x > appw ) c->x -= appw;
if( c->y < 0 ) c->y += apph; else if( c->y > apph ) c->y -= apph;
// Faster animation if walking
int boost = c->vx == 0 && c->vy == 0 ? 1 : 3;
// Update elapsed time
c->elapsed += dt * boost;
// Update move timer -- if we hit zero then change or zero velocity
c->moveTimer -= dt * boost;
if (c->moveTimer < 0) {
if (randf() < .2) {
c->vx = (randf() * 2 - 1) * 30 * 2;
c->vy = (randf() * 2 - 1) * 15 * 2;
c->flip = c->vx < 0;
} else {
c->vx = c->vy = 0;
}
c->moveTimer = 1 + randf() * 5;
}
}
// render
for( int i = 0; i < countof(pos); ++i ) {
int col = frame[i] / 10, num_frame = row[i] * 4 + col % 4; // 4x4 tilesheet
float position[3] = {pos[i].x,pos[i].y,pos[i].y}, offset[2]={0,0}, scale[2]={0.5,0.5};
float spritesheet[3]={num_frame,4,4};
sprite_sheet(kids,
spritesheet, // num_frame in a 4x4 spritesheet
position, 0, // position(x,y,depth:sort-by-Y), angle
uint32_t white = rgba(255,255,255,255);
uint32_t alpha = rgba(255,255,255,255*0.6);
for( int i = 0; i < NUM_SPRITES; ++i ) {
Cat *c = &cats[i];
// Get current animation frame (8x4 tilesheet)
double e = c->elapsed * c->animSpeed;
double frame_num = c->cat * 8 + floor( ((int)(e * 8)) % 4 );
frame_num = c->vx != 0 || c->vy != 0 ? frame_num + 4 : frame_num;
// Get x scale based on flip flag
int xscale = yscale * (c->flip ? -1 : 1);
// Draw
float angle = 0; //fmod(window_time()*360/5, 360);
float scale[2] = { 2*xscale, 2*yscale };
float position[3] = { c->x,c->y,c->y }, no_offset[2] = {0,0}, spritesheet[3] = { frame_num,8,4 };
sprite_sheet(catImage,
spritesheet, // frame_number in a 8x4 spritesheet
position, angle, // position(x,y,depth: sort by Y), angle
no_offset, scale, // offset(x,y), scale(x,y)
0,white,0 // is_additive, tint color, resolution independant
);
float position_neg_sort[3] = { c->x,c->y,-c->y }, offset[2] = {-1,5}, no_spritesheet[3] = {0,0,0};
sprite_sheet(shadowImage,
no_spritesheet, // no frame_number (0x0 spritesheet)
position_neg_sort, angle, // position(x,y,depth: sort by Y), angle
offset, scale, // offset(x,y), scale(x,y)
false, WHITE, false // is_additive, tint color, resolution-independent
0,alpha,0 // is_additive, tint color, resolution independant
);
}
}
void demo_hud() {
// draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
static texture_t inputs; do_once inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
float position[3] = {window_width() - tile_w, window_height() - tile_h, window_height() }; // position in screen-coordinates (x,y,z-index)
sprite_sheet(inputs, spritesheet, position, 0/*deg*/, offset, scale, false, WHITE, 1);
void demo_kids() {
static int angle; //++angle;
static int *x, *y, *v;
// init
if( NUM_SPRITES_CHANGED ) {
NUM_SPRITES_CHANGED = 0;
y = (int*)REALLOC(y, 0 );
x = (int*)REALLOC(x, NUM_SPRITES * sizeof(int) );
y = (int*)REALLOC(y, NUM_SPRITES * sizeof(int) );
v = (int*)REALLOC(v, NUM_SPRITES * sizeof(int) );
for( int i = 0; i < NUM_SPRITES; ++i ) {
randset(i);
x[i] = randi(0, window_width());
y[i] = randi(0, window_height());
v[i] = randi(1, 3);
}
}
// config
const int appw = window_width(), apph = window_height();
// move & render
for( int i = 0; i < NUM_SPRITES; ++i ) {
y[i] = (y[i] + v[i]) % (apph + 128);
int col = ((x[i] / 10) % 4); // 4x4 tilesheet
int row = ((y[i] / 10) % 4);
int num_frame = col * 4 + row;
float position[3] = {x[i],y[i],y[i]}, offset[2]={0,0}, scale[2]={1,1}, spritesheet[3]={num_frame,4,4};
sprite_sheet(kids,
spritesheet, // num_frame in a 4x4 spritesheet
position, angle, // position(x,y,depth: sort by Y), angle
offset, scale, // offset(x,y), scale(x,y)
0, ~0u, 0 // is_additive, tint color, resolution independant
);
}
}
int main() {
// window (80% sized, MSAA x4 flag)
window_create(80.0, WINDOW_MSAA4);
window_title(__FILE__);
int main(int argc, char **argv) {
window_create(75.f, 0);
window_title("V4K - Sprite");
window_color( SILVER );
// tiled map
tiled_t tmx = tiled(vfs_read("castle.tmx"));
// tmx.parallax = true;
// options
int do_cats = 1;
NUM_SPRITES = optioni("--num_sprites,-N", NUM_SPRITES);
if(do_cats) NUM_SPRITES/=2; // cat-sprite+cat-shadow == 2 sprites
// spine model
//spine_t *spn = spine("goblins.json", "goblins.atlas", 0);
// load sprites and sheets
kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
catImage = texture( "cat.png", TEXTURE_LINEAR ); //
shadowImage = texture( "cat-shadow.png", TEXTURE_LINEAR );
inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
// camera 2d
// load all fx files, including subdirs
fx_load("fx**.fs");
// init camera (x,y) (z = zoom)
camera_t cam = camera();
cam.position = vec3(window_width()/2, window_height()/2, 3); // at(CX,CY) zoom(x3)
cam.position = vec3(window_width()/2,window_height()/2,1);
camera_enable(&cam);
// audio (both clips & streams)
audio_t clip1 = audio_clip( "coin.wav" );
audio_t clip2 = audio_clip( "pew.sfxr" );
audio_t stream1 = audio_stream( "larry.mid" );
audio_t stream2 = audio_stream( "monkey1.mid" );
audio_t BGM = stream1;
audio_play(BGM, 0);
// font config: faces (6 max) and colors (10 max)
#define FONT_CJK FONT_FACE3
#define FONT_YELLOW FONT_COLOR2
#define FONT_LIME FONT_COLOR3
font_face(FONT_CJK, "mplus-1p-medium.ttf", 48.f, FONT_JP|FONT_2048); // CJK|FONT_2048|FONT_OVERSAMPLE_Y);
font_color(FONT_YELLOW, RGB4(255,255,0,255));
font_color(FONT_LIME, RGB4(128,255,0,255));
// fx: load all post fx files in all subdirs. enable a few filters by default
fx_load("fx**.fs");
fx_enable(fx_find("fxCRT2.fs"), 1);
fx_enable(fx_find("fxGrain.fs"), 1);
fx_enable(fx_find("fxContrast.fs"), 1);
fx_enable(fx_find("fxVignette.fs"), 1);
// demo loop
while (window_swap() && !input_down(KEY_ESC)) {
// handle input
if( input_down(KEY_F5) ) window_reload();
if( input_down(KEY_F11) ) window_fullscreen( !window_has_fullscreen() );
while(window_swap()) {
if( input(KEY_F5)) window_reload();
if( input(KEY_F11)) window_fullscreen( window_has_fullscreen() ^ 1);
if( input(KEY_ESC) ) break;
// camera panning (x,y) & zooming (z)
if( !ui_hover() && !ui_active() ) {
if( input(MOUSE_L) ) cam.position.x += input_diff(MOUSE_X);
if( input(MOUSE_L) ) cam.position.y += input_diff(MOUSE_Y);
cam.position.z += input_diff(MOUSE_W) * 0.1;
if( input(MOUSE_L) ) cam.position.x -= input_diff(MOUSE_X);
if( input(MOUSE_L) ) cam.position.y -= input_diff(MOUSE_Y);
cam.position.z += input_diff(MOUSE_W) * 0.1; // cam.p.z += 0.001f; for tests
}
// apply post-fxs from here
fx_begin();
profile("Rendering") {
vec3 center = add3(cam.position,vec3(-window_width()/1,-window_height()/2,0));
// render tiled map
tiled_render(tmx, center);
//
demo_kids(vec3(0,0,1));
demo_hud();
// render spine model
// spine_animate(spn, !window_has_pause() * window_delta());
// spine_render(spn, vec3(cam.position.x, cam.position.y, 1), true );
// sprite_flush();
profile("Sprite batching") {
if(do_cats) demo_cats(); else demo_kids();
}
// subtitle sample
font_print(
FONT_BOTTOM FONT_CENTER
FONT_CJK FONT_H1
FONT_YELLOW "私はガラスを食べられます。" FONT_LIME "それは私を傷つけません。\n"
);
// flush retained renderer, so we ensure the fbos are up to date before fx_end()
profile("Sprite flushing") {
sprite_flush();
}
// post-fxs end here
fx_end();
// ui
if( ui_panel("Audio", 0)) {
static float bgm = 1, sfx = 1, master = 1;
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream1, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Monkey Island", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream2, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(clip1, 0);
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(clip2, 0);
ui_panel_end();
}
if( ui_panel("Tiled", 0)) {
ui_float("Zoom in", &cam.position.z);
tiled_ui(&tmx);
ui_panel_end();
}
/*if( ui_panel("Spine", 0)) {
spine_ui(spn);
ui_panel_end();
}*/
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
// draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
{
vec3 old_pos = camera_get_active()->position;
sprite_flush();
camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
float zindex = window_height(); // large number, on top
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
float position[3] = {window_width() - tile_w, window_height() - tile_h, zindex }; // position in screen-coordinates
sprite_sheet(inputs, spritesheet, position, 0/*rotation*/, offset, scale, false/*is_additive*/, WHITE/*color*/, false/*resolution_independant*/);
sprite_flush();
camera_get_active()->position = old_pos;
}
if( ui_panel("Sprite", 0) ) {
const char *labels[] = {"Kids","Cats"};
if( ui_list("Sprite type", labels, countof(labels), &do_cats) ) NUM_SPRITES_CHANGED = 1;
if( ui_int("Number of Sprites", &NUM_SPRITES) ) NUM_SPRITES_CHANGED = 1;
if( ui_clampf("Zoom", &cam.position.z, 0.1, 10));
ui_panel_end();
}
}
}
// this demo supersedes following old sources:
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-audio.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-font.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-spine.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-sprite.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-tiled.c
// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-tilemap.c

View File

@ -51,8 +51,6 @@ int main() {
}
}
fx_begin();
// draw skybox
skybox_render(&sky, cam.proj, cam.view);
@ -88,8 +86,6 @@ int main() {
collide_demo();
}
fx_end();
// ui
if( ui_panel("App", 0) ) {
ui_bool("Boids demo", &do_boids_demo);
@ -106,15 +102,6 @@ int main() {
if( ui_float3("Position", cam.position.v3) ) {}
ui_panel_end();
}
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
ui_fx(i);
}
ui_panel_end();
}
}
}

View File

@ -32,10 +32,10 @@ int main() {
array_resize(M, 32*32);
for(int z = 0, i = 0; z < 32; ++z) {
for(int x = 0; x < 32; ++x, ++i) {
vec3 p = vec3(-x*9,0,-z*9);
vec3 r = vec3(0,-90,0); // kgirl: 0,0,0
vec3 s = vec3(2,2,2);
compose44(M[i], p, eulerq(r), s);
vec3 pos = vec3(-x*3,0,-z*3);
vec3 rot = vec3(0,-90,0); // kgirl: 0,0,0
vec3 sca = vec3(1,1,1); // kgirl: 2,2,2
compose44(M[i], pos, eulerq(rot), sca);
}
}
@ -167,15 +167,6 @@ int main() {
shader_vec3("u_rimrange", rimrange);
ui_panel_end();
}
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, b);
ui_fx(i);
}
ui_panel_end();
}
}
}

View File

@ -130,7 +130,7 @@ void DrawModel(mesh_t *m) {
"fragcolor = vec4(v_normal, 1.0);\n" // diffuse
"}";
static unsigned program; do_once program = shader(vs, fs, "att_position,att_normal", "fragcolor", "");
static unsigned program; do_once program = shader(vs, fs, "att_position,att_normal", "fragcolor", NULL);
shader_bind(program);
shader_mat44("VP", VP);
shader_mat44("M", M);

View File

@ -142,14 +142,6 @@ int main() {
if(ui_bool("Two sided", &do_twosided)) {}
ui_panel_end();
}
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
}
ui_panel_end();
}
}
}
@ -164,7 +156,7 @@ int main() {
// create camera
camera_t cam = camera();
// load video, RGB texture, no audio
video_t *v = video( "bjork-all-is-full-of-love.mp4", VIDEO_RGB | VIDEO_NO_AUDIO ); video_seek(v, 30);
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_NO_AUDIO | VIDEO_LOOP ); video_seek(v, 30);
// load texture
texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
texture_t t2 = texture("matcaps/material3", 0);

View File

@ -2,14 +2,14 @@
// - rlyeh, public domain.
//
// Compile with:
// `make demos\04-controller.c` (windows)
// `sh MAKE.bat demos/04-controller.c` (linux, osx)
// `make demos\99-controller.c` (windows)
// `sh MAKE.bat demos/99-controller.c` (linux, osx)
#include "v4k.h"
int main() {
// 75% window, MSAAx2 flag
window_create(75, WINDOW_MSAA8);
window_create(75, WINDOW_MSAA2);
// fx: load all post fx files in all subdirs
fx_load("fx**.fs");
@ -262,14 +262,6 @@ int main() {
ui_label("Keys I/J/K/L + Z/X");
ui_panel_end();
}
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, b);
}
ui_panel_end();
}
}
}

View File

@ -1,8 +1,14 @@
// material demo
// - rlyeh, public domain
//
// @todo: object_print(obj, "");
#include "v4k.h"
int main() {
// create the window
window_create( 0.75f, WINDOW_MSAA8 );
window_color( GRAY );
// create camera
camera_t cam = camera();
@ -41,22 +47,17 @@ int main() {
// create point light
light_t* l = scene_spawn_light();
light_type(l, LIGHT_SPOT);
light_ambient(l, vec3(0.03,0.03,0.06));
light_specular(l, scale3(vec3(1,1.0,0.2), 2.5f));
light_power(l, 56.f);
light_type(l, LIGHT_POINT);
while(window_swap() && !input(KEY_ESC)) {
// draw environment
viewport_color( RGB3(22,22,32) );
ddraw_grid(0);
// update video
video_decode( v );
// update light data
// update light position
light_teleport(l, cam.position);
light_dir(l, cam.look);
// draw scene
scene_render(SCENE_FOREGROUND|SCENE_BACKGROUND|SCENE_UPDATE_SH_COEF);

View File

@ -8,10 +8,8 @@ int main() {
window_create(80, WINDOW_MSAA4 | WINDOW_SQUARE);
// audio (both streams & clips)
audio_t stream1 = audio_stream( "wrath_of_the_djinn.xm" );
audio_t stream2 = audio_stream( "larry.mid" );
audio_t stream3 = audio_stream( "monkey1.mid" );
audio_t stream4 = audio_stream( "waterworld-map.fur" );
audio_t stream1 = audio_stream( "larry.mid" );
audio_t stream2 = audio_stream( "waterworld-map.fur" );
audio_t BGM = stream1;
audio_play(BGM, 0);
@ -27,10 +25,8 @@ int main() {
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
if( ui_label2_toolbar("BGM: Wrath of the Djinn", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream1, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream2, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Monkey Island", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream3, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Waterworld Map", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream4, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream1, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Waterworld Map", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = stream2, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, 0);
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, 0);
ui_window_end();

View File

@ -5,8 +5,7 @@
int main() {
// 75% window, msaa x2
window_create( 35, WINDOW_MSAA2 );
window_aspect_lock(910, 540);
window_create( 75, WINDOW_MSAA2 );
// load video
int is_rgb = flag("--rgb") ? 1 : 0;

View File

@ -5,12 +5,7 @@ const char *SKY_DIRS[] = {
"cubemaps/bridge3/",
"cubemaps/colors/",
"cubemaps/colors2/",
"cubemaps/mountain/",
"cubemaps/room/",
"cubemaps/stardust/",
"hdr/MonValley_G_DirtRoad_1k.hdr",
"hdr/Factory_Catwalk_1k.hdr",
"hdr/Shiodome_Stairs_1k.hdr",
"hdr/Tokyo_BigSight_1k.hdr",
};
int OBJ_MDL = 0;

View File

@ -0,0 +1,38 @@
// shadertoy viewer
// - rlyeh, public domain
#include "v4k.h"
int main() {
window_create(75, 0); // WINDOW_MSAA8);
array(char*) list = 0;
for( const char **dir = file_list("demos/art/shadertoys/", "**.fs"); *dir; dir++ ) {
array_push(list, STRDUP(file_name(*dir)));
}
shadertoy_t sh = shadertoy(*list, 0); // 0:no flags
while(window_swap()) {
// selector
static int selected = 0;
int prev = input_down(KEY_UP) || input_down(KEY_LEFT);
int next = input_down(KEY_DOWN) || input_down(KEY_RIGHT);
if( prev ) if( selected > 0 ) sh = shadertoy( list[--selected], 0 );
if( next ) if( selected < array_count(list) - 1 ) sh = shadertoy( list[++selected], 0 );
// draw
shadertoy_render(&sh, window_delta());
// UI
if( ui_panel("Shadertoy", 1)) {
for( int i = 0; i < array_count(list); ++i ) {
bool in_use = i == selected;
if( ui_bool(list[i], &in_use) ) {
sh = shadertoy( list[selected = i], 0 );
}
}
ui_panel_end();
}
}
}

View File

@ -1,30 +0,0 @@
#include <stdio.h>
#include <inttypes.h>
/*
https://www.tastyfish.cz/lrs/bytebeat.html
Outputting the variable i creates a periodical saw-shaped beat, multiplication/division decreases/increases the speed, addition/subtraction shifts the phase backward/forward.
Squaring (and other powers) create a wah-wah effect.
Crazier patterns can be achieved by using the variable in places of numerical constants, e.g. i << ((i / 512) % 8) (shifting by a value that depends on the variable).
Modulo (%) increases the frequency and decreases volume (limits the wave peak).
So called Sierpinski harmonies are often used melodic expressions of the form i*N & i >> M.
Bitwise and (&) can add distortion (create steps in the wave).
A macro structure of the song (silent/louds parts, verse/chorus, ...) can be achieved by combining multiple patterns with some low-frequency pattern, e.g. this alternates a slower and faster beat: int cond = (i & 0x8000) == 0;, cond * (i / 16) + !cond * (i / 32)
Extra variables can add more complexity (e.g. precompute some variable a which will subsequently be used multiple times in the final formula).
*/
int main(void) {
for (int t = 0;; ++t) {
putchar(
t|(t<<((t/920)%16))|(t/3*t&(t<<13)*t)|(t%16386?123:t&203?148:3)&(t/920)
// (t/8)>>(t>>9)*t/((t>>14&3)+4)
// ((1-(((t+10)>>((t>>9)&((t>>14))))&(t>>4&-2)))*2)*(((t>>10)^((t+((t>>6)&127))>>10))&1)*32+128
// t*((0xbadbea75>>((t>>12)&30)&3)*0.25*(0x5afe5>>((t>>16)&28)&3))
// ((t>>4)*(13&(0x8898a989>>(t>>11&30)))&255)+((((t>>9|(t>>2)|t>>8)*10+4*((t>>2)&t>>15|t>>8))&255)>>1)
// t*((t>>12|t>>8)&63&t>>4)
// ((0x47 >> ((t >> 9) % 32)) & (t >> (t % 32))) | (0x57 >> ((t >> 7) % 32)) | (0x06 >> ((t >> ((((t * 11) >> 14) & 0x0e) % 32)) % 32))
);
}
return 0;
}

View File

@ -27,7 +27,7 @@ int main() {
ssbo_update(0, sizeof(data), &data);
compute_dispatch(TEX_WIDTH/10, TEX_WIDTH/10, 1);
image_write_barrier();
write_barrier_image();
fullscreen_quad_rgb(tex, 2.2);
}

268
demos/99-demo.c 100644
View File

@ -0,0 +1,268 @@
// framework demo
// - rlyeh, public domain
#include "v4k.h"
int main() {
// options
bool do_about = 0;
float do_scale = 0.10f;
bool do_debugdraw = 0;
float do_gamepad_deadzone = 0.15f;
vec2 do_gamepad_polarity = vec2(+1,+1);
vec2 do_gamepad_sensitivity = vec2(0.1f,0.1f);
vec2 do_mouse_polarity = vec2(+1,-1);
vec2 do_mouse_sensitivity = vec2(0.2f,0.2f);
bool do_billboard_x = 0, do_billboard_y = 0, do_billboard_z = 0;
// window (80% sized, MSAA x4 flag)
window_create(80, WINDOW_MSAA4);
window_title(__FILE__);
// load all fx files, including subdirs
fx_load("fx**.fs");
// load skybox
skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", 0); // --mie for rayleigh/mie scattering
// load static scene
model_t sponza;
int do_sponza = flag("--sponza");
if( do_sponza ) {
sponza = model("sponza.obj", 0); // MODEL_NO_TEXTURES);
translation44(sponza.pivot, 0,-1,0);
rotate44(sponza.pivot, -90,1,0,0);
scale44(sponza.pivot, 10,10,10);
}
model_t shaderball;
int do_shaderball = flag("--shaderball");
if( do_shaderball ) {
shaderball = model("shaderball.glb", 0);
translation44(shaderball.pivot, 0,0,-10);
rotate44(shaderball.pivot, -90,1,0,0);
scale44(shaderball.pivot, 0.02,0.02,0.02);
}
// animated models loading
int model_flags = flag("--matcaps") ? MODEL_MATCAPS : 0;
model_t girl = model("kgirl/kgirls01.fbx", model_flags);
model_t alien = model("alien/alien_helmet.fbx", model_flags); rotation44(alien.pivot, -90,1,0,0);
model_t george = model("robots/george.fbx", model_flags);
model_t leela = model("robots/leela.fbx", model_flags);
model_t mike = model("robots/mike.fbx", model_flags);
model_t stan = model("robots/stan.fbx", model_flags);
model_t robots[4] = { george, leela, mike, stan };
for( int i = 0; i < countof(robots); ++i ) {
rotation44(robots[i].pivot, -90,1,0,0);
}
if( flag("--matcaps") ) {
// patch models to use matcaps
model_set_texture(george, texture("matcaps/3B6E10_E3F2C3_88AC2E_99CE51-256px", 0)); // green
model_set_texture(leela, texture("matcaps/39433A_65866E_86BF8B_BFF8D8-256px", 0));
model_set_texture(mike, texture("matcaps/394641_B1A67E_75BEBE_7D7256-256px.png", 0));
model_set_texture(stan, texture("matcaps/test_steel", 0));
model_set_texture(girl, texture("matcaps/material3", 0));
model_set_texture(alien, texture("matcaps/material3", 0));
if( flag("--shaderball") )
model_set_texture(shaderball, texture("matcaps/normals", 0));
}
// camera
camera_t cam = camera();
cam.speed = 0.2f;
// audio (both clips & streams)
audio_t SFX1 = audio_clip( "coin.wav" );
audio_t SFX2 = audio_clip( "pew.sfxr" );
audio_t BGM1 = audio_stream( "waterworld-map.fur"); // wrath_of_the_djinn.xm" );
audio_t BGM2 = audio_stream( "larry.mid" );
audio_t BGM3 = audio_stream( "monkey1.mid" ), BGM = BGM1;
audio_play(SFX1, 0);
audio_play(BGM, 0);
// demo loop
while (window_swap())
{
// input
if( input_down(KEY_ESC) ) break;
if( input_down(KEY_F5) ) window_reload();
if( input_down(KEY_W) && input_held(KEY_LCTRL) ) break;
if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 );
if( input_down(KEY_X) ) window_screenshot(__FILE__ ".png");
if( input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
// vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), do_gamepad_deadzone + 1e-3);
// vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), do_gamepad_deadzone + 1e-3);
// fps camera
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
// apply post-fxs from here
fx_begin();
// queue debug drawcalls
profile("Debugdraw") {
ddraw_grid(0);
ddraw_color(YELLOW);
ddraw_text(vec3(+1,+1,-1), 0.04f, va("(%f,%f,%f)", cam.position.x,cam.position.y,cam.position.z));
if(do_debugdraw) ddraw_demo(); // showcase many debugdraw shapes
ddraw_color(YELLOW);
ddraw_flush();
}
// draw skybox
profile("Skybox") {
skybox_render(&sky, cam.proj, cam.view);
}
profile("Skeletal update") if(!window_has_pause()) {
float delta = window_delta() * 30; // 30fps anim
// animate girl & alien
girl.curframe = model_animate(girl, girl.curframe + delta);
alien.curframe = model_animate(alien, alien.curframe + delta);
// animate robots
for(int i = 0; i < countof(robots); ++i) {
robots[i].curframe = model_animate(robots[i], robots[i].curframe + delta);
}
}
profile("Skeletal render") {
static vec3 p = {-10,0,-10}, r = {0,0,0}, s = {2,2,2};
gizmo(&p, &r, &s);
mat44 M; rotationq44(M, eulerq(r)); scale44(M, s.x,s.y,s.z); relocate44(M, p.x,p.y,p.z);
model_render(girl, cam.proj, cam.view, M, 0);
aabb box = model_aabb(girl, M);
ddraw_color(YELLOW);
ddraw_aabb(box.min, box.max);
}
profile("Skeletal render") {
static vec3 p = {+10,0,-10}, r = {0,-90,0}, s = {1,1,1};
//gizmo(&p, &r, &s);
mat44 M; rotationq44(M, eulerq(r)); scale44(M, s.x,s.y,s.z); relocate44(M, p.x,p.y,p.z);
model_render(alien, cam.proj, cam.view, M, 0);
aabb box = model_aabb(alien, M); // @fixme: neg Y
ddraw_color(YELLOW);
//ddraw_aabb(box.min, box.max);
}
profile("Skeletal render") for(int i = 0; i < countof(robots); ++i) {
float scale = 0.50;
mat44 M; copy44(M, robots[i].pivot); translate44(M, i*3,0,0); scale44(M, scale,scale,scale);
model_render(robots[i], cam.proj, cam.view, M, 0);
}
if(do_sponza) profile("Sponza") {
float scale = 1.00;
mat44 M; copy44(M, sponza.pivot); translate44(M, 0,0,0); scale44(M, scale,scale,scale);
model_render(sponza, cam.proj, cam.view, M, 0);
}
if(do_shaderball) profile("Shaderball") {
float scale = 1.00;
mat44 M; copy44(M, shaderball.pivot); translate44(M, 0,0,0); scale44(M, scale,scale,scale);
model_render(shaderball, cam.proj, cam.view, M, 0);
}
// post-fxs end here
fx_end();
// font demo
do_once font_scales(FONT_FACE1, 48, 24, 18, 12, 9, 6);
font_print(va(FONT_RIGHT FONT_BOTTOM FONT_H4 "%5.2f FPS", window_fps()));
// queue ui
if( ui_panel("App", 0)) {
if(ui_bool("Show debugdraw demo", &do_debugdraw)) {}
if(ui_separator()) {}
if(ui_slider("Gamepad deadzone", &do_gamepad_deadzone)) {}
if(ui_float2("Gamepad polarity", do_gamepad_polarity.v2)) {}
if(ui_float2("Gamepad sensitivity", do_gamepad_sensitivity.v2)) {}
if(ui_separator()) {}
if(ui_float2("Mouse polarity", do_mouse_polarity.v2)) {}
if(ui_float2("Mouse sensitivity", do_mouse_sensitivity.v2)) {}
if(ui_separator()) {}
if(ui_button("About...")) { do_about = 1; audio_play(SFX1, 0); }
if(ui_dialog("About", __FILE__ "\n" __DATE__ "\n" "Public Domain.", 0, &do_about)) {}
ui_panel_end();
}
if( ui_panel("Camera", 0)) {
if( ui_float("Speed", &cam.speed) ) {}
if( ui_float3("Position", cam.position.v3) ) {}
ui_panel_end();
}
if( ui_panel("Audio", 0)) {
static float bgm = 1, sfx = 1, master = 1;
if( ui_slider2("BGM", &bgm, va("%.2f", bgm))) audio_volume_stream(bgm);
if( ui_slider2("SFX", &sfx, va("%.2f", sfx))) audio_volume_clip(sfx);
if( ui_slider2("Master", &master, va("%.2f", master))) audio_volume_master(master);
if( ui_label2_toolbar("BGM: Waterworld Map" /*Wrath of the Djinn"*/, ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM1, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM2, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("BGM: Monkey Island", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM3, AUDIO_SINGLE_INSTANCE);
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, 0);
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, 0);
ui_panel_end();
}
input_demo(); // show some keyboard/mouse/gamepad UI tabs
ui_demo(1); // show all UI widgets in a tab
}
// data tests (json5)
const char json5[] =
" /* json5 */ // comment\n"
" abc: 42.67, def: true, integer:0x100 \n"
" huge: 2.2239333e5, \n"
" hello: 'world /*comment in string*/ //again', \n"
" children : { a: 1, b: 2, c: 3 },\n"
" array: [+1,2,-3,4,5], \n"
" invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],";
if( json_push(json5) ) {
assert( json_float("/abc") == 42.67 );
assert( json_int("/def") == 1 );
assert( json_int("/integer") == 0x100 );
assert( json_float("/huge") > 2.22e5 );
assert( strlen(json_string("/hello")) == 35 );
assert( json_int("/children/a") == 1 );
assert( json_int("/children.b") == 2 );
assert( json_int("/children[c]") == 3 );
assert( json_int("/array[%d]", 2) == -3 );
assert( json_count("/invalids") == 8 );
assert( isnan(json_float("/invalids[0]")) );
assert( !json_find("/non_existing") );
assert( PRINTF("json5 tests OK\n") );
json_pop();
}
// data tests (xml)
const char *xml = vfs_read("test1.xml");
if( xml_push(xml) ) {
puts( xml );
puts( xml_string("/person/firstName/$") );
puts( xml_string("/person/lastName/$") );
puts( xml_string("/person/address/@type") );
xml_pop();
}
// network test (https)
array(char) webfile = download("https://www.google.com/");
printf("Network test: %d bytes downloaded from google.com\n", array_count(webfile));
// script test (lua)
script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" );
}

View File

@ -1,176 +0,0 @@
#include "v4k.h"
#define WS 32
enum {
WALL=2, DOOR=4
};
typedef struct {
int16_t id:8;
int16_t flags:8;
} cell_t;
#define cell_t(...) C_CAST(cell_t, __VA_ARGS__)
typedef struct {
cell_t grid[WS*WS];
mesh_t level;
} world_t;
static world_t world;
void world_init() {
int i, j;
for (i = 0; i < WS; ++i) {
for (j = 0; j < WS; ++j) {
if (i == 0 || i == WS-1 || j == 0 || j == WS-1) {
// Border cells
world.grid[i*WS + j] = cell_t(0, WALL);
} else {
// Interior cells
world.grid[i*WS + j] = cell_t(rand()%3, 0);
}
}
}
world.level = mesh();
const int cube_vertices = 24;
const int cube_triangles = 12;
const int vertex_count = WS * WS * cube_vertices;
const int index_count = WS * WS * cube_triangles * 3;
struct vert {
vec3 pos;
vec3 normal;
};
struct vert verts[vertex_count];
unsigned index_data[index_count];
int vertex_index = 0;
int index_index = 0;
static vec3 normals[6] = {
{1, 0, 0}, {-1, 0, 0},
{0, 1, 0}, {0, -1, 0},
{0, 0, 1}, {0, 0, -1}
};
for(int z = 0; z < WS; ++z) {
for(int x = 0; x < WS; ++x) {
if(world.grid[z*WS + x].id >= 0) {
for(int face = 0; face < 6; ++face) {
for(int i = 0; i < 4; ++i) {
vertex_index++;
}
}
// Create 12 triangles for the cube
static unsigned indices[12][3] = {
{0, 1, 2}, {2, 1, 3}, {4, 5, 6}, {6, 5, 7},
{0, 4, 1}, {1, 4, 5}, {2, 6, 3}, {3, 6, 7},
{0, 2, 4}, {4, 2, 6}, {1, 3, 5}, {5, 3, 7}
};
for(int i = 0; i < 12; ++i) {
for(int j = 0; j < 3; ++j) {
index_data[index_index++] = vertex_index - 24 + indices[i][j];
}
}
}
}
}
mesh_update(&world.level, "p3 n3", sizeof(struct vert), vertex_count, verts, index_count, index_data, 0);
}
void draw_world() {
static mat44 M; do_once id44(M);
static mat44 VP; multiply44x2(VP, camera_get_active()->proj, camera_get_active()->view);
static const char *vs =
"#version 130\n"
"//" FILELINE "\n"
"uniform mat4 M,VP;\n"
"in vec3 att_position;\n"
"in vec3 att_normal;\n"
"out vec3 v_normal;\n"
"void main() {\n"
" v_normal = normalize(att_position);\n"
" gl_Position = M * VP * vec4( att_position, 1.0 );\n"
"}\n";
static const char *fs =
"#version 130\n"
"//" FILELINE "\n"
"in vec3 v_normal;\n"
"out vec4 fragcolor;\n"
"void main() {\n"
"fragcolor = vec4(v_normal, 1.0);\n" // diffuse
"}";
static unsigned program; do_once program = shader(vs, fs, "att_position,att_normal", "fragcolor", "");
shader_bind(program);
shader_mat44("VP", VP);
shader_mat44("M", M);
mesh_render(&world.level);
}
int main() {
window_create(80, WINDOW_MSAA8);
window_title(__FILE__);
// init world
world_init();
// load all fx files
fx_load("fx**.fs");
// load skybox
skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", 0); // --mie for rayleigh/mie scattering
// camera
camera_t cam = camera();
cam.speed = 0.2f;
// audio (both clips & streams)
// audio_t SFX1 = audio_clip( "coin.wav" );
// audio_t SFX2 = audio_clip( "pew.sfxr" );
// audio_t BGM1 = audio_stream( "waterworld-map.fur"); // wrath_of_the_djinn.xm" );
// audio_t BGM2 = audio_stream( "larry.mid" );
// audio_t BGM3 = audio_stream( "monkey1.mid" ), BGM = BGM1;
// audio_play(SFX1, 0);
// audio_play(BGM1, 0);
while (window_swap()) {
// input
if( input_down(KEY_ESC) ) break;
if( input_down(KEY_F5) ) window_reload();
if( input_down(KEY_W) && input_held(KEY_LCTRL) ) break;
if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 );
if( input_down(KEY_X) ) window_screenshot(__FILE__ ".png");
if( input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
// fps camera
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
camera_move(&cam, wasdecq.x,wasdecq.y,wasdecq.z);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
fx_begin();
skybox_render(&sky, cam.proj, cam.view);
draw_world();
fx_end();
}
return 0;
}

View File

@ -1,62 +0,0 @@
// instanced models demo
// - rlyeh, public domain.
#include "v4k.h"
int main() {
window_create(75, WINDOW_MSAA2);
window_title(__FILE__);
camera_t cam = camera();
skybox_t sky = skybox("cubemaps/stardust", 0);
model_t girl = model("kgirls01.fbx", 0);
while( window_swap() ) {
if(input(KEY_F5)) window_reload();
if(input(KEY_ESC)) break;
// fps camera
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
window_cursor( !active );
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
camera_fps(&cam, mouse.x,mouse.y);
// ground rendering
ddraw_ground(0);
ddraw_flush();
// skeletal
profile("Skeletal update") {
float delta = window_has_pause() ? 0 : window_delta() * 30; // 30fps anim
girl.curframe = model_animate(girl, girl.curframe + delta);
}
profile("Skeletal render") {
enum { ROW = 32, MAX_INSTANCES = ROW * ROW };
static mat44 M[MAX_INSTANCES];
do_once {
int i = 0;
for(int z = 0; z < ROW; ++z) {
for(int x = 0; x < ROW; ++x, ++i) {
vec3 p = vec3(-x*3,0,-z*3);
vec3 r = vec3(0,0,0);
vec3 s = vec3(2,2,2);
rotationq44(M[i], eulerq(r)); scale44(M[i], s.x,s.y,s.z); relocate44(M[i], p.x,p.y,p.z);
}
}
}
model_render_instanced(girl, cam.proj, cam.view, M, 0, MAX_INSTANCES);
}
// skybox
profile("Skybox") {
skybox_render(&sky, cam.proj, cam.view);
}
}
}

View File

@ -1,3 +1,8 @@
// pathfind demo
// - rlyeh, public domain
//
// @todo: use 2d sprites instead, will shorten things
#include "v4k.h"
bool topdown_cam = 1;
@ -5,7 +10,7 @@ bool topdown_cam = 1;
void move_players();
int main() {
window_create(75, 0); // WINDOW_MSAA4);
window_create(85, 0); // WINDOW_MSAA4);
window_title(__FILE__);
window_fps_lock(60);
@ -49,6 +54,10 @@ void draw_scene() {
float dd = randi(1,10);
float hh = randi(3,10);
aabb b = { vec3(ox,0,oz), vec3(ox+ww,hh,oz+dd) };
static aabb spawn_zone = { {-10,-10,-10},{10,10,10} };
if( aabb_hit_aabb(b, spawn_zone) ) continue;
array_push(blockers, b);
for( int y = oz; y < (oz+dd); ++y )
@ -248,7 +257,9 @@ void move_players() {
// ui
if( ui_panel("Controls", 0) ) {
ui_label2("Girl", ICON_MD_MOUSE " Set Waypoint");
ui_label2("[F1]", ICON_MD_KEYBOARD " Debug traversal visualization");
ui_label2("[Left mouse]", ICON_MD_MOUSE " Set Waypoint");
ui_label2("[Right mouse]", ICON_MD_MOUSE " Toggle camera");
ui_label2("Girl", ICON_MD_GAMEPAD " CURSOR keys");
ui_label2("Alien", ICON_MD_GAMEPAD " W,A,S,D keys");
ui_label2("Robot", ICON_MD_GAMEPAD " I,J,K,L keys");

View File

@ -648,16 +648,6 @@ int main( int argc, const char *argv[] ) {
ui_panel_end();
}
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
ui_fx(i);
}
ui_panel_end();
}
if( ui_panel("Help", 0)) {
if( fps_mode ) {
ui_label("TAB: switch to Orbit camera mode");

View File

@ -1,146 +0,0 @@
#include "v4k.h"
typedef void* (*rpc_function)();
typedef struct rpc_call {
char *method;
rpc_function function;
uint64_t function_hash;
} rpc_call;
#define RPC_SIGNATURE_i_iii UINT64_C(0x78409099752fa48a) // printf("%llx\n, HASH_STR("int(int,int,int)"));
#define RPC_SIGNATURE_i_ii UINT64_C(0x258290edf43985a5) // printf("%llx\n, HASH_STR("int(int,int)"));
#define RPC_SIGNATURE_s_s UINT64_C(0x97deedd17d9afb12) // printf("%llx\n, HASH_STR("char*(char*)"));
#define RPC_SIGNATURE_s_v UINT64_C(0x09c16a1242049b80) // printf("%llx\n, HASH_STR("char*(void)"));
static
rpc_call rpc_new_call(const char *signature, rpc_function function) {
if( signature && function ) {
array(char*)tokens = strsplit(signature, "(,)");
if( array_count(tokens) >= 1 ) {
char *method = strrchr(tokens[0], ' ')+1;
char *rettype = va("%.*s", (int)(method - tokens[0] - 1), tokens[0]);
int num_args = array_count(tokens) - 1;
char* hash_sig = va("%s(%s)", rettype, num_args ? (array_pop_front(tokens), strjoin(tokens, ",")) : "void");
uint64_t hash = hash_str(hash_sig);
method = va("%s%d", method, num_args );
#if RPC_DEBUG
printf("%p %p %s `%s` %s(", function, (void*)hash, rettype, hash_sig, method); for(int i = 0, end = array_count(tokens); i < end; ++i) printf("%s%s", tokens[i], i == (end-1)? "":", "); puts(");");
#endif
return (rpc_call) { strdup(method), function, hash }; // LEAK
}
}
return (rpc_call) {0};
}
static map(char*, rpc_call) rpc_calls = 0;
static
void rpc_insert(const char *signature, void *function ) {
rpc_call call = rpc_new_call(signature, function);
if( call.method ) {
if( !rpc_calls ) map_init(rpc_calls, less_str, hash_str);
if( map_find(rpc_calls, call.method)) {
map_erase(rpc_calls, call.method);
}
map_insert(rpc_calls, call.method, call);
}
}
static
char *rpc_full(unsigned id, const char* method, unsigned num_args, char *args[]) {
#if RPC_DEBUG
printf("id:%x method:%s args:", id, method );
for( int i = 0; i < num_args; ++i ) printf("%s,", args[i]); puts("");
#endif
method = va("%s%d", method, num_args);
rpc_call *found = map_find(rpc_calls, (char*)method);
if( found ) {
switch(found->function_hash) {
case RPC_SIGNATURE_i_iii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1]), atoi(args[2])) );
case RPC_SIGNATURE_i_ii: return va("%d %d", id, (int)(uintptr_t)found->function(atoi(args[0]), atoi(args[1])) );
case RPC_SIGNATURE_s_s: return va("%d %s", id, (char*)found->function(args[0]) );
case RPC_SIGNATURE_s_v: return va("%d %s", id, (char*)found->function() );
default: break;
}
}
return va("%d -1", id);
}
static
array(char*) rpc_parse_args( const char *cmdline, bool quote_whitespaces ) { // parse cmdline arguments. must array_free() after use
// - supports quotes: "abc" "abc def" "abc \"def\"" "abc \"def\"""ghi" etc.
// - #comments removed
array(char*) args = 0; // LEAK
for( int i = 0; cmdline[i]; ) {
char buf[256] = {0}, *ptr = buf;
while(cmdline[i] && isspace(cmdline[i])) ++i;
bool quoted = cmdline[i] == '\"';
if( quoted ) {
while(cmdline[++i]) {
char ch = cmdline[i];
/**/ if (ch == '\\' && cmdline[i + 1] == '\"') *ptr++ = '\"', ++i;
else if (ch == '\"' && cmdline[i + 1] == '\"') ++i;
else if (ch == '\"' && (!cmdline[i + 1] || isspace(cmdline[i + 1]))) {
++i; break;
}
else *ptr++ = ch;
}
} else {
while(cmdline[i] && !isspace(cmdline[i])) *ptr++ = cmdline[i++];
}
if (buf[0] && buf[0] != '#') { // exclude empty args + comments
if( quote_whitespaces && quoted )
array_push(args, va("\"%s\"",buf));
else
array_push(args, va("%s",buf));
}
}
return args;
}
static
char* rpc(unsigned id, const char* cmdline) {
array(char*) args = rpc_parse_args(cmdline, false);
int num_args = array_count(args);
char *ret = num_args ? rpc_full(id, args[0], num_args - 1, &args[1]) : rpc_full(id, "", 0, NULL);
array_free(args);
return ret;
}
static void enet_quit(void) {
do_once {
// enet_deinitialize();
}
}
static void enet_init() {
do_once {
if( enet_initialize() != 0 ) {
PANIC("cannot initialize enet");
}
atexit( enet_quit );
}
}
// -----------------------------------------------------------------------------
// demo
int rpc_add2(int num1, int num2) {
return num1+num2;
}
int rpc_add3(int num1, int num2, int num3) {
return num1+num2+num3;
}
char *rpc_echo(char *text) {
return text;
}
int main() {
rpc_insert("int add(int,int)", rpc_add2);
rpc_insert("int add(int,int,int)", rpc_add3);
rpc_insert("char* echo(char*)", rpc_echo);
puts(rpc(0,"add 1 2")); // -> 3
puts(rpc(1,"add 100 3 -3")); // -> 100
puts(rpc(2,"echo \"hello world\"")); // -> hello world
}

View File

@ -1,44 +0,0 @@
// shadertoy viewer
// - rlyeh, public domain
#include "v4k.h"
int main() {
window_create(75, 0); // WINDOW_MSAA8);
window_title(__FILE__);
const char **list = file_list("demos/art/shadertoys/", "**.fs");
if(!list[0]) exit(-1);
array(char*) browser = 0;
while(*list) array_push(browser, STRDUP(file_name(*list++)));
int browser_count = array_count(browser);
shadertoy_t sh = {0};
while(window_swap() && !input(KEY_ESC)) {
if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 );
// selector
int next = input_down(KEY_UP) || input_down(KEY_LEFT);
int prev = input_down(KEY_DOWN) || input_down(KEY_RIGHT);
static int selector = 0;
static int reload = 1;
if( next ) if( selector > 0 ) --selector, reload = 1;
if( prev ) if( selector < browser_count - 1 ) ++selector, reload = 1;
if( reload ) {
reload = 0;
window_title(va("V4K - %s", browser[selector]));
sh = shadertoy( browser[selector], 0 );
}
// draw
shadertoy_render(&sh, window_delta());
// UI
if( ui_panel("Shadertoy", 0)) {
if( ui_list("In use", (const char**)browser, browser_count, &selector) ) {
reload = 1;
}
ui_panel_end();
}
}
}

View File

@ -11,7 +11,7 @@ int main() {
fx_load("fx**.fs");
// load skybox
skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", 0); // --mie for rayleigh/mie scattering
skybox_t sky = skybox(flag("--mie") ? 0 : "hdr/Tokyo_BigSight_1k.hdr", 0); // --mie for rayleigh/mie scattering
// load static scene
model_t sponza;
@ -70,6 +70,6 @@ int main() {
model_render(sponza, cam.proj, cam.view, M, 0);
// post-fxs end here
fx_end();
fx_end(0);
}
}

View File

@ -1,554 +0,0 @@
// [ref] http://fabiensanglard.net/shadowmappingVSM/index.php
// [ref] http://www.opengl-tutorial.org/es/intermediate-tutorials/tutorial-16-shadow-mapping/
// [ref] https://github.com/cforfang/opengl-shadowmapping
// [ref] https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping
// @todo: spotlight (cone light)
// @todo: pointlight (cubemap light)
// @todo: area light (rect or circle light)
// @todo: directional light (sunlight)
// further reading (in order):
// DPSM [3] Brabec, Annen: Shadow mapping for hemispherical and omnidirectional light sources (2002)
// DPSM* [4] Osman, Bukowski: Practical implementation of dual paraboloid shadow maps (2006)
// IPSM [5] Vanek, Herout: High-quality Shadows with Improved Paraboloid Mapping (2011)
// LiSPSMs
// CSMs
// status: CUBE(0)+BLUR(0): ok
// status: CUBE(0)+BLUR(1): ok
// status: CUBE(1)+BLUR(1): ok
// status: CUBE(1)+BLUR(0): ok
// status: CUBE(?)+BLUR(?): no {
// 003.470s|!cannot find uniform 'shadowMap' in shader program 21 |shader_uniform|v4k_render.c:772
// 001: 00007FF7AF6A3FDA callstack (C:\prj\thread\V4K\v4k_system.c:250)
// 002: 00007FF7AF8E7CBC shader_uniform (C:\prj\thread\V4K\v4k_render.c:772)
// 003: 00007FF7AF691C27 shader_int (C:\prj\thread\V4K\v4k_render.c:777)
// 004: 00007FF7AF8F54EF color_begin (C:\prj\thread\V4K\spot.c:525)
// 005: 00007FF7AF8F5BF7 main (C:\prj\thread\V4K\spot.c:607)
// }
#ifndef VSMCUBE
#define VSMCUBE 0
#endif
#ifndef VSMBLUR
#define VSMBLUR 1
#endif
#include "v4k.h"
#include "split/v4k_shaders.c"
model_t sponza;
typedef struct Mesh
{
GLuint vao;
GLuint vbo;
} Mesh;
static float quadVertices[] = {
// Front-face
// Pos // Color //Tex // Norm
-1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-right
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right
-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, //Bottom-left
-1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left
};
static Mesh create_mesh(float* verts, int size) {
Mesh mesh;
// Create VAO
glGenVertexArrays(1, &mesh.vao);
glBindVertexArray(mesh.vao);
// Create VBO and copy the vertex data to it
glGenBuffers(1, &mesh.vbo);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW);
// Enable attribs
// Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0);
// Color
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float)));
// Texcoords
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float)));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float)));
return mesh;
}
Mesh create_quad() {
return create_mesh(quadVertices, sizeof(quadVertices));
}
struct shadow {
// Resources
GLuint shadowProgram, blurProgram;
Mesh quadMesh;
GLuint shadowMapFBO, shadowMapTex, shadowMapTexDepth;
GLuint blurFBO, blurTex;
// Options
bool do_blur;
bool do_debugshadow;
float BLUR_SCALE; // Amount of blurring [0..100]
GLuint SHADOWMAP_WIDTH; // 256,512,1024,2048
// State
int shadow_active;
vec3 lightPos;
vec3 lightAimPos;
// VSM cubemap
GLuint cubeTex, cubeDepthTex, cubeFBOs[6];
GLuint currentSideTex, currentSideDepthTex;
GLuint toCurrentSideFBO;
} shadow;
#define shadowProgram shadow.shadowProgram
#define blurProgram shadow.blurProgram
#define quadMesh shadow.quadMesh
#define shadowMapFBO shadow.shadowMapFBO
#define shadowMapTex shadow.shadowMapTex
#define shadowMapTexDepth shadow.shadowMapTexDepth
#define blurFBO shadow.blurFBO
#define blurTex shadow.blurTex
#define do_blur shadow.do_blur
#define do_debugshadow shadow.do_debugshadow
#define BLUR_SCALE shadow.BLUR_SCALE
#define SHADOWMAP_WIDTH shadow.SHADOWMAP_WIDTH
#define shadow_active shadow.shadow_active
#define lightPos shadow.lightPos
#define lightAimPos shadow.lightAimPos
// vsm cubemap
#define cubeTex shadow.cubeTex
#define cubeDepthTex shadow.cubeDepthTex
#define cubeFBOs shadow.cubeFBOs
#define currentSideTex shadow.currentSideTex
#define currentSideDepthTex shadow.currentSideDepthTex
#define toCurrentSideFBO shadow.toCurrentSideFBO
static GLuint cubemap_create(GLsizei size, int flags) {
GLenum texel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB32F;
GLenum pixel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB;
GLenum storage = flags & TEXTURE_DEPTH ? GL_FLOAT : GL_UNSIGNED_BYTE; // swap?
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, texel, size, size, 0, pixel, storage, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, texel, size, size, 0, pixel, storage, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL);
if( flags & TEXTURE_DEPTH ) {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return id;
}
static void framebuffer_cube_create(GLuint cube_fbo[6], GLuint cube_texture, GLuint cube_texture_depth) {
glGenFramebuffers(6, cube_fbo);
for (int i = 0; i < 6; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, cube_fbo[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture_depth, 0);
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (GL_FRAMEBUFFER_COMPLETE != result) {
printf("ERROR: Framebuffer is not complete.\n");
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
static void set_shadow_matrix_uniform(const GLuint program, int dir) {
if(dir<0) return;
mat44 P, V, PV;
perspective44(P, 90.0f, 1.0f, 0.5f, 100.0f);
/**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X
else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X
else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y
else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y
else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z
else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z
multiply44x2(PV, P, V); // -Z
shader_bind(program); shader_mat44("cameraToShadowView", V);
shader_bind(program); shader_mat44("cameraToShadowProjector", PV);
}
void shadow_create(int RESOLUTION) {
do_blur = 1;
do_debugshadow = 0;
BLUR_SCALE = 0.5; // Amount of blurring [0..1]
SHADOWMAP_WIDTH = RESOLUTION; // 256,512,1024,2048
lightPos = vec3(-2, 2.0, -2);
lightAimPos = vec3(0.0, 0, -5.0);
// Create programs
shadowProgram = shader(vs_shadow_vsm, fs_shadow_vsm, "position", "outColor", "");
blurProgram = shader(vs_shadow_blur, fs_shadow_blur, "position,,texcoord", "outColor", "");
// ShadowMap-textures and FBO // @todo: GL_RG32F+GL_RG also GL_CLAMP to remove artifacts
shadowMapTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id;
shadowMapTexDepth = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id;
shadowMapFBO = fbo(shadowMapTex, shadowMapTexDepth, 0);
// Textures and FBO to perform blurring
blurTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id;
blurFBO = fbo(blurTex, 0, 0);
#if VSMCUBE
// Create cubemap
cubeTex = cubemap_create(SHADOWMAP_WIDTH, 0);
cubeDepthTex = cubemap_create(SHADOWMAP_WIDTH, TEXTURE_DEPTH);
framebuffer_cube_create(cubeFBOs, cubeTex, cubeDepthTex);
// Temporary storage
currentSideTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT /*| TEXTURE_EDGE*/ ).id;
currentSideDepthTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id;
toCurrentSideFBO = fbo(currentSideTex, currentSideDepthTex, 0);
#endif
}
void shadow_destroy() {
glDeleteProgram(shadowProgram);
glDeleteProgram(blurProgram);
glDeleteTextures(1, &blurTex);
glDeleteFramebuffers(1, &blurFBO);
glDeleteTextures(1, &shadowMapTex);
glDeleteTextures(1, &shadowMapTexDepth);
glDeleteFramebuffers(1, &shadowMapFBO);
}
bool shadow_is_active() {
return shadow_active;
}
void shadow_pv_matrix(mat44 PV) {
mat44 P,V;
// perspective44(P, 45.0f, 1.0f, 2.0f, 100.0f);
perspective44(P, 45*2, window_width() / ((float)window_height()+!window_height()), 1.f, 100.f);
lookat44(V, lightPos, lightAimPos, vec3(0, 1, 0)); // Point toward object regardless of position
multiply44x2(PV, P, V);
}
void shadow_position(vec3 p) {
lightPos = p;
}
void shadow_target(vec3 p) {
lightAimPos = p;
}
void shadow_begin() {
shadow_active = 1;
// shadow_state() {
glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE); glCullFace(GL_BACK);
glFrontFace(GL_CW);
glBlendFunc(1, 0);
#if VSMCUBE
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
#endif
// }
glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO);
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
//glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
mat44 PV; shadow_pv_matrix(PV);
shader_bind(shadowProgram);shader_mat44("cameraToShadowProjector", PV);
}
static void draw_fullscreen_quad() {
//delete_mesh(quadMesh);
if(!quadMesh.vao) quadMesh = create_quad();
glBindVertexArray(quadMesh.vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
static void shadow_blur() {
// remap 0(min)..1(max) -> 2(min)..epsilon(max)
float blur_scale = 1.999 * (1 - BLUR_SCALE) + 0.001;
glDisable(GL_DEPTH_TEST);
// Blur shadowMapTex (horizontally) to blurTex
glBindFramebuffer(GL_FRAMEBUFFER, blurFBO);
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, shadowMapTex); //Input-texture
shader_bind(blurProgram); shader_vec2("ScaleU", vec2(1.0 / (SHADOWMAP_WIDTH*blur_scale), 0));
shader_int("textureSource",0);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_fullscreen_quad();
// Blur blurTex vertically and write to shadowMapTex
glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO);
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, blurTex);
shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 1.0 / (SHADOWMAP_WIDTH*blur_scale)));
shader_int("textureSource",0);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_fullscreen_quad();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_DEPTH_TEST);
}
void shadow_end() {
// Reset
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
if(do_blur) shadow_blur();
shadow_active = 0;
glViewport(0, 0, window_width(), window_height());
}
void shadow_ui() {
// UI
if( ui_panel("Shadow", 0) ) {
if(ui_toggle("Debug", &do_debugshadow)) {}
if(ui_toggle("Blur shadow", &do_blur)) {}
if(ui_slider("Blur amount", &BLUR_SCALE)) {}
ui_panel_end();
}
if(do_debugshadow) {
// Blur and draw to screen
shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 0)); // ... but make sure we don't actually blur
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
draw_fullscreen_quad();
glBindTexture(GL_TEXTURE_2D, 0);
}
}
#define USER_DRAWCALL(shader) do { \
model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shader); \
} while(0)
static void vsm_cube_draw()
{
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
shader_bind(shadowProgram);
// For each side of cubemap
for (int i = 0; i < 6; ++i) {
#if VSMBLUR
// Draw to temp. storage
shader_bind(shadowProgram);
glBindFramebuffer(GL_FRAMEBUFFER, toCurrentSideFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
set_shadow_matrix_uniform(shadowProgram, i);
USER_DRAWCALL(shadowProgram);
// Blur horizontally to blurTex
glDisable(GL_DEPTH_TEST);
shader_bind(blurProgram);
shader_vec2("ScaleU", vec2(1.0 / SHADOWMAP_WIDTH, 0));
glBindFramebuffer(GL_FRAMEBUFFER, blurFBO);
glBindTexture(GL_TEXTURE_2D, currentSideTex);
glClear(GL_COLOR_BUFFER_BIT);
draw_fullscreen_quad();
// Blur vertically to actual cubemap
glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]);
glBindTexture(GL_TEXTURE_2D, blurTex);
shader_bind(blurProgram);
shader_vec2("ScaleU", vec2(0, 1.0 / SHADOWMAP_WIDTH));
draw_fullscreen_quad();
glEnable(GL_DEPTH_TEST);
#else
// Draw directly to cubemap
glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
set_shadow_matrix_uniform(shadowProgram, i);
USER_DRAWCALL(shadowProgram);
#endif
}
// Reset state
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
#undef shadowProgram
#undef blurProgram
#undef quadMesh
#undef shadowMapFBO
#undef shadowMapTex
#undef shadowMapTexDepth
#undef blurFBO
#undef blurTex
#undef do_blur
#undef do_debugshadow
#undef BLUR_SCALE
#undef SHADOWMAP_WIDTH
#undef shadow_active
#undef lightPos
#undef lightAimPos
// Geometry (world coordinates)
static bool do_animate = 1;
static void color_begin(const GLuint program) {
glCullFace(GL_BACK);
#if 1 // VSMCUBE
glViewport(0, 0, window_width(), window_height());
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#endif
// Upload uniforms
shader_bind(program);
shader_mat44("view", camera_get_active()->view);
// shader_mat44("proj", camera_get_active()->proj);
shader_vec3("lightPos", shadow.lightPos);
#if VSMCUBE
set_shadow_matrix_uniform(program, -1);
#else
mat44 PV; shadow_pv_matrix(PV);
shader_mat44("cameraToShadowProjector", PV);
#endif
glActiveTexture(GL_TEXTURE0+1);
#if VSMCUBE
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTex);
#else
glBindTexture(GL_TEXTURE_2D, shadow.shadowMapTex); //Input-texture
#endif
shader_int("shadowMap",1);
}
static void color_end() {
#if VSMCUBE
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
#else
glBindTexture(GL_TEXTURE_2D, 0);
#endif
}
int main(int argc, char **argv)
{
window_create(0.75f, 0);
camera_t cam = camera();
// init shadowing 384x384 // 512x512
shadow_create(argc > 1 ? atoi(argv[1]) : 384);
sponza = model("sponza.obj", 0);
translation44(sponza.pivot, 0,-1,0);
rotate44(sponza.pivot, -90,1,0,0);
scale44(sponza.pivot, 10,10,10);
model_t suzanne = model("suzanne.obj", 0);
// create geometry
GLuint vsm_program = sponza.program;
#if 1
const char *tpl[] = {
"{{include-shadowmap}}", fs_0_0_shadowmap_lit,
};
vsm_program = shader(strlerp(1,tpl,vs_323444143_16_332_model), strlerp(1,tpl,fs_32_4_model), "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent", "fragColor", "");
#endif
while (window_swap())
{
// input
if (input(KEY_ESC))
break;
// fps camera
bool active = ui_active() ? 0 : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
vec3 wasdec = scale3( vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), 0.2f);
vec2 mouse = scale2( vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
#if 1
// animate light
if( do_animate ) {
static vec3 lightPos;
do_once {
lightPos = cam.position;
};
vec3 offs = vec3(sin(window_time()) * 15, 0, cos(window_time()) * 15);
shadow_position(add3(lightPos, offs));
// shadow_target(vec3(0,0,0)); // good for pointlight
shadow_target(add3(add3(lightPos, offs), vec3(0,0,-1)));
}
#else
shadow_position(cam.position);
shadow_target(add3(cam.position, cam.look));
#endif
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// render
#if VSMCUBE
shadow_begin();
vsm_cube_draw();
shadow_end();
#else
shadow_begin();
model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shadow.shadowProgram); //< typo!, but works!
shadow_end();
#endif
color_begin(vsm_program);
model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, vsm_program); // does not work without program
color_end();
// // light bulb (suzanne)
// {
// mat44 M; scaling44(M, 10,10,10); relocate44(M, shadow.lightPos.x, shadow.lightPos.y, shadow.lightPos.z );
// model_render(suzanne, camera_get_active()->proj, camera_get_active()->view, M, 0);
// }
// if( ui_panel("App", 0) ) {
// if(ui_toggle("Animate light", &do_animate)) {}
// ui_panel_end();
// }
// shadow_ui();
}
}

View File

@ -1,227 +0,0 @@
// sprite routines
// - rlyeh,
//
// credits: original lovely demo by rxi (MIT License).
// see https://github.com/rxi/autobatch/tree/master/demo/cats
#include "v4k.h"
texture_t kids, catImage, shadowImage, inputs;
int NUM_SPRITES = 100, NUM_SPRITES_CHANGED = 1;
typedef struct Cat {
int cat, flip;
double x, y;
double vx, vy;
double animSpeed;
double moveTimer;
double elapsed;
} Cat;
void demo_cats() {
static array(Cat) cats = 0;
// init
if( NUM_SPRITES_CHANGED ) {
NUM_SPRITES_CHANGED = 0;
array_resize(cats, NUM_SPRITES); int i = 0;
for each_array_ptr(cats, Cat, c) {
randset(i++);
c->x = randf() * window_width();
c->y = randf() * window_height();
c->vx = c->vy = 0;
c->cat = randi(0, 4);
c->flip = randf() < 0.5;
c->animSpeed = 0.8 + randf() * 0.3;
c->moveTimer = 0;
c->elapsed = 0;
}
}
// move
const float dt = 1/120.f;
const int appw = window_width(), apph = window_height();
enum { yscale = 1 };
for( int i = 0; i < NUM_SPRITES; ++i ) {
Cat *c = &cats[i];
// Add velocity to position //and wrap to screen
c->x += yscale * c->vx * dt; // % ;
c->y += yscale * c->vy * dt; // % (int)window_height();
if( c->x < 0 ) c->x += appw; else if( c->x > appw ) c->x -= appw;
if( c->y < 0 ) c->y += apph; else if( c->y > apph ) c->y -= apph;
// Faster animation if walking
int boost = c->vx == 0 && c->vy == 0 ? 1 : 3;
// Update elapsed time
c->elapsed += dt * boost;
// Update move timer -- if we hit zero then change or zero velocity
c->moveTimer -= dt * boost;
if (c->moveTimer < 0) {
if (randf() < .2) {
c->vx = (randf() * 2 - 1) * 30 * 2;
c->vy = (randf() * 2 - 1) * 15 * 2;
c->flip = c->vx < 0;
} else {
c->vx = c->vy = 0;
}
c->moveTimer = 1 + randf() * 5;
}
}
// render
uint32_t white = rgba(255,255,255,255);
uint32_t alpha = rgba(255,255,255,255*0.6);
for( int i = 0; i < NUM_SPRITES; ++i ) {
Cat *c = &cats[i];
// Get current animation frame (8x4 tilesheet)
double e = c->elapsed * c->animSpeed;
double frame_num = c->cat * 8 + floor( ((int)(e * 8)) % 4 );
frame_num = c->vx != 0 || c->vy != 0 ? frame_num + 4 : frame_num;
// Get x scale based on flip flag
int xscale = yscale * (c->flip ? -1 : 1);
// Draw
float angle = 0; //fmod(window_time()*360/5, 360);
float scale[2] = { 2*xscale, 2*yscale };
float position[3] = { c->x,c->y,c->y }, no_offset[2] = {0,0}, spritesheet[3] = { frame_num,8,4 };
sprite_sheet(catImage,
spritesheet, // frame_number in a 8x4 spritesheet
position, angle, // position(x,y,depth: sort by Y), angle
no_offset, scale, // offset(x,y), scale(x,y)
0,white,0 // is_additive, tint color, resolution independant
);
float position_neg_sort[3] = { c->x,c->y,-c->y }, offset[2] = {-1,5}, no_spritesheet[3] = {0,0,0};
sprite_sheet(shadowImage,
no_spritesheet, // no frame_number (0x0 spritesheet)
position_neg_sort, angle, // position(x,y,depth: sort by Y), angle
offset, scale, // offset(x,y), scale(x,y)
0,alpha,0 // is_additive, tint color, resolution independant
);
}
}
void demo_kids() {
static int angle; //++angle;
static int *x, *y, *v;
// init
if( NUM_SPRITES_CHANGED ) {
NUM_SPRITES_CHANGED = 0;
y = (int*)REALLOC(y, 0 );
x = (int*)REALLOC(x, NUM_SPRITES * sizeof(int) );
y = (int*)REALLOC(y, NUM_SPRITES * sizeof(int) );
v = (int*)REALLOC(v, NUM_SPRITES * sizeof(int) );
for( int i = 0; i < NUM_SPRITES; ++i ) {
randset(i);
x[i] = randi(0, window_width());
y[i] = randi(0, window_height());
v[i] = randi(1, 3);
}
}
// config
const int appw = window_width(), apph = window_height();
// move & render
for( int i = 0; i < NUM_SPRITES; ++i ) {
y[i] = (y[i] + v[i]) % (apph + 128);
int col = ((x[i] / 10) % 4); // 4x4 tilesheet
int row = ((y[i] / 10) % 4);
int num_frame = col * 4 + row;
float position[3] = {x[i],y[i],y[i]}, offset[2]={0,0}, scale[2]={1,1}, spritesheet[3]={num_frame,4,4};
sprite_sheet(kids,
spritesheet, // num_frame in a 4x4 spritesheet
position, angle, // position(x,y,depth: sort by Y), angle
offset, scale, // offset(x,y), scale(x,y)
0, ~0u, 0 // is_additive, tint color, resolution independant
);
}
}
int main(int argc, char **argv) {
window_create(75.f, 0);
window_title("V4K - Sprite");
window_color( SILVER );
// options
int do_cats = 1;
NUM_SPRITES = optioni("--num_sprites,-N", NUM_SPRITES);
if(do_cats) NUM_SPRITES/=2; // cat-sprite+cat-shadow == 2 sprites
// load sprites and sheets
kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
catImage = texture( "cat.png", TEXTURE_LINEAR ); //
shadowImage = texture( "cat-shadow.png", TEXTURE_LINEAR );
inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
// load all fx files, including subdirs
fx_load("fx**.fs");
// init camera (x,y) (z = zoom)
camera_t cam = camera();
cam.position = vec3(window_width()/2,window_height()/2,1);
camera_enable(&cam);
while(window_swap()) {
if( input(KEY_F5)) window_reload();
if( input(KEY_F11)) window_fullscreen( window_has_fullscreen() ^ 1);
if( input(KEY_ESC) ) break;
// camera panning (x,y) & zooming (z)
if( !ui_hover() && !ui_active() ) {
if( input(MOUSE_L) ) cam.position.x -= input_diff(MOUSE_X);
if( input(MOUSE_L) ) cam.position.y -= input_diff(MOUSE_Y);
cam.position.z += input_diff(MOUSE_W) * 0.1; // cam.p.z += 0.001f; for tests
}
// apply post-fxs from here
fx_begin();
profile("Sprite batching") {
if(do_cats) demo_cats(); else demo_kids();
}
// flush retained renderer, so we ensure the fbos are up to date before fx_end()
profile("Sprite flushing") {
sprite_flush();
}
// post-fxs end here
fx_end();
// draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
{
vec3 old_pos = camera_get_active()->position;
sprite_flush();
camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
float zindex = window_height(); // large number, on top
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
float position[3] = {window_width() - tile_w, window_height() - tile_h, zindex }; // position in screen-coordinates
sprite_sheet(inputs, spritesheet, position, 0/*rotation*/, offset, scale, false/*is_additive*/, WHITE/*color*/, false/*resolution_independant*/);
sprite_flush();
camera_get_active()->position = old_pos;
}
if( ui_panel("Sprite", 0) ) {
const char *labels[] = {"Kids","Cats"};
if( ui_list("Sprite type", labels, countof(labels), &do_cats) ) NUM_SPRITES_CHANGED = 1;
if( ui_int("Number of Sprites", &NUM_SPRITES) ) NUM_SPRITES_CHANGED = 1;
if( ui_clampf("Zoom", &cam.position.z, 0.1, 10));
ui_panel_end();
}
if( ui_panel("FX", 0) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
ui_fx(i);
}
ui_panel_end();
}
}
}

View File

@ -76,7 +76,7 @@ int main() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, TEX_WIDTH, TEX_WIDTH, 0, GL_RGBA, GL_FLOAT, img);
shader_bind(comp);
compute_dispatch(TEX_WIDTH/16, TEX_WIDTH/16, 1);
image_write_barrier();
write_barrier_image();
} else {
temp_calc(img);
texture_update(&tex, TEX_WIDTH, TEX_WIDTH, 4, img, TEXTURE_LINEAR|TEXTURE_FLOAT);

View File

@ -1,9 +1,9 @@
uniform float intensity = 0.003f; /// min:0.001 max:0.10 set:0.003
uniform float angle = 0.0f; /// min:0 max:6.28 set:0
uniform float separation; /// min:-0.10 max:0.10 set:0.003
uniform float angle; /// min:0 max:6.28 set:0
void main() {
vec2 uv = TEXCOORD.st;
vec2 offset = intensity * vec2( cos(angle), sin(angle) );
vec2 offset = separation * vec2( cos(angle), sin(angle) );
vec4 color = texture( iChannel0, uv);
color.r = texture( iChannel0, uv + offset ).x;
color.b = texture( iChannel0, uv - offset ).z;

View File

@ -1,4 +1,4 @@
uniform float intensity = 2.0; /// set:2.0
uniform float intensity; /// set:2.0
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;

View File

@ -0,0 +1,15 @@
// [ref] https://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
uniform float intensity; /// set:4
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec4 base = texture(iChannel0, uv), color = vec4(0.0);
vec2 offset = vec2(intensity,0) / iResolution;
color += base * 0.30;
color += texture(iChannel0, uv + offset) * 0.35;
color += texture(iChannel0, uv - offset) * 0.35;
fragColor = vec4( color.rgb, base.a );
}

View File

@ -0,0 +1,15 @@
// [ref] https://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
uniform float intensity; /// set:4
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec4 base = texture(iChannel0, uv), color = vec4(0.0);
vec2 offset = vec2(0,intensity) / iResolution;
color += base * 0.30;
color += texture(iChannel0, uv + offset) * 0.35;
color += texture(iChannel0, uv - offset) * 0.35;
fragColor = vec4( color.rgb, base.a );
}

View File

@ -1,6 +1,6 @@
// [ref] https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
uniform int colorblind_mode = 2; /// min:0 max:4 set:2 tip:"off, achromatopsia, protanomaly, deuteranomaly, tritanomaly"
uniform int colorblind_mode; /// set:2 min:0 max:4 tip:"off, achromatopsia, protanomaly, deuteranomaly, tritanomaly"
uniform mat3 colorblind_matrices[5] = mat3[5](
mat3(1.000,0.000,0.000, 0.000,1.000,0.000, 0.000,0.000,1.000), // 0 no colorblind
mat3(0.299,0.587,0.114, 0.299,0.587,0.114, 0.299,0.587,0.114), // 1 achromatopsia (luma)

View File

@ -1,5 +1,5 @@
uniform float contrast = 1.5; /// set:1.5 tip:"bleach-to-gray < 1 > saturate"
uniform float brightness = 0; /// set:0 max:2
uniform float contrast; /// set:1.5 tip:"bleach-to-gray < 1 > saturate"
uniform float brightness; /// set:0 max:2
void main() {
vec4 pixelColor = texture(iChannel0, TEXCOORD.st);

View File

@ -1,4 +1,4 @@
uniform float intensity = 0.004; /// set:0.004 max:0.03
uniform float intensity; /// set:0.004 max:0.03
highp float rand(vec2 co) {
highp float a = 12.9898;

View File

@ -1,3 +1,5 @@
/// tip:"Requires MSAA off for best results"
// FXAA fragment shader by Timothy Lottes (public domain)
// http://timothylottes.blogspot.com/

View File

@ -1,3 +1,5 @@
/// tip:"Requires MSAA off for best results"
/*****************************************
* FXAA 3.11 Implementation - effendiian
* -------------------------------------

View File

@ -1,4 +1,4 @@
uniform float intensity = 16.0; /// set:16 max:32
uniform float intensity; /// set:16 max:32
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;

View File

@ -1,6 +1,6 @@
uniform float h = 1.0; /// set:1.0 tip:"hue color shift"
uniform float s = 0.5; /// set:0.5 tip:"gray: <1, saturate: >1"
uniform float v = 1.0; /// set:1.0 tip:"black: <1, white: >1"
uniform float h; /// set:1.58 tip:"hue color shift"
uniform float s; /// set:1.51 tip:"gray: <1, saturate: >1"
uniform float v; /// set:1.05 tip:"black: <1, white: >1"
vec3 hsv2rgb(vec3 c) {
return mix(vec3(1.),clamp((abs(fract(c.r+vec3(3.,2.,1.)/3.)*6.-3.)-1.),0.,1.),c.g)*c.b;

View File

@ -1,10 +1,13 @@
uniform float amount; /// min:0 set:0.10 max:0.5
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
// letterbox
if( abs(2.*fragCoord.y-iResolution.y) > iResolution.x * 0.42 ) {
if( uv.y < amount || (1.0-uv.y) < amount ) {
fragColor = vec4( 0., 0., 0., 1. );
return;
}
vec2 uv = fragCoord.xy / iResolution.xy;
fragColor = texture(iChannel0, uv);
}

View File

@ -1,5 +1,7 @@
uniform int thickness = 2; /// set:2
uniform vec4 border_color = vec4(1,1,0,1); /// set:1,1,0,1
/// tip:"Ensure colorbuffer is alpha clear before calling this one."
uniform int thickness; /// set:2
uniform vec4 border_color; /// set:1,1,0,1
void main() {
vec4 texel = texture(iChannel0, uv);

View File

@ -1,6 +1,6 @@
uniform float CellSize = 2.5; /// min:1 set:2.5 max:16
//uniform float xCellSize = 2.5; /// min:1 set:2.5
//uniform float yCellSize = 2.5; /// min:1 set:2.5
uniform float CellSize; /// min:1 set:2.5 max:16
//uniform float xCellSize; /// min:1 set:2.5
//uniform float yCellSize; /// min:1 set:2.5
void main() {
float xPixels = iWidth/CellSize, yPixels = iHeight/CellSize; // iWidth/xCellSize, iHeight/yCellSize;

View File

@ -1,4 +1,4 @@
uniform float factor = 3.0; /// min:1 max:255 set:3
uniform float factor; /// min:1 max:255 set:3
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;

View File

@ -1,7 +1,7 @@
// based on code by arkano22. See: http://www.gamedev.net/forums/topic/550699-ssao-no-halo-artifacts/
// - rlyeh, public domain
uniform vec2 camerarange = vec2(1.0, 1024.0);
uniform vec2 camerarange; /// set:1,1024
// uniform sampler2D som; // Depth texture (iChannel1)

View File

@ -1,5 +1,5 @@
uniform float hardness = 0.1; /// set:0.1 max:2
uniform float flickering = 0.01; /// set:0.01
uniform float hardness; /// set:0.1 max:2
uniform float flickering; /// set:0.01
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;

View File

@ -5,7 +5,7 @@
// note: valve edition from http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// note: input in pixels (ie not normalized uv)
uniform float intensity = 250.0; /// min:245 max:255 set:250
uniform float intensity; /// min:245 max:255 set:250
vec3 ScreenSpaceDither2(vec2 vScreenPos, float colorDepth) {
// lestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR

View File

@ -1,13 +1,13 @@
uniform float intensity = 1.0; /// set:1
uniform float brightness; /// set:1
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec4 src = texture(iChannel0, uv);
vec3 color = vec3(
dot(src.rgb, vec3(0.393 * intensity, 0.769 * intensity, 0.189 * intensity)),
dot(src.rgb, vec3(0.349 * intensity, 0.686 * intensity, 0.168 * intensity)),
dot(src.rgb, vec3(0.272 * intensity, 0.534 * intensity, 0.131 * intensity))
dot(src.rgb, vec3(0.393 * brightness, 0.769 * brightness, 0.189 * brightness)),
dot(src.rgb, vec3(0.349 * brightness, 0.686 * brightness, 0.168 * brightness)),
dot(src.rgb, vec3(0.272 * brightness, 0.534 * brightness, 0.131 * brightness))
);
fragColor = vec4(color, src.a);

View File

@ -1,4 +1,4 @@
uniform float intensity = 0.25; /// set:0.25 max:2
uniform float intensity; /// set:0.25 max:2
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
vec2 uv = fragCoord / iResolution.xy;

View File

@ -1,7 +1,7 @@
// exposure tone mapping
// https://learnopengl.com/Advanced-Lighting/HDR
uniform float exposure = 1.0; // min:0.1 max:5 set:1
uniform float exposure; // min:0.1 max:5 set:1
out vec4 color;

View File

@ -1,4 +1,4 @@
uniform float gamma = 2.2; /// set:2.2
uniform float gamma; /// set:2.2
out vec4 color;
void main(void) {

View File

@ -1,4 +1,4 @@
uniform float radius = 0.75; /// set:0.75
uniform float radius; /// set:0.75
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
http://hdri.cgtechniques.com/~sponza/files/
Sponza modeled by Marko Dabrovic, with UVs and crack errors fixed by Kenzie Lamar at Vicarious Visions.
Bump maps painted by Morgan McGuire.

View File

@ -0,0 +1,21 @@
/// tip:"Ensure colorbuffer is alpha clear before calling this one."
uniform int thickness; /// set:2
uniform vec4 border_color; /// set:1,1,0,1
void main() {
vec4 texel = texture(iChannel0, uv);
float outline = 0.0;
if( texel.a == 0.0 ) {
for( int x = -thickness; x <= thickness; x++ ) {
for( int y = -thickness;y <= thickness; y++ ) {
float sample = texture(iChannel0, uv+vec2(float(x)/iWidth, float(y)/iHeight)).a;
if( sample > 0.0 ) {
outline = 1.0;
}
}
}
}
FRAGCOLOR = vec4(border_color.rgb, outline * border_color.a); // mix(texel, border_color, outline * border_color.a);
}

View File

@ -2313,7 +2313,7 @@ enum { NETWORK_USERID = 7, NETWORK_COUNT , NETWORK_CAPACITY };
extern void (*dtor[256])();
void* obj_initialize( void **ptr, char *type_and_info );
void *obj_tmpalloc;
int profile_enable(bool on);
int profiler_enable(bool on);
struct profile_t { double stat; int32_t cost, avg; };
typedef struct { map base; struct { pair p; char * key; struct profile_t val; } tmp, *ptr; struct profile_t* tmpval; int (*typed_cmp)(char *, char *); uint64_t (*typed_hash)(char *); } * profiler_t;
extern profiler_t profiler;
@ -2504,6 +2504,8 @@ int texture_width;
void shader_destroy(unsigned shader);
unsigned shader_properties(unsigned shader);
char** shader_property(unsigned shader, unsigned property_no);
void shader_apply_param(unsigned shader, unsigned param_no);
void shader_apply_params(unsigned shader, const char *parameter_mask);
int ui_shader(unsigned shader);
int ui_shaders();
enum BUFFER_MODE {
@ -2515,8 +2517,8 @@ BUFFER_READ_WRITE
void compute_dispatch(unsigned wx, unsigned wy, unsigned wz);
void shader_image(texture_t t, unsigned unit, unsigned level, int layer, unsigned access);
void shader_image_unit(unsigned texture, unsigned unit, unsigned level, int layer, unsigned texel_type, unsigned access);
void image_write_barrier();
void write_barrier();
void write_barrier_image();
enum SSBO_USAGE {
STATIC_DRAW,
STATIC_READ,
@ -2968,7 +2970,6 @@ PANEL_OPEN = 1,
int ui_double(const char *label, double *value);
int ui_buffer(const char *label, char *buffer, int buflen);
int ui_string(const char *label, char **string);
int ui_text_wrap(const char *label, char *text);
int ui_color3(const char *label, float *color3);
int ui_color3f(const char *label, float *color3);
int ui_color4(const char *label, float *color4);
@ -2990,18 +2991,17 @@ PANEL_OPEN = 1,
int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh);
int ui_colormap(const char *label, colormap_t *cm);
int ui_separator();
int ui_bits8(const char *label, uint8_t *bits);
int ui_bits16(const char *label, uint16_t *bits);
int ui_bitmask8(const char *label, uint8_t *bits);
int ui_bitmask16(const char *label, uint16_t *bits);
int ui_console();
int ui_clampf(const char *label, float *value, float minf, float maxf);
int ui_label(const char *label);
int ui_label2(const char *label, const char *caption);
int ui_label2_bool(const char *label, bool enabled);
int ui_label2_float(const char *label, float value);
int ui_label2_toolbar(const char *label, const char *icons);
int ui_slider(const char *label, float *value);
int ui_slider2(const char *label, float *value, const char *caption);
int ui_const_bool(const char *label, const double value);
int ui_const_float(const char *label, const double value);
int ui_const_string(const char *label, const char *value);
int ui_contextual_end();
int ui_collapse_clicked();
int ui_collapse_end();
@ -3010,9 +3010,10 @@ PANEL_OPEN = 1,
int ui_show(const char *panel_or_window_title, int enabled);
int ui_dims(const char *panel_or_window_title, float width, float height);
int ui_visible(const char *panel_or_window_title);
int ui_enable(int on);
int ui_enabled();
vec2 ui_get_dims();
int ui_enable();
int ui_enabled();
int ui_disable();
int ui_has_menubar();
int ui_menu(const char *items);
int ui_menu_editbox(char *buf, int bufcap);

View File

@ -14226,14 +14226,14 @@ extern "C" {
// system headers
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // for linux
#define _GNU_SOURCE ///- for linux
#endif
#if is(cl) && is(win32) // for VC IDE
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WIN32_WINNT 0x0600 // 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#define _CRT_SECURE_NO_WARNINGS ///-
#define _CRT_NONSTDC_NO_DEPRECATE ///-
#define _WINSOCK_DEPRECATED_NO_WARNINGS ///-
#define _WIN32_WINNT 0x0600 ///- 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#endif
#if is(cl)
@ -16345,9 +16345,9 @@ static __thread void *obj_tmpalloc;
# define profile(section) for(int macro(i) = 1; macro(i); macro(i) = 0)
# define profile_incstat(name, accum) do {} while(0)
# define profile_setstat(name, value) do {} while(0)
# define profile_init() do {} while(0)
# define profile_render() do {} while(0)
# define profile_enable(x) 0
# define profiler_init() do {} while(0)
# define profiler_enable(x) 0
# define ui_profiler() do {} while(0)
#else
# define profile(section) for( \
struct profile_t *found = profiler_enabled ? \
@ -16360,7 +16360,7 @@ static __thread void *obj_tmpalloc;
# define profile_setstat(name, value) for( \
struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \
found; found->stat = value, found = NULL) ///+
API int profile_enable(bool on);
API int profiler_enable(bool on);
struct profile_t { double stat; int32_t cost, avg; }; ///-
typedef map(char *, struct profile_t) profiler_t; ///-
@ -16715,6 +16715,9 @@ API void shader_destroy(unsigned shader);
API unsigned shader_properties(unsigned shader);
API char** shader_property(unsigned shader, unsigned property_no);
API void shader_apply_param(unsigned shader, unsigned param_no);
API void shader_apply_params(unsigned shader, const char *parameter_mask);
API int ui_shader(unsigned shader);
API int ui_shaders();
@ -16759,12 +16762,12 @@ API void shader_image_unit(unsigned texture, unsigned unit, unsigned level, int
// gpu memory barriers
/// Blocks main thread until all image operations are done by the GPU.
API void image_write_barrier();
/// Blocks main thread until all memory operations are done by the GPU.
API void write_barrier();
/// Blocks main thread until all image operations are done by the GPU.
API void write_barrier_image();
// ssbo
/// `STATIC`, `DYNAMIC` AND `STREAM` specify the frequency at which we intend to access the data.
/// `DRAW` favors CPU->GPU operations.
@ -17485,7 +17488,6 @@ API int ui_float4(const char *label, float value[4]);
API int ui_double(const char *label, double *value);
API int ui_buffer(const char *label, char *buffer, int buflen);
API int ui_string(const char *label, char **string);
API int ui_text_wrap(const char *label, char *text);
API int ui_color3(const char *label, float *color3); //[0..255]
API int ui_color3f(const char *label, float *color3); //[0..1]
API int ui_color4(const char *label, float *color4); //[0..255]
@ -17507,18 +17509,17 @@ API int ui_image(const char *label, handle id, unsigned w, unsigned h); //(w,
API int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh);
API int ui_colormap(const char *label, colormap_t *cm); // returns num member changed: 1 for color, 2 for texture map
API int ui_separator();
API int ui_bits8(const char *label, uint8_t *bits);
API int ui_bits16(const char *label, uint16_t *bits);
API int ui_bitmask8(const char *label, uint8_t *bits);
API int ui_bitmask16(const char *label, uint16_t *bits);
API int ui_console();
API int ui_clampf(const char *label, float *value, float minf, float maxf);
API int ui_label(const char *label);
API int ui_label2(const char *label, const char *caption);
API int ui_label2_bool(const char *label, bool enabled);
API int ui_label2_float(const char *label, float value);
API int ui_label2_toolbar(const char *label, const char *icons);
API int ui_slider(const char *label, float *value);
API int ui_slider2(const char *label, float *value, const char *caption);
API int ui_const_bool(const char *label, const double value);
API int ui_const_float(const char *label, const double value);
API int ui_const_string(const char *label, const char *value);
API int ui_contextual_end();
API int ui_collapse_clicked();
API int ui_collapse_end();
@ -17528,10 +17529,12 @@ API int ui_window_end();
API int ui_show(const char *panel_or_window_title, int enabled);
API int ui_dims(const char *panel_or_window_title, float width, float height);
API int ui_visible(const char *panel_or_window_title); // @todo: include ui_collapse() items that are open as well?
API int ui_enable(int on);
API int ui_enabled();
API vec2 ui_get_dims();
API int ui_enable();
API int ui_enabled();
API int ui_disable();
API int ui_has_menubar();
API int ui_menu(const char *items); // semicolon-separated or comma-separated items
API int ui_menu_editbox(char *buf, int bufcap);
@ -330739,6 +330742,9 @@ float audio_volume_master(float gain) {
}
int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
if(muted) return 1;
if( flags & AUDIO_IGNORE_MIXER_GAIN ) {
// do nothing, gain used as-is
} else {
@ -333133,6 +333139,7 @@ int cook_jobs() {
void cook_config( const char *pathfile_to_cook_ini ) { // @todo: test run-from-"bin/" case on Linux.
COOK_INI = pathfile_to_cook_ini;
ASSERT( file_exist(COOK_INI) );
}
#line 0
@ -337536,32 +337543,37 @@ bool input_touch_active() {
void input_demo() {
if( ui_panel("Input",0) ) {
ui_section("Keyboard");
ui_const_bool("[Key 1]", input(KEY_1));
ui_const_bool("[Key 2]", input(KEY_2));
ui_const_bool("[Key 3]", input(KEY_3));
ui_const_bool("[Key 4]", input(KEY_4));
ui_const_bool("[Key 5]", input(KEY_5));
ui_const_bool("[Key 6]", input(KEY_6));
ui_const_bool("[Key 7]", input(KEY_7));
uint8_t keymap = 0;
keymap |= (!!input(KEY_1)) << 7;
keymap |= (!!input(KEY_2)) << 6;
keymap |= (!!input(KEY_3)) << 5;
keymap |= (!!input(KEY_4)) << 4;
keymap |= (!!input(KEY_5)) << 3;
keymap |= (!!input(KEY_6)) << 2;
keymap |= (!!input(KEY_7)) << 1;
keymap |= (!!input(KEY_8)) << 0;
ui_bitmask8("[Keys 1..8]", &keymap);
ui_separator();
ui_const_bool("[Key 1] Down event", input_down(KEY_1) );
ui_const_bool("[Key 2] Held event", input_held(KEY_2) );
ui_const_bool("[Key 3] Up event", input_up(KEY_3) );
ui_const_bool("[Key 4] Idle event", input_idle(KEY_4) );
ui_const_bool("[Key 5] Click event", input_click(KEY_5,500) );
ui_const_bool("[Key 6] Click2 event", input_click2(KEY_6,1000) );
ui_const_bool("[Key 7] Repeat event", input_repeat(KEY_7,750) );
ui_label2_bool("[Key 1] Down event", input_down(KEY_1) );
ui_label2_bool("[Key 2] Held event", input_held(KEY_2) );
ui_label2_bool("[Key 3] Up event", input_up(KEY_3) );
ui_label2_bool("[Key 4] Idle event", input_idle(KEY_4) );
ui_label2_bool("[Key 5] Click event", input_click(KEY_5,500) );
ui_label2_bool("[Key 6] Click2 event", input_click2(KEY_6,1000) );
ui_label2_bool("[Key 7] Repeat event", input_repeat(KEY_7,750) );
ui_separator();
ui_section("Mouse");
ui_const_float("X", input(MOUSE_X));
ui_const_float("Y", input(MOUSE_Y));
ui_label2_float("X", input(MOUSE_X));
ui_label2_float("Y", input(MOUSE_Y));
ui_separator();
ui_const_float("Wheel", input(MOUSE_W));
ui_label2_float("Wheel", input(MOUSE_W));
ui_separator();
ui_const_bool("Left", input(MOUSE_L));
ui_const_bool("Middle", input(MOUSE_M));
ui_const_bool("Right", input(MOUSE_R));
ui_label2_bool("Left", input(MOUSE_L));
ui_label2_bool("Middle", input(MOUSE_M));
ui_label2_bool("Right", input(MOUSE_R));
ui_separator();
for( int i = 0; i <= CURSOR_SW_AUTO; ++i ) if(ui_button(va("Cursor shape #%d", i))) window_cursor_shape(i);
ui_separator();
@ -337573,45 +337585,45 @@ void input_demo() {
input_use(gamepad_id);
ui_const_string("Name", input_frames(GAMEPAD_NAME,0));
ui_const_bool("Connected", input(GAMEPAD_CONNECTED));
ui_label2("Name", input_frames(GAMEPAD_NAME,0));
ui_label2_bool("Connected", input(GAMEPAD_CONNECTED));
ui_separator();
ui_const_bool("A", input(GAMEPAD_A) );
ui_const_bool("B", input(GAMEPAD_B) );
ui_const_bool("X", input(GAMEPAD_X) );
ui_const_bool("Y", input(GAMEPAD_Y) );
ui_const_bool("Up", input(GAMEPAD_UP) );
ui_const_bool("Down", input(GAMEPAD_DOWN) );
ui_const_bool("Left", input(GAMEPAD_LEFT) );
ui_const_bool("Right", input(GAMEPAD_RIGHT) );
ui_const_bool("Menu", input(GAMEPAD_MENU) );
ui_const_bool("Start", input(GAMEPAD_START) );
ui_label2_bool("A", input(GAMEPAD_A) );
ui_label2_bool("B", input(GAMEPAD_B) );
ui_label2_bool("X", input(GAMEPAD_X) );
ui_label2_bool("Y", input(GAMEPAD_Y) );
ui_label2_bool("Up", input(GAMEPAD_UP) );
ui_label2_bool("Down", input(GAMEPAD_DOWN) );
ui_label2_bool("Left", input(GAMEPAD_LEFT) );
ui_label2_bool("Right", input(GAMEPAD_RIGHT) );
ui_label2_bool("Menu", input(GAMEPAD_MENU) );
ui_label2_bool("Start", input(GAMEPAD_START) );
ui_separator();
ui_const_float("Left pad x", input(GAMEPAD_LPADX) );
ui_const_float("Left pad y", input(GAMEPAD_LPADY) );
ui_const_float("Left trigger", input(GAMEPAD_LT) );
ui_const_bool("Left bumper", input(GAMEPAD_LB) );
ui_const_bool("Left thumb", input(GAMEPAD_LTHUMB) );
ui_label2_float("Left pad x", input(GAMEPAD_LPADX) );
ui_label2_float("Left pad y", input(GAMEPAD_LPADY) );
ui_label2_float("Left trigger", input(GAMEPAD_LT) );
ui_label2_bool("Left bumper", input(GAMEPAD_LB) );
ui_label2_bool("Left thumb", input(GAMEPAD_LTHUMB) );
vec2 v = input_filter_deadzone( input2(GAMEPAD_LPADX), 0.1f );
ui_const_float("Filtered pad x", v.x);
ui_const_float("Filtered pad y", v.y);
ui_label2_float("Filtered pad x", v.x);
ui_label2_float("Filtered pad y", v.y);
ui_separator();
ui_const_float("Right pad x", input(GAMEPAD_RPADX) );
ui_const_float("Right pad y", input(GAMEPAD_RPADY) );
ui_const_float("Right trigger", input(GAMEPAD_RT) );
ui_const_bool("Right bumper", input(GAMEPAD_RB) );
ui_const_bool("Right thumb", input(GAMEPAD_RTHUMB) );
ui_label2_float("Right pad x", input(GAMEPAD_RPADX) );
ui_label2_float("Right pad y", input(GAMEPAD_RPADY) );
ui_label2_float("Right trigger", input(GAMEPAD_RT) );
ui_label2_bool("Right bumper", input(GAMEPAD_RB) );
ui_label2_bool("Right thumb", input(GAMEPAD_RTHUMB) );
vec2 w = input_filter_deadzone( input2(GAMEPAD_RPADX), 0.1f );
ui_const_float("Filtered pad x", w.x);
ui_const_float("Filtered pad y", w.y);
ui_label2_float("Filtered pad x", w.x);
ui_label2_float("Filtered pad y", w.y);
input_use(0);
@ -339909,22 +339921,23 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
array(char*) props = 0;
do_once map_init_int( shader_reflect );
if(vs) for each_substring(vs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if(fs) for each_substring(fs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if(gs) for each_substring(gs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if( props ) {
map_insert(shader_reflect, program, props);
for( int i = 0; i < array_count(props); ++i ) shader_apply_param(program, i);
}
return program;
@ -339937,7 +339950,60 @@ unsigned shader_properties(unsigned shader) {
char** shader_property(unsigned shader, unsigned property) {
array(char*) *found = map_find(shader_reflect, shader);
return found ? &(*found)[property] : NULL;
return found && property < array_count(*found) ? &(*found)[property] : NULL;
}
void shader_apply_param(unsigned shader, unsigned param_no) {
unsigned num_properties = shader_properties(shader);
if( param_no < num_properties ) {
char *line = *shader_property(shader, param_no);
char type[32], name[32];
if( sscanf(line, "%*s %s %[^ =;/]", type, name) != 2 ) return;
int is_color = !!strstri(name, "color"), top = is_color ? 1 : 10;
vec4 minv = strstr(line, "min:") ? atof4(strstr(line, "min:") + 4) : vec4(0,0,0,0);
vec4 setv = strstr(line, "set:") ? atof4(strstr(line, "set:") + 4) : vec4(0,0,0,0);
vec4 maxv = strstr(line, "max:") ? atof4(strstr(line, "max:") + 4) : vec4(top,top,top,top);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x);
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y);
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z);
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w);
if( !strstr(line, "max:") ) {
if(setv.x > maxv.x) maxv.x = setv.x;
if(setv.y > maxv.y) maxv.y = setv.y;
if(setv.z > maxv.z) maxv.z = setv.z;
if(setv.w > maxv.w) maxv.w = setv.w;
}
setv = clamp4(setv, minv, maxv);
if( strchr("ibfv", type[0]) ) {
GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak);
glUseProgram(shader);
/**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x);
else if(type[0] == 'b') glUniform1i(glGetUniformLocation(shader, name), !!setv.x);
else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x);
else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x);
glUseProgram(shader_bak);
}
}
}
void shader_apply_params(unsigned shader, const char *parameter_mask) {
unsigned num_properties = shader_properties(shader);
for( unsigned i = 0; i < num_properties; ++i ) {
char *line = *shader_property(shader,i);
char name[32];
if( sscanf(line, "%*s %*s %s", name) != 1 ) continue;
if( !strmatch(name, parameter_mask) ) continue;
shader_apply_param(shader, i);
}
}
int ui_shader(unsigned shader) {
@ -339948,25 +340014,43 @@ int ui_shader(unsigned shader) {
char **ptr = shader_property(shader,i);
const char *line = *ptr; // debug: ui_label(line);
char uniform[32], type[32], name[32];
if( sscanf(line, "%s %s %s", uniform, type, name) != 3) continue;
char* tip = strstr(line, "tip:"); tip = tip && tip[4] ? tip + 4 : 0;
char uniform[32], type[32], name[32], early_exit = '\0';
if( sscanf(line, "%s %s %[^ =;/]", uniform, type, name) != 3 ) continue; // @todo optimize: move to shader()
if( strcmp(uniform, "uniform") && strcmp(uniform, "}uniform") ) { if(tip) ui_label(va(ICON_MD_INFO "%s", tip)); continue; } // @todo optimize: move to shader()
int is_color = !!strstri(name, "color"), top = is_color ? 1 : 10;
vec4 minv = strstr(line, "min:") ? atof4(strstr(line, "min:") + 4) : vec4(0,0,0,0);
vec4 setv = strstr(line, "set:") ? atof4(strstr(line, "set:") + 4) : vec4(0,0,0,0);
vec4 maxv = strstr(line, "max:") ? atof4(strstr(line, "max:") + 4) : vec4(top,top,top,top);
char* tip = strstr(line, "tip:"); tip = tip && tip[4] ? tip + 4 : 0;
char *label = !tip ? va("%c%s", name[0] - 32 * !!(name[0] >= 'a'), name+1) :
va("%c%s " ICON_MD_HELP "@%s", name[0] - 32 * !!(name[0] >= 'a'), name+1, tip);
va("%c%s " ICON_MD_INFO "@%s", name[0] - 32 * !!(name[0] >= 'a'), name+1, tip);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x);
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y);
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z);
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x); // @optimize: move to shader()
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y); // @optimize: move to shader()
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z); // @optimize: move to shader()
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w); // @optimize: move to shader()
if( !strstr(line, "max:") ) {
if(setv.x > maxv.x) maxv.x = setv.x;
if(setv.y > maxv.y) maxv.y = setv.y;
if(setv.z > maxv.z) maxv.z = setv.z;
if(setv.w > maxv.w) maxv.w = setv.w;
}
setv = clamp4(setv, minv, maxv);
// supports int,float,vec2/3/4,color3/4
int touched = 0;
if( type[0] == 'i' ) {
if( type[0] == 'b' ) {
bool v = !!setv.x;
if( (touched = ui_bool(label, &v)) != 0 ) {
setv.x = v;
}
}
else if( type[0] == 'i' ) {
int v = setv.x;
if( (touched = ui_int(label, &v)) != 0 ) {
@ -339974,9 +340058,11 @@ int ui_shader(unsigned shader) {
}
}
else if( type[0] == 'f' ) {
setv.x = (clampf(setv.x, minv.x, maxv.x) - minv.x) / (maxv.x - minv.x);
setv.x = clampf(setv.x, minv.x, maxv.x);
char *caption = va("%5.2f", setv.x);
setv.x = (setv.x - minv.x) / (maxv.x - minv.x);
if( (touched = ui_slider2(label, &setv.x, va("%5.2f", setv.x))) != 0 ) {
if( (touched = ui_slider2(label, &setv.x, caption)) != 0 ) {
setv.x = clampf(minv.x + setv.x * (maxv.x-minv.x), minv.x, maxv.x); // min..max range
}
}
@ -340001,28 +340087,20 @@ int ui_shader(unsigned shader) {
setv = clamp4(setv,minv,maxv);
}
}
else if( tip ) ui_label( tip );
if( touched ) {
// send to shader
GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak);
glUseProgram(shader);
/**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x);
else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x);
else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x);
glUseProgram(shader_bak);
// upgrade value
*ptr = FREE(*ptr);
*ptr = stringf("%s %s %s ///set:%s min:%s max:%s tip:%s", uniform,type,name,ftoa4(setv),ftoa4(minv),ftoa4(maxv),tip?tip:"");
// apply
shader_apply_param(shader, i);
changed = 1;
}
}
if(num_properties) ui_separator();
return changed;
}
@ -340030,13 +340108,14 @@ int ui_shaders() {
if( !map_count(shader_reflect) ) return 0;
int changed = 0;
int has_menu = ui_has_menubar();
if( (has_menu ? ui_window("Shaders", 0) : ui_panel("Shaders", 0) ) ) {
for each_map_ptr(shader_reflect, unsigned, k, array(char*), v) {
ui_section(va("Shader %d",*k));
int open = 0, clicked_or_toggled = 0;
char *id = va("##SHD%d", *k);
char *title = va("Shader %d", *k);
for( int p = (open = ui_collapse(title, id)), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_label(va("Shader %d",*k));
changed |= ui_shader(*k);
}
(has_menu ? ui_window_end : ui_panel_end)();
}
return changed;
}
@ -340091,7 +340170,7 @@ void write_barrier(){
glMemoryBarrier(GL_ALL_BARRIER_BITS);
}
void image_write_barrier(){
void write_barrier_image(){
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
@ -342949,9 +343028,9 @@ void postfx_clear(postfx *fx) {
int ui_postfx(postfx *fx, int pass) {
int on = ui_enabled();
ui_enable( postfx_enabled(fx,pass) );
( postfx_enabled(fx,pass) ? ui_enable : ui_disable )();
int rc = ui_shader(fx->pass[pass].program);
ui_enable( on );
( on ? ui_enable : ui_disable )();
return rc;
}
@ -343132,16 +343211,12 @@ int ui_fxs() {
if(!fx.num_loaded) return 0;
int changed = 0;
int has_menu = ui_has_menubar();
if( (has_menu ? ui_window("FX", 0) : ui_panel("FX", 0) ) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
ui_fx(i);
}
(has_menu ? ui_window_end : ui_panel_end)();
}
return changed;
}
@ -347179,8 +347254,8 @@ default_hue = 0.52;
struct nk_color active = nk_hsv_f( 0.600, 0.00, 0.150); // bright b/w
struct nk_color table[NK_COLOR_COUNT] = {0};
table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_WINDOW] = nk_rgba(42, 42, 42, 215);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
table[NK_COLOR_WINDOW] = nk_rgba(42, 42, 42, 245);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 245);
table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
table[NK_COLOR_BUTTON] = main;
table[NK_COLOR_BUTTON_HOVER] = hover;
@ -347571,7 +347646,7 @@ int ui_active() {
}
static
int ui_enable_(int enabled) {
int ui_set_enable_(int enabled) {
static struct nk_style off, on;
do_once {
off = on = ui_ctx->style;
@ -347809,8 +347884,11 @@ int ui_enable_(int enabled) {
}
static int ui_is_enabled = 1;
int ui_enable(int on) {
return ui_is_enabled == on ? 0 : ui_enable_(ui_is_enabled = on);
int ui_enable() {
return ui_is_enabled == 1 ? 0 : ui_set_enable_(ui_is_enabled = 1);
}
int ui_disable() {
return ui_is_enabled == 0 ? 0 : ui_set_enable_(ui_is_enabled = 0);
}
int ui_enabled() {
return ui_is_enabled;
@ -348592,6 +348670,20 @@ ui_label_icon_clicked_R.x = is_hovering ? ( (int)((input->mouse.pos.x - bounds.x
return ui_label_icon_clicked_R.x;
}
int ui_label2_bool(const char *text, bool value) {
bool b = !!value;
return ui_bool(text, &b), 0;
}
int ui_label2_float(const char *text, float value) {
float f = (float)value;
return ui_float(text, &f), 0;
}
int ui_label2_wrap(const char *label, const char *str) { // @fixme: does not work (remove dynamic layout?)
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
nk_text_wrap(ui_ctx, str, strlen(str));
return 0;
}
int ui_label2_toolbar(const char *label, const char *icons) {
int mouse_click = ui_label2(label, va(">%s", icons));
int choice = !mouse_click ? 0 : 1 + -mouse_click / (UI_ICON_FONTSIZE + UI_ICON_SPACING_X); // divided by px per ICON_MD_ glyph approximately
@ -348706,18 +348798,6 @@ int ui_button(const char *s) {
return ui_buttons(1, s);
}
int ui_const_bool(const char *text, const double value) {
bool b = !!value;
return ui_bool(text, &b), 0;
}
int ui_const_float(const char *text, const double value) {
float f = (float)value;
return ui_float(text, &f), 0;
}
int ui_const_string(const char *label, const char *text) {
return ui_label2(label, text);
}
int ui_toggle(const char *label, bool *value) {
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
@ -348981,13 +349061,6 @@ int ui_buffer(const char *label, char *buffer, int buflen) {
return !!(active & NK_EDIT_COMMITED) ? nk_edit_unfocus(ui_ctx), 1 : 0;
}
int ui_text_wrap(const char *label, char *text) {
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
nk_text_wrap(ui_ctx, text, strlen(text));
return 0;
}
int ui_string(const char *label, char **str) {
char *bak = va("%s%c", *str ? *str : "", '\0');
int rc = ui_buffer(label, bak, strlen(bak)+2);
@ -349111,8 +349184,8 @@ int ui_dialog(const char *title, const char *text, int choices, bool *show) { //
return *show;
}
#define ui_bits_template(X) \
int ui_bits##X(const char *label, uint##X##_t *enabled) { \
#define ui_bitmask_template(X) \
int ui_bitmask##X(const char *label, uint##X##_t *enabled) { \
/* @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive */ \
nk_layout_row_dynamic(ui_ctx, 1, 1); \
struct nk_rect bounds = nk_widget_bounds(ui_ctx); \
@ -349143,9 +349216,9 @@ int ui_bits##X(const char *label, uint##X##_t *enabled) { \
return copy ^ *enabled; \
}
ui_bits_template(8);
ui_bits_template(16);
//ui_bits_template(32);
ui_bitmask_template(8);
ui_bitmask_template(16);
//ui_bitmask_template(32);
int ui_console() { // @fixme: buggy
static char *cmd = 0;
@ -349306,13 +349379,15 @@ int ui_demo(int do_windows) {
if(choice == 2) ui_notify(va("My random toast (%d)", rand()), va("This is notification #%d", ++hits));
if(choice == 3) disable_all ^= 1;
if( disable_all ) ui_enable(0);
if( disable_all ) ui_disable();
if( ui_browse(&browsed_file, &show_browser) ) puts(browsed_file);
if( ui_section("Labels")) {}
if( ui_label("my label")) {}
if( ui_label("my label with tooltip@built on " __DATE__ " " __TIME__)) {}
if( ui_label2_toolbar("my toolbar", ICON_MD_STAR ICON_MD_STAR_OUTLINE ICON_MD_BOOKMARK ICON_MD_BOOKMARK_BORDER) ) {}
//if( ui_label2_wrap("my long label", "and some long long long long text wrapped")) {}
if( ui_section("Types")) {}
if( ui_bool("my bool", &boolean) ) puts("bool changed");
@ -349345,7 +349420,7 @@ int ui_demo(int do_windows) {
}
if( ui_section("Others")) {}
if( ui_bits8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_bitmask8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_toggle("my toggle", &toggle) ) printf("toggle %s\n", toggle ? "on":"off");
if( ui_image("my image", texture_checker().id, 0, 0) ) { puts("image clicked"); }
@ -349355,7 +349430,7 @@ int ui_demo(int do_windows) {
if( ui_buttons(3, "yes", "no", "maybe") ) { puts("button clicked"); }
if( ui_dialog("my dialog", __FILE__ "\n" __DATE__ "\n" "Public Domain.", 2/*two buttons*/, &show_dialog) ) {}
if( disable_all ) ui_enable(1);
if( disable_all ) ui_enable(); // restore enabled state
ui_panel_end();
}
@ -349447,30 +349522,14 @@ int ui_demo(int do_windows) {
profiler_t profiler;
int profiler_enabled = 1;
void (profile_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profile_enable)(bool on) { return profiler_enabled = on; }
void (profile_render)() {
// @transparent
static bool has_transparent_attrib = 0; do_once has_transparent_attrib = glfwGetWindowAttrib(window_handle(), GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE;
if( has_transparent_attrib ) return;
// @transparent
int has_menu = ui_has_menubar();
if( !has_menu ) {
static int cook_on_demand; do_once cook_on_demand = COOK_ON_DEMAND;
if( !cook_on_demand ) {
// render profiler, unless we are in the cook progress screen
static unsigned frames = 0; if(frames <= 0) frames += cook_progress() >= 100;
if( frames <= 0 ) return;
}
}
if( has_menu ? ui_window("Profiler", 0) : ui_panel("Profiler", 0) ) {
void (profiler_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profiler_enable)(bool on) { return profiler_enabled = on; }
void (ui_profiler)() {
// @todo: ui_plot()
double fps = window_fps();
profile_setstat("Render.num_fps", fps);
if(1) { // @todo: ui_plot()
// draw fps-meter: 300 samples, [0..70] range each, 70px height plot.
nk_layout_row_dynamic(ui_ctx, 70, 1);
@ -349499,7 +349558,6 @@ void (profile_render)() {
if( index >= 0 ) {
nk_tooltipf(ui_ctx, "%.2f fps", (float)values[index]);
}
}
for each_map_ptr_sorted(profiler, const char *, key, struct profile_t, val ) {
if( isnan(val->stat) ) {
@ -349511,9 +349569,6 @@ void (profile_render)() {
val->stat = 0;
}
}
(has_menu ? ui_window_end : ui_panel_end)();
}
}
#endif
#line 0
@ -350109,7 +350164,7 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
#if is(ems)
if( FLAGS_FULLSCREEN ) window_fullscreen(1);
#else
gladLoadGL(glfwGetProcAddress);
int gl_version = gladLoadGL(glfwGetProcAddress);
#endif
glDebugEnable();
@ -350133,6 +350188,8 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
PRINTF("GPU driver: %s\n", glGetString(GL_VERSION));
#if !is(ems)
PRINTF("GPU OpenGL: %d.%d\n", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
if( FLAGS_TRANSPARENT ) { // @transparent
glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
if( scale >= 1 ) glfwMaximizeWindow(window);
@ -350261,10 +350318,51 @@ int window_frame_begin() {
ui_create();
profile_render();
bool may_render_stats = 1;
ui_shaders();
int has_menu = ui_has_menubar();
if( !has_menu ) {
static int cook_on_demand; do_once cook_on_demand = COOK_ON_DEMAND;
if( !cook_on_demand ) {
// render profiler, unless we are in the cook progress screen
static unsigned frames = 0; if(frames <= 0) frames += cook_progress() >= 100;
may_render_stats = (frames > 0);
}
}
// @transparent
static bool has_transparent_attrib = 0; do_once has_transparent_attrib = glfwGetWindowAttrib(window_handle(), GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE;
if( has_transparent_attrib ) may_render_stats = 0;
// @transparent
// generate Debug panel contents
if( may_render_stats ) {
if( has_menu ? ui_window("Debug", 0) : ui_panel("Debug", 0) ) {
int open = 0, clicked_or_toggled = 0;
for( int p = (open = ui_collapse("FXs", "Debug.FXs")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_fxs();
}
for( int p = (open = ui_collapse("Profiler", "Debug.Profiler")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_profiler();
}
for( int p = (open = ui_collapse("Shaders", "Debug.Shaders")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_shaders();
}
for( int p = (open = ui_collapse("Keyboard", "Debug.Keyboard")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
for( int p = (open = ui_collapse("Mouse", "Debug.Mouse")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
for( int p = (open = ui_collapse("Gamepads", "Debug.Gamepads")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
(has_menu ? ui_window_end : ui_panel_end)();
}
}
#if 0 // deprecated
// run user-defined hooks
@ -352277,22 +352375,20 @@ int main() {
// ----------------------------------------------------------------------------
static void v4k_pre_init() {
window_icon(va("%s.png", app_name()));
ifdef(win32,window_icon(va("%s.ico", app_name())));
const char *appname = app_name();
window_icon(va("%s.png", appname));
ifdef(win32,window_icon(va("%s.ico", appname)));
glfwPollEvents();
int i;
#if 1 // #ifdef PARALLEL_INIT
#pragma omp parallel for
#endif
for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init();
else if( i == 2 ) profile_init();
else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
}
;
// window_swap();
}

View File

@ -386,6 +386,9 @@ float audio_volume_master(float gain) {
}
int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
if(muted) return 1;
if( flags & AUDIO_IGNORE_MIXER_GAIN ) {
// do nothing, gain used as-is
} else {

View File

@ -211,14 +211,14 @@
// system headers
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // for linux
#define _GNU_SOURCE ///- for linux
#endif
#if is(cl) && is(win32) // for VC IDE
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WIN32_WINNT 0x0600 // 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#define _CRT_SECURE_NO_WARNINGS ///-
#define _CRT_NONSTDC_NO_DEPRECATE ///-
#define _WINSOCK_DEPRECATED_NO_WARNINGS ///-
#define _WIN32_WINNT 0x0600 ///- 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#endif
#if is(cl)

View File

@ -804,4 +804,5 @@ int cook_jobs() {
void cook_config( const char *pathfile_to_cook_ini ) { // @todo: test run-from-"bin/" case on Linux.
COOK_INI = pathfile_to_cook_ini;
ASSERT( file_exist(COOK_INI) );
}

View File

@ -626,32 +626,37 @@ bool input_touch_active() {
void input_demo() {
if( ui_panel("Input",0) ) {
ui_section("Keyboard");
ui_const_bool("[Key 1]", input(KEY_1));
ui_const_bool("[Key 2]", input(KEY_2));
ui_const_bool("[Key 3]", input(KEY_3));
ui_const_bool("[Key 4]", input(KEY_4));
ui_const_bool("[Key 5]", input(KEY_5));
ui_const_bool("[Key 6]", input(KEY_6));
ui_const_bool("[Key 7]", input(KEY_7));
uint8_t keymap = 0;
keymap |= (!!input(KEY_1)) << 7;
keymap |= (!!input(KEY_2)) << 6;
keymap |= (!!input(KEY_3)) << 5;
keymap |= (!!input(KEY_4)) << 4;
keymap |= (!!input(KEY_5)) << 3;
keymap |= (!!input(KEY_6)) << 2;
keymap |= (!!input(KEY_7)) << 1;
keymap |= (!!input(KEY_8)) << 0;
ui_bitmask8("[Keys 1..8]", &keymap);
ui_separator();
ui_const_bool("[Key 1] Down event", input_down(KEY_1) );
ui_const_bool("[Key 2] Held event", input_held(KEY_2) );
ui_const_bool("[Key 3] Up event", input_up(KEY_3) );
ui_const_bool("[Key 4] Idle event", input_idle(KEY_4) );
ui_const_bool("[Key 5] Click event", input_click(KEY_5,500) );
ui_const_bool("[Key 6] Click2 event", input_click2(KEY_6,1000) );
ui_const_bool("[Key 7] Repeat event", input_repeat(KEY_7,750) );
ui_label2_bool("[Key 1] Down event", input_down(KEY_1) );
ui_label2_bool("[Key 2] Held event", input_held(KEY_2) );
ui_label2_bool("[Key 3] Up event", input_up(KEY_3) );
ui_label2_bool("[Key 4] Idle event", input_idle(KEY_4) );
ui_label2_bool("[Key 5] Click event", input_click(KEY_5,500) );
ui_label2_bool("[Key 6] Click2 event", input_click2(KEY_6,1000) );
ui_label2_bool("[Key 7] Repeat event", input_repeat(KEY_7,750) );
ui_separator();
ui_section("Mouse");
ui_const_float("X", input(MOUSE_X));
ui_const_float("Y", input(MOUSE_Y));
ui_label2_float("X", input(MOUSE_X));
ui_label2_float("Y", input(MOUSE_Y));
ui_separator();
ui_const_float("Wheel", input(MOUSE_W));
ui_label2_float("Wheel", input(MOUSE_W));
ui_separator();
ui_const_bool("Left", input(MOUSE_L));
ui_const_bool("Middle", input(MOUSE_M));
ui_const_bool("Right", input(MOUSE_R));
ui_label2_bool("Left", input(MOUSE_L));
ui_label2_bool("Middle", input(MOUSE_M));
ui_label2_bool("Right", input(MOUSE_R));
ui_separator();
for( int i = 0; i <= CURSOR_SW_AUTO; ++i ) if(ui_button(va("Cursor shape #%d", i))) window_cursor_shape(i);
ui_separator();
@ -663,45 +668,45 @@ void input_demo() {
input_use(gamepad_id);
ui_const_string("Name", input_frames(GAMEPAD_NAME,0));
ui_const_bool("Connected", input(GAMEPAD_CONNECTED));
ui_label2("Name", input_frames(GAMEPAD_NAME,0));
ui_label2_bool("Connected", input(GAMEPAD_CONNECTED));
ui_separator();
ui_const_bool("A", input(GAMEPAD_A) );
ui_const_bool("B", input(GAMEPAD_B) );
ui_const_bool("X", input(GAMEPAD_X) );
ui_const_bool("Y", input(GAMEPAD_Y) );
ui_const_bool("Up", input(GAMEPAD_UP) );
ui_const_bool("Down", input(GAMEPAD_DOWN) );
ui_const_bool("Left", input(GAMEPAD_LEFT) );
ui_const_bool("Right", input(GAMEPAD_RIGHT) );
ui_const_bool("Menu", input(GAMEPAD_MENU) );
ui_const_bool("Start", input(GAMEPAD_START) );
ui_label2_bool("A", input(GAMEPAD_A) );
ui_label2_bool("B", input(GAMEPAD_B) );
ui_label2_bool("X", input(GAMEPAD_X) );
ui_label2_bool("Y", input(GAMEPAD_Y) );
ui_label2_bool("Up", input(GAMEPAD_UP) );
ui_label2_bool("Down", input(GAMEPAD_DOWN) );
ui_label2_bool("Left", input(GAMEPAD_LEFT) );
ui_label2_bool("Right", input(GAMEPAD_RIGHT) );
ui_label2_bool("Menu", input(GAMEPAD_MENU) );
ui_label2_bool("Start", input(GAMEPAD_START) );
ui_separator();
ui_const_float("Left pad x", input(GAMEPAD_LPADX) );
ui_const_float("Left pad y", input(GAMEPAD_LPADY) );
ui_const_float("Left trigger", input(GAMEPAD_LT) );
ui_const_bool("Left bumper", input(GAMEPAD_LB) );
ui_const_bool("Left thumb", input(GAMEPAD_LTHUMB) );
ui_label2_float("Left pad x", input(GAMEPAD_LPADX) );
ui_label2_float("Left pad y", input(GAMEPAD_LPADY) );
ui_label2_float("Left trigger", input(GAMEPAD_LT) );
ui_label2_bool("Left bumper", input(GAMEPAD_LB) );
ui_label2_bool("Left thumb", input(GAMEPAD_LTHUMB) );
vec2 v = input_filter_deadzone( input2(GAMEPAD_LPADX), 0.1f );
ui_const_float("Filtered pad x", v.x);
ui_const_float("Filtered pad y", v.y);
ui_label2_float("Filtered pad x", v.x);
ui_label2_float("Filtered pad y", v.y);
ui_separator();
ui_const_float("Right pad x", input(GAMEPAD_RPADX) );
ui_const_float("Right pad y", input(GAMEPAD_RPADY) );
ui_const_float("Right trigger", input(GAMEPAD_RT) );
ui_const_bool("Right bumper", input(GAMEPAD_RB) );
ui_const_bool("Right thumb", input(GAMEPAD_RTHUMB) );
ui_label2_float("Right pad x", input(GAMEPAD_RPADX) );
ui_label2_float("Right pad y", input(GAMEPAD_RPADY) );
ui_label2_float("Right trigger", input(GAMEPAD_RT) );
ui_label2_bool("Right bumper", input(GAMEPAD_RB) );
ui_label2_bool("Right thumb", input(GAMEPAD_RTHUMB) );
vec2 w = input_filter_deadzone( input2(GAMEPAD_RPADX), 0.1f );
ui_const_float("Filtered pad x", w.x);
ui_const_float("Filtered pad y", w.y);
ui_label2_float("Filtered pad x", w.x);
ui_label2_float("Filtered pad y", w.y);
input_use(0);

View File

@ -1,22 +1,20 @@
// ----------------------------------------------------------------------------
static void v4k_pre_init() {
window_icon(va("%s.png", app_name()));
ifdef(win32,window_icon(va("%s.ico", app_name())));
const char *appname = app_name();
window_icon(va("%s.png", appname));
ifdef(win32,window_icon(va("%s.ico", appname)));
glfwPollEvents();
int i;
#if 1 // #ifdef PARALLEL_INIT
#pragma omp parallel for
#endif
for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init();
else if( i == 2 ) profile_init();
else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
}
;
// window_swap();
}

View File

@ -2,30 +2,14 @@
profiler_t profiler;
int profiler_enabled = 1;
void (profile_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profile_enable)(bool on) { return profiler_enabled = on; }
void (profile_render)() {
// @transparent
static bool has_transparent_attrib = 0; do_once has_transparent_attrib = glfwGetWindowAttrib(window_handle(), GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE;
if( has_transparent_attrib ) return;
// @transparent
int has_menu = ui_has_menubar();
if( !has_menu ) {
static int cook_on_demand; do_once cook_on_demand = COOK_ON_DEMAND;
if( !cook_on_demand ) {
// render profiler, unless we are in the cook progress screen
static unsigned frames = 0; if(frames <= 0) frames += cook_progress() >= 100;
if( frames <= 0 ) return;
}
}
if( has_menu ? ui_window("Profiler", 0) : ui_panel("Profiler", 0) ) {
void (profiler_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profiler_enable)(bool on) { return profiler_enabled = on; }
void (ui_profiler)() {
// @todo: ui_plot()
double fps = window_fps();
profile_setstat("Render.num_fps", fps);
if(1) { // @todo: ui_plot()
// draw fps-meter: 300 samples, [0..70] range each, 70px height plot.
nk_layout_row_dynamic(ui_ctx, 70, 1);
@ -54,7 +38,6 @@ void (profile_render)() {
if( index >= 0 ) {
nk_tooltipf(ui_ctx, "%.2f fps", (float)values[index]);
}
}
for each_map_ptr_sorted(profiler, const char *, key, struct profile_t, val ) {
if( isnan(val->stat) ) {
@ -66,8 +49,5 @@ void (profile_render)() {
val->stat = 0;
}
}
(has_menu ? ui_window_end : ui_panel_end)();
}
}
#endif

View File

@ -5,9 +5,9 @@
# define profile(section) for(int macro(i) = 1; macro(i); macro(i) = 0)
# define profile_incstat(name, accum) do {} while(0)
# define profile_setstat(name, value) do {} while(0)
# define profile_init() do {} while(0)
# define profile_render() do {} while(0)
# define profile_enable(x) 0
# define profiler_init() do {} while(0)
# define profiler_enable(x) 0
# define ui_profiler() do {} while(0)
#else
# define profile(section) for( \
struct profile_t *found = profiler_enabled ? \
@ -20,7 +20,7 @@
# define profile_setstat(name, value) for( \
struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \
found; found->stat = value, found = NULL) ///+
API int profile_enable(bool on);
API int profiler_enable(bool on);
struct profile_t { double stat; int32_t cost, avg; }; ///-
typedef map(char *, struct profile_t) profiler_t; ///-

View File

@ -194,22 +194,23 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
array(char*) props = 0;
do_once map_init_int( shader_reflect );
if(vs) for each_substring(vs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if(fs) for each_substring(fs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if(gs) for each_substring(gs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if( props ) {
map_insert(shader_reflect, program, props);
for( int i = 0; i < array_count(props); ++i ) shader_apply_param(program, i);
}
return program;
@ -222,7 +223,60 @@ unsigned shader_properties(unsigned shader) {
char** shader_property(unsigned shader, unsigned property) {
array(char*) *found = map_find(shader_reflect, shader);
return found ? &(*found)[property] : NULL;
return found && property < array_count(*found) ? &(*found)[property] : NULL;
}
void shader_apply_param(unsigned shader, unsigned param_no) {
unsigned num_properties = shader_properties(shader);
if( param_no < num_properties ) {
char *line = *shader_property(shader, param_no);
char type[32], name[32];
if( sscanf(line, "%*s %s %[^ =;/]", type, name) != 2 ) return;
int is_color = !!strstri(name, "color"), top = is_color ? 1 : 10;
vec4 minv = strstr(line, "min:") ? atof4(strstr(line, "min:") + 4) : vec4(0,0,0,0);
vec4 setv = strstr(line, "set:") ? atof4(strstr(line, "set:") + 4) : vec4(0,0,0,0);
vec4 maxv = strstr(line, "max:") ? atof4(strstr(line, "max:") + 4) : vec4(top,top,top,top);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x);
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y);
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z);
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w);
if( !strstr(line, "max:") ) {
if(setv.x > maxv.x) maxv.x = setv.x;
if(setv.y > maxv.y) maxv.y = setv.y;
if(setv.z > maxv.z) maxv.z = setv.z;
if(setv.w > maxv.w) maxv.w = setv.w;
}
setv = clamp4(setv, minv, maxv);
if( strchr("ibfv", type[0]) ) {
GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak);
glUseProgram(shader);
/**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x);
else if(type[0] == 'b') glUniform1i(glGetUniformLocation(shader, name), !!setv.x);
else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x);
else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x);
glUseProgram(shader_bak);
}
}
}
void shader_apply_params(unsigned shader, const char *parameter_mask) {
unsigned num_properties = shader_properties(shader);
for( unsigned i = 0; i < num_properties; ++i ) {
char *line = *shader_property(shader,i);
char name[32];
if( sscanf(line, "%*s %*s %s", name) != 1 ) continue;
if( !strmatch(name, parameter_mask) ) continue;
shader_apply_param(shader, i);
}
}
int ui_shader(unsigned shader) {
@ -233,25 +287,43 @@ int ui_shader(unsigned shader) {
char **ptr = shader_property(shader,i);
const char *line = *ptr; // debug: ui_label(line);
char uniform[32], type[32], name[32];
if( sscanf(line, "%s %s %s", uniform, type, name) != 3) continue;
char* tip = strstr(line, "tip:"); tip = tip && tip[4] ? tip + 4 : 0;
char uniform[32], type[32], name[32], early_exit = '\0';
if( sscanf(line, "%s %s %[^ =;/]", uniform, type, name) != 3 ) continue; // @todo optimize: move to shader()
if( strcmp(uniform, "uniform") && strcmp(uniform, "}uniform") ) { if(tip) ui_label(va(ICON_MD_INFO "%s", tip)); continue; } // @todo optimize: move to shader()
int is_color = !!strstri(name, "color"), top = is_color ? 1 : 10;
vec4 minv = strstr(line, "min:") ? atof4(strstr(line, "min:") + 4) : vec4(0,0,0,0);
vec4 setv = strstr(line, "set:") ? atof4(strstr(line, "set:") + 4) : vec4(0,0,0,0);
vec4 maxv = strstr(line, "max:") ? atof4(strstr(line, "max:") + 4) : vec4(top,top,top,top);
char* tip = strstr(line, "tip:"); tip = tip && tip[4] ? tip + 4 : 0;
char *label = !tip ? va("%c%s", name[0] - 32 * !!(name[0] >= 'a'), name+1) :
va("%c%s " ICON_MD_HELP "@%s", name[0] - 32 * !!(name[0] >= 'a'), name+1, tip);
va("%c%s " ICON_MD_INFO "@%s", name[0] - 32 * !!(name[0] >= 'a'), name+1, tip);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x);
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y);
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z);
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x); // @optimize: move to shader()
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y); // @optimize: move to shader()
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z); // @optimize: move to shader()
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w); // @optimize: move to shader()
if( !strstr(line, "max:") ) {
if(setv.x > maxv.x) maxv.x = setv.x;
if(setv.y > maxv.y) maxv.y = setv.y;
if(setv.z > maxv.z) maxv.z = setv.z;
if(setv.w > maxv.w) maxv.w = setv.w;
}
setv = clamp4(setv, minv, maxv);
// supports int,float,vec2/3/4,color3/4
int touched = 0;
if( type[0] == 'i' ) {
if( type[0] == 'b' ) {
bool v = !!setv.x;
if( (touched = ui_bool(label, &v)) != 0 ) {
setv.x = v;
}
}
else if( type[0] == 'i' ) {
int v = setv.x;
if( (touched = ui_int(label, &v)) != 0 ) {
@ -259,9 +331,11 @@ int ui_shader(unsigned shader) {
}
}
else if( type[0] == 'f' ) {
setv.x = (clampf(setv.x, minv.x, maxv.x) - minv.x) / (maxv.x - minv.x);
setv.x = clampf(setv.x, minv.x, maxv.x);
char *caption = va("%5.2f", setv.x);
setv.x = (setv.x - minv.x) / (maxv.x - minv.x);
if( (touched = ui_slider2(label, &setv.x, va("%5.2f", setv.x))) != 0 ) {
if( (touched = ui_slider2(label, &setv.x, caption)) != 0 ) {
setv.x = clampf(minv.x + setv.x * (maxv.x-minv.x), minv.x, maxv.x); // min..max range
}
}
@ -286,28 +360,20 @@ int ui_shader(unsigned shader) {
setv = clamp4(setv,minv,maxv);
}
}
else if( tip ) ui_label( tip );
if( touched ) {
// send to shader
GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak);
glUseProgram(shader);
/**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x);
else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x);
else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x);
glUseProgram(shader_bak);
// upgrade value
*ptr = FREE(*ptr);
*ptr = stringf("%s %s %s ///set:%s min:%s max:%s tip:%s", uniform,type,name,ftoa4(setv),ftoa4(minv),ftoa4(maxv),tip?tip:"");
// apply
shader_apply_param(shader, i);
changed = 1;
}
}
if(num_properties) ui_separator();
return changed;
}
@ -315,13 +381,14 @@ int ui_shaders() {
if( !map_count(shader_reflect) ) return 0;
int changed = 0;
int has_menu = ui_has_menubar();
if( (has_menu ? ui_window("Shaders", 0) : ui_panel("Shaders", 0) ) ) {
for each_map_ptr(shader_reflect, unsigned, k, array(char*), v) {
ui_section(va("Shader %d",*k));
int open = 0, clicked_or_toggled = 0;
char *id = va("##SHD%d", *k);
char *title = va("Shader %d", *k);
for( int p = (open = ui_collapse(title, id)), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_label(va("Shader %d",*k));
changed |= ui_shader(*k);
}
(has_menu ? ui_window_end : ui_panel_end)();
}
return changed;
}
@ -376,7 +443,7 @@ void write_barrier(){
glMemoryBarrier(GL_ALL_BARRIER_BITS);
}
void image_write_barrier(){
void write_barrier_image(){
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
@ -3234,9 +3301,9 @@ void postfx_clear(postfx *fx) {
int ui_postfx(postfx *fx, int pass) {
int on = ui_enabled();
ui_enable( postfx_enabled(fx,pass) );
( postfx_enabled(fx,pass) ? ui_enable : ui_disable )();
int rc = ui_shader(fx->pass[pass].program);
ui_enable( on );
( on ? ui_enable : ui_disable )();
return rc;
}
@ -3417,16 +3484,12 @@ int ui_fxs() {
if(!fx.num_loaded) return 0;
int changed = 0;
int has_menu = ui_has_menubar();
if( (has_menu ? ui_window("FX", 0) : ui_panel("FX", 0) ) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
ui_fx(i);
}
(has_menu ? ui_window_end : ui_panel_end)();
}
return changed;
}

View File

@ -343,6 +343,9 @@ API void shader_destroy(unsigned shader);
API unsigned shader_properties(unsigned shader);
API char** shader_property(unsigned shader, unsigned property_no);
API void shader_apply_param(unsigned shader, unsigned param_no);
API void shader_apply_params(unsigned shader, const char *parameter_mask);
API int ui_shader(unsigned shader);
API int ui_shaders();
@ -387,12 +390,12 @@ API void shader_image_unit(unsigned texture, unsigned unit, unsigned level, int
// gpu memory barriers
/// Blocks main thread until all image operations are done by the GPU.
API void image_write_barrier();
/// Blocks main thread until all memory operations are done by the GPU.
API void write_barrier();
/// Blocks main thread until all image operations are done by the GPU.
API void write_barrier_image();
// ssbo
/// `STATIC`, `DYNAMIC` AND `STREAM` specify the frequency at which we intend to access the data.
/// `DRAW` favors CPU->GPU operations.

View File

@ -145,8 +145,8 @@ default_hue = 0.52;
struct nk_color active = nk_hsv_f( 0.600, 0.00, 0.150); // bright b/w
struct nk_color table[NK_COLOR_COUNT] = {0};
table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_WINDOW] = nk_rgba(42, 42, 42, 215);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
table[NK_COLOR_WINDOW] = nk_rgba(42, 42, 42, 245);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 245);
table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
table[NK_COLOR_BUTTON] = main;
table[NK_COLOR_BUTTON_HOVER] = hover;
@ -537,7 +537,7 @@ int ui_active() {
}
static
int ui_enable_(int enabled) {
int ui_set_enable_(int enabled) {
static struct nk_style off, on;
do_once {
off = on = ui_ctx->style;
@ -775,8 +775,11 @@ int ui_enable_(int enabled) {
}
static int ui_is_enabled = 1;
int ui_enable(int on) {
return ui_is_enabled == on ? 0 : ui_enable_(ui_is_enabled = on);
int ui_enable() {
return ui_is_enabled == 1 ? 0 : ui_set_enable_(ui_is_enabled = 1);
}
int ui_disable() {
return ui_is_enabled == 0 ? 0 : ui_set_enable_(ui_is_enabled = 0);
}
int ui_enabled() {
return ui_is_enabled;
@ -1558,6 +1561,20 @@ ui_label_icon_clicked_R.x = is_hovering ? ( (int)((input->mouse.pos.x - bounds.x
return ui_label_icon_clicked_R.x;
}
int ui_label2_bool(const char *text, bool value) {
bool b = !!value;
return ui_bool(text, &b), 0;
}
int ui_label2_float(const char *text, float value) {
float f = (float)value;
return ui_float(text, &f), 0;
}
int ui_label2_wrap(const char *label, const char *str) { // @fixme: does not work (remove dynamic layout?)
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
nk_text_wrap(ui_ctx, str, strlen(str));
return 0;
}
int ui_label2_toolbar(const char *label, const char *icons) {
int mouse_click = ui_label2(label, va(">%s", icons));
int choice = !mouse_click ? 0 : 1 + -mouse_click / (UI_ICON_FONTSIZE + UI_ICON_SPACING_X); // divided by px per ICON_MD_ glyph approximately
@ -1672,18 +1689,6 @@ int ui_button(const char *s) {
return ui_buttons(1, s);
}
int ui_const_bool(const char *text, const double value) {
bool b = !!value;
return ui_bool(text, &b), 0;
}
int ui_const_float(const char *text, const double value) {
float f = (float)value;
return ui_float(text, &f), 0;
}
int ui_const_string(const char *label, const char *text) {
return ui_label2(label, text);
}
int ui_toggle(const char *label, bool *value) {
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
@ -1947,13 +1952,6 @@ int ui_buffer(const char *label, char *buffer, int buflen) {
return !!(active & NK_EDIT_COMMITED) ? nk_edit_unfocus(ui_ctx), 1 : 0;
}
int ui_text_wrap(const char *label, char *text) {
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
nk_text_wrap(ui_ctx, text, strlen(text));
return 0;
}
int ui_string(const char *label, char **str) {
char *bak = va("%s%c", *str ? *str : "", '\0');
int rc = ui_buffer(label, bak, strlen(bak)+2);
@ -2077,8 +2075,8 @@ int ui_dialog(const char *title, const char *text, int choices, bool *show) { //
return *show;
}
#define ui_bits_template(X) \
int ui_bits##X(const char *label, uint##X##_t *enabled) { \
#define ui_bitmask_template(X) \
int ui_bitmask##X(const char *label, uint##X##_t *enabled) { \
/* @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive */ \
nk_layout_row_dynamic(ui_ctx, 1, 1); \
struct nk_rect bounds = nk_widget_bounds(ui_ctx); \
@ -2109,9 +2107,9 @@ int ui_bits##X(const char *label, uint##X##_t *enabled) { \
return copy ^ *enabled; \
}
ui_bits_template(8);
ui_bits_template(16);
//ui_bits_template(32);
ui_bitmask_template(8);
ui_bitmask_template(16);
//ui_bitmask_template(32);
int ui_console() { // @fixme: buggy
static char *cmd = 0;
@ -2272,13 +2270,15 @@ int ui_demo(int do_windows) {
if(choice == 2) ui_notify(va("My random toast (%d)", rand()), va("This is notification #%d", ++hits));
if(choice == 3) disable_all ^= 1;
if( disable_all ) ui_enable(0);
if( disable_all ) ui_disable();
if( ui_browse(&browsed_file, &show_browser) ) puts(browsed_file);
if( ui_section("Labels")) {}
if( ui_label("my label")) {}
if( ui_label("my label with tooltip@built on " __DATE__ " " __TIME__)) {}
if( ui_label2_toolbar("my toolbar", ICON_MD_STAR ICON_MD_STAR_OUTLINE ICON_MD_BOOKMARK ICON_MD_BOOKMARK_BORDER) ) {}
//if( ui_label2_wrap("my long label", "and some long long long long text wrapped")) {}
if( ui_section("Types")) {}
if( ui_bool("my bool", &boolean) ) puts("bool changed");
@ -2311,7 +2311,7 @@ int ui_demo(int do_windows) {
}
if( ui_section("Others")) {}
if( ui_bits8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_bitmask8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_toggle("my toggle", &toggle) ) printf("toggle %s\n", toggle ? "on":"off");
if( ui_image("my image", texture_checker().id, 0, 0) ) { puts("image clicked"); }
@ -2321,7 +2321,7 @@ int ui_demo(int do_windows) {
if( ui_buttons(3, "yes", "no", "maybe") ) { puts("button clicked"); }
if( ui_dialog("my dialog", __FILE__ "\n" __DATE__ "\n" "Public Domain.", 2/*two buttons*/, &show_dialog) ) {}
if( disable_all ) ui_enable(1);
if( disable_all ) ui_enable(); // restore enabled state
ui_panel_end();
}

View File

@ -25,7 +25,6 @@ API int ui_float4(const char *label, float value[4]);
API int ui_double(const char *label, double *value);
API int ui_buffer(const char *label, char *buffer, int buflen);
API int ui_string(const char *label, char **string);
API int ui_text_wrap(const char *label, char *text);
API int ui_color3(const char *label, float *color3); //[0..255]
API int ui_color3f(const char *label, float *color3); //[0..1]
API int ui_color4(const char *label, float *color4); //[0..255]
@ -47,18 +46,17 @@ API int ui_image(const char *label, handle id, unsigned w, unsigned h); //(w,
API int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh);
API int ui_colormap(const char *label, colormap_t *cm); // returns num member changed: 1 for color, 2 for texture map
API int ui_separator();
API int ui_bits8(const char *label, uint8_t *bits);
API int ui_bits16(const char *label, uint16_t *bits);
API int ui_bitmask8(const char *label, uint8_t *bits);
API int ui_bitmask16(const char *label, uint16_t *bits);
API int ui_console();
API int ui_clampf(const char *label, float *value, float minf, float maxf);
API int ui_label(const char *label);
API int ui_label2(const char *label, const char *caption);
API int ui_label2_bool(const char *label, bool enabled);
API int ui_label2_float(const char *label, float value);
API int ui_label2_toolbar(const char *label, const char *icons);
API int ui_slider(const char *label, float *value);
API int ui_slider2(const char *label, float *value, const char *caption);
API int ui_const_bool(const char *label, const double value);
API int ui_const_float(const char *label, const double value);
API int ui_const_string(const char *label, const char *value);
API int ui_contextual_end();
API int ui_collapse_clicked();
API int ui_collapse_end();
@ -68,10 +66,12 @@ API int ui_window_end();
API int ui_show(const char *panel_or_window_title, int enabled);
API int ui_dims(const char *panel_or_window_title, float width, float height);
API int ui_visible(const char *panel_or_window_title); // @todo: include ui_collapse() items that are open as well?
API int ui_enable(int on);
API int ui_enabled();
API vec2 ui_get_dims();
API int ui_enable();
API int ui_enabled();
API int ui_disable();
API int ui_has_menubar();
API int ui_menu(const char *items); // semicolon-separated or comma-separated items
API int ui_menu_editbox(char *buf, int bufcap);

View File

@ -356,7 +356,7 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
#if is(ems)
if( FLAGS_FULLSCREEN ) window_fullscreen(1);
#else
gladLoadGL(glfwGetProcAddress);
int gl_version = gladLoadGL(glfwGetProcAddress);
#endif
glDebugEnable();
@ -380,6 +380,8 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
PRINTF("GPU driver: %s\n", glGetString(GL_VERSION));
#if !is(ems)
PRINTF("GPU OpenGL: %d.%d\n", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
if( FLAGS_TRANSPARENT ) { // @transparent
glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
if( scale >= 1 ) glfwMaximizeWindow(window);
@ -508,10 +510,51 @@ int window_frame_begin() {
ui_create();
profile_render();
bool may_render_stats = 1;
ui_shaders();
int has_menu = ui_has_menubar();
if( !has_menu ) {
static int cook_on_demand; do_once cook_on_demand = COOK_ON_DEMAND;
if( !cook_on_demand ) {
// render profiler, unless we are in the cook progress screen
static unsigned frames = 0; if(frames <= 0) frames += cook_progress() >= 100;
may_render_stats = (frames > 0);
}
}
// @transparent
static bool has_transparent_attrib = 0; do_once has_transparent_attrib = glfwGetWindowAttrib(window_handle(), GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE;
if( has_transparent_attrib ) may_render_stats = 0;
// @transparent
// generate Debug panel contents
if( may_render_stats ) {
if( has_menu ? ui_window("Debug", 0) : ui_panel("Debug", 0) ) {
int open = 0, clicked_or_toggled = 0;
for( int p = (open = ui_collapse("FXs", "Debug.FXs")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_fxs();
}
for( int p = (open = ui_collapse("Profiler", "Debug.Profiler")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_profiler();
}
for( int p = (open = ui_collapse("Shaders", "Debug.Shaders")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_shaders();
}
for( int p = (open = ui_collapse("Keyboard", "Debug.Keyboard")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
for( int p = (open = ui_collapse("Mouse", "Debug.Mouse")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
for( int p = (open = ui_collapse("Gamepads", "Debug.Gamepads")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
(has_menu ? ui_window_end : ui_panel_end)();
}
}
#if 0 // deprecated
// run user-defined hooks

View File

@ -1346,6 +1346,9 @@ float audio_volume_master(float gain) {
}
int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan ) {
static bool muted = 0; do_once muted = flag("--mute") || flag("--muted");
if(muted) return 1;
if( flags & AUDIO_IGNORE_MIXER_GAIN ) {
// do nothing, gain used as-is
} else {
@ -3740,6 +3743,7 @@ int cook_jobs() {
void cook_config( const char *pathfile_to_cook_ini ) { // @todo: test run-from-"bin/" case on Linux.
COOK_INI = pathfile_to_cook_ini;
ASSERT( file_exist(COOK_INI) );
}
#line 0
@ -8143,32 +8147,37 @@ bool input_touch_active() {
void input_demo() {
if( ui_panel("Input",0) ) {
ui_section("Keyboard");
ui_const_bool("[Key 1]", input(KEY_1));
ui_const_bool("[Key 2]", input(KEY_2));
ui_const_bool("[Key 3]", input(KEY_3));
ui_const_bool("[Key 4]", input(KEY_4));
ui_const_bool("[Key 5]", input(KEY_5));
ui_const_bool("[Key 6]", input(KEY_6));
ui_const_bool("[Key 7]", input(KEY_7));
uint8_t keymap = 0;
keymap |= (!!input(KEY_1)) << 7;
keymap |= (!!input(KEY_2)) << 6;
keymap |= (!!input(KEY_3)) << 5;
keymap |= (!!input(KEY_4)) << 4;
keymap |= (!!input(KEY_5)) << 3;
keymap |= (!!input(KEY_6)) << 2;
keymap |= (!!input(KEY_7)) << 1;
keymap |= (!!input(KEY_8)) << 0;
ui_bitmask8("[Keys 1..8]", &keymap);
ui_separator();
ui_const_bool("[Key 1] Down event", input_down(KEY_1) );
ui_const_bool("[Key 2] Held event", input_held(KEY_2) );
ui_const_bool("[Key 3] Up event", input_up(KEY_3) );
ui_const_bool("[Key 4] Idle event", input_idle(KEY_4) );
ui_const_bool("[Key 5] Click event", input_click(KEY_5,500) );
ui_const_bool("[Key 6] Click2 event", input_click2(KEY_6,1000) );
ui_const_bool("[Key 7] Repeat event", input_repeat(KEY_7,750) );
ui_label2_bool("[Key 1] Down event", input_down(KEY_1) );
ui_label2_bool("[Key 2] Held event", input_held(KEY_2) );
ui_label2_bool("[Key 3] Up event", input_up(KEY_3) );
ui_label2_bool("[Key 4] Idle event", input_idle(KEY_4) );
ui_label2_bool("[Key 5] Click event", input_click(KEY_5,500) );
ui_label2_bool("[Key 6] Click2 event", input_click2(KEY_6,1000) );
ui_label2_bool("[Key 7] Repeat event", input_repeat(KEY_7,750) );
ui_separator();
ui_section("Mouse");
ui_const_float("X", input(MOUSE_X));
ui_const_float("Y", input(MOUSE_Y));
ui_label2_float("X", input(MOUSE_X));
ui_label2_float("Y", input(MOUSE_Y));
ui_separator();
ui_const_float("Wheel", input(MOUSE_W));
ui_label2_float("Wheel", input(MOUSE_W));
ui_separator();
ui_const_bool("Left", input(MOUSE_L));
ui_const_bool("Middle", input(MOUSE_M));
ui_const_bool("Right", input(MOUSE_R));
ui_label2_bool("Left", input(MOUSE_L));
ui_label2_bool("Middle", input(MOUSE_M));
ui_label2_bool("Right", input(MOUSE_R));
ui_separator();
for( int i = 0; i <= CURSOR_SW_AUTO; ++i ) if(ui_button(va("Cursor shape #%d", i))) window_cursor_shape(i);
ui_separator();
@ -8180,45 +8189,45 @@ void input_demo() {
input_use(gamepad_id);
ui_const_string("Name", input_frames(GAMEPAD_NAME,0));
ui_const_bool("Connected", input(GAMEPAD_CONNECTED));
ui_label2("Name", input_frames(GAMEPAD_NAME,0));
ui_label2_bool("Connected", input(GAMEPAD_CONNECTED));
ui_separator();
ui_const_bool("A", input(GAMEPAD_A) );
ui_const_bool("B", input(GAMEPAD_B) );
ui_const_bool("X", input(GAMEPAD_X) );
ui_const_bool("Y", input(GAMEPAD_Y) );
ui_const_bool("Up", input(GAMEPAD_UP) );
ui_const_bool("Down", input(GAMEPAD_DOWN) );
ui_const_bool("Left", input(GAMEPAD_LEFT) );
ui_const_bool("Right", input(GAMEPAD_RIGHT) );
ui_const_bool("Menu", input(GAMEPAD_MENU) );
ui_const_bool("Start", input(GAMEPAD_START) );
ui_label2_bool("A", input(GAMEPAD_A) );
ui_label2_bool("B", input(GAMEPAD_B) );
ui_label2_bool("X", input(GAMEPAD_X) );
ui_label2_bool("Y", input(GAMEPAD_Y) );
ui_label2_bool("Up", input(GAMEPAD_UP) );
ui_label2_bool("Down", input(GAMEPAD_DOWN) );
ui_label2_bool("Left", input(GAMEPAD_LEFT) );
ui_label2_bool("Right", input(GAMEPAD_RIGHT) );
ui_label2_bool("Menu", input(GAMEPAD_MENU) );
ui_label2_bool("Start", input(GAMEPAD_START) );
ui_separator();
ui_const_float("Left pad x", input(GAMEPAD_LPADX) );
ui_const_float("Left pad y", input(GAMEPAD_LPADY) );
ui_const_float("Left trigger", input(GAMEPAD_LT) );
ui_const_bool("Left bumper", input(GAMEPAD_LB) );
ui_const_bool("Left thumb", input(GAMEPAD_LTHUMB) );
ui_label2_float("Left pad x", input(GAMEPAD_LPADX) );
ui_label2_float("Left pad y", input(GAMEPAD_LPADY) );
ui_label2_float("Left trigger", input(GAMEPAD_LT) );
ui_label2_bool("Left bumper", input(GAMEPAD_LB) );
ui_label2_bool("Left thumb", input(GAMEPAD_LTHUMB) );
vec2 v = input_filter_deadzone( input2(GAMEPAD_LPADX), 0.1f );
ui_const_float("Filtered pad x", v.x);
ui_const_float("Filtered pad y", v.y);
ui_label2_float("Filtered pad x", v.x);
ui_label2_float("Filtered pad y", v.y);
ui_separator();
ui_const_float("Right pad x", input(GAMEPAD_RPADX) );
ui_const_float("Right pad y", input(GAMEPAD_RPADY) );
ui_const_float("Right trigger", input(GAMEPAD_RT) );
ui_const_bool("Right bumper", input(GAMEPAD_RB) );
ui_const_bool("Right thumb", input(GAMEPAD_RTHUMB) );
ui_label2_float("Right pad x", input(GAMEPAD_RPADX) );
ui_label2_float("Right pad y", input(GAMEPAD_RPADY) );
ui_label2_float("Right trigger", input(GAMEPAD_RT) );
ui_label2_bool("Right bumper", input(GAMEPAD_RB) );
ui_label2_bool("Right thumb", input(GAMEPAD_RTHUMB) );
vec2 w = input_filter_deadzone( input2(GAMEPAD_RPADX), 0.1f );
ui_const_float("Filtered pad x", w.x);
ui_const_float("Filtered pad y", w.y);
ui_label2_float("Filtered pad x", w.x);
ui_label2_float("Filtered pad y", w.y);
input_use(0);
@ -10516,22 +10525,23 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
array(char*) props = 0;
do_once map_init_int( shader_reflect );
if(vs) for each_substring(vs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if(fs) for each_substring(fs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if(gs) for each_substring(gs, "\r\n", line) {
if( strstr(line, "/""//") && !strbeg(line,"//") ) {
array_push(props, STRDUP(line));
}
const char *found = strstr(line, "/""//");
if( found > line && line[0] == '/' && line[1] == '/' ) continue;
if( found ) array_push(props, STRDUP(line));
}
if( props ) {
map_insert(shader_reflect, program, props);
for( int i = 0; i < array_count(props); ++i ) shader_apply_param(program, i);
}
return program;
@ -10544,7 +10554,60 @@ unsigned shader_properties(unsigned shader) {
char** shader_property(unsigned shader, unsigned property) {
array(char*) *found = map_find(shader_reflect, shader);
return found ? &(*found)[property] : NULL;
return found && property < array_count(*found) ? &(*found)[property] : NULL;
}
void shader_apply_param(unsigned shader, unsigned param_no) {
unsigned num_properties = shader_properties(shader);
if( param_no < num_properties ) {
char *line = *shader_property(shader, param_no);
char type[32], name[32];
if( sscanf(line, "%*s %s %[^ =;/]", type, name) != 2 ) return;
int is_color = !!strstri(name, "color"), top = is_color ? 1 : 10;
vec4 minv = strstr(line, "min:") ? atof4(strstr(line, "min:") + 4) : vec4(0,0,0,0);
vec4 setv = strstr(line, "set:") ? atof4(strstr(line, "set:") + 4) : vec4(0,0,0,0);
vec4 maxv = strstr(line, "max:") ? atof4(strstr(line, "max:") + 4) : vec4(top,top,top,top);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x);
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y);
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z);
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w);
if( !strstr(line, "max:") ) {
if(setv.x > maxv.x) maxv.x = setv.x;
if(setv.y > maxv.y) maxv.y = setv.y;
if(setv.z > maxv.z) maxv.z = setv.z;
if(setv.w > maxv.w) maxv.w = setv.w;
}
setv = clamp4(setv, minv, maxv);
if( strchr("ibfv", type[0]) ) {
GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak);
glUseProgram(shader);
/**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x);
else if(type[0] == 'b') glUniform1i(glGetUniformLocation(shader, name), !!setv.x);
else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x);
else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x);
glUseProgram(shader_bak);
}
}
}
void shader_apply_params(unsigned shader, const char *parameter_mask) {
unsigned num_properties = shader_properties(shader);
for( unsigned i = 0; i < num_properties; ++i ) {
char *line = *shader_property(shader,i);
char name[32];
if( sscanf(line, "%*s %*s %s", name) != 1 ) continue;
if( !strmatch(name, parameter_mask) ) continue;
shader_apply_param(shader, i);
}
}
int ui_shader(unsigned shader) {
@ -10555,25 +10618,43 @@ int ui_shader(unsigned shader) {
char **ptr = shader_property(shader,i);
const char *line = *ptr; // debug: ui_label(line);
char uniform[32], type[32], name[32];
if( sscanf(line, "%s %s %s", uniform, type, name) != 3) continue;
char* tip = strstr(line, "tip:"); tip = tip && tip[4] ? tip + 4 : 0;
char uniform[32], type[32], name[32], early_exit = '\0';
if( sscanf(line, "%s %s %[^ =;/]", uniform, type, name) != 3 ) continue; // @todo optimize: move to shader()
if( strcmp(uniform, "uniform") && strcmp(uniform, "}uniform") ) { if(tip) ui_label(va(ICON_MD_INFO "%s", tip)); continue; } // @todo optimize: move to shader()
int is_color = !!strstri(name, "color"), top = is_color ? 1 : 10;
vec4 minv = strstr(line, "min:") ? atof4(strstr(line, "min:") + 4) : vec4(0,0,0,0);
vec4 setv = strstr(line, "set:") ? atof4(strstr(line, "set:") + 4) : vec4(0,0,0,0);
vec4 maxv = strstr(line, "max:") ? atof4(strstr(line, "max:") + 4) : vec4(top,top,top,top);
char* tip = strstr(line, "tip:"); tip = tip && tip[4] ? tip + 4 : 0;
char *label = !tip ? va("%c%s", name[0] - 32 * !!(name[0] >= 'a'), name+1) :
va("%c%s " ICON_MD_HELP "@%s", name[0] - 32 * !!(name[0] >= 'a'), name+1, tip);
va("%c%s " ICON_MD_INFO "@%s", name[0] - 32 * !!(name[0] >= 'a'), name+1, tip);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x);
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y);
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z);
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w);
if(minv.x > maxv.x) swapf(&minv.x, &maxv.x); // @optimize: move to shader()
if(minv.y > maxv.y) swapf(&minv.y, &maxv.y); // @optimize: move to shader()
if(minv.z > maxv.z) swapf(&minv.z, &maxv.z); // @optimize: move to shader()
if(minv.w > maxv.w) swapf(&minv.w, &maxv.w); // @optimize: move to shader()
if( !strstr(line, "max:") ) {
if(setv.x > maxv.x) maxv.x = setv.x;
if(setv.y > maxv.y) maxv.y = setv.y;
if(setv.z > maxv.z) maxv.z = setv.z;
if(setv.w > maxv.w) maxv.w = setv.w;
}
setv = clamp4(setv, minv, maxv);
// supports int,float,vec2/3/4,color3/4
int touched = 0;
if( type[0] == 'i' ) {
if( type[0] == 'b' ) {
bool v = !!setv.x;
if( (touched = ui_bool(label, &v)) != 0 ) {
setv.x = v;
}
}
else if( type[0] == 'i' ) {
int v = setv.x;
if( (touched = ui_int(label, &v)) != 0 ) {
@ -10581,9 +10662,11 @@ int ui_shader(unsigned shader) {
}
}
else if( type[0] == 'f' ) {
setv.x = (clampf(setv.x, minv.x, maxv.x) - minv.x) / (maxv.x - minv.x);
setv.x = clampf(setv.x, minv.x, maxv.x);
char *caption = va("%5.2f", setv.x);
setv.x = (setv.x - minv.x) / (maxv.x - minv.x);
if( (touched = ui_slider2(label, &setv.x, va("%5.2f", setv.x))) != 0 ) {
if( (touched = ui_slider2(label, &setv.x, caption)) != 0 ) {
setv.x = clampf(minv.x + setv.x * (maxv.x-minv.x), minv.x, maxv.x); // min..max range
}
}
@ -10608,28 +10691,20 @@ int ui_shader(unsigned shader) {
setv = clamp4(setv,minv,maxv);
}
}
else if( tip ) ui_label( tip );
if( touched ) {
// send to shader
GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak);
glUseProgram(shader);
/**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x);
else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x);
else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x);
else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x);
glUseProgram(shader_bak);
// upgrade value
*ptr = FREE(*ptr);
*ptr = stringf("%s %s %s ///set:%s min:%s max:%s tip:%s", uniform,type,name,ftoa4(setv),ftoa4(minv),ftoa4(maxv),tip?tip:"");
// apply
shader_apply_param(shader, i);
changed = 1;
}
}
if(num_properties) ui_separator();
return changed;
}
@ -10637,13 +10712,14 @@ int ui_shaders() {
if( !map_count(shader_reflect) ) return 0;
int changed = 0;
int has_menu = ui_has_menubar();
if( (has_menu ? ui_window("Shaders", 0) : ui_panel("Shaders", 0) ) ) {
for each_map_ptr(shader_reflect, unsigned, k, array(char*), v) {
ui_section(va("Shader %d",*k));
int open = 0, clicked_or_toggled = 0;
char *id = va("##SHD%d", *k);
char *title = va("Shader %d", *k);
for( int p = (open = ui_collapse(title, id)), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_label(va("Shader %d",*k));
changed |= ui_shader(*k);
}
(has_menu ? ui_window_end : ui_panel_end)();
}
return changed;
}
@ -10698,7 +10774,7 @@ void write_barrier(){
glMemoryBarrier(GL_ALL_BARRIER_BITS);
}
void image_write_barrier(){
void write_barrier_image(){
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
@ -13556,9 +13632,9 @@ void postfx_clear(postfx *fx) {
int ui_postfx(postfx *fx, int pass) {
int on = ui_enabled();
ui_enable( postfx_enabled(fx,pass) );
( postfx_enabled(fx,pass) ? ui_enable : ui_disable )();
int rc = ui_shader(fx->pass[pass].program);
ui_enable( on );
( on ? ui_enable : ui_disable )();
return rc;
}
@ -13739,16 +13815,12 @@ int ui_fxs() {
if(!fx.num_loaded) return 0;
int changed = 0;
int has_menu = ui_has_menubar();
if( (has_menu ? ui_window("FX", 0) : ui_panel("FX", 0) ) ) {
for( int i = 0; i < 64; ++i ) {
char *name = fx_name(i); if( !name ) break;
bool b = fx_enabled(i);
if( ui_bool(name, &b) ) fx_enable(i, fx_enabled(i) ^ 1);
ui_fx(i);
}
(has_menu ? ui_window_end : ui_panel_end)();
}
return changed;
}
@ -17786,8 +17858,8 @@ default_hue = 0.52;
struct nk_color active = nk_hsv_f( 0.600, 0.00, 0.150); // bright b/w
struct nk_color table[NK_COLOR_COUNT] = {0};
table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_WINDOW] = nk_rgba(42, 42, 42, 215);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
table[NK_COLOR_WINDOW] = nk_rgba(42, 42, 42, 245);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 245);
table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
table[NK_COLOR_BUTTON] = main;
table[NK_COLOR_BUTTON_HOVER] = hover;
@ -18178,7 +18250,7 @@ int ui_active() {
}
static
int ui_enable_(int enabled) {
int ui_set_enable_(int enabled) {
static struct nk_style off, on;
do_once {
off = on = ui_ctx->style;
@ -18416,8 +18488,11 @@ int ui_enable_(int enabled) {
}
static int ui_is_enabled = 1;
int ui_enable(int on) {
return ui_is_enabled == on ? 0 : ui_enable_(ui_is_enabled = on);
int ui_enable() {
return ui_is_enabled == 1 ? 0 : ui_set_enable_(ui_is_enabled = 1);
}
int ui_disable() {
return ui_is_enabled == 0 ? 0 : ui_set_enable_(ui_is_enabled = 0);
}
int ui_enabled() {
return ui_is_enabled;
@ -19199,6 +19274,20 @@ ui_label_icon_clicked_R.x = is_hovering ? ( (int)((input->mouse.pos.x - bounds.x
return ui_label_icon_clicked_R.x;
}
int ui_label2_bool(const char *text, bool value) {
bool b = !!value;
return ui_bool(text, &b), 0;
}
int ui_label2_float(const char *text, float value) {
float f = (float)value;
return ui_float(text, &f), 0;
}
int ui_label2_wrap(const char *label, const char *str) { // @fixme: does not work (remove dynamic layout?)
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
nk_text_wrap(ui_ctx, str, strlen(str));
return 0;
}
int ui_label2_toolbar(const char *label, const char *icons) {
int mouse_click = ui_label2(label, va(">%s", icons));
int choice = !mouse_click ? 0 : 1 + -mouse_click / (UI_ICON_FONTSIZE + UI_ICON_SPACING_X); // divided by px per ICON_MD_ glyph approximately
@ -19313,18 +19402,6 @@ int ui_button(const char *s) {
return ui_buttons(1, s);
}
int ui_const_bool(const char *text, const double value) {
bool b = !!value;
return ui_bool(text, &b), 0;
}
int ui_const_float(const char *text, const double value) {
float f = (float)value;
return ui_float(text, &f), 0;
}
int ui_const_string(const char *label, const char *text) {
return ui_label2(label, text);
}
int ui_toggle(const char *label, bool *value) {
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
@ -19588,13 +19665,6 @@ int ui_buffer(const char *label, char *buffer, int buflen) {
return !!(active & NK_EDIT_COMMITED) ? nk_edit_unfocus(ui_ctx), 1 : 0;
}
int ui_text_wrap(const char *label, char *text) {
nk_layout_row_dynamic(ui_ctx, 0, 2 - (label ? !label[0] : 1));
ui_label_(label, NK_TEXT_LEFT);
nk_text_wrap(ui_ctx, text, strlen(text));
return 0;
}
int ui_string(const char *label, char **str) {
char *bak = va("%s%c", *str ? *str : "", '\0');
int rc = ui_buffer(label, bak, strlen(bak)+2);
@ -19718,8 +19788,8 @@ int ui_dialog(const char *title, const char *text, int choices, bool *show) { //
return *show;
}
#define ui_bits_template(X) \
int ui_bits##X(const char *label, uint##X##_t *enabled) { \
#define ui_bitmask_template(X) \
int ui_bitmask##X(const char *label, uint##X##_t *enabled) { \
/* @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive */ \
nk_layout_row_dynamic(ui_ctx, 1, 1); \
struct nk_rect bounds = nk_widget_bounds(ui_ctx); \
@ -19750,9 +19820,9 @@ int ui_bits##X(const char *label, uint##X##_t *enabled) { \
return copy ^ *enabled; \
}
ui_bits_template(8);
ui_bits_template(16);
//ui_bits_template(32);
ui_bitmask_template(8);
ui_bitmask_template(16);
//ui_bitmask_template(32);
int ui_console() { // @fixme: buggy
static char *cmd = 0;
@ -19913,13 +19983,15 @@ int ui_demo(int do_windows) {
if(choice == 2) ui_notify(va("My random toast (%d)", rand()), va("This is notification #%d", ++hits));
if(choice == 3) disable_all ^= 1;
if( disable_all ) ui_enable(0);
if( disable_all ) ui_disable();
if( ui_browse(&browsed_file, &show_browser) ) puts(browsed_file);
if( ui_section("Labels")) {}
if( ui_label("my label")) {}
if( ui_label("my label with tooltip@built on " __DATE__ " " __TIME__)) {}
if( ui_label2_toolbar("my toolbar", ICON_MD_STAR ICON_MD_STAR_OUTLINE ICON_MD_BOOKMARK ICON_MD_BOOKMARK_BORDER) ) {}
//if( ui_label2_wrap("my long label", "and some long long long long text wrapped")) {}
if( ui_section("Types")) {}
if( ui_bool("my bool", &boolean) ) puts("bool changed");
@ -19952,7 +20024,7 @@ int ui_demo(int do_windows) {
}
if( ui_section("Others")) {}
if( ui_bits8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_bitmask8("my bitmask", &bitmask) ) printf("bitmask changed %x\n", bitmask);
if( ui_toggle("my toggle", &toggle) ) printf("toggle %s\n", toggle ? "on":"off");
if( ui_image("my image", texture_checker().id, 0, 0) ) { puts("image clicked"); }
@ -19962,7 +20034,7 @@ int ui_demo(int do_windows) {
if( ui_buttons(3, "yes", "no", "maybe") ) { puts("button clicked"); }
if( ui_dialog("my dialog", __FILE__ "\n" __DATE__ "\n" "Public Domain.", 2/*two buttons*/, &show_dialog) ) {}
if( disable_all ) ui_enable(1);
if( disable_all ) ui_enable(); // restore enabled state
ui_panel_end();
}
@ -20054,30 +20126,14 @@ int ui_demo(int do_windows) {
profiler_t profiler;
int profiler_enabled = 1;
void (profile_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profile_enable)(bool on) { return profiler_enabled = on; }
void (profile_render)() {
// @transparent
static bool has_transparent_attrib = 0; do_once has_transparent_attrib = glfwGetWindowAttrib(window_handle(), GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE;
if( has_transparent_attrib ) return;
// @transparent
int has_menu = ui_has_menubar();
if( !has_menu ) {
static int cook_on_demand; do_once cook_on_demand = COOK_ON_DEMAND;
if( !cook_on_demand ) {
// render profiler, unless we are in the cook progress screen
static unsigned frames = 0; if(frames <= 0) frames += cook_progress() >= 100;
if( frames <= 0 ) return;
}
}
if( has_menu ? ui_window("Profiler", 0) : ui_panel("Profiler", 0) ) {
void (profiler_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profiler_enable)(bool on) { return profiler_enabled = on; }
void (ui_profiler)() {
// @todo: ui_plot()
double fps = window_fps();
profile_setstat("Render.num_fps", fps);
if(1) { // @todo: ui_plot()
// draw fps-meter: 300 samples, [0..70] range each, 70px height plot.
nk_layout_row_dynamic(ui_ctx, 70, 1);
@ -20106,7 +20162,6 @@ void (profile_render)() {
if( index >= 0 ) {
nk_tooltipf(ui_ctx, "%.2f fps", (float)values[index]);
}
}
for each_map_ptr_sorted(profiler, const char *, key, struct profile_t, val ) {
if( isnan(val->stat) ) {
@ -20118,9 +20173,6 @@ void (profile_render)() {
val->stat = 0;
}
}
(has_menu ? ui_window_end : ui_panel_end)();
}
}
#endif
#line 0
@ -20716,7 +20768,7 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
#if is(ems)
if( FLAGS_FULLSCREEN ) window_fullscreen(1);
#else
gladLoadGL(glfwGetProcAddress);
int gl_version = gladLoadGL(glfwGetProcAddress);
#endif
glDebugEnable();
@ -20740,6 +20792,8 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
PRINTF("GPU driver: %s\n", glGetString(GL_VERSION));
#if !is(ems)
PRINTF("GPU OpenGL: %d.%d\n", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
if( FLAGS_TRANSPARENT ) { // @transparent
glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
if( scale >= 1 ) glfwMaximizeWindow(window);
@ -20868,10 +20922,51 @@ int window_frame_begin() {
ui_create();
profile_render();
bool may_render_stats = 1;
ui_shaders();
int has_menu = ui_has_menubar();
if( !has_menu ) {
static int cook_on_demand; do_once cook_on_demand = COOK_ON_DEMAND;
if( !cook_on_demand ) {
// render profiler, unless we are in the cook progress screen
static unsigned frames = 0; if(frames <= 0) frames += cook_progress() >= 100;
may_render_stats = (frames > 0);
}
}
// @transparent
static bool has_transparent_attrib = 0; do_once has_transparent_attrib = glfwGetWindowAttrib(window_handle(), GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE;
if( has_transparent_attrib ) may_render_stats = 0;
// @transparent
// generate Debug panel contents
if( may_render_stats ) {
if( has_menu ? ui_window("Debug", 0) : ui_panel("Debug", 0) ) {
int open = 0, clicked_or_toggled = 0;
for( int p = (open = ui_collapse("FXs", "Debug.FXs")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_fxs();
}
for( int p = (open = ui_collapse("Profiler", "Debug.Profiler")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_profiler();
}
for( int p = (open = ui_collapse("Shaders", "Debug.Shaders")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
ui_shaders();
}
for( int p = (open = ui_collapse("Keyboard", "Debug.Keyboard")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
for( int p = (open = ui_collapse("Mouse", "Debug.Mouse")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
for( int p = (open = ui_collapse("Gamepads", "Debug.Gamepads")), dummy = (clicked_or_toggled = ui_collapse_clicked()); p; ui_collapse_end(), p = 0) {
}
(has_menu ? ui_window_end : ui_panel_end)();
}
}
#if 0 // deprecated
// run user-defined hooks
@ -22884,22 +22979,20 @@ int main() {
// ----------------------------------------------------------------------------
static void v4k_pre_init() {
window_icon(va("%s.png", app_name()));
ifdef(win32,window_icon(va("%s.ico", app_name())));
const char *appname = app_name();
window_icon(va("%s.png", appname));
ifdef(win32,window_icon(va("%s.ico", appname)));
glfwPollEvents();
int i;
#if 1 // #ifdef PARALLEL_INIT
#pragma omp parallel for
#endif
for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init();
else if( i == 2 ) profile_init();
else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
}
;
// window_swap();
}

View File

@ -309,14 +309,14 @@ extern "C" {
// system headers
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // for linux
#define _GNU_SOURCE ///- for linux
#endif
#if is(cl) && is(win32) // for VC IDE
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WIN32_WINNT 0x0600 // 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#define _CRT_SECURE_NO_WARNINGS ///-
#define _CRT_NONSTDC_NO_DEPRECATE ///-
#define _WINSOCK_DEPRECATED_NO_WARNINGS ///-
#define _WIN32_WINNT 0x0600 ///- 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#endif
#if is(cl)
@ -2428,9 +2428,9 @@ static __thread void *obj_tmpalloc;
# define profile(section) for(int macro(i) = 1; macro(i); macro(i) = 0)
# define profile_incstat(name, accum) do {} while(0)
# define profile_setstat(name, value) do {} while(0)
# define profile_init() do {} while(0)
# define profile_render() do {} while(0)
# define profile_enable(x) 0
# define profiler_init() do {} while(0)
# define profiler_enable(x) 0
# define ui_profiler() do {} while(0)
#else
# define profile(section) for( \
struct profile_t *found = profiler_enabled ? \
@ -2443,7 +2443,7 @@ static __thread void *obj_tmpalloc;
# define profile_setstat(name, value) for( \
struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \
found; found->stat = value, found = NULL) ///+
API int profile_enable(bool on);
API int profiler_enable(bool on);
struct profile_t { double stat; int32_t cost, avg; }; ///-
typedef map(char *, struct profile_t) profiler_t; ///-
@ -2798,6 +2798,9 @@ API void shader_destroy(unsigned shader);
API unsigned shader_properties(unsigned shader);
API char** shader_property(unsigned shader, unsigned property_no);
API void shader_apply_param(unsigned shader, unsigned param_no);
API void shader_apply_params(unsigned shader, const char *parameter_mask);
API int ui_shader(unsigned shader);
API int ui_shaders();
@ -2842,12 +2845,12 @@ API void shader_image_unit(unsigned texture, unsigned unit, unsigned level, int
// gpu memory barriers
/// Blocks main thread until all image operations are done by the GPU.
API void image_write_barrier();
/// Blocks main thread until all memory operations are done by the GPU.
API void write_barrier();
/// Blocks main thread until all image operations are done by the GPU.
API void write_barrier_image();
// ssbo
/// `STATIC`, `DYNAMIC` AND `STREAM` specify the frequency at which we intend to access the data.
/// `DRAW` favors CPU->GPU operations.
@ -3568,7 +3571,6 @@ API int ui_float4(const char *label, float value[4]);
API int ui_double(const char *label, double *value);
API int ui_buffer(const char *label, char *buffer, int buflen);
API int ui_string(const char *label, char **string);
API int ui_text_wrap(const char *label, char *text);
API int ui_color3(const char *label, float *color3); //[0..255]
API int ui_color3f(const char *label, float *color3); //[0..1]
API int ui_color4(const char *label, float *color4); //[0..255]
@ -3590,18 +3592,17 @@ API int ui_image(const char *label, handle id, unsigned w, unsigned h); //(w,
API int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh);
API int ui_colormap(const char *label, colormap_t *cm); // returns num member changed: 1 for color, 2 for texture map
API int ui_separator();
API int ui_bits8(const char *label, uint8_t *bits);
API int ui_bits16(const char *label, uint16_t *bits);
API int ui_bitmask8(const char *label, uint8_t *bits);
API int ui_bitmask16(const char *label, uint16_t *bits);
API int ui_console();
API int ui_clampf(const char *label, float *value, float minf, float maxf);
API int ui_label(const char *label);
API int ui_label2(const char *label, const char *caption);
API int ui_label2_bool(const char *label, bool enabled);
API int ui_label2_float(const char *label, float value);
API int ui_label2_toolbar(const char *label, const char *icons);
API int ui_slider(const char *label, float *value);
API int ui_slider2(const char *label, float *value, const char *caption);
API int ui_const_bool(const char *label, const double value);
API int ui_const_float(const char *label, const double value);
API int ui_const_string(const char *label, const char *value);
API int ui_contextual_end();
API int ui_collapse_clicked();
API int ui_collapse_end();
@ -3611,10 +3612,12 @@ API int ui_window_end();
API int ui_show(const char *panel_or_window_title, int enabled);
API int ui_dims(const char *panel_or_window_title, float width, float height);
API int ui_visible(const char *panel_or_window_title); // @todo: include ui_collapse() items that are open as well?
API int ui_enable(int on);
API int ui_enabled();
API vec2 ui_get_dims();
API int ui_enable();
API int ui_enabled();
API int ui_disable();
API int ui_has_menubar();
API int ui_menu(const char *items); // semicolon-separated or comma-separated items
API int ui_menu_editbox(char *buf, int bufcap);

23
hello.c
View File

@ -27,8 +27,7 @@ int main() {
// animated models loading (no flags)
model_t girl = model("kgirl/kgirls01.fbx", 0);
vec3 pos = vec3(0,0,0), sca = vec3(2,2,2), rot = vec3(-90,0,0);
compose44( girl.pivot, pos, eulerq(rot), sca); // position, rotation, scale
compose44( girl.pivot, vec3(0,0,0), eulerq(vec3(-90,0,0)), vec3(2,2,2)); // position, rotation, scale
// camera
camera_t cam = camera();
@ -38,7 +37,7 @@ int main() {
// audio (both clips & streams)
audio_t SFX1 = audio_clip( "coin.wav" ), SFX2 = audio_clip( "pew.sfxr" );
audio_t BGM1 = audio_stream( "waterworld-map.fur"), BGM2 = audio_stream( "larry.mid" ), BGM = BGM1;
audio_t BGM1 = audio_stream( "waterworld-map.fur" ), BGM2 = audio_stream( "larry.mid" ), BGM = BGM1;
audio_play(SFX1, 0);
audio_play(BGM, 0);
@ -61,17 +60,17 @@ int main() {
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
// apply post-fxs from here
fx_begin();
// debug draw
ddraw_grid(0);
ddraw_ground(0);
if(do_debugdraw) ddraw_demo(); // showcase many debugdraw shapes
ddraw_flush();
// draw skybox
skybox_render(&sky, cam.proj, cam.view);
// apply post-fxs from here
fx_begin();
// animate girl
float delta = window_delta() * 30; // 30fps anim
girl.curframe = model_animate(girl, girl.curframe + delta);
@ -82,10 +81,6 @@ int main() {
// post-fxs end here
fx_end();
gizmo(&pos, &rot, &sca);
model_render_skeleton(girl, girl.pivot);
compose44( girl.pivot, pos, eulerq(rot), sca); // position, rotation, scale
// font demo
font_print(va(FONT_BOTTOM FONT_RIGHT FONT_H6 "%5.2f FPS", window_fps()));
@ -115,12 +110,6 @@ int main() {
if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, 0);
if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, 0);
ui_section("FX");
for( int i = 0, on; i < 64 && fx_name(i); ++i ) {
bool enabled = fx_enabled(i);
if( ui_bool(fx_name(i), &enabled) ) fx_enable(i, enabled);
}
ui_panel_end();
}
}