naev 0.10.4
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 "opengl.h"
14#include "pause.h"
15#include "player.h"
16#include "space.h"
17#include "spfx.h"
18#include "toolkit.h"
19#include "weapon.h"
20
21#include "nlua_shader.h"
22
28typedef struct PPShader_s {
29 unsigned int id; /*< Global id (greater than 0). */
31 unsigned int flags;
32 double dt;
33 GLuint program;
34 /* Shared uniforms. */
35 GLint ClipSpaceFromLocal;
36 GLint u_time;
37 /* Fragment Shader. */
38 GLint MainTex;
39 GLint love_ScreenSize;
40 /* Vertex shader. */
41 GLint VertexPosition;
42 GLint VertexTexCoord;
43 /* Textures. */
44 LuaTexture_t *tex;
45} PPShader;
46
47static unsigned int pp_shaders_id = 0;
48static PPShader *pp_shaders_list[PP_LAYER_MAX];
50static LuaShader_t gamma_correction_shader;
51static int pp_gamma_correction = 0;
56static void render_fbo( double dt, GLuint fbo, GLuint tex, PPShader *shader )
57{
58 /* Have to consider alpha premultiply. */
59 glBlendFuncSeparate( GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
60
61 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
62
63 glUseProgram( shader->program );
64
65 /* Screen size. */
66 if (shader->love_ScreenSize >= 0)
67 /* TODO don't have to upload this every frame, only when resized... */
68 glUniform4f( shader->love_ScreenSize, SCREEN_W, SCREEN_H, 1., 0. );
69
70 /* Time stuff. */
71 if (shader->u_time >= 0) {
72 shader->dt += dt;
73 glUniform1f( shader->u_time, shader->dt );
74 }
75
76 /* Set up stuff .*/
77 glEnableVertexAttribArray( shader->VertexPosition );
78 gl_vboActivateAttribOffset( gl_squareVBO, shader->VertexPosition, 0, 2, GL_FLOAT, 0 );
79 if (shader->VertexTexCoord >= 0) {
80 glEnableVertexAttribArray( shader->VertexTexCoord );
81 gl_vboActivateAttribOffset( gl_squareVBO, shader->VertexTexCoord, 0, 2, GL_FLOAT, 0 );
82 }
83
84 /* Set the texture(s). */
85 glBindTexture( GL_TEXTURE_2D, tex );
86 glUniform1i( shader->MainTex, 0 );
87 for (int i=0; i<array_size(shader->tex); i++) {
88 LuaTexture_t *t = &shader->tex[i];
89 glActiveTexture( t->active );
90 glBindTexture( GL_TEXTURE_2D, t->texid );
91 glUniform1i( t->uniform, t->value );
92 }
93 glActiveTexture( GL_TEXTURE0 );
94
95 /* Set shader uniforms. */
96 const mat4 ortho = mat4_ortho(0., 1., 1., 0., 1., -1.);
97 gl_uniformMat4(shader->ClipSpaceFromLocal, &ortho);
98
99 /* Draw. */
100 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
101
102 /* Clear state. */
103 glDisableVertexAttribArray( shader->VertexPosition );
104 if (shader->VertexTexCoord >= 0)
105 glDisableVertexAttribArray( shader->VertexTexCoord );
106 glUseProgram( 0 );
107
108 /* Restore the default mode. */
109 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
110}
111
115static void render_fbo_list( double dt, PPShader *list, int *current, int done )
116{
117 PPShader *pplast;
118 int i, cur, next;
119 cur = *current;
120
121 /* Render all except the last post-process shader. */
122 for (i=0; i<array_size(list)-1; i++) {
123 PPShader *pp = &list[i];
124 next = 1-cur;
125 /* Render cur to next. */
126 render_fbo( dt, gl_screen.fbo[next], gl_screen.fbo_tex[cur], pp );
127 cur = next;
128 }
129
130 /* Final render is to the screen. */
131 pplast = &list[i];
132 if (done) {
134 /* Do the render. */
135 render_fbo( dt, gl_screen.current_fbo, gl_screen.fbo_tex[cur], pplast );
136 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
137 return;
138
139 }
140
141 /* Draw the last shader. */
142 next = 1-cur;
143 render_fbo( dt, gl_screen.fbo[next], gl_screen.fbo_tex[cur], pplast );
144 cur = next;
145
146 /* Set the framebuffer again. */
148 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
149
150 /* Set the new current framebuffer. */
151 *current = cur;
152}
153
172void render_all( double game_dt, double real_dt )
173{
174 double dt;
175 int pp_final, pp_gui, pp_game;
176 int cur = 0;
177
178 /* See what post-processing is up. */
179 pp_game = (array_size(pp_shaders_list[PP_LAYER_GAME]) > 0);
180 pp_gui = (array_size(pp_shaders_list[PP_LAYER_GUI]) > 0);
181 pp_final = (array_size(pp_shaders_list[PP_LAYER_FINAL]) > 0);
182
183 /* Case we have a post-processing shader we use the framebuffers. */
184 if (pp_game || pp_gui || pp_final) {
185 /* Clear main screen. */
186 glBindFramebuffer(GL_FRAMEBUFFER, 0);
187 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
188
189 /* Clear back buffer. */
190 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.fbo[1]);
191 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
192
193 /* Set to front buffer. */
195 }
196 else
198
199 /* Bind and clear new drawing area. */
200 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
201 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
202
203 dt = (paused) ? 0. : game_dt;
204
205 /* Set up the default viewport. */
207
208 /* Background stuff */
209 space_render( real_dt ); /* Nebula looks really weird otherwise. */
210 hooks_run( "renderbg" );
211 spobs_render();
212 spfx_render(SPFX_LAYER_BACK);
213 weapons_render(WEAPON_LAYER_BG, dt);
214 /* Middle stuff */
217 weapons_render(WEAPON_LAYER_FG, dt);
218 spfx_render(SPFX_LAYER_MIDDLE);
219 /* Foreground stuff */
220 player_render(dt);
221 spfx_render(SPFX_LAYER_FRONT);
225 hooks_run( "renderfg" );
226
227 /* Process game stuff only. */
228 if (pp_game)
229 render_fbo_list( dt, pp_shaders_list[PP_LAYER_GAME], &cur, !(pp_final || pp_gui) );
230
231 /* GUi stuff. */
232 gui_render(dt);
233
234 if (pp_gui)
235 render_fbo_list( dt, pp_shaders_list[PP_LAYER_GUI], &cur, !pp_final );
236
237 /* We set the to fullscreen, ignoring the GUI modifications. */
239
240 /* Top stuff. */
241 ovr_render( real_dt ); /* Using real_dt is sort of a hack for now. */
242 hooks_run( "rendertop" );
243 display_fps( real_dt ); /* Exception using real_dt. */
245
246 /* Final post-processing. */
247 if (pp_final)
248 render_fbo_list( dt, pp_shaders_list[PP_LAYER_FINAL], &cur, 1 );
249
250 /* check error every loop */
251 gl_checkErr();
252}
253
257static int ppshader_compare( const void *a, const void *b )
258{
259 PPShader *ppa, *ppb;
260 ppa = (PPShader*) a;
261 ppb = (PPShader*) b;
262 if (ppa->priority > ppb->priority)
263 return +1;
264 if (ppa->priority < ppb->priority)
265 return -1;
266 return 0;
267}
268
278unsigned int render_postprocessAdd( LuaShader_t *shader, int layer, int priority, unsigned int flags )
279{
280 PPShader *pp, **pp_shaders;
281 unsigned int id;
282
283 /* Select the layer. */
284 if (layer < 0 || layer >= PP_LAYER_MAX) {
285 WARN(_("Unknown post-processing shader layer '%d'!"), layer);
286 return 0;
287 }
288 pp_shaders = &pp_shaders_list[layer];
289
290 if (*pp_shaders==NULL)
291 *pp_shaders = array_create( PPShader );
292 pp = &array_grow( pp_shaders );
293 id = ++pp_shaders_id;
294 pp->id = id;
295 pp->priority = priority;
296 pp->flags = flags;
297 pp->program = shader->program;
298 pp->ClipSpaceFromLocal = shader->ClipSpaceFromLocal;
299 pp->MainTex = shader->MainTex;
300 pp->VertexPosition = shader->VertexPosition;
301 pp->VertexTexCoord = shader->VertexTexCoord;
302 if (shader->tex != NULL)
303 pp->tex = array_copy( LuaTexture_t, shader->tex );
304 else
305 pp->tex = NULL;
306 /* Special uniforms. */
307 pp->u_time = glGetUniformLocation( pp->program, "u_time" );
308 pp->love_ScreenSize = glGetUniformLocation( pp->program, "love_ScreenSize" );
309 pp->dt = 0.;
310
311 /* Resort n case stuff is weird. */
312 qsort( *pp_shaders, array_size(*pp_shaders), sizeof(PPShader), ppshader_compare );
313
314 gl_checkErr();
315
316 return id;
317}
318
325int render_postprocessRm( unsigned int id )
326{
327 int j;
328 int found = -1;
329 for (j=0; j<PP_LAYER_MAX; j++) {
330 PPShader *pp_shaders = pp_shaders_list[j];
331 for (int i=0; i<array_size(pp_shaders); i++) {
332 PPShader *pp = &pp_shaders[i];
333 if (pp->id != id)
334 continue;
335 found = i;
336 break;
337 }
338 if (found>=0)
339 break;
340 }
341 if (found==-1) {
342 /* Don't warn since they can get cleaned up twice: once from postprocessCleanup, once from Lua gc. */
343 //WARN(_("Trying to remove non-existant post-processing shader with id '%d'!"), id);
344 return -1;
345 }
346
347 /* No need to resort. */
348 array_erase( &pp_shaders_list[j], &pp_shaders_list[j][found], &pp_shaders_list[j][found+1] );
349 return 0;
350}
351
355void render_postprocessCleanup (void)
356{
357 for (int j=0; j<PP_LAYER_MAX; j++) {
358 PPShader *pp_shaders = pp_shaders_list[j];
359 for (int i=array_size(pp_shaders)-1; i>=0; i--) {
360 PPShader *pp = &pp_shaders[i];
361 if (pp->flags & PP_SHADER_PERMANENT)
362 continue;
363 array_erase( &pp_shaders_list[j], &pp_shaders_list[j][i], &pp_shaders_list[j][i+1] );
364 }
365 }
366 /* No need to resort. */
367}
368
372void render_init (void)
373{
374 LuaShader_t *s = &gamma_correction_shader;
375 memset( s, 0, sizeof(LuaShader_t) );
376 s->program = shaders.gamma_correction.program;
377 s->VertexPosition = shaders.gamma_correction.VertexPosition;
378 s->ClipSpaceFromLocal = shaders.gamma_correction.ClipSpaceFromLocal;
379 s->MainTex = shaders.gamma_correction.MainTex;
380
381 /* Initialize the gamma. */
382 render_setGamma( conf.gamma_correction );
383}
384
388void render_exit (void)
389{
390 for (int i=0; i<PP_LAYER_MAX; i++) {
391 array_free( pp_shaders_list[i] );
392 pp_shaders_list[i] = NULL;
393 }
394}
395
399void render_setGamma( double gamma )
400{
401 if (pp_gamma_correction > 0) {
402 render_postprocessRm( pp_gamma_correction );
403 pp_gamma_correction = 0;
404 }
405
406 /* Ignore small gamma. */
407 if (fabs(gamma-1.) < 1e-3)
408 return;
409
410 /* Set gamma and upload. */
411 glUseProgram( shaders.gamma_correction.program );
412 glUniform1f( shaders.gamma_correction.gamma, gamma );
413 glUseProgram( 0 );
414 pp_gamma_correction = render_postprocessAdd( &gamma_correction_shader, PP_LAYER_FINAL, 98, PP_SHADER_PERMANENT );
415}
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:698
void gui_render(double dt)
Renders the player's GUI.
Definition: gui.c:720
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition: hook.c:987
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Definition: mat4.c:209
void display_fps(const double dt)
Displays FPS on the screen.
Definition: naev.c:915
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_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
Definition: opengl_vbo.c:228
int paused
Definition: pause.c:21
void pilots_renderOverlay(void)
Renders all the pilots overlays.
Definition: pilot.c:3748
void pilots_render(void)
Renders all the pilots.
Definition: pilot.c:3731
void player_render(double dt)
Renders the player.
Definition: player.c:955
void player_renderUnderlay(double dt)
Renders the player underlay.
Definition: player.c:993
void space_render(const double dt)
Renders the system.
Definition: space.c:3395
void space_renderOverlay(const double dt)
Renders the system overlay.
Definition: space.c:3411
void spobs_render(void)
Renders the current systems' spobs.
Definition: space.c:3430
void spfx_render(int layer)
Renders the entire spfx layer.
Definition: spfx.c:1002
Post-Processing Shader.
Definition: render.c:28
unsigned int flags
Definition: render.c:31
GLuint program
Definition: render.c:33
double dt
Definition: render.c:32
GLint u_time
Definition: render.c:36
int priority
Definition: render.c:30
double gamma_correction
Definition: conf.h:102
GLuint fbo_tex[OPENGL_NUM_FBOS]
Definition: opengl.h:68
GLuint fbo[OPENGL_NUM_FBOS]
Definition: opengl.h:67
int nw
Definition: opengl.h:43
int nh
Definition: opengl.h:44
GLuint current_fbo
Definition: opengl.h:66
Definition: mat4.h:10
void toolkit_render(double dt)
Renders the windows.
Definition: toolkit.c:1590
void weapons_render(const WeaponLayer layer, const double dt)
Renders all the weapons in a layer.
Definition: weapon.c:715