/* 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 "SDL2/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; size_t State::state_logo_texture_id = 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 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_layer(const model::Material * material, const model::Layer *layer) { if (!material || !layer) { gl::color(math::Color(1.0f, 0.0f, 1.0f)); gl::specular(math::Color(1.0f, 0.0f, 1.0f)); return; } // material has the decal flag set if (material->has_flag(model::Material::FlagDecal)) { gl::enable(GL_POLYGON_OFFSET_FILL); gl::enable(GL_ALPHA_TEST); gl::polygonoffset(-1,-1); gl::alphafunc(GL_GEQUAL, 0.5f); } math::Color color(layer->color()); math::Color specular(layer->specular()); math::Color shine(layer->shininess()); // apply color generation rules switch (layer->rgbgen()) { case model::Layer::RGBGenIdentity: break; case model::Layer::RGBGenColor: break; case model::Layer::RGBGenEngine: // assign current engine color color.assign(state_color_engine); specular.assign(0.0f); break; case model::Layer::RGBGenPrimary: // assign current primary entity color color.assign(state_color_primary); specular.assign(state_color_primary); break; case model::Layer::RGBGenSecondary: // assign current secondry entity color color.assign(state_color_secondary); specular.assign(state_color_secondary); break; case model::Layer::RGBGenTertiary: // assign current tertiary entity color 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; } break; } // blend current color with layer color if ((layer->rgbgen() != model::Layer::RGBGenIdentity) && (layer->rgbgen() != model::Layer::RGBGenColor)) { color.r *= layer->color().r; color.g *= layer->color().g; color.b *= layer->color().b; specular.r *= layer->specular().r; specular.g *= layer->specular().g; specular.b *= layer->specular().b; } gl::color(color); gl::specular(specular); gl::shininess(shine); // lighted or fullbright if (state_power && layer->fullbright()) { gl::disable(GL_LIGHTING); } else if (state_power && (layer->rgbgen() == model::Layer::RGBGenEngine)) { gl::disable(GL_LIGHTING); } else { gl::enable(GL_LIGHTING); } // texture map if (layer->texmap() == model::Layer::TexMapImage) { // map a texture image Textures::bind(layer->texture_id()); gl::enable(GL_TEXTURE_2D); // texture coordinate generation if (layer->tcgen() == model::Layer::TCGenEnvironment) { 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 if (layer->texmap() == model::Layer::TexMapEnvironment) { // map the current skybox 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); } } // alpha blending switch(layer->blendfunc()) { case model::Layer::BlendFuncNone: gl::disable(GL_BLEND); break; case model::Layer::BlendFuncAdd: gl::blendfunc(GL_ONE, GL_ONE); gl::enable(GL_BLEND); break; case model::Layer::BlendFuncBlend: gl::enable(GL_BLEND); break; } } void State::reset() { gl::blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl::enable(GL_BLEND); 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(math::Color(1.0f)); gl::specular(math::Color(0.0f)); } } // namespace render