261 lines
11 KiB
C
261 lines
11 KiB
C
#include "state.h"
|
|
#include "../passthrough.h"
|
|
|
|
#include <GLES/gl.h>
|
|
|
|
#include <libreborn/libreborn.h>
|
|
|
|
// Shaders
|
|
#define REAL_GL_FRAGMENT_SHADER 0x8b30
|
|
#define REAL_GL_VERTEX_SHADER 0x8b31
|
|
#define REAL_GL_INFO_LOG_LENGTH 0x8b84
|
|
#define REAL_GL_COMPILE_STATUS 0x8b81
|
|
GL_FUNC(glUseProgram, void, (GLuint program));
|
|
GL_FUNC(glGetUniformLocation, GLint, (GLuint program, const GLchar *name));
|
|
GL_FUNC(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
|
|
GL_FUNC(glUniform1i, void, (GLint location, GLint v0));
|
|
GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0));
|
|
GL_FUNC(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
|
|
GL_FUNC(glGetAttribLocation, GLint, (GLuint program, const GLchar *name));
|
|
GL_FUNC(glEnableVertexAttribArray, void, (GLuint index));
|
|
GL_FUNC(glDisableVertexAttribArray, void, (GLuint index));
|
|
GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
|
|
GL_FUNC(glVertexAttrib3f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2));
|
|
GL_FUNC(glVertexAttrib4f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
|
|
GL_FUNC(glCreateShader, GLuint, (GLenum type));
|
|
GL_FUNC(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length));
|
|
GL_FUNC(glCompileShader, void, (GLuint shader));
|
|
GL_FUNC(glCreateProgram, GLuint, ());
|
|
GL_FUNC(glAttachShader, void, (GLuint program, GLuint shader));
|
|
GL_FUNC(glLinkProgram, void, (GLuint program));
|
|
GL_FUNC(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params));
|
|
GL_FUNC(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
|
|
|
|
// Compile Shader
|
|
static void log_shader(GLuint shader, const char *name) {
|
|
// Log
|
|
GLint log_length = 0;
|
|
real_glGetShaderiv()(shader, REAL_GL_INFO_LOG_LENGTH, &log_length);
|
|
GLchar *log = malloc(log_length * sizeof (GLchar));
|
|
ALLOC_CHECK(log);
|
|
real_glGetShaderInfoLog()(shader, log_length, &log_length, log);
|
|
if (log_length > 0) {
|
|
if (log_length > 1 && log[log_length - 1] == '\n') {
|
|
log[log_length - 1] = '\0';
|
|
}
|
|
DEBUG("%s Shader Compile Log: %s", name, log);
|
|
}
|
|
free(log);
|
|
|
|
// Check Status
|
|
GLint is_compiled = 0;
|
|
real_glGetShaderiv()(shader, REAL_GL_COMPILE_STATUS, &is_compiled);
|
|
if (!is_compiled) {
|
|
ERR("Failed To Compile %s Shader", name);
|
|
}
|
|
}
|
|
static GLuint compile_shader(const char *vertex_shader_text, const char *fragment_shader_text) {
|
|
// Vertex Shader
|
|
const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER);
|
|
real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, NULL);
|
|
real_glCompileShader()(vertex_shader);
|
|
log_shader(vertex_shader, "Vertex");
|
|
|
|
// Fragment Shader
|
|
const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER);
|
|
real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, NULL);
|
|
real_glCompileShader()(fragment_shader);
|
|
log_shader(fragment_shader, "Fragment");
|
|
|
|
// Link
|
|
GLuint program = real_glCreateProgram()();
|
|
real_glAttachShader()(program, vertex_shader);
|
|
real_glAttachShader()(program, fragment_shader);
|
|
real_glLinkProgram()(program);
|
|
|
|
// Return
|
|
return program;
|
|
}
|
|
|
|
// Shader
|
|
static GLuint get_shader() {
|
|
static GLuint program = 0;
|
|
if (program == 0) {
|
|
static const char *vertex_shader_text =
|
|
"#version 100\n"
|
|
"precision mediump float;\n"
|
|
// Matrices
|
|
"uniform mat4 u_projection;\n"
|
|
"uniform mat4 u_model_view;\n"
|
|
"uniform mat4 u_texture;\n"
|
|
// Texture
|
|
"attribute vec3 a_vertex_coords;\n"
|
|
"attribute vec2 a_texture_coords;\n"
|
|
"varying vec4 v_texture_pos;\n"
|
|
// Color
|
|
"attribute vec4 a_color;\n"
|
|
"varying vec4 v_color;\n"
|
|
// Fog
|
|
"varying vec4 v_fog_eye_position;\n"
|
|
// Main
|
|
"void main() {\n"
|
|
" v_texture_pos = u_texture * vec4(a_texture_coords.xy, 0.0, 1.0);\n"
|
|
" gl_Position = u_projection * u_model_view * vec4(a_vertex_coords.xyz, 1.0);\n"
|
|
" v_color = a_color;\n"
|
|
" v_fog_eye_position = u_model_view * vec4(a_vertex_coords.xyz, 1.0);\n"
|
|
"}";
|
|
static const char *fragment_shader_text =
|
|
"#version 100\n"
|
|
"precision mediump float;\n"
|
|
// Texture
|
|
"uniform bool u_has_texture;"
|
|
"uniform sampler2D u_texture_unit;\n"
|
|
// Color
|
|
"varying vec4 v_color;\n"
|
|
"varying vec4 v_texture_pos;\n"
|
|
// Alpha Test
|
|
"uniform bool u_alpha_test;\n"
|
|
// Fog
|
|
"uniform bool u_fog;\n"
|
|
"uniform vec4 u_fog_color;\n"
|
|
"uniform bool u_fog_is_linear;\n"
|
|
"uniform float u_fog_start;\n"
|
|
"uniform float u_fog_end;\n"
|
|
"varying vec4 v_fog_eye_position;\n"
|
|
// Main
|
|
"void main(void) {\n"
|
|
" gl_FragColor = v_color;\n"
|
|
" if (u_has_texture) {\n"
|
|
" gl_FragColor *= texture2D(u_texture_unit, v_texture_pos.xy);\n"
|
|
" }\n"
|
|
" if (u_alpha_test && gl_FragColor.a <= 0.1) {\n"
|
|
" discard;\n"
|
|
" }\n"
|
|
" if (u_fog) {\n"
|
|
" float fog_factor;\n"
|
|
" if (u_fog_is_linear) {\n"
|
|
" fog_factor = (u_fog_end - length(v_fog_eye_position)) / (u_fog_end - u_fog_start);\n"
|
|
" } else {\n"
|
|
" fog_factor = exp(-u_fog_start * length(v_fog_eye_position));\n"
|
|
" }\n"
|
|
" gl_FragColor = mix(gl_FragColor, u_fog_color, 1.0 - clamp(fog_factor, 0.0, 1.0));\n"
|
|
" }\n"
|
|
"}";
|
|
program = compile_shader(vertex_shader_text, fragment_shader_text);
|
|
}
|
|
return program;
|
|
}
|
|
|
|
// Shader Switching
|
|
static void use_shader(GLuint program) {
|
|
static GLuint current_program = 0;
|
|
if (current_program != program) {
|
|
real_glUseProgram()(program);
|
|
current_program = program;
|
|
}
|
|
}
|
|
|
|
// Array Pointer Drawing
|
|
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count));
|
|
#define lazy_uniform(name) \
|
|
static GLint name##_handle = -1; \
|
|
if (name##_handle == -1) { \
|
|
name##_handle = real_glGetUniformLocation()(program, #name); \
|
|
}
|
|
void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
|
|
// Verify
|
|
if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) {
|
|
ERR("Unsupported Vertex Conifguration");
|
|
}
|
|
|
|
// Check Mode
|
|
int use_color_pointer = gl_state.array_pointers.color.enabled;
|
|
if (use_color_pointer && (gl_state.array_pointers.color.size != 4 || gl_state.array_pointers.color.type != GL_UNSIGNED_BYTE)) {
|
|
ERR("Unsupported Color Conifguration");
|
|
}
|
|
int use_texture = gl_state.texture_2d && gl_state.array_pointers.tex_coord.enabled;
|
|
if (use_texture && (gl_state.array_pointers.tex_coord.size != 2 || gl_state.array_pointers.tex_coord.type != GL_FLOAT)) {
|
|
ERR("Unsupported Texture Conifguration");
|
|
}
|
|
|
|
// Load Shader
|
|
GLuint program = get_shader();
|
|
use_shader(program);
|
|
|
|
// Projection Matrix
|
|
lazy_uniform(u_projection);
|
|
matrix_t *p = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i];
|
|
real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
|
|
|
// Model View Matrix
|
|
lazy_uniform(u_model_view);
|
|
p = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i];
|
|
real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
|
|
|
// Has Texture
|
|
lazy_uniform(u_has_texture); \
|
|
real_glUniform1i()(u_has_texture_handle, use_texture); \
|
|
|
|
// Texture Matrix
|
|
lazy_uniform(u_texture);
|
|
p = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i];
|
|
real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
|
|
|
// Texture Unit
|
|
lazy_uniform(u_texture_unit);
|
|
real_glUniform1i()(u_texture_unit_handle, 0);
|
|
|
|
// Alpha Test
|
|
lazy_uniform(u_alpha_test);
|
|
real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test);
|
|
|
|
// Color
|
|
GLint a_color_handle = real_glGetAttribLocation()(program, "a_color");
|
|
if (use_color_pointer) {
|
|
real_glVertexAttribPointer()(a_color_handle, gl_state.array_pointers.color.size, gl_state.array_pointers.color.type, 1, gl_state.array_pointers.color.stride, gl_state.array_pointers.color.pointer);
|
|
real_glEnableVertexAttribArray()(a_color_handle);
|
|
} else {
|
|
real_glVertexAttrib4f()(a_color_handle, gl_state.color.red, gl_state.color.green, gl_state.color.blue, gl_state.color.alpha);
|
|
}
|
|
|
|
// Fog
|
|
lazy_uniform(u_fog);
|
|
real_glUniform1i()(u_fog_handle, gl_state.fog.enabled);
|
|
if (gl_state.fog.enabled) {
|
|
lazy_uniform(u_fog_color);
|
|
real_glUniform4f()(u_fog_color_handle, gl_state.fog.color[0], gl_state.fog.color[1], gl_state.fog.color[2], gl_state.fog.color[3]);
|
|
lazy_uniform(u_fog_is_linear);
|
|
real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR);
|
|
lazy_uniform(u_fog_start);
|
|
real_glUniform1f()(u_fog_start_handle, gl_state.fog.start);
|
|
lazy_uniform(u_fog_end);
|
|
real_glUniform1f()(u_fog_end_handle, gl_state.fog.end);
|
|
}
|
|
|
|
// Vertices
|
|
GLint a_vertex_coords_handle = real_glGetAttribLocation()(program, "a_vertex_coords");
|
|
real_glVertexAttribPointer()(a_vertex_coords_handle, gl_state.array_pointers.vertex.size, gl_state.array_pointers.vertex.type, 0, gl_state.array_pointers.vertex.stride, gl_state.array_pointers.vertex.pointer);
|
|
real_glEnableVertexAttribArray()(a_vertex_coords_handle);
|
|
|
|
// Texture Coordinates
|
|
GLint a_texture_coords_handle = real_glGetAttribLocation()(program, "a_texture_coords");
|
|
if (use_texture) {
|
|
real_glVertexAttribPointer()(a_texture_coords_handle, gl_state.array_pointers.tex_coord.size, gl_state.array_pointers.tex_coord.type, 0, gl_state.array_pointers.tex_coord.stride, gl_state.array_pointers.tex_coord.pointer);
|
|
real_glEnableVertexAttribArray()(a_texture_coords_handle);
|
|
} else {
|
|
real_glVertexAttrib3f()(a_texture_coords_handle, 0, 0, 0);
|
|
}
|
|
|
|
// Draw
|
|
real_glDrawArrays()(mode, first, count);
|
|
|
|
// Cleanup
|
|
if (use_color_pointer) {
|
|
real_glDisableVertexAttribArray()(a_color_handle);
|
|
}
|
|
real_glDisableVertexAttribArray()(a_vertex_coords_handle);
|
|
if (use_texture) {
|
|
real_glDisableVertexAttribArray()(a_texture_coords_handle);
|
|
}
|
|
}
|