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