naev 0.11.5
render.c
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
4#include "render.h"
5
6#include "array.h"
7#include "conf.h"
8#include "font.h"
9#include "gui.h"
10#include "hook.h"
11#include "map_overlay.h"
12#include "naev.h"
13#include "menu.h"
14#include "opengl.h"
15#include "pause.h"
16#include "player.h"
17#include "nlua_canvas.h"
18#include "space.h"
19#include "spfx.h"
20#include "toolkit.h"
21#include "weapon.h"
22
23#include "nlua_shader.h"
24
30typedef struct PPShader_s {
31 unsigned int id; /*< Global id (greater than 0). */
33 unsigned int flags;
34 double dt;
35 GLuint program;
36 /* Shared uniforms. */
37 GLint ClipSpaceFromLocal;
38 GLint u_time;
39 /* Fragment Shader. */
40 GLint MainTex;
41 GLint love_ScreenSize;
42 /* Vertex shader. */
43 GLint VertexPosition;
44 GLint VertexTexCoord;
45 /* Textures. */
46 LuaTexture_t *tex;
47} PPShader;
48
49static unsigned int pp_shaders_id = 0;
50static PPShader *pp_shaders_list[PP_LAYER_MAX];
52static LuaShader_t gamma_correction_shader;
53static int pp_gamma_correction = 0;
58static void render_fbo( double dt, GLuint fbo, GLuint tex, PPShader *shader )
59{
60 /* Have to consider alpha premultiply. */
61 glBlendFuncSeparate( GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
62
63 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
64
65 glUseProgram( shader->program );
66
67 /* Screen size. */
68 if (shader->love_ScreenSize >= 0)
69 /* TODO don't have to upload this every frame, only when resized... */
70 glUniform4f( shader->love_ScreenSize, SCREEN_W, SCREEN_H, 1., 0. );
71
72 /* Time stuff. */
73 if (shader->u_time >= 0) {
74 shader->dt += dt;
75 glUniform1f( shader->u_time, shader->dt );
76 }
77
78 /* Set up stuff .*/
79 glEnableVertexAttribArray( shader->VertexPosition );
80 gl_vboActivateAttribOffset( gl_squareVBO, shader->VertexPosition, 0, 2, GL_FLOAT, 0 );
81 if (shader->VertexTexCoord >= 0) {
82 glEnableVertexAttribArray( shader->VertexTexCoord );
83 gl_vboActivateAttribOffset( gl_squareVBO, shader->VertexTexCoord, 0, 2, GL_FLOAT, 0 );
84 }
85
86 /* Set the texture(s). */
87 glBindTexture( GL_TEXTURE_2D, tex );
88 glUniform1i( shader->MainTex, 0 );
89 for (int i=0; i<array_size(shader->tex); i++) {
90 LuaTexture_t *t = &shader->tex[i];
91 glActiveTexture( t->active );
92 glBindTexture( GL_TEXTURE_2D, t->texid );
93 glUniform1i( t->uniform, t->value );
94 }
95 glActiveTexture( GL_TEXTURE0 );
96
97 /* Set shader uniforms. */
98 const mat4 ortho = mat4_ortho(0., 1., 1., 0., 1., -1.);
99 gl_uniformMat4(shader->ClipSpaceFromLocal, &ortho);
100
101 /* Draw. */
102 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
103
104 /* Clear state. */
105 glDisableVertexAttribArray( shader->VertexPosition );
106 if (shader->VertexTexCoord >= 0)
107 glDisableVertexAttribArray( shader->VertexTexCoord );
108 glUseProgram( 0 );
109
110 /* Restore the default mode. */
111 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
112}
113
117static void render_fbo_list( double dt, PPShader *list, int *current, int done )
118{
119 PPShader *pplast;
120 int i, cur, next;
121 cur = *current;
122
123 /* Render all except the last post-process shader. */
124 for (i=0; i<array_size(list)-1; i++) {
125 PPShader *pp = &list[i];
126 next = 1-cur;
127 /* Render cur to next. */
128 render_fbo( dt, gl_screen.fbo[next], gl_screen.fbo_tex[cur], pp );
129 cur = next;
130 }
131
132 /* Final render is to the screen. */
133 pplast = &list[i];
134 if (done) {
136 /* Do the render. */
137 render_fbo( dt, gl_screen.current_fbo, gl_screen.fbo_tex[cur], pplast );
138 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
139 return;
140
141 }
142
143 /* Draw the last shader. */
144 next = 1-cur;
145 render_fbo( dt, gl_screen.fbo[next], gl_screen.fbo_tex[cur], pplast );
146 cur = next;
147
148 /* Set the framebuffer again. */
150 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
151
152 /* Set the new current framebuffer. */
153 *current = cur;
154}
155
174void render_all( double game_dt, double real_dt )
175{
176 double dt;
177 int pp_core, pp_final, pp_gui, pp_game;
178 int cur = 0;
179
180 /* See what post-processing is up. */
181 pp_game = (array_size(pp_shaders_list[PP_LAYER_GAME]) > 0);
182 pp_gui = (array_size(pp_shaders_list[PP_LAYER_GUI]) > 0);
183 pp_final = (array_size(pp_shaders_list[PP_LAYER_FINAL]) > 0);
184 pp_core = (array_size(pp_shaders_list[PP_LAYER_CORE]) > 0);
185
186 /* Case we have a post-processing shader we use the framebuffers. */
187 if (pp_game || pp_gui || pp_final || pp_core) {
188 /* Clear main screen. */
189 glBindFramebuffer(GL_FRAMEBUFFER, 0);
190 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
191
192 /* Clear back buffer. */
193 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.fbo[1]);
194 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
195
196 /* Set to front buffer. */
198 }
199 else
201
202 /* Bind and clear new drawing area. */
203 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
204 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
205
206 dt = (paused) ? 0. : game_dt;
207
208 /* Set up the default viewport. */
210
211 /* Background stuff */
212 space_render( real_dt ); /* Nebula looks really weird otherwise. */
213 render_reset(); /* space_render can use a lua background. */
214 hooks_run( "renderbg" );
215 render_reset();
216 spobs_render();
217 spfx_render(SPFX_LAYER_BACK, dt);
218 weapons_render(WEAPON_LAYER_BG, dt);
219 /* Middle stuff */
222 spfx_render(SPFX_LAYER_MIDDLE, dt);
223 weapons_render(WEAPON_LAYER_FG, dt);
224 /* Foreground stuff */
225 player_render(dt);
226 spfx_render(SPFX_LAYER_FRONT, dt);
228 render_reset(); /* space_render can use a lua background. */
231 hooks_run( "renderfg" );
232 render_reset();
233
234 /* Process game stuff only. */
235 if (pp_game)
236 render_fbo_list( dt, pp_shaders_list[PP_LAYER_GAME], &cur, !(pp_core || pp_final || pp_gui) );
237
238 /* GUi stuff. */
239 gui_render(dt);
240 render_reset();
241
242 if (pp_gui)
243 render_fbo_list( dt, pp_shaders_list[PP_LAYER_GUI], &cur, !(pp_core || pp_final) );
244
245 /* We set the to fullscreen, ignoring the GUI modifications. */
247
248 /* Top stuff. */
249 ovr_render( real_dt ); /* Using real_dt is sort of a hack for now. */
250 hooks_run( "rendertop" );
251 render_reset();
252 fps_display( real_dt ); /* Exception using real_dt. */
253 if (!menu_open)
255
256 /* Final post-processing. */
257 if (pp_final)
258 render_fbo_list( dt, pp_shaders_list[PP_LAYER_FINAL], &cur, !(pp_core) );
259
260 if (menu_open)
262
263 /* Final post-processing. */
264 if (pp_core)
265 render_fbo_list( dt, pp_shaders_list[PP_LAYER_CORE], &cur, 1 );
266
267 /* check error every loop */
268 gl_checkErr();
269}
270
274static int ppshader_compare( const void *a, const void *b )
275{
276 PPShader *ppa, *ppb;
277 ppa = (PPShader*) a;
278 ppb = (PPShader*) b;
279 if (ppa->priority > ppb->priority)
280 return +1;
281 if (ppa->priority < ppb->priority)
282 return -1;
283 return 0;
284}
285
295unsigned int render_postprocessAdd( LuaShader_t *shader, int layer, int priority, unsigned int flags )
296{
297 PPShader *pp, **pp_shaders;
298 unsigned int id;
299
300 /* Select the layer. */
301 if (layer < 0 || layer >= PP_LAYER_MAX) {
302 WARN(_("Unknown post-processing shader layer '%d'!"), layer);
303 return 0;
304 }
305 pp_shaders = &pp_shaders_list[layer];
306
307 if (*pp_shaders==NULL)
308 *pp_shaders = array_create( PPShader );
309 pp = &array_grow( pp_shaders );
310 id = ++pp_shaders_id;
311 pp->id = id;
312 pp->priority = priority;
313 pp->flags = flags;
314 pp->program = shader->program;
315 pp->ClipSpaceFromLocal = shader->ClipSpaceFromLocal;
316 pp->MainTex = shader->MainTex;
317 pp->VertexPosition = shader->VertexPosition;
318 pp->VertexTexCoord = shader->VertexTexCoord;
319 if (shader->tex != NULL)
320 pp->tex = array_copy( LuaTexture_t, shader->tex );
321 else
322 pp->tex = NULL;
323 /* Special uniforms. */
324 pp->u_time = glGetUniformLocation( pp->program, "u_time" );
325 pp->love_ScreenSize = glGetUniformLocation( pp->program, "love_ScreenSize" );
326 pp->dt = 0.;
327
328 /* Resort n case stuff is weird. */
329 qsort( *pp_shaders, array_size(*pp_shaders), sizeof(PPShader), ppshader_compare );
330
331 gl_checkErr();
332
333 return id;
334}
335
342int render_postprocessRm( unsigned int id )
343{
344 int j;
345 int found = -1;
346 for (j=0; j<PP_LAYER_MAX; j++) {
347 PPShader *pp_shaders = pp_shaders_list[j];
348 for (int i=0; i<array_size(pp_shaders); i++) {
349 const PPShader *pp = &pp_shaders[i];
350 if (pp->id != id)
351 continue;
352 found = i;
353 break;
354 }
355 if (found>=0)
356 break;
357 }
358 if (found==-1) {
359 /* Don't warn since they can get cleaned up twice: once from postprocessCleanup, once from Lua gc. */
360 //WARN(_("Trying to remove non-existant post-processing shader with id '%d'!"), id);
361 return -1;
362 }
363
364 /* No need to resort. */
365 array_erase( &pp_shaders_list[j], &pp_shaders_list[j][found], &pp_shaders_list[j][found+1] );
366 return 0;
367}
368
372void render_postprocessCleanup (void)
373{
374 for (int j=0; j<PP_LAYER_MAX; j++) {
375 PPShader *pp_shaders = pp_shaders_list[j];
376 for (int i=array_size(pp_shaders)-1; i>=0; i--) {
377 const PPShader *pp = &pp_shaders[i];
378 if (pp->flags & PP_SHADER_PERMANENT)
379 continue;
380 array_erase( &pp_shaders_list[j], &pp_shaders_list[j][i], &pp_shaders_list[j][i+1] );
381 }
382 }
383 /* No need to resort. */
384}
385
389void render_init (void)
390{
391 LuaShader_t *s = &gamma_correction_shader;
392 memset( s, 0, sizeof(LuaShader_t) );
393 s->program = shaders.gamma_correction.program;
394 s->VertexPosition = shaders.gamma_correction.VertexPosition;
395 s->ClipSpaceFromLocal = shaders.gamma_correction.ClipSpaceFromLocal;
396 s->MainTex = shaders.gamma_correction.MainTex;
397
398 /* Initialize the gamma. */
399 render_setGamma( conf.gamma_correction );
400}
401
405void render_exit (void)
406{
407 for (int i=0; i<PP_LAYER_MAX; i++) {
408 array_free( pp_shaders_list[i] );
409 pp_shaders_list[i] = NULL;
410 }
411}
412
416void render_setGamma( double gamma )
417{
418 if (pp_gamma_correction > 0) {
419 render_postprocessRm( pp_gamma_correction );
420 pp_gamma_correction = 0;
421 }
422
423 /* Ignore small gamma. */
424 if (fabs(gamma-1.) < 1e-3)
425 return;
426
427 /* Set gamma and upload. */
428 glUseProgram( shaders.gamma_correction.program );
429 glUniform1f( shaders.gamma_correction.gamma, gamma );
430 glUseProgram( 0 );
431 pp_gamma_correction = render_postprocessAdd( &gamma_correction_shader, PP_LAYER_CORE, 98, PP_SHADER_PERMANENT );
432}
433
434static int needsReset = 0;
438void render_reset (void)
439{
440 if (!needsReset)
441 return;
442 needsReset = 0;
443
444 glBlendEquation( GL_FUNC_ADD );
445 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
447 canvas_reset();
448}
449
453void render_needsReset (void)
454{
455 needsReset = 1;
456}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_copy(basic_type, ptr_array)
Returns a shallow copy of the input array.
Definition array.h:218
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void gui_renderReticles(double dt)
Renders the gui targeting reticles.
Definition gui.c:703
void gui_render(double dt)
Renders the player's GUI.
Definition gui.c:725
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition hook.c:999
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Definition mat4.c:209
Handles the important game menus.
void fps_display(double dt)
Displays FPS on the screen.
Definition naev.c:945
static double game_dt
Definition naev.c:112
static double real_dt
Definition naev.c:113
Header file with generic functions and naev-specifics.
void gl_defViewport(void)
Resets viewport to default.
Definition opengl.c:608
void gl_viewport(int x, int y, int w, int h)
Sets the opengl viewport.
Definition opengl.c:569
glInfo gl_screen
Definition opengl.c:51
void gl_unclipRect(void)
Clears the 2d clipping planes.
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
Definition opengl_vbo.c:226
int paused
Definition pause.c:21
void pilots_renderOverlay(void)
Renders all the pilots overlays.
Definition pilot.c:3926
void pilots_render(void)
Renders all the pilots.
Definition pilot.c:3909
void player_render(double dt)
Renders the player.
Definition player.c:983
void player_renderUnderlay(double dt)
Renders the player underlay.
Definition player.c:1021
void space_render(const double dt)
Renders the system.
Definition space.c:3441
void space_renderOverlay(const double dt)
Renders the system overlay.
Definition space.c:3457
void spobs_render(void)
Renders the current systems' spobs.
Definition space.c:3476
void spfx_render(int layer, double dt)
Renders the entire spfx layer.
Definition spfx.c:1093
Post-Processing Shader.
Definition render.c:30
unsigned int flags
Definition render.c:33
GLuint program
Definition render.c:35
double dt
Definition render.c:34
GLint u_time
Definition render.c:38
int priority
Definition render.c:32
double gamma_correction
Definition conf.h:101
GLuint fbo_tex[OPENGL_NUM_FBOS]
Definition opengl.h:72
GLuint fbo[OPENGL_NUM_FBOS]
Definition opengl.h:71
int nw
Definition opengl.h:47
int nh
Definition opengl.h:48
GLuint current_fbo
Definition opengl.h:70
Definition mat4.h:10
void toolkit_render(double dt)
Renders the windows.
Definition toolkit.c:1593
void weapons_render(const WeaponLayer layer, double dt)
Renders all the weapons in a layer.
Definition weapon.c:712