Something went wrong on our end
-
marco authored
git-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@1742 5a81b35b-ba03-0410-adc8-b2c5c5119f08
marco authoredgit-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@1742 5a81b35b-ba03-0410-adc8-b2c5c5119f08
shader.cc 11.61 KiB
//------------------------------------------------------------------------------
// This file is part of the OpenStructure project <www.openstructure.org>
//
// Copyright (C) 2008-2010 by the OpenStructure authors
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3.0 of the License, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------
/*
Author: Ansgar Philippsen
*/
#include <vector>
#include <sstream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <ost/platform.hh>
#include <ost/log.hh>
#include "glext_include.hh"
#include "shader.hh"
#include "scene.hh"
namespace ost { namespace gfx {
namespace bf = boost::filesystem;
Shader& Shader::Instance()
{
static Shader instance;
return instance;
}
Shader::Shader():
valid_(false),
current_program_(0),
current_name_(""),
shader_code_map_(),
shader_program_map_()
{}
void Shader::PreGLInit()
{
#if !defined(__APPLE__)
GLenum err = glewInit();
if (GLEW_OK != err) {
LOGN_ERROR("glew failure: " << glewGetErrorString(err));
assert(false);
}
#endif
}
namespace {
bool compile_shader(String shader_name, String shader_code, GLenum shader_type, GLuint& shader_id)
{
shader_id = glCreateShader(shader_type);
const char* tmp_ptr[] = {0};
tmp_ptr[0]=shader_code.c_str();
glShaderSource(shader_id, 1, tmp_ptr, NULL);
glCompileShader(shader_id);
GLint sh_compiled;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &sh_compiled);
if(sh_compiled==GL_TRUE) {
LOGN_VERBOSE("shader [" << shader_name << "] successfully compiled (" << shader_id << ")");
} else {
GLint sh_log_length;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &sh_log_length);
std::vector<GLchar> sh_log(sh_log_length+1);
glGetShaderInfoLog(shader_id, sh_log_length, NULL, &sh_log[0]);
LOGN_VERBOSE("shader [" << shader_name << "] compilation failed:" << std::endl << String(&sh_log[0]));
return false;
}
return true;
}
bool link_shader(const std::vector<GLuint>& code_list, String pr_name, GLuint& shader_pr)
{
shader_pr = glCreateProgram();
for(std::vector<GLuint>::const_iterator it=code_list.begin();it!=code_list.end();++it) {
if(*it == 0) {
LOGN_VERBOSE("skipping shader [" << pr_name << "] due to missing compiled code");
return false;
}
LOGN_DEBUG("attaching compiled shader id " << *it << " to " << shader_pr);
glAttachShader(shader_pr,*it);
}
glLinkProgram(shader_pr);
GLint pr_linked;
glGetProgramiv(shader_pr,GL_LINK_STATUS,&pr_linked);
if(pr_linked==GL_TRUE) {
LOGN_VERBOSE("shader [" << pr_name << "] sucessfully linked");
} else {
GLint pr_log_length;
glGetProgramiv(shader_pr, GL_INFO_LOG_LENGTH, &pr_log_length);
std::vector<GLchar> pr_log(pr_log_length+1);
glGetProgramInfoLog(shader_pr, pr_log_length, NULL, &pr_log[0]);
LOGN_VERBOSE("shader [" << pr_name << "] linking failed:" << std::endl << String(&pr_log[0]));
return false;
}
return true;
}
}
void Shader::Setup()
{
String ost_root = GetSharedDataPath();
bf::path ost_root_dir(ost_root);
bf::path shader_dir(ost_root_dir / "shader");
struct ShaderListEntry {
const char* file;
GLenum type;
} shader_list[] = {
//////////////////////////////////////////////////////////////////
// this is the master list of all shader code in lib/ost/shader
{"basic_lf_vs.glsl", GL_VERTEX_SHADER},
{"basic_lf_fs.glsl", GL_FRAGMENT_SHADER},
{"fraglight_lf_vs.glsl", GL_VERTEX_SHADER},
{"fraglight_lf_fs.glsl", GL_FRAGMENT_SHADER},
{"basic_lfs_vs.glsl", GL_VERTEX_SHADER},
{"basic_lfs_fs.glsl", GL_FRAGMENT_SHADER},
{"fraglight_lfs_vs.glsl", GL_VERTEX_SHADER},
{"fraglight_lfs_fs.glsl", GL_FRAGMENT_SHADER},
{"basic_hf_vs.glsl", GL_VERTEX_SHADER},
{"selfx_vs.glsl", GL_VERTEX_SHADER},
{"selfx_fs.glsl", GL_FRAGMENT_SHADER},
{"toon_vs.glsl", GL_VERTEX_SHADER},
{"toon_fs.glsl", GL_FRAGMENT_SHADER},
{"toon2_fs.glsl", GL_FRAGMENT_SHADER},
{"noop_vs.glsl", GL_VERTEX_SHADER},
{"aaline_fs.glsl", GL_FRAGMENT_SHADER},
{"iso_vs.glsl", GL_VERTEX_SHADER},
{"iso_fs.glsl", GL_FRAGMENT_SHADER},
{"fast_sphere_vs.glsl", GL_VERTEX_SHADER},
{"fast_sphere_fs.glsl", GL_FRAGMENT_SHADER},
{"outline_vs.glsl", GL_VERTEX_SHADER}
//////////////////////////////////////////////////////////////////
};
shader_code_map_.clear();
for(unsigned int i=0;i<sizeof(shader_list)/sizeof(ShaderListEntry);++i) {
String shader_name(shader_list[i].file);
bf::path shader_file(shader_dir / shader_name);
if(!bf::exists(shader_file)){
LOGN_ERROR("not found: [" << shader_file.string() << "], cannot create shaders");
continue;
}
bf::ifstream shader_file_stream(shader_file);
String shader_code;
String line;
while (std::getline(shader_file_stream,line)) {
shader_code += line + "\n";
}
GLuint shader_id;
if(compile_shader(shader_name,shader_code,shader_list[i].type,shader_id)) {
shader_code_map_[shader_name]=shader_id;
} else {
shader_code_map_[shader_name]=0;
}
}
std::vector<GLuint> shader_program_list;
GLuint shader_program_id;
// basic shader
shader_program_list.push_back(shader_code_map_["basic_lf_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["basic_lf_fs.glsl"]);
if(link_shader(shader_program_list,"basic",shader_program_id)) {
shader_program_map_["basic"]=shader_program_id;
}
// fraglight shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["fraglight_lf_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["fraglight_lf_fs.glsl"]);
if(link_shader(shader_program_list,"fraglight",shader_program_id)) {
shader_program_map_["fraglight"]=shader_program_id;
}
// basic shadow map shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["basic_lfs_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["basic_lfs_fs.glsl"]);
if(link_shader(shader_program_list,"basic_shadow",shader_program_id)) {
shader_program_map_["basic_shadow"]=shader_program_id;
}
// fraglight shader with shadow map
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["fraglight_lfs_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["fraglight_lfs_fs.glsl"]);
if(link_shader(shader_program_list,"fraglight_shadow",shader_program_id)) {
shader_program_map_["fraglight_shadow"]=shader_program_id;
}
// basic hemisphere lighting shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["basic_hf_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["basic_lf_fs.glsl"]);
if(link_shader(shader_program_list,"hemilight",shader_program_id)) {
shader_program_map_["hemilight"]=shader_program_id;
}
// selfx shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["selfx_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["selfx_fs.glsl"]);
if(link_shader(shader_program_list,"selfx",shader_program_id)) {
shader_program_map_["selfx"]=shader_program_id;
}
// toon shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["toon_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["toon_fs.glsl"]);
if(link_shader(shader_program_list,"toon",shader_program_id)) {
shader_program_map_["toon"]=shader_program_id;
}
// toon2 shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["toon_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["toon2_fs.glsl"]);
if(link_shader(shader_program_list,"toon2",shader_program_id)) {
shader_program_map_["toon2"]=shader_program_id;
}
// line shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["basic_lf_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["aaline_fs.glsl"]);
if(link_shader(shader_program_list,"aaline",shader_program_id)) {
shader_program_map_["aaline"]=shader_program_id;
}
// iso shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["iso_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["iso_fs.glsl"]);
if(link_shader(shader_program_list,"iso",shader_program_id)) {
shader_program_map_["iso"]=shader_program_id;
}
// fast sphere shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["fast_sphere_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["fast_sphere_fs.glsl"]);
if(link_shader(shader_program_list,"fast_sphere",shader_program_id)) {
shader_program_map_["fast_sphere"]=shader_program_id;
}
// basic shader
shader_program_list.clear();
shader_program_list.push_back(shader_code_map_["outline_vs.glsl"]);
shader_program_list.push_back(shader_code_map_["basic_lf_fs.glsl"]);
if(link_shader(shader_program_list,"outline",shader_program_id)) {
shader_program_map_["outline"]=shader_program_id;
}
valid_=true;
}
void Shader::Activate(const String& name)
{
if(!name.empty()) {
std::map<ost::String, GLuint>::iterator it = shader_program_map_.find(name);
if(it!=shader_program_map_.end()) {
LOGN_DUMP("switching to shader [" << name << "]");
glUseProgram(it->second);
current_program_=it->second;
current_name_=name;
if(name=="basic_shadow" || name=="fraglight_shadow") {
if(!Scene::Instance().GetShadow())
Scene::Instance().SetShadow(true);
} else {
if(Scene::Instance().GetShadow())
Scene::Instance().SetShadow(false);
}
UpdateState();
return;
} else {
LOGN_MESSAGE("shader program [" << name << "] not present");
return;
}
}
LOGN_DUMP("switching to fixed pipeline");
glUseProgram(0);
current_program_=0;
current_name_="";
}
GLuint Shader::GetCurrentProgram() const
{
return current_program_;
}
String Shader::GetCurrentName() const
{
return current_name_;
}
bool Shader::IsValid() const
{
return valid_;
}
bool Shader::IsActive() const
{
return current_program_!=0;
}
void Shader::PushProgram()
{
program_stack_.push(current_name_);
}
void Shader::PopProgram()
{
if(!program_stack_.empty()) {
current_name_ = program_stack_.top();
program_stack_.pop();
Activate(current_name_);
}
}
void Shader::UpdateState()
{
if(current_program_!=0) {
// update current lighting and fog settings, valid for all shaders
GLint result;
glGetIntegerv(GL_LIGHTING,&result);
LOGN_TRACE("setting lighting flag to " << result);
glUniform1i(glGetUniformLocation(current_program_,"lighting_flag"),result);
GLboolean bresult;
glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE,&bresult);
LOGN_TRACE("setting two_sided flag to " << bresult);
glUniform1i(glGetUniformLocation(current_program_,"two_sided_flag"),bresult);
glGetIntegerv(GL_FOG,&result);
LOGN_TRACE("setting fog flag to " << result);
glUniform1i(glGetUniformLocation(current_program_,"fog_flag"),result);
glDisable(GL_COLOR_MATERIAL);
} else {
glEnable(GL_COLOR_MATERIAL);
}
}
}} // ns