diff --git a/MAKE.bat b/MAKE.bat
index 02d9a6e..14b7cc5 100644
--- a/MAKE.bat
+++ b/MAKE.bat
@@ -75,6 +75,13 @@ if "%1"=="cook" (
exit /b
)
+if "%1"=="build_cook" (
+ pushd tools
+ cl cook.c -I..\engine /openmp /Os /Ox /O2 /Oy /MT /DNDEBUG /GL /GF /Gw /arch:AVX2 /link /OPT:ICF /LTCG
+ popd
+
+ exit /b
+)
rem generate bindings
if "%1"=="bind" (
rem luajit
@@ -324,7 +331,7 @@ if "%1"=="fwk_prep" (
xcopy /y "engine\split\3rd_*" "_fwk\engine\split"
xcopy /y "engine\art\shaders\*" "_fwk\engine\art\shaders"
xcopy /y "demos" "_fwk\demos"
- xcopy /y "engine\editor.c" "_fwk\engine\editor.c"
+ copy /y "engine\editor.c" "_fwk\engine\editor.c"
rem xcopy /y/E "tools "_fwk\tools"
for %%f in ("engine\split\v4k*") do (
set "filename=%%~nf"
@@ -371,6 +378,7 @@ if "%1"=="back" (
xcopy /y "_fwk" "."
xcopy /y "_fwk\engine\split\3rd_*" "engine\split"
xcopy /y "_fwk\engine\art\shaders\*" "engine\art\shaders"
+ del "demos\*.c"
xcopy /y "_fwk\demos" "demos"
xcopy /y "_fwk\engine\editor.c" "engine\editor.c"
tools\fwkren.exe "engine\editor.c" to
diff --git a/demos/00-hello.c b/demos/00-loop.c
similarity index 98%
rename from demos/00-hello.c
rename to demos/00-loop.c
index 7ff2a88..5ae1497 100644
--- a/demos/00-hello.c
+++ b/demos/00-loop.c
@@ -1,6 +1,8 @@
#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!");
}
diff --git a/demos/00-ui.c b/demos/00-ui.c
deleted file mode 100644
index 7035670..0000000
--- a/demos/00-ui.c
+++ /dev/null
@@ -1,86 +0,0 @@
-// hello ui: config, window, system, ui, video
-// - rlyeh, public domain.
-//
-// Compile with:
-// `make demos\01-ui.c` (windows)
-// `sh MAKE.bat demos/01-ui.c` (linux, osx)
-
-#include "v4k.h"
-
-int main() {
- float app_volume = 1.00f;
- unsigned app_size = flag("--fullscreen") ? 100 : 75;
- unsigned app_flags = flag("--msaa") ? WINDOW_MSAA4 : 0;
- unsigned app_target_fps = optioni("--fps", 60); // --fps=30, --fps=45, etc. defaults to 60.
-
- // window api (fullscreen or 75% sized, optional MSAA flags)
- window_create(app_size, app_flags);
- window_title(__FILE__);
- window_fps_lock(app_target_fps);
-
- // load video
- video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_LOOP );
-
- // app loop
- while( window_swap() ) {
- // input controls
- if( input(KEY_ESC) ) break;
-
- // profile api
- texture_t *textures;
- profile( "Video decoder" ) {
- // video api: decode frame and get associated textures (audio is sent to audiomixer automatically)
- textures = video_decode( v );
- // fullscreen video
- // if(video_is_rgb(v)) fullscreen_quad_rgb( textures[0], 1.3f );
- // else fullscreen_quad_ycbcr( textures, 1.3f );
- }
-
- // create menubar on top
- int choice1 = ui_menu("File;Shell;Exit");
- int choice2 = ui_menu("Help;About");
- if( choice1 == 1 ) system(ifdef(win32, "start \"\" cmd", ifdef(osx, "open sh", "xdg-open sh")));
- if( choice1 == 2 ) exit(0);
-
- // showcase a few ui widgets
- ui_demo(0);
-
- // create ui panel
- if( ui_panel("myPanel", PANEL_OPEN) ) {
- // Print some numbers
- ui_section("Stats");
- ui_label2("FPS", va("%5.2f", window_fps()));
- ui_separator();
-
- // add some buttons
- ui_section("Buttons");
- if( ui_button("Screenshot") ) window_screenshot(__FILE__ ".png"), ui_notify(0,ICON_MD_WARNING "Screenshot");
- if( ui_button("Record Video") ) window_record(__FILE__ ".mp4"), ui_notify(0,ICON_MD_WARNING "Recoding video");
- if( ui_button("Toggle fullscreen") ) window_fullscreen( !window_has_fullscreen() );
- ui_separator();
-
- // some more video controls
- ui_section("Video");
- if( ui_button("Rewind") ) video_seek(v, video_position(v) - 3);
- if( ui_button("Pause") ) video_pause(v, video_is_paused(v) ^ 1);
- if( ui_button("Forward") ) video_seek(v, video_position(v) + 3);
- if( ui_slider2("Volume", &app_volume, va("%.2f", app_volume))) audio_volume_master(app_volume);
-
- // end of panel. must be enclosed within same if() branch.
- ui_panel_end();
- }
-
- // create window
- static int open = 1;
- if( ui_window("myWindow", &open) ) {
- // present decoded texture in a widget, without any label (NULL)
- ui_texture( NULL, textures[0] );
- // end of window. must be enclosed within same if() branch.
- ui_window_end();
- }
- }
-}
-
-// this demo supersedes following old sources:
-// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-hello.c
-// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-video.c
diff --git a/demos/01-sprite.c b/demos/01-sprite.c
deleted file mode 100644
index 4e65c4d..0000000
--- a/demos/01-sprite.c
+++ /dev/null
@@ -1,218 +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();
- }
- }
-}
diff --git a/demos/04-lod.c b/demos/04-lod.c
deleted file mode 100644
index 99bfe91..0000000
--- a/demos/04-lod.c
+++ /dev/null
@@ -1,234 +0,0 @@
-// LOD demo, based on Polygon Reduction Demo by Stan Melax (PD)
-// - rlyeh, public domain.
-
-#include "v4k.h"
-
-vec2 world2screen(vec3 p) {
- vec4 clip_pos = transform444(camera_get_active()->proj, transform444(camera_get_active()->view, vec4(p.x,p.y,p.z,1.0)));
- vec4 ndc_pos = scale4(clip_pos, 1.0 / (clip_pos.w + !clip_pos.w)); // [-1..1]
- vec2 screen_pos = vec2( window_width() * (ndc_pos.x + 1) / 2.0, window_height() * (1 - ndc_pos.y) / 2.0 );
- return screen_pos;
-}
-
-float mesh_area(mesh_t *m) {
- // @fixme: return 0 if mesh is out of frustum, or window is minimized
-
- aabb box = mesh_bounds(m);
- ddraw_aabb(box.min, box.max);
-
- vec2 A = world2screen(vec3(box.min.x,box.min.y,box.min.z)); ddraw_text2d(A, va("A: %5.2f,%5.2f", A.x, A.y));
- vec2 B = world2screen(vec3(box.min.x,box.min.y,box.max.z)); ddraw_text2d(B, va("B: %5.2f,%5.2f", B.x, B.y));
- vec2 C = world2screen(vec3(box.min.x,box.max.y,box.min.z)); ddraw_text2d(C, va("C: %5.2f,%5.2f", C.x, C.y));
- vec2 D = world2screen(vec3(box.min.x,box.max.y,box.max.z)); ddraw_text2d(D, va("D: %5.2f,%5.2f", D.x, D.y));
- vec2 E = world2screen(vec3(box.max.x,box.min.y,box.min.z)); ddraw_text2d(E, va("E: %5.2f,%5.2f", E.x, E.y));
- vec2 F = world2screen(vec3(box.max.x,box.min.y,box.max.z)); ddraw_text2d(F, va("F: %5.2f,%5.2f", F.x, F.y));
- vec2 G = world2screen(vec3(box.max.x,box.max.y,box.min.z)); ddraw_text2d(G, va("G: %5.2f,%5.2f", G.x, G.y));
- vec2 H = world2screen(vec3(box.max.x,box.max.y,box.max.z)); ddraw_text2d(H, va("H: %5.2f,%5.2f", H.x, H.y));
-
- vec2 O = min2(min2(min2(min2(min2(min2(min2(A,B),C),D),E),F),G),H); ddraw_text2d(O, "|\\");
- vec2 P = max2(max2(max2(max2(max2(max2(max2(A,B),C),D),E),F),G),H); ddraw_text2d(P, "\\|");
-
- float area = (P.x-O.x) * (P.y-O.y); // len2(sub2(P,O));
- float pct = area / (float)(window_height() * window_width());
-
- font_print(va(FONT_RIGHT "area: %5.2f%%", pct*100));
- return pct;
-}
-
-
-API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n, const int *tri, int *map, int *permutation);
-
-// Map()
-//
-// Note that the use of the Map() function and the collapse_map Array isn't part of the polygon reduction
-// algorithm. We set up the function here so that we could retrieve the model at any desired vertex count.
-//
-// When the model is rendered using a maximum of mx vertices then it is vertices 0 through mx-1 that are used.
-// We are able to do this because the vertex Array gets sorted according to the collapse order.
-// The Map() routine takes a vertex number 'n' and the maximum number of vertices 'mx' and returns the
-// appropriate vertex in the range 0 to mx-1. When 'n' is greater than 'mx' the Map() routine follows the
-// chain of edge collapses until a vertex within the limit is reached.
-// An example to make this clear: assume there is a triangle with vertices 1, 3 and 12. But when
-// rendering the model we limit ourselves to 10 vertices. In that case we find out how vertex 12 was
-// removed by the polygon reduction algorithm. i.e. which edge was collapsed. Lets say that vertex 12 was
-// collapsed to vertex number 7. This number would have been stored in the collapse_map array (i.e.
-// collapse_map[12]==7). Since vertex 7 is in range (less than max of 10) we will want to render the
-// triangle 1,3,7. Pretend now that we want to limit ourselves to 5 vertices. and vertex 7 was collapsed
-// to vertex 3 (i.e. collapse_map[7]==3). Then triangle 1,3,12 would now be triangle 1,3,3. i.e. this
-// polygon was removed by the progressive mesh polygon reduction algorithm by the time it had gotten down
-// to 5 vertices. No need to draw a one dimensional polygon. :-)
-
-static inline int MapReduce(array(int) collapse_map, int n, int mx) {
- while( n >= mx ) n = collapse_map[n];
- return n;
-}
-
-mesh_t *ReduceModel(mesh_t *m, float lo_detail, float hi_detail, float morph) {
- int max_verts_to_render = hi_detail * array_count(m->in_vertex3);
- int min_verts_to_render = lo_detail * array_count(m->in_vertex3);
-
- if( max_verts_to_render <= 0 || min_verts_to_render <= 0 )
- return m;
-
- array_resize(m->out_index3, 0);
- array_resize(m->out_vertex3, 0);
-
- ASSERT(array_count(m->lod_collapse_map));
- for( unsigned int i = 0; i < array_count(m->in_index3); i++ ) {
- int p0 = MapReduce(m->lod_collapse_map, m->in_index3[i].x, max_verts_to_render);
- int p1 = MapReduce(m->lod_collapse_map, m->in_index3[i].y, max_verts_to_render);
- int p2 = MapReduce(m->lod_collapse_map, m->in_index3[i].z, max_verts_to_render);
- // @fixme: serious optimization opportunity here,
- // by sorting the triangles the following "continue"
- // could have been made into a "break" statement.
- if(p0==p1 || p0==p2 || p1==p2) continue;
- // if we are not currenly morphing between 2 levels of detail
- // (i.e. if morph=1.0) then q0,q1, and q2 may not be necessary
- int q0 = MapReduce(m->lod_collapse_map, p0, min_verts_to_render);
- int q1 = MapReduce(m->lod_collapse_map, p1, min_verts_to_render);
- int q2 = MapReduce(m->lod_collapse_map, p2, min_verts_to_render);
- vec3 v0, v1, v2;
- v0 = mix3(m->in_vertex3[p0], m->in_vertex3[q0], (1-morph));
- v1 = mix3(m->in_vertex3[p1], m->in_vertex3[q1], (1-morph));
- v2 = mix3(m->in_vertex3[p2], m->in_vertex3[q2], (1-morph));
- vec3 normal = norm3(cross3(sub3(v1,v0),sub3(v2,v1)));
- array_push(m->out_vertex3, v0);
- array_push(m->out_vertex3, normal);
- array_push(m->out_vertex3, v1);
- array_push(m->out_vertex3, normal);
- array_push(m->out_vertex3, v2);
- array_push(m->out_vertex3, normal);
-
- int idx = array_count(m->out_vertex3) / 2;
- array_push(m->out_index3, vec3i(idx-3,idx-2,idx-1));
- }
-
- return m;
-}
-
-void DrawModel(mesh_t *m) {
- 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_normal);\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", NULL);
- shader_bind(program);
- shader_mat44("VP", VP);
- shader_mat44("M", M);
-
- mesh_update(m, "p3 n3", 0,array_count(m->out_vertex3)/2,m->out_vertex3, array_count(m->out_index3)*3,m->out_index3,0);
- mesh_render(m);
-}
-
-void InitModel(mesh_t *m) {
- static const double verts[]={-0.334392,+0.133007,+0.062259,-0.350189,+0.150354,-0.147769,-0.234201,+0.343811,-0.174307,-0.200259,+0.285207,+0.093749,+0.003520,+0.475208,-0.159365,+0.001856,+0.419203,+0.098582,-0.252802,+0.093666,+0.237538,-0.162901,+0.237984,+0.206905,+0.000865,+0.318141,+0.235370,-0.414624,+0.164083,-0.278254,-0.262213,+0.357334,-0.293246,+0.004628,+0.482694,-0.338626,-0.402162,+0.133528,-0.443247,-0.243781,+0.324275,-0.436763,+0.005293,+0.437592,-0.458332,-0.339884,-0.041150,-0.668211,-0.248382,+0.255825,-0.627493,+0.006261,+0.376103,-0.631506,-0.216201,-0.126776,-0.886936,-0.171075,+0.011544,-0.881386,-0.181074,+0.098223,-0.814779,-0.119891,+0.218786,-0.760153,-0.078895,+0.276780,-0.739281,+0.006801,+0.310959,-0.735661,-0.168842,+0.102387,-0.920381,-0.104072,+0.177278,-0.952530,-0.129704,+0.211848,-0.836678,-0.099875,+0.310931,-0.799381,+0.007237,+0.361687,-0.794439,-0.077913,+0.258753,-0.921640,+0.007957,+0.282241,-0.931680,-0.252222,-0.550401,-0.557810,-0.267633,-0.603419,-0.655209,-0.446838,-0.118517,-0.466159,-0.459488,-0.093017,-0.311341,-0.370645,-0.100108,-0.159454,-0.371984,-0.091991,-0.011044,-0.328945,-0.098269,+0.088659,-0.282452,-0.018862,+0.311501,-0.352403,-0.131341,+0.144902,-0.364126,-0.200299,+0.202388,-0.283965,-0.231869,+0.023668,-0.298943,-0.155218,+0.369716,-0.293787,-0.121856,+0.419097,-0.290163,-0.290797,+0.107824,-0.264165,-0.272849,+0.036347,-0.228567,-0.372573,+0.290309,-0.190431,-0.286997,+0.421917,-0.191039,-0.240973,+0.507118,-0.287272,-0.276431,-0.065444,-0.295675,-0.280818,-0.174200,-0.399537,-0.313131,-0.376167,-0.392666,-0.488581,-0.427494,-0.331669,-0.570185,-0.466054,-0.282290,-0.618140,-0.589220,-0.374238,-0.594882,-0.323298,-0.381071,-0.629723,-0.350777,-0.382112,-0.624060,-0.221577,-0.272701,-0.566522,+0.259157,-0.256702,-0.663406,+0.286079,-0.280948,-0.428359,+0.055790,-0.184974,-0.508894,+0.326265,-0.279971,-0.526918,+0.395319,-0.282599,-0.663393,+0.412411,-0.188329,-0.475093,+0.417954,-0.263384,-0.663396,+0.466604,-0.209063,-0.663393,+0.509344,-0.002044,-0.319624,+0.553078,-0.001266,-0.371260,+0.413296,-0.219753,-0.339762,-0.040921,-0.256986,-0.282511,-0.006349,-0.271706,-0.260881,+0.001764,-0.091191,-0.419184,-0.045912,-0.114944,-0.429752,-0.124739,-0.113970,-0.382987,-0.188540,-0.243012,-0.464942,-0.242850,-0.314815,-0.505402,-0.324768,+0.002774,-0.437526,-0.262766,-0.072625,-0.417748,-0.221440,-0.160112,-0.476932,-0.293450,+0.003859,-0.453425,-0.443916,-0.120363,-0.581567,-0.438689,-0.091499,-0.584191,-0.294511,-0.116469,-0.599861,-0.188308,-0.208032,-0.513640,-0.134649,-0.235749,-0.610017,-0.040939,-0.344916,-0.622487,-0.085380,-0.336401,-0.531864,-0.212298,+0.001961,-0.459550,-0.135547,-0.058296,-0.430536,-0.043440,+0.001378,-0.449511,-0.037762,-0.130135,-0.510222,+0.079144,+0.000142,-0.477549,+0.157064,-0.114284,-0.453206,+0.304397,-0.000592,-0.443558,+0.285401,-0.056215,-0.663402,+0.326073,-0.026248,-0.568010,+0.273318,-0.049261,-0.531064,+0.389854,-0.127096,-0.663398,+0.479316,-0.058384,-0.663401,+0.372891,-0.303961,+0.054199,+0.625921,-0.268594,+0.193403,+0.502766,-0.277159,+0.126123,+0.443289,-0.287605,-0.005722,+0.531844,-0.231396,-0.121289,+0.587387,-0.253475,-0.081797,+0.756541,-0.195164,-0.137969,+0.728011,-0.167673,-0.156573,+0.609388,-0.145917,-0.169029,+0.697600,-0.077776,-0.214247,+0.622586,-0.076873,-0.214971,+0.696301,-0.002341,-0.233135,+0.622859,-0.002730,-0.213526,+0.691267,-0.003136,-0.192628,+0.762731,-0.056136,-0.201222,+0.763806,-0.114589,-0.166192,+0.770723,-0.155145,-0.129632,+0.791738,-0.183611,-0.058705,+0.847012,-0.165562,+0.001980,+0.833386,-0.220084,+0.019914,+0.768935,-0.255730,+0.090306,+0.670782,-0.255594,+0.113833,+0.663389,-0.226380,+0.212655,+0.617740,-0.003367,-0.195342,+0.799680,-0.029743,-0.210508,+0.827180,-0.003818,-0.194783,+0.873636,-0.004116,-0.157907,+0.931268,-0.031280,-0.184555,+0.889476,-0.059885,-0.184448,+0.841330,-0.135333,-0.164332,+0.878200,-0.085574,-0.170948,+0.925547,-0.163833,-0.094170,+0.897114,-0.138444,-0.104250,+0.945975,-0.083497,-0.084934,+0.979607,-0.004433,-0.146642,+0.985872,-0.150715,+0.032650,+0.884111,-0.135892,-0.035520,+0.945455,-0.070612,+0.036849,+0.975733,-0.004458,-0.042526,+1.015670,-0.004249,+0.046042,+1.003240,-0.086969,+0.133224,+0.947633,-0.003873,+0.161605,+0.970499,-0.125544,+0.140012,+0.917678,-0.125651,+0.250246,+0.857602,-0.003127,+0.284070,+0.878870,-0.159174,+0.125726,+0.888878,-0.183807,+0.196970,+0.844480,-0.159890,+0.291736,+0.732480,-0.199495,+0.207230,+0.779864,-0.206182,+0.164608,+0.693257,-0.186315,+0.160689,+0.817193,-0.192827,+0.166706,+0.782271,-0.175112,+0.110008,+0.860621,-0.161022,+0.057420,+0.855111,-0.172319,+0.036155,+0.816189,-0.190318,+0.064083,+0.760605,-0.195072,+0.129179,+0.731104,-0.203126,+0.410287,+0.680536,-0.216677,+0.309274,+0.642272,-0.241515,+0.311485,+0.587832,-0.002209,+0.366663,+0.749413,-0.088230,+0.396265,+0.678635,-0.170147,+0.109517,+0.840784,-0.160521,+0.067766,+0.830650,-0.181546,+0.139805,+0.812146,-0.180495,+0.148568,+0.776087,-0.180255,+0.129125,+0.744192,-0.186298,+0.078308,+0.769352,-0.167622,+0.060539,+0.806675,-0.189876,+0.102760,+0.802582,-0.108340,+0.455446,+0.657174,-0.241585,+0.527592,+0.669296,-0.265676,+0.513366,+0.634594,-0.203073,+0.478550,+0.581526,-0.266772,+0.642330,+0.602061,-0.216961,+0.564846,+0.535435,-0.202210,+0.525495,+0.475944,-0.193888,+0.467925,+0.520606,-0.265837,+0.757267,+0.500933,-0.240306,+0.653440,+0.463215,-0.309239,+0.776868,+0.304726,-0.271009,+0.683094,+0.382018,-0.312111,+0.671099,+0.286687,-0.268791,+0.624342,+0.377231,-0.302457,+0.533996,+0.360289,-0.263656,+0.529310,+0.412564,-0.282311,+0.415167,+0.447666,-0.239201,+0.442096,+0.495604,-0.220043,+0.569026,+0.445877,-0.001263,+0.395631,+0.602029,-0.057345,+0.442535,+0.572224,-0.088927,+0.506333,+0.529106,-0.125738,+0.535076,+0.612913,-0.126251,+0.577170,+0.483159,-0.149594,+0.611520,+0.557731,-0.163188,+0.660791,+0.491080,-0.172482,+0.663387,+0.415416,-0.160464,+0.591710,+0.370659,-0.156445,+0.536396,+0.378302,-0.136496,+0.444358,+0.425226,-0.095564,+0.373768,+0.473659,-0.104146,+0.315912,+0.498104,-0.000496,+0.384194,+0.473817,-0.000183,+0.297770,+0.401486,-0.129042,+0.270145,+0.434495,+0.000100,+0.272963,+0.349138,-0.113060,+0.236984,+0.385554,+0.007260,+0.016311,-0.883396,+0.007865,+0.122104,-0.956137,-0.032842,+0.115282,-0.953252,-0.089115,+0.108449,-0.950317,-0.047440,+0.014729,-0.882756,-0.104458,+0.013137,-0.882070,-0.086439,-0.584866,-0.608343,-0.115026,-0.662605,-0.436732,-0.071683,-0.665372,-0.606385,-0.257884,-0.665381,-0.658052,-0.272542,-0.665381,-0.592063,-0.371322,-0.665382,-0.353620,-0.372362,-0.665381,-0.224420,-0.335166,-0.665380,-0.078623,-0.225999,-0.665375,-0.038981,-0.106719,-0.665374,-0.186351,-0.081749,-0.665372,-0.292554,+0.006943,-0.091505,-0.858354,+0.006117,-0.280985,-0.769967,+0.004495,-0.502360,-0.559799,-0.198638,-0.302135,-0.845816,-0.237395,-0.542544,-0.587188,-0.270001,-0.279489,-0.669861,-0.134547,-0.119852,-0.959004,-0.052088,-0.122463,-0.944549,-0.124463,-0.293508,-0.899566,-0.047616,-0.289643,-0.879292,-0.168595,-0.529132,-0.654931,-0.099793,-0.515719,-0.645873,-0.186168,-0.605282,-0.724690,-0.112970,-0.583097,-0.707469,-0.108152,-0.665375,-0.700408,-0.183019,-0.665378,-0.717630,-0.349529,-0.334459,-0.511985,-0.141182,-0.437705,-0.798194,-0.212670,-0.448725,-0.737447,-0.261111,-0.414945,-0.613835,-0.077364,-0.431480,-0.778113,+0.005174,-0.425277,-0.651592,+0.089236,-0.431732,-0.777093,+0.271006,-0.415749,-0.610577,+0.223981,-0.449384,-0.734774,+0.153275,-0.438150,-0.796391,+0.358414,-0.335529,-0.507649,+0.193434,-0.665946,-0.715325,+0.118363,-0.665717,-0.699021,+0.123515,-0.583454,-0.706020,+0.196851,-0.605860,-0.722345,+0.109788,-0.516035,-0.644590,+0.178656,-0.529656,-0.652804,+0.061157,-0.289807,-0.878626,+0.138234,-0.293905,-0.897958,+0.066933,-0.122643,-0.943820,+0.149571,-0.120281,-0.957264,+0.280989,-0.280321,-0.666487,+0.246581,-0.543275,-0.584224,+0.211720,-0.302754,-0.843303,+0.086966,-0.665627,-0.291520,+0.110634,-0.665702,-0.185021,+0.228099,-0.666061,-0.036201,+0.337743,-0.666396,-0.074503,+0.376722,-0.666513,-0.219833,+0.377265,-0.666513,-0.349036,+0.281411,-0.666217,-0.588670,+0.267564,-0.666174,-0.654834,+0.080745,-0.665602,-0.605452,+0.122016,-0.662963,-0.435280,+0.095767,-0.585141,-0.607228,+0.118944,+0.012799,-0.880702,+0.061944,+0.014564,-0.882086,+0.104725,+0.108156,-0.949130,+0.048513,+0.115159,-0.952753,+0.112696,+0.236643,+0.386937,+0.128177,+0.269757,+0.436071,+0.102643,+0.315600,+0.499370,+0.094535,+0.373481,+0.474824,+0.136270,+0.443946,+0.426895,+0.157071,+0.535923,+0.380222,+0.161350,+0.591224,+0.372630,+0.173035,+0.662865,+0.417531,+0.162808,+0.660299,+0.493077,+0.148250,+0.611070,+0.559555,+0.125719,+0.576790,+0.484702,+0.123489,+0.534699,+0.614440,+0.087621,+0.506066,+0.530188,+0.055321,+0.442365,+0.572915,+0.219936,+0.568361,+0.448571,+0.238099,+0.441375,+0.498528,+0.281711,+0.414315,+0.451121,+0.263833,+0.528513,+0.415794,+0.303284,+0.533081,+0.363998,+0.269687,+0.623528,+0.380528,+0.314255,+0.670153,+0.290524,+0.272023,+0.682273,+0.385343,+0.311480,+0.775931,+0.308527,+0.240239,+0.652714,+0.466159,+0.265619,+0.756464,+0.504187,+0.192562,+0.467341,+0.522972,+0.201605,+0.524885,+0.478417,+0.215743,+0.564193,+0.538084,+0.264969,+0.641527,+0.605317,+0.201031,+0.477940,+0.584002,+0.263086,+0.512567,+0.637832,+0.238615,+0.526867,+0.672237,+0.105309,+0.455123,+0.658482,+0.183993,+0.102195,+0.804872,+0.161563,+0.060042,+0.808692,+0.180748,+0.077754,+0.771600,+0.175168,+0.128588,+0.746368,+0.175075,+0.148030,+0.778264,+0.175658,+0.139265,+0.814333,+0.154191,+0.067291,+0.832578,+0.163818,+0.109013,+0.842830,+0.084760,+0.396004,+0.679695,+0.238888,+0.310760,+0.590775,+0.213380,+0.308625,+0.644905,+0.199666,+0.409678,+0.683003,+0.190143,+0.128597,+0.733463,+0.184833,+0.063516,+0.762902,+0.166070,+0.035644,+0.818261,+0.154361,+0.056943,+0.857042,+0.168542,+0.109489,+0.862725,+0.187387,+0.166131,+0.784599,+0.180428,+0.160135,+0.819438,+0.201823,+0.163991,+0.695756,+0.194206,+0.206635,+0.782275,+0.155438,+0.291260,+0.734412,+0.177696,+0.196424,+0.846693,+0.152305,+0.125256,+0.890786,+0.119546,+0.249876,+0.859104,+0.118369,+0.139643,+0.919173,+0.079410,+0.132973,+0.948652,+0.062419,+0.036648,+0.976547,+0.127847,-0.035919,+0.947070,+0.143624,+0.032206,+0.885913,+0.074888,-0.085173,+0.980577,+0.130184,-0.104656,+0.947620,+0.156201,-0.094653,+0.899074,+0.077366,-0.171194,+0.926545,+0.127722,-0.164729,+0.879810,+0.052670,-0.184618,+0.842019,+0.023477,-0.184638,+0.889811,+0.022626,-0.210587,+0.827500,+0.223089,+0.211976,+0.620493,+0.251444,+0.113067,+0.666494,+0.251419,+0.089540,+0.673887,+0.214360,+0.019258,+0.771595,+0.158999,+0.001490,+0.835374,+0.176696,-0.059249,+0.849218,+0.148696,-0.130091,+0.793599,+0.108290,-0.166528,+0.772088,+0.049820,-0.201382,+0.764454,+0.071341,-0.215195,+0.697209,+0.073148,-0.214475,+0.623510,+0.140502,-0.169461,+0.699354,+0.163374,-0.157073,+0.611416,+0.189466,-0.138550,+0.730366,+0.247593,-0.082554,+0.759610,+0.227468,-0.121982,+0.590197,+0.284702,-0.006586,+0.535347,+0.275741,+0.125287,+0.446676,+0.266650,+0.192594,+0.506044,+0.300086,+0.053287,+0.629620,+0.055450,-0.663935,+0.375065,+0.122854,-0.664138,+0.482323,+0.046520,-0.531571,+0.391918,+0.024824,-0.568450,+0.275106,+0.053855,-0.663931,+0.328224,+0.112829,-0.453549,+0.305788,+0.131265,-0.510617,+0.080746,+0.061174,-0.430716,-0.042710,+0.341019,-0.532887,-0.208150,+0.347705,-0.623533,-0.081139,+0.238040,-0.610732,-0.038037,+0.211764,-0.514274,-0.132078,+0.120605,-0.600219,-0.186856,+0.096985,-0.584476,-0.293357,+0.127621,-0.581941,-0.437170,+0.165902,-0.477425,-0.291453,+0.077720,-0.417975,-0.220519,+0.320892,-0.506363,-0.320874,+0.248214,-0.465684,-0.239842,+0.118764,-0.383338,-0.187114,+0.118816,-0.430106,-0.123307,+0.094131,-0.419464,-0.044777,+0.274526,-0.261706,+0.005110,+0.259842,-0.283292,-0.003185,+0.222861,-0.340431,-0.038210,+0.204445,-0.664380,+0.513353,+0.259286,-0.664547,+0.471281,+0.185402,-0.476020,+0.421718,+0.279163,-0.664604,+0.417328,+0.277157,-0.528122,+0.400208,+0.183069,-0.509812,+0.329995,+0.282599,-0.429210,+0.059242,+0.254816,-0.664541,+0.290687,+0.271436,-0.567707,+0.263966,+0.386561,-0.625221,-0.216870,+0.387086,-0.630883,-0.346073,+0.380021,-0.596021,-0.318679,+0.291269,-0.619007,-0.585707,+0.339280,-0.571198,-0.461946,+0.400045,-0.489778,-0.422640,+0.406817,-0.314349,-0.371230,+0.300588,-0.281718,-0.170549,+0.290866,-0.277304,-0.061905,+0.187735,-0.241545,+0.509437,+0.188032,-0.287569,+0.424234,+0.227520,-0.373262,+0.293102,+0.266526,-0.273650,+0.039597,+0.291592,-0.291676,+0.111386,+0.291914,-0.122741,+0.422683,+0.297574,-0.156119,+0.373368,+0.286603,-0.232731,+0.027162,+0.364663,-0.201399,+0.206850,+0.353855,-0.132408,+0.149228,+0.282208,-0.019715,+0.314960,+0.331187,-0.099266,+0.092701,+0.375463,-0.093120,-0.006467,+0.375917,-0.101236,-0.154882,+0.466635,-0.094416,-0.305669,+0.455805,-0.119881,-0.460632,+0.277465,-0.604242,-0.651871,+0.261022,-0.551176,-0.554667,+0.093627,+0.258494,-0.920589,+0.114248,+0.310608,-0.798070,+0.144232,+0.211434,-0.835001,+0.119916,+0.176940,-0.951159,+0.184061,+0.101854,-0.918220,+0.092431,+0.276521,-0.738231,+0.133504,+0.218403,-0.758602,+0.194987,+0.097655,-0.812476,+0.185542,+0.011005,-0.879202,+0.230315,-0.127450,-0.884202,+0.260471,+0.255056,-0.624378,+0.351567,-0.042194,-0.663976,+0.253742,+0.323524,-0.433716,+0.411612,+0.132299,-0.438264,+0.270513,+0.356530,-0.289984,+0.422146,+0.162819,-0.273130,+0.164724,+0.237490,+0.208912,+0.253806,+0.092900,+0.240640,+0.203608,+0.284597,+0.096223,+0.241006,+0.343093,-0.171396,+0.356076,+0.149288,-0.143443,+0.337656,+0.131992,+0.066374,};
- static const int tris[]={126,134,133,342,138,134,133,134,138,126,342,134,312,316,317,169,163,162,312,317,319,312,319,318,169,162,164,169,168,163,312,314,315,169,164,165,169,167,168,312,315,316,312,313,314,169,165,166,169,166,167,312,318,313,308,304,305,308,305,306,179,181,188,177,173,175,177,175,176,302,293,300,322,294,304,188,176,175,188,175,179,158,177,187,305,293,302,305,302,306,322,304,308,188,181,183,158,173,177,293,298,300,304,294,296,304,296,305,185,176,188,185,188,183,187,177,176,187,176,185,305,296,298,305,298,293,436,432, 28,436, 28, 23,434,278,431, 30,208,209, 30,209, 29, 19, 20, 24,208,207,211,208,211,209, 19,210,212,433,434,431,433,431,432,433,432,436,436,437,433,277,275,276,277,276,278,209,210, 25, 21, 26, 24, 21, 24, 20, 25, 26, 27, 25, 27, 29,435,439,277,439,275,277,432,431, 30,432, 30, 28,433,437,438,433,438,435,434,277,278, 24, 25,210, 24, 26, 25, 29, 27, 28, 29, 28, 30, 19, 24,210,208, 30,431,208,431,278,435,434,433,435,277,434, 25, 29,209, 27, 22, 23, 27, 23, 28, 26, 22, 27, 26, 21, 22,212,210,209,212,209,211,207,208,278,207,278,276,439,435,438, 12, 9, 10, 12, 10, 13, 2, 3, 5, 2, 5, 4, 16, 13, 14, 16, 14, 17, 22, 21, 16, 13, 10, 11, 13, 11, 14, 1, 0, 3, 1, 3, 2, 15, 12, 16, 19, 18, 15, 19, 15, 16, 19, 16, 20, 9, 1, 2, 9, 2, 10, 3, 7, 8, 3, 8, 5, 16, 17, 23, 16, 23, 22, 21, 20, 16, 10, 2, 4, 10, 4, 11, 0, 6, 7, 0, 7, 3, 12, 13, 16,451,446,445,451,445,450,442,440,439,442,439,438,442,438,441,421,420,422,412,411,426,412,426,425,408,405,407,413, 67, 68,413, 68,414,391,390,412, 80,384,386,404,406,378,390,391,377,390,377, 88,400,415,375,398,396,395,398,395,371,398,371,370,112,359,358,112,358,113,351,352,369,125,349,348,345,343,342,342,340,339,341,335,337,328,341,327,331,323,333,331,322,323,327,318,319,327,319,328,315,314,324,302,300,301,302,301,303,320,311,292,285,284,289,310,307,288,310,288,290,321,350,281,321,281,282,423,448,367,272,273,384,272,384,274,264,265,382,264,382,383,440,442,261,440,261,263,252,253,254,252,254,251,262,256,249,262,249,248,228,243,242,228, 31,243,213,215,238,213,238,237, 19,212,230,224,225,233,224,233,231,217,218, 56,217, 56, 54,217,216,239,217,239,238,217,238,215,218,217,215,218,215,214, 6,102,206,186,199,200,197,182,180,170,171,157,201,200,189,170,190,191,170,191,192,175,174,178,175,178,179,168,167,155,122,149,158,122,158,159,135,153,154,135,154,118,143,140,141,143,141,144,132,133,136,130,126,133,124,125,127,122,101,100,122,100,121,110,108,107,110,107,109, 98, 99, 97, 98, 97, 64, 98, 64, 66, 87, 55, 57, 83, 82, 79, 83, 79, 84, 78, 74, 50, 49, 71, 41, 49, 41, 37, 49, 37, 36, 58, 44, 60, 60, 59, 58, 51, 34, 33, 39, 40, 42, 39, 42, 38,243,240, 33,243, 33,229, 39, 38, 6, 44, 46, 40, 55, 56, 57, 64, 62, 65, 64, 65, 66, 41, 71, 45, 75, 50, 51, 81, 79, 82, 77, 88, 73, 93, 92, 94, 68, 47, 46, 96, 97, 99, 96, 99, 95,110,109,111,111,112,110,114,113,123,114,123,124,132,131,129,133,137,136,135,142,145,145,152,135,149,147,157,157,158,149,164,150,151,153,163,168,153,168,154,185,183,182,185,182,184,161,189,190,200,199,191,200,191,190,180,178,195,180,195,196,102,101,204,102,204,206, 43, 48,104, 43,104,103,216,217, 54,216, 54, 32,207,224,231,230,212,211,230,211,231,227,232,241,227,241,242,235,234,241,235,241,244,430,248,247,272,274,253,272,253,252,439,260,275,225,224,259,225,259,257,269,270,407,269,407,405,270,269,273,270,273,272,273,269,268,273,268,267,273,267,266,273,266,265,273,265,264,448,279,367,281,350,368,285,286,301,290,323,310,290,311,323,282,281,189,292,311,290,292,290,291,307,306,302,307,302,303,316,315,324,316,324,329,331,351,350,330,334,335,330,335,328,341,337,338,344,355,354,346,345,348,346,348,347,364,369,352,364,352,353,365,363,361,365,361,362,376,401,402,373,372,397,373,397,400,376, 92,377,381,378,387,381,387,385,386, 77, 80,390,389,412,416,417,401,403,417,415,408,429,430,419,423,418,427,428,444,427,444,446,437,436,441,450,445, 11,450, 11, 4,447,449, 5,447, 5, 8,441,438,437,425,426,451,425,451,452,417,421,415,408,407,429,399,403,400,399,400,397,394,393,416,389,411,412,386,383,385,408,387,378,408,378,406,377,391,376, 94,375,415,372,373,374,372,374,370,359,111,360,359,112,111,113,358,349,113,349,123,346,343,345,343,340,342,338,336,144,338,144,141,327,341,354,327,354,326,331,350,321,331,321,322,314,313,326,314,326,325,300,298,299,300,299,301,288,287,289,189,292,282,287,288,303,284,285,297,368,280,281,448,447,279,274,226,255,267,268,404,267,404,379,429,262,430,439,440,260,257,258,249,257,249,246,430,262,248,234,228,242,234,242,241,237,238,239,237,239,236, 15, 18,227, 15,227,229,222,223, 82,222, 82, 83,214,215,213,214,213, 81, 38,102, 6,122,159,200,122,200,201,174,171,192,174,192,194,197,193,198,190,170,161,181,179,178,181,178,180,166,156,155,163,153,152,163,152,162,120,156,149,120,149,121,152,153,135,140,143,142,135,131,132,135,132,136,130,129,128,130,128,127,100,105,119,100,119,120,106,104,107,106,107,108, 91, 95, 59, 93, 94, 68, 91, 89, 92, 76, 53, 55, 76, 55, 87, 81, 78, 79, 74, 73, 49, 69, 60, 45, 58, 62, 64, 58, 64, 61, 53, 31, 32, 32, 54, 53, 42, 43, 38, 35, 36, 0, 35, 0, 1, 34, 35, 1, 34, 1, 9, 44, 40, 41, 44, 41, 45, 33,240, 51, 63, 62, 58, 63, 58, 59, 45, 71, 70, 76, 75, 51, 76, 51, 52, 86, 85, 84, 86, 84, 87, 89, 72, 73, 89, 73, 88, 91, 92, 96, 91, 96, 95, 72, 91, 60, 72, 60, 69,104,106,105,119,105,117,119,117,118,124,127,128,117,116,129,117,129,131,118,117,131,135,140,142,146,150,152,146,152,145,149,122,121,166,165,151,166,151,156,158,172,173,161,160,189,199,198,193,199,193,191,204,201,202,178,174,194,200,159,186,109, 48, 67, 48,107,104,216, 32,236,216,236,239,223,214, 81,223, 81, 82, 33, 12, 15, 32,228,234, 32,234,236,240, 31, 52,256,255,246,256,246,249,258,263,248,258,248,249,275,260,259,275,259,276,207,276,259,270,271,429,270,429,407,413,418,366,413,366,365,368,367,279,368,279,280,303,301,286,303,286,287,283,282,292,283,292,291,320,292,189,298,296,297,298,297,299,318,327,326,318,326,313,329,330,317,336,333,320,326,354,353,334,332,333,334,333,336,342,339,139,342,139,138,345,342,126,347,357,356,369,368,351,363,356,357,363,357,361,366,367,368,366,368,369,375,373,400, 92, 90,377,409,387,408,386,385,387,386,387,388,412,394,391,396,398,399,408,406,405,415,421,419,415,419,414,425,452,448,425,448,424,444,441,443,448,452,449,448,449,447,446,444,443,446,443,445,250,247,261,250,261,428,421,422,423,421,423,419,427,410,250,417,403,401,403,402,401,420,392,412,420,412,425,420,425,424,386,411,389,383,382,381,383,381,385,378,379,404,372,371,395,372,395,397,371,372,370,361,359,360,361,360,362,368,350,351,349,347,348,356,355,344,356,344,346,344,341,340,344,340,343,338,337,336,328,335,341,324,352,351,324,351,331,320,144,336,314,325,324,322,308,309,310,309,307,287,286,289,203,280,279,203,279,205,297,295,283,297,283,284,447,205,279,274,384, 80,274, 80,226,266,267,379,266,379,380,225,257,246,225,246,245,256,254,253,256,253,255,430,247,250,226,235,244,226,244,245,232,233,244,232,244,241,230, 18, 19, 32, 31,228,219,220, 86,219, 86, 57,226,213,235,206, 7, 6,122,201,101,201,204,101,180,196,197,170,192,171,200,190,189,194,193,195,183,181,180,183,180,182,155,154,168,149,156,151,149,151,148,155,156,120,145,142,143,145,143,146,136,137,140,133,132,130,128,129,116,100,120,121,110,112,113,110,113,114, 66, 65, 63, 66, 63, 99, 66, 99, 98, 96, 46, 61, 89, 88, 90, 86, 87, 57, 80, 78, 81, 72, 69, 49, 67, 48, 47, 67, 47, 68, 56, 55, 53, 50, 49, 36, 50, 36, 35, 40, 39, 41,242,243,229,242,229,227, 6, 37, 39, 42, 47, 48, 42, 48, 43, 61, 46, 44, 45, 70, 69, 69, 70, 71, 69, 71, 49, 74, 78, 77, 83, 84, 85, 73, 74, 77, 93, 96, 92, 68, 46, 93, 95, 99, 63, 95, 63, 59,115,108,110,115,110,114,125,126,127,129,130,132,137,133,138,137,138,139,148,146,143,148,143,147,119,118,154,161,147,143,165,164,151,158,157,171,158,171,172,159,158,187,159,187,186,194,192,191,194,191,193,189,202,201,182,197,184,205, 8, 7, 48,109,107,218,219, 57,218, 57, 56,207,231,211,232,230,231,232,231,233, 53, 52, 31,388,411,386,409,430,250,262,429,254,262,254,256,442,444,428,273,264,383,273,383,384,429,271,251,429,251,254,413,365,362, 67,413,360,282,283,295,285,301,299,202,281,280,284,283,291,284,291,289,320,189,160,308,306,307,307,309,308,319,317,330,319,330,328,353,352,324,332,331,333,340,341,338,354,341,344,349,358,357,349,357,347,364,355,356,364,356,363,364,365,366,364,366,369,374,376,402,375, 92,373, 77,389,390,382,380,381,389, 77,386,393,394,412,393,412,392,401,394,416,415,400,403,411,410,427,411,427,426,422,420,424,247,248,263,247,263,261,445,443, 14,445, 14, 11,449,450, 4,449, 4, 5,443,441, 17,443, 17, 14,436, 23, 17,436, 17,441,424,448,422,448,423,422,414,419,418,414,418,413,406,404,405,399,397,395,399,395,396,420,416,392,388,410,411,386,384,383,390, 88, 77,375, 94, 92,415,414, 68,415, 68, 94,370,374,402,370,402,398,361,357,358,361,358,359,125,348,126,346,344,343,340,338,339,337,335,334,337,334,336,325,353,324,324,331,332,324,332,329,323,322,309,323,309,310,294,295,297,294,297,296,289,286,285,202,280,203,288,307,303,282,295,321, 67,360,111,418,423,367,418,367,366,272,252,251,272,251,271,272,271,270,255,253,274,265,266,380,265,380,382,442,428,261,440,263,258,440,258,260,409,250,410,255,226,245,255,245,246, 31,240,243,236,234,235,236,235,237,233,225,245,233,245,244,220,221, 85,220, 85, 86, 81,213,226, 81,226, 80, 7,206,205,186,184,198,186,198,199,204,203,205,204,205,206,195,193,196,171,174,172,173,174,175,173,172,174,155,167,166,160,161,143,160,143,144,119,154,155,148,151,150,148,150,146,140,137,139,140,139,141,127,126,130,114,124,128,114,128,115,117,105,106,117,106,116,104,105,100,104,100,103, 59, 60, 91, 97, 96, 61, 97, 61, 64, 91, 72, 89, 87, 84, 79, 87, 79, 76, 78, 80, 77, 49, 50, 74, 60, 44, 45, 61, 44, 58, 51, 50, 35, 51, 35, 34, 39, 37, 41, 33, 34, 9, 33, 9, 12, 0, 36, 37, 0, 37, 6, 40, 46, 47, 40, 47, 42, 53, 54, 56, 65, 62, 63, 72, 49, 73, 79, 78, 75, 79, 75, 76, 52, 53, 76, 92, 89, 90, 96, 93, 46,102,103,100,102,100,101,116,106,108,116,108,115,123,125,124,116,115,128,118,131,135,140,135,136,148,147,149,120,119,155,164,162,152,164,152,150,157,147,161,157,161,170,186,187,185,186,185,184,193,197,196,202,203,204,194,195,178,198,184,197, 67,111,109, 38, 43,103, 38,103,102,214,223,222,214,222,221,214,221,220,214,220,219,214,219,218,213,237,235,221,222, 83,221, 83, 85, 15,229, 33,227, 18,230,227,230,232, 52, 51,240, 75, 78, 50,408,430,409,260,258,257,260,257,259,224,207,259,268,269,405,268,405,404,413,362,360,447, 8,205,299,297,285,189,281,202,290,288,289,290,289,291,322,321,295,322,295,294,333,323,311,333,311,320,317,316,329,320,160,144,353,325,326,329,332,334,329,334,330,339,338,141,339,141,139,348,345,126,347,356,346,123,349,125,364,353,354,364,354,355,365,364,363,376,391,394,376,394,401, 92,376,374, 92,374,373,377, 90, 88,380,379,378,380,378,381,388,387,409,388,409,410,416,393,392,399,398,402,399,402,403,250,428,427,421,417,416,421,416,420,426,427,446,426,446,451,444,442,441,452,451,450,452,450,449,};
- enum { NUM_VERTS = countof(verts) / 3, NUM_TRIS = countof(tris) / 3 };
-
- // Copy the geometry from the arrays of data into the arrays which we send to the reduction routine
- for(int i = 0; i < NUM_VERTS; i++ ) {
- const double *vp = &verts[i*3];
- array_push(m->in_vertex3, vec3(vp[0],vp[1],vp[2]));
- }
- for(int i = 0; i < NUM_TRIS; i++ ) {
- const int *td = &tris[i*3];
- array_push(m->in_index3, vec3i(td[0],td[1],td[2]));
- }
-
- int tri_n = array_count(m->in_index3);
- int vert_n = array_count(m->in_vertex3);
- int vert_stride = sizeof(float) * 3;
- array(int) permutation = 0;
- array_resize(m->lod_collapse_map, vert_n);
- array_resize(permutation, vert_n);
- ProgressiveMesh(vert_n, vert_stride, (const float *)m->in_vertex3, tri_n, (const int *)m->in_index3, m->lod_collapse_map, permutation);
- // PermuteVertices {
- ASSERT(array_count(permutation) == array_count(m->in_vertex3));
- // rearrange the vertex Array
- array(vec3) tmp = 0;
- for(int i = 0; i < array_count(m->in_vertex3); i++) array_push(tmp, m->in_vertex3[i]);
- for(int i = 0; i < array_count(m->in_vertex3); i++) m->in_vertex3[permutation[i]]=tmp[i];
- // update the changes in the entries in the triangle Array
- for (int i = 0; i < array_count(m->in_index3); i++) {
- m->in_index3[i].x = permutation[m->in_index3[i].x];
- m->in_index3[i].y = permutation[m->in_index3[i].y];
- m->in_index3[i].z = permutation[m->in_index3[i].z];
- }
- array_free(tmp);
- // } PermuteVertices
- array_free(permutation);
-}
-
-int main() {
- window_create(0.75, 0);
- window_color(PURPLE);
-
- camera_t cam = camera();
- cam.speed /= 4;
- cam.position = vec3(1.667,0.503,2.417);
- camera_lookat(&cam, vec3(0,0,0));
-
- mesh_t m = mesh();
- InitModel(&m);
-
- float lo_detail=0.25f;
- float hi_detail=1.00f;
- float morph=0.75f;
-
- while( window_swap() && !input(KEY_ESC) ) {
- if( input(KEY_LALT) && input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
-
- // fps camera
- if( input(GAMEPAD_CONNECTED) ) {
- vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
- vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
- vec2 mouse = scale2(vec2(filtered_rpad.x, filtered_rpad.y), 1.0f);
- vec3 wasdec = scale3(vec3(filtered_lpad.x, input(GAMEPAD_LT) - input(GAMEPAD_RT), filtered_lpad.y), 1.0f);
- camera_moveby(&cam, wasdec);
- camera_fps(&cam, mouse.x,mouse.y);
- window_cursor( true );
- } else {
- 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_moveby(&cam, wasdecq);
- camera_fps(&cam, mouse.x,mouse.y);
- window_cursor( !active );
- }
-
- profile("LOD generation") {
- ReduceModel(&m, lo_detail, hi_detail, morph);
- mesh_area(&m);
- }
-
- DrawModel(&m);
-
- if( ui_panel("LODs", PANEL_OPEN) ) {
- ui_label(va("Polys: %d/%d Vertices: %d/%d", array_count(m.out_index3), array_count(m.in_index3), (int)(lo_detail * array_count(m.in_vertex3)), (int)(hi_detail * array_count(m.in_vertex3))));
- if(ui_slider("Lo detail", &lo_detail)) { lo_detail = clampf(lo_detail, 0.01f, 1.0f); if(lo_detail > hi_detail) hi_detail = lo_detail; }
- if(ui_slider("Hi detail", &hi_detail)) { hi_detail = clampf(hi_detail, 0.01f, 1.0f); if(hi_detail < lo_detail) lo_detail = hi_detail; }
- ui_slider("Morph", &morph);
- ui_panel_end();
- }
- }
-}
diff --git a/demos/05-scene.c b/demos/05-scene.c
deleted file mode 100644
index fd00e77..0000000
--- a/demos/05-scene.c
+++ /dev/null
@@ -1,216 +0,0 @@
-// scene demo
-// - rlyeh, public domain
-
-#include "v4k.h"
-
-int main() {
- // options
- bool do_twosided = 1;
- bool do_wireframe = 0;
- bool do_billboard_x = 1, do_billboard_y = 1, do_billboard_z = 1;
-
- // window (80% sized, MSAA x4 flag)
- window_create(80, WINDOW_MSAA4);
- window_title(__FILE__);
-
- // load all postfx files in all subdirs
- fx_load("fx**.fs");
-
- // scene loading
- #define SCENE(...) #__VA_ARGS__
- const char *my_scene = SCENE([
- {
- skybox: 'cubemaps/stardust/',
- },
- {
- position:[-5.0,-2.0,2.0],
- rotation: [90.0,0.0,180.0],
- scale:0.20,
- //anchor/pivot:[],
- // vertex:'p3 t2',
- mesh:'models/witch/witch.obj',
- texture:'models/witch/witch_diffuse.tga.png',
-// swapzy:true,
- flipuv:false,
- },
- {
- position:[-5.0,-2.0,2.0],
- rotation: [90.0,0.0,180.0],
- scale:2.20,
- //anchor/pivot:[],
- // vertex:'p3 t2',
- mesh:'models/witch/witch_object.obj',
- texture:'models/witch/witch_object_diffuse.tga.png',
-// swapzy:true,
- flipuv:false,
- },
- ]);
- int num_spawned = scene_merge(my_scene);
- object_t *obj1 = scene_index(0);
- object_t *obj2 = scene_index(1);
-
- // manual spawn & loading
- model_t m1 = model("kgirl/kgirls01.fbx", 0); //MODEL_NO_ANIMS);
- texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
- object_t* obj3 = scene_spawn();
- object_model(obj3, m1);
- object_diffuse(obj3, t1);
- object_scale(obj3, vec3(3,3,3));
- object_move(obj3, vec3(-10,0,-10));
- object_pivot(obj3, vec3(-90+180,180,0));
-
- // camera
- camera_t cam = camera();
-
- // demo loop
- while (window_swap())
- {
- // input
- if( input_down(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 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_moveby(&cam, wasdecq);
- camera_fps(&cam, mouse.x,mouse.y);
-
- // queue model scale bounces
- float t = fmod(window_time(), 0.3) / 0.3;
- float s = 0.01f * ease_ping_pong(t, EASE_IN|EASE_CUBIC,EASE_OUT|EASE_CUBIC);
- object_scale(obj1, vec3(0.20f - s,0.20f + s,0.20f - s));
- object_scale(obj2, vec3(0.20f - s,0.20f + s,0.20f - s));
-
- // queue model billboard
- object_billboard(obj1, (do_billboard_x << 2)|(do_billboard_y << 1)|(do_billboard_z << 0));
- object_billboard(obj2, (do_billboard_x << 2)|(do_billboard_y << 1)|(do_billboard_z << 0));
-
- // queue model rotation
- //object_rotate(obj3, vec3(0,1*window_time() * 20,0));
-
- // flush render scene (background objects: skybox)
- profile("Scene background") {
- scene_render(SCENE_BACKGROUND);
- }
-
- // queue debug drawcalls
- profile("Debugdraw") {
- ddraw_ground(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));
- ddraw_color(YELLOW);
- ddraw_flush();
- }
-
- // apply post-fxs from here
- fx_begin();
-
- // render scene (foreground objects) with post-effects
- profile("Scene foreground") {
- int scene_flags = 0;
- scene_flags |= do_wireframe ? SCENE_WIREFRAME : 0;
- scene_flags |= do_twosided ? 0 : SCENE_CULLFACE;
- scene_render(SCENE_FOREGROUND | scene_flags);
- }
-
- profile("Skeletal update") if(!window_has_pause()) {
- float delta = window_delta() * 30 ; // 30fps anim
- m1.curframe = model_animate(m1, m1.curframe + delta);
-
- ddraw_text(vec3(-10,5,-10), 0.05, va("Frame: %.1f", m1.curframe));
- }
-
- // post-fxs end here
- fx_end();
-
- // queue ui
- if( ui_panel("Scene", 0)) {
- if(ui_toggle("Billboard X", &do_billboard_x)) {}
- if(ui_toggle("Billboard Y", &do_billboard_y)) {}
- if(ui_toggle("Billboard Z", &do_billboard_z)) {}
- if(ui_separator()) {}
- if(ui_bool("Wireframe", &do_wireframe)) {}
- if(ui_bool("Two sided", &do_twosided)) {}
- ui_panel_end();
- }
- }
-}
-
-#if 0
-
-// ----------------------------------------------------------------------------
-// material demo
-// - rlyeh, public domain
-//
-// @todo: object_print(obj, "");
-
-// create camera
-camera_t cam = camera();
-// load video, RGB texture, no audio
-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);
-// load model
-model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
-model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
-
-// spawn object1 (diffuse)
-object_t* obj1 = scene_spawn();
-object_model(obj1, m1);
-object_diffuse(obj1, t1);
-object_scale(obj1, vec3(3,3,3));
-object_move(obj1, vec3(-10+5*0,0,-10));
-object_pivot(obj1, vec3(0,90,0));
-
-// spawn object2 (matcap)
-object_t* obj2 = scene_spawn();
-object_model(obj2, m2);
-object_diffuse(obj2, t2);
-object_scale(obj2, vec3(3,3,3));
-object_move(obj2, vec3(-10+5*2,0,-10));
-object_pivot(obj2, vec3(0,90,0));
-
-// spawn object2 (video)
-object_t* obj3 = scene_spawn();
-object_model(obj3, m1);
-object_diffuse(obj3, video_textures(v)[0]);
-object_scale(obj3, vec3(3,3,3));
-object_move(obj3, vec3(-10+5*1,0,-10));
-object_pivot(obj3, vec3(0,90,0));
-
-// @todo: add shadertoy material
- static model_t cube; do_once cube = model("cube.obj", 0);
- static shadertoy_t s; do_once s = shadertoy("shadertoys/4ttGWM.fs", 256);
- model_set_texture(cube, shadertoy_render(&s, window_delta())->tx);
- model_render(cube, cam.proj, cam.view, cube.pivot, 0);
-
-while(window_swap() && !input(KEY_ESC)) {
- // draw environment
- viewport_color( RGB3(22,22,32) );
- ddraw_grid(0);
- ddraw_flush();
-
- // update video
- video_decode( v );
-
- // draw scene
- scene_render(SCENE_FOREGROUND);
-}
-
-// load static scene
-// model_t sponza = model("sponza.obj", MODEL_MATCAPS);
-// model_set_texture(sponza, texture("matcaps/normals", 0));
-// translation44(sponza.pivot, 0,-1,0);
-// rotate44(sponza.pivot, -90,1,0,0);
-// scale44(sponza.pivot, 10,10,10);
- // model_render(sponza, cam.proj, cam.view, sponza.pivot, 0);
-
-// this demo supersedes following old sources:
-// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-material.c
-// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-shadertoy.c
-
-#endif
diff --git a/demos/06-controller.c b/demos/06-controller.c
deleted file mode 100644
index faf5a98..0000000
--- a/demos/06-controller.c
+++ /dev/null
@@ -1,280 +0,0 @@
-// full controller demo: anims, input, collide; @todo: gamepad, input opts, easing on hits, notify on gamepad connect
-// - rlyeh, public domain.
-//
-// Compile with:
-// `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_MSAA2);
-
- // fx: load all post fx files in all subdirs
- fx_load("fx**.fs");
-
- // create a camera
- camera_t cam = camera();
- camera_enable(&cam);
-
- // config 3d model #1
- model_t witch = model("witch/witch.obj", 0);
- model_set_texture(witch, texture("witch/witch_diffuse.tga.png", 0));
- mat44 witch_pivot; vec3 witch_p = {-5,0,-5}, witch_r={-180,180,0}, witch_s={0.1,-0.1,0.1};
-
- // config 3d model #2
- model_t girl = model("kgirl/kgirls01.fbx", 0);
- mat44 girl_pivot; vec3 girl_p = {0,0,0}, girl_r = {270,0,0}, girl_s = {2,2,2};
-
- // skybox
- skybox_t sky = skybox("cubemaps/stardust", 0);
-
- // BGM
- audio_play( audio_stream("waterworld-map.fur"), 0 );
-
- // editor loop
- while( window_swap() ) {
-
- // game camera
- profile("Game.Camera") {
- camera_t *cam = camera_get_active();
-
- static vec3 source;
- do_once source = cam->position;
-
- vec3 target = add3(girl_p, vec3(0,10,0));
- target = add3(target, scale3(norm3(sub3(source, target)), 10.0));
- source = mix3(source, target, 1-0.99f);
-
- camera_teleport(cam, source);
- camera_lookat(cam, vec3(girl_p.x,0,girl_p.z));
- }
-
- // render begin (postfx)
- fx_begin();
-
- // skybox
- skybox_render(&sky, cam.proj, cam.view);
-
- // world
- ddraw_grid(0);
- ddraw_flush();
-
- // models
- compose44(girl.pivot, girl_p, eulerq(girl_r), girl_s);
- model_render(girl, cam.proj, cam.view, girl.pivot, 0);
-
- compose44(witch.pivot, witch_p, eulerq(witch_r), witch_s);
- model_render(witch, cam.proj, cam.view, witch.pivot, 0);
-
- // render end (postfx)
- fx_end();
-
- // input controllers
-
- double GAME_JUMP_DOWN = input_down(KEY_Z);
- double GAME_FIRE_DOWN = input_down(KEY_X);
- double GAME_JUMP = input(KEY_Z);
- double GAME_FIRE = input(KEY_X);
- double GAME_LEFT = input(KEY_J);
- double GAME_RIGHT = input(KEY_L);
- double GAME_UP = input(KEY_I);
- double GAME_DOWN = input(KEY_K);
- double GAME_AXISX = input(KEY_L) - input(KEY_J);
- double GAME_AXISY = input(KEY_I) - input(KEY_K);
-
- if( !input_anykey() ) {
- if( input(GAMEPAD_CONNECTED) ) {
- vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f /*15% deadzone*/);
- GAME_JUMP_DOWN = input_down(GAMEPAD_A);
- GAME_FIRE_DOWN = input_down(GAMEPAD_B) || input_down(GAMEPAD_X) || input_down(GAMEPAD_Y);
- GAME_JUMP = input(GAMEPAD_A);
- GAME_FIRE = input(GAMEPAD_B) || input(GAMEPAD_X) || input(GAMEPAD_Y);
- GAME_AXISX = filtered_lpad.x;
- GAME_AXISY = filtered_lpad.y;
- }
- }
-
- // animation controllers
-
- profile("Game.Animate scene") if( !window_has_pause() ) {
- float delta = window_delta() * 30; // 30fps anim
-
- // animate girl
- girl.curframe = model_animate(girl, girl.curframe + delta);
-
- // jump controller: jump duration=1.5s, jump height=6 units, anims (expo->circ)
- float jump_delta = 1.0;
- static double jump_timer = 0, jump_ss = 1.5, jump_h = 6;
- if( GAME_JUMP_DOWN ) if( jump_timer == 0 ) jump_timer = time_ss();
- jump_delta = clampf(time_ss() - jump_timer, 0, jump_ss) * (1.0/jump_ss);
- if( jump_delta >= 1 ) { jump_timer = 0; }
- float y = ease_ping_pong( jump_delta, EASE_OUT|EASE_EXPO, EASE_OUT|EASE_CIRC);
- girl_p.y = y * jump_h;
-
- // punch controller
- float punch_delta = 1;
- if( jump_delta >= 1 ) {
- static vec3 origin;
- static double punch_timer = 0, punch_ss = 0.5;
- if( GAME_FIRE_DOWN ) if( punch_timer == 0 ) punch_timer = time_ss(), origin = girl_p;
- punch_delta = clampf(time_ss() - punch_timer, 0, punch_ss) * (1.0/punch_ss);
- if( punch_delta >= 1 ) { punch_timer = 0; }
- else {
- float x = ease_out_expo( punch_delta );
- vec3 fwd = rotate3q(vec3(0,0,1), eulerq(vec3(girl_r.x - 170,girl_r.y,girl_r.z)));
- vec3 mix = mix3(girl_p, add3(origin,scale3(fwd,x*2)), x);
- girl_p.x = mix.x, girl_p.z = mix.z;
- }
- }
-
- int modern_controller = 1;
- int running = 0;
-
- // girl controller
-
- // locomotion vars
- float speed = 0.2f * delta;
- float yaw_boost = GAME_AXISY > 0 ? 1.0 : 1.75;
- if(punch_delta < 1) yaw_boost = 0.0; // if firing...
- else if(punch_delta <= 0.1) yaw_boost = 4.0; // unless initial punch chaining, extra yaw
-
- // old fashioned locomotion controller (boat controller)
- if(!modern_controller) {
- running = GAME_AXISY > 0;
-
- girl_r.x -= 170;
- quat q = eulerq(girl_r); // += custom.pivot
- vec3 rgt = rotate3q(vec3(1,0,0), q);
- vec3 up = rotate3q(vec3(0,1,0), q);
- vec3 fwd = rotate3q(vec3(0,0,1), q);
- vec3 dir = scale3(fwd, speed * GAME_AXISY * (GAME_AXISY > 0 ? 2.0 : 0.5));
- girl_r.x += speed * 20.0 * yaw_boost * GAME_AXISX; // yaw
- girl_p = add3(girl_p, dir);
- girl_r.x += 170;
- }
-
- // modern locomotion controller (mario 3d)
- if(modern_controller) {
- running = GAME_AXISX != 0 || GAME_AXISY != 0;
-
- camera_t *cam = camera_get_active();
- vec3 fwd = sub3(girl_p, cam->position); fwd.y = 0; fwd = norm3(fwd);
- vec3 rgt = norm3(cross3(fwd, vec3(0,1,0)));
-
- // target
- vec3 dir = add3(
- scale3(fwd, GAME_AXISY),
- scale3(rgt, GAME_AXISX)
- ); dir.y = 0; dir = norm3(dir);
-
- // smoothing
- static vec3 olddir; do_once olddir = dir;
- dir = mix3(dir, olddir, 1 - (yaw_boost / 4.0) * 0.85);
- olddir = dir;
-
- // vis
- // ddraw_arrow(girl_p, add3(girl_p,scale3(dir,10)));
-
- // apply direction
- girl_p = add3(girl_p, scale3(dir, speed * 2));
-
- // apply rotation
- {
- girl_r.x -= 170;
- quat q = eulerq(girl_r);
- vec3 fwdg = rotate3q(vec3(0,0,1), q);
- girl_r.x += 170;
-
- //float cosAngle = dot3(dir,fwdg);
- //float angle = acos(cosAngle) * TO_DEG;
- float angle = TO_DEG * ( atan2(fwdg.z, fwdg.x) - atan2(dir.z, dir.x));
-
- if( !isnan(angle) ) {
- girl_r.x -= angle;
- while(girl_r.x> 180) girl_r.x-=360;
- while(girl_r.x<-180) girl_r.x+=360;
- }
- }
- }
-
- // anim loops
- if( jump_delta < 1 ) { // jump/kick anim
-#if 0
- girl.curframe = clampf(girl.curframe, 184, 202);
- if( girl.curframe > 202-4 && GAME_FIRE_DOWN ) girl.curframe = 184+4;
-#else
- #define loopf(frame, min, max) (frame < min ? min : frame > max ? min + frame - max : frame)
- if(girl.curframe >= 203)
- girl.curframe = loopf(girl.curframe, 203, 220);
- else
- girl.curframe = clampf(girl.curframe, 184, 202);
- if( girl.curframe > 202-4 && girl.curframe < 208 && GAME_FIRE_DOWN ) girl.curframe = 203;
-#endif
- }
- else if( punch_delta < 1 ) { // punch anim
- girl.curframe = clampf(girl.curframe, 90, 101);
- if( girl.curframe > 101-6 && GAME_FIRE_DOWN ) girl.curframe = 101-6;
- }
- else if( running ) {
- // loop running anim
- if( girl.curframe < 65 ) girl.curframe = 65;
- if( girl.curframe > 85 ) girl.curframe = 65;
- }
- else { // loop idle anim
- if( girl.curframe > 59 ) girl.curframe = 0;
- }
- }
-
- // Game collisions
-
- profile("Game.collisions") {
- bool punching = girl.curframe >= 90 && girl.curframe < 101;
- bool air_kicking = girl.curframe >= 184 && girl.curframe < 202;
- bool jump_kicking = girl.curframe >= 203 && girl.curframe < 220;
- bool attacking = punching || air_kicking || jump_kicking;
-
- if( attacking ) {
- aabb boxg = model_aabb(girl, girl_pivot);
- aabb boxw = model_aabb(witch, witch_pivot);
-#if 0 // halve aabb. ok
- {
- vec3 diag = sub3(boxg.max, boxg.min);
- vec3 halve = scale3(diag, 0.25);
- vec3 center = scale3(add3(boxg.min, boxg.max), 0.5);
- boxg.min = sub3(center, halve);
- boxg.max = add3(center, halve);
- }
-#endif
- hit* h = aabb_hit_aabb(boxg, boxw);
- if( h && GAME_FIRE ) {
- vec3 dir = norm3(sub3(witch_p, girl_p));
- witch_p = add3(witch_p, mul3(dir,vec3(1,0,1)));
- }
- }
- }
-
- // ui
- if( ui_panel("Input", 0) ) { // @todo: showcase input binding
- ui_section("Controllers");
- ui_label("Gamepad #1");
- ui_label("Keys I/J/K/L + Z/X");
- ui_panel_end();
- }
- }
-}
-
-// 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);
-// float do_gamepad_deadzone = 0.15f;//
-//
-// 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)) {}//
diff --git a/demos/99-nodes.c b/demos/99-nodes.c
deleted file mode 100644
index 0e3c094..0000000
--- a/demos/99-nodes.c
+++ /dev/null
@@ -1,877 +0,0 @@
-#define V4K_IMPLEMENTATION
-#include "joint/v4k.h"
-
-/*
-A basic node-based UI built with Nuklear.
-Builds on the node editor example included in Nuklear v1.00, with the aim of
-being used as a prototype for implementing a functioning node editor.
-
-Features:
-- Nodes of different types. Currently their implementations are #included in
- the main file, but they could easily be turned into eg. a plugin system.
-- Pins/pins of different types -- currently float values and colors.
-- Adding and removing nodes.
-- Linking nodes, with validation (one link per input, only link similar pins).
-- Detaching and moving links.
-- Evaluation of output values of connected nodes.
-- Memory management based on fixed size arrays for links and node pointers
-- Multiple node types
-- Multiple pin types
-- Linking between pins of the same type
-- Detaching and reattaching links
-- Getting value from linked node if pin is connected
-
-Todo:
-- Complete pin types.
-- Allow dragging from output to input pin.
-- Cut link by CTRL+clicking input pin.
-- Cut link by drawing intersect line on a link.
-- Group elemnts together with mouse, or LSHIFT+clicking.
-- Drag groups.
-- DEL elements.
-- DEL groups.
-- CTRL-C/CTRL-V/CTRL-X elements.
-- CTRL-C/CTRL-V/CTRL-X groups.
-- CTRL-Z,CTRL-Y.
-- CTRL-N.
-- CTRL-L,CTRL-S.
-- CTRL-F.
-- CTRL-Wheel Zooming.
-- Allow to extend node types from Lua.
-
-Extra todo:
-- Execution Flow (see: nk_stroke_triangle, nk_fill_triangle)
-- Complete missing nodes (see: nk_draw_image, nk_draw_text)
-- Right-click could visualize node/board diagram as Lua script.
-- Once that done, copy/pasting scripts should work within editor.
-
-Sources:
-- https://github.com/Immediate-Mode-UI/Nuklear/pull/561
-- https://github.com/vurtun/nuklear/blob/master/demo/node_editor.c
-*/
-
-typedef enum pin_type_t {
- type_flow,
- type_int,type_float,
- type_block,type_texture,type_image,
- type_color,
- /*
- type_bool,
- type_char, type_string,
- type_int2, type_int3, type_int4,
- type_float2, type_float3, type_float4,
- type_array, type_map,
- */
-
- type_total
-} pin_type_t;
-
-struct node_pin {
- pin_type_t pin_type;
- nk_bool is_connected;
- struct node* connected_node;
- int connected_pin;
-};
-
-struct node {
- int ID;
- char name[32];
- struct nk_rect bounds;
- int input_count;
- int output_count;
- struct node_pin *inputs;
- struct node_pin *outputs;
- struct {
- float in_padding_x;
- float in_padding_y;
- float in_spacing_y;
- float out_padding_x;
- float out_padding_y;
- float out_spacing_y;
- } pin_spacing; /* Maybe this should be called "node_layout" and include the bounds? */
- struct node *next; /* Z ordering only */
- struct node *prev; /* Z ordering only */
-
- void* (*eval_func)(struct node*, int oIndex);
- void (*display_func)(struct nk_context*, struct node*);
-};
-
-struct node_link {
- struct node* input_node;
- int input_pin;
- struct node* output_node;
- int output_pin;
- nk_bool is_active;
-};
-
-struct node_linking {
- int active;
- struct node *node;
- int input_id;
- int input_pin;
-};
-
-struct node_editor {
- int initialized;
- struct node *node_buf[32];
- struct node_link links[64];
- struct node *output_node;
- struct node *begin;
- struct node *end;
- int node_count;
- int link_count;
- struct nk_rect bounds;
- struct node *selected;
- int show_grid;
- struct nk_vec2 scrolling;
- struct node_linking linking;
-};
-
-/* === PROTOTYPES === */
-/* The node implementations need these two functions. */
-/* These could/should go in a header file along with the node and node_pin structs and be #included in the node implementations */
-
-struct node* node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, int in_count, int out_count);
-void* node_editor_eval_connected(struct node *node, int input_pin_number);
-/* ================== */
-
-/* === NODE TYPE IMPLEMENTATIONS === */
-
-#define NODE_DEFAULT_ROW_HEIGHT 25
-
-
-// ----------------------------------------------------------------------------------------------------
-// #include "node_output.h"
-
-struct node_type_output {
- struct node node;
- struct nk_colorf input_val;
-};
-
-struct nk_colorf *node_output_get(struct node* node) {
- struct node_type_output *output_node = (struct node_type_output*)node;
- if (!node->inputs[0].is_connected) {
- struct nk_colorf black = {0.0f, 0.0f, 0.0f, 0.0f};
- output_node->input_val = black;
- }
- return &output_node->input_val;
-}
-
-static void node_output_display(struct nk_context *ctx, struct node *node) {
- if (node->inputs[0].is_connected) {
- struct node_type_output *output_node = (struct node_type_output*)node;
- output_node->input_val = *(struct nk_colorf*)node_editor_eval_connected(node, 0);
- nk_layout_row_dynamic(ctx, 60, 1);
- nk_button_color(ctx, nk_rgba_cf(output_node->input_val));
- }
-}
-
-struct node* node_output_create(struct node_editor *editor, struct nk_vec2 position) {
- struct node_type_output *output_node = (struct node_type_output*)node_editor_add(editor, sizeof(struct node_type_output), "Output", nk_rect(position.x, position.y, 100, 100), 1, 0);
- if (output_node){
- output_node->node.inputs[0].pin_type = type_color;
- output_node->node.display_func = node_output_display;
- }
- return (struct node*)output_node;
-}
-
-// ----------------------------------------------------------------------------------------------------
-// #include "node_float.h"
-
-struct node_type_float {
- struct node node;
- float output_val;
-};
-
-static float *node_float_eval(struct node* node, int oIndex) {
- struct node_type_float *float_node = (struct node_type_float*)node;
- NK_ASSERT(oIndex == 0);
- return &float_node->output_val;
-}
-
-static void node_float_draw(struct nk_context *ctx, struct node *node) {
- struct node_type_float *float_node = (struct node_type_float*)node;
- nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
- float_node->output_val = nk_propertyf(ctx, "#Value:", 0.0f, float_node->output_val, 1.0f, 0.01f, 0.01f);
-}
-
-void node_float_create(struct node_editor *editor, struct nk_vec2 position) {
- struct node_type_float *float_node = (struct node_type_float*)node_editor_add(editor, sizeof(struct node_type_float), "Float", nk_rect(position.x, position.y, 180, 75), 0, 1);
- if (float_node)
- {
- float_node->output_val = 1.0f;
- float_node->node.display_func = node_float_draw;
- float_node->node.eval_func = (void*(*)(struct node*, int)) node_float_eval;
- }
-}
-
-// ----------------------------------------------------------------------------------------------------
-// #include "node_color.h"
-
-struct node_type_color {
- struct node node;
- float input_val[4];
- struct nk_colorf output_val;
-};
-
-static struct nk_colorf *node_color_eval(struct node* node, int oIndex)
-{
- struct node_type_color *color_node = (struct node_type_color*)node;
- NK_ASSERT(oIndex == 0); /* only one output connector */
-
- return &color_node->output_val;
-}
-
-
-static void node_color_draw(struct nk_context *ctx, struct node *node)
-{
- struct node_type_color *color_node = (struct node_type_color*)node;
- float eval_result; /* Get the values from connected nodes into this so the inputs revert on disconnect */
- const char* labels[4] = {"#R:","#G:","#B:","#A:"};
- float color_val[4]; /* Because we can't just loop through the struct... */
- nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
- nk_button_color(ctx, nk_rgba_cf(color_node->output_val));
-
- for (int i = 0; i < 4; i++)
- {
- if (color_node->node.inputs[i].is_connected) {
- eval_result = *(float*)node_editor_eval_connected(node, i);
- eval_result = nk_propertyf(ctx, labels[i], eval_result, eval_result, eval_result, 0.01f, 0.01f);
- color_val[i] = eval_result;
- }
- else {
- color_node->input_val[i] = nk_propertyf(ctx, labels[i], 0.0f, color_node->input_val[i], 1.0f, 0.01f, 0.01f);
- color_val[i] = color_node->input_val[i];
- }
- }
-
- color_node->output_val.r = color_val[0];
- color_node->output_val.g = color_val[1];
- color_node->output_val.b = color_val[2];
- color_node->output_val.a = color_val[3];
-}
-
-void node_color_create(struct node_editor *editor, struct nk_vec2 position)
-{
- struct node_type_color *color_node = (struct node_type_color*)node_editor_add(editor, sizeof(struct node_type_color), "Color", nk_rect(position.x, position.y, 180, 190), 4, 1);
- if (color_node)
- {
- const struct nk_colorf black = {0.0f, 0.0f, 0.0f, 1.0f};
-
- for (int i = 0; i < color_node->node.input_count; i++)
- color_node->node.inputs[i].pin_type = type_float;
- color_node->node.outputs[0].pin_type = type_color;
-
- color_node->node.pin_spacing.in_padding_y += NODE_DEFAULT_ROW_HEIGHT;
-
- color_node->input_val[0] = 0.0f;
- color_node->input_val[1] = 0.0f;
- color_node->input_val[2] = 0.0f;
- color_node->input_val[3] = 1.0f;
-
- color_node->output_val = black;
-
- color_node->node.display_func = node_color_draw;
- color_node->node.eval_func = (void*(*)(struct node*, int)) node_color_eval;
- }
-}
-
-// ----------------------------------------------------------------------------------------------------
-// #include "node_blend.h"
-
-struct node_type_blend {
- struct node node;
- struct nk_colorf input_val[2];
- struct nk_colorf output_val;
- float blend_val;
-};
-
-static struct nk_colorf *node_blend_eval(struct node *node, int oIndex) {
- struct node_type_blend* blend_node = (struct node_type_blend*)node;
- return &blend_node->output_val;
-}
-
-static void node_blend_display(struct nk_context *ctx, struct node *node) {
- struct node_type_blend *blend_node = (struct node_type_blend*)node;
- const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
- float blend_amnt;
-
- nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
- for (int i = 0; i < 2; i++){
- if(node->inputs[i].is_connected) {
- blend_node->input_val[i] = *(struct nk_colorf*)node_editor_eval_connected(node, i);
- }
- else {
- blend_node->input_val[i] = blank;
- }
- nk_button_color(ctx, nk_rgba_cf(blend_node->input_val[i]));
- }
-
- if (node->inputs[2].is_connected) {
- blend_amnt = *(float*)node_editor_eval_connected(node, 2);
- blend_amnt = nk_propertyf(ctx, "#Blend", blend_amnt, blend_amnt, blend_amnt, 0.01f, 0.01f);
- }
- else {
- blend_node->blend_val = nk_propertyf(ctx, "#Blend", 0.0f, blend_node->blend_val, 1.0f, 0.01f, 0.01f);
- blend_amnt = blend_node->blend_val;
- }
-
-
- if(node->inputs[0].is_connected && node->inputs[1].is_connected) {
- blend_node->output_val.r = blend_node->input_val[0].r * (1.0f-blend_amnt) + blend_node->input_val[1].r * blend_amnt;
- blend_node->output_val.g = blend_node->input_val[0].g * (1.0f-blend_amnt) + blend_node->input_val[1].g * blend_amnt;
- blend_node->output_val.b = blend_node->input_val[0].b * (1.0f-blend_amnt) + blend_node->input_val[1].b * blend_amnt;
- blend_node->output_val.a = blend_node->input_val[0].a * (1.0f-blend_amnt) + blend_node->input_val[1].a * blend_amnt;
- }
- else {
- blend_node->output_val = blank;
- }
-}
-
-void node_blend_create(struct node_editor *editor, struct nk_vec2 position) {
- struct node_type_blend* blend_node = (struct node_type_blend*)node_editor_add(editor, sizeof(struct node_type_blend), "Blend", nk_rect(position.x, position.y, 180, 130), 3, 1);
- if (blend_node) {
- const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
- for (int i = 0; i < (int)NK_LEN(blend_node->input_val); i++)
- blend_node->node.inputs[i].pin_type = type_color;
- blend_node->node.outputs[0].pin_type = type_color;
-
- // blend_node->node.pin_spacing.in_padding_y = 42.0f;
- // blend_node->node.pin_spacing.in_spacing_y = 29.0f;
-
- for (int i = 0; i < (int)NK_LEN(blend_node->input_val); i++)
- blend_node->input_val[i] = blank;
- blend_node->output_val = blank;
-
- blend_node->blend_val = 0.5f;
-
- blend_node->node.display_func = node_blend_display;
- blend_node->node.eval_func = (void*(*)(struct node*, int)) node_blend_eval;
-
- }
-}
-
-/* ================================= */
-
-#define NK_RGB3(r,g,b) {r,g,b,255}
-#define BG_COLOR ((struct nk_color){60,60,60,192}) // nk_rgba(0,0,0,192)
-
-static
-struct editor_node_style {
- int pin_type;
- const char *shape;
- struct nk_color color_idle;
- struct nk_color color_hover;
-} styles[] = {
- // order matters:
- { type_flow, "triangle_right", NK_RGB3(200,200,200), NK_RGB3(255,255,255) }, // if .num_links == 0
- { type_int, "circle", NK_RGB3(33,227,175), NK_RGB3(135,239,195) },
- { type_float, "circle", NK_RGB3(156,253,65), NK_RGB3(144,225,137) },
- { type_block, "circle", NK_RGB3(6,165,239), NK_RGB3(137,196,247) },
- { type_texture, "circle", NK_RGB3(148,0,0), NK_RGB3(183,137,137) },
- { type_image, "circle", NK_RGB3(200,130,255), NK_RGB3(220,170,255) },
- { type_color, "circle", NK_RGB3(252,200,35), NK_RGB3(255,217,140) },
-};
-
-#define COLOR_FLOW_HI styles[type_flow].color_hover
-#define COLOR_FLOW_LO styles[type_flow].color_idle
-
-#define GRID_SIZE 64.0f
-#define GRID_COLOR ((struct nk_color)NK_RGB3(80,80,120))
-#define GRID_THICKNESS 1.0f
-
-// 4 colors: top-left, top-right, bottom-right, bottom-left
-#define GRID_BG_COLORS ((struct nk_color){30,30,30,255}), ((struct nk_color){40,20,0,255}), ((struct nk_color){30,30,30,255}), ((struct nk_color){20,30,40,255})
-
-#define LINK_THICKNESS 1.0f
-#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
- vec2 a = (POINT_A); \
- vec2 b = (POINT_B); \
- nk_stroke_line(canvas, a.x, a.y, b.x, b.y, LINK_THICKNESS, COLOR); \
-} while(0)
-#undef LINK_DRAW
-#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
- vec2 a = (POINT_A); \
- vec2 b = (POINT_B); \
- nk_stroke_curve(canvas, a.x, a.y, a.x+50, a.y, b.x-50, b.y, b.x, b.y, LINK_THICKNESS, COLOR); \
-} while(0)
-#undef LINK_DRAW
-#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
- vec2 a = (POINT_A); \
- vec2 b = (POINT_B); \
- float dist2 = len2( sub2( ptr2(&b.x), ptr2(&a.x) ) ); \
- vec2 mid_a = mix2( ptr2(&a.x), ptr2(&b.x), 0.25 ); mid_a.y += dist2/2; \
- vec2 mid_b = mix2( ptr2(&a.x), ptr2(&b.x), 0.75 ); mid_b.y += dist2/3; \
- nk_stroke_curve(canvas, a.x, a.y, mid_a.x, mid_a.y, mid_b.x, mid_b.y, b.x, b.y, LINK_THICKNESS, COLOR); \
-} while(0)
-
-
-#define PIN_RADIUS 12
-#define PIN_THICKNESS 1.0f
-#define PIN_DRAW(PIN_ADDR,POINT,RADIUS) do { \
- circle.x = (POINT).x - (RADIUS) / 2; \
- circle.y = (POINT).y - (RADIUS) / 2; \
- circle.w = circle.h = (RADIUS); \
- struct nk_color color = node_get_type_color((PIN_ADDR).pin_type); \
- if((PIN_ADDR).is_connected) \
- nk_fill_circle(canvas, circle, color); \
- else \
- nk_stroke_circle(canvas, circle, PIN_THICKNESS, color); \
-} while(0)
-
-
-static struct nk_color node_get_type_color(unsigned pin_type) {
- for( int i = 0; i < type_total; ++i )
- if( styles[i].pin_type == pin_type )
- return styles[i].color_idle;
- return ((struct nk_color)NK_RGB3(255,0,255));
-}
-
-static void node_editor_push(struct node_editor *editor, struct node *node) {
- if (!editor->begin) {
- node->next = NULL;
- node->prev = NULL;
- editor->begin = node;
- editor->end = node;
- } else {
- node->prev = editor->end;
- if (editor->end)
- editor->end->next = node;
- node->next = NULL;
- editor->end = node;
- }
-}
-
-static void node_editor_pop(struct node_editor *editor, struct node *node) {
- if (node->next)
- node->next->prev = node->prev;
- if (node->prev)
- node->prev->next = node->next;
- if (editor->end == node)
- editor->end = node->prev;
- if (editor->begin == node)
- editor->begin = node->next;
- node->next = NULL;
- node->prev = NULL;
-}
-
-static struct node* node_editor_find_by_id(struct node_editor *editor, int ID) {
- struct node *iter = editor->begin;
- while (iter) {
- if (iter->ID == ID)
- return iter;
- iter = iter->next;
- }
- return NULL;
-}
-
-static struct node_link* node_editor_find_link_by_output(struct node_editor *editor, struct node *output_node, int node_input_connector) {
- for( int i = 0; i < editor->link_count; i++ ) {
- if (editor->links[i].output_node == output_node &&
- editor->links[i].output_pin == node_input_connector &&
- editor->links[i].is_active == nk_true) {
- return &editor->links[i];
- }
- }
- return NULL;
-}
-
-static struct node_link* node_editor_find_link_by_input(struct node_editor *editor, struct node *input_node, int node_output_connector) {
- for( int i = 0; i < editor->link_count; i++ ) {
- if (editor->links[i].input_node == input_node &&
- editor->links[i].input_pin == node_output_connector &&
- editor->links[i].is_active == nk_true) {
- return &editor->links[i];
- }
- }
- return NULL;
-}
-
-static void node_editor_delete_link(struct node_link *link) {
- link->is_active = nk_false;
- link->input_node->outputs[link->input_pin].is_connected = nk_false;
- link->output_node->inputs[link->output_pin].is_connected = nk_false;
-}
-
-struct node* node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, int in_count, int out_count) {
- static int IDs = 0;
- struct node *node = NULL;
-
- if ((nk_size)editor->node_count < NK_LEN(editor->node_buf)) {
- /* node_buf has unused pins */
- node = MALLOC(nodeSize);
- editor->node_buf[editor->node_count++] = node;
- node->ID = IDs++;
- } else {
- /* check for freed up pins in node_buf */
- for (int i = 0; i < editor->node_count; i++) {
- if (editor->node_buf[i] == NULL) {
- node = MALLOC(nodeSize);
- editor->node_buf[i] = node;
- node->ID = i;
- break;
- }
- }
- }
- if (node == NULL) {
- puts("Node creation failed");
- return NULL;
- }
-
- node->bounds = bounds;
-
- node->input_count = in_count;
- node->output_count = out_count;
-
- node->inputs = MALLOC(node->input_count * sizeof(struct node_pin));
- node->outputs = MALLOC(node->output_count * sizeof(struct node_pin));
-
- for (int i = 0; i < node->input_count; i++) {
- node->inputs[i].is_connected = nk_false;
- node->inputs[i].pin_type = type_float; /* default pin type */
- }
- for (int i = 0; i < node->output_count; i++) {
- node->outputs[i].is_connected = nk_false;
- node->outputs[i].pin_type = type_float; /* default pin type */
- }
-
- /* default pin spacing */
- node->pin_spacing.in_padding_x = 2;
- node->pin_spacing.in_padding_y = 32 + 25/2 + 6; // titlebar height + next half row + adjust
- node->pin_spacing.in_spacing_y = 25; // row height+border
- node->pin_spacing.out_padding_x = 3;
- node->pin_spacing.out_padding_y = 32 + 25/2 + 6; // titlebar height + next half row + adjust
- node->pin_spacing.out_spacing_y = 25; // row height+border
-
- strcpy(node->name, name);
- node_editor_push(editor, node);
-
- return node;
-}
-
-void *node_editor_eval_connected(struct node* node, int input_pin_number) {
- NK_ASSERT(node->inputs[input_pin_number].is_connected);
- return node->inputs[input_pin_number].connected_node->eval_func(node->inputs[input_pin_number].connected_node, node->inputs[input_pin_number].connected_pin);
-}
-
-static void node_editor_link(struct node_editor *editor, struct node *in_node, int in_pin, struct node *out_node, int out_pin) {
- /* Confusingly, in and out nodes/pins here refer to the inputs and outputs OF THE LINK ITSELF, not the nodes */
- struct node_link *link = NULL;
-
- if ((nk_size)editor->link_count < NK_LEN(editor->links)) {
- link = &editor->links[editor->link_count++];
- } else {
- for (int i = 0; i < (int)NK_LEN(editor->links); i++)
- {
- if (editor->links[i].is_active == nk_false) {
- link = &editor->links[i];
- break;
- }
- }
- }
- if (link) {
- out_node->inputs[out_pin].is_connected = nk_true;
- in_node->outputs[in_pin].is_connected = nk_true;
- out_node->inputs[out_pin].connected_node = in_node;
- out_node->inputs[out_pin].connected_pin = in_pin;
-
- link->input_node = in_node;
- link->input_pin = in_pin;
- link->output_node = out_node;
- link->output_pin = out_pin;
- link->is_active = nk_true;
- } else {
- puts("Too many links");
- }
-}
-
-static void node_editor_init(struct node_editor *editor) {
- if (editor->initialized) return;
-
- struct nk_rect total_space = nk_window_get_content_region(ui_ctx);
- struct nk_vec2 output_node_position = { total_space.w*2/3, total_space.h/3 };
- struct nk_vec2 color_node_position = { total_space.w*1/4, total_space.h/3 };
-
- memset(editor, 0, sizeof(*editor));
-
- editor->output_node = node_output_create(editor, output_node_position);
- node_color_create(editor, color_node_position);
- editor->show_grid = nk_true;
-
- editor->initialized = 1;
-}
-
-static int node_editor(struct node_editor *editor) {
- int n = 0;
- struct nk_rect total_space;
- const struct nk_input *in = &ui_ctx->input;
- struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
- struct node *updated = 0;
-
- node_editor_init(editor);
-
- {
- /* allocate complete window space */
- total_space = nk_window_get_content_region(ui_ctx);
- nk_layout_space_begin(ui_ctx, NK_STATIC, total_space.h, editor->node_count);
- {
- struct node *it = editor->begin;
- struct nk_rect size = nk_layout_space_bounds(ui_ctx);
- struct nk_panel *nodePanel = 0;
-
- //nk_fill_rect(canvas, size, 0/*rounding*/, ((struct nk_color){30,30,30,255})); // 20,30,40,255
- nk_fill_rect_multi_color(canvas, size, GRID_BG_COLORS);
-
- if (editor->show_grid) {
- /* display grid */
- for (float x = (float)fmod(size.x - editor->scrolling.x, GRID_SIZE); x < size.w; x += GRID_SIZE)
- nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, GRID_THICKNESS, GRID_COLOR);
- for (float y = (float)fmod(size.y - editor->scrolling.y, GRID_SIZE); y < size.h; y += GRID_SIZE)
- nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, GRID_THICKNESS, GRID_COLOR);
- }
-
- /* execute each node as a movable group */
- /* loop through nodes */
- while (it) {
- /* Output node window should not have a close button */
- nk_flags nodePanel_flags = NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE;
- if (it != editor->output_node)
- nodePanel_flags |= NK_WINDOW_CLOSABLE;
-
- /* calculate scrolled node window position and size */
- nk_layout_space_push(ui_ctx, nk_rect(it->bounds.x - editor->scrolling.x,
- it->bounds.y - editor->scrolling.y, it->bounds.w, it->bounds.h));
-
- /* execute node window */
- char *name = va(" " ICON_MD_MENU " %s",it->name); //< @r-lyeh added some spacing+icon because of our UI customizations
-
-struct nk_color bak = ui_ctx->style.window.fixed_background.data.color;
-ui_ctx->style.window.fixed_background.data.color = BG_COLOR;
-
- if (nk_group_begin(ui_ctx, name, nodePanel_flags))
- {
- /* always have last selected node on top */
-
- nodePanel = nk_window_get_panel(ui_ctx);
- if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nodePanel->bounds) &&
- (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,
- nk_layout_space_rect_to_screen(ui_ctx, nodePanel->bounds)))) &&
- editor->end != it)
- {
- updated = it;
- }
-
- if ((nodePanel->flags & NK_WINDOW_HIDDEN)) /* Node close button has been clicked */
- {
- /* Delete node */
- struct node_link *link_remove;
- node_editor_pop(editor, it);
- for (int n = 0; n < it->input_count; n++) {
- if ((link_remove = node_editor_find_link_by_output(editor, it, n)))
- {
- node_editor_delete_link(link_remove);
- }
- }
- for (int n = 0; n < it -> output_count; n++) {
- while((link_remove = node_editor_find_link_by_input(editor, it, n)))
- {
- node_editor_delete_link(link_remove);
- }
- }
- NK_ASSERT(editor->node_buf[it->ID] == it);
- editor->node_buf[it->ID] = NULL;
- FREE(it->inputs);
- FREE(it->outputs);
- FREE(it);
- }
- else {
-
- /* ================= NODE CONTENT ===================== */
-
- it->display_func(ui_ctx, it);
-
- /* ==================================================== */
-
- }
- nk_group_end(ui_ctx);
-
- }
-
-ui_ctx->style.window.fixed_background.data.color = bak;
-
- if (!(nodePanel->flags & NK_WINDOW_HIDDEN))
- {
- /* node pin and linking */
- struct nk_rect bounds;
- bounds = nk_layout_space_rect_to_local(ui_ctx, nodePanel->bounds);
- bounds.x += editor->scrolling.x;
- bounds.y += editor->scrolling.y;
- it->bounds = bounds;
-
- /* output pins */
- for (int n = 0; n < it->output_count; ++n) {
- struct nk_rect circle;
- struct nk_vec2 pt = {nodePanel->bounds.x, nodePanel->bounds.y};
- pt.x += nodePanel->bounds.w - PIN_RADIUS / 2 + it->pin_spacing.out_padding_x;
- pt.y += it->pin_spacing.out_padding_y + it->pin_spacing.out_spacing_y * (n);
- PIN_DRAW(it->outputs[n],pt,PIN_RADIUS);
-
- /* start linking process */
- /* set linking active */
- if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
- editor->linking.active = nk_true;
- editor->linking.node = it;
- editor->linking.input_id = it->ID;
- editor->linking.input_pin = n;
- }
-
- /* draw link being dragged (from linked pin to mouse position) */
- if (editor->linking.active && editor->linking.node == it &&
- editor->linking.input_pin == n) {
- LINK_DRAW(vec2(circle.x+3,circle.y+3),ptr2(&in->mouse.pos.x),COLOR_FLOW_HI);
- }
- }
-
- /* input pins */
- for (int n = 0; n < it->input_count; ++n) {
- struct nk_rect circle;
- struct nk_vec2 pt = {nodePanel->bounds.x, nodePanel->bounds.y};
- pt.x += it->pin_spacing.in_padding_x;
- pt.y += it->pin_spacing.in_padding_y + it->pin_spacing.in_spacing_y * (n);
- PIN_DRAW(it->inputs[n],pt,PIN_RADIUS);
-
- /* Detach link */
- if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true) &&
- editor->linking.active == nk_false &&
- it->inputs[n].is_connected == nk_true) {
- struct node_link *node_relink = node_editor_find_link_by_output(editor, it, n);
- editor->linking.active = nk_true;
- editor->linking.node = node_relink->input_node;
- editor->linking.input_id = node_relink->input_node->ID;
- editor->linking.input_pin = node_relink->input_pin;
- node_editor_delete_link(node_relink);
- }
-
- /* Create link */
- if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
- nk_input_is_mouse_hovering_rect(in, circle) &&
- editor->linking.active &&
- editor->linking.node != it &&
- it->inputs[n].pin_type == editor->linking.node->outputs[editor->linking.input_pin].pin_type &&
- it->inputs[n].is_connected != nk_true) {
- editor->linking.active = nk_false;
-
- node_editor_link(editor, editor->linking.node,
- editor->linking.input_pin, it, n);
- }
- }
- }
- it = it->next;
- }
-
- /* reset (output) linking connection */
- if (editor->linking.active && (!!input(KEY_LCTRL) || !!input(KEY_RCTRL) || nk_input_is_mouse_released(in, NK_BUTTON_LEFT))) {
- editor->linking.active = nk_false;
- editor->linking.node = NULL;
- }
-
- /* draw each static link */
- for (int n = 0; n < editor->link_count; ++n) {
- struct node_link *link = &editor->links[n];
- if (link->is_active == nk_true){
- struct node *ni = link->input_node;
- struct node *no = link->output_node;
- struct nk_vec2 l0 = nk_layout_space_to_screen(ui_ctx, nk_vec2(ni->bounds.x + ni->bounds.w + ni->pin_spacing.out_padding_x, 3.0f + ni->bounds.y + ni->pin_spacing.out_padding_y + ni->pin_spacing.out_spacing_y * (link->input_pin)));
- struct nk_vec2 l1 = nk_layout_space_to_screen(ui_ctx, nk_vec2(no->bounds.x + no->pin_spacing.in_padding_x, 3.0f + no->bounds.y + no->pin_spacing.in_padding_y + no->pin_spacing.in_spacing_y * (link->output_pin)));
-
- l0.x -= editor->scrolling.x;
- l0.y -= editor->scrolling.y;
- l1.x -= editor->scrolling.x;
- l1.y -= editor->scrolling.y;
-
- struct nk_color color = node_get_type_color(no->inputs[link->output_pin].pin_type);
- LINK_DRAW(ptr2(&l0.x), ptr2(&l1.x), color);
- }
- }
-
- if (updated) {
- /* reshuffle nodes to have least recently selected node on top */
- node_editor_pop(editor, updated);
- node_editor_push(editor, updated);
- }
-
- /* node selection */
- if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ui_ctx))) {
- it = editor->begin;
- editor->selected = NULL;
- editor->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
- while (it) {
- struct nk_rect b = nk_layout_space_rect_to_screen(ui_ctx, it->bounds);
- b.x -= editor->scrolling.x;
- b.y -= editor->scrolling.y;
- if (nk_input_is_mouse_hovering_rect(in, b))
- editor->selected = it;
- it = it->next;
- }
- }
-
- /* contextual menu */
- if (nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 220), nk_window_get_bounds(ui_ctx))) {
- struct nk_vec2 wincoords = { in->mouse.pos.x-total_space.x-50, in->mouse.pos.y-total_space.y-32 };
-
-#if 1
- static char *filter = 0;
- static int do_filter = 0;
- if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
- int choice = ui_toolbar(ICON_MD_SEARCH ";");
- if( choice == 1 ) do_filter = 1;
- if( do_filter ) {
- ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter);
- if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
- do_filter = 0;
- }
- } else {
- if( filter ) filter[0] = '\0';
- }
- char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*";
-#endif
-
- #define ui_label_filtered(lbl) (strmatchi(lbl,filter_mask) && ui_label(lbl))
-
- int close = 0;
- if (ui_label_filtered("=Add Color node")) close=1,node_color_create(editor, wincoords);
- if (ui_label_filtered("=Add Float node")) close=1,node_float_create(editor, wincoords);
- if (ui_label_filtered("=Add Blend Node")) close=1,node_blend_create(editor, wincoords);
- if (ui_label_filtered(editor->show_grid ? "=Hide Grid" : "=Show Grid"))
- close=1,editor->show_grid = !editor->show_grid;
- if(close) do_filter = 0, (filter ? filter[0] = '\0' : '\0'), nk_contextual_close(ui_ctx);
- nk_contextual_end(ui_ctx);
- }
- }
- nk_layout_space_end(ui_ctx);
-
- /* window content scrolling */
- if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ui_ctx)) &&
- nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {
- editor->scrolling.x += in->mouse.delta.x;
- editor->scrolling.y += in->mouse.delta.y;
- }
- }
-
- return !nk_window_is_closed(ui_ctx, "NodeEdit");
-}
-
-
-
-
-int main() {
- static int open = 1;
- window_create(0.75, 0);
- while(window_swap() && open) {
- if( ui_window("Node editor",&open) ) {
- static struct node_editor nodeEditor = {0};
- node_editor(&nodeEditor);
- ui_window_end();
- }
- }
-}
diff --git a/demos/art/sprites/Treasure Hunters/Captain Clown Nose.ase b/demos/art/sprites/Treasure Hunters/Captain Clown Nose.ase
new file mode 100644
index 0000000..b4b6335
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Captain Clown Nose.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Crew-Crabby.ase b/demos/art/sprites/Treasure Hunters/Crew-Crabby.ase
new file mode 100644
index 0000000..dfd4cf8
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Crew-Crabby.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Crew-Fierce Tooth.ase b/demos/art/sprites/Treasure Hunters/Crew-Fierce Tooth.ase
new file mode 100644
index 0000000..7c5f11a
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Crew-Fierce Tooth.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Crew-Pink Start.ase b/demos/art/sprites/Treasure Hunters/Crew-Pink Start.ase
new file mode 100644
index 0000000..4f6e1ad
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Crew-Pink Start.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/FX1-Dust Particles.ase b/demos/art/sprites/Treasure Hunters/FX1-Dust Particles.ase
new file mode 100644
index 0000000..1bf9c3f
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/FX1-Dust Particles.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Chest.ase b/demos/art/sprites/Treasure Hunters/Props-Chest.ase
new file mode 100644
index 0000000..4a18738
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Chest.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Decorations.ase b/demos/art/sprites/Treasure Hunters/Props-Decorations.ase
new file mode 100644
index 0000000..cc12e94
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Decorations.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Flag.ase b/demos/art/sprites/Treasure Hunters/Props-Flag.ase
new file mode 100644
index 0000000..dd29052
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Flag.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Merchant Ship.ase b/demos/art/sprites/Treasure Hunters/Props-Merchant Ship.ase
new file mode 100644
index 0000000..2147b67
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Merchant Ship.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Palm Tree.ase b/demos/art/sprites/Treasure Hunters/Props-Palm Tree.ase
new file mode 100644
index 0000000..19e4452
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Palm Tree.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Pirate Treasure.ase b/demos/art/sprites/Treasure Hunters/Props-Pirate Treasure.ase
new file mode 100644
index 0000000..11b5e74
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Pirate Treasure.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Ship Helm.ase b/demos/art/sprites/Treasure Hunters/Props-Ship Helm.ase
new file mode 100644
index 0000000..693699c
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Ship Helm.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Shooter Traps.ase b/demos/art/sprites/Treasure Hunters/Props-Shooter Traps.ase
new file mode 100644
index 0000000..e5a22a0
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Shooter Traps.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-TileSets.ase b/demos/art/sprites/Treasure Hunters/Props-TileSets.ase
new file mode 100644
index 0000000..8a560d7
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-TileSets.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/Props-Water Reflect.ase b/demos/art/sprites/Treasure Hunters/Props-Water Reflect.ase
new file mode 100644
index 0000000..537cd5f
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/Props-Water Reflect.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/UI-Button Cooldown.ase b/demos/art/sprites/Treasure Hunters/UI-Button Cooldown.ase
new file mode 100644
index 0000000..07c1295
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/UI-Button Cooldown.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/UI-Dialogue.ase b/demos/art/sprites/Treasure Hunters/UI-Dialogue.ase
new file mode 100644
index 0000000..341aead
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/UI-Dialogue.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/UI-Wood and Paper.ase b/demos/art/sprites/Treasure Hunters/UI-Wood and Paper.ase
new file mode 100644
index 0000000..81b64db
Binary files /dev/null and b/demos/art/sprites/Treasure Hunters/UI-Wood and Paper.ase differ
diff --git a/demos/art/sprites/Treasure Hunters/_license b/demos/art/sprites/Treasure Hunters/_license
new file mode 100644
index 0000000..66abd7d
--- /dev/null
+++ b/demos/art/sprites/Treasure Hunters/_license
@@ -0,0 +1,123 @@
+https://pixelfrog-assets.itch.io/treasure-hunters
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
\ No newline at end of file
diff --git a/demos/art/sprites/spines/goblins.atlas b/demos/art/sprites/spines/goblins.atlas
new file mode 100644
index 0000000..e601faf
--- /dev/null
+++ b/demos/art/sprites/spines/goblins.atlas
@@ -0,0 +1,98 @@
+
+goblins.png
+ size: 1024, 128
+ filter: Linear, Linear
+ pma: true
+dagger
+ bounds: 2, 18, 26, 108
+goblin/eyes-closed
+ bounds: 2, 4, 34, 12
+goblin/head
+ bounds: 113, 23, 103, 66
+ rotate: 90
+goblin/left-arm
+ bounds: 937, 89, 37, 35
+ rotate: 90
+goblin/left-foot
+ bounds: 609, 61, 65, 31
+ rotate: 90
+goblin/left-hand
+ bounds: 840, 21, 36, 41
+goblin/left-lower-leg
+ bounds: 504, 56, 33, 70
+goblin/left-shoulder
+ bounds: 745, 17, 29, 44
+goblin/left-upper-leg
+ bounds: 397, 53, 33, 73
+goblin/neck
+ bounds: 862, 85, 36, 41
+goblin/pelvis
+ bounds: 776, 18, 62, 43
+goblin/right-arm
+ bounds: 181, 5, 23, 50
+ rotate: 90
+goblin/right-foot
+ bounds: 747, 63, 63, 33
+ rotate: 90
+goblin/right-hand
+ bounds: 878, 3, 36, 37
+goblin/right-lower-leg
+ bounds: 321, 50, 36, 76
+goblin/right-shoulder
+ bounds: 663, 14, 39, 45
+goblin/right-upper-leg
+ bounds: 675, 63, 34, 63
+goblin/torso
+ bounds: 181, 30, 68, 96
+goblin/undie-straps
+ bounds: 38, 2, 55, 19
+goblin/undies
+ bounds: 974, 97, 36, 29
+goblingirl/eyes-closed
+ bounds: 397, 30, 37, 21
+goblingirl/head
+ bounds: 30, 23, 103, 81
+ rotate: 90
+goblingirl/left-arm
+ bounds: 916, 8, 37, 35
+ rotate: 90
+goblingirl/left-foot
+ bounds: 642, 61, 65, 31
+ rotate: 90
+goblingirl/left-hand
+ bounds: 900, 86, 35, 40
+goblingirl/left-lower-leg
+ bounds: 539, 56, 33, 70
+goblingirl/left-shoulder
+ bounds: 633, 13, 28, 46
+goblingirl/left-upper-leg
+ bounds: 574, 56, 33, 70
+goblingirl/neck
+ bounds: 878, 42, 35, 41
+goblingirl/pelvis
+ bounds: 817, 64, 62, 43
+ rotate: 90
+goblingirl/right-arm
+ bounds: 603, 4, 28, 50
+goblingirl/right-foot
+ bounds: 782, 63, 63, 33
+ rotate: 90
+goblingirl/right-hand
+ bounds: 915, 47, 36, 37
+goblingirl/right-lower-leg
+ bounds: 359, 50, 36, 76
+goblingirl/right-shoulder
+ bounds: 704, 16, 39, 45
+goblingirl/right-upper-leg
+ bounds: 711, 63, 34, 63
+goblingirl/torso
+ bounds: 251, 30, 68, 96
+goblingirl/undie-straps
+ bounds: 95, 2, 55, 19
+goblingirl/undies
+ bounds: 974, 66, 36, 29
+shield
+ bounds: 432, 54, 70, 72
+spear
+ bounds: 233, 6, 22, 368
+ rotate: 90
\ No newline at end of file
diff --git a/demos/art/sprites/spines/goblins.json b/demos/art/sprites/spines/goblins.json
new file mode 100644
index 0000000..14d356e
--- /dev/null
+++ b/demos/art/sprites/spines/goblins.json
@@ -0,0 +1,627 @@
+{
+"skeleton": {
+ "hash": "djttFmlR6Co",
+ "spine": "4.1.17",
+ "x": -92.53,
+ "y": -5.3,
+ "width": 234.03,
+ "height": 354.91,
+ "images": "./images/",
+ "audio": ""
+},
+"bones": [
+ { "name": "root" },
+ { "name": "hip", "parent": "root", "x": 0.65, "y": 114.41, "color": "ffd300ff" },
+ {
+ "name": "torso",
+ "parent": "hip",
+ "length": 85.83,
+ "rotation": 93.93,
+ "x": -6.42,
+ "y": 1.98,
+ "color": "ffd300ff"
+ },
+ {
+ "name": "neck",
+ "parent": "torso",
+ "length": 18.38,
+ "rotation": -1.52,
+ "x": 81.68,
+ "y": -6.35,
+ "color": "ffd300ff"
+ },
+ {
+ "name": "head",
+ "parent": "neck",
+ "length": 68.29,
+ "rotation": -13.92,
+ "x": 20.94,
+ "y": 11.59,
+ "color": "ffd300ff"
+ },
+ {
+ "name": "left-shoulder",
+ "parent": "torso",
+ "length": 35.43,
+ "rotation": -156.96,
+ "x": 74.05,
+ "y": -20.39,
+ "color": "ff0000ff"
+ },
+ {
+ "name": "left-arm",
+ "parent": "left-shoulder",
+ "length": 35.62,
+ "rotation": 28.17,
+ "x": 37.86,
+ "y": -2.35,
+ "color": "ff0000ff"
+ },
+ {
+ "name": "left-upper-leg",
+ "parent": "hip",
+ "length": 50.4,
+ "rotation": -89.1,
+ "x": 14.45,
+ "y": 2.81,
+ "color": "ff0000ff"
+ },
+ {
+ "name": "left-lower-leg",
+ "parent": "left-upper-leg",
+ "length": 49.9,
+ "rotation": -16.66,
+ "x": 56.34,
+ "y": 0.99,
+ "color": "ff0000ff"
+ },
+ {
+ "name": "left-foot",
+ "parent": "left-lower-leg",
+ "length": 46.5,
+ "rotation": 102.43,
+ "x": 58.94,
+ "y": -7.61,
+ "color": "ff0000ff"
+ },
+ {
+ "name": "left-hand",
+ "parent": "left-arm",
+ "length": 11.52,
+ "rotation": 2.7,
+ "x": 35.62,
+ "y": 0.08,
+ "color": "ff0000ff"
+ },
+ { "name": "pelvis", "parent": "hip", "x": 1.41, "y": -6.58, "color": "ffd300ff" },
+ {
+ "name": "right-shoulder",
+ "parent": "torso",
+ "length": 37.25,
+ "rotation": 133.89,
+ "x": 76.02,
+ "y": 18.15,
+ "color": "54ff00ff"
+ },
+ {
+ "name": "right-arm",
+ "parent": "right-shoulder",
+ "length": 36.75,
+ "rotation": 36.33,
+ "x": 37.61,
+ "y": 0.31,
+ "color": "54ff00ff"
+ },
+ {
+ "name": "right-upper-leg",
+ "parent": "hip",
+ "length": 42.46,
+ "rotation": -97.5,
+ "x": -20.08,
+ "y": -6.84,
+ "color": "54ff00ff"
+ },
+ {
+ "name": "right-lower-leg",
+ "parent": "right-upper-leg",
+ "length": 58.53,
+ "rotation": -14.34,
+ "x": 43,
+ "y": -0.62,
+ "color": "54ff00ff"
+ },
+ {
+ "name": "right-foot",
+ "parent": "right-lower-leg",
+ "length": 45.46,
+ "rotation": 110.31,
+ "x": 64.89,
+ "y": 0.04,
+ "color": "54ff00ff"
+ },
+ {
+ "name": "right-hand",
+ "parent": "right-arm",
+ "length": 15.32,
+ "rotation": 2.36,
+ "x": 36.9,
+ "y": 0.35,
+ "color": "54ff00ff"
+ }
+],
+"slots": [
+ { "name": "left-shoulder", "bone": "left-shoulder", "attachment": "left-shoulder" },
+ { "name": "left-arm", "bone": "left-arm", "attachment": "left-arm" },
+ { "name": "left-hand-item", "bone": "left-hand", "attachment": "spear" },
+ { "name": "left-hand", "bone": "left-hand", "attachment": "left-hand" },
+ { "name": "left-foot", "bone": "left-foot", "attachment": "left-foot" },
+ { "name": "left-lower-leg", "bone": "left-lower-leg", "attachment": "left-lower-leg" },
+ { "name": "left-upper-leg", "bone": "left-upper-leg", "attachment": "left-upper-leg" },
+ { "name": "neck", "bone": "neck", "attachment": "neck" },
+ { "name": "torso", "bone": "torso", "attachment": "torso" },
+ { "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" },
+ { "name": "right-foot", "bone": "right-foot", "attachment": "right-foot" },
+ { "name": "right-lower-leg", "bone": "right-lower-leg", "attachment": "right-lower-leg" },
+ { "name": "undie-straps", "bone": "pelvis", "attachment": "undie-straps" },
+ { "name": "undies", "bone": "pelvis", "attachment": "undies" },
+ { "name": "right-upper-leg", "bone": "right-upper-leg", "attachment": "right-upper-leg" },
+ { "name": "head", "bone": "head", "attachment": "head" },
+ { "name": "eyes", "bone": "head" },
+ { "name": "right-shoulder", "bone": "right-shoulder", "attachment": "right-shoulder" },
+ { "name": "right-arm", "bone": "right-arm", "attachment": "right-arm" },
+ { "name": "right-hand-item", "bone": "right-hand" },
+ { "name": "right-hand", "bone": "right-hand", "attachment": "right-hand" },
+ { "name": "right-hand-item-top", "bone": "right-hand", "attachment": "shield" }
+],
+"skins": [
+ {
+ "name": "default",
+ "attachments": {
+ "left-hand-item": {
+ "dagger": { "x": 7.88, "y": -23.46, "rotation": 10.48, "width": 26, "height": 108 },
+ "spear": { "x": -4.56, "y": 39.2, "rotation": 13.05, "width": 22, "height": 368 }
+ },
+ "right-hand-item": {
+ "dagger": { "x": 6.52, "y": -24.16, "rotation": -8.06, "width": 26, "height": 108 }
+ },
+ "right-hand-item-top": {
+ "shield": { "rotation": 93.5, "width": 70, "height": 72 }
+ }
+ }
+ },
+ {
+ "name": "goblin",
+ "attachments": {
+ "eyes": {
+ "eyes-closed": { "name": "goblin/eyes-closed", "x": 32.22, "y": -21.27, "rotation": -88.93, "width": 34, "height": 12 }
+ },
+ "head": {
+ "head": { "name": "goblin/head", "x": 25.74, "y": 2.33, "rotation": -92.29, "width": 103, "height": 66 }
+ },
+ "left-arm": {
+ "left-arm": {
+ "name": "goblin/left-arm",
+ "x": 16.7,
+ "y": -1.69,
+ "scaleX": 1.0573,
+ "scaleY": 1.0573,
+ "rotation": 33.85,
+ "width": 37,
+ "height": 35
+ }
+ },
+ "left-foot": {
+ "left-foot": { "name": "goblin/left-foot", "x": 24.85, "y": 8.75, "rotation": 3.32, "width": 65, "height": 31 }
+ },
+ "left-hand": {
+ "left-hand": {
+ "name": "goblin/left-hand",
+ "x": 3.47,
+ "y": 3.41,
+ "scaleX": 0.8922,
+ "scaleY": 0.8922,
+ "rotation": 31.14,
+ "width": 36,
+ "height": 41
+ }
+ },
+ "left-lower-leg": {
+ "left-lower-leg": { "name": "goblin/left-lower-leg", "x": 23.59, "y": -2.07, "rotation": 105.76, "width": 33, "height": 70 }
+ },
+ "left-shoulder": {
+ "left-shoulder": { "name": "goblin/left-shoulder", "x": 15.56, "y": -2.27, "rotation": 62.01, "width": 29, "height": 44 }
+ },
+ "left-upper-leg": {
+ "left-upper-leg": { "name": "goblin/left-upper-leg", "x": 29.69, "y": -3.87, "rotation": 89.1, "width": 33, "height": 73 }
+ },
+ "neck": {
+ "neck": { "name": "goblin/neck", "x": 10.1, "y": 0.42, "rotation": -93.7, "width": 36, "height": 41 }
+ },
+ "pelvis": {
+ "pelvis": { "name": "goblin/pelvis", "x": -5.62, "y": 0.77, "width": 62, "height": 43 }
+ },
+ "right-arm": {
+ "right-arm": { "name": "goblin/right-arm", "x": 16.44, "y": -1.04, "rotation": 94.32, "width": 23, "height": 50 }
+ },
+ "right-foot": {
+ "right-foot": { "name": "goblin/right-foot", "x": 23.57, "y": 9.8, "rotation": 1.53, "width": 63, "height": 33 }
+ },
+ "right-hand": {
+ "right-hand": { "name": "goblin/right-hand", "x": 7.89, "y": 2.78, "rotation": 91.96, "width": 36, "height": 37 }
+ },
+ "right-lower-leg": {
+ "right-lower-leg": { "name": "goblin/right-lower-leg", "x": 25.68, "y": -3.16, "rotation": 111.84, "width": 36, "height": 76 }
+ },
+ "right-shoulder": {
+ "right-shoulder": { "name": "goblin/right-shoulder", "x": 15.68, "y": -1.03, "rotation": 130.65, "width": 39, "height": 45 }
+ },
+ "right-upper-leg": {
+ "right-upper-leg": { "name": "goblin/right-upper-leg", "x": 20.35, "y": 1.48, "rotation": 97.5, "width": 34, "height": 63 }
+ },
+ "torso": {
+ "torso": { "name": "goblin/torso", "x": 38.1, "y": -3.87, "rotation": -94.95, "width": 68, "height": 96 }
+ },
+ "undie-straps": {
+ "undie-straps": { "name": "goblin/undie-straps", "x": -3.88, "y": 13.11, "scaleX": 1.0896, "width": 55, "height": 19 }
+ },
+ "undies": {
+ "undies": { "name": "goblin/undies", "x": 6.3, "y": 0.13, "rotation": 0.92, "width": 36, "height": 29 }
+ }
+ }
+ },
+ {
+ "name": "goblingirl",
+ "attachments": {
+ "eyes": {
+ "eyes-closed": { "name": "goblingirl/eyes-closed", "x": 28, "y": -25.55, "rotation": -87.05, "width": 37, "height": 21 }
+ },
+ "head": {
+ "head": { "name": "goblingirl/head", "x": 27.72, "y": -4.32, "rotation": -85.58, "width": 103, "height": 81 }
+ },
+ "left-arm": {
+ "left-arm": { "name": "goblingirl/left-arm", "x": 19.64, "y": -2.43, "rotation": 33.05, "width": 37, "height": 35 }
+ },
+ "left-foot": {
+ "left-foot": { "name": "goblingirl/left-foot", "x": 25.18, "y": 7.92, "rotation": 3.32, "width": 65, "height": 31 }
+ },
+ "left-hand": {
+ "left-hand": {
+ "name": "goblingirl/left-hand",
+ "x": 4.34,
+ "y": 2.39,
+ "scaleX": 0.8965,
+ "scaleY": 0.8965,
+ "rotation": 30.35,
+ "width": 35,
+ "height": 40
+ }
+ },
+ "left-lower-leg": {
+ "left-lower-leg": { "name": "goblingirl/left-lower-leg", "x": 25.02, "y": -0.61, "rotation": 105.76, "width": 33, "height": 70 }
+ },
+ "left-shoulder": {
+ "left-shoulder": { "name": "goblingirl/left-shoulder", "x": 19.81, "y": -0.43, "rotation": 61.22, "width": 28, "height": 46 }
+ },
+ "left-upper-leg": {
+ "left-upper-leg": { "name": "goblingirl/left-upper-leg", "x": 30.22, "y": -2.95, "rotation": 89.1, "width": 33, "height": 70 }
+ },
+ "neck": {
+ "neck": { "name": "goblingirl/neck", "x": 6.16, "y": -3.15, "rotation": -98.86, "width": 35, "height": 41 }
+ },
+ "pelvis": {
+ "pelvis": { "name": "goblingirl/pelvis", "x": -3.88, "y": 3.19, "width": 62, "height": 43 }
+ },
+ "right-arm": {
+ "right-arm": { "name": "goblingirl/right-arm", "x": 16.85, "y": -0.66, "rotation": 93.53, "width": 28, "height": 50 }
+ },
+ "right-foot": {
+ "right-foot": { "name": "goblingirl/right-foot", "x": 23.46, "y": 9.66, "rotation": 1.53, "width": 63, "height": 33 }
+ },
+ "right-hand": {
+ "right-hand": { "name": "goblingirl/right-hand", "x": 7.22, "y": 3.44, "rotation": 91.17, "width": 36, "height": 37 }
+ },
+ "right-lower-leg": {
+ "right-lower-leg": { "name": "goblingirl/right-lower-leg", "x": 26.15, "y": -3.28, "rotation": 111.84, "width": 36, "height": 76 }
+ },
+ "right-shoulder": {
+ "right-shoulder": { "name": "goblingirl/right-shoulder", "x": 14.46, "y": 0.46, "rotation": 129.85, "width": 39, "height": 45 }
+ },
+ "right-upper-leg": {
+ "right-upper-leg": { "name": "goblingirl/right-upper-leg", "x": 19.7, "y": 2.13, "rotation": 97.5, "width": 34, "height": 63 }
+ },
+ "torso": {
+ "torso": { "name": "goblingirl/torso", "x": 36.28, "y": -5.14, "rotation": -95.75, "width": 68, "height": 96 }
+ },
+ "undie-straps": {
+ "undie-straps": { "name": "goblingirl/undie-straps", "x": -1.52, "y": 14.19, "width": 55, "height": 19 }
+ },
+ "undies": {
+ "undies": { "name": "goblingirl/undies", "x": 5.4, "y": 1.71, "width": 36, "height": 29 }
+ }
+ }
+ }
+],
+"animations": {
+ "walk": {
+ "slots": {
+ "eyes": {
+ "attachment": [
+ { "time": 0.7, "name": "eyes-closed" },
+ { "time": 0.8 }
+ ]
+ }
+ },
+ "bones": {
+ "left-upper-leg": {
+ "rotate": [
+ { "value": -26.56 },
+ { "time": 0.1333, "value": -8.79 },
+ { "time": 0.2333, "value": 9.51 },
+ { "time": 0.3667, "value": 30.74 },
+ { "time": 0.5, "value": 25.34 },
+ { "time": 0.6333, "value": 26.12 },
+ { "time": 0.7333, "value": -7.71 },
+ { "time": 0.8667, "value": -21.19 },
+ { "time": 1, "value": -26.56 }
+ ],
+ "translate": [
+ { "x": -1.32, "y": 1.71 },
+ { "time": 0.3667, "x": -0.06, "y": 2.43 },
+ { "time": 1, "x": -1.32, "y": 1.71 }
+ ]
+ },
+ "right-upper-leg": {
+ "rotate": [
+ { "value": 42.45 },
+ { "time": 0.1333, "value": 52.11 },
+ { "time": 0.2333, "value": 8.54 },
+ { "time": 0.5, "value": -16.94 },
+ { "time": 0.6333, "value": 1.9 },
+ {
+ "time": 0.7333,
+ "value": 28.06,
+ "curve": [ 0.795, 31.71, 0.867, 58.69 ]
+ },
+ {
+ "time": 0.8667,
+ "value": 58.69,
+ "curve": [ 0.933, 58.35, 1, 42.45 ]
+ },
+ { "time": 1, "value": 42.45 }
+ ],
+ "translate": [
+ { "x": 6.24 },
+ { "time": 0.2333, "x": 2.14, "y": 2.4 },
+ { "time": 0.5, "x": 2.44, "y": 4.8 },
+ { "time": 1, "x": 6.24 }
+ ]
+ },
+ "left-lower-leg": {
+ "rotate": [
+ { "value": -22.98 },
+ { "time": 0.1333, "value": -63.51 },
+ { "time": 0.2333, "value": -73.76 },
+ { "time": 0.5, "value": 5.12 },
+ { "time": 0.6333, "value": -28.3 },
+ { "time": 0.7333, "value": 4.08 },
+ { "time": 0.8667, "value": 3.53 },
+ { "time": 1, "value": -22.98 }
+ ],
+ "translate": [
+ {},
+ { "time": 0.2333, "x": 2.56, "y": -0.47 },
+ { "time": 0.5 }
+ ]
+ },
+ "left-foot": {
+ "rotate": [
+ { "value": -3.69 },
+ { "time": 0.1333, "value": -10.42 },
+ { "time": 0.2333, "value": -5.01 },
+ { "time": 0.3667, "value": 3.87 },
+ { "time": 0.5, "value": -3.88 },
+ { "time": 0.6333, "value": 2.78 },
+ { "time": 0.7333, "value": 1.68 },
+ { "time": 0.8667, "value": -8.54 },
+ { "time": 1, "value": -3.69 }
+ ]
+ },
+ "right-shoulder": {
+ "rotate": [
+ {
+ "value": 5.29,
+ "curve": [ 0.167, 5.29, 0.475, 6.65 ]
+ },
+ { "time": 0.6333, "value": 6.65 },
+ { "time": 1, "value": 5.29 }
+ ]
+ },
+ "right-arm": {
+ "rotate": [
+ {
+ "value": -4.03,
+ "curve": [ 0.169, -3.91, 0.51, 19.66 ]
+ },
+ {
+ "time": 0.6333,
+ "value": 19.79,
+ "curve": [ 0.746, 19.75, 0.922, -3.91 ]
+ },
+ { "time": 1, "value": -4.03 }
+ ]
+ },
+ "right-hand": {
+ "rotate": [
+ { "value": 8.99 },
+ { "time": 0.6333, "value": 0.51 },
+ { "time": 1, "value": 8.99 }
+ ]
+ },
+ "left-shoulder": {
+ "rotate": [
+ {
+ "value": 6.26,
+ "curve": [ 0.17, 6.26, 0.342, -11.79 ]
+ },
+ {
+ "time": 0.5,
+ "value": -11.79,
+ "curve": [ 0.641, -11.79, 0.843, 6.16 ]
+ },
+ { "time": 1, "value": 6.26 }
+ ],
+ "translate": [
+ { "x": 1.15, "y": 0.24 }
+ ]
+ },
+ "left-hand": {
+ "rotate": [
+ {
+ "value": -21.24,
+ "curve": [ 0.148, -21.24, 0.378, -27.21 ]
+ },
+ {
+ "time": 0.5,
+ "value": -27.28,
+ "curve": [ 0.621, -27.28, 0.875, -21.4 ]
+ },
+ { "time": 1, "value": -21.24 }
+ ]
+ },
+ "left-arm": {
+ "rotate": [
+ {
+ "value": 28.38,
+ "curve": [ 0.17, 28.38, 0.342, 60.09 ]
+ },
+ {
+ "time": 0.5,
+ "value": 60.09,
+ "curve": [ 0.641, 60.09, 0.843, 28.54 ]
+ },
+ { "time": 1, "value": 28.38 }
+ ]
+ },
+ "torso": {
+ "rotate": [
+ { "value": -10.28 },
+ {
+ "time": 0.1333,
+ "value": -15.39,
+ "curve": [ 0.261, -15.36, 0.324, -9.78 ]
+ },
+ {
+ "time": 0.3667,
+ "value": -9.78,
+ "curve": [ 0.521, -10.8, 0.545, -15.72 ]
+ },
+ {
+ "time": 0.6333,
+ "value": -15.75,
+ "curve": [ 0.688, -15.66, 0.819, -7.07 ]
+ },
+ {
+ "time": 0.8667,
+ "value": -7.07,
+ "curve": [ 0.895, -7.07, 0.975, -10.25 ]
+ },
+ { "time": 1, "value": -10.28 }
+ ],
+ "translate": [
+ { "x": -1.29, "y": 1.69 }
+ ]
+ },
+ "right-foot": {
+ "rotate": [
+ { "value": -5.25 },
+ { "time": 0.2333, "value": -1.91 },
+ { "time": 0.3667, "value": -6.45 },
+ { "time": 0.5, "value": -5.4 },
+ { "time": 0.7333, "value": -11.69 },
+ { "time": 0.8667, "value": 0.46 },
+ { "time": 1, "value": -5.25 }
+ ]
+ },
+ "right-lower-leg": {
+ "rotate": [
+ {
+ "value": -3.39,
+ "curve": [ 0.042, -4.05, 0.099, -45.1 ]
+ },
+ {
+ "time": 0.1333,
+ "value": -45.53,
+ "curve": [ 0.156, -45.53, 0.207, -5.89 ]
+ },
+ { "time": 0.2333, "value": -4.83 },
+ { "time": 0.5, "value": -19.53 },
+ { "time": 0.6333, "value": -64.8 },
+ {
+ "time": 0.7333,
+ "value": -82.56,
+ "curve": [ 0.882, -68.28, 1, -3.39 ]
+ },
+ { "time": 1, "value": -3.39 }
+ ],
+ "translate": [
+ { "time": 0.5 },
+ { "time": 0.6333, "x": 2.19, "y": 0.21 },
+ { "time": 1 }
+ ]
+ },
+ "hip": {
+ "translate": [
+ { "y": -4.16 },
+ {
+ "time": 0.1333,
+ "y": -7.06,
+ "curve": [ 0.217, 0, 0.284, 0, 0.217, -0.53, 0.284, 3.27 ]
+ },
+ { "time": 0.3667, "y": 6.78 },
+ { "time": 0.5, "y": -6.14 },
+ {
+ "time": 0.6333,
+ "y": -7.06,
+ "curve": [ 0.717, 0, 0.784, 0, 0.717, -0.53, 0.784, 3.27 ]
+ },
+ { "time": 0.8667, "y": 6.78 },
+ { "time": 1, "y": -4.16 }
+ ]
+ },
+ "neck": {
+ "rotate": [
+ { "value": 3.6 },
+ { "time": 0.1333, "value": 17.5 },
+ { "time": 0.2333, "value": 6.11 },
+ { "time": 0.3667, "value": 3.46 },
+ { "time": 0.5, "value": 5.18 },
+ { "time": 0.6333, "value": 18.36 },
+ { "time": 0.7333, "value": 6.09 },
+ { "time": 0.8667, "value": 2.29 },
+ { "time": 1, "value": 3.6 }
+ ]
+ },
+ "head": {
+ "rotate": [
+ {
+ "value": 3.6,
+ "curve": [ 0, 3.6, 0.094, -0.89 ]
+ },
+ { "time": 0.1333, "value": -0.21 },
+ { "time": 0.2333, "value": 6.11 },
+ { "time": 0.3667, "value": 3.46 },
+ {
+ "time": 0.5,
+ "value": 5.18,
+ "curve": [ 0.5, 5.18, 0.617, -1.4 ]
+ },
+ { "time": 0.6667, "value": 1.11 },
+ { "time": 0.7333, "value": 6.09 },
+ { "time": 0.8667, "value": 2.29 },
+ { "time": 1, "value": 3.6 }
+ ]
+ }
+ }
+ }
+}
+}
\ No newline at end of file
diff --git a/demos/art/sprites/spines/goblins.license b/demos/art/sprites/spines/goblins.license
new file mode 100644
index 0000000..cd3e3b4
--- /dev/null
+++ b/demos/art/sprites/spines/goblins.license
@@ -0,0 +1,8 @@
+Copyright (c) 2013, Esoteric Software
+
+The images in this project may be redistributed as long as they are accompanied
+by this license file. The images may not be used for commercial use of any
+kind.
+
+The project file is released into the public domain. It may be used as the basis
+for derivative work.
\ No newline at end of file
diff --git a/demos/art/sprites/spines/goblins.png b/demos/art/sprites/spines/goblins.png
new file mode 100644
index 0000000..4613441
Binary files /dev/null and b/demos/art/sprites/spines/goblins.png differ
diff --git a/demos/art/sprites/tiled/castle-tileset-by-RottingPixels-(CC0).png b/demos/art/sprites/tiled/castle-tileset-by-RottingPixels-(CC0).png
new file mode 100644
index 0000000..c76c30b
Binary files /dev/null and b/demos/art/sprites/tiled/castle-tileset-by-RottingPixels-(CC0).png differ
diff --git a/demos/art/sprites/tiled/castle.tmx b/demos/art/sprites/tiled/castle.tmx
new file mode 100644
index 0000000..d984584
--- /dev/null
+++ b/demos/art/sprites/tiled/castle.tmx
@@ -0,0 +1,14 @@
+
+
diff --git a/demos/art/sprites/tiled/castle.tsx b/demos/art/sprites/tiled/castle.tsx
new file mode 100644
index 0000000..62df76d
--- /dev/null
+++ b/demos/art/sprites/tiled/castle.tsx
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/engine/editor.c b/engine/editor.c
index c00a656..aaf7378 100644
--- a/engine/editor.c
+++ b/engine/editor.c
@@ -56,7 +56,7 @@ TODO("obj: free obj_components()/payload2");
TODO("pack: mp2json, json2mp");
TODO("pack: simplify msgpack API, make it growth similar to va()")
-#if 0 // fwk_pack proposal
+#if 0 // v4k_pack proposal
static __thread char* mpin;
static __thread unsigned mpinlen;
static __thread char mpinbuf[256];
diff --git a/hello.c b/hello.c
index eb4b40a..2c8e04d 100644
--- a/hello.c
+++ b/hello.c
@@ -1,4 +1,4 @@
-// playground tests for FWK
+// playground tests for V4K
// - rlyeh, public domain
//
// # quickstart
diff --git a/tools/cook.exe b/tools/cook.exe
index dda9c7e..046148c 100644
Binary files a/tools/cook.exe and b/tools/cook.exe differ
diff --git a/tools/cook.ini b/tools/cook.ini
index 589747c..a599b5d 100644
--- a/tools/cook.ini
+++ b/tools/cook.ini
@@ -7,7 +7,7 @@
; syntax: symbols are defined in KEY=value form, as seen below.
TOOLS=./ ; folder where our pipeline tools are located
-ART=../demos/art/,../engine/art/,../tools/editor/art/ ; comma-separated folder(s) that store all our asset files
+ART=../demos/art/,../engine/art/,../editor/art/ ; comma-separated folder(s) that store all our asset files
; lines starting with @windows, @linux or @osx will be processed only where OS matches.
; we are defining here some symbols differently for each platform.
@@ -25,9 +25,9 @@ ART=../demos/art/,../engine/art/,../tools/editor/art/ ; comma-separated folder(
; also, once a symbol is found, it is replaced by its value always.
; some predefined symbols: INPUT (input filename), OUTPUT (output filename), PRETTY (clean input filename), PROGRESS (cook progress).
-@windows `echo Cooking PROGRESS% PRETTY...`
-@linux `echo "Cooking PROGRESS% PRETTY..."`
-@osx `echo "Cooking PROGRESS% PRETTY..."`
+;@windows `echo Cooking PROGRESS% PRETTY...`
+;@linux `echo "Cooking PROGRESS% PRETTY..."`
+;@osx `echo "Cooking PROGRESS% PRETTY..."`
; ------------------------------------------------------------------------------
; groups below are collection of files that we want to cook, and then package.
@@ -212,4 +212,4 @@ TOOLS/ase2ini.EXE "INPUT" > OUTPUT
[compress]
0|ULZ=texture,image,model,audio,font,text,shader,script
-0=video,flac,ogg,wav,mp1,mp3,jpg,png,atlas,tiled
+0=video,flac,ogg,wav,mp1,mp3,jpg,png,atlas,tiled
\ No newline at end of file