main.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434
  1. #include <gs.h>
  2. #include "font.h"
  3. #include "tinyfiledialogs.h"
  4. #include "font/font_data.c"
  5. #define NK_INCLUDE_FIXED_TYPES
  6. #define NK_INCLUDE_STANDARD_IO
  7. #define NK_INCLUDE_STANDARD_VARARGS
  8. #define NK_INCLUDE_DEFAULT_ALLOCATOR
  9. #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
  10. #define NK_INCLUDE_FONT_BAKING
  11. #define NK_INCLUDE_DEFAULT_FONT
  12. #define NK_IMPLEMENTATION
  13. #define NK_GLFW_GL3_IMPLEMENTATION
  14. #define NK_KEYSTATE_BASED_INPUT
  15. #include "nuklear.h"
  16. #include "nuklear_glfw_gl3.h"
  17. #define MAX_VERTEX_BUFFER 512 * 1024
  18. #define MAX_ELEMENT_BUFFER 128 * 1024
  19. /*=======================================================================================================================================
  20. Custom Byte Buffer / Binary Serialization example
  21. The purpose of this example is to demonstrate how to serialize arbitrary data to disk using a custom byte buffer implementation.
  22. A simple pixel art editor is thrown in to demonstrate some of these ideas in practice.
  23. Libraries used :
  24. {
  25. * Nuklear UI: https://github.com/Immediate-Mode-UI/Nuklear
  26. * TinyFileDialog: https://github.com/native-toolkit/tinyfiledialogs
  27. }
  28. ========================================================================================================================================*/
  29. //================================================================
  30. void print_bin(uint8_t byte)
  31. {
  32. int i = CHAR_BIT; /* however many bits are in a byte on your platform */
  33. while(i--) {
  34. putchar('0' + ((byte >> i) & 1)); /* loop through and print the bits */
  35. }
  36. }
  37. // Forward Decls
  38. void pan_camera();
  39. /*==============
  40. // Byte Buffer
  41. ==============*/
  42. typedef struct byte_buffer_t
  43. {
  44. uint8_t* data;
  45. uint32_t position;
  46. uint32_t capacity;
  47. uint32_t size;
  48. } byte_buffer_t;
  49. #define byte_buffer_default_capacity 1024
  50. byte_buffer_t byte_buffer_new()
  51. {
  52. byte_buffer_t buffer = {0};
  53. buffer.data = malloc( byte_buffer_default_capacity );
  54. memset( buffer.data, 0, byte_buffer_default_capacity );
  55. buffer.capacity = byte_buffer_default_capacity;
  56. buffer.size = 0;
  57. buffer.position = 0;
  58. return buffer;
  59. }
  60. void byte_buffer_resize( byte_buffer_t* buffer, size_t sz );
  61. void __byte_buffer_write_impl( byte_buffer_t* buffer, void* data, size_t sz )
  62. {
  63. size_t total_write_size = buffer->position + sz;
  64. if ( total_write_size >= buffer->capacity )
  65. {
  66. size_t capacity = buffer->capacity ? buffer->capacity * 2 : byte_buffer_default_capacity;
  67. while ( capacity < total_write_size )
  68. {
  69. capacity *= 2;
  70. }
  71. byte_buffer_resize( buffer, capacity );
  72. }
  73. memcpy( buffer->data + buffer->position, data, sz );
  74. buffer->position += sz;
  75. buffer->size += sz;
  76. }
  77. // Generic write function
  78. #define byte_buffer_write( _buffer, T, _val )\
  79. do {\
  80. byte_buffer_t* _bb = (_buffer );\
  81. size_t _sz = sizeof(T);\
  82. T _v = _val;\
  83. __byte_buffer_write_impl( _bb, (void*)&(_v), _sz );\
  84. } while (0)
  85. // Generic read function
  86. #define byte_buffer_read( _buffer, T, _val_p )\
  87. do {\
  88. T* _v = (T*)(_val_p);\
  89. byte_buffer_t* _bb = (_buffer);\
  90. *(_v) = *(T*)( _bb->data + _bb->position );\
  91. _bb->position += sizeof(T);\
  92. } while (0)
  93. // Utiltiy functions
  94. void byte_buffer_clear( byte_buffer_t* buffer )
  95. {
  96. buffer->size = 0;
  97. buffer->position = 0;
  98. }
  99. void byte_buffer_free( byte_buffer_t* buffer )
  100. {
  101. byte_buffer_clear( buffer );
  102. free( buffer->data );
  103. buffer->data = NULL;
  104. buffer->capacity = 0;
  105. }
  106. void byte_buffer_resize( byte_buffer_t* buffer, size_t sz )
  107. {
  108. uint8_t* data = realloc( buffer->data, sz );
  109. if ( data == NULL ) {
  110. return;
  111. }
  112. buffer->data = data;
  113. buffer->capacity = sz;
  114. }
  115. void byte_buffer_seek_to_beg( byte_buffer_t* buffer )
  116. {
  117. buffer->position = 0;
  118. }
  119. void byte_buffer_seek_to_end( byte_buffer_t* buffer )
  120. {
  121. buffer->position = buffer->size;
  122. }
  123. // Writing
  124. gs_result
  125. byte_buffer_write_to_file( byte_buffer_t* buffer, const char* path )
  126. {
  127. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  128. gs_result res = platform->write_file_contents( path, "wb", buffer->data, sizeof(uint8_t), buffer->size );
  129. return res;
  130. }
  131. // Reading
  132. gs_result
  133. byte_buffer_read_from_file( byte_buffer_t* buffer, const char* path )
  134. {
  135. // Clear previous data if any
  136. if ( buffer->data )
  137. {
  138. byte_buffer_free( buffer );
  139. }
  140. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  141. buffer->size = platform->file_size_in_bytes( path );
  142. buffer->data = platform->read_file_contents( path, "rb", NULL );
  143. if ( !buffer->data )
  144. {
  145. gs_assert( false );
  146. return gs_result_failure;
  147. }
  148. buffer->position = 0;
  149. buffer->capacity = buffer->size;
  150. return gs_result_success;
  151. }
  152. //================================================================
  153. /*=========
  154. // NK - UI
  155. =========*/
  156. struct pixel_frame_t;
  157. _global struct nk_glfw g_nk_glfw = {0};
  158. _global struct nk_context* g_nk_ctx;
  159. _global struct nk_colorf g_nk_color;
  160. void nk_init_ui();
  161. void nk_do_ui( struct pixel_frame_t* pf );
  162. //================================================================
  163. /*=======================================
  164. // Texture Buffer For Simple Pixel Editor
  165. =======================================*/
  166. b32 color_equal( gs_color_t c0, gs_color_t c1 )
  167. {
  168. return (c0.r == c1.r) &&
  169. (c0.g == c1.g) &&
  170. (c0.b == c1.b) &&
  171. (c0.a == c1.a);
  172. }
  173. #define default_pixel_frame_width 128
  174. #define default_pixel_frame_height 128
  175. #define ui_frame_width 128
  176. #define ui_frame_height 128
  177. const char* pixel_frame_v_src = "\n"
  178. "#version 330 core\n"
  179. "layout(location = 0) in vec2 a_pos;\n"
  180. "layout(location = 1) in vec2 a_uv;\n"
  181. "uniform mat4 u_proj;\n"
  182. "uniform mat4 u_view;\n"
  183. "out vec2 uv;\n"
  184. "void main()\n"
  185. "{\n"
  186. " gl_Position = u_proj * u_view * vec4(a_pos, 0.0, 1.0);\n"
  187. " uv = a_uv;\n"
  188. "}";
  189. const char* pixel_frame_f_src = "\n"
  190. "#version 330 core\n"
  191. "uniform sampler2D u_tex;"
  192. "in vec2 uv;\n"
  193. "out vec4 frag_color;\n"
  194. "void main()\n"
  195. "{\n"
  196. " frag_color = texture(u_tex, uv);\n"
  197. "}";
  198. /*
  199. These will be all the required op codes for undo/redo in our pixel editor
  200. We'll treat our undo/redo buffer as a simple VM
  201. */
  202. typedef enum pixel_frame_action_op_code_type
  203. {
  204. pixel_frame_action_op_write_pixels = 0x00,
  205. pixel_frame_action_op_clear_pixels = 0x01
  206. } pixel_frame_action_op_code_type;
  207. typedef struct pixel_frame_delta_color_t
  208. {
  209. u8 r, g, b, a;
  210. u8 sign_bits;
  211. } pixel_frame_delta_color_t;
  212. typedef struct pixel_frame_action_write_t
  213. {
  214. uint16_t idx;
  215. u8 r, g, b, a;
  216. u8 sign_bits;
  217. } pixel_frame_action_write_t;
  218. typedef struct pixel_frame_t
  219. {
  220. gs_color_t* pixel_data;
  221. gs_color_t* ui_data;
  222. uint32_t pixel_frame_width;
  223. uint32_t pixel_frame_height;
  224. gs_resource( gs_texture ) bg_texture;
  225. gs_resource( gs_texture ) texture;
  226. gs_resource( gs_texture ) ui_texture;
  227. gs_resource( gs_shader ) shader;
  228. gs_resource( gs_uniform ) u_tex;
  229. gs_resource( gs_uniform ) u_proj;
  230. gs_resource( gs_uniform ) u_view;
  231. gs_resource( gs_vertex_buffer ) vbo;
  232. gs_resource( gs_index_buffer ) ibo;
  233. uint32_t paint_radius;
  234. b32 mouse_down;
  235. byte_buffer_t undo_buffer;
  236. byte_buffer_t redo_buffer;
  237. uint32_t current_write_size;
  238. } pixel_frame_t;
  239. typedef void ( *put_pixel_func )(void*, gs_color_t, int32_t, int32_t);
  240. // Bresenham Line -> from https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm
  241. void drawLine( void* data, gs_color_t color, int32_t x0, int32_t x1, int32_t y0, int32_t y1, put_pixel_func func )
  242. {
  243. int32_t dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
  244. int32_t dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
  245. int32_t err = (dx>dy ? dx : -dy)/2, e2;
  246. for(;;)
  247. {
  248. func( data, color, x0, y0 );
  249. if (x0==x1 && y0==y1) break;
  250. e2 = err;
  251. if (e2 >-dx) { err -= dy; x0 += sx; }
  252. if (e2 < dy) { err += dx; y0 += sy; }
  253. }
  254. }
  255. // Function to put pixels
  256. // at subsequence points
  257. void drawCircle( void* data, gs_color_t color, b32 filled, int32_t xc, int32_t yc, int32_t x, int32_t y, put_pixel_func func )
  258. {
  259. if ( filled )
  260. {
  261. drawLine( data, color, xc - x, xc + x, yc + y, yc + y, func );
  262. drawLine( data, color, xc - x, xc + x, yc - y, yc - y, func );
  263. drawLine( data, color, xc - y, xc + y, yc + x, yc + x, func );
  264. drawLine( data, color, xc - y, xc + y, yc - x, yc - x, func );
  265. }
  266. else
  267. {
  268. func( data, color, xc+x, yc+y );
  269. func( data, color, xc-x, yc+y );
  270. func( data, color, xc+x, yc-y );
  271. func( data, color, xc-x, yc-y );
  272. func( data, color, xc+y, yc+x );
  273. func( data, color, xc-y, yc+x );
  274. func( data, color, xc+y, yc-x );
  275. func( data, color, xc-y, yc-x );
  276. }
  277. }
  278. // Function for circle-generation
  279. // using Bresenham's algorithm
  280. void circleBres( void* data, gs_color_t color, b32 filled, int32_t xc, int32_t yc, int32_t r, put_pixel_func func )
  281. {
  282. int x = 0, y = r;
  283. int d = 3 - 2 * r;
  284. drawCircle( data, color, filled, xc, yc, x, y, func );
  285. while (y >= x)
  286. {
  287. // For each pixel we will
  288. // draw all eight pixels
  289. x++;
  290. // Check for decision parameter
  291. // and correspondingly
  292. // update d, x, y
  293. if (d > 0)
  294. {
  295. y--;
  296. d = d + 4 * (x - y) + 10;
  297. }
  298. else
  299. d = d + 4 * x + 6;
  300. drawCircle( data, color, filled, xc, yc, x, y, func );
  301. }
  302. }
  303. gs_texture_parameter_desc pixel_frame_texture_parameter_desc()
  304. {
  305. gs_texture_parameter_desc desc = gs_texture_parameter_desc_default();
  306. desc.mag_filter = gs_nearest;
  307. desc.min_filter = gs_nearest;
  308. desc.generate_mips = false;
  309. desc.width = default_pixel_frame_width;
  310. desc.height = default_pixel_frame_height;
  311. desc.num_comps = 4;
  312. return desc;
  313. }
  314. pixel_frame_t pixel_frame_new()
  315. {
  316. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  317. pixel_frame_t pf = {0};
  318. gs_texture_parameter_desc desc = pixel_frame_texture_parameter_desc();
  319. const gs_color_t checker_blue = (gs_color_t){ 50, 80, 180, 100 };
  320. const gs_color_t checker_white = (gs_color_t){ 255, 255, 255, 100 };
  321. const uint32_t bg_width = 5;
  322. const uint32_t bg_height = 5;
  323. gs_color_t* bg_data = gs_malloc( bg_width * bg_height * sizeof(gs_color_t) );
  324. // Background image
  325. for ( uint32_t h = 0; h < bg_width; ++h )
  326. {
  327. for ( uint32_t w = 0; w < bg_height; ++w )
  328. {
  329. const uint32_t idx = h * bg_width + w;
  330. if ( h % 2 == 0 ) {
  331. bg_data[ idx ] = w % 2 == 0 ? checker_white : checker_blue;
  332. }
  333. else {
  334. bg_data[ idx ] = w % 2 == 0 ? checker_blue : checker_white;
  335. }
  336. }
  337. }
  338. desc.width = bg_width;
  339. desc.height = bg_height;
  340. desc.data = bg_data;
  341. pf.bg_texture = gfx->construct_texture( desc );
  342. gs_free( bg_data );
  343. pf.pixel_frame_width = default_pixel_frame_width;
  344. pf.pixel_frame_height = default_pixel_frame_height;
  345. pf.pixel_data = gs_malloc( default_pixel_frame_width * default_pixel_frame_height * sizeof(gs_color_t) );
  346. memset( pf.pixel_data, 0, default_pixel_frame_width * default_pixel_frame_height * sizeof(gs_color_t) );
  347. desc = pixel_frame_texture_parameter_desc();
  348. desc.data = pf.pixel_data;
  349. pf.texture = gfx->construct_texture( desc );
  350. // UI data
  351. desc.width = ui_frame_width;
  352. desc.height = ui_frame_height;
  353. pf.ui_data = gs_malloc( desc.width * desc.height * sizeof(gs_color_t) );
  354. desc.data = pf.ui_data;
  355. memset( pf.ui_data, 0, desc.width * desc.height * sizeof(gs_color_t) );
  356. pf.ui_texture = gfx->construct_texture( desc );
  357. pf.paint_radius = 1;
  358. pf.shader = gfx->construct_shader( pixel_frame_v_src, pixel_frame_f_src );
  359. pf.u_tex = gfx->construct_uniform( pf.shader, "u_tex", gs_uniform_type_sampler2d );
  360. pf.u_proj = gfx->construct_uniform( pf.shader, "u_proj", gs_uniform_type_mat4 );
  361. pf.u_view = gfx->construct_uniform( pf.shader, "u_view", gs_uniform_type_mat4 );
  362. // Vertex data layout for our mesh
  363. gs_vertex_attribute_type layout[] = {
  364. gs_vertex_attribute_float2, // Position
  365. gs_vertex_attribute_float2 // UV
  366. };
  367. // Count of our vertex attribute array
  368. u32 layout_count = sizeof( layout ) / sizeof( gs_vertex_attribute_type );
  369. // Vertex data for editor screen quad
  370. f32 v_data[] =
  371. {
  372. // Positions UVs
  373. -1.0f, -1.0f, 0.0f, 0.0f, // Top Left
  374. 1.0f, -1.0f, 1.0f, 0.0f, // Top Right
  375. -1.0f, 1.0f, 0.0f, 1.0f, // Bottom Left
  376. 1.0f, 1.0f, 1.0f, 1.0f // Bottom Right
  377. };
  378. u32 i_data[] = {
  379. 0, 3, 2, // First Triangle
  380. 0, 1, 3 // Second Triangle
  381. };
  382. // Construct vertex and index buffers
  383. pf.vbo = gfx->construct_vertex_buffer( layout, layout_count, v_data, sizeof(v_data) );
  384. pf.ibo = gfx->construct_index_buffer( i_data, sizeof(i_data) );
  385. pf.mouse_down = false;
  386. pf.undo_buffer = byte_buffer_new();
  387. pf.redo_buffer = byte_buffer_new();
  388. pf.current_write_size = 0;
  389. return pf;
  390. }
  391. b32 pixel_frame_action_is_recording( pixel_frame_t* pf )
  392. {
  393. return (pf->current_write_size != 0);
  394. }
  395. // Undo and Redo ops
  396. void pixel_frame_action_start_record( pixel_frame_t* pf, pixel_frame_action_op_code_type op )
  397. {
  398. // Cannot start another operation until the previous is done recording
  399. if ( pixel_frame_action_is_recording( pf ) ) {
  400. return;
  401. }
  402. gs_println( "Starting action..." );
  403. // Write op code into buffer
  404. byte_buffer_write( &pf->undo_buffer, uint32_t, (uint32_t)op );
  405. pf->current_write_size += sizeof( pixel_frame_action_op_code_type );
  406. // Clear out redo buffer from previous actions
  407. byte_buffer_clear( &pf->redo_buffer );
  408. }
  409. void pixel_frame_action_end_record( pixel_frame_t* pf )
  410. {
  411. if ( !pixel_frame_action_is_recording( pf ) ) {
  412. return;
  413. }
  414. if ( pf->current_write_size > sizeof(pixel_frame_action_op_code_type ) ) {
  415. // Write current write size into buffer then reset write size
  416. byte_buffer_write( &pf->undo_buffer, uint32_t, pf->current_write_size );
  417. }
  418. else {
  419. pf->undo_buffer.position -= sizeof(pixel_frame_action_op_code_type);
  420. pf->undo_buffer.size -= sizeof(pixel_frame_action_op_code_type);
  421. }
  422. gs_println( "Ending action: sz: %zu, undo_size: %zu, undo_cap: %zu, redo_cap: %zu", pf->current_write_size,
  423. pf->undo_buffer.size, pf->undo_buffer.capacity, pf->redo_buffer.capacity );
  424. pf->current_write_size = 0;
  425. }
  426. // Writing actions pushing ops into undo buffer
  427. void pixel_frame_write_action_op( pixel_frame_t* pf, pixel_frame_action_write_t data )
  428. {
  429. if ( !pixel_frame_action_is_recording( pf ) ) {
  430. return;
  431. }
  432. // Write pixels...okie dokie, what does that data look like?
  433. // Do I need to keep track of previous pixel data? Not really, right? Because we know the starting state for all pixel data. It's memset to nothing.
  434. // Push data into byte buffer
  435. byte_buffer_write( &pf->undo_buffer, pixel_frame_action_write_t, data );
  436. pf->current_write_size += sizeof( data );
  437. }
  438. void pixel_frame_undo_action( pixel_frame_t* pf )
  439. {
  440. if ( pixel_frame_action_is_recording( pf ) ) {
  441. return;
  442. }
  443. if ( pf->undo_buffer.position == 0 )
  444. {
  445. return;
  446. }
  447. // To undo, we'll transfer an action from the undo buffer into the redo buffer, assuming there is data to be read
  448. // Move position back to read size from buffer
  449. pf->undo_buffer.position -= sizeof(uint32_t);
  450. uint32_t sz;
  451. byte_buffer_read( &pf->undo_buffer, uint32_t, &sz );
  452. // Move back in buffer entire write size now, including size variable
  453. pf->undo_buffer.position -= (sz + sizeof(uint32_t));
  454. // Save current position. We'll use this reset ourselves after applying undo.
  455. uint32_t start_position = pf->undo_buffer.position;
  456. pixel_frame_action_op_code_type op;
  457. byte_buffer_read( &pf->undo_buffer, uint32_t, &op );
  458. switch ( op )
  459. {
  460. case pixel_frame_action_op_write_pixels:
  461. {
  462. const uint32_t num_pixels = (sz - sizeof(uint32_t)) / sizeof(pixel_frame_action_write_t);
  463. // Write op into redo buffer
  464. byte_buffer_write( &pf->redo_buffer, uint32_t, pixel_frame_action_op_write_pixels );
  465. // Write data into redo buffer and reset pixels before action
  466. for ( u32 i = 0; i < num_pixels; ++i )
  467. {
  468. pixel_frame_action_write_t wd;
  469. byte_buffer_read( &pf->undo_buffer, pixel_frame_action_write_t, &wd );
  470. // Compute new delta based on this change
  471. gs_color_t c = pf->pixel_data[ wd.idx ];
  472. u8 r = wd.r;
  473. u8 g = wd.g;
  474. u8 b = wd.b;
  475. u8 a = wd.a;
  476. gs_color_t p;
  477. p.r = ( wd.sign_bits & 0x01 ) ? c.r + r : c.r - r;
  478. p.g = ( wd.sign_bits & 0x02 ) ? c.g + g : c.g - g;
  479. p.b = ( wd.sign_bits & 0x04 ) ? c.b + b : c.b - b;
  480. p.a = ( wd.sign_bits & 0x08 ) ? c.a + a : c.a - a;
  481. pf->pixel_data[ wd.idx ] = p;
  482. // Calculate new delta for redo
  483. wd.sign_bits = 0x0;
  484. wd.sign_bits |= c.r > p.r ? 0x01 : 0x0;
  485. wd.sign_bits |= c.g > p.g ? 0x02 : 0x0;
  486. wd.sign_bits |= c.b > p.b ? 0x04 : 0x0;
  487. wd.sign_bits |= c.a > p.a ? 0x08 : 0x0;
  488. byte_buffer_write( &pf->redo_buffer, pixel_frame_action_write_t, wd );
  489. }
  490. // Write total size into redo buffer
  491. byte_buffer_write( &pf->redo_buffer, uint32_t, sz );
  492. // Set back to position before this action was recorded
  493. pf->undo_buffer.position = start_position;
  494. } break;
  495. default:
  496. {
  497. gs_assert( false );
  498. } break;
  499. }
  500. }
  501. typedef struct texture_t {
  502. uint32_t width;
  503. uint32_t height;
  504. uint32_t num_comps;
  505. void* pixels;
  506. } texture_t;
  507. void pixel_frame_redo_action( pixel_frame_t* pf )
  508. {
  509. if ( pixel_frame_action_is_recording( pf ) ) {
  510. return;
  511. }
  512. if ( pf->redo_buffer.position == 0 )
  513. {
  514. return;
  515. }
  516. // Same as undo
  517. pf->redo_buffer.position -= sizeof(uint32_t);
  518. uint32_t sz;
  519. byte_buffer_read( &pf->redo_buffer, uint32_t, &sz );
  520. // Move back in buffer entire write size now, including size variable
  521. pf->redo_buffer.position -= (sz + sizeof(uint32_t));
  522. // Save current position. We'll use this reset ourselves after applying undo.
  523. uint32_t start_position = pf->redo_buffer.position;
  524. pixel_frame_action_op_code_type op;
  525. byte_buffer_read( &pf->redo_buffer, uint32_t, &op );
  526. switch ( op )
  527. {
  528. case pixel_frame_action_op_write_pixels:
  529. {
  530. const uint32_t num_pixels = (sz - sizeof(uint32_t)) / sizeof(pixel_frame_action_write_t);
  531. // Write op into undo buffer
  532. byte_buffer_write( &pf->undo_buffer, uint32_t, pixel_frame_action_op_write_pixels );
  533. // Write data into redo buffer and reset pixels before action
  534. for ( u32 i = 0; i < num_pixels; ++i )
  535. {
  536. pixel_frame_action_write_t wd;
  537. byte_buffer_read( &pf->redo_buffer, pixel_frame_action_write_t, &wd );
  538. // Compute new delta based on this change
  539. gs_color_t c = pf->pixel_data[ wd.idx ];
  540. u8 r = wd.r;
  541. u8 g = wd.g;
  542. u8 b = wd.b;
  543. u8 a = wd.a;
  544. gs_color_t p;
  545. p.r = ( wd.sign_bits & 0x01 ) ? c.r + r : c.r - r;
  546. p.g = ( wd.sign_bits & 0x02 ) ? c.g + g : c.g - g;
  547. p.b = ( wd.sign_bits & 0x04 ) ? c.b + b : c.b - b;
  548. p.a = ( wd.sign_bits & 0x08 ) ? c.a + a : c.a - a;
  549. pf->pixel_data[ wd.idx ] = p;
  550. // Calculate new delta for redo
  551. wd.sign_bits = 0x0;
  552. wd.sign_bits |= c.r > p.r ? 0x01 : 0x0;
  553. wd.sign_bits |= c.g > p.g ? 0x02 : 0x0;
  554. wd.sign_bits |= c.b > p.b ? 0x04 : 0x0;
  555. wd.sign_bits |= c.a > p.a ? 0x08 : 0x0;
  556. byte_buffer_write( &pf->undo_buffer, pixel_frame_action_write_t, wd );
  557. }
  558. // Write total size into redo buffer
  559. byte_buffer_write( &pf->undo_buffer, uint32_t, sz );
  560. // Set back to position before this action was recorded
  561. pf->redo_buffer.position = start_position;
  562. } break;
  563. default:
  564. {
  565. gs_assert( false );
  566. } break;
  567. }
  568. }
  569. gs_vec2 pixel_frame_calculate_mouse_position( pixel_frame_t* pf, gs_camera* camera )
  570. {
  571. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  572. gs_vec2 ws = platform->window_size( platform->main_window() );
  573. gs_vec2 pmp = platform->mouse_position();
  574. gs_vec3 _tpmp = gs_camera_unproject( camera, (gs_vec3){pmp.x, pmp.y, 0.f}, ws.x, ws.y );
  575. gs_vec2 tpmp = (gs_vec2){_tpmp.x, _tpmp.y};
  576. tpmp.x = tpmp.x * 0.5f + 0.5f;
  577. tpmp.y = tpmp.y * 0.5f + 0.5f;
  578. tpmp.y = gs_map_range( 1.f, 0.f, 0.f, 1.f, tpmp.y );
  579. // Need to place mouse into frame
  580. f32 x_scale = tpmp.x;
  581. f32 y_scale = tpmp.y;
  582. return (gs_vec2){ x_scale * (f32)pf->pixel_frame_width, y_scale * (f32)pf->pixel_frame_height };
  583. }
  584. int32_t pixel_frame_compute_idx_from_position( pixel_frame_t* pf, int32_t x, int32_t y )
  585. {
  586. if ( x >= pf->pixel_frame_width || y >= pf->pixel_frame_height || x < 0 || y < 0 ) {
  587. return -1;
  588. }
  589. return ( y * pf->pixel_frame_width + x );
  590. }
  591. void pixel_frame_draw_pixel( void* data, gs_color_t color, int32_t x, int32_t y )
  592. {
  593. pixel_frame_t* pf = (pixel_frame_t*)data;
  594. if ( x < 0 || x >= pf->pixel_frame_width || y < 0 || y >= pf->pixel_frame_height )
  595. return;
  596. int32_t idx = pixel_frame_compute_idx_from_position( pf, x, y );
  597. if ( idx != -1 ) {
  598. // Get converted color from color picker
  599. gs_color_t c = color;
  600. gs_color_t p = pf->pixel_data[ idx ];
  601. // Compute delta and signs
  602. uint8_t sign_bits = 0x0;
  603. uint8_t r = (uint8_t)abs((int32_t)c.r - (int32_t)p.r);
  604. uint8_t g = (uint8_t)abs((int32_t)c.g - (int32_t)p.g);
  605. uint8_t b = (uint8_t)abs((int32_t)c.b - (int32_t)p.b);
  606. uint8_t a = (uint8_t)abs((int32_t)c.a - (int32_t)p.a);
  607. sign_bits |= c.r < p.r ? 0x01 : 0x0;
  608. sign_bits |= c.g < p.g ? 0x02 : 0x0;
  609. sign_bits |= c.b < p.b ? 0x04 : 0x0;
  610. sign_bits |= c.a < p.a ? 0x08 : 0x0;
  611. pixel_frame_action_write_t wd =
  612. {
  613. (uint16_t)idx,
  614. r, g, b, a,
  615. sign_bits
  616. };
  617. // Only write if there's an actual change
  618. if ( !color_equal( c, p ) ) {
  619. pixel_frame_write_action_op( pf, wd );
  620. pf->pixel_data[ idx ] = color;
  621. }
  622. }
  623. }
  624. void pixel_frame_draw_ui_pixel( void* data, gs_color_t color, int32_t x, int32_t y )
  625. {
  626. pixel_frame_t* pf = (pixel_frame_t*)data;
  627. if ( x >= ui_frame_width || x < 0 || y >= ui_frame_height || y < 0 )
  628. return;
  629. uint32_t idx = y * ui_frame_width + x;
  630. // Get converted color from color picker
  631. gs_color_t c = (gs_color_t){g_nk_color.r * 255, g_nk_color.g * 255, g_nk_color.b * 255, g_nk_color.a * 100};
  632. pf->ui_data[ idx ] = color;
  633. }
  634. void pixel_frame_clear_data( pixel_frame_t* pf )
  635. {
  636. if ( !pixel_frame_action_is_recording( pf ) )
  637. {
  638. // Start record
  639. pixel_frame_action_start_record( pf, pixel_frame_action_op_write_pixels );
  640. const gs_color_t clear_color = (gs_color_t){ 0, 0, 0, 0 };
  641. // Clear all data
  642. for ( uint32_t h = 0; h < pf->pixel_frame_height; ++h ) {
  643. for ( uint32_t w = 0; w < pf->pixel_frame_width; ++w ) {
  644. pixel_frame_draw_pixel( pf, clear_color, w, h );
  645. }
  646. }
  647. // End record
  648. pixel_frame_action_end_record( pf );
  649. }
  650. // memset( pf->pixel_data, 0, pf->pixel_frame_width * pf->pixel_frame_height * sizeof(gs_color_t) );
  651. }
  652. void pixel_frame_save_image_to_disk( pixel_frame_t* pf )
  653. {
  654. if ( pixel_frame_action_is_recording( pf ) ) {
  655. return;
  656. }
  657. // We'll just write it to 'test.bin'
  658. byte_buffer_t buffer = byte_buffer_new();
  659. // Serialize all pixel frame data to disk
  660. for ( uint32_t h = 0; h < pf->pixel_frame_height; ++h )
  661. {
  662. for ( uint32_t w = 0; w < pf->pixel_frame_width; ++w )
  663. {
  664. uint32_t idx = h * pf->pixel_frame_width + w;
  665. byte_buffer_write( &buffer, uint8_t, pf->pixel_data[ idx ].r );
  666. byte_buffer_write( &buffer, uint8_t, pf->pixel_data[ idx ].g );
  667. byte_buffer_write( &buffer, uint8_t, pf->pixel_data[ idx ].b );
  668. byte_buffer_write( &buffer, uint8_t, pf->pixel_data[ idx ].a );
  669. }
  670. }
  671. const char* filter_patterns[] = {
  672. "*.pix"
  673. };
  674. const char* file_name = tinyfd_saveFileDialog(
  675. "Save Image",
  676. "./image.pix",
  677. sizeof(filter_patterns) / sizeof(char*),
  678. filter_patterns,
  679. NULL
  680. );
  681. // Write to file if valid
  682. if ( file_name ) {
  683. byte_buffer_write_to_file( &buffer, file_name );
  684. }
  685. byte_buffer_free( &buffer );
  686. }
  687. void pixel_frame_load_image_from_disk( pixel_frame_t* pf )
  688. {
  689. if ( pixel_frame_action_is_recording( pf ) ) {
  690. return;
  691. }
  692. const char* filter_patterns[] = {
  693. "*.pix", "*.png"
  694. };
  695. const char* file_name = tinyfd_openFileDialog(
  696. "Open Image",
  697. "./",
  698. sizeof(filter_patterns) / sizeof(char*),
  699. filter_patterns,
  700. NULL,
  701. false
  702. );
  703. if ( file_name == NULL ) {
  704. return;
  705. }
  706. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  707. if ( !platform->file_exists( file_name ) ) {
  708. return;
  709. }
  710. char file_ext[256];
  711. gs_util_get_file_extension( file_ext, sizeof(file_ext), file_name );
  712. if ( gs_string_compare_equal( file_ext, "pix" ) )
  713. {
  714. byte_buffer_t buffer = byte_buffer_new();
  715. byte_buffer_read_from_file( &buffer, file_name );
  716. // Serialize all pixel frame data to disk
  717. for ( uint32_t h = 0; h < pf->pixel_frame_height; ++h )
  718. {
  719. for ( uint32_t w = 0; w < pf->pixel_frame_width; ++w )
  720. {
  721. uint32_t idx = h * pf->pixel_frame_width + w;
  722. byte_buffer_read( &buffer, uint8_t, &pf->pixel_data[ idx ].r );
  723. byte_buffer_read( &buffer, uint8_t, &pf->pixel_data[ idx ].g );
  724. byte_buffer_read( &buffer, uint8_t, &pf->pixel_data[ idx ].b );
  725. byte_buffer_read( &buffer, uint8_t, &pf->pixel_data[ idx ].a );
  726. }
  727. }
  728. // Clear out undo/redo buffers
  729. byte_buffer_clear( &pf->undo_buffer );
  730. byte_buffer_clear( &pf->redo_buffer );
  731. byte_buffer_free( &buffer );
  732. }
  733. else if ( gs_string_compare_equal( file_ext, "png" ) )
  734. {
  735. // Need to load in .png and then change size of texture...
  736. }
  737. }
  738. b32 pixel_frame_hovering_ui_window()
  739. {
  740. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  741. gs_vec2 mp = platform->mouse_position();
  742. gs_vec2 ws = platform->window_size(platform->main_window());
  743. uint32_t sw = 250.f;
  744. return mp.x < sw;
  745. }
  746. // Drag/drop texture into frame?
  747. // Save/Load images
  748. // Change colors (might just have a set number of colors - not sure how I'd represent 32 bit colors without some
  749. // complicated gui mechanism)
  750. // Radius for painting
  751. void pixel_frame_update( pixel_frame_t* pf, gs_camera* camera )
  752. {
  753. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  754. b32 need_update = false;
  755. static gs_vec2 original_mouse_position;
  756. b32 alt_down = platform->key_down( gs_keycode_lalt );
  757. b32 space_down = platform->key_down( gs_keycode_space );
  758. gs_vec2 mp = pixel_frame_calculate_mouse_position( pf, camera );
  759. const uint32_t mp_x = (uint32_t)mp.x;
  760. const uint32_t mp_y = pf->pixel_frame_height - (uint32_t)mp.y - 1;
  761. const int32_t idx = pixel_frame_compute_idx_from_position( pf, mp_x, mp_y );
  762. // Painting operation
  763. if ( platform->mouse_down( gs_mouse_lbutton ) && !pixel_frame_hovering_ui_window() )
  764. {
  765. if ( !alt_down && !space_down )
  766. {
  767. if ( !pf->mouse_down ) {
  768. pf->mouse_down = true;
  769. // Start recording
  770. pixel_frame_action_start_record( pf, pixel_frame_action_op_write_pixels );
  771. }
  772. if ( idx != -1 ) {
  773. // Get converted color from color picker
  774. gs_color_t col = (gs_color_t){g_nk_color.r * 255, g_nk_color.g * 255, g_nk_color.b * 255, g_nk_color.a * 255};
  775. if ( pf->paint_radius > 1 ) {
  776. circleBres( pf, col, true, mp.x, pf->pixel_frame_height - mp.y, pf->paint_radius, &pixel_frame_draw_pixel );
  777. } else {
  778. pixel_frame_draw_pixel( pf, col, mp_x, mp_y );
  779. }
  780. }
  781. }
  782. // Color picking
  783. else if ( alt_down )
  784. {
  785. if ( idx != -1 ) {
  786. gs_color_t c = pf->pixel_data[ idx ];
  787. g_nk_color.r = (f32)c.r / 255.f;
  788. g_nk_color.g = (f32)c.g / 255.f;
  789. g_nk_color.b = (f32)c.b / 255.f;
  790. g_nk_color.a = (f32)c.a / 255.f;
  791. }
  792. }
  793. // Camera pan
  794. else if ( space_down )
  795. {
  796. pan_camera();
  797. }
  798. }
  799. // Need to record actions here
  800. if ( platform->mouse_released( gs_mouse_lbutton ) )
  801. {
  802. // Start recording
  803. pixel_frame_action_end_record( pf );
  804. pf->mouse_down = false;
  805. }
  806. // Paint radius
  807. if ( platform->key_pressed( gs_keycode_lbracket ) )
  808. {
  809. pf->paint_radius = gs_max( (int32_t)1, (int32_t)pf->paint_radius - 1 );
  810. }
  811. if ( platform->key_pressed( gs_keycode_rbracket ) )
  812. {
  813. pf->paint_radius = gs_min( 20, pf->paint_radius + 1 );
  814. }
  815. if ( platform->key_down( gs_keycode_lctrl ) && platform->key_pressed( gs_keycode_z ) )
  816. {
  817. pixel_frame_undo_action( pf );
  818. }
  819. if ( platform->key_down( gs_keycode_lctrl ) && platform->key_pressed( gs_keycode_y ) )
  820. {
  821. pixel_frame_redo_action( pf );
  822. }
  823. if ( platform->key_down( gs_keycode_lctrl ) && platform->key_pressed( gs_keycode_s ) )
  824. {
  825. pixel_frame_save_image_to_disk( pf );
  826. }
  827. if ( platform->key_down( gs_keycode_lctrl ) && platform->key_pressed( gs_keycode_o ) )
  828. {
  829. pixel_frame_load_image_from_disk( pf );
  830. }
  831. if ( platform->key_pressed( gs_keycode_c ) )
  832. {
  833. pixel_frame_clear_data( pf );
  834. }
  835. // Update GPU texture data
  836. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  837. gs_texture_parameter_desc desc = pixel_frame_texture_parameter_desc();
  838. desc.width = pf->pixel_frame_width;
  839. desc.height = pf->pixel_frame_height;
  840. desc.data = pf->pixel_data;
  841. gfx->update_texture_data( pf->texture, desc );
  842. // Draw ui into buffer
  843. memset( pf->ui_data, 0, ui_frame_width * ui_frame_height * sizeof(gs_color_t) );
  844. const gs_color_t col = (gs_color_t){ (u8)g_nk_color.r * 255, (u8)g_nk_color.g * 255, (u8)g_nk_color.b * 255, 50 };
  845. gs_vec2 ws = platform->window_size(platform->main_window());
  846. gs_vec2 m_pos = platform->mouse_position();
  847. f32 scl_x = m_pos.x / ws.x;
  848. f32 scl_y = m_pos.y / ws.y;
  849. if ( pf->paint_radius > 0 )
  850. {
  851. circleBres( pf, col, false, mp.x, ui_frame_height - mp.y, pf->paint_radius, &pixel_frame_draw_ui_pixel );
  852. }
  853. desc = pixel_frame_texture_parameter_desc();
  854. desc.width = ui_frame_width;
  855. desc.height = ui_frame_height;
  856. desc.data = pf->ui_data;
  857. gfx->update_texture_data( pf->ui_texture, desc );
  858. }
  859. void pixel_frame_render( pixel_frame_t* pf, gs_resource( gs_command_buffer ) cb, gs_camera* camera )
  860. {
  861. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  862. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  863. gs_vec2 ws = platform->window_size(platform->main_window());
  864. gs_mat4 proj_mtx = gs_camera_get_projection( camera, ws.x, ws.y );
  865. gs_mat4 view_mtx = gs_camera_get_view( camera );
  866. f32 clear_color[4] = { 0.5f, 0.5f, 0.5f, 1.f };
  867. gfx->set_view_clear( cb, clear_color );
  868. // Bind shader
  869. gfx->bind_shader( cb, pf->shader );
  870. gfx->bind_uniform( cb, pf->u_proj, &proj_mtx );
  871. gfx->bind_uniform( cb, pf->u_view, &view_mtx );
  872. // Render background texture
  873. gfx->bind_texture( cb, pf->u_tex, pf->bg_texture, 0 );
  874. gfx->bind_vertex_buffer( cb, pf->vbo );
  875. gfx->bind_index_buffer( cb, pf->ibo );
  876. gfx->draw_indexed( cb, 6, 0 );
  877. // Render paint texture
  878. gfx->bind_texture( cb, pf->u_tex, pf->texture, 0 );
  879. gfx->bind_vertex_buffer( cb, pf->vbo );
  880. gfx->bind_index_buffer( cb, pf->ibo );
  881. gfx->draw_indexed( cb, 6, 0 );
  882. // Render ui texture
  883. gfx->bind_texture( cb, pf->u_tex, pf->ui_texture, 0 );
  884. gfx->bind_vertex_buffer( cb, pf->vbo );
  885. gfx->bind_index_buffer( cb, pf->ibo );
  886. gfx->draw_indexed( cb, 6, 0 );
  887. }
  888. //================================================================
  889. // Globals
  890. _global gs_resource( gs_command_buffer ) g_cb = {0};
  891. _global pixel_frame_t g_pixel_frame = {0};
  892. _global b32 g_app_running = true;
  893. _global gs_camera g_camera = {0};
  894. // Forward Decls.
  895. gs_result app_init(); // Use to init your application
  896. gs_result app_update(); // Use to update your application
  897. gs_result app_shutdown(); // Use to shutdown your appliaction
  898. void app_close_window_callback( void* window )
  899. {
  900. g_app_running = false;
  901. }
  902. typedef struct test_t
  903. {
  904. u32 unsigned_val;
  905. s32 signed_val;
  906. f32 float_val;
  907. f64 double_val;
  908. } test_t;
  909. void print_test( test_t* t )
  910. {
  911. gs_println( "test: { %zu, %d, %.2f, %.5f }",
  912. t->unsigned_val, t->signed_val, t->float_val, t->double_val );
  913. }
  914. int main( int argc, char** argv )
  915. {
  916. gs_application_desc app = {0};
  917. app.window_title = "Serialization Example";
  918. app.window_width = 1200;
  919. app.window_height = 600;
  920. app.init = &app_init;
  921. app.update = &app_update;
  922. app.shutdown = &app_shutdown;
  923. // Construct internal instance of our engine
  924. gs_engine* engine = gs_engine_construct( app );
  925. // Run the internal engine loop until completion
  926. gs_result res = engine->run();
  927. // Check result of engine after exiting loop
  928. if ( res != gs_result_success )
  929. {
  930. gs_println( "Error: Engine did not successfully finish running." );
  931. return -1;
  932. }
  933. gs_println( "Gunslinger exited successfully." );
  934. return 0;
  935. }
  936. void byte_buffer_test()
  937. {
  938. test_t t0 = {0};
  939. t0.unsigned_val = 5;
  940. t0.signed_val = -20;
  941. t0.float_val = -3.145f;
  942. t0.double_val = 2.37854;
  943. byte_buffer_t buffer = byte_buffer_new();
  944. // Serialize our test data structure into our buffer
  945. byte_buffer_write( &buffer, uint32_t, t0.unsigned_val );
  946. byte_buffer_write( &buffer, int32_t, t0.signed_val );
  947. byte_buffer_write( &buffer, float, t0.float_val );
  948. byte_buffer_write( &buffer, double, t0.double_val );
  949. // Seek back to beginning
  950. byte_buffer_seek_to_beg( &buffer );
  951. // Read values into our new test data
  952. test_t t1 = {0};
  953. byte_buffer_read( &buffer, uint32_t, &t1.unsigned_val );
  954. byte_buffer_read( &buffer, int32_t, &t1.signed_val );
  955. byte_buffer_read( &buffer, float, &t1.float_val );
  956. byte_buffer_read( &buffer, double, &t1.double_val );
  957. print_test( &t1 );
  958. // Write to file
  959. byte_buffer_write_to_file( &buffer, "./test.bin" );
  960. // Read back from file
  961. byte_buffer_read_from_file( &buffer, "./test.bin" );
  962. // Read back into new object
  963. test_t t2 = {0};
  964. // Read back entire object from memory
  965. byte_buffer_read( &buffer, uint32_t, &t2.unsigned_val );
  966. byte_buffer_read( &buffer, int32_t, &t2.signed_val );
  967. byte_buffer_read( &buffer, float, &t2.float_val );
  968. byte_buffer_read( &buffer, double, &t2.double_val );
  969. print_test( &t2 );
  970. // Clean up byte buffer memory
  971. byte_buffer_free( &buffer );
  972. }
  973. // Here, we'll initialize all of our application data, which in this case is our graphics resources
  974. gs_result app_init()
  975. {
  976. // Cache instance of graphics/platform apis from engine
  977. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  978. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  979. // Set callback for when window close button is pressed
  980. platform->set_window_close_callback( platform->main_window(), &app_close_window_callback );
  981. byte_buffer_test();
  982. g_pixel_frame = pixel_frame_new();
  983. // This is a descriptor for our texture. It includes various metrics, such as the width, height, texture format,
  984. // and holds the actual uncompressed texture data for the texture. After using it for loading a raw texture
  985. // from file, it's the responsibility of the user to free the data.
  986. gs_texture_parameter_desc desc = gs_texture_parameter_desc_default();
  987. // Construct command buffer ( the command buffer is used to allow for immediate drawing at any point in our program )
  988. g_cb = gfx->construct_command_buffer();
  989. // Construct camera parameters
  990. g_camera.transform = gs_vqs_default();
  991. g_camera.transform.position = (gs_vec3){-1.f, 0.f, -1.f};
  992. g_camera.fov = 60.f;
  993. g_camera.near_plane = 0.1f;
  994. g_camera.far_plane = 1000.f;
  995. g_camera.ortho_scale = 2.f;
  996. g_camera.proj_type = gs_projection_type_orthographic;
  997. nk_init_ui();
  998. return gs_result_success;
  999. }
  1000. gs_result app_update()
  1001. {
  1002. // Grab global instance of engine
  1003. gs_engine* engine = gs_engine_instance();
  1004. // Platform api
  1005. gs_platform_i* platform = engine->ctx.platform;
  1006. // Main window size
  1007. gs_vec2 ws = platform->window_size( platform->main_window() );
  1008. gs_vec2 fbs = platform->frame_buffer_size( platform->main_window() );
  1009. // If we press the escape key, exit the application
  1010. if ( platform->key_pressed( gs_keycode_esc ) || !g_app_running )
  1011. {
  1012. return gs_result_success;
  1013. }
  1014. const f32 dt = platform->time.delta;
  1015. const f32 t = platform->elapsed_time();
  1016. /*=================
  1017. // Camera controls
  1018. ==================*/
  1019. if ( platform->key_down( gs_keycode_q ) ) {
  1020. g_camera.ortho_scale += 0.1f;
  1021. }
  1022. if ( platform->key_down( gs_keycode_e ) ) {
  1023. g_camera.ortho_scale -= 0.1f;
  1024. }
  1025. if (platform->key_down(gs_keycode_a)) {
  1026. g_camera.transform.position.x -= 0.1f;
  1027. }
  1028. if (platform->key_down(gs_keycode_d)) {
  1029. g_camera.transform.position.x += 0.1f;
  1030. }
  1031. if (platform->key_down(gs_keycode_w)) {
  1032. g_camera.transform.position.y += 0.1f;
  1033. }
  1034. if (platform->key_down(gs_keycode_s)) {
  1035. g_camera.transform.position.y -= 0.1f;
  1036. }
  1037. if ( platform->mouse_down( gs_mouse_mbutton ) )
  1038. {
  1039. // Need to transform the camera's position by the transformation of the mouse in world space only...I think
  1040. gs_vec2 md = platform->mouse_delta();
  1041. gs_vec2 mc = platform->mouse_position();
  1042. gs_vec3 wc = (gs_vec3){mc.x, mc.y, 0.f};
  1043. gs_vec3 pmp = gs_camera_unproject( &g_camera, wc, ws.x, ws.y );
  1044. gs_vec3 pmp_d = gs_camera_unproject( &g_camera, (gs_vec3){mc.x + md.x, mc.y + md.y, 0.f}, ws.x, ws.y );
  1045. gs_vec3 delta = gs_vec3_sub( pmp, pmp_d );
  1046. g_camera.transform.position.x += delta.x;
  1047. g_camera.transform.position.y += delta.y;
  1048. }
  1049. f32 mwx, mwy;
  1050. platform->mouse_wheel( &mwx, &mwy );
  1051. g_camera.ortho_scale = gs_clamp( g_camera.ortho_scale - mwy * 0.2f, 0.2f, 10.f );
  1052. /*===============
  1053. // Update scene
  1054. ================*/
  1055. pixel_frame_update( &g_pixel_frame, &g_camera );
  1056. /*===============
  1057. // Render scene
  1058. ================*/
  1059. // Graphics api instance
  1060. gs_graphics_i* gfx = engine->ctx.graphics;
  1061. // Set clear color and clear screen
  1062. f32 clear_color[4] = { 0.1f, 0.1f, 0.1f, 1.f };
  1063. gfx->set_view_clear( g_cb, clear_color );
  1064. gfx->set_view_port( g_cb, fbs.x, fbs.y );
  1065. gfx->set_depth_enabled( g_cb, false );
  1066. gfx->set_blend_mode( g_cb, gs_blend_mode_src_alpha, gs_blend_mode_one_minus_src_alpha );
  1067. pixel_frame_render( &g_pixel_frame, g_cb, &g_camera );
  1068. // Submit command buffer for rendering
  1069. gfx->submit_command_buffer( g_cb );
  1070. // Handle ui
  1071. nk_do_ui( &g_pixel_frame );
  1072. return gs_result_in_progress;
  1073. }
  1074. gs_result app_shutdown()
  1075. {
  1076. gs_println( "Goodbye, Gunslinger." );
  1077. return gs_result_success;
  1078. }
  1079. void pan_camera()
  1080. {
  1081. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  1082. gs_vec2 ws = platform->window_size( platform->main_window() );
  1083. gs_vec2 md = platform->mouse_delta();
  1084. gs_vec2 mc = platform->mouse_position();
  1085. gs_vec3 wc = (gs_vec3){mc.x, mc.y, 0.f};
  1086. gs_vec3 pmp = gs_camera_unproject( &g_camera, wc, ws.x, ws.y );
  1087. gs_vec3 pmp_d = gs_camera_unproject( &g_camera, (gs_vec3){mc.x + md.x, mc.y + md.y, 0.f}, ws.x, ws.y );
  1088. gs_vec3 delta = gs_vec3_sub( pmp, pmp_d );
  1089. g_camera.transform.position.x += delta.x;
  1090. g_camera.transform.position.y += delta.y;
  1091. }
  1092. void nk_init_ui()
  1093. {
  1094. g_nk_color = (struct nk_colorf){0.f, 0.f, 0.f, 1.f};
  1095. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  1096. GLFWwindow* win = platform->raw_window_handle( platform->main_window() );
  1097. g_nk_ctx = nk_glfw3_init(&g_nk_glfw, win, 0);
  1098. struct nk_font_atlas* atlas;
  1099. nk_glfw3_font_stash_begin(&g_nk_glfw, &atlas);
  1100. nk_glfw3_font_stash_end(&g_nk_glfw);
  1101. }
  1102. void nk_do_ui( struct pixel_frame_t* pf )
  1103. {
  1104. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  1105. gs_vec2 ws = platform->window_size(platform->main_window());
  1106. // Do the ui stuff
  1107. nk_glfw3_new_frame(&g_nk_glfw);
  1108. /* GUI */
  1109. if (nk_begin(g_nk_ctx, "Demo", nk_rect(0, 0, 250, ws.y), NK_WINDOW_BORDER))
  1110. {
  1111. nk_layout_row_dynamic(g_nk_ctx, 20, 1);
  1112. nk_label(g_nk_ctx, "Color", NK_TEXT_LEFT);
  1113. {
  1114. nk_layout_row_dynamic(g_nk_ctx, 120, 1);
  1115. g_nk_color = nk_color_picker(g_nk_ctx, g_nk_color, NK_RGBA);
  1116. nk_layout_row_dynamic(g_nk_ctx, 25, 1);
  1117. g_nk_color.r = nk_propertyf(g_nk_ctx, "#R:", 0, g_nk_color.r, 1.0f, 0.01f,0.005f);
  1118. g_nk_color.g = nk_propertyf(g_nk_ctx, "#G:", 0, g_nk_color.g, 1.0f, 0.01f,0.005f);
  1119. g_nk_color.b = nk_propertyf(g_nk_ctx, "#B:", 0, g_nk_color.b, 1.0f, 0.01f,0.005f);
  1120. g_nk_color.a = nk_propertyf(g_nk_ctx, "#A:", 0, g_nk_color.a, 1.0f, 0.01f,0.005f);
  1121. }
  1122. // nk_layout_row_begin( g_nk_ctx, NK_STATIC, 2, 3 );
  1123. {
  1124. g_pixel_frame.paint_radius = nk_propertyi(g_nk_ctx, "Paint Radius", 0, g_pixel_frame.paint_radius, 20, 1, 0.8f);
  1125. // nk_layout_row_static(g_nk_ctx, 30, 80, 1);
  1126. if (nk_button_label(g_nk_ctx, "Save"))
  1127. {
  1128. pixel_frame_save_image_to_disk( pf );
  1129. }
  1130. // nk_layout_row_static(g_nk_ctx, 30, 80, 1);
  1131. if (nk_button_label(g_nk_ctx, "Load"))
  1132. {
  1133. pixel_frame_load_image_from_disk( pf );
  1134. }
  1135. }
  1136. // nk_layout_row_end( g_nk_ctx );
  1137. }
  1138. nk_end(g_nk_ctx);
  1139. nk_glfw3_render(&g_nk_glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
  1140. }