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