mirror of
https://github.com/DrBeef/Doom3Quest.git
synced 2024-12-01 08:21:39 +00:00
b2b8f43c9d
Builds, runs, no stereo or much else is working, menus work ok though
360 lines
9.3 KiB
C++
360 lines
9.3 KiB
C++
/*
|
|
Emile Belanger
|
|
GPL3
|
|
*/
|
|
#include "renderer/tr_local.h"
|
|
#include "renderer/VertexCache.h"
|
|
|
|
|
|
idCVar r_framebufferFilter( "r_framebufferFilter", "0", CVAR_RENDERER | CVAR_BOOL, "Image filter when using the framebuffer. 0 = Nearest, 1 = Linear" );
|
|
|
|
static GLuint m_framebuffer = -1;
|
|
static GLuint m_depthbuffer;
|
|
static GLuint m_stencilbuffer;
|
|
|
|
static int m_framebuffer_width, m_framebuffer_height;
|
|
static GLuint m_framebuffer_texture;
|
|
|
|
static GLuint m_positionLoc;
|
|
static GLuint m_texCoordLoc;
|
|
static GLuint m_samplerLoc;
|
|
|
|
static GLuint r_program;
|
|
|
|
static int fixNpot(int v)
|
|
{
|
|
int ret = 1;
|
|
while(ret < v)
|
|
ret <<= 1;
|
|
return ret;
|
|
}
|
|
|
|
#define ALOGE(...) __android_log_print( ANDROID_LOG_ERROR, "FRAMEBUFFER", __VA_ARGS__ )
|
|
|
|
static const char * GlErrorString( GLenum error )
|
|
{
|
|
switch ( error )
|
|
{
|
|
case GL_NO_ERROR: return "GL_NO_ERROR";
|
|
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
|
|
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
|
|
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
|
|
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
|
|
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
static void GLCheckErrors( int line )
|
|
{
|
|
for ( int i = 0; i < 10; i++ )
|
|
{
|
|
const GLenum error = glGetError();
|
|
if ( error == GL_NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
ALOGE( "GL error on line %d: %s", line, GlErrorString( error ) );
|
|
}
|
|
}
|
|
|
|
#define LOG common->Printf
|
|
int loadShader(int shaderType, const char * source)
|
|
{
|
|
int shader = qglCreateShader(shaderType);
|
|
|
|
if(shader != 0)
|
|
{
|
|
qglShaderSource(shader, 1, &source, NULL);
|
|
qglCompileShader(shader);
|
|
|
|
GLint length;
|
|
|
|
qglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
|
|
|
|
if(length)
|
|
{
|
|
char* buffer = new char [ length ];
|
|
qglGetShaderInfoLog(shader, length, NULL, buffer);
|
|
LOG("shader = %s\n", buffer);
|
|
delete [] buffer;
|
|
|
|
GLint success;
|
|
qglGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
|
|
if(success != GL_TRUE)
|
|
{
|
|
LOG("ERROR compiling shader\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG("FAILED to create shader");
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
int createProgram(const char * vertexSource, const char * fragmentSource)
|
|
{
|
|
int vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
|
|
int pixelShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
|
|
|
|
int program = glCreateProgram();
|
|
|
|
if(program != 0)
|
|
{
|
|
glAttachShader(program, vertexShader);
|
|
// checkGlError("glAttachShader");
|
|
glAttachShader(program, pixelShader);
|
|
// checkGlError("glAttachShader");
|
|
glLinkProgram(program);
|
|
#define GL_LINK_STATUS 0x8B82
|
|
int linkStatus[1];
|
|
glGetProgramiv(program, GL_LINK_STATUS, linkStatus);
|
|
|
|
if(linkStatus[0] != GL_TRUE)
|
|
{
|
|
LOG("Could not link program: ");
|
|
char log[256];
|
|
GLsizei size;
|
|
glGetProgramInfoLog(program, 256, &size, log);
|
|
LOG("Log: %s", log);
|
|
//glDeleteProgram(program);
|
|
program = 0;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
LOG("FAILED to create program");
|
|
}
|
|
|
|
LOG("Program linked OK %d", program);
|
|
return program;
|
|
}
|
|
|
|
static void createShaders (void)
|
|
{
|
|
const GLchar *vertSource = \
|
|
"attribute vec2 a_texCoord; \n \
|
|
attribute vec4 a_position; \n \
|
|
varying vec2 v_texCoord; \n \
|
|
void main() \n \
|
|
{ \n \
|
|
gl_Position = a_position; \n \
|
|
v_texCoord = a_texCoord; \n \
|
|
} \n \
|
|
";
|
|
|
|
const GLchar *fragSource = \
|
|
"precision mediump float; \n \
|
|
varying vec2 v_texCoord; \n \
|
|
uniform sampler2D s_texture; \n \
|
|
void main() \n \
|
|
{ \n \
|
|
gl_FragColor = texture2D( s_texture, v_texCoord ); \n \
|
|
//gl_FragColor = vec4( 0.8, 0.5, 0.9, 1.0 ); \n \
|
|
} \n \
|
|
";
|
|
|
|
|
|
r_program = createProgram(vertSource, fragSource);
|
|
|
|
glUseProgram(r_program);
|
|
|
|
// get attrib locations
|
|
m_positionLoc = glGetAttribLocation(r_program, "a_position");
|
|
m_texCoordLoc = glGetAttribLocation(r_program, "a_texCoord");
|
|
m_samplerLoc = glGetUniformLocation(r_program, "s_texture");
|
|
|
|
if(m_positionLoc == -1)
|
|
LOG("Failed to get m_positionLoc");
|
|
|
|
if(m_texCoordLoc == -1)
|
|
LOG("Failed to get m_texCoordLoc");
|
|
|
|
if(m_samplerLoc == -1)
|
|
LOG("Failed to get m_samplerLoc");
|
|
|
|
glUniform1i(m_samplerLoc, 0);
|
|
}
|
|
|
|
|
|
void R_InitFrameBuffer()
|
|
{
|
|
//LOG("R_InitFrameBuffer Real[%d, %d] -> Framebuffer[%d,%d]", glConfig.vidWidthReal, glConfig.vidHeightReal, glConfig.vidWidth, glConfig.vidHeight);
|
|
|
|
/* if(glConfig.vidWidthReal == glConfig.vidWidth && glConfig.vidHeightReal == glConfig.vidHeight)
|
|
{
|
|
LOGI("Not using framebuffer");
|
|
return;
|
|
}*/
|
|
|
|
//glConfig.npotAvailable = false;
|
|
|
|
m_framebuffer_width = glConfig.vidWidth;
|
|
m_framebuffer_height = glConfig.vidHeight;
|
|
|
|
if (!glConfig.npotAvailable)
|
|
{
|
|
m_framebuffer_width = fixNpot(m_framebuffer_width);
|
|
m_framebuffer_height = fixNpot(m_framebuffer_height);
|
|
}
|
|
|
|
LOGI("Framebuffer buffer size = [%d, %d]", m_framebuffer_width, m_framebuffer_height);
|
|
|
|
// Create texture
|
|
glGenTextures(1, &m_framebuffer_texture);
|
|
glBindTexture(GL_TEXTURE_2D, m_framebuffer_texture);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_framebuffer_width, m_framebuffer_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
if(r_framebufferFilter.GetInteger() == 0)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
}
|
|
|
|
// Create framebuffer
|
|
glGenFramebuffers(1, &m_framebuffer);
|
|
|
|
// Create renderbuffer
|
|
glGenRenderbuffers(1, &m_depthbuffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, m_depthbuffer);
|
|
|
|
if(glConfig.depthStencilAvailable)
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, m_framebuffer_width, m_framebuffer_height);
|
|
else
|
|
{
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, m_framebuffer_width, m_framebuffer_height);
|
|
|
|
// Need separate Stencil buffer
|
|
glGenRenderbuffers(1, &m_stencilbuffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, m_stencilbuffer);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, m_framebuffer_width, m_framebuffer_height);
|
|
}
|
|
|
|
createShaders();
|
|
}
|
|
|
|
void R_FrameBufferStart()
|
|
{
|
|
if(m_framebuffer == -1)
|
|
return;
|
|
|
|
// Render to framebuffer
|
|
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
|
GLCheckErrors(__LINE__);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_framebuffer_texture, 0);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
// Attach combined depth+stencil
|
|
if(glConfig.depthStencilAvailable)
|
|
{
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
|
|
}
|
|
else
|
|
{
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilbuffer);
|
|
}
|
|
|
|
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
if(result != GL_FRAMEBUFFER_COMPLETE)
|
|
{
|
|
common->Error( "Error binding Framebuffer: %d\n", result );
|
|
}
|
|
}
|
|
|
|
|
|
void R_FrameBufferEnd()
|
|
{
|
|
if(m_framebuffer == -1)
|
|
return;
|
|
|
|
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
//glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
|
// Bind the texture
|
|
glBindTexture(GL_TEXTURE_2D, m_framebuffer_texture);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
// Unbind any VBOs
|
|
vertexCache.UnbindIndex();
|
|
vertexCache.UnbindVertex();
|
|
|
|
glUseProgram(r_program);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
GLfloat vert[] =
|
|
{
|
|
-1.f, -1.f, 0.0f, // 0. left-bottom
|
|
-1.f, 1.f, 0.0f, // 1. left-top
|
|
1.f, 1.f, 0.0f, // 2. right-top
|
|
1.f, -1.f, 0.0f, // 3. right-bottom
|
|
};
|
|
|
|
GLfloat smax = 1;
|
|
GLfloat tmax = 1;
|
|
|
|
if (!glConfig.npotAvailable)
|
|
{
|
|
smax = (float)glConfig.vidWidth / (float)m_framebuffer_width;
|
|
tmax = (float)glConfig.vidHeight / (float)m_framebuffer_height;
|
|
}
|
|
|
|
GLfloat texVert[] =
|
|
{
|
|
0.0f, 0.0f, // TexCoord 0
|
|
0.0f, tmax, // TexCoord 1
|
|
smax, tmax, // TexCoord 2
|
|
smax, 0.0f // TexCoord 3
|
|
};
|
|
|
|
GLCheckErrors(__LINE__);
|
|
glVertexAttribPointer(m_positionLoc, 3, GL_FLOAT,
|
|
false,
|
|
3 * 4,
|
|
vert);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
glVertexAttribPointer(m_texCoordLoc, 2, GL_FLOAT,
|
|
false,
|
|
2 * 4,
|
|
texVert);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
glEnableVertexAttribArray(m_positionLoc);
|
|
GLCheckErrors(__LINE__);
|
|
glEnableVertexAttribArray(m_texCoordLoc);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
|
|
// Set the sampler texture unit to 0
|
|
glUniform1i(m_samplerLoc, 0);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
glViewport (0, 0, glConfig.vidWidth, glConfig.vidHeight );
|
|
//glViewport (0, 0, glConfig.vidWidthReal, glConfig.vidHeightReal );
|
|
GLCheckErrors(__LINE__);
|
|
|
|
glDisable(GL_BLEND);
|
|
GLCheckErrors(__LINE__);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
GLCheckErrors(__LINE__);
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
GLCheckErrors(__LINE__);
|
|
}
|
|
|
|
|