main
Dominik Madarász 2023-10-29 12:19:16 +01:00
parent 27b868d522
commit 6998920b35
10 changed files with 504 additions and 8 deletions

View File

@ -499,7 +499,7 @@ set run=no
if "%1"=="lab" set "lab=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"=="noeditor" set "editor=no" && goto loop
if "%1"=="hello" set "hello=yes" && 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"=="editor" set "editor=yes" && set "v4k=yes" && set "hello=no"&& goto loop
if "%1"=="run" set "run=yes" && goto loop if "%1"=="run" set "run=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"=="all" set "v4k=yes" && set "demos=yes" && set "lab=yes" && set "editor=yes" && set "hello=yes" && goto loop
@ -754,7 +754,6 @@ if "!v4k!"=="yes" (
) )
) )
!echo! v4k && !cc! engine\v4k.c !export! !edit! !args! || set rc=1
rem editor rem editor
if "!editor!"=="yes" ( if "!editor!"=="yes" (

View File

@ -1841,6 +1841,8 @@ EASE_OUT = 0,
float ease_pong(float t01, unsigned fn); float ease_pong(float t01, unsigned fn);
float ease_ping_pong(float t, unsigned fn1, unsigned fn2); float ease_ping_pong(float t, unsigned fn1, unsigned fn2);
float ease_pong_ping(float t, unsigned fn1, unsigned fn2); float ease_pong_ping(float t, unsigned fn1, unsigned fn2);
const char *ease_enum(unsigned fn);
const char**ease_enums();
typedef struct tween_keyframe_t { typedef struct tween_keyframe_t {
int easing_mode; int easing_mode;
float t; float t;

View File

@ -15226,6 +15226,9 @@ API float ease_pong(float t01, unsigned fn); // \ 1-to-0
API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0 API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0
API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1 API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1
API const char *ease_enum(unsigned fn);
API const char**ease_enums();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tween // tween
@ -342325,6 +342328,91 @@ float ease_pong(float t, unsigned fn) { return 1 - ease(t, fn); }
float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); } float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); }
float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); } float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); }
const char **ease_enums() {
static const char *list[] = {
"ease_linear",
"ease_out_sine",
"ease_out_quad",
"ease_out_cubic",
"ease_out_quart",
"ease_out_quint",
"ease_out_expo",
"ease_out_circ",
"ease_out_back",
"ease_out_elastic",
"ease_out_bounce",
"ease_linear",
"ease_in_sine",
"ease_in_quad",
"ease_in_cubic",
"ease_in_quart",
"ease_in_quint",
"ease_in_expo",
"ease_in_circ",
"ease_in_back",
"ease_in_elastic",
"ease_in_bounce",
"ease_linear",
"ease_inout_sine",
"ease_inout_quad",
"ease_inout_cubic",
"ease_inout_quart",
"ease_inout_quint",
"ease_inout_expo",
"ease_inout_circ",
"ease_inout_back",
"ease_inout_elastic",
"ease_inout_bounce",
"ease_inout_perlin",
0
};
return list;
}
const char *ease_enum(unsigned mode) {
return mode[ ease_enums() ];
}
/*AUTORUN {
ENUM(EASE_LINEAR|EASE_OUT);
ENUM(EASE_SINE|EASE_OUT);
ENUM(EASE_QUAD|EASE_OUT);
ENUM(EASE_CUBIC|EASE_OUT);
ENUM(EASE_QUART|EASE_OUT);
ENUM(EASE_QUINT|EASE_OUT);
ENUM(EASE_EXPO|EASE_OUT);
ENUM(EASE_CIRC|EASE_OUT);
ENUM(EASE_BACK|EASE_OUT);
ENUM(EASE_ELASTIC|EASE_OUT);
ENUM(EASE_BOUNCE|EASE_OUT);
ENUM(EASE_SINE|EASE_IN);
ENUM(EASE_QUAD|EASE_IN);
ENUM(EASE_CUBIC|EASE_IN);
ENUM(EASE_QUART|EASE_IN);
ENUM(EASE_QUINT|EASE_IN);
ENUM(EASE_EXPO|EASE_IN);
ENUM(EASE_CIRC|EASE_IN);
ENUM(EASE_BACK|EASE_IN);
ENUM(EASE_ELASTIC|EASE_IN);
ENUM(EASE_BOUNCE|EASE_IN);
ENUM(EASE_SINE|EASE_INOUT);
ENUM(EASE_QUAD|EASE_INOUT);
ENUM(EASE_CUBIC|EASE_INOUT);
ENUM(EASE_QUART|EASE_INOUT);
ENUM(EASE_QUINT|EASE_INOUT);
ENUM(EASE_EXPO|EASE_INOUT);
ENUM(EASE_CIRC|EASE_INOUT);
ENUM(EASE_BACK|EASE_INOUT);
ENUM(EASE_ELASTIC|EASE_INOUT);
ENUM(EASE_BOUNCE|EASE_INOUT);
};*/
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tween // tween
@ -359084,7 +359172,7 @@ int engine_send(const char *cmd, const char *optional_value) {
int engine_tick() { int engine_tick() {
enum { engine_hz = 60 }; enum { engine_hz = 60 };
enum { engine_hz_mid = 30 }; enum { engine_hz_mid = 18 };
enum { engine_hz_low = 5 }; enum { engine_hz_low = 5 };
if( *engine_geti("powersave") ) { if( *engine_geti("powersave") ) {
// adaptive framerate // adaptive framerate

View File

@ -176,7 +176,7 @@ int engine_send(const char *cmd, const char *optional_value) {
int engine_tick() { int engine_tick() {
enum { engine_hz = 60 }; enum { engine_hz = 60 };
enum { engine_hz_mid = 30 }; enum { engine_hz_mid = 18 };
enum { engine_hz_low = 5 }; enum { engine_hz_low = 5 };
if( *engine_geti("powersave") ) { if( *engine_geti("powersave") ) {
// adaptive framerate // adaptive framerate

View File

@ -86,6 +86,91 @@ float ease_pong(float t, unsigned fn) { return 1 - ease(t, fn); }
float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); } float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); }
float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); } float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); }
const char **ease_enums() {
static const char *list[] = {
"ease_linear",
"ease_out_sine",
"ease_out_quad",
"ease_out_cubic",
"ease_out_quart",
"ease_out_quint",
"ease_out_expo",
"ease_out_circ",
"ease_out_back",
"ease_out_elastic",
"ease_out_bounce",
"ease_linear",
"ease_in_sine",
"ease_in_quad",
"ease_in_cubic",
"ease_in_quart",
"ease_in_quint",
"ease_in_expo",
"ease_in_circ",
"ease_in_back",
"ease_in_elastic",
"ease_in_bounce",
"ease_linear",
"ease_inout_sine",
"ease_inout_quad",
"ease_inout_cubic",
"ease_inout_quart",
"ease_inout_quint",
"ease_inout_expo",
"ease_inout_circ",
"ease_inout_back",
"ease_inout_elastic",
"ease_inout_bounce",
"ease_inout_perlin",
0
};
return list;
}
const char *ease_enum(unsigned mode) {
return mode[ ease_enums() ];
}
/*AUTORUN {
ENUM(EASE_LINEAR|EASE_OUT);
ENUM(EASE_SINE|EASE_OUT);
ENUM(EASE_QUAD|EASE_OUT);
ENUM(EASE_CUBIC|EASE_OUT);
ENUM(EASE_QUART|EASE_OUT);
ENUM(EASE_QUINT|EASE_OUT);
ENUM(EASE_EXPO|EASE_OUT);
ENUM(EASE_CIRC|EASE_OUT);
ENUM(EASE_BACK|EASE_OUT);
ENUM(EASE_ELASTIC|EASE_OUT);
ENUM(EASE_BOUNCE|EASE_OUT);
ENUM(EASE_SINE|EASE_IN);
ENUM(EASE_QUAD|EASE_IN);
ENUM(EASE_CUBIC|EASE_IN);
ENUM(EASE_QUART|EASE_IN);
ENUM(EASE_QUINT|EASE_IN);
ENUM(EASE_EXPO|EASE_IN);
ENUM(EASE_CIRC|EASE_IN);
ENUM(EASE_BACK|EASE_IN);
ENUM(EASE_ELASTIC|EASE_IN);
ENUM(EASE_BOUNCE|EASE_IN);
ENUM(EASE_SINE|EASE_INOUT);
ENUM(EASE_QUAD|EASE_INOUT);
ENUM(EASE_CUBIC|EASE_INOUT);
ENUM(EASE_QUART|EASE_INOUT);
ENUM(EASE_QUINT|EASE_INOUT);
ENUM(EASE_EXPO|EASE_INOUT);
ENUM(EASE_CIRC|EASE_INOUT);
ENUM(EASE_BACK|EASE_INOUT);
ENUM(EASE_ELASTIC|EASE_INOUT);
ENUM(EASE_BOUNCE|EASE_INOUT);
};*/
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tween // tween

View File

@ -61,6 +61,9 @@ API float ease_pong(float t01, unsigned fn); // \ 1-to-0
API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0 API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0
API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1 API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1
API const char *ease_enum(unsigned fn);
API const char**ease_enums();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tween // tween

View File

@ -10221,6 +10221,91 @@ float ease_pong(float t, unsigned fn) { return 1 - ease(t, fn); }
float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); } float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); }
float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); } float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); }
const char **ease_enums() {
static const char *list[] = {
"ease_linear",
"ease_out_sine",
"ease_out_quad",
"ease_out_cubic",
"ease_out_quart",
"ease_out_quint",
"ease_out_expo",
"ease_out_circ",
"ease_out_back",
"ease_out_elastic",
"ease_out_bounce",
"ease_linear",
"ease_in_sine",
"ease_in_quad",
"ease_in_cubic",
"ease_in_quart",
"ease_in_quint",
"ease_in_expo",
"ease_in_circ",
"ease_in_back",
"ease_in_elastic",
"ease_in_bounce",
"ease_linear",
"ease_inout_sine",
"ease_inout_quad",
"ease_inout_cubic",
"ease_inout_quart",
"ease_inout_quint",
"ease_inout_expo",
"ease_inout_circ",
"ease_inout_back",
"ease_inout_elastic",
"ease_inout_bounce",
"ease_inout_perlin",
0
};
return list;
}
const char *ease_enum(unsigned mode) {
return mode[ ease_enums() ];
}
/*AUTORUN {
ENUM(EASE_LINEAR|EASE_OUT);
ENUM(EASE_SINE|EASE_OUT);
ENUM(EASE_QUAD|EASE_OUT);
ENUM(EASE_CUBIC|EASE_OUT);
ENUM(EASE_QUART|EASE_OUT);
ENUM(EASE_QUINT|EASE_OUT);
ENUM(EASE_EXPO|EASE_OUT);
ENUM(EASE_CIRC|EASE_OUT);
ENUM(EASE_BACK|EASE_OUT);
ENUM(EASE_ELASTIC|EASE_OUT);
ENUM(EASE_BOUNCE|EASE_OUT);
ENUM(EASE_SINE|EASE_IN);
ENUM(EASE_QUAD|EASE_IN);
ENUM(EASE_CUBIC|EASE_IN);
ENUM(EASE_QUART|EASE_IN);
ENUM(EASE_QUINT|EASE_IN);
ENUM(EASE_EXPO|EASE_IN);
ENUM(EASE_CIRC|EASE_IN);
ENUM(EASE_BACK|EASE_IN);
ENUM(EASE_ELASTIC|EASE_IN);
ENUM(EASE_BOUNCE|EASE_IN);
ENUM(EASE_SINE|EASE_INOUT);
ENUM(EASE_QUAD|EASE_INOUT);
ENUM(EASE_CUBIC|EASE_INOUT);
ENUM(EASE_QUART|EASE_INOUT);
ENUM(EASE_QUINT|EASE_INOUT);
ENUM(EASE_EXPO|EASE_INOUT);
ENUM(EASE_CIRC|EASE_INOUT);
ENUM(EASE_BACK|EASE_INOUT);
ENUM(EASE_ELASTIC|EASE_INOUT);
ENUM(EASE_BOUNCE|EASE_INOUT);
};*/
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tween // tween
@ -26980,7 +27065,7 @@ int engine_send(const char *cmd, const char *optional_value) {
int engine_tick() { int engine_tick() {
enum { engine_hz = 60 }; enum { engine_hz = 60 };
enum { engine_hz_mid = 30 }; enum { engine_hz_mid = 18 };
enum { engine_hz_low = 5 }; enum { engine_hz_low = 5 };
if( *engine_geti("powersave") ) { if( *engine_geti("powersave") ) {
// adaptive framerate // adaptive framerate

View File

@ -1293,6 +1293,9 @@ API float ease_pong(float t01, unsigned fn); // \ 1-to-0
API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0 API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0
API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1 API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1
API const char *ease_enum(unsigned fn);
API const char**ease_enums();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tween // tween

View File

@ -50,6 +50,7 @@
//#include "objtests.h" //#include "objtests.h"
#include "editor3.h" #include "editor3.h"
#define EXTEND obj_extend #define EXTEND obj_extend
int editor_timeline();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -176,6 +177,8 @@ AUTORUN {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
typedef int(*subeditor)();
struct editor_t { struct editor_t {
// time // time
unsigned frame; unsigned frame;
@ -203,6 +206,8 @@ struct editor_t {
// all of them // all of them
array(obj*) objs; // @todo:set() world? array(obj*) objs; // @todo:set() world?
array(char*) cmds; array(char*) cmds;
// subeditors
array(subeditor) subeditors;
} editor = { } editor = {
.active = 1, .active = 1,
.gamepad = 1, .gamepad = 1,
@ -607,7 +612,7 @@ array(editor_bind_t) editor_binds;
#define EDITOR_BIND(CMD,KEYS,...) void macro(editor_bind_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){CMD,KEYS,macro(editor_bind_fn_)}) ); } #define EDITOR_BIND(CMD,KEYS,...) void macro(editor_bind_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){CMD,KEYS,macro(editor_bind_fn_)}) ); }
EDITOR_BIND("play", "held(CTRL) & down(SPC)", { window_pause(0); if(!editor.slomo) editor.active = 0; editor.slomo = 1; } ); EDITOR_BIND("play", "held(CTRL) & down(SPC)", { window_pause(0); /* if(!editor.slomo) editor.active = 0; */ editor.slomo = 1; } );
EDITOR_BIND("slomo", "", { window_pause(0); editor.slomo = maxf(fmod(editor.slomo * 2, 16), 0.125); } ); EDITOR_BIND("slomo", "", { window_pause(0); editor.slomo = maxf(fmod(editor.slomo * 2, 16), 0.125); } );
EDITOR_BIND("stop", "(held(ALT)|held(SHIFT))&down(ESC)", { window_pause(1), editor.frame = 0, editor.t = 0, editor.dt = 0, editor.slomo = 0, editor.active = 1; editor_select("**"); editor_destroy_selected(); } ); EDITOR_BIND("stop", "(held(ALT)|held(SHIFT))&down(ESC)", { window_pause(1), editor.frame = 0, editor.t = 0, editor.dt = 0, editor.slomo = 0, editor.active = 1; editor_select("**"); editor_destroy_selected(); } );
EDITOR_BIND("pause", "down(ESC)", { window_pause( window_has_pause() ^ 1 ); } ); EDITOR_BIND("pause", "down(ESC)", { window_pause( window_has_pause() ^ 1 ); } );
@ -722,8 +727,10 @@ void editor_frame( void (*game)(unsigned, float, double) ) {
// draw menubar // draw menubar
static double last_fps = 0; if(!window_has_pause()) last_fps = window_fps(); static double last_fps = 0; if(!window_has_pause()) last_fps = window_fps();
int fps_target = window_fps_target() > 0.0f ? (int)window_fps_target() : 60; const char *TITLE = va("%02dm:%02ds:%03dms:%02dF %5.2f/%dfps x%4.3f",
const char *TITLE = va("%02dF %5.2f/%dfps x%4.3f", editor.frame % (int)fps_target, last_fps, fps_target, editor.slomo); (int)editor.t / 60, (int)fmod(editor.t, 60), (int)(1000 * (editor.t - (int)editor.t)),
editor.frame % ((int)window_fps_target() + !(int)window_fps_target()),
last_fps, (int)window_fps_target(), editor.slomo);
const char *ICON_PL4Y = window_has_pause() ? ICON_MDI_PLAY : ICON_MDI_PAUSE; const char *ICON_PL4Y = window_has_pause() ? ICON_MDI_PLAY : ICON_MDI_PAUSE;
const char *ICON_SKIP = window_has_pause() ? ICON_MDI_STEP_FORWARD/*ICON_MDI_SKIP_NEXT*/ : ICON_MDI_FAST_FORWARD; const char *ICON_SKIP = window_has_pause() ? ICON_MDI_STEP_FORWARD/*ICON_MDI_SKIP_NEXT*/ : ICON_MDI_FAST_FORWARD;
@ -815,6 +822,11 @@ void editor_frame( void (*game)(unsigned, float, double) ) {
ui_window_end(); ui_window_end();
} }
// draw subeditors
for each_array(editor.subeditors, subeditor, fn) {
fn();
}
// draw ui filter (note: render at end-of-frame, so it's hopefully on-top) // draw ui filter (note: render at end-of-frame, so it's hopefully on-top)
editor_filter(); editor_filter();
} }
@ -924,3 +936,5 @@ int main(){
editor_frame(game); editor_frame(game);
} }
} }
#include "editor3timeline.h"

View File

@ -0,0 +1,217 @@
int ui_window_nk(const char *title, void *open) {
int ww = window_width(); int w = ww * 0.66;
int hh = window_height(); int h = hh * 0.66;
nk_flags flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER |
NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
NK_WINDOW_CLOSABLE | NK_WINDOW_MINIMIZABLE | NK_WINDOW_MAXIMIZABLE |
NK_WINDOW_PINNABLE |
0; // NK_WINDOW_SCROLL_AUTO_HIDE;
if (nk_begin(ui_ctx, title, nk_rect( (ww-w)/2,(hh-h)/2, w,h), flags))
return 1;
nk_end(ui_ctx);
return 0;
}
int ui_window_nk_end() {
nk_end(ui_ctx);
return 0;
}
#define AS_NKCOLOR(color) \
((struct nk_color){ ((color>>16))&255,((color>>8))&255,((color>>0))&255,((color>>24))&255 })
/*
typedef struct tween_keyframe_t {
int easing_mode;
float t;
vec3 v;
} tween_keyframe_t;
typedef struct tween_t {
array(tween_keyframe_t) keyframes;
vec3 result;
float time;
float duration;
} tween_t;
API tween_t tween();
API float tween_update(tween_t *tw, float dt);
API void tween_reset(tween_t *tw);
API void tween_destroy(tween_t *tw);
API void tween_keyframe_set(tween_t *tw, float t, int easing_mode, vec3 v);
API void tween_keyframe_unset(tween_t *tw, float t);
*/
int ui_tween(const char *label, tween_t *t) {
if( ui_filter && ui_filter[0] ) if( !strstr(label, ui_filter) ) return 0;
int expand_keys = label[0] == '!'; label += expand_keys;
const char *id = label;
if( strchr(id, '@') ) *strchr(((char*)id = va("%s", label)), '@') = '\0';
enum { LABEL_SPACING = 250 };
enum { ROUNDING = 0 };
enum { THICKNESS = 1 };
enum { PIXELS_PER_SECOND = 60 };
enum { KEY_WIDTH = 5, KEY_HEIGHT = 5 };
enum { TIMELINE_HEIGHT = 25 };
enum { MARKER1_HEIGHT = 5, MARKER10_HEIGHT = 20, MARKER5_HEIGHT = (MARKER1_HEIGHT + MARKER10_HEIGHT) / 2 };
unsigned base_color = WHITE;
unsigned time_color = YELLOW;
unsigned duration_color = ORANGE;
unsigned key_color = GREEN;
int changed = 0;
#if 0
// two rows with height:30 composed of three widgets
nk_layout_row_template_begin(ui_ctx, 30);
nk_layout_row_template_push_variable(ui_ctx, t->duration * PIXELS_PER_SECOND); // min 80px. can grow
nk_layout_row_template_end(ui_ctx);
#endif
char *sid = va("%s.%d", id, 0);
uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
ui_label(label);
struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
bounds.y -= 30;
struct nk_rect baseline = bounds; baseline.y += 30/2;
baseline.x += LABEL_SPACING;
baseline.w -= LABEL_SPACING;
// tween duration
{
struct nk_rect pos = baseline;
pos.w = pos.x + t->duration * PIXELS_PER_SECOND;
pos.y -= TIMELINE_HEIGHT/2;
pos.h = TIMELINE_HEIGHT;
nk_stroke_rect(canvas, pos, ROUNDING, THICKNESS*2, AS_NKCOLOR(duration_color));
}
// tween ranges
for(int i = 0, end = array_count(t->keyframes) - 1; i < end; ++i) {
tween_keyframe_t *k = t->keyframes + i;
tween_keyframe_t *next = k + 1;
struct nk_rect pos = baseline;
pos.x += k->t * PIXELS_PER_SECOND;
pos.w = (next->t - k->t) * PIXELS_PER_SECOND;
pos.y -= TIMELINE_HEIGHT/2;
pos.h = TIMELINE_HEIGHT;
char *sid = va("%s.%d", id, i);
uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
struct nk_color c = nk_hsva_f(ui_hue, 0.75f, 0.8f, ui_alpha);
nk_fill_rect(canvas, pos, ROUNDING, c); // AS_NKCOLOR(track_color));
}
// horizontal line
nk_stroke_line(canvas, baseline.x, baseline.y, baseline.x+baseline.w,baseline.y, THICKNESS, AS_NKCOLOR(base_color));
// unit, 5-unit and 10-unit markers
for( int i = 0, j = 0; i < baseline.w; i += PIXELS_PER_SECOND/10, ++j ) {
int len = !(j%10) ? MARKER10_HEIGHT : !(j%5) ? MARKER5_HEIGHT : MARKER1_HEIGHT;
nk_stroke_line(canvas, baseline.x+i, baseline.y-len, baseline.x+i, baseline.y+len, THICKNESS, AS_NKCOLOR(base_color));
}
// time marker
float px = t->time * PIXELS_PER_SECOND;
nk_stroke_line(canvas, baseline.x+px, bounds.y, baseline.x+px, bounds.y+bounds.h, THICKNESS*2, AS_NKCOLOR(time_color));
nk_draw_symbol(canvas, NK_SYMBOL_TRIANGLE_DOWN, ((struct nk_rect){ baseline.x+px-4,bounds.y-4-8,8,8}), /*bg*/AS_NKCOLOR(0), /*fg*/AS_NKCOLOR(time_color), 0.f/*border_width*/, ui_ctx->style.font);
// key markers
for each_array_ptr(t->keyframes, tween_keyframe_t, k) {
struct nk_rect pos = baseline;
pos.x += k->t * PIXELS_PER_SECOND;
vec2 romboid[] = {
{pos.x-KEY_WIDTH,pos.y}, {pos.x,pos.y-KEY_HEIGHT},
{pos.x+KEY_WIDTH,pos.y}, {pos.x,pos.y+KEY_HEIGHT}
};
nk_fill_polygon(canvas, (float*)romboid, countof(romboid), AS_NKCOLOR(key_color));
}
// keys ui
static int num_eases = 0; if(!num_eases) while(num_eases[ease_enums()]) ++num_eases;
if( expand_keys )
for(int i = 0, end = array_count(t->keyframes); i < end; ++i) {
tween_keyframe_t *k = t->keyframes + i;
if( ui_collapse(va("Key %d", i), va("%s.%d", id, i))) {
changed |= ui_float("time", &k->t);
changed |= ui_float3("value", &k->v.x);
changed |= ui_list("easing", ease_enums(), num_eases, &k->easing_mode );
ui_collapse_end();
}
}
return changed;
}
tween_t* rand_tween() {
tween_t demo = tween();
int num_keys = randi(2,8);
double t = 0;
for( int i = 0; i < num_keys; ++i) {
tween_keyframe_set(&demo, t, randi(0,33), scale3(vec3(randf(),randf(),randf()),randi(-5,5)) );
t += randi(1,5) / ((float)(1 << randi(0,2)));
}
tween_t *p = CALLOC(1, sizeof(tween_t));
memcpy(p, &demo, sizeof(tween_t));
return p;
}
static array(tween_t*) tweens;
int editor_timeline() {
do_once {
array_push(tweens, rand_tween());
}
if( editor.t == 0 )
for each_array(tweens, tween_t*,t) {
tween_reset(t);
}
else
for each_array(tweens, tween_t*,t) {
tween_update(t, editor.dt);
}
static void *selected = NULL;
static int open = 1;
if( ui_window/*_nk*/("Timeline " ICON_MDI_CHART_TIMELINE, &open) ) {
int choice = ui_toolbar(ICON_MDI_PLUS ";" ICON_MDI_MINUS );
if( choice == 1 ) array_push(tweens, rand_tween());
if( choice == 2 && selected ) {
int target = -1;
for( int i = 0, end = array_count(tweens); i < end; ++i ) if( tweens[i] == selected ) { target = i; break; }
if( target >= 0 ) { array_erase_slow(tweens, target); selected = NULL; }
}
for each_array(tweens, tween_t*,t) {
ui_tween(va("%s%p@%05.2fs Value: %s", t == selected ? "!":"", t, t->time, ftoa3(t->result)), t);
if(ui_label_icon_clicked_L.x) selected = (t != selected) ? t : NULL;
}
ui_window_end/*_nk_end*/();
}
return 0;
}
AUTORUN {
array_push(editor.subeditors, editor_timeline);
}