Files
librw-vita/src/gl/gl3shader.cpp
T
2020-10-18 23:29:03 +02:00

256 lines
5.6 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "../rwbase.h"
#include "../rwerror.h"
#include "../rwplg.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "../rwengine.h"
#ifdef RW_OPENGL
#include "rwgl3.h"
#include "rwgl3shader.h"
namespace rw {
namespace gl3 {
#ifdef RW_GLES2
#include "gl2_shaders/header_vs.inc"
#include "gl2_shaders/header_fs.inc"
#else
#include "shaders/header_vs.inc"
#include "shaders/header_fs.inc"
#endif
UniformRegistry uniformRegistry;
int32
registerUniform(const char *name)
{
int i;
i = findUniform(name);
if(i >= 0) return i;
// TODO: print error
if(uniformRegistry.numUniforms+1 >= MAX_UNIFORMS){
assert(0 && "no space for uniform");
return -1;
}
uniformRegistry.uniformNames[uniformRegistry.numUniforms] = strdup(name);
return uniformRegistry.numUniforms++;
}
int32
findUniform(const char *name)
{
int i;
for(i = 0; i < uniformRegistry.numUniforms; i++)
if(strcmp(name, uniformRegistry.uniformNames[i]) == 0)
return i;
return -1;
}
int32
registerBlock(const char *name)
{
int i;
i = findBlock(name);
if(i >= 0) return i;
// TODO: print error
if(uniformRegistry.numBlocks+1 >= MAX_BLOCKS)
return -1;
uniformRegistry.blockNames[uniformRegistry.numBlocks] = strdup(name);
return uniformRegistry.numBlocks++;
}
int32
findBlock(const char *name)
{
int i;
for(i = 0; i < uniformRegistry.numBlocks; i++)
if(strcmp(name, uniformRegistry.blockNames[i]) == 0)
return i;
return -1;
}
Shader *currentShader;
static void
printShaderSource(const char **src)
{
int f;
const char *file;
bool printline;
int line = 1;
for(f = 0; src[f]; f++){
int fileline = 1;
char c;
file = src[f];
printline = true;
while(c = *file++, c != '\0'){
if(printline)
printf("%.4d/%d:%.4d: ", line++, f, fileline++);
putchar(c);
printline = c == '\n';
}
putchar('\n');
}
}
char shader_source_buffer[16 * 1024];
static int
compileshader(GLenum type, const char **src, GLuint *shader)
{
GLint n;
GLint shdr, success;
GLint len;
char *log;
shader_source_buffer[0] = 0;
for(n = 0; src[n]; n++) {
sprintf(shader_source_buffer, "%s%s", shader_source_buffer, src[n]);
}
const char *_src = (const char*)shader_source_buffer;
shdr = glCreateShader(type);
glShaderSource(shdr, 1, &_src, nil);
glCompileShader(shdr);
glGetShaderiv(shdr, GL_COMPILE_STATUS, &success);
if(!success){
printShaderSource(src);
fprintf(stderr, "Error in %s shader\n",
type == GL_VERTEX_SHADER ? "vertex" : "fragment");
glGetShaderiv(shdr, GL_INFO_LOG_LENGTH, &len);
log = (char*)rwMalloc(len, MEMDUR_FUNCTION);
glGetShaderInfoLog(shdr, len, nil, log);
fprintf(stderr, "%s\n", log);
rwFree(log);
return 1;
}
*shader = shdr;
return 0;
}
static int
linkprogram(GLint vs, GLint fs, GLuint *program, bool is_2d)
{
GLint prog, success;
GLint len;
char *log;
prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
int stride = 0;
int pos_size = is_2d ? 4 : 3;
stride += vglBindPackedAttribLocation(prog, "in_pos" , pos_size, GL_FLOAT, stride, stride + sizeof(float) * pos_size) * (sizeof(float) * pos_size);
stride += vglBindPackedAttribLocation(prog, "in_normal" , 3, GL_FLOAT, stride, stride + sizeof(float) * 3) * (sizeof(float) * 3);
stride += vglBindPackedAttribLocation(prog, "in_color" , 4, GL_UNSIGNED_BYTE, stride, stride + 4) * 4;
stride += vglBindPackedAttribLocation(prog, "in_tex0" , 2, GL_FLOAT, stride, stride + sizeof(float) * 2) * (sizeof(float) * 2);
stride += vglBindPackedAttribLocation(prog, "in_weights", 4, GL_FLOAT, stride, stride + sizeof(float) * 4) * (sizeof(float) * 4);
vglBindPackedAttribLocation(prog, "in_indices", 4, GL_UNSIGNED_BYTE, stride, stride + 4);
glLinkProgram(prog);
*program = prog;
return 0;
}
Shader*
Shader::create(const char **vsrc, const char **fsrc, bool is_2d)
{
GLuint vs, fs, program;
int i;
int fail;
fail = compileshader(GL_VERTEX_SHADER, vsrc, &vs);
if(fail)
return nil;
fail = compileshader(GL_FRAGMENT_SHADER, fsrc, &fs);
if(fail){
glDeleteShader(vs);
return nil;
}
fail = linkprogram(vs, fs, &program, is_2d);
if(fail){
glDeleteShader(fs);
glDeleteShader(vs);
return nil;
}
Shader *sh = rwNewT(Shader, 1, MEMDUR_EVENT | ID_DRIVER); // or global?
#ifdef xxxRW_GLES2
int numUniforms;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms);
for(i = 0; i < numUniforms; i++){
GLint size;
GLenum type;
char name[100];
glGetActiveUniform(program, i, 100, nil, &size, &type, name);
printf("%d %d %s\n", size, type, name);
}
printf("\n");
#endif
#ifdef xxxRW_GLES2
int numAttribs;
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numAttribs);
for(i = 0; i < numAttribs; i++){
GLint size;
GLenum type;
char name[100];
glGetActiveAttrib(program, i, 100, nil, &size, &type, name);
GLint bind = glGetAttribLocation(program, name);
printf("%d %d %s. %d\n", size, type, name, bind);
}
printf("\n");
#endif
// query uniform locations
sh->program = program;
sh->uniformLocations = rwNewT(GLint, uniformRegistry.numUniforms, MEMDUR_EVENT | ID_DRIVER);
for(i = 0; i < uniformRegistry.numUniforms; i++)
sh->uniformLocations[i] = glGetUniformLocation(program,
uniformRegistry.uniformNames[i]);
// set samplers
glUseProgram(program);
// reset program
if(currentShader)
glUseProgram(currentShader->program);
return sh;
}
void
Shader::use(void)
{
if(currentShader != this){
glUseProgram(this->program);
currentShader = this;
}
}
void
Shader::destroy(void)
{
glDeleteProgram(this->program);
rwFree(this->uniformLocations);
rwFree(this);
}
}
}
#endif