/**
 * Compile the deferred light shader and the clear shader.
 */
void opengl_shader_compile_deferred_light_shader()
{
	bool in_error = false;

	int sdr_handle = gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, 0);

	if ( sdr_handle >= 0 ) {
		opengl_shader_set_current(sdr_handle);

		Current_shader->program->Uniforms.setUniformi("ColorBuffer", 0);
		Current_shader->program->Uniforms.setUniformi("NormalBuffer", 1);
		Current_shader->program->Uniforms.setUniformi("PositionBuffer", 2);
		Current_shader->program->Uniforms.setUniformi("SpecBuffer", 3);
		Current_shader->program->Uniforms.setUniformf("invScreenWidth", 1.0f / gr_screen.max_w);
		Current_shader->program->Uniforms.setUniformf("invScreenHeight", 1.0f / gr_screen.max_h);
		Current_shader->program->Uniforms.setUniformf("specFactor", Cmdline_ogl_spec);
	} else {
		opengl_shader_set_current();
		mprintf(("Failed to compile deferred lighting shader!\n"));
		in_error = true;
	}

	if ( gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_CLEAR, 0) < 0 ) {
		mprintf(("Failed to compile deferred lighting buffer clear shader!\n"));
		in_error = true;
	}

	if ( in_error ) {
		mprintf(("  Shader in_error! Disabling deferred lighting!\n"));
		Cmdline_no_deferred_lighting = 1;
	}
}
void opengl_shader_compile_passthrough_shader()
{
	mprintf(("Compiling passthrough shader...\n"));

	int sdr_handle = gr_opengl_maybe_create_shader(SDR_TYPE_PASSTHROUGH_RENDER, 0);

	opengl_shader_set_current(sdr_handle);

	//Hardcoded Uniforms
	Current_shader->program->Uniforms.setUniformi("baseMap", 0);
	Current_shader->program->Uniforms.setUniformi("clipEnabled", 0);

	opengl_shader_set_current();
}
/**
 * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector
 * if compilation is successful.
 *
 * @param sdr		Identifier defined with the program we wish to compile
 * @param flags		Combination of SDR_* flags
 * @param replacement_idx	The index of the shader this replaces. If -1, the newly compiled shader will be appended to the GL_shader vector
 *					or inserted at the first available empty slot
 */
int opengl_compile_shader(shader_type sdr, uint flags)
{
	GR_DEBUG_SCOPE("Creating new shader");

	int sdr_index = -1;
	int empty_idx;
	opengl_shader_t new_shader;

	Assert(sdr < NUM_SHADER_TYPES);

	opengl_compile_shader_actual(sdr, flags, new_shader);

	opengl_shader_set_current();

	// add it to our list of embedded shaders
	// see if we have empty shader slots
	empty_idx = -1;
	for (int i = 0; i < (int)GL_shader.size(); ++i) {
		if (GL_shader[i].shader == NUM_SHADER_TYPES) {
			empty_idx = i;
			break;
		}
	}

	// then insert it at an empty slot or at the end
	if ( empty_idx >= 0 ) {
		GL_shader[empty_idx] = std::move(new_shader);
		sdr_index = empty_idx;
	} else {
		sdr_index = (int)GL_shader.size();
		GL_shader.push_back(std::move(new_shader));
	}

	return sdr_index;
}
void opengl_shader_set_current(int handle)
{
	Assert(handle >= 0);
	Assert(handle < (int)GL_shader.size());

	opengl_shader_set_current(&GL_shader[handle]);
}
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<n_lights; idx++ ) {
			vec3d light_dir;
			vec3d local_light_dir;
			light_get_global_dir(&light_dir, idx);
			vm_vec_rotate(&local_light_dir, &light_dir, &Eye_matrix);

			if ( !stars_sun_has_glare(idx) ) {
				continue;
			}

			float dot;
			if ( (dot = vm_vec_dot(&light_dir, &Eye_matrix.vec.fvec)) > 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;
				Current_shader->program->Uniforms.setUniform2f("sun_pos", x, y);
				Current_shader->program->Uniforms.setUniformi("scene", 0);
				Current_shader->program->Uniforms.setUniformi("cockpit", 1);
				Current_shader->program->Uniforms.setUniformf("density", ls_density);
				Current_shader->program->Uniforms.setUniformf("falloff", ls_falloff);
				Current_shader->program->Uniforms.setUniformf("weight", ls_weight);
				Current_shader->program->Uniforms.setUniformf("intensity", Sun_spot * ls_intensity);
				Current_shader->program->Uniforms.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.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);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, Scene_depth_texture, 0);
	}
}
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);

	// 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 );

	vglFramebufferTexture2DEXT(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_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);

	GL_state.Texture.Disable();

	// set and configure post shader ..
	opengl_shader_set_current( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0) );

	vglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, Scene_color_texture, 0);

	// basic/default uniforms
	GL_state.Uniform.setUniformi( "tex0", 0 );
	GL_state.Uniform.setUniformf( "rt_w", static_cast<float>(Post_texture_width));
	GL_state.Uniform.setUniformf( "rt_h", static_cast<float>(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();
}
void gr_opengl_clear_states()
{
	gr_zbias(0);
	gr_zbuffer_set(ZBUFFER_TYPE_READ);
	gr_set_cull(0);
	gr_set_fill_mode(GR_FILL_MODE_SOLID);

	opengl_shader_set_current();
}
void gr_opengl_clear_states()
{
	GL_state.Texture.DisableAll();

	gr_zbias(0);
	gr_zbuffer_set(ZBUFFER_TYPE_READ);
	gr_set_cull(0);
	gr_set_fill_mode(GR_FILL_MODE_SOLID);
	gr_reset_lighting();
	gr_set_lighting(false, false);

	opengl_shader_set_current();
}
Esempio n. 9
0
void opengl_tnl_set_material(material* material_info, bool set_base_map)
{
	int shader_handle = material_info->get_shader_handle();
	int base_map = material_info->get_texture_map(TM_BASE_TYPE);
	vec4 clr = material_info->get_color();

	Assert(shader_handle >= 0);

	opengl_shader_set_current(shader_handle);

	if ( Current_shader->shader == SDR_TYPE_PASSTHROUGH_RENDER ) {
		opengl_shader_set_passthrough(base_map >= 0, material_info->get_texture_type() == TCACHE_TYPE_AABITMAP, &clr, material_info->get_color_scale());
	}

	GL_state.SetAlphaBlendMode(material_info->get_blend_mode());
	GL_state.SetZbufferType(material_info->get_depth_mode());

	gr_set_cull(material_info->get_cull_mode() ? 1 : 0);

	gr_zbias(material_info->get_depth_bias());

	gr_set_fill_mode(material_info->get_fill_mode());

	material::fog &fog_params = material_info->get_fog();

	if ( fog_params.enabled ) {
		gr_fog_set(GR_FOGMODE_FOG, fog_params.r, fog_params.g, fog_params.b, fog_params.dist_near, fog_params.dist_far);
	} else {
		gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
	}

	gr_set_texture_addressing(material_info->get_texture_addressing());

	material::clip_plane &clip_params = material_info->get_clip_plane();

	if ( clip_params.enabled ) {
		gr_opengl_set_clip_plane(&clip_params.normal, &clip_params.position);
	} else {
		gr_opengl_set_clip_plane(NULL, NULL);
	}

	if ( set_base_map && base_map >= 0 ) {
		float u_scale, v_scale;

		if ( !gr_opengl_tcache_set(base_map, material_info->get_texture_type(), &u_scale, &v_scale) ) {
			mprintf(("WARNING: Error setting bitmap texture (%i)!\n", base_map));
		}
	}
}
void opengl_post_pass_tonemap()
{
	opengl_shader_set_current( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_TONEMAPPING, 0) );

	Current_shader->program->Uniforms.setUniformi("tex", 0);
	Current_shader->program->Uniforms.setUniformf("exposure", 4.0f);

	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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);
}
void gr_opengl_clear_states()
{
	if ( GL_version >= 30 ) {
		glBindVertexArray(GL_vao);
	}

	gr_zbias(0);
	gr_zbuffer_set(ZBUFFER_TYPE_READ);
	gr_set_cull(0);
	gr_set_fill_mode(GR_FILL_MODE_SOLID);
	gr_reset_lighting();
	gr_set_lighting(false, false);

	opengl_shader_set_current();
}
void opengl_shader_set_passthrough(bool textured)
{
	opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_PASSTHROUGH_RENDER, 0));

	if ( textured ) {
		Current_shader->program->Uniforms.setUniformi("noTexturing", 0);
	} else {
		Current_shader->program->Uniforms.setUniformi("noTexturing", 1);
	}

	Current_shader->program->Uniforms.setUniformi("alphaTexture", 0);

	Current_shader->program->Uniforms.setUniformi("srgb", High_dynamic_range ? 1 : 0);
	Current_shader->program->Uniforms.setUniformf("intensity", 1.0f);

	Current_shader->program->Uniforms.setUniformf("alphaThreshold", GL_alpha_threshold);

	Current_shader->program->Uniforms.setUniform4f("color", 1.0f, 1.0f, 1.0f, 1.0f);

	Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", gr_model_view_matrix);
	Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", gr_projection_matrix);
}
/**
 * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector
 * if compilation is successful.
 *
 * @param sdr		Identifier defined with the program we wish to compile
 * @param flags		Combination of SDR_* flags
 */
int opengl_compile_shader(shader_type sdr, uint flags)
{
	int sdr_index = -1;
	int empty_idx;
	opengl_shader_t new_shader;

	Assert(sdr < NUM_SHADER_TYPES);

	opengl_shader_type_t *sdr_info = &GL_shader_types[sdr];

	mprintf(("Compiling new shader:\n"));
	mprintf(("	%s\n", sdr_info->description));

	// figure out if the variant requested needs a geometry shader
	bool use_geo_sdr = false;

	// do we even have a geometry shader?
	if ( sdr_info->geo != NULL ) {
		for (int i = 0; i < GL_num_shader_variants; ++i) {
			opengl_shader_variant_t *variant = &GL_shader_variants[i];

			if (variant->type_id == sdr && flags & variant->flag && variant->use_geometry_sdr) {
				use_geo_sdr = true;
				break;
			}
		}
	}

	auto vertex_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags);
	auto fragment_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags);
	SCP_vector<SCP_string> geom_content;

	if ( use_geo_sdr ) {
		if (!Is_Extension_Enabled(OGL_EXT_GEOMETRY_SHADER4)) {
			return -1;
		}

		// read geometry shader
		geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags);

		Current_geo_sdr_params = &sdr_info->geo_sdr_info;
	}

	new_shader.program_id = opengl_shader_create(vertex_content, fragment_content, geom_content);

	if (!new_shader.program_id) {
		return -1;
	}

	new_shader.shader = sdr_info->type_id;
	new_shader.flags = flags;

	opengl_shader_set_current(&new_shader);

	// initialize uniforms and attributes
	for ( int i = 0; i < sdr_info->num_uniforms; ++i ) {
		opengl_shader_init_uniform( sdr_info->uniforms[i] );
	}

	for (int i = 0; i < sdr_info->num_attributes; ++i) {
		opengl_shader_init_attribute(sdr_info->attributes[i]);
	}

	// if this shader is POST_PROCESS_MAIN, hack in the user-defined flags
	if ( sdr_info->type_id == SDR_TYPE_POST_PROCESS_MAIN ) {
		opengl_post_init_uniforms(flags);
	}

	mprintf(("Shader Variant Features:\n"));

	// initialize all uniforms and attributes that are specific to this variant
	for ( int i = 0; i < GL_num_shader_variants; ++i ) {
		opengl_shader_variant_t &variant = GL_shader_variants[i];

		if ( sdr_info->type_id == variant.type_id && variant.flag & flags ) {
			for (int j = 0; j < variant.num_uniforms; ++j) {
				opengl_shader_init_uniform(variant.uniforms[j]);
			}

			for (int j = 0; j < variant.num_attributes; ++j) {
				opengl_shader_init_attribute(variant.attributes[j]);
			}

			mprintf(("	%s\n", variant.description));
		}
	}

	opengl_shader_set_current();

	// add it to our list of embedded shaders
	// see if we have empty shader slots
	empty_idx = -1;
	for ( int i = 0; i < (int)GL_shader.size(); ++i ) {
		if ( GL_shader[i].shader == NUM_SHADER_TYPES ) {
			empty_idx = i;
			break;
		}
	}

	// then insert it at an empty slot or at the end
	if ( empty_idx >= 0 ) {
		GL_shader[empty_idx] = new_shader;
		sdr_index = empty_idx;
	} else {
		sdr_index = GL_shader.size();
		GL_shader.push_back(new_shader);
	}

	return sdr_index;
}
void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_shader_t &new_shader)
{
	opengl_shader_type_t *sdr_info = &GL_shader_types[sdr];

	Assert(sdr_info->type_id == sdr);
	mprintf(("Compiling new shader:\n"));
	mprintf(("	%s\n", sdr_info->description));

	// figure out if the variant requested needs a geometry shader
	bool use_geo_sdr = false;

	// do we even have a geometry shader?
	if (sdr_info->geo != NULL) {
		for (int i = 0; i < GL_num_shader_variants; ++i) {
			opengl_shader_variant_t *variant = &GL_shader_variants[i];

			if (variant->type_id == sdr && flags & variant->flag && variant->use_geometry_sdr) {
				use_geo_sdr = true;
				break;
			}
		}
	}

	auto vert_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, use_geo_sdr);
	auto frag_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, use_geo_sdr);
	SCP_vector<SCP_string> geom_content;

	if (use_geo_sdr) {
		// read geometry shader
		geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, use_geo_sdr);
	}

	auto shader_hash = get_shader_hash(vert_content, geom_content, frag_content);
	std::unique_ptr<opengl::ShaderProgram> program(new opengl::ShaderProgram(sdr_info->description));

	if (!load_cached_shader_binary(program.get(), shader_hash)) {
		GR_DEBUG_SCOPE("Compiling shader code");
		try {
			program->addShaderCode(opengl::STAGE_VERTEX, sdr_info->vert, vert_content);
			program->addShaderCode(opengl::STAGE_FRAGMENT, sdr_info->frag, frag_content);
			if (use_geo_sdr) {
				program->addShaderCode(opengl::STAGE_GEOMETRY, sdr_info->geo, geom_content);
			}

			for (size_t i = 0; i < GL_vertex_attrib_info.size(); ++i) {
				// Check that the enum values match the position in the vector to make accessing that information more efficient
				Assertion(GL_vertex_attrib_info[i].attribute_id == (int)i, "Mistmatch between enum values and attribute vector detected!");

				// assign vert attribute binding locations before we link the shader
				glBindAttribLocation(program->getShaderHandle(), (GLint)i, GL_vertex_attrib_info[i].name.c_str());
			}

			// bind fragment data locations before we link the shader
			glBindFragDataLocation(program->getShaderHandle(), 0, "fragOut0");
			glBindFragDataLocation(program->getShaderHandle(), 1, "fragOut1");
			glBindFragDataLocation(program->getShaderHandle(), 2, "fragOut2");
			glBindFragDataLocation(program->getShaderHandle(), 3, "fragOut3");
			glBindFragDataLocation(program->getShaderHandle(), 4, "fragOut4");

			if (do_shader_caching()) {
				// Enable shader caching
				glProgramParameteri(program->getShaderHandle(), GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
			}

			program->linkProgram();
		}
		catch (const std::exception&) {
			// Since all shaders are required a compilation failure is a fatal error
			Error(LOCATION, "A shader failed to compile! Check the debug log for more information.");
		}

		cache_program_binary(program->getShaderHandle(), shader_hash);
	}

	new_shader.shader = sdr_info->type_id;
	new_shader.flags = flags;
	new_shader.program = std::move(program);

	opengl_shader_set_current(&new_shader);

	// initialize the attributes
	for (auto& attr : sdr_info->attributes) {
		new_shader.program->initAttribute(GL_vertex_attrib_info[attr].name, GL_vertex_attrib_info[attr].attribute_id, GL_vertex_attrib_info[attr].default_value);
	}

	for (auto& uniform_block : GL_uniform_blocks) {
		auto blockIndex = glGetUniformBlockIndex(new_shader.program->getShaderHandle(), uniform_block.name);

		if (blockIndex != GL_INVALID_INDEX) {
			glUniformBlockBinding(new_shader.program->getShaderHandle(), blockIndex, static_cast<GLuint>(uniform_block.block_type));
		}
	}

	mprintf(("Shader Variant Features:\n"));

	// initialize all uniforms and attributes that are specific to this variant
	for (int i = 0; i < GL_num_shader_variants; ++i) {
		opengl_shader_variant_t &variant = GL_shader_variants[i];

		if (sdr_info->type_id == variant.type_id && variant.flag & flags) {
			for (auto& attr : variant.attributes) {
				auto& attr_info = GL_vertex_attrib_info[attr];
				new_shader.program->initAttribute(attr_info.name, attr_info.attribute_id, attr_info.default_value);
			}

			mprintf(("	%s\n", variant.description));
		}
	}

	opengl_set_default_uniforms(new_shader);
}
Esempio n. 15
0
void opengl_tnl_set_material(material* material_info, bool set_base_map, bool set_clipping)
{
	int shader_handle = material_info->get_shader_handle();
	int base_map = material_info->get_texture_map(TM_BASE_TYPE);
	vec4 clr = material_info->get_color();

	Assert(shader_handle >= 0);

	opengl_shader_set_current(shader_handle);

	if (material_info->has_buffer_blend_modes()) {
		Assertion(GLAD_GL_ARB_draw_buffers_blend != 0,
				  "Buffer blend modes are not supported at the moment! Query the capability before using this feature.");

		auto enable_blend = false;
		for (auto i = 0; i < (int) material::NUM_BUFFER_BLENDS; ++i) {
			auto mode = material_info->get_blend_mode(i);

			GL_state.SetAlphaBlendModei(i, mode);
			enable_blend = enable_blend || mode != ALPHA_BLEND_NONE;
		}
		GL_state.Blend(enable_blend ? GL_TRUE : GL_FALSE);
	} else {
		GL_state.SetAlphaBlendMode(material_info->get_blend_mode());
	}
	GL_state.SetZbufferType(material_info->get_depth_mode());

	gr_set_cull(material_info->get_cull_mode() ? 1 : 0);

	gr_zbias(material_info->get_depth_bias());

	gr_set_fill_mode(material_info->get_fill_mode());

	gr_set_texture_addressing(material_info->get_texture_addressing());

	if (set_clipping) {
		// Only set the clipping state if explicitly requested by the caller to avoid unnecessary state changes
		auto& clip_params = material_info->get_clip_plane();
		if (!clip_params.enabled) {
			GL_state.ClipDistance(0, false);
		} else {
			Assertion(Current_shader != NULL && (Current_shader->shader == SDR_TYPE_MODEL
				|| Current_shader->shader == SDR_TYPE_PASSTHROUGH_RENDER
				|| Current_shader->shader == SDR_TYPE_DEFAULT_MATERIAL),
					  "Clip planes are not supported by this shader!");

			GL_state.ClipDistance(0, true);
		}
	}

	GL_state.StencilMask(material_info->get_stencil_mask());

	auto& stencilFunc = material_info->get_stencil_func();
	GL_state.StencilFunc(convertComparisionFunction(stencilFunc.compare), stencilFunc.ref, stencilFunc.mask);

	auto& frontStencilOp = material_info->get_front_stencil_op();
	GL_state.StencilOpSeparate(GL_FRONT,
							   convertStencilOp(frontStencilOp.stencilFailOperation),
							   convertStencilOp(frontStencilOp.depthFailOperation),
							   convertStencilOp(frontStencilOp.successOperation));
	auto& backStencilOp = material_info->get_back_stencil_op();
	GL_state.StencilOpSeparate(GL_BACK,
							   convertStencilOp(backStencilOp.stencilFailOperation),
							   convertStencilOp(backStencilOp.depthFailOperation),
							   convertStencilOp(backStencilOp.successOperation));

	GL_state.StencilTest(material_info->is_stencil_enabled() ? GL_TRUE : GL_FALSE);

	auto& color_mask = material_info->get_color_mask();
	GL_state.ColorMask(color_mask.x, color_mask.y, color_mask.z, color_mask.w);

	// This is only needed for the passthrough shader
	uint32_t array_index = 0;
	if ( set_base_map && base_map >= 0 ) {
		float u_scale, v_scale;

		if ( !gr_opengl_tcache_set(base_map, material_info->get_texture_type(), &u_scale, &v_scale, &array_index) ) {
			mprintf(("WARNING: Error setting bitmap texture (%i)!\n", base_map));
		}
	}

	if ( Current_shader->shader == SDR_TYPE_DEFAULT_MATERIAL ) {
		opengl_shader_set_default_material(base_map >= 0,
										   material_info->get_texture_type() == TCACHE_TYPE_AABITMAP,
										   &clr,
										   material_info->get_color_scale(),
										   array_index,
										   material_info->get_clip_plane());
	}
}
Esempio n. 16
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 FXAA
	if (Cmdline_fxaa && !fxaa_unavailable && !GL_rendering_to_texture) {
		opengl_post_pass_fxaa();
	}
	
	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<n_lights; idx++)
		{
			vec3d light_dir;
			vec3d local_light_dir;
			light_get_global_dir(&light_dir, idx);
			vm_vec_rotate(&local_light_dir, &light_dir, &Eye_matrix);
			if (!stars_sun_has_glare(idx))
				continue;
			float dot;
			if((dot=vm_vec_dot( &light_dir, &Eye_matrix.vec.fvec )) > 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);
		vglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Scene_depth_texture, 0);
	}

	// do bloom, hopefully ;)
	bool bloomed = opengl_post_pass_bloom();
	
	// do tone mapping
	opengl_post_pass_tonemap();

	// now write to the on-screen buffer
	vglBindFramebufferEXT(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<float>(timer_get_milliseconds() % 100 + 1) );

	for (size_t idx = 0; idx < Post_effects.size(); idx++) {
		if ( GL_shader[post_sdr_handle].flags & (1<<idx) ) {
			const char *name = Post_effects[idx].uniform_name.c_str();
			float value = Post_effects[idx].intensity;

			GL_state.Uniform.setUniformf( name, value);
		}
	}

	// bloom uniforms, but only if we did the bloom
	if (bloomed) {
		float intensity = MIN((float)Cmdline_bloom_intensity, 200.0f) * 0.01f;

		if (Neb2_render_mode != NEB2_RENDER_NONE) {
			// we need less intensity for full neb missions, so cut it by 30%
			intensity /= 3.0f;
		}

		//GL_state.Uniform.setUniformf( "bloom_intensity", intensity );
		GL_state.Uniform.setUniformf( "bloom_intensity", 0.0f );
		GL_state.Uniform.setUniformi( "levels" , MAX_MIP_BLUR_LEVELS );
		GL_state.Uniform.setUniformi( "bloomed", 1 );

		GL_state.Texture.SetActiveUnit(1);
		GL_state.Texture.SetTarget(GL_TEXTURE_2D);
		//GL_state.Texture.Enable(Post_bloom_texture_id[2]);
		GL_state.Texture.Enable(Bloom_textures[0]);
	}
	else
		GL_state.Uniform.setUniformf( "bloom_intensity", 0.0f );

	// now render it to the screen ...
	vglBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	//GL_state.Texture.Enable(Scene_color_texture);
	GL_state.Texture.Enable(Scene_ldr_texture);

	GL_state.Texture.SetActiveUnit(2);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_depth_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);

	//Shadow Map debug window
//#define SHADOW_DEBUG
#ifdef SHADOW_DEBUG
	opengl_shader_set_current( &GL_post_shader[8] );	
	GL_state.Texture.SetActiveUnit(0);
//	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
//	GL_state.Texture.Enable(Shadow_map_depth_texture);
	extern GLuint Shadow_map_texture;
	extern GLuint Post_shadow_texture_id;
	GL_state.Texture.Enable(Shadow_map_texture);
	vglUniform1iARB( opengl_shader_get_uniform("shadow_map"), 0);
	vglUniform1iARB( opengl_shader_get_uniform("index"), 0);
	//opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, Scene_texture_u_scale, Scene_texture_u_scale);
	//opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.5f);
	opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 1.0f, 1.0f);
	vglUniform1iARB( opengl_shader_get_uniform("index"), 1);
	//opengl_draw_textured_quad(-1.0f, -0.5f, 0.5f, 0.0f, -0.5f, 0.0f, 0.75f, 0.25f);
	opengl_draw_textured_quad(-1.0f, -0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 1.0f, 1.0f);
	vglUniform1iARB( opengl_shader_get_uniform("index"), 2);
	opengl_draw_textured_quad(-0.5f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 1.0f, 1.0f);
	vglUniform1iARB( opengl_shader_get_uniform("index"), 3);
	opengl_draw_textured_quad(-0.5f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 1.0f, 1.0f);
	opengl_shader_set_current();
#endif

	/*GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_depth_texture);

	
	*/
	// Done!
	/*GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_effect_texture);

	opengl_draw_textured_quad(0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, Scene_texture_u_scale, Scene_texture_u_scale);

	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_normal_texture);

	opengl_draw_textured_quad(-1.0f, -0.0f, 0.0f, 0.0f, 0.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale);

	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_specular_texture);

	opengl_draw_textured_quad(0.0f, -0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale);
	*/
	GL_state.Texture.SetActiveUnit(2);
	GL_state.Texture.Disable();
	GL_state.Texture.SetActiveUnit(1);
	GL_state.Texture.Disable();
	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.Disable();

	GL_state.Texture.SetShaderMode(GL_FALSE);

	// reset state
	GL_state.DepthTest(depth);
	GL_state.DepthMask(depth_mask);
	GL_state.Lighting(lighting);
	GL_state.Blend(blend);
	GL_state.CullFace(cull);

	opengl_shader_set_current();

	Post_in_frame = false;
}
/**
 * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector
 * if compilation is successful.
 * This function is used for main (i.e. model rendering) and particle shaders, post processing shaders use their own infrastructure
 *
 * @param flags		Combination of SDR_* flags
 */
void opengl_compile_main_shader(int flags) {
	char *vert = NULL, *frag = NULL;

	mprintf(("Compiling new shader:\n"));

	bool in_error = false;
	opengl_shader_t new_shader;

	// choose appropriate files
	char vert_name[NAME_LENGTH];
	char frag_name[NAME_LENGTH];

	if (flags & SDR_FLAG_SOFT_QUAD) {
		strcpy_s( vert_name, "soft-v.sdr");
		strcpy_s( frag_name, "soft-f.sdr");
	} else {
		strcpy_s( vert_name, "main-v.sdr");
		strcpy_s( frag_name, "main-f.sdr");
	}

	// read vertex shader
	if ( (vert = opengl_load_shader(vert_name, flags)) == NULL ) {
		in_error = true;
		goto Done;
	}

	// read fragment shader
	if ( (frag = opengl_load_shader(frag_name, flags)) == NULL ) {
		in_error = true;
		goto Done;
	}

	Verify( vert != NULL );
	Verify( frag != NULL );

	new_shader.program_id = opengl_shader_create(vert, frag);

	if ( !new_shader.program_id ) {
		in_error = true;
		goto Done;
	}

	new_shader.flags = flags;

	opengl_shader_set_current( &new_shader );
	
	mprintf(("Shader features:\n"));

	//Init all the uniforms
	if (new_shader.flags & SDR_FLAG_SOFT_QUAD) {
		for (int j = 0; j < Particle_shader_flag_references; j++) {
			if (new_shader.flags == GL_Uniform_Reference_Particle[j].flag) {
				int k;

			// Equality check needed because the combination of SDR_FLAG_SOFT_QUAD and SDR_FLAG_DISTORTION define something very different
			// than just SDR_FLAG_SOFT_QUAD alone
				for (k = 0; k < GL_Uniform_Reference_Particle[j].num_uniforms; k++) {
					opengl_shader_init_uniform( GL_Uniform_Reference_Particle[j].uniforms[k] );
				}

				for (k = 0; k < GL_Uniform_Reference_Particle[j].num_attributes; k++) {
					opengl_shader_init_attribute( GL_Uniform_Reference_Particle[j].attributes[k] );
				}

				mprintf(("   %s\n", GL_Uniform_Reference_Particle[j].name));
			}
		}
	} else {
		for (int j = 0; j < Main_shader_flag_references; j++) {
			if (new_shader.flags & GL_Uniform_Reference_Main[j].flag) {
				if (GL_Uniform_Reference_Main[j].num_uniforms > 0) {
					for (int k = 0; k < GL_Uniform_Reference_Main[j].num_uniforms; k++) {
						opengl_shader_init_uniform( GL_Uniform_Reference_Main[j].uniforms[k] );
					}
				}

				if (GL_Uniform_Reference_Main[j].num_attributes > 0) {
					for (int k = 0; k < GL_Uniform_Reference_Main[j].num_attributes; k++) {
						opengl_shader_init_attribute( GL_Uniform_Reference_Main[j].attributes[k] );
					}
				}

				mprintf(("   %s\n", GL_Uniform_Reference_Main[j].name));
			}
		}
	}

	opengl_shader_set_current();

	// add it to our list of embedded shaders
	GL_shader.push_back( new_shader );

Done:
	if (vert != NULL) {
		vm_free(vert);
		vert = NULL;
	}

	if (frag != NULL) {
		vm_free(frag);
		frag = NULL;
	}

	if (in_error) {
		// shut off relevant usage things ...
		bool dealt_with = false;

		if (flags & SDR_FLAG_HEIGHT_MAP) {
			mprintf(("  Shader in_error!  Disabling height maps!\n"));
			Cmdline_height = 0;
			dealt_with = true;
		}

		if (flags & SDR_FLAG_NORMAL_MAP) {
			mprintf(("  Shader in_error!  Disabling normal maps and height maps!\n"));
			Cmdline_height = 0;
			Cmdline_normal = 0;
			dealt_with = true;
		}

		if (!dealt_with) {
			if (flags == 0) {
				mprintf(("  Shader in_error!  Disabling GLSL!\n"));

				Use_GLSL = 0;
				Cmdline_height = 0;
				Cmdline_normal = 0;

				GL_shader.clear();
			} else {
				// We died on a lighting shader, probably due to instruction count.
				// Drop down to a special var that will use fixed-function rendering
				// but still allow for post-processing to work
				mprintf(("  Shader in_error!  Disabling GLSL model rendering!\n"));
				Use_GLSL = 1;
				Cmdline_height = 0;
				Cmdline_normal = 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 blend = GL_state.Blend(GL_FALSE);
	GLboolean cull = GL_state.CullFace(GL_FALSE);

	GL_state.Texture.SetShaderMode(GL_TRUE);
	
	// do bloom, hopefully ;)
	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
	glBindFramebuffer(GL_FRAMEBUFFER, opengl_get_rtt_framebuffer());

	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	// 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
	Current_shader->program->Uniforms.setUniformi( "tex", 0 );
	Current_shader->program->Uniforms.setUniformi( "depth_tex", 1);
	Current_shader->program->Uniforms.setUniformf( "timer", static_cast<float>(timer_get_milliseconds() % 100 + 1) );

	for (size_t idx = 0; idx < Post_effects.size(); idx++) {
		if ( GL_shader[post_sdr_handle].flags & (1<<idx) ) {
			const char *name = Post_effects[idx].uniform_name.c_str();
			float value = Post_effects[idx].intensity;

			Current_shader->program->Uniforms.setUniformf( name, value);
		}
	}

	// now render it to the screen ...
	glBindFramebuffer(GL_FRAMEBUFFER,0);
	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	//GL_state.Texture.Enable(Scene_color_texture);
	GL_state.Texture.Enable(Scene_ldr_texture);

	GL_state.Texture.SetActiveUnit(1);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_depth_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);

	//Shadow Map debug window
//#define SHADOW_DEBUG
#ifdef SHADOW_DEBUG
	opengl_shader_set_current( &GL_post_shader[8] );	
	GL_state.Texture.SetActiveUnit(0);
//	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
//	GL_state.Texture.Enable(Shadow_map_depth_texture);
	extern GLuint Shadow_map_texture;
	extern GLuint Post_shadow_texture_id;
	GL_state.Texture.Enable(Shadow_map_texture);
	glUniform1iARB( opengl_shader_get_uniform("shadow_map"), 0);
	glUniform1iARB( opengl_shader_get_uniform("index"), 0);
	//opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, Scene_texture_u_scale, Scene_texture_u_scale);
	//opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.5f);
	opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 1.0f, 1.0f);
	glUniform1iARB( opengl_shader_get_uniform("index"), 1);
	//opengl_draw_textured_quad(-1.0f, -0.5f, 0.5f, 0.0f, -0.5f, 0.0f, 0.75f, 0.25f);
	opengl_draw_textured_quad(-1.0f, -0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 1.0f, 1.0f);
	glUniform1iARB( opengl_shader_get_uniform("index"), 2);
	opengl_draw_textured_quad(-0.5f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 1.0f, 1.0f);
	glUniform1iARB( opengl_shader_get_uniform("index"), 3);
	opengl_draw_textured_quad(-0.5f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 1.0f, 1.0f);
	opengl_shader_set_current();
#endif

	/*GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_depth_texture);

	
	*/
	// Done!
	/*GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_effect_texture);

	opengl_draw_textured_quad(0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, Scene_texture_u_scale, Scene_texture_u_scale);

	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_normal_texture);

	opengl_draw_textured_quad(-1.0f, -0.0f, 0.0f, 0.0f, 0.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale);

	GL_state.Texture.SetActiveUnit(0);
	GL_state.Texture.SetTarget(GL_TEXTURE_2D);
	GL_state.Texture.Enable(Scene_specular_texture);

	opengl_draw_textured_quad(0.0f, -0.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale);
	*/

	GL_state.Texture.SetShaderMode(GL_FALSE);

	// reset state
	GL_state.DepthTest(depth);
	GL_state.DepthMask(depth_mask);
	GL_state.Blend(blend);
	GL_state.CullFace(cull);

	opengl_shader_set_current();

	Post_in_frame = false;
}
void opengl_post_pass_bloom()
{
	// we need the scissor test disabled
	GLboolean scissor_test = GL_state.ScissorTest(GL_FALSE);

	// ------  begin bright pass ------

	glBindFramebuffer(GL_FRAMEBUFFER, Bloom_framebuffer);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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) );

	Current_shader->program->Uniforms.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);

	// ------ 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]);

	glGenerateMipmap(GL_TEXTURE_2D);

	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));
			}

			Current_shader->program->Uniforms.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;

				Current_shader->program->Uniforms.setUniformf("texSize", (pass) ? 1.0f / i2fl(bloom_width) : 1.0f / i2fl(bloom_height));
				Current_shader->program->Uniforms.setUniformi("level", mipmap);
				Current_shader->program->Uniforms.setUniformf("tapSize", 1.0f);

				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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);
			}
		}
	}

	// composite blur to the color texture

	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Scene_color_texture, 0);

	opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_BLOOM_COMP, 0));

	Current_shader->program->Uniforms.setUniformi("tex", 0);
	Current_shader->program->Uniforms.setUniformi("levels", MAX_MIP_BLUR_LEVELS);
	Current_shader->program->Uniforms.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);
}