/* render/state.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include #include #include "SDL/SDL.h" #include "render/state.h" #include "render/gl.h" #include "render/render.h" namespace render { int State::state_width = 0; int State::state_height = 0; float State::state_aspect = 0; bool State::state_has_generate_mipmaps = false; bool State::state_has_vbo = false; GLuint State::state_vbo = 0; int State::state_maxlights; int State::state_maxtextureunits; math::Color State::state_color_primary; math::Color State::state_color_secondary; math::Color State::state_color_engine; bool State::state_power = true; void State::init(int width, int height) { resize(width, height); state_has_generate_mipmaps = false; std::string version(gl::version()); for (size_t i = 0; i < version.size(); i++) { if (version[i] == '.') version[i] = ' '; } std::stringstream versionstream(version); int major, minor; if (versionstream >> major >> minor) { if (major > 1) { state_has_generate_mipmaps = true; } else if (major == 1) { if (minor > 3) state_has_generate_mipmaps = true; } } else { con_warn << "Could not determine OpenGL version!" << std::endl; } con_print << " hardware generated mipmaps "; if (state_has_generate_mipmaps) con_print << "available" << std::endl; else con_print << "not available" << std::endl; // initialize gl functions state_has_vbo = true; gl::genbuffers = (gl::genbuffers_func) SDL_GL_GetProcAddress("glGenBuffers"); if (!gl::genbuffers) { con_debug << " glGenBuffers not available" << std::endl; state_has_vbo = false; } gl::deletebuffers = (gl::deletebuffers_func) SDL_GL_GetProcAddress("glDeleteBuffers"); if (!gl::deletebuffers) { con_debug << " glDeleteBuffers not available" << std::endl; state_has_vbo = false; } gl::bindbuffer = (gl::bindbuffer_func) SDL_GL_GetProcAddress("glBindBuffer"); if (!gl::bindbuffer) { con_debug << " glBindBuffer not available" << std::endl; state_has_vbo = false; } gl::bufferdata = (gl::bufferdata_func) SDL_GL_GetProcAddress("glBufferData"); if (!gl::bufferdata) { con_debug << " glBufferData not available" << std::endl; state_has_vbo = false; } con_print << " vertex buffer objects "; if (state_has_vbo) con_print << "enabled" << std::endl; else con_print << "disabled" << std::endl; // probe maximal number of lights gl::getinteger(GL_MAX_LIGHTS, &state_maxlights); con_debug << " maximum number of OpenGL lights is " << state_maxlights << std::endl; // probe maximal number of texture units gl::getinteger(GL_MAX_TEXTURE_UNITS, &state_maxtextureunits); con_debug << " maximum number of OpenGL texture units is " << state_maxtextureunits << std::endl; // bind multitexture functions gl::activetexture = (gl::activetexture_func) SDL_GL_GetProcAddress("glActiveTexture"); gl::clientactivetexture = (gl::activetexture_func) SDL_GL_GetProcAddress("glClientActiveTexture"); // Generate VBO if (state_has_vbo) gl::genbuffers(1, &state_vbo); } void State::shutdown() { // Delete VBO if (state_has_vbo) gl::deletebuffers(1, &state_vbo); } void State::resize(int width, int height) { state_width = width; state_height = height; state_aspect = (float) width / (float) height; clear(); } void State::clear() { // set viewport gl::viewport(0, 0, state_width, state_height); // set clear color gl::clearcolor(0.0f, 0.0f, 0.0f, 1.0f); // load identity matrices gl::matrixmode(GL_PROJECTION); gl::loadidentity(); gl::matrixmode(GL_MODELVIEW); gl::loadidentity(); // shading model: Gouraud (smooth, the default) gl::shademodel(GL_SMOOTH); //gl::shademodel(GL_FLAT); // lighting model gl::lightmodel(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); gl::lightmodel(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); // color tracking gl::colormaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // alpha blending function gl::blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl::disable(GL_LIGHTING); gl::disable(GL_COLOR_MATERIAL); gl::cullface(GL_BACK); gl::frontface(GL_CCW); gl::disable(GL_CULL_FACE); gl::disable(GL_DEPTH_TEST); gl::disable(GL_BLEND); gl::disable(GL_TEXTURE_2D); } void State::set_normalize(const bool enable) { if (r_normalize && r_normalize->value()) { // enable full normalization if(enable) { gl::enable(GL_NORMALIZE); } else { gl::disable(GL_NORMALIZE); } } else { // enable rescaling of normals if(enable) { gl::enable(GL_RESCALE_NORMAL); } else { gl::disable(GL_RESCALE_NORMAL); } } } void State::set_color(const math::Color & color) { state_color_primary.assign(color); } void State::set_color_second(const math::Color & color) { state_color_secondary.assign(color); } void State::set_color_engine(const math::Color & color) { state_color_engine.assign(color); } void State::set_color(const core::Entity *entity) { state_color_primary.assign(entity->color()); state_color_secondary.assign(entity->color_second()); } void State::set_power(const bool power) { state_power = power; } void State::use_material(const model::Material * material) { math::Color color; math::Color specular; reset(); // default specular shininess setting gl::material(GL_FRONT, GL_SHININESS, 8); if (!material) { color.assign(1.0f, 0.0f, 1.0f); specular.assign(1.0f, 0.0f, 1.0f); gl::color(color); gl::specular(specular); return; } // material has the decal flag set if (material->flags() & model::Material::Decal) { gl::enable(GL_POLYGON_OFFSET_FILL); gl::enable(GL_ALPHA_TEST); gl::polygonoffset(-1,-1); gl::alphafunc(GL_GEQUAL, 0.5f); } // assign the opengl drawing color according to material flags if (material->flags() & model::Material::Engine) { // use current engine color color.assign(state_color_engine); specular.assign(0.0f); } else if (material->flags() & model::Material::Tertiary) { // use entity colors if ((material->flags() & model::Material::Tertiary) == model::Material::Tertiary) { for (size_t i = 0; i < 3; i++) { color[i] = (state_color_primary[i] + state_color_secondary[i]) / 2; specular[i] = (state_color_primary[i] + state_color_secondary[i]) / 2; } } else if ((material->flags() & model::Material::Secondary) == model::Material::Secondary) { color.assign(state_color_secondary); specular.assign(state_color_secondary); } else if ((material->flags() & model::Material::Primary) == model::Material::Primary) { color.assign(state_color_primary); specular.assign(state_color_primary); } color.r *= material->color().r; color.g *= material->color().g; color.b *= material->color().b; specular.r *= material->specular().r; specular.g *= material->specular().g; specular.b *= material->specular().b; } else { // use material color color.assign(material->color()); specular.assign(material->specular()); } // lighted or fullbright if (state_power && (material->flags() & model::Material::Bright)) { gl::disable(GL_LIGHTING); } else if (state_power && (material->flags() & model::Material::Engine)) { gl::disable(GL_LIGHTING); } else { gl::enable(GL_LIGHTING); } // texture if (material->flags() & model::Material::Texture) { Textures::bind(material->texture_id()); gl::enable(GL_TEXTURE_2D); if (material->flags() & model::Material::Environment) { gl::texgen(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); gl::texgen(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); gl::enable(GL_TEXTURE_GEN_S); gl::enable(GL_TEXTURE_GEN_T); } } else { // envmapped without texture: use the skybox as envmap if (material->flags() & model::Material::Environment) { if (core::localplayer()->zone()->sky().size()) { gl::enable(GL_TEXTURE_CUBE_MAP); gl::texgen(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); gl::texgen(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); gl::texgen(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); gl::enable(GL_TEXTURE_GEN_S); gl::enable(GL_TEXTURE_GEN_T); gl::enable(GL_TEXTURE_GEN_R); } else { color.assign(0.0f, 0.0f, 0.0f); } gl::material(GL_FRONT, GL_SHININESS, 4); } } gl::color(color); gl::specular(specular); } void State::reset() { gl::disable(GL_POLYGON_OFFSET_FILL); gl::disable(GL_ALPHA_TEST); gl::disable(GL_TEXTURE_GEN_S); gl::disable(GL_TEXTURE_GEN_T); gl::disable(GL_TEXTURE_GEN_R); gl::disable(GL_LIGHTING); gl::disable(GL_TEXTURE_CUBE_MAP); gl::disable(GL_TEXTURE_2D); gl::color(1.0f, 1.0f, 1.0f, 1.0f); } } // namespace render