/* ui/modelview.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "auxiliary/functions.h" #include "core/application.h" #include "ui/modelview.h" #include "ui/paint.h" #include "ui/ui.h" #include "sys/sys.h" #include "render/camera.h" #include "render/draw.h" #include "render/light.h" #include "render/lightenvironment.h" #include "render/render.h" #include #include namespace ui { const float LIGHT_DISTANCE = -10.0f; const float LIGHT_ATTENUATION = 1.5f; ModelView::ModelView(Widget *parent) : Widget(parent) { set_border(false); set_background(false); set_label("modelview"); modelview_radius = 0.75f; modelview_zoom = 1.0f; modelview_dragging = false; modelview_axis.clear(); modelview_axis.change_direction(180); modelview_axis.change_pitch(-15); modelview_mode = Model; } ModelView::~ModelView() {} void ModelView::print(const size_t indent) const { std::string marker(""); con_print << aux::pad_left(marker, indent*2) << label() << " \"" << modelname() << "\"" << std::endl; } void ModelView::reset() { set_background(false); modelview_axis.clear(); modelview_axis.change_direction(180); modelview_axis.change_pitch(-15); modelview_zoom = 1.0f; modelview_modelname.clear(); modelview_globetexturename.clear(); modelview_globecoronaname.clear(); modelview_globeringsname.clear(); modelview_globebright = false; } void ModelView::clear() { reset(); modelview_mode = Model; } void ModelView::set_globetexturename(const std::string & texturename, const std::string & coronaname, const std::string ringsname, const bool bright) { reset(); modelview_globetexturename.assign(texturename); modelview_globecoronaname.assign(coronaname); modelview_globeringsname.assign(ringsname); modelview_globebright = bright; } void ModelView::set_modelname(const std::string & modelname) { reset(); modelview_modelname.assign(modelname); } void ModelView::set_colors(const math::Color & color_primary, const math::Color & color_secondary) { modelview_color_primary.assign(color_primary); modelview_color_secondary.assign(color_secondary); } void ModelView::set_zoom(const float zoom) { modelview_zoom = zoom; math::clamp(modelview_zoom, 1.0f, 5.0f); } bool ModelView::on_mousewheel(const math::Vector2f & direction) { if (direction.y() > 0 ) { modelview_zoom -= 0.25f; if (modelview_zoom < 1.0f) modelview_zoom = 1.0f; return true; } else if (direction.y() < 0 ) { modelview_zoom += 0.25f; if (modelview_zoom > 5.0f) modelview_zoom = 5.0f; return true; } return false; } bool ModelView::on_mousepress(const unsigned int button) { if (button == SDL_BUTTON_LEFT) { modelview_dragging = true; return true; } return false; } bool ModelView::on_mouserelease(const unsigned int button) { if (button == SDL_BUTTON_LEFT) { modelview_dragging = false; return true; } return false; } void ModelView::on_mousemove(const math::Vector2f &cursor) { if ((width() <= 0) || (height() <= 0)) { return; } if (modelview_dragging) { const math::Vector2f pos(cursor - modelview_cursor); const math::Vector3f up(0.0f, 0.0f, 1.0f); const float zrot = 2.0f * M_PI * pos.x() / width(); modelview_axis.rotate(up, -zrot); const math::Vector3f left(0.0f, 1.0f, 0.0f); const float yrot = 2.0f * M_PI * pos.y() / height(); modelview_axis.rotate(left, yrot); modelview_cursor.assign(cursor); } modelview_cursor.assign(cursor); } void ModelView::on_mouseover(const math::Vector2f &cursor) { modelview_cursor.assign(cursor); modelview_dragging = false; } void ModelView::draw_background() { Paint::set_color(1.0f, 1.0f, 1.0f); Paint::draw_bitmap(global_location(), size(), "textures/common/notex"); } void ModelView::draw() { if (!core::application()->connected() || !core::game()->time()) { return; } switch (mode()) { case Model: draw_model(); break; case Globe: draw_globe(); break; } } void ModelView::draw_globe() { math::Vector2f center(global_location() + size() * 0.5f); const float minscreen(math::min(root()->width(),root()->height())); const float minwidget(math::min(width(), height())); const float reference_radius = radius() * minwidget / minscreen; // gl 3d mode render::Camera::frustum_default(modelview_zoom, center.x(), center.y()); // set up light environment render::Light *light = new render::Light( math::Vector3f(LIGHT_DISTANCE * reference_radius, 0, 0), math::Color(0.5f, 0.5f, 0.5f) ); light->set_attenuation(LIGHT_ATTENUATION, 0.0f, 0.0f); render::LightEnvironment lightenv; lightenv.add(light); lightenv.enable(); lightenv.draw(); // enable lighting gl::enable(GL_LIGHTING); gl::disable(GL_BLEND); gl::depthmask(GL_TRUE); // enable writing to the depth buffer gl::enable(GL_DEPTH_TEST); // enable depth test gl::enable(GL_CULL_FACE); // enable culling gl::enable(GL_COLOR_MATERIAL); // enable color tracking // clear depth buffer gl::clear(GL_DEPTH_BUFFER_BIT); // enable vertex arrays glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); render::State::set_normalize(true); // push transformation matrix to stack gl::push(); if (modelview_globebright) { gl::disable(GL_LIGHTING); if (modelview_globecoronaname.size()) { size_t corona_id = render::Textures::load("textures/" + modelview_globecoronaname); render::draw_globe_corona(math::Vector3f(0.0f, 0.0f, 0.0f), modelview_color_primary, reference_radius, corona_id); } } gl::multmatrix(modelview_axis); if (modelview_globetexturename.size()) { // textured globe render::Textures::bind("textures/" + modelview_globetexturename); gl::enable(GL_TEXTURE_2D); } render::draw_sphere(modelview_color_primary, reference_radius); if (modelview_globeringsname.size()) { size_t rings_id = render::Textures::load("textures/" + modelview_globeringsname); if (!modelview_globetexturename.size()) { gl::enable(GL_TEXTURE_2D); } render::draw_globe_rings(modelview_color_primary, rings_id); } gl::pop(); render::State::set_normalize(false); lightenv.disable(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); gl::enable(GL_BLEND); gl::disable(GL_TEXTURE_2D); gl::disable(GL_COLOR_MATERIAL); // disable color tracking gl::disable(GL_CULL_FACE); // disable culling gl::depthmask(GL_FALSE); // enable depth buffer writing gl::disable(GL_DEPTH_TEST); // disable depth buffer testing gl::disable(GL_LIGHTING); // gl 2d mode render::Camera::ortho(); } void ModelView::draw_model() { if (!modelview_modelname.size()) { return; } Paint::set_color(1.0f, 1.0f, 1.0f); model::Model *model = model::Model::load(modelview_modelname); if (!model) { modelview_modelname.clear(); set_background(true); return; } math::Vector2f center(global_location() + size() * 0.5f); const float minscreen(math::min(root()->width(),root()->height())); const float minwidget(math::min(width(), height())); const float reference_radius = radius() * minwidget / minscreen; const float modelscale = reference_radius / model->radius(); // gl 3d mode render::Camera::frustum_default(modelview_zoom, center.x(), center.y()); // set up light environment render::Light *light = new render::Light( math::Vector3f(LIGHT_DISTANCE * reference_radius, 0, 0), math::Color(0.5f, 0.5f, 0.5f) ); light->set_attenuation(LIGHT_ATTENUATION, 0.0f, 0.0f); render::LightEnvironment lightenv; lightenv.add(light); lightenv.enable(); lightenv.draw(); // enable lighting gl::enable(GL_LIGHTING); gl::disable(GL_BLEND); gl::depthmask(GL_TRUE); // enable writing to the depth buffer gl::enable(GL_DEPTH_TEST); // enable depth test gl::enable(GL_CULL_FACE); // enable culling gl::enable(GL_COLOR_MATERIAL); // enable color tracking // clear depth buffer gl::clear(GL_DEPTH_BUFFER_BIT); // enable vertex arrays glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); // push transformation matrix to stack gl::push(); gl::multmatrix(modelview_axis); gl::scale(modelscale, modelscale, modelscale); render::State::set_normalize(true); // FIXME the inventory window needs to be able to use actual thrust values float thrust = ::sinf(core::application()->time() * 0.5f); if (thrust < 0.0f ) { thrust = 1.0f + thrust; } else { thrust = 1.0f; } render::draw_model_fragments(model, modelview_color_primary, modelview_color_secondary, core::application()->time(), true, true, thrust); render::State::set_normalize(false); gl::pop(); lightenv.disable(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); gl::disable(GL_LIGHTING); gl::enable(GL_TEXTURE_2D); gl::enable(GL_BLEND); gl::depthmask(GL_FALSE); // disable depth buffer writing // load model light textures for (model::Model::Lights::iterator lit = model->lights().begin(); lit != model->lights().end(); lit++) { model::Light *light = (*lit); // load light texture std::stringstream texturename; texturename << "textures/fx/flare" << std::setfill('0') << std::setw(2) << light->flare(); light->set_texture(render::Textures::load(texturename.str())); } for (model::Model::Flares::iterator flit = model->flares().begin(); flit != model->flares().end(); flit++) { model::Flare *flare = (*flit); // load flare texture std::stringstream texturename; texturename << "textures/fx/flare" << std::setfill('0') << std::setw(2) << flare->flare(); flare->set_texture(render::Textures::load(texturename.str())); } render::draw_model_lights(model, modelscale, math::Vector3f(), modelview_axis, core::localplayer()->color(), core::localplayer()->color_second(), thrust, 0.0f); gl::disable(GL_TEXTURE_2D); gl::disable(GL_COLOR_MATERIAL); // disable color tracking gl::disable(GL_CULL_FACE); // disable culling gl::depthmask(GL_FALSE); // enable depth buffer writing gl::disable(GL_DEPTH_TEST); // disable depth buffer testing // gl 2d mode render::Camera::ortho(); } void ModelView::draw_border() { Paint::set_color(palette()->foreground()); Paint::draw_border(global_location(), size()); } }