mirror of
https://github.com/blawar/GLideN64.git
synced 2024-07-07 03:13:49 +00:00
781 lines
24 KiB
C++
781 lines
24 KiB
C++
#ifndef __LINUX__
|
|
# include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#else
|
|
# include "winlnxdefs.h"
|
|
# include <stdlib.h> // malloc()
|
|
#endif
|
|
#include <assert.h>
|
|
#include "N64.h"
|
|
#include "OpenGL.h"
|
|
#include "Combiner.h"
|
|
#include "GLSLCombiner.h"
|
|
#include "Shaders.h"
|
|
#include "Noise_shader.h"
|
|
#include "FrameBuffer.h"
|
|
#include "DepthBuffer.h"
|
|
|
|
static GLuint g_vertex_shader_object;
|
|
static GLuint g_calc_light_shader_object;
|
|
static GLuint g_calc_lod_shader_object;
|
|
static GLuint g_calc_noise_shader_object;
|
|
static GLuint g_calc_depth_shader_object;
|
|
static GLuint g_test_alpha_shader_object;
|
|
static GLuint g_zlut_tex = 0;
|
|
|
|
static GLuint g_shadow_map_vertex_shader_object;
|
|
static GLuint g_shadow_map_fragment_shader_object;
|
|
static GLuint g_draw_shadow_map_program;
|
|
GLuint g_tlut_tex = 0;
|
|
static u32 g_paletteCRC256 = 0;
|
|
|
|
static const GLuint ZlutImageUnit = 0;
|
|
static const GLuint TlutImageUnit = 1;
|
|
static const GLuint depthImageUnit = 2;
|
|
|
|
static
|
|
void display_warning(const char *text, ...)
|
|
{
|
|
static int first_message = 100;
|
|
if (first_message)
|
|
{
|
|
char buf[1000];
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, text);
|
|
vsprintf(buf, text, ap);
|
|
va_end(ap);
|
|
first_message--;
|
|
}
|
|
}
|
|
|
|
static const GLsizei nShaderLogSize = 1024;
|
|
static
|
|
bool check_shader_compile_status(GLuint obj)
|
|
{
|
|
GLint status;
|
|
glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
|
|
if(status == GL_FALSE)
|
|
{
|
|
GLchar shader_log[nShaderLogSize];
|
|
GLsizei nLogSize = nShaderLogSize;
|
|
glGetShaderInfoLog(obj, nShaderLogSize, &nLogSize, shader_log);
|
|
display_warning(shader_log);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool check_program_link_status(GLuint obj)
|
|
{
|
|
GLint status;
|
|
glGetProgramiv(obj, GL_LINK_STATUS, &status);
|
|
if(status == GL_FALSE)
|
|
{
|
|
GLsizei nLogSize = nShaderLogSize;
|
|
GLchar shader_log[nShaderLogSize];
|
|
glGetProgramInfoLog(obj, nShaderLogSize, &nLogSize, shader_log);
|
|
display_warning(shader_log);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static
|
|
void InitZlutTexture()
|
|
{
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
|
|
u16 * zLUT = new u16[0x40000];
|
|
for(int i=0; i<0x40000; i++) {
|
|
u32 exponent = 0;
|
|
u32 testbit = 1 << 17;
|
|
while((i & testbit) && (exponent < 7)) {
|
|
exponent++;
|
|
testbit = 1 << (17 - exponent);
|
|
}
|
|
|
|
u32 mantissa = (i >> (6 - (6 < exponent ? 6 : exponent))) & 0x7ff;
|
|
zLUT[i] = (u16)(((exponent << 11) | mantissa) << 2);
|
|
}
|
|
glGenTextures(1, &g_zlut_tex);
|
|
glBindTexture(GL_TEXTURE_2D, g_zlut_tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16,
|
|
512, 512, 0, GL_RED, GL_UNSIGNED_SHORT,
|
|
zLUT);
|
|
delete[] zLUT;
|
|
}
|
|
|
|
static
|
|
void DestroyZlutTexture()
|
|
{
|
|
if (g_zlut_tex > 0)
|
|
glDeleteTextures(1, &g_zlut_tex);
|
|
}
|
|
|
|
static
|
|
void InitShadowMapShader()
|
|
{
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
|
|
g_paletteCRC256 = 0;
|
|
glGenTextures(1, &g_tlut_tex);
|
|
glBindTexture(GL_TEXTURE_1D, g_tlut_tex);
|
|
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexImage1D(GL_TEXTURE_1D, 0, GL_R16, 256, 0, GL_RED, GL_UNSIGNED_SHORT, NULL);
|
|
|
|
g_shadow_map_vertex_shader_object = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(g_shadow_map_vertex_shader_object, 1, &shadow_map_vertex_shader, NULL);
|
|
glCompileShader(g_shadow_map_vertex_shader_object);
|
|
assert(check_shader_compile_status(g_shadow_map_vertex_shader_object));
|
|
|
|
g_shadow_map_fragment_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
|
if (g_bUseFloatDepthTexture)
|
|
glShaderSource(g_shadow_map_fragment_shader_object, 1, &shadow_map_fragment_shader_float, NULL);
|
|
else
|
|
glShaderSource(g_shadow_map_fragment_shader_object, 1, &shadow_map_fragment_shader_int, NULL);
|
|
glCompileShader(g_shadow_map_fragment_shader_object);
|
|
assert(check_shader_compile_status(g_shadow_map_fragment_shader_object));
|
|
|
|
g_draw_shadow_map_program = glCreateProgram();
|
|
glAttachShader(g_draw_shadow_map_program, g_shadow_map_vertex_shader_object);
|
|
glAttachShader(g_draw_shadow_map_program, g_shadow_map_fragment_shader_object);
|
|
glLinkProgram(g_draw_shadow_map_program);
|
|
assert(check_program_link_status(g_draw_shadow_map_program));
|
|
}
|
|
|
|
static
|
|
void DestroyShadowMapShader()
|
|
{
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
|
|
if (g_tlut_tex > 0)
|
|
glDeleteTextures(1, &g_tlut_tex);
|
|
glDetachShader(g_draw_shadow_map_program, g_shadow_map_vertex_shader_object);
|
|
glDetachShader(g_draw_shadow_map_program, g_shadow_map_fragment_shader_object);
|
|
glDeleteShader(g_shadow_map_vertex_shader_object);
|
|
glDeleteShader(g_shadow_map_fragment_shader_object);
|
|
glDeleteProgram(g_draw_shadow_map_program);
|
|
}
|
|
|
|
void InitGLSLCombiner()
|
|
{
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
g_vertex_shader_object = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(g_vertex_shader_object, 1, &vertex_shader, NULL);
|
|
glCompileShader(g_vertex_shader_object);
|
|
assert(check_shader_compile_status(g_vertex_shader_object));
|
|
|
|
g_calc_light_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(g_calc_light_shader_object, 1, &fragment_shader_calc_light, NULL);
|
|
glCompileShader(g_calc_light_shader_object);
|
|
assert(check_shader_compile_status(g_calc_light_shader_object));
|
|
|
|
g_calc_lod_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(g_calc_lod_shader_object, 1, &fragment_shader_calc_lod, NULL);
|
|
glCompileShader(g_calc_lod_shader_object);
|
|
assert(check_shader_compile_status(g_calc_lod_shader_object));
|
|
|
|
g_calc_noise_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(g_calc_noise_shader_object, 1, &noise_fragment_shader, NULL);
|
|
glCompileShader(g_calc_noise_shader_object);
|
|
assert(check_shader_compile_status(g_calc_noise_shader_object));
|
|
|
|
g_test_alpha_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(g_test_alpha_shader_object, 1, &alpha_test_fragment_shader, NULL);
|
|
glCompileShader(g_test_alpha_shader_object);
|
|
assert(check_shader_compile_status(g_test_alpha_shader_object));
|
|
|
|
if (OGL.bImageTexture) {
|
|
g_calc_depth_shader_object = glCreateShader(GL_FRAGMENT_SHADER);
|
|
if (g_bUseFloatDepthTexture)
|
|
glShaderSource(g_calc_depth_shader_object, 1, &depth_compare_shader_float, NULL);
|
|
else
|
|
glShaderSource(g_calc_depth_shader_object, 1, &depth_compare_shader_int, NULL);
|
|
glCompileShader(g_calc_depth_shader_object);
|
|
assert(check_shader_compile_status(g_calc_depth_shader_object));
|
|
}
|
|
|
|
InitZlutTexture();
|
|
InitShadowMapShader();
|
|
}
|
|
|
|
void DestroyGLSLCombiner() {
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
DestroyZlutTexture();
|
|
DestroyShadowMapShader();
|
|
}
|
|
|
|
const char *ColorInput_1cycle[] = {
|
|
"combined_color.rgb",
|
|
"readtex0.rgb",
|
|
"readtex1.rgb",
|
|
"prim_color.rgb",
|
|
"vec_color.rgb",
|
|
"env_color.rgb",
|
|
"center_color.rgb",
|
|
"scale_color.rgb",
|
|
"combined_color.a",
|
|
"readtex0.a",
|
|
"readtex1.a",
|
|
"prim_color.a",
|
|
"vec_color.a",
|
|
"env_color.a",
|
|
"lod_frac", // TODO: emulate lod_fraction
|
|
"vec3(prim_lod)",
|
|
"vec3(0.5 + 0.5*snoise(noiseCoord2D))",
|
|
"vec3(k4)",
|
|
"vec3(k5)",
|
|
"vec3(1.0)",
|
|
"vec3(0.0)"
|
|
};
|
|
|
|
const char *ColorInput_2cycle[] = {
|
|
"combined_color.rgb",
|
|
"readtex1.rgb",
|
|
"readtex0.rgb",
|
|
"prim_color.rgb",
|
|
"vec_color.rgb",
|
|
"env_color.rgb",
|
|
"center_color.rgb",
|
|
"scale_color.rgb",
|
|
"combined_color.a",
|
|
"readtex1.a",
|
|
"readtex0.a",
|
|
"prim_color.a",
|
|
"vec_color.a",
|
|
"env_color.a",
|
|
"lod_frac", // TODO: emulate lod_fraction
|
|
"vec3(prim_lod)",
|
|
"vec3(0.5 + 0.5*snoise(noiseCoord2D))",
|
|
"vec3(k4)",
|
|
"vec3(k5)",
|
|
"vec3(1.0)",
|
|
"vec3(0.0)"
|
|
};
|
|
|
|
const char *AlphaInput_1cycle[] = {
|
|
"combined_color.a",
|
|
"readtex0.a",
|
|
"readtex1.a",
|
|
"prim_color.a",
|
|
"vec_color.a",
|
|
"env_color.a",
|
|
"center_color.a",
|
|
"scale_color.a",
|
|
"combined_color.a",
|
|
"readtex0.a",
|
|
"readtex1.a",
|
|
"prim_color.a",
|
|
"vec_color.a",
|
|
"env_color.a",
|
|
"lod_frac", // TODO: emulate lod_fraction
|
|
"prim_lod",
|
|
"1.0",
|
|
"k4",
|
|
"k5",
|
|
"1.0",
|
|
"0.0"
|
|
};
|
|
|
|
const char *AlphaInput_2cycle[] = {
|
|
"combined_color.a",
|
|
"readtex1.a",
|
|
"readtex0.a",
|
|
"prim_color.a",
|
|
"vec_color.a",
|
|
"env_color.a",
|
|
"center_color.a",
|
|
"scale_color.a",
|
|
"combined_color.a",
|
|
"readtex1.a",
|
|
"readtex0.a",
|
|
"prim_color.a",
|
|
"vec_color.a",
|
|
"env_color.a",
|
|
"lod_frac", // TODO: emulate lod_fraction
|
|
"prim_lod",
|
|
"1.0",
|
|
"k4",
|
|
"k5",
|
|
"1.0",
|
|
"0.0"
|
|
};
|
|
|
|
|
|
static
|
|
int CompileCombiner(const CombinerStage & _stage, const char** _Input, char * _fragment_shader) {
|
|
char buf[128];
|
|
bool bBracketOpen = false;
|
|
int nRes = 0;
|
|
for (int i = 0; i < _stage.numOps; ++i) {
|
|
switch(_stage.op[i].op) {
|
|
case LOAD:
|
|
sprintf(buf, "(%s ", _Input[_stage.op[i].param1]);
|
|
strcat(_fragment_shader, buf);
|
|
bBracketOpen = true;
|
|
nRes |= 1 << _stage.op[i].param1;
|
|
break;
|
|
case SUB:
|
|
if (bBracketOpen) {
|
|
sprintf(buf, "- %s)", _Input[_stage.op[i].param1]);
|
|
bBracketOpen = false;
|
|
} else
|
|
sprintf(buf, "- %s", _Input[_stage.op[i].param1]);
|
|
strcat(_fragment_shader, buf);
|
|
nRes |= 1 << _stage.op[i].param1;
|
|
break;
|
|
case ADD:
|
|
if (bBracketOpen) {
|
|
sprintf(buf, "+ %s)", _Input[_stage.op[i].param1]);
|
|
bBracketOpen = false;
|
|
} else
|
|
sprintf(buf, "+ %s", _Input[_stage.op[i].param1]);
|
|
strcat(_fragment_shader, buf);
|
|
nRes |= 1 << _stage.op[i].param1;
|
|
break;
|
|
case MUL:
|
|
if (bBracketOpen) {
|
|
sprintf(buf, ")*%s", _Input[_stage.op[i].param1]);
|
|
bBracketOpen = false;
|
|
} else
|
|
sprintf(buf, "*%s", _Input[_stage.op[i].param1]);
|
|
strcat(_fragment_shader, buf);
|
|
nRes |= 1 << _stage.op[i].param1;
|
|
break;
|
|
case INTER:
|
|
sprintf(buf, "mix(%s, %s, %s)", _Input[_stage.op[0].param2], _Input[_stage.op[0].param1], _Input[_stage.op[0].param3]);
|
|
strcat(_fragment_shader, buf);
|
|
nRes |= 1 << _stage.op[i].param1;
|
|
nRes |= 1 << _stage.op[i].param2;
|
|
nRes |= 1 << _stage.op[i].param3;
|
|
break;
|
|
|
|
// default:
|
|
// assert(false);
|
|
}
|
|
}
|
|
if (bBracketOpen)
|
|
strcat(_fragment_shader, ")");
|
|
strcat(_fragment_shader, "; \n");
|
|
return nRes;
|
|
}
|
|
|
|
GLSLCombiner::GLSLCombiner(Combiner *_color, Combiner *_alpha) {
|
|
char *fragment_shader = (char*)malloc(4096);
|
|
strcpy(fragment_shader, fragment_shader_header_common_variables);
|
|
|
|
char strCombiner[512];
|
|
strcpy(strCombiner, " alpha1 = ");
|
|
m_nInputs = CompileCombiner(_alpha->stage[0], AlphaInput_1cycle, strCombiner);
|
|
strcat(strCombiner, " color1 = ");
|
|
m_nInputs |= CompileCombiner(_color->stage[0], ColorInput_1cycle, strCombiner);
|
|
strcat(strCombiner, " combined_color = vec4(color1, alpha1); \n");
|
|
if (_alpha->numStages == 2) {
|
|
strcat(strCombiner, " alpha2 = ");
|
|
m_nInputs |= CompileCombiner(_alpha->stage[1], AlphaInput_2cycle, strCombiner);
|
|
} else
|
|
strcat(strCombiner, " alpha2 = alpha1; \n");
|
|
if (_color->numStages == 2) {
|
|
strcat(strCombiner, " color2 = ");
|
|
m_nInputs |= CompileCombiner(_color->stage[1], ColorInput_2cycle, strCombiner);
|
|
} else
|
|
strcat(strCombiner, " color2 = color1; \n");
|
|
|
|
strcat(fragment_shader, fragment_shader_header_common_functions);
|
|
strcat(fragment_shader, fragment_shader_header_main);
|
|
const bool bUseLod = (m_nInputs & (1<<LOD_FRACTION)) > 0;
|
|
if (bUseLod)
|
|
strcat(fragment_shader, " float lod_frac = calc_lod(prim_lod, 255.0*vec2(secondary_color.g, secondary_color.b)); \n");
|
|
if ((m_nInputs & ((1<<TEXEL0)|(1<<TEXEL1)|(1<<TEXEL0_ALPHA)|(1<<TEXEL1_ALPHA))) > 0) {
|
|
strcat(fragment_shader, fragment_shader_readtex0color);
|
|
strcat(fragment_shader, fragment_shader_readtex1color);
|
|
} else {
|
|
assert(strstr(strCombiner, "readtex") == 0);
|
|
}
|
|
if (OGL.bHWLighting)
|
|
strcat(fragment_shader, " float intensity = calc_light(int(secondary_color.r), input_color); \n");
|
|
else
|
|
strcat(fragment_shader, " input_color = gl_Color.rgb;\n");
|
|
strcat(fragment_shader, " vec_color = vec4(input_color, gl_Color.a); \n");
|
|
strcat(fragment_shader, strCombiner);
|
|
strcat(fragment_shader, " gl_FragColor = vec4(color2, alpha2); \n");
|
|
|
|
strcat(fragment_shader, " if (!alpha_test(gl_FragColor.a)) discard; \n");
|
|
if (OGL.bImageTexture)
|
|
strcat(fragment_shader, " bool bDC = depth_compare(); \n");
|
|
// strcat(fragment_shader, " if (!depth_compare()) discard; \n");
|
|
|
|
#ifdef USE_TOONIFY
|
|
strcat(fragment_shader, " toonify(intensity); \n");
|
|
#endif
|
|
strcat(fragment_shader, " if (fog_enabled > 0) \n");
|
|
strcat(fragment_shader, " gl_FragColor = vec4(mix(gl_Fog.color.rgb, gl_FragColor.rgb, gl_FogFragCoord), gl_FragColor.a); \n");
|
|
|
|
strcat(fragment_shader, fragment_shader_end);
|
|
|
|
#ifdef USE_TOONIFY
|
|
strcat(fragment_shader, fragment_shader_toonify);
|
|
#endif
|
|
|
|
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(fragmentShader, 1, (const GLchar**)&fragment_shader, NULL);
|
|
free(fragment_shader);
|
|
glCompileShader(fragmentShader);
|
|
assert(check_shader_compile_status(fragmentShader));
|
|
|
|
memset(m_aShaders, 0, sizeof(m_aShaders));
|
|
u32 uShaderIdx = 0;
|
|
|
|
m_program = glCreateProgram();
|
|
glAttachShader(m_program, g_vertex_shader_object);
|
|
m_aShaders[uShaderIdx++] = g_vertex_shader_object;
|
|
glAttachShader(m_program, fragmentShader);
|
|
m_aShaders[uShaderIdx++] = fragmentShader;
|
|
glAttachShader(m_program, g_calc_depth_shader_object);
|
|
m_aShaders[uShaderIdx++] = g_calc_depth_shader_object;
|
|
if (OGL.bHWLighting) {
|
|
glAttachShader(m_program, g_calc_light_shader_object);
|
|
m_aShaders[uShaderIdx++] = g_calc_light_shader_object;
|
|
}
|
|
if (bUseLod) {
|
|
glAttachShader(m_program, g_calc_lod_shader_object);
|
|
m_aShaders[uShaderIdx++] = g_calc_lod_shader_object;
|
|
}
|
|
glAttachShader(m_program, g_test_alpha_shader_object);
|
|
m_aShaders[uShaderIdx++] = g_test_alpha_shader_object;
|
|
if (OGL.bImageTexture) {
|
|
glAttachShader(m_program, g_calc_depth_shader_object);
|
|
m_aShaders[uShaderIdx++] = g_calc_depth_shader_object;
|
|
}
|
|
glAttachShader(m_program, g_calc_noise_shader_object);
|
|
m_aShaders[uShaderIdx] = g_calc_noise_shader_object;
|
|
assert(uShaderIdx <= sizeof(m_aShaders)/sizeof(m_aShaders[0]));
|
|
glLinkProgram(m_program);
|
|
assert(check_program_link_status(m_program));
|
|
}
|
|
|
|
GLSLCombiner::~GLSLCombiner() {
|
|
u32 shaderIndex = 0;
|
|
const u32 arraySize = sizeof(m_aShaders)/sizeof(m_aShaders[0]);
|
|
while (shaderIndex < arraySize && m_aShaders[shaderIndex] > 0) {
|
|
glDetachShader(m_program, m_aShaders[shaderIndex]);
|
|
glDeleteShader(m_aShaders[shaderIndex++]);
|
|
}
|
|
glDeleteProgram(m_program);
|
|
}
|
|
|
|
void GLSLCombiner::Set() {
|
|
combiner.usesT0 = FALSE;
|
|
combiner.usesT1 = FALSE;
|
|
combiner.usesLOD = (m_nInputs & (1<<LOD_FRACTION)) > 0 ? TRUE : FALSE;
|
|
|
|
combiner.vertex.color = COMBINED;
|
|
combiner.vertex.alpha = COMBINED;
|
|
combiner.vertex.secondaryColor = LIGHT;
|
|
|
|
glUseProgram(m_program);
|
|
|
|
int texture0_location = glGetUniformLocation(m_program, "texture0");
|
|
if (texture0_location != -1) {
|
|
glUniform1i(texture0_location, 0);
|
|
combiner.usesT0 = TRUE;
|
|
}
|
|
|
|
int texture1_location = glGetUniformLocation(m_program, "texture1");
|
|
if (texture1_location != -1) {
|
|
glUniform1i(texture1_location, 1);
|
|
combiner.usesT1 = TRUE;
|
|
}
|
|
|
|
UpdateColors();
|
|
UpdateAlphaTestInfo();
|
|
}
|
|
|
|
void GLSLCombiner::UpdateColors() {
|
|
int prim_color_location = glGetUniformLocation(m_program, "prim_color");
|
|
glUniform4f(prim_color_location, gDP.primColor.r, gDP.primColor.g, gDP.primColor.b, gDP.primColor.a);
|
|
|
|
int env_color_location = glGetUniformLocation(m_program, "env_color");
|
|
glUniform4f(env_color_location, gDP.envColor.r, gDP.envColor.g, gDP.envColor.b, gDP.envColor.a);
|
|
|
|
int prim_lod_location = glGetUniformLocation(m_program, "prim_lod");
|
|
glUniform1f(prim_lod_location, gDP.primColor.l);
|
|
|
|
if (combiner.usesLOD) {
|
|
BOOL bCalcLOD = gDP.otherMode.textureLOD == G_TL_LOD;
|
|
int lod_en_location = glGetUniformLocation(m_program, "lod_enabled");
|
|
glUniform1i(lod_en_location, bCalcLOD);
|
|
if (bCalcLOD) {
|
|
int scale_x_location = glGetUniformLocation(m_program, "lod_x_scale");
|
|
glUniform1f(scale_x_location, OGL.scaleX);
|
|
int scale_y_location = glGetUniformLocation(m_program, "lod_y_scale");
|
|
glUniform1f(scale_y_location, OGL.scaleY);
|
|
int min_lod_location = glGetUniformLocation(m_program, "min_lod");
|
|
glUniform1f(min_lod_location, gDP.primColor.m);
|
|
int max_tile_location = glGetUniformLocation(m_program, "max_tile");
|
|
glUniform1i(max_tile_location, gSP.texture.level);
|
|
int texture_detail_location = glGetUniformLocation(m_program, "texture_detail");
|
|
glUniform1i(texture_detail_location, gDP.otherMode.textureDetail);
|
|
}
|
|
}
|
|
|
|
int nDither = (gDP.otherMode.alphaCompare == 3 && (gDP.otherMode.colorDither == 2 || gDP.otherMode.alphaDither == 2)) ? 1 : 0;
|
|
int dither_location = glGetUniformLocation(m_program, "dither_enabled");
|
|
glUniform1i(dither_location, nDither);
|
|
|
|
if ((m_nInputs & (1<<NOISE)) + nDither > 0) {
|
|
int time_location = glGetUniformLocation(m_program, "time");
|
|
glUniform1f(time_location, (float)(rand()&255));
|
|
}
|
|
|
|
int fog_location = glGetUniformLocation(m_program, "fog_enabled");
|
|
glUniform1i(fog_location, (gSP.geometryMode & G_FOG) > 0 ? 1 : 0);
|
|
|
|
int fb8bit_location = glGetUniformLocation(m_program, "fb_8bit_mode");
|
|
glUniform1i(fb8bit_location, 0);
|
|
|
|
}
|
|
|
|
void GLSLCombiner::UpdateFBInfo() {
|
|
int nFb8bitMode = 0, nFbFixedAlpha = 0;
|
|
if (cache.current[0] != NULL && cache.current[0]->frameBufferTexture == TRUE) {
|
|
if (cache.current[0]->size == G_IM_SIZ_8b) {
|
|
nFb8bitMode |= 1;
|
|
if (gDP.otherMode.imageRead == 0)
|
|
nFbFixedAlpha |= 1;
|
|
}
|
|
}
|
|
if (cache.current[1] != NULL && cache.current[1]->frameBufferTexture == TRUE) {
|
|
if (cache.current[1]->size == G_IM_SIZ_8b) {
|
|
nFb8bitMode |= 2;
|
|
if (gDP.otherMode.imageRead == 0)
|
|
nFbFixedAlpha |= 2;
|
|
}
|
|
}
|
|
int fb8bit_location = glGetUniformLocation(m_program, "fb_8bit_mode");
|
|
glUniform1i(fb8bit_location, nFb8bitMode);
|
|
int fbFixedAlpha_location = glGetUniformLocation(m_program, "fb_fixed_alpha");
|
|
glUniform1i(fbFixedAlpha_location, nFbFixedAlpha);
|
|
}
|
|
|
|
static
|
|
void _unbindImageTextures() {
|
|
glBindImageTexture(TlutImageUnit, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16UI);
|
|
glBindImageTexture(ZlutImageUnit, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16UI);
|
|
const GLenum depthTexFormat = g_bUseFloatDepthTexture ? GL_R32F : GL_R16UI;
|
|
glBindImageTexture(depthImageUnit, 0, 0, GL_FALSE, 0, GL_READ_WRITE, depthTexFormat);
|
|
}
|
|
|
|
void GLSLCombiner::UpdateDepthInfo() {
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
|
|
_unbindImageTextures();
|
|
|
|
if (frameBuffer.top == NULL || frameBuffer.top->pDepthBuffer == NULL)
|
|
return;
|
|
|
|
int nDepthEnabled = (gSP.geometryMode & G_ZBUFFER) > 0 ? 1 : 0;
|
|
int depth_enabled_location = glGetUniformLocation(m_program, "depthEnabled");
|
|
glUniform1i(depth_enabled_location, nDepthEnabled);
|
|
if (nDepthEnabled == 0)
|
|
return;
|
|
|
|
const int depth_compare_location = glGetUniformLocation(m_program, "depthCompareEnabled");
|
|
glUniform1i(depth_compare_location, gDP.otherMode.depthCompare);
|
|
const int depth_update_location = glGetUniformLocation(m_program, "depthUpdateEnabled");
|
|
glUniform1i(depth_update_location, gDP.otherMode.depthUpdate);
|
|
const int depth_polygon_offset = glGetUniformLocation(m_program, "depthPolygonOffset");
|
|
if (g_bUseFloatDepthTexture) {
|
|
float fPlygonOffset = gDP.otherMode.depthMode == ZMODE_DEC ? 0.005f : 0.0f;
|
|
glUniform1f(depth_polygon_offset, fPlygonOffset);
|
|
} else {
|
|
int iPlygonOffset = gDP.otherMode.depthMode == ZMODE_DEC ? 5 : 0;
|
|
glUniform1i(depth_polygon_offset, iPlygonOffset);
|
|
}
|
|
const int depth_scale_location = glGetUniformLocation(m_program, "depthScale");
|
|
glUniform1f(depth_scale_location, gSP.viewport.vscale[2]*32768);
|
|
const int depth_trans_location = glGetUniformLocation(m_program, "depthTrans");
|
|
glUniform1f(depth_trans_location, gSP.viewport.vtrans[2]*32768);
|
|
|
|
GLuint texture = frameBuffer.top->pDepthBuffer->depth_texture->glName;
|
|
glBindImageTexture(ZlutImageUnit, g_zlut_tex, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16UI);
|
|
GLenum depthTexFormat = g_bUseFloatDepthTexture ? GL_R32F : GL_R16UI;
|
|
glBindImageTexture(depthImageUnit, texture, 0, GL_FALSE, 0, GL_READ_WRITE, depthTexFormat);
|
|
}
|
|
|
|
void GLSL_ClearDepthBuffer() {
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
|
|
if (frameBuffer.top == NULL || frameBuffer.top->pDepthBuffer == NULL)
|
|
return;
|
|
|
|
CachedTexture * pDepthTexture = frameBuffer.top->pDepthBuffer->depth_texture;
|
|
const u32 numTexels = pDepthTexture->width*pDepthTexture->height;
|
|
|
|
GLenum type = GL_UNSIGNED_SHORT;
|
|
int dataSize = g_bUseFloatDepthTexture ? sizeof(float) : sizeof(unsigned short);
|
|
char * pData = (char*)malloc(numTexels * dataSize);;
|
|
|
|
if (g_bUseFloatDepthTexture) {
|
|
type = GL_FLOAT;
|
|
f32 * pDepth = (f32*)pData;
|
|
for (int i = 0; i < numTexels; i++)
|
|
pDepth[i] = 1.0f;
|
|
} else {
|
|
u16 * pDepth = (u16*)pData;
|
|
for (int i = 0; i < numTexels; i++)
|
|
pDepth[i] = 0xfffc;
|
|
}
|
|
glBindTexture(GL_TEXTURE_2D, pDepthTexture->glName);
|
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
|
pDepthTexture->width, pDepthTexture->height,
|
|
GL_RED, type, pData);
|
|
free(pData);
|
|
|
|
gSP.changed |= CHANGED_TEXTURE;
|
|
gDP.changed |= CHANGED_COMBINE;
|
|
}
|
|
|
|
void GLSLCombiner::UpdateAlphaTestInfo() {
|
|
int at_enabled_location = glGetUniformLocation(m_program, "alphaTestEnabled");
|
|
int at_value_location = glGetUniformLocation(m_program, "alphaTestValue");
|
|
if ((gDP.otherMode.alphaCompare == G_AC_THRESHOLD) && !(gDP.otherMode.alphaCvgSel)) {
|
|
glUniform1i(at_enabled_location, 1);
|
|
glUniform1f(at_value_location, gDP.blendColor.a);
|
|
} else if (gDP.otherMode.cvgXAlpha) {
|
|
glUniform1i(at_enabled_location, 1);
|
|
glUniform1f(at_value_location, 0.5f);
|
|
} else {
|
|
glUniform1i(at_enabled_location, 0);
|
|
glUniform1f(at_value_location, 0.0f);
|
|
}
|
|
}
|
|
|
|
void GLSL_RenderDepth() {
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
#if 0
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, g_zbuf_fbo);
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
glDrawBuffer( GL_FRONT );
|
|
ogl_glBlitFramebuffer(
|
|
0, 0, OGL.width, OGL.height,
|
|
0, OGL.heightOffset, OGL.width, OGL.heightOffset + OGL.height,
|
|
GL_COLOR_BUFFER_BIT, GL_LINEAR
|
|
);
|
|
glDrawBuffer( GL_BACK );
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top != NULL ? frameBuffer.top->fbo : 0);
|
|
#else
|
|
if (frameBuffer.top == NULL || frameBuffer.top->pDepthBuffer == NULL)
|
|
return;
|
|
glPushAttrib( GL_ENABLE_BIT | GL_VIEWPORT_BIT );
|
|
|
|
glActiveTexture( GL_TEXTURE0 );
|
|
glBindTexture(GL_TEXTURE_2D, frameBuffer.top->pDepthBuffer->depth_texture->glName);
|
|
// glBindTexture(GL_TEXTURE_2D, g_zlut_tex);
|
|
|
|
Combiner_SetCombine( EncodeCombineMode( 0, 0, 0, TEXEL0, 0, 0, 0, 1, 0, 0, 0, TEXEL0, 0, 0, 0, 1 ) );
|
|
|
|
glDisable( GL_BLEND );
|
|
glDisable( GL_ALPHA_TEST );
|
|
glDisable( GL_DEPTH_TEST );
|
|
glDisable( GL_CULL_FACE );
|
|
glDisable( GL_POLYGON_OFFSET_FILL );
|
|
glDisable( GL_FOG );
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
glLoadIdentity();
|
|
glOrtho( 0, OGL.width, 0, OGL.height, -1.0f, 1.0f );
|
|
glViewport( 0, OGL.heightOffset, OGL.width, OGL.height );
|
|
glDisable( GL_SCISSOR_TEST );
|
|
|
|
float u1, v1;
|
|
|
|
u1 = 1.0;
|
|
v1 = 1.0;
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
#ifndef __LINUX__
|
|
glDrawBuffer( GL_FRONT );
|
|
#else
|
|
glDrawBuffer( GL_BACK );
|
|
#endif
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f( 0.0f, 0.0f );
|
|
glVertex2f( 0.0f, 0.0f );
|
|
|
|
glTexCoord2f( 0.0f, v1 );
|
|
glVertex2f( 0.0f, (GLfloat)OGL.height );
|
|
|
|
glTexCoord2f( u1, v1 );
|
|
glVertex2f( (GLfloat)OGL.width, (GLfloat)OGL.height );
|
|
|
|
glTexCoord2f( u1, 0.0f );
|
|
glVertex2f( (GLfloat)OGL.width, 0.0f );
|
|
glEnd();
|
|
#ifndef __LINUX__
|
|
glDrawBuffer( GL_BACK );
|
|
#else
|
|
OGL_SwapBuffers();
|
|
#endif
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top->fbo);
|
|
|
|
glLoadIdentity();
|
|
glPopAttrib();
|
|
|
|
gSP.changed |= CHANGED_TEXTURE | CHANGED_VIEWPORT;
|
|
gDP.changed |= CHANGED_COMBINE;
|
|
#endif
|
|
}
|
|
|
|
void GLS_SetShadowMapCombiner() {
|
|
|
|
if (!OGL.bImageTexture)
|
|
return;
|
|
|
|
_unbindImageTextures();
|
|
|
|
if (g_paletteCRC256 != gDP.paletteCRC256) {
|
|
g_paletteCRC256 = gDP.paletteCRC256;
|
|
u16 palette[256];
|
|
u16 *src = (u16*)&TMEM[256];
|
|
for (int i = 0; i < 256; ++i)
|
|
palette[i] = swapword(src[i*4]);
|
|
glBindTexture(GL_TEXTURE_1D, g_tlut_tex);
|
|
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RED, GL_UNSIGNED_SHORT, palette);
|
|
glBindTexture(GL_TEXTURE_1D, 0);
|
|
}
|
|
|
|
glUseProgram(g_draw_shadow_map_program);
|
|
|
|
glBindImageTexture(TlutImageUnit, g_tlut_tex, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16UI);
|
|
GLenum depthTexFormat = g_bUseFloatDepthTexture ? GL_R32F : GL_R16UI;
|
|
GLuint texture = frameBuffer.top->pDepthBuffer->depth_texture->glName;
|
|
glBindImageTexture(depthImageUnit, texture, 0, GL_FALSE, 0, GL_READ_ONLY, depthTexFormat);
|
|
gDP.changed |= CHANGED_COMBINE;
|
|
}
|