/* 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; 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 bufer objects "; if (state_has_vbo) con_print << "enabled" << std::endl; else con_print << "disabled" << std::endl; // 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 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); // color tracking glColorMaterial(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; reset(); // material settings glMateriali(GL_FRONT, GL_SHININESS, 8); GLfloat specular_reflectance[3]; if (!material) { color.assign(1.0f, 0.0f, 1.0f); gl::color(color); return; } // Decal macro if (material->flags() & model::Material::Decal) { gl::enable(GL_POLYGON_OFFSET_FILL); gl::enable(GL_ALPHA_TEST); glPolygonOffset(-1,-1); glAlphaFunc(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); } 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; } else if ((material->flags() & model::Material::Secondary) == model::Material::Secondary) { color.assign(state_color_secondary); } else if ((material->flags() & model::Material::Primary) == model::Material::Primary) { color.assign(state_color_primary); } color.r *= material->color().r; color.g *= material->color().g; color.b *= material->color().b; } else { // use material color color.assign(material->color()); } // 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::texgeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); gl::texgeni(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); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); glTexGeni(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); } specular_reflectance[0] = 1.0f; specular_reflectance[1] = 1.0f; specular_reflectance[2] = 1.0f; glMateriali(GL_FRONT, GL_SHININESS, 4); glMaterialfv(GL_FRONT, GL_SPECULAR, specular_reflectance); gl::color(color); return; } } specular_reflectance[0] = color.r; specular_reflectance[1] = color.g; specular_reflectance[2] = color.b; glMaterialfv(GL_FRONT, GL_SPECULAR, specular_reflectance); gl::color(color); } 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