framebuffer formalitites
[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
9 #include "shaders/blit.h"
10 #include "shaders/blitblur.h"
11 #include "shaders/standard.h"
12 #include "shaders/vblend.h"
13
14 VG_STATIC void render_water_texture( camera *cam );
15 VG_STATIC void render_water_surface( camera *cam );
16 VG_STATIC void render_world( camera *cam );
17 VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id );
18 VG_STATIC void render_world_depth( camera *cam );
19
20 #ifndef RENDER_H
21 #define RENDER_H
22
23 typedef struct framebuffer framebuffer;
24
25
26 /*
27 * All standard buffers used in rendering
28 */
29 VG_STATIC struct pipeline
30 {
31 glmesh fsquad;
32
33 framebuffer *fb_main,
34 *fb_heightmap,
35 *fb_water_reflection,
36 *fb_water_beneath;
37
38 /* STD140 */
39 struct ub_world_lighting
40 {
41 /* v3f (padded) */
42 v4f g_light_colours[3],
43 g_light_directions[3],
44 g_ambient_colour;
45
46 v4f g_water_plane,
47 g_depth_bounds;
48
49 float g_water_fog;
50 int g_light_count;
51 int g_light_preview;
52 int g_shadow_samples;
53 }
54 ub_world_lighting;
55
56 struct light_widget
57 {
58 int enabled;
59 v2f dir;
60 v3f colour;
61 }
62 widgets[3];
63
64 float shadow_spread, shadow_length;
65 GLuint ubo_world_lighting,
66 ubo_world;
67
68 int ready;
69 }
70 gpipeline =
71 {
72 .widgets =
73 {
74 {
75 .enabled = 1,
76 .colour = { 1.36f, 1.35f, 1.01f },
77 .dir = { 0.63f, -0.08f }
78 },
79 {
80 .enabled = 1,
81 .colour = { 0.33f, 0.56f, 0.64f },
82 .dir = { -2.60f, -0.13f }
83 },
84 {
85 .enabled = 1,
86 .colour = { 0.05f, 0.05f, 0.23f },
87 .dir = { 2.60f, -0.84f }
88 }
89 },
90 .shadow_spread = 0.65f,
91 .shadow_length = 9.50f,
92
93 .ub_world_lighting =
94 {
95 .g_ambient_colour = { 0.09f, 0.03f, 0.07f }
96 }
97 };
98
99 struct framebuffer
100 {
101 const char *display_name;
102 int resolution_div,
103 fixed_w,
104 fixed_h;
105
106 struct framebuffer_attachment
107 {
108 const char *display_name;
109
110 enum framebuffer_attachment_type
111 {
112 k_framebuffer_attachment_type_none,
113 k_framebuffer_attachment_type_colour,
114 k_framebuffer_attachment_type_renderbuffer
115 }
116 purpose;
117
118 enum framebuffer_quality_profile
119 {
120 k_framebuffer_quality_all,
121 k_framebuffer_quality_high_only
122 }
123 quality;
124
125 GLenum internalformat,
126 format,
127 type,
128 attachment;
129
130 GLuint id;
131 }
132 attachments[5];
133 GLuint fb;
134 framebuffer **link;
135 }
136 framebuffers[] =
137 {
138 {
139 /*
140 * The primary draw target
141 */
142 "Main",
143 .link = &gpipeline.fb_main,
144 .resolution_div = 1,
145 .attachments =
146 {
147 {
148 "Colour", k_framebuffer_attachment_type_colour,
149
150 .internalformat = GL_RGB,
151 .format = GL_RGB,
152 .type = GL_UNSIGNED_BYTE,
153 .attachment = GL_COLOR_ATTACHMENT0
154 },
155 {
156 "Motion Vectors", k_framebuffer_attachment_type_colour,
157
158 .quality = k_framebuffer_quality_high_only,
159 .internalformat = GL_RG16F,
160 .format = GL_RG,
161 .type = GL_FLOAT,
162 .attachment = GL_COLOR_ATTACHMENT1
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 /*
174 * A ortho projection of the world, used for shadows and ocean colouring.
175 * Note: it does not have a render buffer attachement because it's
176 * intended to be drawn to in a MAX blending mode
177 */
178 "Heightmap",
179 .link = &gpipeline.fb_heightmap,
180 .fixed_w = 1024,
181 .fixed_h = 1024,
182
183 .attachments =
184 {
185 {
186 "Depth", k_framebuffer_attachment_type_colour,
187
188 .internalformat = GL_R32F,
189 .format = GL_RED,
190 .type = GL_FLOAT,
191 .attachment = GL_COLOR_ATTACHMENT0
192 }
193 }
194 },
195 {
196 /*
197 * Second rendered view from the perspective of the water reflection
198 */
199 "Water reflection",
200 .link = &gpipeline.fb_water_reflection,
201 .resolution_div = 3,
202 .attachments =
203 {
204 {
205 "Colour", k_framebuffer_attachment_type_colour,
206 .internalformat = GL_RGB,
207 .format = GL_RGB,
208 .type = GL_UNSIGNED_BYTE,
209 .attachment = GL_COLOR_ATTACHMENT0
210 },
211 {
212 "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
213
214 .internalformat = GL_DEPTH24_STENCIL8,
215 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
216 }
217 }
218 },
219 {
220 /*
221 * Thid rendered view from the perspective of the camera, but just
222 * captures stuff thats under the water
223 */
224 "Water Beneath",
225 .link = &gpipeline.fb_water_beneath,
226 .resolution_div = 4,
227 .attachments =
228 {
229 {
230 "Colour", k_framebuffer_attachment_type_colour,
231 .internalformat = GL_RGBA,
232 .format = GL_RGBA,
233 .type = GL_UNSIGNED_BYTE,
234 .attachment = GL_COLOR_ATTACHMENT0
235 },
236 {
237 "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
238
239 .internalformat = GL_DEPTH24_STENCIL8,
240 .attachment = GL_DEPTH_STENCIL_ATTACHMENT
241 }
242 }
243 }
244 };
245
246 /*
247 * Get the current (automatically scaled or fixed) resolution of framebuffer
248 */
249 VG_STATIC void render_fb_get_current_res( struct framebuffer *fb,
250 int *x, int *y )
251 {
252 if( fb->resolution_div )
253 {
254 *x = vg.window_x / fb->resolution_div;
255 *y = vg.window_y / fb->resolution_div;
256 }
257 else
258 {
259 *x = fb->fixed_w;
260 *y = fb->fixed_h;
261 }
262 }
263
264 /*
265 * Bind framebuffer for drawing to
266 */
267 VG_STATIC void render_fb_bind( framebuffer *fb )
268 {
269 int x, y;
270 render_fb_get_current_res( fb, &x, &y );
271 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
272 glViewport( 0, 0, x, y );
273 }
274
275 /*
276 * Bind framebuffer attachment's texture
277 */
278 VG_STATIC void render_fb_bind_texture( framebuffer *fb,
279 int attachment, int slot )
280 {
281 struct framebuffer_attachment *at = &fb->attachments[attachment];
282
283 if( at->purpose != k_framebuffer_attachment_type_colour )
284 {
285 vg_fatal_exit_loop( "illegal operation: bind non-colour framebuffer"
286 " attachment to texture slot" );
287 }
288
289 glActiveTexture( GL_TEXTURE0 + slot );
290 glBindTexture( GL_TEXTURE_2D, fb->attachments[attachment].id );
291 }
292
293
294 /*
295 * Shaders
296 */
297 VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id )
298 {
299 GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
300 glUniformBlockBinding( shader, idx, 0 );
301
302 render_fb_bind_texture( gpipeline.fb_heightmap, 0, texture_id );
303 glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
304 }
305
306 VG_STATIC void render_update_lighting_ub(void)
307 {
308 struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
309 int c = 0;
310
311 for( int i=0; i<3; i++ )
312 {
313 struct light_widget *lw = &gpipeline.widgets[i];
314
315 if( lw->enabled )
316 {
317 float pitch = lw->dir[0],
318 yaw = lw->dir[1],
319 xz = cosf( pitch );
320
321 v3_copy( (v3f){ xz*cosf(yaw), sinf(pitch), xz*sinf(yaw) },
322 winf->g_light_directions[c] );
323 v3_copy( lw->colour, winf->g_light_colours[c] );
324
325 c ++;
326 }
327 }
328
329 winf->g_light_count = c;
330 winf->g_light_directions[0][3] = gpipeline.shadow_length;
331 winf->g_light_colours[0][3] = gpipeline.shadow_spread;
332
333 if( vg.quality_profile == k_quality_profile_low )
334 winf->g_shadow_samples = 0;
335 else
336 winf->g_shadow_samples = 8;
337
338 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
339 glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
340 &gpipeline.ub_world_lighting );
341 }
342
343 #define FB_FORMAT_STR( E ) { E, #E },
344
345 /*
346 * Convert OpenGL attachment ID enum to string
347 */
348 VG_STATIC const char *render_fb_attachment_str( GLenum e )
349 {
350 struct { GLenum e; const char *str; }
351 formats[] =
352 {
353 FB_FORMAT_STR(GL_COLOR_ATTACHMENT0)
354 FB_FORMAT_STR(GL_COLOR_ATTACHMENT1)
355 FB_FORMAT_STR(GL_COLOR_ATTACHMENT2)
356 FB_FORMAT_STR(GL_COLOR_ATTACHMENT3)
357 FB_FORMAT_STR(GL_COLOR_ATTACHMENT4)
358 FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT)
359 };
360
361 for( int i=0; i<vg_list_size(formats); i++ )
362 if( formats[i].e == e )
363 return formats[i].str;
364
365 return "UNDEFINED";
366 }
367
368 /*
369 * Convert OpenGL texture format enums from TexImage2D table 1,2 &
370 * RenderBufferStorage Table 1, into strings
371 */
372 VG_STATIC const char *render_fb_format_str( GLenum format )
373 {
374 struct { GLenum e; const char *str; }
375 formats[] =
376 {
377 /* Table 1 */
378 FB_FORMAT_STR(GL_DEPTH_COMPONENT)
379 FB_FORMAT_STR(GL_DEPTH_STENCIL)
380 FB_FORMAT_STR(GL_RED)
381 FB_FORMAT_STR(GL_RG)
382 FB_FORMAT_STR(GL_RGB)
383 FB_FORMAT_STR(GL_RGBA)
384
385 /* Render buffer formats */
386 FB_FORMAT_STR(GL_DEPTH_COMPONENT16)
387 FB_FORMAT_STR(GL_DEPTH_COMPONENT24)
388 FB_FORMAT_STR(GL_DEPTH_COMPONENT32F)
389 FB_FORMAT_STR(GL_DEPTH24_STENCIL8)
390 FB_FORMAT_STR(GL_DEPTH32F_STENCIL8)
391 FB_FORMAT_STR(GL_STENCIL_INDEX8)
392
393 /* Table 2 */
394 FB_FORMAT_STR(GL_R8)
395 FB_FORMAT_STR(GL_R8_SNORM)
396 FB_FORMAT_STR(GL_R16)
397 FB_FORMAT_STR(GL_R16_SNORM)
398 FB_FORMAT_STR(GL_RG8)
399 FB_FORMAT_STR(GL_RG8_SNORM)
400 FB_FORMAT_STR(GL_RG16)
401 FB_FORMAT_STR(GL_RG16_SNORM)
402 FB_FORMAT_STR(GL_R3_G3_B2)
403 FB_FORMAT_STR(GL_RGB4)
404 FB_FORMAT_STR(GL_RGB5)
405 FB_FORMAT_STR(GL_RGB8)
406 FB_FORMAT_STR(GL_RGB8_SNORM)
407 FB_FORMAT_STR(GL_RGB10)
408 FB_FORMAT_STR(GL_RGB12)
409 FB_FORMAT_STR(GL_RGB16_SNORM)
410 FB_FORMAT_STR(GL_RGBA2)
411 FB_FORMAT_STR(GL_RGBA4)
412 FB_FORMAT_STR(GL_RGB5_A1)
413 FB_FORMAT_STR(GL_RGBA8)
414 FB_FORMAT_STR(GL_RGBA8_SNORM)
415 FB_FORMAT_STR(GL_RGB10_A2)
416 FB_FORMAT_STR(GL_RGB10_A2UI)
417 FB_FORMAT_STR(GL_RGBA12)
418 FB_FORMAT_STR(GL_RGBA16)
419 FB_FORMAT_STR(GL_SRGB8)
420 FB_FORMAT_STR(GL_SRGB8_ALPHA8)
421 FB_FORMAT_STR(GL_R16F)
422 FB_FORMAT_STR(GL_RG16F)
423 FB_FORMAT_STR(GL_RGB16F)
424 FB_FORMAT_STR(GL_RGBA16F)
425 FB_FORMAT_STR(GL_R32F)
426 FB_FORMAT_STR(GL_RG32F)
427 FB_FORMAT_STR(GL_RGB32F)
428 FB_FORMAT_STR(GL_RGBA32F)
429 FB_FORMAT_STR(GL_R11F_G11F_B10F)
430 FB_FORMAT_STR(GL_RGB9_E5)
431 FB_FORMAT_STR(GL_R8I)
432 FB_FORMAT_STR(GL_R8UI)
433 FB_FORMAT_STR(GL_R16I)
434 FB_FORMAT_STR(GL_R16UI)
435 FB_FORMAT_STR(GL_R32I)
436 FB_FORMAT_STR(GL_R32UI)
437 FB_FORMAT_STR(GL_RG8I)
438 FB_FORMAT_STR(GL_RG8UI)
439 FB_FORMAT_STR(GL_RG16I)
440 FB_FORMAT_STR(GL_RG16UI)
441 FB_FORMAT_STR(GL_RG32I)
442 FB_FORMAT_STR(GL_RG32UI)
443 FB_FORMAT_STR(GL_RGB8I)
444 FB_FORMAT_STR(GL_RGB8UI)
445 FB_FORMAT_STR(GL_RGB16I)
446 FB_FORMAT_STR(GL_RGB16UI)
447 FB_FORMAT_STR(GL_RGB32I)
448 FB_FORMAT_STR(GL_RGB32UI)
449 FB_FORMAT_STR(GL_RGBA8I)
450 FB_FORMAT_STR(GL_RGBA8UI)
451 FB_FORMAT_STR(GL_RGBA16I)
452 FB_FORMAT_STR(GL_RGBA16UI)
453 FB_FORMAT_STR(GL_RGBA32I)
454 FB_FORMAT_STR(GL_RGBA32UI)
455 };
456
457 for( int i=0; i<vg_list_size(formats); i++ )
458 if( formats[i].e == format )
459 return formats[i].str;
460
461 return "UNDEFINED";
462 }
463
464 /*
465 * Bind and allocate texture for framebuffer attachment
466 */
467 VG_STATIC void render_fb_allocate_texture( struct framebuffer *fb,
468 struct framebuffer_attachment *a )
469 {
470 int rx, ry;
471 render_fb_get_current_res( fb, &rx, &ry );
472
473 if( a->purpose == k_framebuffer_attachment_type_renderbuffer )
474 {
475 glBindRenderbuffer( GL_RENDERBUFFER, a->id );
476 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, rx, ry );
477 }
478 else if( a->purpose == k_framebuffer_attachment_type_colour )
479 {
480 glBindTexture( GL_TEXTURE_2D, a->id );
481 glTexImage2D( GL_TEXTURE_2D, 0, a->internalformat, rx, ry,
482 0, a->format, a->type, NULL );
483 }
484 }
485
486 /*
487 * Full allocation of a framebuffer
488 */
489 VG_STATIC void render_fb_allocate( struct framebuffer *fb )
490 {
491 glGenFramebuffers( 1, &fb->fb );
492 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
493
494 int rx, ry;
495 render_fb_get_current_res( fb, &rx, &ry );
496
497 vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry );
498 vg_info( "{\n" );
499
500 GLenum colour_attachments[4];
501 u32 colour_count = 0;
502
503 for( int j=0; j<vg_list_size(fb->attachments); j++ )
504 {
505 struct framebuffer_attachment *attachment = &fb->attachments[j];
506
507 if( attachment->purpose == k_framebuffer_attachment_type_none )
508 continue;
509
510 vg_info( " %s: %s\n",
511 render_fb_attachment_str( attachment->attachment ),
512 render_fb_format_str( attachment->internalformat ) );
513
514 if( attachment->purpose == k_framebuffer_attachment_type_renderbuffer )
515 {
516 glGenRenderbuffers( 1, &attachment->id );
517 render_fb_allocate_texture( fb, attachment );
518 glFramebufferRenderbuffer( GL_FRAMEBUFFER,
519 GL_DEPTH_STENCIL_ATTACHMENT,
520 GL_RENDERBUFFER, attachment->id );
521 }
522 else if( attachment->purpose == k_framebuffer_attachment_type_colour )
523 {
524 glGenTextures( 1, &attachment->id );
525 render_fb_allocate_texture( fb, attachment );
526 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
527 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
528 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
529 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
530
531 glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment,
532 GL_TEXTURE_2D, attachment->id, 0 );
533
534 colour_attachments[ colour_count ++ ] = attachment->attachment;
535 }
536 }
537
538 glDrawBuffers( colour_count, colour_attachments );
539
540 /*
541 * Check result
542 */
543 GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER );
544
545 if( result == GL_FRAMEBUFFER_COMPLETE )
546 {
547 /*
548 * Attatch to gpipeline
549 */
550 if( fb->link )
551 *fb->link = fb;
552
553 vg_success( " status: complete\n" );
554 vg_info( "}\n" );
555 }
556 else
557 {
558 if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
559 vg_error( " status: Incomplete attachment" );
560 else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
561 vg_error( " status: Missing attachment" );
562 else if( result == GL_FRAMEBUFFER_UNSUPPORTED )
563 vg_error( " status: Unsupported framebuffer format" );
564 else
565 vg_error( " status: Generic Error" );
566
567 vg_info( "}\n" );
568 vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" );
569 }
570 }
571
572 /*
573 * Resize/Update all framebuffers(we know about)
574 */
575 VG_STATIC void render_fb_resize(void)
576 {
577 if( !gpipeline.ready )
578 return;
579
580 for( int i=0; i<vg_list_size(framebuffers); i++ )
581 {
582 struct framebuffer *fb = &framebuffers[i];
583 for( int j=0; j<vg_list_size(fb->attachments); j++ )
584 {
585 struct framebuffer_attachment *attachment = &fb->attachments[j];
586 render_fb_allocate_texture( fb, attachment );
587 }
588 }
589 }
590
591 #if 0
592 VG_STATIC void fb_use( struct framebuffer *fb )
593 {
594 if( !fb )
595 {
596 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background );
597 glViewport( 0, 0, vg.window_x, vg.window_y );
598 }
599 else
600 {
601 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
602 glViewport( 0, 0, vg.window_x / fb->div, vg.window_y / fb->div );
603 }
604 }
605
606 VG_STATIC void fb_init( struct framebuffer *fb )
607 {
608 i32 ix = vg.window_x / fb->div,
609 iy = vg.window_y / fb->div;
610
611 glGenFramebuffers( 1, &fb->fb );
612 glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
613
614 glGenTextures( 1, &fb->colour );
615 glBindTexture( GL_TEXTURE_2D, fb->colour );
616 glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy,
617 0, fb->format, GL_UNSIGNED_BYTE, NULL);
618
619 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
620 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
621 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
622 GL_TEXTURE_2D, fb->colour, 0);
623
624 glGenRenderbuffers( 1, &fb->rb );
625 glBindRenderbuffer( GL_RENDERBUFFER, fb->rb );
626 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
627
628 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
629 GL_RENDERBUFFER, fb->rb );
630 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
631
632 VG_CHECK_GL_ERR();
633 fb->allocated = 1;
634 }
635
636 VG_STATIC void _fb_glTexImage2D( GLsizei x, GLsizei y, GLint internalformat,
637 GLenum format, GLenum type, const void *data )
638 {
639 glTexImage2D( GL_TEXTURE_2D, 0, internalformat, x,y, 0,
640 format, type, data );
641
642 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
643 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
644 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
645 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
646 }
647
648 #define fb_tex2d( X,Y, INTERNAL_FORMAT, FORMAT, TYPE, DATA ) \
649 _fb_glTexImage2D( X,Y, INTERNAL_FORMAT, FORMAT, TYPE, DATA ); \
650 vg_info( "texture( %dx%d, internal: %s, format: %s, type: %s )\n", \
651 X,Y, #INTERNAL_FORMAT, #FORMAT, #TYPE );
652
653 VG_STATIC void fb_free( struct framebuffer *fb )
654 {
655 glDeleteTextures( 1, &fb->colour );
656 glDeleteFramebuffers( 1, &fb->fb );
657 }
658
659 VG_STATIC void fb_bindtex( struct framebuffer *fb, int texture )
660 {
661 glActiveTexture( GL_TEXTURE0 + texture );
662 glBindTexture( GL_TEXTURE_2D, fb->colour );
663 }
664
665 VG_STATIC void fb_resize( struct framebuffer *fb )
666 {
667 if( !fb->allocated )
668 return;
669
670 i32 ix = vg.window_x / fb->div,
671 iy = vg.window_y / fb->div;
672
673 glBindTexture( GL_TEXTURE_2D, fb->colour );
674 glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy, 0,
675 fb->format, GL_UNSIGNED_BYTE, NULL );
676
677 glBindRenderbuffer( GL_RENDERBUFFER, fb->rb );
678 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
679 }
680 #endif
681
682 #if 0
683 VG_STATIC void render_init_temp_buffer(void)
684 {
685 vg_info( "[render] Allocate framebuffer\n" );
686
687 glGenFramebuffers( 1, &gpipeline.fb_background );
688 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background );
689
690 glGenTextures( 1, &gpipeline.rgb_background );
691 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
692 fb_tex2d( vg.window_x, vg.window_y, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, NULL );
693 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
694 GL_TEXTURE_2D,
695 gpipeline.rgb_background, 0 );
696
697 glGenTextures( 1, &gpipeline.mv_background );
698 glBindTexture( GL_TEXTURE_2D, gpipeline.mv_background );
699 #if 0
700 glTexImage2D( GL_TEXTURE_2D, 0, GL_RG, vg.window_x, vg.window_y,
701 0, GL_RG, GL_FLOAT, NULL);
702 #endif
703 glTexImage2D( GL_TEXTURE_2D, 0, GL_RG16F, vg.window_x, vg.window_y,
704 0, GL_RG, GL_FLOAT, NULL);
705
706 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
707 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
708 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
709 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
710 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
711 GL_TEXTURE_2D,
712 gpipeline.mv_background, 0 );
713
714 /* render buffer */
715 glGenRenderbuffers( 1, &gpipeline.rb_background );
716 glBindRenderbuffer( GL_RENDERBUFFER, gpipeline.rb_background );
717 glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
718 vg.window_x, vg.window_y );
719 glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
720 GL_RENDERBUFFER, gpipeline.rb_background );
721
722 GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
723 glDrawBuffers( 2, attachments );
724
725 render_check_framebuffer_complete();
726
727 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
728 VG_CHECK_GL_ERR();
729 }
730
731 /* used for drawing world depth from the top view, used in our water and
732 * lighting calculations */
733 VG_STATIC void render_init_depthmap_buffer(void)
734 {
735 vg_info( "[render] Allocate depth map buffer\n" );
736
737 glGenFramebuffers( 1, &gpipeline.fb_depthmap );
738 glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
739
740 glGenTextures( 1, &gpipeline.rgb_depthmap );
741 glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap );
742 glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0,
743 GL_RED, GL_FLOAT, NULL );
744 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
745 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
746 vg_tex2d_clamp();
747
748 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
749 GL_TEXTURE_2D,
750 gpipeline.rgb_depthmap, 0);
751
752 render_check_framebuffer_complete();
753 VG_CHECK_GL_ERR();
754 }
755 #endif
756
757 VG_STATIC void render_init_fs_quad(void)
758 {
759 vg_info( "[render] Allocate quad\n" );
760
761 float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
762 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
763
764 0.2f, 0.0f, 0.8f, 1.0f, 0.2f, 1.0f,
765 0.2f, 0.0f, 0.8f, 0.0f, 0.8f, 1.0f};
766
767 glGenVertexArrays( 1, &gpipeline.fsquad.vao );
768 glGenBuffers( 1, &gpipeline.fsquad.vbo );
769 glBindVertexArray( gpipeline.fsquad.vao );
770 glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo );
771 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
772 glBindVertexArray( gpipeline.fsquad.vao );
773 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
774 sizeof(float)*2, (void*)0 );
775 glEnableVertexAttribArray( 0 );
776
777 VG_CHECK_GL_ERR();
778 }
779
780 VG_STATIC void render_init_uniform_buffers(void)
781 {
782 vg_info( "[render] Allocate uniform buffer\n" );
783
784 glGenBuffers( 1, &gpipeline.ubo_world_lighting );
785 glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
786 glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
787 NULL, GL_DYNAMIC_DRAW );
788
789 render_update_lighting_ub();
790 glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
791
792 VG_CHECK_GL_ERR();
793 }
794
795 VG_STATIC void render_init(void)
796 {
797 shader_blit_register();
798 shader_blitblur_register();
799 shader_standard_register();
800 shader_vblend_register();
801
802 vg_acquire_thread_sync();
803 {
804 /*
805 * Complete Framebuffers
806 */
807 for( int i=0; i<vg_list_size(framebuffers); i++ )
808 {
809 struct framebuffer *fb = &framebuffers[i];
810 render_fb_allocate( fb );
811 }
812
813 render_init_fs_quad();
814 render_init_uniform_buffers();
815
816 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
817 gpipeline.ready = 1;
818 }
819
820 vg_release_thread_sync();
821 }
822
823 /*
824 * Utility
825 */
826 VG_STATIC void render_fsquad(void)
827 {
828 glBindVertexArray( gpipeline.fsquad.vao );
829 glDrawArrays( GL_TRIANGLES, 0, 6 );
830 }
831
832 VG_STATIC void render_fsquad1(void)
833 {
834 glBindVertexArray( gpipeline.fsquad.vao );
835 glDrawArrays( GL_TRIANGLES, 6, 6 );
836 }
837
838 #endif /* RENDER_H */