#include "cmdline/cmdline.h" #include "freespace.h" #include "def_files/def_files.h" #include "graphics/gropengl.h" #include "graphics/gropengldraw.h" #include "graphics/gropenglpostprocessing.h" #include "graphics/gropenglshader.h" #include "graphics/gropenglstate.h" #include "io/timer.h" #include "lighting/lighting.h" #include "mod_table/mod_table.h" #include "nebula/neb.h" #include "parse/parselo.h" #include "ship/ship.h" extern bool PostProcessing_override; extern int opengl_check_framebuffer(); //Needed to track where the FXAA shaders are size_t fxaa_shader_id; //In case we don't find the shaders at all, this override is needed bool fxaa_unavailable = false; int Fxaa_preset_last_frame; bool zbuffer_saved = false; // lightshaft parameters bool ls_on = false; bool ls_force_off = false; float ls_density = 0.5f; float ls_weight = 0.02f; float ls_falloff = 1.0f; float ls_intensity = 0.5f; float ls_cpintensity = 0.5f * 50 * 0.02f; int ls_samplenum = 50; const int MAX_MIP_BLUR_LEVELS = 4; typedef struct post_effect_t { SCP_string name; SCP_string uniform_name; SCP_string define_name; float intensity; float default_intensity; float div; float add; bool always_on; post_effect_t() : intensity(0.0f), default_intensity(0.0f), div(1.0f), add(0.0f), always_on(false) { } } post_effect_t; SCP_vector Post_effects; static int Post_initialized = 0; bool Post_in_frame = false; static int Post_active_shader_index = -1; static GLuint Bloom_framebuffer = 0; static GLuint Bloom_textures[2] = { 0 }; static GLuint Post_framebuffer_id[2] = { 0 }; static GLuint Post_shadow_framebuffer_id = 0; static GLuint Post_shadow_texture_id = 0; static GLuint Post_shadow_depth_texture_id = 0; static int Post_texture_width = 0; static int Post_texture_height = 0; void opengl_post_pass_tonemap() { opengl_shader_set_current( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_TONEMAPPING, 0) ); GL_state.Uniform.setUniformi("tex", 0); GL_state.Uniform.setUniformf("exposure", 4.0f); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Scene_ldr_texture, 0); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Scene_color_texture); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale); } bool opengl_post_pass_bloom() { if (Cmdline_bloom_intensity <= 0) { return false; } // we need the scissor test disabled GLboolean scissor_test = GL_state.ScissorTest(GL_FALSE); // ------ begin bright pass ------ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Bloom_framebuffer); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Bloom_textures[0], 0); // width and height are 1/2 for the bright pass int width = Post_texture_width >> 1; int height = Post_texture_height >> 1; glViewport(0, 0, width, height); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); opengl_shader_set_current( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BRIGHTPASS, 0) ); GL_state.Uniform.setUniformi("tex", 0); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Scene_color_texture); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f); GL_state.Texture.Disable(); // ------ end bright pass ------ // ------ begin blur pass ------ GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Bloom_textures[0]); glGenerateMipmapEXT(GL_TEXTURE_2D); GL_state.Texture.Disable(); for ( int iteration = 0; iteration < 2; iteration++) { for (int pass = 0; pass < 2; pass++) { GLuint source_tex = Bloom_textures[pass]; GLuint dest_tex = Bloom_textures[1 - pass]; if (pass) { opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLUR, SDR_FLAG_BLUR_HORIZONTAL)); } else { opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLUR, SDR_FLAG_BLUR_VERTICAL)); } GL_state.Uniform.setUniformi("tex", 0); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(source_tex); for (int mipmap = 0; mipmap < MAX_MIP_BLUR_LEVELS; ++mipmap) { int bloom_width = width >> mipmap; int bloom_height = height >> mipmap; GL_state.Uniform.setUniformf("texSize", (pass) ? 1.0f / i2fl(bloom_width) : 1.0f / i2fl(bloom_height)); GL_state.Uniform.setUniformi("level", mipmap); GL_state.Uniform.setUniformf("tapSize", 1.0f); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, dest_tex, mipmap); glViewport(0, 0, bloom_width, bloom_height); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f); } } } GL_state.Texture.Disable(); // composite blur to the color texture glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Scene_color_texture, 0); opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLOOM_COMP, 0)); GL_state.Uniform.setUniformi("tex", 0); GL_state.Uniform.setUniformi("levels", MAX_MIP_BLUR_LEVELS); GL_state.Uniform.setUniformf("bloom_intensity", Cmdline_bloom_intensity / 100.0f); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Bloom_textures[0]); GL_state.SetAlphaBlendMode( ALPHA_BLEND_ADDITIVE ); glViewport(0, 0, gr_screen.max_w, gr_screen.max_h); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f); GL_state.SetAlphaBlendMode( ALPHA_BLEND_NONE ); // ------ end blur pass -------- // reset viewport, scissor test and exit GL_state.ScissorTest(scissor_test); return true; } void gr_opengl_post_process_begin() { if ( !Post_initialized ) { return; } if (Post_in_frame) { return; } if (PostProcessing_override) { return; } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Post_framebuffer_id[0]); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Post_in_frame = true; } void recompile_fxaa_shader() { mprintf(("Recompiling FXAA shader with preset %d\n", Cmdline_fxaa_preset)); // start recompile by grabbing deleting the current shader we have, assuming it's already created opengl_delete_shader( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0) ); // then recreate it again. shader loading code will be updated with the new FXAA presets gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0); Fxaa_preset_last_frame = Cmdline_fxaa_preset; } void opengl_post_pass_fxaa() { //If the preset changed, recompile the shader if (Fxaa_preset_last_frame != Cmdline_fxaa_preset) { recompile_fxaa_shader(); } // We only want to draw to ATTACHMENT0 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Do a prepass to convert the main shaders' RGBA output into RGBL opengl_shader_set_current( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA_PREPASS, 0) ); // basic/default uniforms GL_state.Uniform.setUniformi( "tex", 0 ); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Scene_luminance_texture, 0); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Scene_ldr_texture); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale); GL_state.Texture.Disable(); // set and configure post shader .. opengl_shader_set_current( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0) ); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Scene_ldr_texture, 0); // basic/default uniforms GL_state.Uniform.setUniformi( "tex0", 0 ); GL_state.Uniform.setUniformf( "rt_w", static_cast(Post_texture_width)); GL_state.Uniform.setUniformf( "rt_h", static_cast(Post_texture_height)); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Scene_luminance_texture); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale); GL_state.Texture.Disable(); opengl_shader_set_current(); } extern GLuint Shadow_map_depth_texture; extern GLuint Scene_depth_texture; extern GLuint Cockpit_depth_texture; extern GLuint Scene_position_texture; extern GLuint Scene_normal_texture; extern GLuint Scene_specular_texture; extern bool stars_sun_has_glare(int index); extern float Sun_spot; void opengl_post_lightshafts() { opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_LIGHTSHAFTS, 0)); float x, y; // should we even be here? if ( !Game_subspace_effect && ls_on && !ls_force_off ) { int n_lights = light_get_global_count(); for ( int idx = 0; idx 0.7f ) { x = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI*1.5f + 0.5f; //cant get the coordinates right but this works for the limited glare fov y = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI*1.5f*gr_screen.clip_aspect + 0.5f; GL_state.Uniform.setUniform2f("sun_pos", x, y); GL_state.Uniform.setUniformi("scene", 0); GL_state.Uniform.setUniformi("cockpit", 1); GL_state.Uniform.setUniformf("density", ls_density); GL_state.Uniform.setUniformf("falloff", ls_falloff); GL_state.Uniform.setUniformf("weight", ls_weight); GL_state.Uniform.setUniformf("intensity", Sun_spot * ls_intensity); GL_state.Uniform.setUniformf("cp_intensity", Sun_spot * ls_cpintensity); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Scene_depth_texture); GL_state.Texture.SetActiveUnit(1); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Cockpit_depth_texture); GL_state.Color(255, 255, 255, 255); GL_state.Blend(GL_TRUE); GL_state.SetAlphaBlendMode(ALPHA_BLEND_ADDITIVE); opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale); GL_state.Blend(GL_FALSE); break; } } } if ( zbuffer_saved ) { zbuffer_saved = false; gr_zbuffer_set(GR_ZBUFF_FULL); glClear(GL_DEPTH_BUFFER_BIT); gr_zbuffer_set(GR_ZBUFF_NONE); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Scene_depth_texture, 0); } } void gr_opengl_post_process_end() { // state switch just the once (for bloom pass and final render-to-screen) GLboolean depth = GL_state.DepthTest(GL_FALSE); GLboolean depth_mask = GL_state.DepthMask(GL_FALSE); GLboolean lighting = GL_state.Lighting(GL_FALSE); GLboolean blend = GL_state.Blend(GL_FALSE); GLboolean cull = GL_state.CullFace(GL_FALSE); GL_state.Texture.SetShaderMode(GL_TRUE); // do bloom, hopefully ;) bool bloomed = opengl_post_pass_bloom(); // do tone mapping opengl_post_pass_tonemap(); // Do FXAA if (Cmdline_fxaa && !fxaa_unavailable && !GL_rendering_to_texture) { opengl_post_pass_fxaa(); } // render lightshafts opengl_post_lightshafts(); // now write to the on-screen buffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, opengl_get_rtt_framebuffer()); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); GL_state.Color(255, 255, 255, 255); // set and configure post shader ... int flags = 0; for ( int i = 0; i < (int)Post_effects.size(); i++) { if (Post_effects[i].always_on) { flags |= (1 << i); } } int post_sdr_handle = Post_active_shader_index; if ( post_sdr_handle < 0 ) { // no active shader index? use the always on shader. post_sdr_handle = gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_MAIN, flags); } opengl_shader_set_current(post_sdr_handle); // basic/default uniforms GL_state.Uniform.setUniformi( "tex", 0 ); GL_state.Uniform.setUniformi( "depth_tex", 2); GL_state.Uniform.setUniformf( "timer", static_cast(timer_get_milliseconds() % 100 + 1) ); for (size_t idx = 0; idx < Post_effects.size(); idx++) { if ( GL_shader[post_sdr_handle].flags & (1< &names) { size_t idx; for (idx = 0; idx < Post_effects.size(); idx++) { names.push_back(Post_effects[idx].name); } } void opengl_post_init_uniforms(int flags) { for (int idx = 0; idx < (int)Post_effects.size(); idx++) { if (flags & (1 << idx)) { opengl_shader_init_uniform(Post_effects[idx].uniform_name.c_str()); } } } void gr_opengl_post_process_set_effect(const char *name, int value) { if ( !Post_initialized ) { return; } if (name == NULL) { return; } size_t idx; int sflags = 0; if(!stricmp("lightshafts",name)) { ls_intensity = value / 100.0f; ls_on = !!value; return; } for (idx = 0; idx < Post_effects.size(); idx++) { const char *eff_name = Post_effects[idx].name.c_str(); if ( !stricmp(eff_name, name) ) { Post_effects[idx].intensity = (value / Post_effects[idx].div) + Post_effects[idx].add; break; } } // figure out new flags for (idx = 0; idx < Post_effects.size(); idx++) { if ( Post_effects[idx].always_on || (Post_effects[idx].intensity != Post_effects[idx].default_intensity) ) { sflags |= (1< 120) { sflags << "#define FXAA_GLSL_120 0\n"; sflags << "#define FXAA_GLSL_130 1\n"; } switch (Cmdline_fxaa_preset) { case 0: sflags << "#define FXAA_QUALITY_PRESET 10\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/6.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/12.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 1: sflags << "#define FXAA_QUALITY_PRESET 11\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/7.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/14.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 2: sflags << "#define FXAA_QUALITY_PRESET 12\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/8.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/16.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 3: sflags << "#define FXAA_QUALITY_PRESET 13\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/9.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/18.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 4: sflags << "#define FXAA_QUALITY_PRESET 14\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/10.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/20.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 5: sflags << "#define FXAA_QUALITY_PRESET 25\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/11.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/22.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 6: sflags << "#define FXAA_QUALITY_PRESET 26\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/12.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/24.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 7: sflags << "#define FXAA_PC 1\n"; sflags << "#define FXAA_QUALITY_PRESET 27\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/13.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/26.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 8: sflags << "#define FXAA_QUALITY_PRESET 28\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/14.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/28.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; case 9: sflags << "#define FXAA_QUALITY_PRESET 39\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/15.0)\n"; sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/32.0)\n"; sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n"; break; } } } bool opengl_post_init_shaders() { int idx; int flags = 0; // figure out which flags we need for the main post process shader for (idx = 0; idx < (int)Post_effects.size(); idx++) { if (Post_effects[idx].always_on) { flags |= (1 << idx); } } if ( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_MAIN, flags) < 0 ) { // only the main shader is actually required for post-processing return false; } if ( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BRIGHTPASS, 0) < 0 || gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLUR, SDR_FLAG_BLUR_HORIZONTAL) < 0 || gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLUR, SDR_FLAG_BLUR_VERTICAL) < 0 || gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLOOM_COMP, 0) < 0) { // disable bloom if we don't have those shaders available Cmdline_bloom_intensity = 0; } if ( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0) < 0 || gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA_PREPASS, 0) < 0 ) { Cmdline_fxaa = false; fxaa_unavailable = true; mprintf(("Error while compiling FXAA shaders. FXAA will be unavailable.\n")); } return true; } void opengl_setup_bloom_textures() { if (Cmdline_bloom_intensity <= 0) { return; } // two more framebuffers, one each for the two different sized bloom textures glGenFramebuffersEXT(1, &Bloom_framebuffer); // need to generate textures for bloom too glGenTextures(2, Bloom_textures); // half size int width = Post_texture_width >> 1; int height = Post_texture_height >> 1; for (int tex = 0; tex < 2; tex++) { GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Bloom_textures[tex]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glGenerateMipmapEXT(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, MAX_MIP_BLUR_LEVELS-1); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } // generate and test the framebuffer and textures that we are going to use static bool opengl_post_init_framebuffer() { bool rval = false; // clamp size, if needed Post_texture_width = gr_screen.max_w; Post_texture_height = gr_screen.max_h; if (Post_texture_width > GL_max_renderbuffer_size) { Post_texture_width = GL_max_renderbuffer_size; } if (Post_texture_height > GL_max_renderbuffer_size) { Post_texture_height = GL_max_renderbuffer_size; } opengl_setup_bloom_textures(); if ( Cmdline_shadow_quality ) { int size = (Cmdline_shadow_quality == 2 ? 1024 : 512); glGenFramebuffersEXT(1, &Post_shadow_framebuffer_id); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Post_shadow_framebuffer_id); glGenTextures(1, &Post_shadow_texture_id); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY_EXT); // GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Post_shadow_texture_id); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGBA32F_ARB, size, size, 4, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, size, size, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Post_shadow_texture_id, 0); glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, Post_shadow_texture_id, 0); glGenTextures(1, &Post_shadow_depth_texture_id); GL_state.Texture.SetActiveUnit(0); GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY_EXT); // GL_state.Texture.SetTarget(GL_TEXTURE_2D); GL_state.Texture.Enable(Post_shadow_depth_texture_id); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_DEPTH_COMPONENT32, size, size, 4, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, size, size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); // glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Post_shadow_depth_texture_id, 0); glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, Post_shadow_depth_texture_id, 0); } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); GL_state.Texture.Disable(); rval = true; if ( opengl_check_for_errors("post_init_framebuffer()") ) { rval = false; } return rval; } void opengl_post_process_shutdown_bloom() { if ( Bloom_textures[0] ) { glDeleteTextures(1, &Bloom_textures[0]); Bloom_textures[0] = 0; } if ( Bloom_textures[1] ) { glDeleteTextures(1, &Bloom_textures[1]); Bloom_textures[1] = 0; } if ( Bloom_framebuffer > 0 ) { glDeleteFramebuffersEXT(1, &Bloom_framebuffer); Bloom_framebuffer = 0; } } void opengl_post_process_init() { Post_initialized = 0; //We need to read the tbl first. This is mostly for FRED's benefit, as otherwise the list of post effects for the sexp doesn't get updated. if ( !opengl_post_init_table() ) { mprintf((" Unable to read post-processing table! Disabling post-processing...\n\n")); Cmdline_postprocess = 0; return; } if ( !Cmdline_postprocess ) { return; } if ( !Scene_texture_initialized ) { return; } if ( !is_minimum_GLSL_version() || Cmdline_no_fbo || !GLAD_GL_EXT_framebuffer_object ) { Cmdline_postprocess = 0; return; } if ( !opengl_post_init_shaders() ) { mprintf((" Unable to initialize post-processing shaders! Disabling post-processing...\n\n")); Cmdline_postprocess = 0; return; } if ( !opengl_post_init_framebuffer() ) { mprintf((" Unable to initialize post-processing framebuffer! Disabling post-processing...\n\n")); Cmdline_postprocess = 0; return; } Post_initialized = 1; } void opengl_post_process_shutdown() { if ( !Post_initialized ) { return; } if (Post_framebuffer_id[0]) { glDeleteFramebuffersEXT(1, &Post_framebuffer_id[0]); Post_framebuffer_id[0] = 0; if (Post_framebuffer_id[1]) { glDeleteFramebuffersEXT(1, &Post_framebuffer_id[1]); Post_framebuffer_id[1] = 0; } } Post_effects.clear(); opengl_post_process_shutdown_bloom(); Post_in_frame = false; Post_active_shader_index = 0; Post_initialized = 0; }