review save method
[carveJwlIkooP6JGAAIwe30JlM.git] / render.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #include "common.h"
6 #include "model.h"
7 #include "camera.h"
8 #include "world.h"
9
10 #include "shaders/blit.h"
11 #include "shaders/blitblur.h"
12 #include "shaders/blitcolour.h"
13
14 #define WORKSHOP_PREVIEW_WIDTH 504
15 #define WORKSHOP_PREVIEW_HEIGHT 336
16 #ifndef RENDER_H
17 #define RENDER_H
18
19 static f32 k_render_scale = 1.0f;
20 static i32 k_blur_effect = 1;
21 static f32 k_blur_strength = 0.3f;
22 static f32 k_fov = 0.86f;
23
24 typedef struct framebuffer framebuffer;
25
26 /*
27 * All standard buffers used in rendering
28 */
29 VG_STATIC struct pipeline{
30 glmesh fsquad;
31
32 framebuffer *fb_main,
33 *fb_water_reflection,
34 *fb_water_beneath,
35 *fb_workshop_preview;
36 int ready;
37 }
38 gpipeline;
39
40 struct framebuffer{
41 const char *display_name;
42 int resolution_div, /* definition */
43 fixed_w,
44 fixed_h,
45
46 render_w, /* runtime */
47 render_h;
48
49 struct framebuffer_attachment{
50 const char *display_name;
51
52 enum framebuffer_attachment_type{
53 k_framebuffer_attachment_type_none,
54 k_framebuffer_attachment_type_texture,
55 k_framebuffer_attachment_type_renderbuffer,
56 k_framebuffer_attachment_type_texture_depth
57 }
58 purpose;
59
60 enum framebuffer_quality_profile{
61 k_framebuffer_quality_all,
62 k_framebuffer_quality_high_only
63 }
64 quality;
65
66 GLenum internalformat,
67 format,
68 type,
69 attachment;
70
71 GLuint id;
72
73 /* Runtime */
74 int debug_view;
75 }
76 attachments[5];
77 GLuint fb;
78 framebuffer **link;
79 }
80 framebuffers[] =
81 {
82 {
83 /*
84 * The primary draw target
85 */
86 "main",
87 .link = &gpipeline.fb_main,
88 .resolution_div = 1,
89 .attachments =
90 {
91 {
92 "colour", k_framebuffer_attachment_type_texture,
93
94 .internalformat = GL_RGB,
95 .format = GL_RGB,
96 .type = GL_UNSIGNED_BYTE,
97 .attachment = GL_COLOR_ATTACHMENT0
98 },
99 {
100 "motion", k_framebuffer_attachment_type_texture,
101
102 .quality = k_framebuffer_quality_high_only,
103 .internalformat = GL_RG16F,
104 .format = GL_RG,
105 .type = GL_FLOAT,
106 .attachment = GL_COLOR_ATTACHMENT1
107 },
108 {
109 #if 0
110 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
111
112 .internalformat = GL_DEPTH24_STENCIL8,
113 #else
114 "depth_stencil", k_framebuffer_attachment_type_texture_depth,
115 .internalformat = GL_DEPTH24_STENCIL8,
116 .format = GL_DEPTH_STENCIL,
117 .type = GL_UNSIGNED_INT_24_8,
118 #endif
119 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
120 }
121 }
122 },
123 {
124 /*
125 * Second rendered view from the perspective of the water reflection
126 */
127 "water_reflection",
128 .link = &gpipeline.fb_water_reflection,
129 .resolution_div = 2,
130 .attachments =
131 {
132 {
133 "colour", k_framebuffer_attachment_type_texture,
134 .internalformat = GL_RGB,
135 .format = GL_RGB,
136 .type = GL_UNSIGNED_BYTE,
137 .attachment = GL_COLOR_ATTACHMENT0
138 },
139 {
140 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
141
142 .internalformat = GL_DEPTH24_STENCIL8,
143 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
144 }
145 }
146 },
147 {
148 /*
149 * Thid rendered view from the perspective of the camera, but just
150 * captures stuff thats under the water
151 */
152 "water_beneath",
153 .link = &gpipeline.fb_water_beneath,
154 .resolution_div = 2,
155 .attachments =
156 {
157 {
158 "colour", k_framebuffer_attachment_type_texture,
159 .internalformat = GL_RED,
160 .format = GL_RED,
161 .type = GL_UNSIGNED_BYTE,
162 .attachment = GL_COLOR_ATTACHMENT0
163 },
164 {
165 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
166
167 .internalformat = GL_DEPTH24_STENCIL8,
168 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
169 }
170 }
171 },
172 {
173 "workshop_preview",
174 .link = &gpipeline.fb_workshop_preview,
175 .resolution_div = 0,
176 .fixed_w = WORKSHOP_PREVIEW_WIDTH, .fixed_h = WORKSHOP_PREVIEW_HEIGHT,
177 .attachments =
178 {
179 {
180 "colour", k_framebuffer_attachment_type_texture,
181 .internalformat = GL_RGB,
182 .format = GL_RGB,
183 .type = GL_UNSIGNED_BYTE,
184 .attachment = GL_COLOR_ATTACHMENT0
185 },
186 {
187 "depth_stencil", k_framebuffer_attachment_type_renderbuffer,
188 .internalformat = GL_DEPTH24_STENCIL8,
189 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
190 }
191 }
192 }
193 };
194
195 /*
196 * Get the current (automatically scaled or fixed) resolution of framebuffer
197 */
198 VG_STATIC void render_fb_get_current_res( struct framebuffer *fb,
199 int *x, int *y )
200 {
201 if( fb->resolution_div ){
202 *x = vg.window_x / fb->resolution_div;
203 *y = vg.window_y / fb->resolution_div;
204 }
205 else{
206 *x = fb->fixed_w;
207 *y = fb->fixed_h;
208 }
209 }
210
211 VG_STATIC void render_fb_inverse_ratio( framebuffer *fb, v2f inverse )
212 {
213 if( fb ){
214 int x, y;
215 render_fb_get_current_res( fb, &x, &y );
216
217 v2f render = { fb->render_w, fb->render_h },
218 original = { x, y };
219
220 v2_div( render, original, inverse );
221 }
222 else{
223 v2_div( (v2f){1.0f,1.0f}, (v2f){ vg.window_x, vg.window_y }, inverse );
224 }
225 }
226
227 /*
228 * Bind framebuffer for drawing to
229 */
230 VG_STATIC void render_fb_bind( framebuffer *fb, int use_scaling )
231 {
232 int x, y;
233 render_fb_get_current_res( fb, &x, &y );
234
235 if( use_scaling ){
236 x = k_render_scale*(float)x;
237 y = k_render_scale*(float)y;
238
239 x = VG_MAX( 16, x );
240 y = VG_MAX( 16, y );
241
242 fb->render_w = x;
243 fb->render_h = y;
244 }
245
246 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
247 glViewport( 0, 0, x, y );
248 }
249
250 /*
251 * Bind framebuffer attachment's texture
252 */
253 VG_STATIC void render_fb_bind_texture( framebuffer *fb,
254 int attachment, int slot )
255 {
256 struct framebuffer_attachment *at = &fb->attachments[attachment];
257
258 if( (at->purpose != k_framebuffer_attachment_type_texture) &&
259 (at->purpose != k_framebuffer_attachment_type_texture_depth) )
260 {
261 vg_fatal_error( "illegal operation: bind non-texture framebuffer"
262 " attachment to texture slot" );
263 }
264
265 glActiveTexture( GL_TEXTURE0 + slot );
266 glBindTexture( GL_TEXTURE_2D, fb->attachments[attachment].id );
267 }
268
269
270 /*
271 * Shaders
272 */
273
274 #define FB_FORMAT_STR( E ) { E, #E },
275
276 /*
277 * Convert OpenGL attachment ID enum to string
278 */
279 VG_STATIC const char *render_fb_attachment_str( GLenum e )
280 {
281 struct { GLenum e; const char *str; }
282 formats[] =
283 {
284 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0)
285 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1)
286 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2)
287 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3)
288 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4)
289 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT)
290 };
291
292 for( int i=0; i<vg_list_size(formats); i++ )
293 if( formats[i].e == e )
294 return formats[i].str;
295
296 return "UNDEFINED";
297 }
298
299 /*
300 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
301 * RenderBufferStorage Table 1, into strings
302 */
303 VG_STATIC const char *render_fb_format_str( GLenum format )
304 {
305 struct { GLenum e; const char *str; }
306 formats[] =
307 {
308 /* Table 1 */
309 FB_FORMAT_STR(GL_DEPTH_COMPONENT)
310 FB_FORMAT_STR(GL_DEPTH_STENCIL)
311 FB_FORMAT_STR(GL_RED)
312 FB_FORMAT_STR(GL_RG)
313 FB_FORMAT_STR(GL_RGB)
314 FB_FORMAT_STR(GL_RGBA)
315
316 /* Render buffer formats */
317 FB_FORMAT_STR(GL_DEPTH_COMPONENT16)
318 FB_FORMAT_STR(GL_DEPTH_COMPONENT24)
319 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F)
320 FB_FORMAT_STR(GL_DEPTH24_STENCIL8)
321 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8)
322 FB_FORMAT_STR(GL_STENCIL_INDEX8)
323
324 /* Table 2 */
325 FB_FORMAT_STR(GL_R8)
326 FB_FORMAT_STR(GL_R8_SNORM)
327 FB_FORMAT_STR(GL_R16)
328 FB_FORMAT_STR(GL_R16_SNORM)
329 FB_FORMAT_STR(GL_RG8)
330 FB_FORMAT_STR(GL_RG8_SNORM)
331 FB_FORMAT_STR(GL_RG16)
332 FB_FORMAT_STR(GL_RG16_SNORM)
333 FB_FORMAT_STR(GL_R3_G3_B2)
334 FB_FORMAT_STR(GL_RGB4)
335 FB_FORMAT_STR(GL_RGB5)
336 FB_FORMAT_STR(GL_RGB8)
337 FB_FORMAT_STR(GL_RGB8_SNORM)
338 FB_FORMAT_STR(GL_RGB10)
339 FB_FORMAT_STR(GL_RGB12)
340 FB_FORMAT_STR(GL_RGB16_SNORM)
341 FB_FORMAT_STR(GL_RGBA2)
342 FB_FORMAT_STR(GL_RGBA4)
343 FB_FORMAT_STR(GL_RGB5_A1)
344 FB_FORMAT_STR(GL_RGBA8)
345 FB_FORMAT_STR(GL_RGBA8_SNORM)
346 FB_FORMAT_STR(GL_RGB10_A2)
347 FB_FORMAT_STR(GL_RGB10_A2UI)
348 FB_FORMAT_STR(GL_RGBA12)
349 FB_FORMAT_STR(GL_RGBA16)
350 FB_FORMAT_STR(GL_SRGB8)
351 FB_FORMAT_STR(GL_SRGB8_ALPHA8)
352 FB_FORMAT_STR(GL_R16F)
353 FB_FORMAT_STR(GL_RG16F)
354 FB_FORMAT_STR(GL_RGB16F)
355 FB_FORMAT_STR(GL_RGBA16F)
356 FB_FORMAT_STR(GL_R32F)
357 FB_FORMAT_STR(GL_RG32F)
358 FB_FORMAT_STR(GL_RGB32F)
359 FB_FORMAT_STR(GL_RGBA32F)
360 FB_FORMAT_STR(GL_R11F_G11F_B10F)
361 FB_FORMAT_STR(GL_RGB9_E5)
362 FB_FORMAT_STR(GL_R8I)
363 FB_FORMAT_STR(GL_R8UI)
364 FB_FORMAT_STR(GL_R16I)
365 FB_FORMAT_STR(GL_R16UI)
366 FB_FORMAT_STR(GL_R32I)
367 FB_FORMAT_STR(GL_R32UI)
368 FB_FORMAT_STR(GL_RG8I)
369 FB_FORMAT_STR(GL_RG8UI)
370 FB_FORMAT_STR(GL_RG16I)
371 FB_FORMAT_STR(GL_RG16UI)
372 FB_FORMAT_STR(GL_RG32I)
373 FB_FORMAT_STR(GL_RG32UI)
374 FB_FORMAT_STR(GL_RGB8I)
375 FB_FORMAT_STR(GL_RGB8UI)
376 FB_FORMAT_STR(GL_RGB16I)
377 FB_FORMAT_STR(GL_RGB16UI)
378 FB_FORMAT_STR(GL_RGB32I)
379 FB_FORMAT_STR(GL_RGB32UI)
380 FB_FORMAT_STR(GL_RGBA8I)
381 FB_FORMAT_STR(GL_RGBA8UI)
382 FB_FORMAT_STR(GL_RGBA16I)
383 FB_FORMAT_STR(GL_RGBA16UI)
384 FB_FORMAT_STR(GL_RGBA32I)
385 FB_FORMAT_STR(GL_RGBA32UI)
386 };
387
388 for( int i=0; i<vg_list_size(formats); i++ )
389 if( formats[i].e == format )
390 return formats[i].str;
391
392 return "UNDEFINED";
393 }
394
395 /*
396 * Bind and allocate texture for framebuffer attachment
397 */
398 VG_STATIC void render_fb_allocate_texture( struct framebuffer *fb,
399 struct framebuffer_attachment *a )
400 {
401 int rx, ry;
402 render_fb_get_current_res( fb, &rx, &ry );
403
404 if( a->purpose == k_framebuffer_attachment_type_renderbuffer ){
405 glBindRenderbuffer( GL_RENDERBUFFER, a->id );
406 glRenderbufferStorage( GL_RENDERBUFFER, a->internalformat, rx, ry );
407 }
408 else if( a->purpose == k_framebuffer_attachment_type_texture ||
409 a->purpose == k_framebuffer_attachment_type_texture_depth )
410 {
411 glBindTexture( GL_TEXTURE_2D, a->id );
412 glTexImage2D( GL_TEXTURE_2D, 0, a->internalformat, rx, ry,
413 0, a->format, a->type, NULL );
414 }
415 }
416
417 /*
418 * Full allocation of a framebuffer
419 */
420 VG_STATIC void render_fb_allocate( struct framebuffer *fb )
421 {
422 glGenFramebuffers( 1, &fb->fb );
423 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
424
425 int rx, ry;
426 render_fb_get_current_res( fb, &rx, &ry );
427
428 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry );
429 vg_info( "{\n" );
430
431 GLenum colour_attachments[4];
432 u32 colour_count = 0;
433
434 for( int j=0; j<vg_list_size(fb->attachments); j++ ){
435 struct framebuffer_attachment *attachment = &fb->attachments[j];
436
437 if( attachment->purpose == k_framebuffer_attachment_type_none )
438 continue;
439
440 vg_info( " %s: %s\n",
441 render_fb_attachment_str( attachment->attachment ),
442 render_fb_format_str( attachment->internalformat ) );
443
444 if( attachment->purpose == k_framebuffer_attachment_type_renderbuffer ){
445 glGenRenderbuffers( 1, &attachment->id );
446 render_fb_allocate_texture( fb, attachment );
447 glFramebufferRenderbuffer( GL_FRAMEBUFFER,
448 GL_DEPTH_STENCIL_ATTACHMENT,
449 GL_RENDERBUFFER, attachment->id );
450 }
451 else if( attachment->purpose == k_framebuffer_attachment_type_texture ||
452 attachment->purpose == k_framebuffer_attachment_type_texture_depth )
453 {
454 glGenTextures( 1, &attachment->id );
455 render_fb_allocate_texture( fb, attachment );
456 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
457 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
458 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
459 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
460
461 glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment,
462 GL_TEXTURE_2D, attachment->id, 0 );
463
464 if( attachment->purpose == k_framebuffer_attachment_type_texture )
465 colour_attachments[ colour_count ++ ] = attachment->attachment;
466 }
467 }
468
469 glDrawBuffers( colour_count, colour_attachments );
470
471 /*
472 * Check result
473 */
474 GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER );
475
476 if( result == GL_FRAMEBUFFER_COMPLETE ){
477 /*
478 * Attatch to gpipeline
479 */
480 if( fb->link )
481 *fb->link = fb;
482
483 vg_success( " status: complete\n" );
484 vg_info( "}\n" );
485 }
486 else{
487 if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
488 vg_error( " status: Incomplete attachment" );
489 else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
490 vg_error( " status: Missing attachment" );
491 else if( result == GL_FRAMEBUFFER_UNSUPPORTED )
492 vg_error( " status: Unsupported framebuffer format" );
493 else
494 vg_error( " status: Generic Error" );
495
496 vg_info( "}\n" );
497 vg_fatal_error( "Incomplete framebuffer (see logs)" );
498 }
499 }
500
501 /*
502 * Resize/Update all framebuffers(we know about)
503 */
504 VG_STATIC void render_fb_resize(void)
505 {
506 if( !gpipeline.ready ) return;
507
508 for( int i=0; i<vg_list_size(framebuffers); i++ ){
509 struct framebuffer *fb = &framebuffers[i];
510 for( int j=0; j<vg_list_size(fb->attachments); j++ ){
511 struct framebuffer_attachment *attachment = &fb->attachments[j];
512 render_fb_allocate_texture( fb, attachment );
513 }
514 }
515 }
516
517 VG_STATIC int render_framebuffer_control( int argc, char const *argv[] );
518 VG_STATIC void render_framebuffer_poll( int argc, char const *argv[] );
519
520 VG_STATIC void async_render_init( void *payload, u32 size )
521 {
522 /*
523 * Complete Framebuffers
524 */
525 for( int i=0; i<vg_list_size(framebuffers); i++ ){
526 struct framebuffer *fb = &framebuffers[i];
527 render_fb_allocate( fb );
528 }
529
530 f32 rh = 0x1p-4f, ih = 0.3f;
531
532 float quad[] = {
533 0.00f,0.00f, 1.00f,1.00f, 0.00f,1.00f, /* fsquad */
534 0.00f,0.00f, 1.00f,0.00f, 1.00f,1.00f,
535
536 0.00f,0.00f, 1.00f,rh, 0.00f,rh, /* fsquad1 */
537 0.00f,0.00f, 1.00f,0.00f, 1.00f,rh,
538
539 /* 9x9 debug grid */
540 /* row0 */
541 0.00f,0.00f, 0.30f,0.30f, 0.00f,0.30f,
542 0.00f,0.00f, 0.30f,0.00f, 0.30f,0.30f,
543 0.30f,0.00f, 0.60f,0.30f, 0.30f,0.30f,
544 0.30f,0.00f, 0.60f,0.00f, 0.60f,0.30f,
545 0.60f,0.00f, 0.90f,0.30f, 0.60f,0.30f,
546 0.60f,0.00f, 0.90f,0.00f, 0.90f,0.30f,
547 /* row1 */
548 0.00f,0.30f, 0.30f,0.60f, 0.00f,0.60f,
549 0.00f,0.30f, 0.30f,0.30f, 0.30f,0.60f,
550 0.30f,0.30f, 0.60f,0.60f, 0.30f,0.60f,
551 0.30f,0.30f, 0.60f,0.30f, 0.60f,0.60f,
552 0.60f,0.30f, 0.90f,0.60f, 0.60f,0.60f,
553 0.60f,0.30f, 0.90f,0.30f, 0.90f,0.60f,
554 /* row2 */
555 0.00f,0.60f, 0.30f,0.90f, 0.00f,0.90f,
556 0.00f,0.60f, 0.30f,0.60f, 0.30f,0.90f,
557 0.30f,0.60f, 0.60f,0.90f, 0.30f,0.90f,
558 0.30f,0.60f, 0.60f,0.60f, 0.60f,0.90f,
559 0.60f,0.60f, 0.90f,0.90f, 0.60f,0.90f,
560 0.60f,0.60f, 0.90f,0.60f, 0.90f,0.90f,
561
562 0.00f,ih, 1.00f,ih+rh, 0.00f,ih+rh, /* fsquad2 */
563 0.00f,ih, 1.00f,ih, 1.00f,ih+rh,
564 };
565
566 vg_console_reg_cmd( "fb", render_framebuffer_control,
567 render_framebuffer_poll );
568 glGenVertexArrays( 1, &gpipeline.fsquad.vao );
569 glGenBuffers( 1, &gpipeline.fsquad.vbo );
570 glBindVertexArray( gpipeline.fsquad.vao );
571 glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo );
572 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
573 glBindVertexArray( gpipeline.fsquad.vao );
574 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
575 sizeof(float)*2, (void*)0 );
576 glEnableVertexAttribArray( 0 );
577
578 VG_CHECK_GL_ERR();
579
580 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
581 gpipeline.ready = 1;
582 }
583
584 VG_STATIC void render_init(void)
585 {
586 vg_console_reg_var( "blur_strength", &k_blur_strength, k_var_dtype_f32, 0 );
587 vg_console_reg_var( "render_scale", &k_render_scale,
588 k_var_dtype_f32, VG_VAR_PERSISTENT );
589 vg_console_reg_var( "fov", &k_fov, k_var_dtype_f32, VG_VAR_PERSISTENT );
590 vg_console_reg_var( "blur_effect", &k_blur_effect,
591 k_var_dtype_i32, VG_VAR_PERSISTENT );
592
593
594 shader_blit_register();
595 shader_blitblur_register();
596 shader_blitcolour_register();
597
598 vg_async_call( async_render_init, NULL, 0 );
599 }
600
601 /*
602 * Utility
603 */
604 VG_STATIC void render_fsquad(void)
605 {
606 glBindVertexArray( gpipeline.fsquad.vao );
607 glDrawArrays( GL_TRIANGLES, 0, 6 );
608 }
609
610 VG_STATIC void render_fsquad1(void)
611 {
612 glBindVertexArray( gpipeline.fsquad.vao );
613 glDrawArrays( GL_TRIANGLES, 6, 6 );
614 }
615
616 VG_STATIC void render_fsquad2(void)
617 {
618 glBindVertexArray( gpipeline.fsquad.vao );
619 glDrawArrays( GL_TRIANGLES, 66,6 );
620 }
621
622 /*
623 * Call this inside the UI function
624 */
625 VG_STATIC void render_view_framebuffer_ui(void)
626 {
627 #if 0
628 int viewing_count = 0;
629
630 glBindVertexArray( gpipeline.fsquad.vao );
631 shader_blit_use();
632 shader_blit_uTexMain( 0 );
633
634 v2f identity = { 1.0f, 1.0f };
635 shader_blit_uInverseRatio( identity );
636
637 for( int i=0; i<vg_list_size(framebuffers); i++ ){
638 struct framebuffer *fb = &framebuffers[i];
639
640 for( int j=0; j<vg_list_size(fb->attachments); j++ ){
641 struct framebuffer_attachment *at = &fb->attachments[j];
642
643 if( !at->debug_view )
644 continue;
645
646 v2f corner,
647 window = { vg.window_x, vg.window_y };
648
649 corner[0] = viewing_count % 3;
650 corner[1] = 1 + (viewing_count / 3);
651 v2_mul( corner, window, corner );
652 v2_muls( corner, 0.3f, corner );
653 corner[1] = vg.window_y - corner[1];
654
655 ui_text( (ui_rect){ corner[0], corner[1], 0.0f, 0.0f },
656 fb->display_name, 2, k_text_align_left );
657 ui_text( (ui_rect){ corner[0], corner[1] + 32, 0.0f, 0.0f, },
658 at->display_name, 1, k_text_align_left );
659
660 if( at->purpose == k_framebuffer_attachment_type_renderbuffer ){
661 v2f center;
662 v2_muladds( corner, window, 0.15f, center );
663
664 ui_text( (ui_rect){ center[0], center[1], 0.0f, 0.0f },
665 "<hardware texture>", 1, k_text_align_center );
666 }
667 else{
668 render_fb_bind_texture( fb, j, 0 );
669
670 int start = (viewing_count+2) * 6,
671 count = 6;
672 glDrawArrays( GL_TRIANGLES, start, count );
673 }
674
675 viewing_count ++;
676 }
677 }
678 #endif
679 }
680
681 VG_STATIC void render_framebuffer_show( struct framebuffer *fb,
682 struct framebuffer_attachment *at,
683 int operation )
684 {
685 at->debug_view = operation;
686 vg_info( "%s %s:%s\n", (operation?"shown": "hidden"),
687 fb->display_name, at->display_name );
688 }
689
690 /*
691 * arg0: command "show"/"hide"
692 * arg1: framebuffer name <name>/"all"
693 * arg2: subname <name>/none
694 */
695 VG_STATIC int render_framebuffer_control( int argc, char const *argv[] )
696 {
697 if( argc < 2 ){
698 vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
699 return 0;
700 }
701
702 int modify_all = 0,
703 operation = 0;
704
705 if( !strcmp( argv[0], "show" ) )
706 operation = 1;
707 else if( !strcmp( argv[0], "hide" ) )
708 operation = 0;
709 else{
710 vg_error( "Unknown framebuffer operation: '%s'\n", argv[0] );
711 return 0;
712 }
713
714 if( !strcmp( argv[1], "all" ) )
715 modify_all = 1;
716
717 for( int i=0; i<vg_list_size(framebuffers); i++ ){
718 struct framebuffer *fb = &framebuffers[i];
719
720 for( int j=0; j<vg_list_size(fb->attachments); j++ ){
721 struct framebuffer_attachment *at = &fb->attachments[j];
722
723 if( at->purpose == k_framebuffer_attachment_type_none )
724 continue;
725
726 if( modify_all ){
727 render_framebuffer_show( fb, at, operation );
728 }
729 else{
730 if( !strcmp( fb->display_name, argv[1] ) ){
731 if( argc == 2 )
732 render_framebuffer_show( fb, at, operation );
733 else if( !strcmp( at->display_name, argv[2] ) )
734 render_framebuffer_show( fb, at, operation );
735 }
736 }
737 }
738 }
739
740 return 0;
741 }
742
743 VG_STATIC void render_framebuffer_poll( int argc, char const *argv[] )
744 {
745 const char *term = argv[argc-1];
746
747 if( argc == 1 ){
748 console_suggest_score_text( "show", term, 0 );
749 console_suggest_score_text( "hide", term, 0 );
750 }
751 else if( argc == 2 ){
752 console_suggest_score_text( "all", term, 0 );
753
754 for( int i=0; i<vg_list_size(framebuffers); i++ ){
755 struct framebuffer *fb = &framebuffers[i];
756 console_suggest_score_text( fb->display_name, term, 0 );
757 }
758 }
759 else if( argc == 3 ){
760 int modify_all = 0;
761
762 if( !strcmp( argv[1], "all" ) )
763 modify_all = 1;
764
765 for( int i=0; i<vg_list_size(framebuffers); i++ ){
766 struct framebuffer *fb = &framebuffers[i];
767
768 for( int j=0; j<vg_list_size(fb->attachments); j++ ){
769 struct framebuffer_attachment *at = &fb->attachments[j];
770
771 if( at->purpose == k_framebuffer_attachment_type_none )
772 continue;
773
774 if( modify_all ){
775 console_suggest_score_text( at->display_name, term, 0 );
776 }
777 else if( !strcmp( fb->display_name, argv[1] ) ){
778 console_suggest_score_text( at->display_name, term, 0 );
779 }
780 }
781 }
782 }
783 }
784
785 #endif /* RENDER_H */