// shader handling
// Author: Supakorn "Jamie" Rassameemasmuang
#include "common.h"
#ifdef HAVE_GL
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <iostream>
#include "settings.h"
#include "fpu.h"
#include "shaders.h"
int GLSLversion;
GLuint compileAndLinkShader(std::vector<ShaderfileModePair> const& shaders,
std::vector<std::string> const& defineflags,
bool ssbo, bool interlock, bool compute, bool test)
{
GLuint shader = glCreateProgram();
std::vector<GLuint> compiledShaders;
size_t n=shaders.size();
for(size_t i=0; i < n; ++i) {
GLint newshader=createShaderFile(shaders[i].first,shaders[i].second,
defineflags,ssbo,interlock,compute,test);
if(test && newshader == 0) return 0;
glAttachShader(shader,newshader);
compiledShaders.push_back(newshader);
}
glBindAttribLocation(shader,positionAttrib,"position");
glBindAttribLocation(shader,normalAttrib,"normal");
glBindAttribLocation(shader,materialAttrib,"material");
glBindAttribLocation(shader,colorAttrib,"color");
glBindAttribLocation(shader,widthAttrib,"width");
fpu_trap(false); // Work around FE_INVALID
glLinkProgram(shader);
fpu_trap(settings::trap());
for(size_t i=0; i < n; ++i) {
glDetachShader(shader,compiledShaders[i]);
glDeleteShader(compiledShaders[i]);
}
return shader;
}
GLuint createShader(const std::string& src, int shaderType,
const std::string& filename, bool ssbo, bool interlock,
bool compute, bool test)
{
const GLchar *source=src.c_str();
GLuint shader=glCreateShader(shaderType);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status != GL_TRUE) {
if(test) return 0;
GLint length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> msg(length);
glGetShaderInfoLog(shader, length, &length, msg.data());
size_t n=msg.size();
for(size_t i=0; i < n; ++i)
std::cerr << msg[i];
std::cerr << std::endl << "GL Compile error" << std::endl;
std::stringstream s(src);
std::string line;
unsigned int k=0;
while(getline(s,line))
std::cerr << ++k << ": " << line << std::endl;
exit(-1);
}
return shader;
}
GLuint createShaderFile(std::string file, int shaderType,
std::vector<std::string> const& defineflags,
bool ssbo, bool interlock, bool compute, bool test)
{
std::ifstream shaderFile;
shaderFile.open(file.c_str());
std::stringstream shaderSrc;
shaderSrc << "#version " << GLSLversion << "\n";
#ifndef __APPLE__
shaderSrc << "#extension GL_ARB_uniform_buffer_object : enable" << "\n";
#ifdef HAVE_SSBO
if(ssbo) {
shaderSrc << "#extension GL_ARB_shader_storage_buffer_object : enable" << "\n";
shaderSrc << "#extension GL_ARB_shader_atomic_counters : enable" << "\n";
if(interlock)
shaderSrc << "#extension GL_ARB_fragment_shader_interlock : enable"
<< "\n";
if(compute)
shaderSrc << "#extension GL_ARB_compute_shader : enable" << "\n";
}
#endif
#endif
size_t n=defineflags.size();
for(size_t i=0; i < n; ++i)
shaderSrc << "#define " << defineflags[i] << "\n";
if(shaderFile) {
shaderSrc << shaderFile.rdbuf();
shaderFile.close();
} else {
std::cerr << "Cannot read from shader file " << file << std::endl;
exit(-1);
}
return createShader(shaderSrc.str(),shaderType,file,ssbo,interlock,compute,
test);
}
#endif