GLWindow(const char *name = "SDL GL Window", const Size &s = Size(800,600), unsigned int flags = 0) throw(GLException) : SDLWindow(name,s,SDL_WINDOW_OPENGL|flags) { context = SDL_GL_CreateContext(getSDLWindow()); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetAttribute(SDL_GL_RED_SIZE,5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,5); SDL_GL_SetSwapInterval(1); GLenum glew_status = glewInit(); if(GLEW_OK != glew_status) { throw(GLException(reinterpret_cast<const char*>(glewGetErrorString(glew_status)))); } if(!GLEW_VERSION_2_0) { /* TODO: * in this case use old OpenGL */ throw(GLException("No support for OpenGL 2.0 found")); } glClearColor(0, 0, 0, 0); glViewport(0,0,s.w,s.h); }
AssimpModel::AssimpModel ( const std::string& fileName ) { m_scene = m_importer.ReadFile ( fileName.c_str(), aiProcess_Triangulate ); if ( !m_scene ) { throw GLException("Load model failed"); } if (m_scene->HasTextures()) { throw GLException("AssimpModel::LoadGLTextures failed"); } loadTextures(fileName); }
IndexSlot operator[](int index) { if(index >= m_indexCount) { logError("[IndexSet] Index <", index, "> out of bounds!"); throw GLException("[IndexSet] Index out of bounds"); } return std::move(IndexSlot(*(m_buffer + index))); }
void debugGLError( const std::string& when, const GLenum error, const char* file, const int line ) { LBWARN << lunchbox::disableFlush << "Got " << glError( error ) << ' ' << when << " in " << file << ':' << line << std::endl << lunchbox::backtrace << lunchbox::enableFlush << std::endl; throw GLException( error ); }
void CheckForGLError( const std::string &situation ) { GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { const char *string = (const char *)gluErrorString(errorCode); _THROW_ GLException( TO_STRING( situation << " : " << string ) ); } }
void GLSLProgram::setUniform(const char* uniformName, T& value) { if (!m_linked) { SAFE_THROW(GLException(E_BADSTATE, "GLSL program must be linked before binding uniforms")); } int loc = glGetUniformLocation(m_progID, uniformName); // the uniform could either not exist or be inactive (e.g. removed by the glsl compiler as it was not used) if (loc != -1) { this->setUniform(loc, value); } }
GLBuffer::GLBuffer() { GLuint id = 0; try { GLError::clearAll(); glGenBuffers(1, &id); setID(id); GLError::throwExceptionOnError(); } catch (GLException& e) { glDeleteBuffers(1, &id); throw GLException(string("Couldn't create buffer: ") + string(e.what())); } }
GLTexture::GLTexture() : MioObject() { glGetError(); glGenTextures(1, &texID_); GLint error = glGetError(); if (error != GL_NO_ERROR) throw GLException("GLException: cannot generate new texture"); components_ = 4; format_ = GL_RGBA; type_ = GL_UNSIGNED_BYTE; width_ = 0; height_ = 0; mag_filter_ = GL_LINEAR; min_filter_ = GL_LINEAR; wrap_s_ = GL_REPEAT; wrap_t_ = GL_REPEAT; mipmapBuilt_ = false; }
void Program::create(VShader& vs, FShader& fs) { auto program = glCreateProgram(); // attach both shaders glAttachShader(program, vs.getHandle()); glAttachShader(program, fs.getHandle()); // link program glLinkProgram(program); // check for errors GLint linkStatus; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if(linkStatus != GL_TRUE) { // obtain error message GLint logLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); vector<char> compileLog(logLength); glGetShaderInfoLog(program, logLength, nullptr, compileLog.data()); logError("[Program] Could not link shaders <", vs.getFilename(), ", ", fs.getFilename(), "> ->"); logError("[Program] ", compileLog.data()); throw GLException("Could not link shaders"); } log("[Program] Shaders <", vs.getFilename(), ", ", fs.getFilename(), "> were successfully linked."); // detach shaders (TODO: is this a good idea?) glDetachShader(program, vs.getHandle()); glDetachShader(program, fs.getHandle()); // check for any error checkGLError("[Program] GL error while linking program <", GLERR, ">!"); // linking was successful: commit changes m_handle = program; }
void GLSLProgram::setUniform(const String& uniformName, T& value) { if (!m_linked) { SAFE_THROW(GLException(E_BADSTATE, "GLSL program must be linked before binding uniforms")); } this->setUniform(uniformName.c_str(), value); }
void ShaderGenerator::generateShaders(Material& mat, const RenderState& rs, const VertexFormat& vf, const FogParameters fogParams) { bool hasNormalMap = false; bool hasParallaxMap = false; ctemplate::TemplateDictionary vertexShaderDict("vertexShader"); ctemplate::TemplateDictionary fragmentShaderDict("fragmentShader"); ctemplate::TemplateDictionary* vertexIoDict = vertexShaderDict.AddIncludeDictionary("VERTEX_INPUTS"); vertexIoDict->SetFilename("shader_templates/ft_vertex_inout.tpl"); ctemplate::TemplateDictionary* fragmentOutDict = vertexShaderDict.AddIncludeDictionary("FRAGMENT_INPUTS"); fragmentOutDict->SetFilename("shader_templates/ft_fragment_inout.tpl"); fragmentOutDict->ShowSection("OUT_DIRECTION"); ctemplate::TemplateDictionary* uniformsDict = vertexShaderDict.AddIncludeDictionary("UNIFORMS"); uniformsDict->SetFilename("shader_templates/uniforms.tpl"); // emit the fog uniforms if necessary if (fogParams.m_fogMode != FOG_NONE) { uniformsDict->ShowSection("FOG"); } // use lighting when material uses shading and we have normals bool useLighting = !mat.m_shadeless && vf.getAttributeBySemantic(Vertex_Normal); if (useLighting) { uniformsDict->ShowSection("USE_LIGHTING"); } if (vf.getAttributeBySemantic(Vertex_Normal)) { vertexShaderDict.ShowSection("HAS_NORMALS"); vertexShaderDict.ShowSection("NORMALIZE_NORMALS"); vertexIoDict->ShowSection("HAS_NORMALS"); vertexIoDict->ShowSection("NORMALIZE_NORMALS"); fragmentOutDict->ShowSection("HAS_NORMALS"); uniformsDict->ShowSection("HAS_NORMALS"); } if (vf.getAttributeBySemantic(Vertex_Tangent)) { fragmentOutDict->ShowSection("HAS_TANGENTS"); vertexIoDict->ShowSection("HAS_TANGENTS"); } if (vf.getAttributeBySemantic(Vertex_BiNormal)) { fragmentOutDict->ShowSection("HAS_BINORMALS"); vertexIoDict->ShowSection("HAS_BINORMALS"); } if (vf.getAttributeBySemantic(Vertex_Color)) { vertexShaderDict.ShowSection("HAS_COLORS"); vertexIoDict->ShowSection("HAS_COLORS"); fragmentOutDict->ShowSection("HAS_COLORS"); } // indicates if the tex coords generation functions declarations template has already been // included in the vertex shader template bool texGenDeclIncluded = false; // number of active texture units uint activeTextures = 0; ctemplate::TemplateDictionary* texGenDict = vertexShaderDict.AddIncludeDictionary("TEX_COORDS_GEN"); texGenDict->SetFilename("shader_templates/ft_tex_coords_gen.tpl"); // Loops over all material textures and performs the following: // 1. Declares a respective uniform sampler object which will be named as u_sampler#, // where # is the active texture index. // 2. Emits code for any texture coordinates generation scheme, if not simple UV. ctemplate::TemplateDictionary* parallaxMapDict = 0; for (int i = 0; i < MAX_TEXTURES_STACK; i++) { TexturePtr tex = mat.m_texStack->textures[i]; if (tex) { // for the fragment shader, here we can fill in the dictionary for the texture application section // that takes into account the texture's mapTo, environment color, uvset, etc. ctemplate::TemplateDictionary* texUnitDict = fragmentShaderDict.AddIncludeDictionary( "SINGLE_TEXTURE_STACK_ENTRY"); texUnitDict->SetFilename("shader_templates/ft_tex_stack_application.tpl"); ctemplate::TemplateDictionary* alphaMapDict = 0; ctemplate::TemplateDictionary* tangentNormalMapDict = 0; ctemplate::TemplateDictionary* offsetMappingDict = 0; // depending on the texture's mapTo, we will emit different sections in the template ctemplate::TemplateDictionary* texMapToDict = 0; switch (mat.m_texStack->texOutputs[i].mapTo) { case TexMapTo_Diffuse: texMapToDict = texUnitDict->AddSectionDictionary("TEX_MAP_TO_DIFFUSE"); break; case TexMapTo_CSpecular: texMapToDict = texUnitDict->AddSectionDictionary("TEX_MAP_TO_SPECULAR"); break; case TexMapTo_Shininess: texMapToDict = texUnitDict->AddSectionDictionary("TEX_MAP_TO_SHININESS"); break; case TexMapTo_Alpha: alphaMapDict = fragmentShaderDict.AddSectionDictionary("ALPHA_MAP_APPLICATION"); break; case TexMapTo_Normal: tangentNormalMapDict = fragmentShaderDict.AddIncludeDictionary("TANGENT_SPACE_NORMAL_MAP"); tangentNormalMapDict->SetFilename(TANGENT_SPACE_NMAP_TPL); parallaxMapDict = tangentNormalMapDict; hasNormalMap = true; break; case TexMapTo_Parallax: /* IMPORTANT: Parallax maps must come after the normal maps */ if (parallaxMapDict) { offsetMappingDict = parallaxMapDict->AddSectionDictionary("PARALLAX_OFFSET_MAPPING"); } hasParallaxMap = true; break; default: SAFE_THROW(GLException(E_NOTIMPL, "Unimplemented texture output mapping mode")) } texUnitDict->SetIntValue(TEX_INDEX, activeTextures); texUnitDict->SetIntValue(UV_SET_INDEX, mat.m_texStack->texInputs[i].uvSet); if (alphaMapDict) { alphaMapDict->SetIntValue(TEX_INDEX, activeTextures); alphaMapDict->SetIntValue(UV_SET_INDEX, mat.m_texStack->texInputs[i].uvSet); } if (tangentNormalMapDict) { tangentNormalMapDict->SetIntValue(TEX_INDEX, activeTextures); tangentNormalMapDict->SetIntValue(UV_SET_INDEX, mat.m_texStack->texInputs[i].uvSet); } if (offsetMappingDict) { offsetMappingDict->SetIntValue(TEX_INDEX, activeTextures); offsetMappingDict->SetIntValue(UV_SET_INDEX, mat.m_texStack->texInputs[i].uvSet); } switch (mat.m_texStack->texOutputs[i].blendOp) { case TexBlendOp_Mix: texUnitDict->ShowSection("TEX_BLENDOP_BLEND"); break; case TexBlendOp_Add: texUnitDict->ShowSection("TEX_BLENDOP_ADD"); break; case TexBlendOp_Multiply: texUnitDict->ShowSection("TEX_BLENDOP_MULTIPLY"); break; case TexBlendOp_Decal: texUnitDict->ShowSection("TEX_BLENDOP_DECAL"); break; default: SAFE_THROW(GLException(E_NOTIMPL, "Unimplemented texture blending mode")) } // this is the dictionary for a single uniform sampler declaration ctemplate::TemplateDictionary* samplerDict = uniformsDict->AddSectionDictionary("SINGLE_SAMPLER_DECL"); samplerDict->SetIntValue(TEX_INDEX, activeTextures); const char* samplerToken; const char* coordsToken; switch (tex->getTextureTarget()) { case GL_TEXTURE_1D: samplerToken = "sampler1D"; coordsToken = S_COORD; break; case GL_TEXTURE_CUBE_MAP: samplerToken = "samplerCube"; coordsToken = STP_COORDS; break; case GL_TEXTURE_2D: default: samplerToken = "sampler2D"; coordsToken = ST_COORDS; break; } samplerDict->SetValue("SAMPLER_SPEC", samplerToken); texUnitDict->SetValue(TEX_COORDS, coordsToken); if (alphaMapDict) { alphaMapDict->SetValue(TEX_COORDS, coordsToken); } if (tangentNormalMapDict) { tangentNormalMapDict->SetValue(TEX_COORDS, coordsToken); } if (offsetMappingDict) { offsetMappingDict->SetValue(TEX_COORDS, coordsToken); } // When a special texture coordinate generation system is used, we have to include // the TEX_COORDS_GEN_DECL template which contains function declarations for the various // tex gen systems. Then for each texture unit that uses custom tex gen, we need to // instantiate a SINGLE_TEX_COORDS_GEN section with an appropriately initialized dictionary ctemplate::TemplateDictionary* singleTexGen = texGenDict->AddSectionDictionary("SINGLE_TEXCOORDS_ASSIGN"); singleTexGen->SetIntValue(UV_SET_INDEX, mat.m_texStack->texInputs[i].uvSet); singleTexGen->SetValue(TEX_COORDS, coordsToken); TexMapInput inputMapping = mat.m_texStack->texInputs[i].mapping; if (inputMapping != TexMapInput_UV) { if (!texGenDeclIncluded) { ctemplate::TemplateDictionary* texGenDecl = vertexShaderDict.AddIncludeDictionary( "TEX_COORDS_GEN_DECL"); texGenDecl->SetFilename("shader_templates/ft_tex_coords_gen_decl.tpl"); texGenDeclIncluded = true; } switch (inputMapping) { case TexMapInput_Normal: singleTexGen->ShowSection("NORMAL_TEXGEN"); break; case TexMapInput_Refl: singleTexGen->ShowSection("REFLECTION_TEXGEN"); break; case TexMapInput_Spherical: singleTexGen->ShowSection("SPHERE_TEXGEN"); break; case TexMapInput_EyeSpace: singleTexGen->ShowSection("EYE_TEXGEN"); break; case TexMapInput_ObjectSpace: singleTexGen->ShowSection("OBJECT_TEXGEN"); break; case TexMapInput_Cube: singleTexGen->ShowSection("CUBE_TEXGEN"); break; default: SAFE_THROW(GLException(E_NOTIMPL, "Unimplemented texture mapping mode")) } } else { singleTexGen->ShowSection("UV_MAPPING"); } ++activeTextures; } }
void GLProgram::build( const char* vertsrc, const char* fragsrc, const char* geomsrc ) { GLuint vs = 0, fs = 0, gs = 0; GLint status = GL_TRUE; GLint loglen; std::string logbuf; if( !vertsrc || !fragsrc ) throw GLException( "Verter/Fragment shader source missing!\n" ); vs = glCreateShader( GL_VERTEX_SHADER ); if( !vs ) throw GLException("Vertex-Shader creation failed!\n"); glShaderSource( vs, 1, &vertsrc, NULL ); glCompileShader( vs ); glGetShaderiv( vs, GL_COMPILE_STATUS, &status ); if( status == GL_FALSE ) { glGetShaderiv( vs, GL_INFO_LOG_LENGTH, &loglen ); logbuf.resize( loglen ); glGetShaderInfoLog( vs, loglen, &loglen, &logbuf[ 0 ] ); glDeleteShader(vs); throw GLException("Vertex-Shader compilation error\n", logbuf ); } fs = glCreateShader( GL_FRAGMENT_SHADER ); if( !fs ) { glDeleteShader( vs ); throw GLException("Fragment-Shader creation failed!\n"); } glShaderSource( fs, 1, &fragsrc, NULL ); glCompileShader( fs ); glGetShaderiv( fs, GL_COMPILE_STATUS, &status ); if( status == GL_FALSE ) { glGetShaderiv( fs, GL_INFO_LOG_LENGTH, &loglen ); logbuf.resize( loglen ); glGetShaderInfoLog( fs, loglen, &loglen, &logbuf[ 0 ] ); glDeleteShader(fs); glDeleteShader(vs); throw GLException("Fragment-Shader compilation error\n", logbuf ); } if( geomsrc ) { gs = glCreateShader( GL_GEOMETRY_SHADER ); if( !gs ) { glDeleteShader( vs ); throw GLException("Geometry-Shader creation failed!\n"); } glShaderSource( gs, 1, &geomsrc, NULL ); glCompileShader( gs ); glGetShaderiv( gs, GL_COMPILE_STATUS, &status ); if( status == GL_FALSE ) { glGetShaderiv( gs, GL_INFO_LOG_LENGTH, &loglen ); logbuf.resize( loglen ); glGetShaderInfoLog( gs, loglen, &loglen, &logbuf[ 0 ] ); glDeleteShader( fs ); glDeleteShader( vs ); glDeleteShader( gs ); throw GLException("Geometry-Shader compilation error\n", logbuf ); } } glAttachShader( program, fs ); glAttachShader( program, vs ); if( gs ) glAttachShader( program, gs ); /* shaders are now referenced by programm, delete them*/ glDeleteShader( vs ); glDeleteShader( fs ); if( gs ) glDeleteShader( gs ); glLinkProgram( program ); glGetProgramiv( program, GL_LINK_STATUS, &status ); if(status == GL_FALSE) { glGetProgramiv( program, GL_INFO_LOG_LENGTH, &loglen ); logbuf.resize( loglen ); glGetProgramInfoLog( program, loglen, &loglen, &logbuf[ 0 ] ); throw GLException("Shader link error\n", logbuf ); } }