2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 #include "shaders/blit.h"
11 #include "shaders/blitblur.h"
12 #include "shaders/blitcolour.h"
15 #include "shaders/standard.h"
16 #include "shaders/vblend.h"
19 VG_STATIC
void render_water_texture( world_instance
*world
, camera
*cam
);
20 VG_STATIC
void render_water_surface( world_instance
*world
, camera
*cam
);
21 VG_STATIC
void render_world( world_instance
*world
, camera
*cam
);
22 VG_STATIC
void render_world_depth( world_instance
*world
, camera
*cam
);
27 typedef struct framebuffer framebuffer
;
31 * All standard buffers used in rendering
33 VG_STATIC
struct pipeline
49 float shadow_spread
, shadow_length
;
59 .colour
= { 1.36f
, 1.35f
, 1.01f
},
60 .dir
= { 0.63f
, -0.08f
}
64 .colour
= { 0.33f
, 0.56f
, 0.64f
},
65 .dir
= { -2.60f
, -0.13f
}
69 .colour
= { 0.05f
, 0.05f
, 0.23f
},
70 .dir
= { 2.60f
, -0.84f
}
73 .shadow_spread
= 0.65f
,
74 .shadow_length
= 9.50f
,
79 const char *display_name
;
84 struct framebuffer_attachment
86 const char *display_name
;
88 enum framebuffer_attachment_type
90 k_framebuffer_attachment_type_none
,
91 k_framebuffer_attachment_type_colour
,
92 k_framebuffer_attachment_type_renderbuffer
96 enum framebuffer_quality_profile
98 k_framebuffer_quality_all
,
99 k_framebuffer_quality_high_only
103 GLenum internalformat
,
121 * The primary draw target
124 .link
= &gpipeline
.fb_main
,
129 "colour", k_framebuffer_attachment_type_colour
,
131 .internalformat
= GL_RGB
,
133 .type
= GL_UNSIGNED_BYTE
,
134 .attachment
= GL_COLOR_ATTACHMENT0
137 "motion", k_framebuffer_attachment_type_colour
,
139 .quality
= k_framebuffer_quality_high_only
,
140 .internalformat
= GL_RG16F
,
143 .attachment
= GL_COLOR_ATTACHMENT1
146 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
148 .internalformat
= GL_DEPTH24_STENCIL8
,
149 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
155 * Second rendered view from the perspective of the water reflection
158 .link
= &gpipeline
.fb_water_reflection
,
163 "colour", k_framebuffer_attachment_type_colour
,
164 .internalformat
= GL_RGB
,
166 .type
= GL_UNSIGNED_BYTE
,
167 .attachment
= GL_COLOR_ATTACHMENT0
170 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
172 .internalformat
= GL_DEPTH24_STENCIL8
,
173 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
179 * Thid rendered view from the perspective of the camera, but just
180 * captures stuff thats under the water
183 .link
= &gpipeline
.fb_water_beneath
,
188 "colour", k_framebuffer_attachment_type_colour
,
189 .internalformat
= GL_RGBA
,
191 .type
= GL_UNSIGNED_BYTE
,
192 .attachment
= GL_COLOR_ATTACHMENT0
195 "depth_stencil", k_framebuffer_attachment_type_renderbuffer
,
197 .internalformat
= GL_DEPTH24_STENCIL8
,
198 .attachment
= GL_DEPTH_STENCIL_ATTACHMENT
205 * Get the current (automatically scaled or fixed) resolution of framebuffer
207 VG_STATIC
void render_fb_get_current_res( struct framebuffer
*fb
,
210 if( fb
->resolution_div
)
212 *x
= vg
.window_x
/ fb
->resolution_div
;
213 *y
= vg
.window_y
/ fb
->resolution_div
;
223 * Bind framebuffer for drawing to
225 VG_STATIC
void render_fb_bind( framebuffer
*fb
)
228 render_fb_get_current_res( fb
, &x
, &y
);
229 glBindFramebuffer( GL_FRAMEBUFFER
, fb
->fb
);
230 glViewport( 0, 0, x
, y
);
234 * Bind framebuffer attachment's texture
236 VG_STATIC
void render_fb_bind_texture( framebuffer
*fb
,
237 int attachment
, int slot
)
239 struct framebuffer_attachment
*at
= &fb
->attachments
[attachment
];
241 if( at
->purpose
!= k_framebuffer_attachment_type_colour
)
243 vg_fatal_exit_loop( "illegal operation: bind non-colour framebuffer"
244 " attachment to texture slot" );
247 glActiveTexture( GL_TEXTURE0
+ slot
);
248 glBindTexture( GL_TEXTURE_2D
, fb
->attachments
[attachment
].id
);
256 #define FB_FORMAT_STR( E ) { E, #E },
259 * Convert OpenGL attachment ID enum to string
261 VG_STATIC
const char *render_fb_attachment_str( GLenum e
)
263 struct { GLenum e
; const char *str
; }
266 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0
)
267 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1
)
268 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2
)
269 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3
)
270 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4
)
271 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT
)
274 for( int i
=0; i
<vg_list_size(formats
); i
++ )
275 if( formats
[i
].e
== e
)
276 return formats
[i
].str
;
282 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
283 * RenderBufferStorage Table 1, into strings
285 VG_STATIC
const char *render_fb_format_str( GLenum format
)
287 struct { GLenum e
; const char *str
; }
291 FB_FORMAT_STR(GL_DEPTH_COMPONENT
)
292 FB_FORMAT_STR(GL_DEPTH_STENCIL
)
293 FB_FORMAT_STR(GL_RED
)
295 FB_FORMAT_STR(GL_RGB
)
296 FB_FORMAT_STR(GL_RGBA
)
298 /* Render buffer formats */
299 FB_FORMAT_STR(GL_DEPTH_COMPONENT16
)
300 FB_FORMAT_STR(GL_DEPTH_COMPONENT24
)
301 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F
)
302 FB_FORMAT_STR(GL_DEPTH24_STENCIL8
)
303 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8
)
304 FB_FORMAT_STR(GL_STENCIL_INDEX8
)
308 FB_FORMAT_STR(GL_R8_SNORM
)
309 FB_FORMAT_STR(GL_R16
)
310 FB_FORMAT_STR(GL_R16_SNORM
)
311 FB_FORMAT_STR(GL_RG8
)
312 FB_FORMAT_STR(GL_RG8_SNORM
)
313 FB_FORMAT_STR(GL_RG16
)
314 FB_FORMAT_STR(GL_RG16_SNORM
)
315 FB_FORMAT_STR(GL_R3_G3_B2
)
316 FB_FORMAT_STR(GL_RGB4
)
317 FB_FORMAT_STR(GL_RGB5
)
318 FB_FORMAT_STR(GL_RGB8
)
319 FB_FORMAT_STR(GL_RGB8_SNORM
)
320 FB_FORMAT_STR(GL_RGB10
)
321 FB_FORMAT_STR(GL_RGB12
)
322 FB_FORMAT_STR(GL_RGB16_SNORM
)
323 FB_FORMAT_STR(GL_RGBA2
)
324 FB_FORMAT_STR(GL_RGBA4
)
325 FB_FORMAT_STR(GL_RGB5_A1
)
326 FB_FORMAT_STR(GL_RGBA8
)
327 FB_FORMAT_STR(GL_RGBA8_SNORM
)
328 FB_FORMAT_STR(GL_RGB10_A2
)
329 FB_FORMAT_STR(GL_RGB10_A2UI
)
330 FB_FORMAT_STR(GL_RGBA12
)
331 FB_FORMAT_STR(GL_RGBA16
)
332 FB_FORMAT_STR(GL_SRGB8
)
333 FB_FORMAT_STR(GL_SRGB8_ALPHA8
)
334 FB_FORMAT_STR(GL_R16F
)
335 FB_FORMAT_STR(GL_RG16F
)
336 FB_FORMAT_STR(GL_RGB16F
)
337 FB_FORMAT_STR(GL_RGBA16F
)
338 FB_FORMAT_STR(GL_R32F
)
339 FB_FORMAT_STR(GL_RG32F
)
340 FB_FORMAT_STR(GL_RGB32F
)
341 FB_FORMAT_STR(GL_RGBA32F
)
342 FB_FORMAT_STR(GL_R11F_G11F_B10F
)
343 FB_FORMAT_STR(GL_RGB9_E5
)
344 FB_FORMAT_STR(GL_R8I
)
345 FB_FORMAT_STR(GL_R8UI
)
346 FB_FORMAT_STR(GL_R16I
)
347 FB_FORMAT_STR(GL_R16UI
)
348 FB_FORMAT_STR(GL_R32I
)
349 FB_FORMAT_STR(GL_R32UI
)
350 FB_FORMAT_STR(GL_RG8I
)
351 FB_FORMAT_STR(GL_RG8UI
)
352 FB_FORMAT_STR(GL_RG16I
)
353 FB_FORMAT_STR(GL_RG16UI
)
354 FB_FORMAT_STR(GL_RG32I
)
355 FB_FORMAT_STR(GL_RG32UI
)
356 FB_FORMAT_STR(GL_RGB8I
)
357 FB_FORMAT_STR(GL_RGB8UI
)
358 FB_FORMAT_STR(GL_RGB16I
)
359 FB_FORMAT_STR(GL_RGB16UI
)
360 FB_FORMAT_STR(GL_RGB32I
)
361 FB_FORMAT_STR(GL_RGB32UI
)
362 FB_FORMAT_STR(GL_RGBA8I
)
363 FB_FORMAT_STR(GL_RGBA8UI
)
364 FB_FORMAT_STR(GL_RGBA16I
)
365 FB_FORMAT_STR(GL_RGBA16UI
)
366 FB_FORMAT_STR(GL_RGBA32I
)
367 FB_FORMAT_STR(GL_RGBA32UI
)
370 for( int i
=0; i
<vg_list_size(formats
); i
++ )
371 if( formats
[i
].e
== format
)
372 return formats
[i
].str
;
378 * Bind and allocate texture for framebuffer attachment
380 VG_STATIC
void render_fb_allocate_texture( struct framebuffer
*fb
,
381 struct framebuffer_attachment
*a
)
384 render_fb_get_current_res( fb
, &rx
, &ry
);
386 if( a
->purpose
== k_framebuffer_attachment_type_renderbuffer
)
388 glBindRenderbuffer( GL_RENDERBUFFER
, a
->id
);
389 glRenderbufferStorage( GL_RENDERBUFFER
, GL_DEPTH24_STENCIL8
, rx
, ry
);
391 else if( a
->purpose
== k_framebuffer_attachment_type_colour
)
393 glBindTexture( GL_TEXTURE_2D
, a
->id
);
394 glTexImage2D( GL_TEXTURE_2D
, 0, a
->internalformat
, rx
, ry
,
395 0, a
->format
, a
->type
, NULL
);
400 * Full allocation of a framebuffer
402 VG_STATIC
void render_fb_allocate( struct framebuffer
*fb
)
404 glGenFramebuffers( 1, &fb
->fb
);
405 glBindFramebuffer( GL_FRAMEBUFFER
, fb
->fb
);
408 render_fb_get_current_res( fb
, &rx
, &ry
);
410 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb
->display_name
, rx
, ry
);
413 GLenum colour_attachments
[4];
414 u32 colour_count
= 0;
416 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ )
418 struct framebuffer_attachment
*attachment
= &fb
->attachments
[j
];
420 if( attachment
->purpose
== k_framebuffer_attachment_type_none
)
423 vg_info( " %s: %s\n",
424 render_fb_attachment_str( attachment
->attachment
),
425 render_fb_format_str( attachment
->internalformat
) );
427 if( attachment
->purpose
== k_framebuffer_attachment_type_renderbuffer
)
429 glGenRenderbuffers( 1, &attachment
->id
);
430 render_fb_allocate_texture( fb
, attachment
);
431 glFramebufferRenderbuffer( GL_FRAMEBUFFER
,
432 GL_DEPTH_STENCIL_ATTACHMENT
,
433 GL_RENDERBUFFER
, attachment
->id
);
435 else if( attachment
->purpose
== k_framebuffer_attachment_type_colour
)
437 glGenTextures( 1, &attachment
->id
);
438 render_fb_allocate_texture( fb
, attachment
);
439 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
440 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
441 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
442 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
444 glFramebufferTexture2D( GL_FRAMEBUFFER
, attachment
->attachment
,
445 GL_TEXTURE_2D
, attachment
->id
, 0 );
447 colour_attachments
[ colour_count
++ ] = attachment
->attachment
;
451 glDrawBuffers( colour_count
, colour_attachments
);
456 GLenum result
= glCheckFramebufferStatus( GL_FRAMEBUFFER
);
458 if( result
== GL_FRAMEBUFFER_COMPLETE
)
461 * Attatch to gpipeline
466 vg_success( " status: complete\n" );
471 if( result
== GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
)
472 vg_error( " status: Incomplete attachment" );
473 else if( result
== GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
)
474 vg_error( " status: Missing attachment" );
475 else if( result
== GL_FRAMEBUFFER_UNSUPPORTED
)
476 vg_error( " status: Unsupported framebuffer format" );
478 vg_error( " status: Generic Error" );
481 vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" );
486 * Resize/Update all framebuffers(we know about)
488 VG_STATIC
void render_fb_resize(void)
490 if( !gpipeline
.ready
)
493 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ )
495 struct framebuffer
*fb
= &framebuffers
[i
];
496 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ )
498 struct framebuffer_attachment
*attachment
= &fb
->attachments
[j
];
499 render_fb_allocate_texture( fb
, attachment
);
504 VG_STATIC
int render_framebuffer_control( int argc
, char const *argv
[] );
505 VG_STATIC
void render_framebuffer_poll( int argc
, char const *argv
[] );
506 VG_STATIC
void render_init_fs_quad(void)
508 vg_info( "[render] Allocate quad\n" );
512 0.00f
,0.00f
, 1.00f
,1.00f
, 0.00f
,1.00f
,
513 0.00f
,0.00f
, 1.00f
,0.00f
, 1.00f
,1.00f
,
515 0.20f
,0.00f
, 0.80f
,1.00f
, 0.20f
,1.00f
,
516 0.20f
,0.00f
, 0.80f
,0.00f
, 0.80f
,1.00f
,
520 0.00f
,0.00f
, 0.30f
,0.30f
, 0.00f
,0.30f
,
521 0.00f
,0.00f
, 0.30f
,0.00f
, 0.30f
,0.30f
,
522 0.30f
,0.00f
, 0.60f
,0.30f
, 0.30f
,0.30f
,
523 0.30f
,0.00f
, 0.60f
,0.00f
, 0.60f
,0.30f
,
524 0.60f
,0.00f
, 0.90f
,0.30f
, 0.60f
,0.30f
,
525 0.60f
,0.00f
, 0.90f
,0.00f
, 0.90f
,0.30f
,
527 0.00f
,0.30f
, 0.30f
,0.60f
, 0.00f
,0.60f
,
528 0.00f
,0.30f
, 0.30f
,0.30f
, 0.30f
,0.60f
,
529 0.30f
,0.30f
, 0.60f
,0.60f
, 0.30f
,0.60f
,
530 0.30f
,0.30f
, 0.60f
,0.30f
, 0.60f
,0.60f
,
531 0.60f
,0.30f
, 0.90f
,0.60f
, 0.60f
,0.60f
,
532 0.60f
,0.30f
, 0.90f
,0.30f
, 0.90f
,0.60f
,
534 0.00f
,0.60f
, 0.30f
,0.90f
, 0.00f
,0.90f
,
535 0.00f
,0.60f
, 0.30f
,0.60f
, 0.30f
,0.90f
,
536 0.30f
,0.60f
, 0.60f
,0.90f
, 0.30f
,0.90f
,
537 0.30f
,0.60f
, 0.60f
,0.60f
, 0.60f
,0.90f
,
538 0.60f
,0.60f
, 0.90f
,0.90f
, 0.60f
,0.90f
,
539 0.60f
,0.60f
, 0.90f
,0.60f
, 0.90f
,0.90f
,
542 vg_function_push( (struct vg_cmd
)
545 .function
= render_framebuffer_control
,
546 .poll_suggest
= render_framebuffer_poll
549 glGenVertexArrays( 1, &gpipeline
.fsquad
.vao
);
550 glGenBuffers( 1, &gpipeline
.fsquad
.vbo
);
551 glBindVertexArray( gpipeline
.fsquad
.vao
);
552 glBindBuffer( GL_ARRAY_BUFFER
, gpipeline
.fsquad
.vbo
);
553 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
554 glBindVertexArray( gpipeline
.fsquad
.vao
);
555 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
556 sizeof(float)*2, (void*)0 );
557 glEnableVertexAttribArray( 0 );
562 VG_STATIC
void render_init(void)
564 shader_blit_register();
565 shader_blitblur_register();
566 shader_blitcolour_register();
568 vg_acquire_thread_sync();
571 * Complete Framebuffers
573 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ )
575 struct framebuffer
*fb
= &framebuffers
[i
];
576 render_fb_allocate( fb
);
579 render_init_fs_quad();
581 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
585 vg_release_thread_sync();
591 VG_STATIC
void render_fsquad(void)
593 glBindVertexArray( gpipeline
.fsquad
.vao
);
594 glDrawArrays( GL_TRIANGLES
, 0, 6 );
597 VG_STATIC
void render_fsquad1(void)
599 glBindVertexArray( gpipeline
.fsquad
.vao
);
600 glDrawArrays( GL_TRIANGLES
, 6, 6 );
604 * Call this inside the UI function
606 VG_STATIC
void render_view_framebuffer_ui(void)
608 int viewing_count
= 0;
610 glBindVertexArray( gpipeline
.fsquad
.vao
);
612 shader_blit_uTexMain( 0 );
614 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ )
616 struct framebuffer
*fb
= &framebuffers
[i
];
618 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ )
620 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
622 if( !at
->debug_view
)
626 window
= { vg
.window_x
, vg
.window_y
};
628 corner
[0] = viewing_count
% 3;
629 corner
[1] = 1 + (viewing_count
/ 3);
630 v2_mul( corner
, window
, corner
);
631 v2_muls( corner
, 0.3f
, corner
);
632 corner
[1] = vg
.window_y
- corner
[1];
634 ui_text( (ui_rect
){ corner
[0], corner
[1], 0.0f
, 0.0f
},
635 fb
->display_name
, 2, k_text_align_left
);
636 ui_text( (ui_rect
){ corner
[0], corner
[1] + 32, 0.0f
, 0.0f
, },
637 at
->display_name
, 1, k_text_align_left
);
639 if( at
->purpose
== k_framebuffer_attachment_type_renderbuffer
)
642 v2_muladds( corner
, window
, 0.15f
, center
);
644 ui_text( (ui_rect
){ center
[0], center
[1], 0.0f
, 0.0f
},
645 "<hardware texture>", 1, k_text_align_center
);
649 render_fb_bind_texture( fb
, j
, 0 );
651 int start
= (viewing_count
+2) * 6,
653 glDrawArrays( GL_TRIANGLES
, start
, count
);
661 VG_STATIC
void render_framebuffer_show( struct framebuffer
*fb
,
662 struct framebuffer_attachment
*at
,
665 at
->debug_view
= operation
;
666 vg_info( "%s %s:%s\n", (operation
?"shown": "hidden"),
667 fb
->display_name
, at
->display_name
);
671 * arg0: command "show"/"hide"
672 * arg1: framebuffer name <name>/"all"
673 * arg2: subname <name>/none
675 VG_STATIC
int render_framebuffer_control( int argc
, char const *argv
[] )
679 vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
686 if( !strcmp( argv
[0], "show" ) )
688 else if( !strcmp( argv
[0], "hide" ) )
692 vg_error( "Unknown framebuffer operation: '%s'\n", argv
[0] );
696 if( !strcmp( argv
[1], "all" ) )
699 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ )
701 struct framebuffer
*fb
= &framebuffers
[i
];
703 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ )
705 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
707 if( at
->purpose
== k_framebuffer_attachment_type_none
)
712 render_framebuffer_show( fb
, at
, operation
);
716 if( !strcmp( fb
->display_name
, argv
[1] ) )
719 render_framebuffer_show( fb
, at
, operation
);
720 else if( !strcmp( at
->display_name
, argv
[2] ) )
721 render_framebuffer_show( fb
, at
, operation
);
730 VG_STATIC
void render_framebuffer_poll( int argc
, char const *argv
[] )
732 const char *term
= argv
[argc
-1];
736 console_suggest_score_text( "show", term
, 0 );
737 console_suggest_score_text( "hide", term
, 0 );
741 console_suggest_score_text( "all", term
, 0 );
743 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ )
745 struct framebuffer
*fb
= &framebuffers
[i
];
746 console_suggest_score_text( fb
->display_name
, term
, 0 );
753 if( !strcmp( argv
[1], "all" ) )
756 for( int i
=0; i
<vg_list_size(framebuffers
); i
++ )
758 struct framebuffer
*fb
= &framebuffers
[i
];
760 for( int j
=0; j
<vg_list_size(fb
->attachments
); j
++ )
762 struct framebuffer_attachment
*at
= &fb
->attachments
[j
];
764 if( at
->purpose
== k_framebuffer_attachment_type_none
)
769 console_suggest_score_text( at
->display_name
, term
, 0 );
771 else if( !strcmp( fb
->display_name
, argv
[1] ) )
773 console_suggest_score_text( at
->display_name
, term
, 0 );
780 #endif /* RENDER_H */