Files
fs2open.github.com/code/graphics/opengl/gropengldraw.cpp
T
Goober5000andClaude Opus 5 1fdb67649c Clear cockpit depth mask each frame so lightshafts don't use a stale one (#7775)
Views that don't render the cockpit (external, chase, topdown, etc.) left
Cockpit_depth_texture holding the last cockpit-view frame, so the lightshaft
pass painted that silhouette.  Fixes #7568.

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-12 02:59:38 +02:00

1318 lines
42 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include "gropengldraw.h"
#include "globalincs/pstypes.h"
#include "ShaderProgram.h"
#include "freespace.h"
#include "gropengl.h"
#include "gropengldeferred.h"
#include "gropenglpostprocessing.h"
#include "gropenglshader.h"
#include "gropengltexture.h"
#include "gropengltnl.h"
#include "cmdline/cmdline.h"
#include "graphics/light.h"
#include "graphics/matrix.h"
#include "graphics/paths/PathRenderer.h"
#include "graphics/util/uniform_structs.h"
#include "lighting/lighting.h"
#include "render/3d.h"
#include "tracing/tracing.h"
#ifdef USE_OPENGL_ES
#include "es_compatibility.h"
#endif
GLuint Scene_framebuffer;
GLuint Scene_framebuffer_ms;
GLuint Scene_ldr_texture;
GLuint Scene_color_texture;
GLuint Scene_position_texture;
GLuint Scene_normal_texture;
GLuint Scene_specular_texture;
GLuint Scene_emissive_texture;
GLuint Scene_color_texture_ms;
GLuint Scene_position_texture_ms;
GLuint Scene_normal_texture_ms;
GLuint Scene_specular_texture_ms;
GLuint Scene_emissive_texture_ms;
GLuint Scene_composite_texture;
GLuint Scene_luminance_texture;
GLuint Scene_depth_texture;
GLuint Scene_depth_texture_ms;
GLuint Cockpit_depth_texture;
GLuint Back_framebuffer;
GLuint Back_texture;
GLuint Back_depth_texture;
GLuint GammaBlit_framebuffer;
GLuint GammaBlit_texture;
GLuint Distortion_framebuffer = 0;
GLuint Distortion_texture[2];
int Distortion_switch = 0;
int Scene_texture_initialized;
int Scene_texture_width;
int Scene_texture_height;
GLfloat Scene_texture_u_scale = 1.0f;
GLfloat Scene_texture_v_scale = 1.0f;
inline GLenum opengl_primitive_type(primitive_type prim_type)
{
switch ( prim_type ) {
case PRIM_TYPE_POINTS:
return GL_POINTS;
case PRIM_TYPE_TRIS:
return GL_TRIANGLES;
case PRIM_TYPE_TRISTRIP:
return GL_TRIANGLE_STRIP;
case PRIM_TYPE_TRIFAN:
return GL_TRIANGLE_FAN;
case PRIM_TYPE_LINES:
return GL_LINES;
case PRIM_TYPE_LINESTRIP:
return GL_LINE_STRIP;
default:
return GL_TRIANGLE_FAN;
}
}
void gr_opengl_sphere(material* material_def, float /*rad*/)
{
opengl_tnl_set_material(material_def, true);
opengl_draw_sphere();
}
extern int opengl_check_framebuffer();
void opengl_setup_scene_textures()
{
Scene_texture_initialized = 0;
if ( Cmdline_no_fbo ) {
Gr_post_processing_enabled = false;
Gr_enable_soft_particles = false;
Gr_framebuffer_effects = {};
Scene_ldr_texture = 0;
Scene_color_texture = 0;
Scene_depth_texture = 0;
return;
}
// clamp size, if needed
Scene_texture_width = gr_screen.max_w;
Scene_texture_height = gr_screen.max_h;
if ( Scene_texture_width > GL_max_renderbuffer_size ) {
Scene_texture_width = GL_max_renderbuffer_size;
}
if ( Scene_texture_height > GL_max_renderbuffer_size) {
Scene_texture_height = GL_max_renderbuffer_size;
}
// create framebuffer
glGenFramebuffers(1, &Scene_framebuffer);
GL_state.BindFrameBuffer(Scene_framebuffer);
opengl_set_object_label(GL_FRAMEBUFFER, Scene_framebuffer, "Scene framebuffer");
// setup main render texture
// setup high dynamic range color texture
glGenTextures(1, &Scene_color_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_color_texture);
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_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Scene_color_texture, 0);
opengl_set_object_label(GL_TEXTURE, Scene_color_texture, "Scene color texture");
// setup low dynamic range color texture
glGenTextures(1, &Scene_ldr_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_ldr_texture);
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_RGBA8, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_ldr_texture, "Scene LDR texture");
// setup position render texture
glGenTextures(1, &Scene_position_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_position_texture);
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_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_position_texture, "Scene Position texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, Scene_position_texture, 0);
// setup normal render texture
glGenTextures(1, &Scene_normal_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_normal_texture);
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_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_normal_texture, "Scene Normal texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, Scene_normal_texture, 0);
// setup specular render texture
glGenTextures(1, &Scene_specular_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_specular_texture);
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_RGBA8, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_specular_texture, "Scene Specular texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, Scene_specular_texture, 0);
// setup emissive render texture
glGenTextures(1, &Scene_emissive_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_emissive_texture);
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_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glGenerateMipmap(GL_TEXTURE_2D);
opengl_set_object_label(GL_TEXTURE, Scene_emissive_texture, "Scene Emissive texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, Scene_emissive_texture, 0);
// setup compositing render texture
glGenTextures(1, &Scene_composite_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_composite_texture);
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_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_composite_texture, "Scene Composite texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_composite_texture, 0);
//Set up luminance texture (used as input for FXAA)
// also used as a light accumulation buffer during the deferred pass
glGenTextures(1, &Scene_luminance_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_luminance_texture);
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_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_luminance_texture, "Scene Luminance texture");
// setup cockpit depth texture
glGenTextures(1, &Cockpit_depth_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Cockpit_depth_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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_COMPARE_MODE, GL_NONE);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_DEPTH24_STENCIL8,
Scene_texture_width,
Scene_texture_height,
0,
GL_DEPTH_COMPONENT,
GL_FLOAT,
nullptr);
opengl_set_object_label(GL_TEXTURE, Cockpit_depth_texture, "Cockpit depth texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, Cockpit_depth_texture, 0);
gr_zbuffer_set(GR_ZBUFF_FULL);
glClear(GL_DEPTH_BUFFER_BIT);
// setup main depth texture
glGenTextures(1, &Scene_depth_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_depth_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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_COMPARE_MODE, GL_NONE);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_DEPTH24_STENCIL8,
Scene_texture_width,
Scene_texture_height,
0,
GL_DEPTH_COMPONENT,
GL_FLOAT,
nullptr);
opengl_set_object_label(GL_TEXTURE, Scene_depth_texture, "Scene depth texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, Scene_depth_texture, 0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
if ( opengl_check_framebuffer() ) {
GL_state.BindFrameBuffer(0);
glDeleteFramebuffers(1, &Scene_framebuffer);
Scene_framebuffer = 0;
glDeleteTextures(1, &Scene_color_texture);
Scene_color_texture = 0;
glDeleteTextures(1, &Scene_position_texture);
Scene_position_texture = 0;
glDeleteTextures(1, &Scene_normal_texture);
Scene_normal_texture = 0;
glDeleteTextures(1, &Scene_specular_texture);
Scene_specular_texture = 0;
glDeleteTextures(1, &Scene_emissive_texture);
Scene_emissive_texture = 0;
glDeleteTextures(1, &Scene_depth_texture);
Scene_depth_texture = 0;
glDeleteTextures(1, &Scene_luminance_texture);
Scene_luminance_texture = 0;
//glDeleteTextures(1, &Scene_fxaa_output_texture);
//Scene_fxaa_output_texture = 0;
Gr_post_processing_enabled = false;
Gr_enable_soft_particles = false;
return;
}
#ifdef USE_OPENGL_ES
if (Cmdline_msaa_enabled > 0) {
Cmdline_msaa_enabled = 0;
Warning(LOCATION, "MSAA is not currently supported under OpenGL ES. Disabling MSAA.");
}
#endif
if (Cmdline_msaa_enabled > 0) {
glEnable(GL_MULTISAMPLE);
// Make sure our MSAA setting are valid
int maxSamples;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
//Disallow >16 samples due to manual sorting networks in shader
if (maxSamples > 16)
maxSamples = 16;
if (maxSamples < Cmdline_msaa_enabled) {
Warning(LOCATION, "Requested MSAA level of %d is not supported. Max MSAA level is %d.", Cmdline_msaa_enabled, maxSamples);
Cmdline_msaa_enabled = maxSamples;
}
else if (Cmdline_msaa_enabled & (Cmdline_msaa_enabled - 1)) {
int newLevel = 1 << (sizeof(int) * 8 - 2);
while ((newLevel & Cmdline_msaa_enabled) == 0)
newLevel = newLevel >> 1;
Warning(LOCATION, "Requested MSAA level of %d is not a power of 2. Setting to %d.", Cmdline_msaa_enabled, newLevel);
Cmdline_msaa_enabled = newLevel;
}
// create framebuffer
glGenFramebuffers(1, &Scene_framebuffer_ms);
GL_state.BindFrameBuffer(Scene_framebuffer_ms);
opengl_set_object_label(GL_FRAMEBUFFER, Scene_framebuffer_ms, "Scene framebuffer multisampling");
// setup high dynamic range color texture
glGenTextures(1, &Scene_color_texture_ms);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE);
GL_state.Texture.Enable(Scene_color_texture_ms);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
Cmdline_msaa_enabled,
GL_RGBA16F,
Scene_texture_width,
Scene_texture_height,
GL_TRUE);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D_MULTISAMPLE,
Scene_color_texture_ms,
0);
opengl_set_object_label(GL_TEXTURE, Scene_color_texture_ms, "Scene color texture multisampling");
// setup position render texture
glGenTextures(1, &Scene_position_texture_ms);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE);
GL_state.Texture.Enable(Scene_position_texture_ms);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
Cmdline_msaa_enabled,
GL_RGBA16F,
Scene_texture_width,
Scene_texture_height,
GL_TRUE);
opengl_set_object_label(GL_TEXTURE, Scene_position_texture_ms, "Scene Position texture multisampling");
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D_MULTISAMPLE,
Scene_position_texture_ms,
0);
// setup normal render texture
glGenTextures(1, &Scene_normal_texture_ms);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE);
GL_state.Texture.Enable(Scene_normal_texture_ms);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
Cmdline_msaa_enabled,
GL_RGBA16F,
Scene_texture_width,
Scene_texture_height,
GL_TRUE);
opengl_set_object_label(GL_TEXTURE, Scene_normal_texture_ms, "Scene Normal texture multisampling");
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT2,
GL_TEXTURE_2D_MULTISAMPLE,
Scene_normal_texture_ms,
0);
// setup specular render texture
glGenTextures(1, &Scene_specular_texture_ms);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE);
GL_state.Texture.Enable(Scene_specular_texture_ms);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
Cmdline_msaa_enabled,
GL_RGBA8,
Scene_texture_width,
Scene_texture_height,
GL_TRUE);
opengl_set_object_label(GL_TEXTURE, Scene_specular_texture_ms, "Scene Specular texture multisample");
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT3,
GL_TEXTURE_2D_MULTISAMPLE,
Scene_specular_texture_ms,
0);
// setup emissive render texture
glGenTextures(1, &Scene_emissive_texture_ms);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE);
GL_state.Texture.Enable(Scene_emissive_texture_ms);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
Cmdline_msaa_enabled,
GL_RGBA16F,
Scene_texture_width,
Scene_texture_height,
GL_TRUE);
opengl_set_object_label(GL_TEXTURE, Scene_emissive_texture_ms, "Scene Emissive texture multisample");
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT4,
GL_TEXTURE_2D_MULTISAMPLE,
Scene_emissive_texture_ms,
0);
// setup main depth texture
glGenTextures(1, &Scene_depth_texture_ms);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_MULTISAMPLE);
GL_state.Texture.Enable(Scene_depth_texture_ms);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
Cmdline_msaa_enabled,
GL_DEPTH24_STENCIL8,
Scene_texture_width,
Scene_texture_height,
GL_TRUE);
opengl_set_object_label(GL_TEXTURE, Scene_depth_texture_ms, "Scene depth texture multisample");
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D_MULTISAMPLE,
Scene_depth_texture_ms,
0);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
}
if (Cmdline_window_res) {
//Gen Framebuffer
glGenFramebuffers(1, &Back_framebuffer);
GL_state.BindFrameBuffer(Back_framebuffer);
opengl_set_object_label(GL_FRAMEBUFFER, Back_framebuffer, "Backbuffer");
// setup main render texture
// setup high dynamic range color texture
glGenTextures(1, &Back_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Back_texture);
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_RGBA16F, gr_screen.max_w, gr_screen.max_h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Back_texture, 0);
opengl_set_object_label(GL_TEXTURE, Back_texture, "Backbuffer texture");
glGenTextures(1, &Back_depth_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Back_depth_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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_COMPARE_MODE, GL_NONE);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_DEPTH24_STENCIL8,
gr_screen.max_w,
gr_screen.max_h,
0,
GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8,
nullptr);
opengl_set_object_label(GL_TEXTURE, Back_depth_texture, "Backbuffer depth texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, Back_depth_texture, 0);
gr_zbuffer_set(GR_ZBUFF_FULL);
glClear(GL_DEPTH_BUFFER_BIT);
// Intermediate target for the gamma-correction pass. The gamma pass samples Back_texture and writes
// here (an offscreen FBO->FBO draw, same as every other post-process pass); the result is then
// presented to the window via glBlitFramebuffer. Some drivers show flicker when a shader draw that
// samples a just-rendered texture targets the window-system default framebuffer directly, so the
// final presentation step always goes through a blit instead.
glGenFramebuffers(1, &GammaBlit_framebuffer);
GL_state.BindFrameBuffer(GammaBlit_framebuffer);
opengl_set_object_label(GL_FRAMEBUFFER, GammaBlit_framebuffer, "Gamma blit framebuffer");
if (Scene_ldr_texture != 0 && Scene_texture_width == gr_screen.max_w && Scene_texture_height == gr_screen.max_h) {
// Scene_ldr_texture is dead scratch by flip time: its consumers (tonemap, AA, the final
// post pass) all write before reading within gr_opengl_post_process_end(), which completes
// before the flip. Reuse it as the gamma pass target instead of allocating another
// screen-sized texture. GammaBlit_texture stays 0 so shutdown won't delete it.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Scene_ldr_texture, 0);
} else {
// Scene textures are clamped to GL_max_renderbuffer_size and may not cover the screen;
// fall back to a dedicated texture in that case.
glGenTextures(1, &GammaBlit_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(GammaBlit_texture);
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_RGBA8, gr_screen.max_w, gr_screen.max_h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GammaBlit_texture, 0);
opengl_set_object_label(GL_TEXTURE, GammaBlit_texture, "Gamma blit texture");
}
GL_state.BindFrameBuffer(Back_framebuffer);
}
//Setup thruster distortion framebuffer
if (Gr_framebuffer_effects.any_set())
{
glGenFramebuffers(1, &Distortion_framebuffer);
GL_state.BindFrameBuffer(Distortion_framebuffer);
glGenTextures(2, Distortion_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Distortion_texture[0]);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 32, 32, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
GL_state.Texture.Enable(Distortion_texture[1]);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 32, 32, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Distortion_texture[0], 0);
}
if ( opengl_check_framebuffer() ) {
GL_state.BindFrameBuffer(0);
glDeleteFramebuffers(1, &Distortion_framebuffer);
Distortion_framebuffer = 0;
glDeleteTextures(2, Distortion_texture);
Distortion_texture[0] = 0;
Distortion_texture[1] = 0;
return;
}
if ( opengl_check_for_errors("post_init_framebuffer()") ) {
Scene_color_texture = 0;
Scene_depth_texture = 0;
Gr_post_processing_enabled = false;
Gr_enable_soft_particles = false;
return;
}
GL_state.BindFrameBuffer(0);
Scene_texture_initialized = 1;
Scene_framebuffer_in_frame = false;
}
void opengl_scene_texture_shutdown()
{
if ( !Scene_texture_initialized ) {
return;
}
if ( Scene_color_texture ) {
glDeleteTextures(1, &Scene_color_texture);
Scene_color_texture = 0;
}
if ( Scene_position_texture ) {
glDeleteTextures(1, &Scene_position_texture);
Scene_position_texture = 0;
}
if ( Scene_normal_texture ) {
glDeleteTextures(1, &Scene_normal_texture);
Scene_normal_texture = 0;
}
if ( Scene_specular_texture ) {
glDeleteTextures(1, &Scene_specular_texture);
Scene_specular_texture = 0;
}
if (Scene_emissive_texture) {
glDeleteTextures(1, &Scene_emissive_texture);
Scene_emissive_texture = 0;
}
if ( Scene_depth_texture ) {
glDeleteTextures(1, &Scene_depth_texture);
Scene_depth_texture = 0;
}
if ( Scene_framebuffer ) {
glDeleteFramebuffers(1, &Scene_framebuffer);
Scene_framebuffer = 0;
}
if (Back_texture) {
glDeleteTextures(1, &Back_texture);
Back_texture = 0;
}
if (Back_depth_texture) {
glDeleteTextures(1, &Back_depth_texture);
Back_depth_texture = 0;
}
if (Back_framebuffer) {
glDeleteFramebuffers(1, &Back_framebuffer);
Back_framebuffer = 0;
}
if (GammaBlit_texture) {
glDeleteTextures(1, &GammaBlit_texture);
GammaBlit_texture = 0;
}
if (GammaBlit_framebuffer) {
glDeleteFramebuffers(1, &GammaBlit_framebuffer);
GammaBlit_framebuffer = 0;
}
glDeleteTextures(2, Distortion_texture);
Distortion_texture[0] = 0;
Distortion_texture[1] = 0;
if ( Distortion_framebuffer ) {
glDeleteFramebuffers(1, &Distortion_framebuffer);
Distortion_framebuffer = 0;
}
Scene_texture_initialized = 0;
Scene_framebuffer_in_frame = false;
}
void gr_opengl_scene_texture_begin()
{
if ( !Scene_texture_initialized ) {
return;
}
if ( Scene_framebuffer_in_frame ) {
return;
}
GR_DEBUG_SCOPE("Begin scene texture");
TRACE_SCOPE(tracing::SceneTextureBegin);
GL_state.PushFramebufferState();
GL_state.BindFrameBuffer(Scene_framebuffer);
// The cockpit depth mask is only written when the cockpit is actually rendered (see
// gr_opengl_post_process_save_zbuffer), and the views that skip it -- external, chase,
// topdown, warp chase -- would otherwise leave the lightshaft pass masking against the
// silhouette left over from the last cockpit-view frame. Clear it every frame; when a
// cockpit does render, save_zbuffer clears it again anyway.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, Cockpit_depth_texture, 0);
GL_state.SetZbufferType(ZBUFFER_TYPE_FULL);
glClear(GL_DEPTH_BUFFER_BIT);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, Scene_depth_texture, 0);
if (GL_rendering_to_texture)
{
Scene_texture_u_scale = i2fl(gr_screen.max_w) / i2fl(Scene_texture_width);
Scene_texture_v_scale = i2fl(gr_screen.max_h) / i2fl(Scene_texture_height);
CLAMP(Scene_texture_u_scale, 0.0f, 1.0f);
CLAMP(Scene_texture_v_scale, 0.0f, 1.0f);
}
else
{
Scene_texture_u_scale = 1.0f;
Scene_texture_v_scale = 1.0f;
}
if (!light_deferred_enabled()) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} else {
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
glDrawBuffers(6, buffers);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
opengl_clear_deferred_buffers();
if (Cmdline_msaa_enabled > 0) {
GL_state.BindFrameBuffer(Scene_framebuffer_ms);
glDrawBuffers(6, buffers);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
opengl_clear_deferred_buffers();
GL_state.BindFrameBuffer(Scene_framebuffer);
}
glDrawBuffer(GL_COLOR_ATTACHMENT0);
}
Scene_framebuffer_in_frame = true;
if ( Gr_post_processing_enabled && !PostProcessing_override ) {
High_dynamic_range = true;
}
}
float time_buffer = 0.0f;
void gr_opengl_scene_texture_end()
{
if ( !Scene_framebuffer_in_frame ) {
return;
}
GR_DEBUG_SCOPE("End scene texture");
TRACE_SCOPE(tracing::SceneTextureEnd);
time_buffer+=flFrametime;
if(time_buffer>0.03f)
{
gr_opengl_update_distortion();
time_buffer = 0.0f;
}
if ( Gr_post_processing_enabled && !PostProcessing_override ) {
gr_opengl_post_process_end();
} else {
GR_DEBUG_SCOPE("Draw scene texture");
TRACE_SCOPE(tracing::DrawSceneTexture);
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.PopFramebufferState();
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_color_texture);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
opengl_shader_set_passthrough(true, High_dynamic_range);
GL_state.Array.BindArrayBuffer(0);
if (GL_rendering_to_texture)
{
opengl_draw_textured_quad(0.0f, 0.0f, 0.0f, 0.0f, (float)gr_screen.max_w, (float)gr_screen.max_h, Scene_texture_u_scale, Scene_texture_v_scale);
}
else
{
opengl_draw_textured_quad(0.0f, 0.0f, 0.0f, Scene_texture_v_scale, (float)gr_screen.max_w, (float)gr_screen.max_h, Scene_texture_u_scale, 0.0f);
}
// reset state
GL_state.DepthTest(depth);
GL_state.DepthMask(depth_mask);
GL_state.Blend(blend);
GL_state.CullFace(cull);
}
// Reset the UV scale values
Scene_texture_u_scale = 1.0f;
Scene_texture_v_scale = 1.0f;
Scene_framebuffer_in_frame = false;
High_dynamic_range = false;
}
void gr_opengl_copy_effect_texture()
{
GR_DEBUG_SCOPE("Copy effect texture");
if ( !Scene_framebuffer_in_frame ) {
return;
}
//Make sure we're reading from the up-to-date color texture
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT5);
glBlitFramebuffer(0, 0, gr_screen.max_w, gr_screen.max_h, 0, 0, gr_screen.max_w, gr_screen.max_h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
}
void gr_opengl_render_shield_impact(shield_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
gr_buffer_handle buffer_handle,
int n_verts)
{
matrix4 impact_transform;
matrix4 impact_projection;
vec3d min;
vec3d max;
opengl_tnl_set_material(material_info, false);
float radius = material_info->get_impact_radius();
min.xyz.x = min.xyz.y = min.xyz.z = -radius;
max.xyz.x = max.xyz.y = max.xyz.z = radius;
vm_matrix4_set_orthographic(&impact_projection, &max, &min);
matrix impact_orient = material_info->get_impact_orient();
vec3d impact_pos = material_info->get_impact_pos();
vm_matrix4_set_inverse_transform(&impact_transform, &impact_orient, &impact_pos);
uint32_t array_index = 0;
if (material_info->get_texture_map(TM_BASE_TYPE) >= 0) {
float u_scale, v_scale;
if (!gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE), material_info->get_texture_type(),
&u_scale, &v_scale, &array_index)) {
mprintf(("WARNING: Error setting bitmap texture (%i)!\n", material_info->get_texture_map(TM_BASE_TYPE)));
}
}
opengl_set_generic_uniform_data<graphics::generic_data::shield_impact_data>(
[&](graphics::generic_data::shield_impact_data* data) {
data->hitNormal = impact_orient.vec.fvec;
data->shieldProjMatrix = impact_projection;
data->shieldModelViewMatrix = impact_transform;
data->shieldMapIndex = array_index;
data->srgb = High_dynamic_range ? 1 : 0;
data->color = material_info->get_color();
});
gr_matrix_set_uniforms();
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, 0, 0);
}
void gr_opengl_update_distortion()
{
if (Distortion_framebuffer == 0) {
// distortion is disabled
return;
}
GR_DEBUG_SCOPE("Update distortion");
TRACE_SCOPE(tracing::UpdateDistortion);
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);
opengl_shader_set_passthrough(true, High_dynamic_range);
GL_state.PushFramebufferState();
GL_state.BindFrameBuffer(Distortion_framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Distortion_texture[!Distortion_switch], 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glViewport(0,0,32,32);
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Distortion_texture[Distortion_switch]);
glClearColor(0.5f, 0.5f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
vertex vertices[4];
vertices[0].texture_position.u = 0.0f;
vertices[0].texture_position.v = 0.0f;
vertices[1].texture_position.u = 0.96875f;
vertices[1].texture_position.v = 0.0f;
vertices[2].texture_position.u = 0.0f;
vertices[2].texture_position.v = 1.0f;
vertices[3].texture_position.u = 0.96875f;
vertices[3].texture_position.v = 1.0f;
vertices[0].screen.xyw.x = 0.03f*(float)gr_screen.max_w;
vertices[0].screen.xyw.y = (float)gr_screen.max_h;
vertices[1].screen.xyw.x = (float)gr_screen.max_w;
vertices[1].screen.xyw.y = (float)gr_screen.max_h;
vertices[2].screen.xyw.x = 0.03f*(float)gr_screen.max_w;
vertices[2].screen.xyw.y = 0.0f;
vertices[3].screen.xyw.x = (float)gr_screen.max_w;
vertices[3].screen.xyw.y = 0.0f;
vertex_layout vert_def;
vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), offsetof(vertex, screen));
vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex), offsetof(vertex, texture_position));
opengl_render_primitives_immediate(PRIM_TYPE_TRISTRIP, &vert_def, 4, vertices, sizeof(vertex) * 4);
opengl_shader_set_passthrough(false, High_dynamic_range);
vertex distortion_verts[33];
for(int i = 0; i < 33; i++)
{
distortion_verts[i].r = (ubyte)Random::next(256);
distortion_verts[i].g = (ubyte)Random::next(256);
distortion_verts[i].b = 255;
distortion_verts[i].a = 255;
distortion_verts[i].screen.xyw.x = 1.f;
distortion_verts[i].screen.xyw.y = (float)gr_screen.max_h*0.03125f*i;
}
vert_def = vertex_layout();
vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), offsetof(vertex, screen));
vert_def.add_vertex_component(vertex_format_data::COLOR4, sizeof(vertex), offsetof(vertex, r));
opengl_render_primitives_immediate(PRIM_TYPE_POINTS, &vert_def, 33, distortion_verts, 33 * sizeof(vertex));
Distortion_switch = !Distortion_switch;
// reset state
GL_state.PopFramebufferState();
glViewport(0,0,gr_screen.max_w,gr_screen.max_h);
GL_state.DepthTest(depth);
GL_state.DepthMask(depth_mask);
GL_state.Blend(blend);
GL_state.CullFace(cull);
}
void opengl_render_primitives(primitive_type prim_type,
vertex_layout* layout,
int n_verts,
gr_buffer_handle buffer_handle,
size_t vert_offset,
size_t byte_offset)
{
GR_DEBUG_SCOPE("Render primitives");
Assertion(buffer_handle.isValid(),
"A valid buffer handle is required! Use the immediate buffer if data is not in GPU buffer yet.");
opengl_bind_vertex_layout(*layout, opengl_buffer_get_id(GL_ARRAY_BUFFER, buffer_handle), 0, byte_offset);
glDrawArrays(opengl_primitive_type(prim_type), (GLint)vert_offset, n_verts);
}
void opengl_render_primitives_immediate(primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
{
auto offset = gr_add_to_immediate_buffer(size, data);
opengl_render_primitives(prim_type, layout, n_verts, gr_immediate_buffer_handle, 0, offset);
}
void gr_opengl_render_primitives(material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int offset,
int n_verts,
gr_buffer_handle buffer_handle,
size_t buffer_offset)
{
GL_CHECK_FOR_ERRORS("start of gr_opengl_render_primitives()");
opengl_tnl_set_material(material_info, true);
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, offset, buffer_offset);
GL_CHECK_FOR_ERRORS("end of gr_opengl_render_primitives()");
}
void gr_opengl_render_primitives_particle(particle_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int offset,
int n_verts,
gr_buffer_handle buffer_handle)
{
GL_CHECK_FOR_ERRORS("start of gr_opengl_render_primitives_particle()");
opengl_tnl_set_material_particle(material_info);
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, offset, 0);
GL_CHECK_FOR_ERRORS("end of gr_opengl_render_primitives_particle()");
}
void gr_opengl_render_primitives_distortion(distortion_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int offset,
int n_verts,
gr_buffer_handle buffer_handle)
{
GL_CHECK_FOR_ERRORS("start of gr_opengl_render_primitives_distortion()");
opengl_tnl_set_material_distortion(material_info);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, offset, 0);
GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, buffers);
GL_CHECK_FOR_ERRORS("start of gr_opengl_render_primitives_distortion()");
}
void gr_opengl_render_movie(movie_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int n_verts,
gr_buffer_handle buffer,
size_t buffer_offset)
{
GR_DEBUG_SCOPE("Render movie frame");
gr_set_2d_matrix();
opengl_tnl_set_material_movie(material_info);
opengl_render_primitives(prim_type, layout, n_verts, buffer, 0, buffer_offset);
gr_end_2d_matrix();
}
void gr_opengl_render_nanovg(nanovg_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int offset,
int n_verts,
gr_buffer_handle buffer_handle)
{
GR_DEBUG_SCOPE("Render NanoVG primitives");
opengl_tnl_set_material_nanovg(material_info);
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, offset, 0);
}
void gr_opengl_render_primitives_batched(batched_bitmap_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int offset,
int n_verts,
gr_buffer_handle buffer_handle)
{
GR_DEBUG_SCOPE("Render batched primitives");
opengl_tnl_set_material_batched(material_info);
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, offset, 0);
}
void gr_opengl_render_rocket_primitives(interface_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int n_indices,
gr_buffer_handle vertex_buffer,
gr_buffer_handle index_buffer)
{
GR_DEBUG_SCOPE("Render rocket ui primitives");
gr_set_2d_matrix();
opengl_tnl_set_rocketui_material(material_info);
opengl_bind_vertex_layout(*layout,
opengl_buffer_get_id(GL_ARRAY_BUFFER, vertex_buffer),
opengl_buffer_get_id(GL_ELEMENT_ARRAY_BUFFER, index_buffer));
glDrawElements(opengl_primitive_type(prim_type), n_indices, GL_UNSIGNED_INT, nullptr);
gr_end_2d_matrix();
}
void opengl_draw_textured_quad(GLfloat x1,
GLfloat y1,
GLfloat u1,
GLfloat v1,
GLfloat x2,
GLfloat y2,
GLfloat u2,
GLfloat v2) {
GR_DEBUG_SCOPE("Draw textured quad");
GLfloat glVertices[4][4] = {
{ x1, y1, u1, v1 },
{ x1, y2, u1, v2 },
{ x2, y1, u2, v1 },
{ x2, y2, u2, v2 }
};
vertex_layout vert_def;
vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(GLfloat) * 4, 0);
vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(GLfloat) * 4, sizeof(GLfloat) * 2);
opengl_render_primitives_immediate(PRIM_TYPE_TRISTRIP, &vert_def, 4, glVertices, sizeof(glVertices));
}
void opengl_draw_full_screen_textured(GLfloat u1, GLfloat v1, GLfloat u2, GLfloat v2)
{
GR_DEBUG_SCOPE("Draw full screen triangle");
GLfloat glVertices[3][4] = {
{-1.f, -1.f, u1, v1},
{3.f, -1.f, u2 * 2.f, v1},
{-1.f, 3.f, u1, v2 * 2.f},
};
vertex_layout vert_def;
vert_def.add_vertex_component(vertex_format_data::POSITION2, sizeof(GLfloat) * 4, 0);
vert_def.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(GLfloat) * 4, sizeof(GLfloat) * 2);
opengl_render_primitives_immediate(PRIM_TYPE_TRIS, &vert_def, 3, glVertices, sizeof(glVertices));
}
void gr_opengl_render_decals(decal_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int num_elements,
const indexed_vertex_source& binding,
const gr_buffer_handle& instance_buffer,
int num_instances) {
opengl_tnl_set_material_decal(material_info);
opengl_bind_vertex_layout_multiple(*layout,
SCP_vector<GLuint> { opengl_buffer_get_id(GL_ARRAY_BUFFER, binding.Vbuffer_handle), opengl_buffer_get_id(GL_ARRAY_BUFFER, instance_buffer) },
opengl_buffer_get_id(GL_ELEMENT_ARRAY_BUFFER, binding.Ibuffer_handle));
glDrawElementsInstanced(opengl_primitive_type(prim_type), num_elements, GL_UNSIGNED_INT, nullptr, num_instances);
}
void gr_opengl_start_decal_pass() {
// For now we only render into the diffuse channel of the framebuffer
#ifndef USE_OPENGL_ES
GLenum buffers[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT4,
};
glDrawBuffers(3, buffers);
#else
GLenum buffers[] = {
GL_COLOR_ATTACHMENT0,
GL_NONE,
GL_COLOR_ATTACHMENT2,
GL_NONE,
GL_COLOR_ATTACHMENT4,
};
glDrawBuffers(5, buffers);
#endif
}
void gr_opengl_stop_decal_pass() {
GLenum buffers2[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4,
GL_COLOR_ATTACHMENT5,
};
glDrawBuffers(6, buffers2);
}
void gr_opengl_calculate_irrmap()
{
auto previous_target = gr_screen.rendering_to_texture;
int irr_shader = gr_opengl_maybe_create_shader(SDR_TYPE_IRRADIANCE_MAP_GEN, 0);
opengl_shader_set_current(irr_shader);
auto env_tex = bm_get_gr_info<tcache_slot_opengl>(ENVMAP);
glBindTexture(env_tex->texture_target, env_tex->texture_id);
GL_state.Texture.Enable(0, GL_TEXTURE_CUBE_MAP, env_tex->texture_id);
Current_shader->program->Uniforms.setTextureUniform("envmap", 0);
for (int i = 0; i < 6; i++) {
bm_set_render_target(gr_screen.irrmap_render_target, i);
gr_clear();
opengl_set_generic_uniform_data<graphics::generic_data::irrmap_data>(
[&](graphics::generic_data::irrmap_data* data) { data->face = i; });
opengl_draw_full_screen_textured(-1.0f, -1.0f, 1.0f, 1.0f);
}
bm_set_render_target(previous_target);
}