/* render/draw.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include #include #include "core/core.h" #include "core/range.h" #include "model/fragment.h" #include "model/material.h" #include "model/model.h" #include "render/render.h" #include "render/textures.h" #include "render/draw.h" #include "render/dust.h" #include "render/gl.h" namespace render { size_t Stats::tris = 0; size_t Stats::quads = 0; void Stats::clear() { tris = 0; quads = 0; } math::Vector3f v0(1, -1, 1); math::Vector3f v1(1, 1, 1); math::Vector3f v2(-1, 1, 1); math::Vector3f v3(-1, -1, 1); math::Vector3f v4(1, -1, -1); math::Vector3f v5(1, 1, -1); math::Vector3f v6(-1, 1, -1); math::Vector3f v7(-1, -1, -1); const float drawdistance = 256.0f; const float drawfxdistance = 64.0f; const float farplane = 1016.0f; core::Zone *zone = 0; float zone_light[4]; // locaton of the zone light math::Color zone_color; // color of the zone light bool has_zone_light = false; typedef std::map Globes; Globes globes_list; // function to test flags inline bool flag_is_set(unsigned int const spawnflags, unsigned int const flag) { return ((spawnflags & flag) == flag); } /* ---- Prepare the renderer state --------------------------------- */ void pass_prepare(float seconds) { using namespace model; // reset light state gl::disable(GL_LIGHT1); has_zone_light = false; zone_color.assign(1.0); // clear current list of globes globes_list.clear(); for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { core::Entity *entity = (*it); // load entity models and light flare textures if (!entity->model() && entity->modelname().size()) { entity->entity_model = Model::load(entity->modelname()); if (!entity->model()) { entity->entity_modelname.clear(); entity->entity_radius = 0.25; } else { // set entity radius to model radius entity->entity_radius = entity->entity_model->radius(); for (Model::Lights::iterator lit = entity->model()->lights().begin(); lit != entity->model()->lights().end(); lit++) { Light *light = (*lit); // load light texture std::stringstream flarename; flarename << "bitmaps/fx/flare" << std::setfill('0') << std::setw(2) << light->flare(); light->render_texture = Textures::load(flarename.str()); } for(Model::Engines::iterator eit = entity->model()->engines().begin(); eit != entity->model()->engines().end(); eit++) { Engine *engine = (*eit); if (!engine->flare()) engine->engine_flare = 1; // load engine texture std::stringstream flarename; flarename << "bitmaps/fx/flare" << std::setfill('0') << std::setw(2) << engine->flare(); engine->render_texture = Textures::load(flarename.str()); } for (Model::Flares::iterator flit = entity->model()->flares().begin(); flit != entity->model()->flares().end(); flit++) { Flare *flare = (*flit); // load flare texture std::stringstream flarename; flarename << "bitmaps/fx/flare" << std::setfill('0') << std::setw(2) << flare->flare(); flare->render_texture = Textures::load(flarename.str()); } } } if (!entity->state()) { entity->entity_clientstate = new core::ClientState(entity); } entity->state()->state_visible = false; entity->state()->state_detailvisible = false; entity->state()->state_targetable = false; entity->state()->state_distance = math::distance(Camera::eye(), entity->state()->location()); // calculate visibility for entities with models if (entity->model()) { float r = entity->model()->radius(); math::clamp(r, 1.0f, farplane / drawfxdistance); if (entity->state()->distance() < drawfxdistance * r) { // entites within detail range entity->state()->state_visible = true; entity->state()->state_detailvisible = true; } else if (entity->state()->distance() < drawdistance * r && entity->state()->distance() < core::range::max) { // entities within drawing distance, outside detail range entity->state()->state_visible = true; entity->state()->state_detailvisible = false; } } else { entity->state()->state_visible = true; if (entity->type() == core::Entity::Globe) { core::EntityGlobe *globe = static_cast(entity); // add the globe to the globes list globes_list[globe->state()->distance()] = globe; // load globe textures if (!globe->render_texture && globe->texture().size()) { std::stringstream texname; texname << "textures/" << globe->texture(); globe->render_texture = Textures::load(texname.str()); if (!globe->render_texture) globe->entity_texture.clear(); } if (flag_is_set(globe->flags(), core::Entity::Bright)) { // bright globes set level light GLfloat diffuse_light[4]; GLfloat ambient_light[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat specular_light[] = { 0.2f, 0.2f, 0.2f, 1.0f }; for (size_t i=0; i <3; i++) { zone_light[i] = globe->location()[i]; zone_color[i] = globe->color()[i]; diffuse_light[i] = globe->color()[i] * 0.4; } zone_light[3] = 1.0f; diffuse_light[3] = 1.0f; glLightfv(GL_LIGHT1, GL_POSITION, zone_light); glLightfv(GL_LIGHT1, GL_AMBIENT, ambient_light); glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse_light); glLightfv(GL_LIGHT1, GL_SPECULAR, specular_light); gl::enable(GL_LIGHT1); has_zone_light = true; } } } } } /* ----- Skybox ---------------------------------------------------- */ void draw_sphere_inside(math::Color const & color, float radius) { gl::scale(radius, radius, radius); gl::color(color); size_t index = (model::SPHERESEGMENTS) * (model::SPHERESEGMENTS-1); size_t count = (model::SPHERESEGMENTS)*2; // draw body for (int j=0; j < (model::SPHERESEGMENTS-1)/2; j++) { glDrawArrays(gl::QuadStrip, index, count); index += count; Stats::quads += count/2-1; } } void draw_pass_sky() { if (!(r_sky && r_sky->value())) return; if (!core::localplayer()->zone()) return; if (!core::localplayer()->zone()->sky().size()) return; if (!core::localplayer()->zone()->sky_texture()) { std::string texture_name("textures/env/"); texture_name.append(core::localplayer()->zone()->sky()); core::localplayer()->zone()->set_sky_texture(Textures::load(texture_name)); if (!core::localplayer()->zone()->sky_texture()) { core::localplayer()->zone()->set_sky(""); return; } } Textures::bind(core::localplayer()->zone()->sky_texture()); gl::enable(GL_TEXTURE_2D); gl::push(); gl::translate(Camera::eye()); draw_sphere_inside(math::Color(), 1016.0f); gl::pop(); gl::disable(GL_TEXTURE_2D); } /* ---- Globes ----------------------------------------------------- */ void draw_sphere(math::Color const & color, float radius) { gl::scale(radius, radius, radius); gl::color(color); size_t index = 0; size_t count = (model::SPHERESEGMENTS)*2; // draw body for (int j=0; j < (model::SPHERESEGMENTS-1)/2; j++) { glDrawArrays(gl::QuadStrip, index, count); index += count; Stats::quads += count/2-1; } } void draw_globe(core::EntityGlobe *globe) { /* Globes have to be rendered distance sorted, closest last. Globes behind farplane should be rendered with z-buffer writes disabled. */ math::Vector3f location(globe->state()->location()); float radius = globe->radius(); if(flag_is_set(globe->flags(), core::Entity::Bright)) { // bright globe, render fullbright gl::disable(GL_LIGHTING); } else { // disable camera light, level light only gl::disable(GL_LIGHT0); } if (globe->render_texture) { // textured globe Textures::bind(globe->render_texture); gl::enable(GL_TEXTURE_2D); } if (globe->state()->distance() > farplane) { // globe is behind the far plane, make a fake size calculation location = Camera::eye() + (location - Camera::eye()) * (farplane / globe->state()->distance()); radius *= farplane / globe->state()->distance(); gl::depthmask(GL_FALSE); if (has_zone_light) { // move zone light float fake_light[4]; for (size_t i=0; i < 3; i++) { fake_light[i] = zone_light[i] + location[i] - globe->state()->location()[i]; } fake_light[3] = 1.0f; glLightfv(GL_LIGHT1, GL_POSITION, fake_light); } } gl::push(); gl::translate(location); gl::multmatrix(globe->state()->axis()); if (globe->rotationspeed()) { float angle = core::application()->time() * globe->rotationspeed(); angle = angle - 360.0f * floorf(angle / 360.0f); gl::rotate(angle, math::Vector3f::Zaxis()); } draw_sphere(globe->color(), radius); gl::pop(); if (globe->state()->distance() > farplane) { gl::depthmask(GL_TRUE); if (has_zone_light) { // restore zone light glLightfv(GL_LIGHT1, GL_POSITION, zone_light); } } if (flag_is_set(globe->flags(), core::Entity::Bright)) { gl::enable(GL_LIGHTING); } else { gl::enable(GL_LIGHT0); } if (globe->render_texture) { gl::disable(GL_TEXTURE_2D); } } void draw_pass_globes() { // draw globes first, closest last for (Globes::reverse_iterator rit = globes_list.rbegin(); rit != globes_list.rend(); rit++) { draw_globe((*rit).second); } } /* ---- Default entities ------------------------------------------ */ void draw_entity_sphere(core::Entity *entity) { draw_sphere(entity->color(), entity->radius()); } void draw_entity_cube(core::Entity *entity) { float radius = entity->radius(); gl::scale(radius, radius, radius); gl::color(entity->color()); gl::begin(gl::Quads); // top gl::normal(0,0,1); gl::vertex(v0); gl::vertex(v1); gl::vertex(v2); gl::vertex(v3); // bottom gl::normal(0,0, -1); gl::vertex(v7); gl::vertex(v6); gl::vertex(v5); gl::vertex(v4); // sides gl::normal(1,0,0); gl::vertex(v1); gl::vertex(v0); gl::vertex(v4); gl::vertex(v5); gl::normal(-1,0,0); gl::vertex(v3); gl::vertex(v2); gl::vertex(v6); gl::vertex(v7); gl::normal(0,1,0); gl::vertex(v2); gl::vertex(v1); gl::vertex(v5); gl::vertex(v6); gl::normal(0,-1,0); gl::vertex(v0); gl::vertex(v3); gl::vertex(v7); gl::vertex(v4); gl::end(); } void draw_entity_diamond(core::Entity *entity) { float radius = entity->radius()/2; /* ---- draw axis lines ---- */ gl::color(entity->color_second()); gl::begin(gl::Lines); gl::vertex(1.25f * radius, 0, 0); gl::vertex(2* radius, 0, 0); gl::vertex(0, 1.25f * radius, 0); gl::vertex(0, 2* radius, 0); gl::vertex(0, 0, 1.25f * radius); gl::vertex(0, 0, 2 * radius); gl::vertex(-1.25f * radius, 0, 0); gl::vertex(-2 * radius, 0, 0); gl::vertex(0, -1.25f * radius, 0); gl::vertex(0, -2 * radius, 0); gl::vertex(0, 0, -1.25f * radius); gl::vertex(0, 0, -2 * radius); gl::end(); /* ---- draw rotating body lines ---- */ float angle = (core::application()->time() + entity->state()->fuzz() ) * 45.0f; angle = angle - 360.0f * floorf(angle / 360.0f); gl::rotate(angle, math::Vector3f::Zaxis()); if (r_wireframe->value() == 0.0f) { glPolygonMode(GL_FRONT, GL_LINE); } gl::color(entity->color()); gl::begin(gl::TriangleFan ); gl::normal(0, 0 , 1); gl::vertex(0, 0, radius); gl::normal(1, 0 ,0); gl::vertex(radius, 0.0f, 0.0f); gl::normal(0, 1, 0); gl::vertex(0.0f, radius, 0.0f); gl::normal(-1, 0 ,0); gl::vertex(-radius, 0.0f, 0.0f); gl::normal(0, -1, 0); gl::vertex(0.0f, -radius, 0.0f); gl::normal(1, 0 ,0); gl::vertex(radius, 0.0f, 0.0f); gl::end(); gl::begin(gl::TriangleFan); gl::normal(0, 0 , -1); gl::vertex(0, 0, -radius); gl::normal(1, 0, 0); gl::vertex(radius, 0.0f, 0.0f); gl::normal(0, -1, 0); gl::vertex(0.0f, -radius, 0.0f); gl::normal(-1, 0 ,0); gl::vertex(-radius, 0.0f, 0.0f); gl::normal(0, 1, 0); gl::vertex(0.0f, radius, 0.0f); gl::normal(1, 0 ,0); gl::vertex(radius, 0.0f, 0.0f); gl::end(); if (r_wireframe->value() == 0.0f) { glPolygonMode(GL_FRONT, GL_FILL); } } void draw_entity_axis(core::Entity *entity) { float r = entity->radius(); gl::begin(gl::Lines); gl::color(entity->color_second()); gl::vertex(r,0.0f,0.0f); gl::color(entity->color()); gl::vertex(-r,0.0f,0.0f); gl::vertex(0.0f,r/2,0.0f); gl::vertex(0.0f,-r/2,0.0f); gl::vertex(0.0f,0.0f,r); gl::vertex(0.0f,0.0f,-r); gl::end(); } void draw_pass_default() { for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); ++it) { core::Entity *entity = (*it); if (!entity->serverside() && !entity->model() && (entity->type() != core::Entity::Globe)) { gl::push(); gl::translate(entity->state()->location()); gl::multmatrix(entity->state()->axis()); if (flag_is_set(entity->flags(), core::Entity::Bright)) { gl::disable(GL_LIGHTING); } switch(entity->shape()) { case core::Entity::Sphere: draw_entity_sphere(entity); break; case core::Entity::Diamond: draw_entity_diamond(entity); break; case core::Entity::Axis: draw_entity_axis(entity); break; case core::Entity::Cube: default: draw_entity_cube(entity); break; } if (flag_is_set(entity->flags(), core::Entity::Bright)) { gl::enable(GL_LIGHTING); } gl::pop(); } } } /* ---- Model Fragments -------------------------------------------- */ void draw_fragment(model::Fragment *fragment, bool draw_details) { size_t index = fragment->index(); size_t vertex_count = fragment->structural_size(); if (draw_details) vertex_count += fragment->detail_size(); switch (fragment->type()) { case model::Fragment::Triangles: glDrawArrays(gl::Triangles, index, vertex_count); Stats::tris += vertex_count / 3; break; case model::Fragment::Quads: glDrawArrays(gl::Quads, index, vertex_count); Stats::quads += vertex_count / 4; break; } } void draw_model_fragments(core::Entity *entity) { using namespace model; Model *model = entity->model(); if (!model) return; // default material, lighted and geometry color unsigned int material = Material::None; bool use_color_array = true; // glEnableClientState(GL_COLOR_ARRAY) is set bool use_light = true; // gl::disable(GL_LIGHTING) is set bool power = true; float thrust = 0; if ((entity->type() == core::Entity::Dynamic) || (entity->type() == core::Entity::Controlable)) { if (static_cast(entity)->eventstate() == core::Entity::NoPower) { power = false; } else if (entity->type() == core::Entity::Controlable) { core::EntityControlable *ec = static_cast(entity); if ((ec->eventstate() == core::Entity::Impulse) || (ec->eventstate() == core::Entity::ImpulseInitiate)) { thrust = 1.0f; } else { thrust = ec->thrust(); } } } for (model::FragmentGroup::iterator fit = model->worldspawn().begin(); fit != model->worldspawn().end(); fit++) { Fragment *fragment = (*fit); if (fragment->material() != material) { material = fragment->material(); if (material & Material::Engine) { if (use_color_array) { glDisableClientState(GL_COLOR_ARRAY); use_color_array = false; } gl::color(model->enginecolor() * thrust); } else if (material & Material::Tertiary) { if (use_color_array) { use_color_array = false; glDisableClientState(GL_COLOR_ARRAY); } math::Color color; if ((material & Material::Tertiary) == Material::Tertiary) { for (size_t i = 0; i < 3; i++) color[i] = (entity->color()[i] + entity->color_second()[i]) / 2; } else if ((material & Material::Secondary) == Material::Secondary) { color.assign(entity->color_second()); } if ((material & Material::Primary) == Material::Primary) { color.assign(entity->color()); } if (material & Material::Dark) color *= 0.5f; gl::color(color); } else { if (!use_color_array) { glEnableClientState(GL_COLOR_ARRAY); use_color_array = true; } } if (power && (material & Material::Light)) { if (use_light) { gl::disable(GL_LIGHTING); use_light = false; } } else if (power && (material & Material::Engine)) { if (use_light) { gl::disable(GL_LIGHTING); use_light = false; } } else { if (!use_light) { gl::enable(GL_LIGHTING); use_light = true; } } } draw_fragment(fragment, entity->state()->detailvisible()); } if (!use_light) { gl::enable(GL_LIGHTING); } if (!use_color_array) { glEnableClientState(GL_COLOR_ARRAY); } } // draw bounding box void draw_model_bbox(model::Model *model) { // top gl::begin(gl::LineLoop); gl::vertex(model->model_maxbbox.x, model->model_maxbbox.y, model->model_maxbbox.z); gl::vertex(model->model_minbbox.x, model->model_maxbbox.y, model->model_maxbbox.z); gl::vertex(model->model_minbbox.x, model->model_minbbox.y, model->model_maxbbox.z); gl::vertex(model->model_maxbbox.x, model->model_minbbox.y, model->model_maxbbox.z); gl::end(); // bottom gl::begin(gl::LineLoop); gl::vertex(model->model_maxbbox.x, model->model_maxbbox.y, model->model_minbbox.z); gl::vertex(model->model_minbbox.x, model->model_maxbbox.y, model->model_minbbox.z); gl::vertex(model->model_minbbox.x, model->model_minbbox.y, model->model_minbbox.z); gl::vertex(model->model_maxbbox.x, model->model_minbbox.y, model->model_minbbox.z); gl::end(); gl::begin(gl::Lines); gl::vertex(model->model_maxbbox.x, model->model_maxbbox.y, model->model_maxbbox.z); gl::vertex(model->model_maxbbox.x, model->model_maxbbox.y, model->model_minbbox.z); gl::vertex(model->model_minbbox.x, model->model_maxbbox.y, model->model_maxbbox.z); gl::vertex(model->model_minbbox.x, model->model_maxbbox.y, model->model_minbbox.z); gl::vertex(model->model_minbbox.x, model->model_minbbox.y, model->model_maxbbox.z); gl::vertex(model->model_minbbox.x, model->model_minbbox.y, model->model_minbbox.z); gl::vertex(model->model_maxbbox.x, model->model_minbbox.y, model->model_maxbbox.z); gl::vertex(model->model_maxbbox.x, model->model_minbbox.y, model->model_minbbox.z); gl::end(); } void draw_pass_model_fragments() { for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { core::Entity *entity = (*it); if (entity->model() && entity->state()->visible()) { gl::push(); gl::translate(entity->state()->location()); gl::multmatrix(entity->state()->axis()); draw_model_fragments(entity); if (r_bbox->value()) { gl::color(entity->color()); draw_model_bbox(entity->model()); } gl::pop(); } } } /* ---- Model FX --------------------------------------------------- */ void draw_pass_model_fx(float elapsed) { const size_t count = 8; // number of engine trail particles float t = 0.0f; float u = 0.0f; float a = 0.0f; float light_size = 0.0f; float engine_size = 0.0f; float trail_size = 0.0f; bool power = true; math::Vector3f quad[4]; math::Vector3f location; math::Vector3f offset; math::Color color; model::Light *light; model::Flare *flare; model::Engine *engine; math::Axis flare_axis; size_t circle_texture = Textures::load("bitmaps/fx/circle01"); size_t current_texture = Textures::bind("bitmaps/fx/flare00"); gl::enable(GL_TEXTURE_2D); gl::begin(gl::Quads); for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { core::Entity *entity = (*it); power = true; if ((entity->type() == core::Entity::Dynamic) && (static_cast(entity)->eventstate() == core::Entity::NoPower)) { power = false; } else if ((entity->type() == core::Entity::Controlable) && (static_cast(entity)->eventstate() == core::Entity::NoPower)) { power = false; } if (entity->model() && entity->state()->detailvisible() && power) { // draw model lights for (model::Model::Lights::iterator lit = entity->model()->lights().begin(); lit != entity->model()->lights().end(); lit++) { light = (*lit); // strobe frequency t = 1.0f; if (light->strobe()) t = (core::application()->time() + entity->state()->fuzz() - light->offset()) * light->frequency(); if ((!light->strobe()) || (( t - floorf(t)) <= light->time())) { location.assign(entity->state()->location() + (entity->state()->axis() * light->location())); light_size = 0.0625 * light->radius(); if (current_texture != light->texture()) { gl::end(); current_texture = Textures::bind(light->texture()); gl::begin(gl::Quads); } if (light->entity()) { color.assign(entity->color()); } else { color.assign(light->color()); } color.a = 0.8; gl::color(color); glTexCoord2f(0,1); gl::vertex(location + (Camera::axis().up() - Camera::axis().left()) * light_size); glTexCoord2f(0,0); gl::vertex(location + (Camera::axis().up() + Camera::axis().left()) * light_size); glTexCoord2f(1,0); gl::vertex(location + (Camera::axis().up() * -1 + Camera::axis().left()) * light_size); glTexCoord2f(1,1); gl::vertex(location + (Camera::axis().up() * -1 - Camera::axis().left()) * light_size); Stats::quads++; } } // draw flares for (model::Model::Flares::iterator flit = entity->model()->flares().begin(); flit != entity->model()->flares().end(); flit++) { flare = (*flit); // strobe frequency t = 1.0f; if (flare->strobe()) t = (core::application()->time() + entity->state()->fuzz() - flare->offset()) * flare->frequency(); if ((!flare->strobe()) || (( t - floorf(t)) <= flare->time())) { flare_axis.assign(entity->state()->axis()); if (flare->angle()) flare_axis.change_direction(flare->angle()); location.assign(entity->state()->location() + (entity->state()->axis() * flare->location())); light_size = 0.0625 * flare->radius(); if (current_texture != flare->texture()) { gl::end(); current_texture = Textures::bind(flare->texture()); gl::begin(gl::Quads); } if (flare->entity()) { color.assign(entity->color()); } else { color.assign(flare->color()); } a = dotproduct(flare_axis.forward(), Camera::axis().forward()); if (a < -0.1f) { color.a = -a - 0.1f; gl::color(color); glTexCoord2f(0,1); gl::vertex(location + (flare_axis.up() + flare_axis.left()) * light_size); glTexCoord2f(0,0); gl::vertex(location + (flare_axis.up() - flare_axis.left()) * light_size); glTexCoord2f(1,0); gl::vertex(location + (flare_axis.up() * -1 - flare_axis.left()) * light_size); glTexCoord2f(1,1); gl::vertex(location + (flare_axis.up() * -1 + flare_axis.left()) * light_size); Stats::quads++; } } } // draw model engines for Controlable entities if ((entity->type() == core::Entity::Controlable) && entity->model()->engines().size()) { core::EntityControlable *ec = static_cast(entity); u = ec->thrust(); if ((ec->eventstate() == core::Entity::ImpulseInitiate) || (ec->eventstate() == core::Entity::Impulse)) { u = 1; } if (u > 0) { t = entity->state()->state_engine_trail_offset; t += elapsed * 4.0f * u; if (t > 1.0f) t -= 1.0f; math::clamp(t, 0.0f, 1.0f); entity->state()->state_engine_trail_offset = t; for(model::Model::Engines::iterator eit = entity->model()->engines().begin(); eit != entity->model()->engines().end(); eit++) { engine = (*eit); location.assign(entity->state()->location() + (entity->state()->axis() * engine->location())); engine_size = 0.0625 * engine->radius(); if (current_texture != engine->texture() ) { gl::end(); current_texture = Textures::bind(engine->texture()); gl::begin(gl::Quads); } quad[0].assign(entity->state()->axis().up() - entity->state()->axis().left()); quad[1].assign(entity->state()->axis().up() + entity->state()->axis().left()); quad[2].assign(entity->state()->axis().up() * -1 + entity->state()->axis().left()); quad[3].assign(entity->state()->axis().up() * -1 - entity->state()->axis().left()); // assign engine color to the flare if (!engine->noflare()){ color.assign(entity->model()->enginecolor()); color.a = 0.9f * u; gl::color(color); glTexCoord2f(0,1); gl::vertex(location + quad[0] * engine_size); glTexCoord2f(0,0); gl::vertex(location + quad[1] * engine_size); glTexCoord2f(1,0); gl::vertex(location + quad[2] * engine_size); glTexCoord2f(1,1); gl::vertex(location + quad[3] * engine_size); Stats::quads++; } if (!(engine->notrail() || (ec->eventstate() == core::Entity::Impulse))) { // draw the engine trail if (current_texture != circle_texture) { gl::end(); current_texture = Textures::bind(circle_texture); gl::begin(gl::Quads); } color.assign(1.0f, 1.0f); offset.assign(entity->state()->axis().forward() * engine_size); if (t > 0) location -= offset * t; for (size_t i = count; i > 0; i--) { trail_size = engine_size * 0.8f * (0.4f + ((-t + (float) i) / (float) count) * 0.6f); color.a = (0.1f + ((-t + (float) i) / (float) count) * 0.7f) * u; gl::color(color); glTexCoord2f(0,1); gl::vertex(location + quad[0] * trail_size); glTexCoord2f(0,0); gl::vertex(location + quad[1] * trail_size); glTexCoord2f(1,0); gl::vertex(location + quad[2] * trail_size); glTexCoord2f(1,1); gl::vertex(location + quad[3] * trail_size); Stats::quads++; gl::color(color); glTexCoord2f(1,1); gl::vertex(location + quad[3] * trail_size); glTexCoord2f(1,0); gl::vertex(location + quad[2] * trail_size); glTexCoord2f(0,0); gl::vertex(location + quad[1] * trail_size); glTexCoord2f(0,1); gl::vertex(location + quad[0] * trail_size); Stats::quads++; location -= offset; } } } } } } } gl::end(); gl::disable(GL_TEXTURE_2D); } void draw_pass_model_corona() { if (!(r_radius && r_radius->value())) return; for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { core::Entity *entity = (*it); if (entity->model() && entity->state()->visible()) { gl::push(); gl::translate(entity->state()->location()); math::Color color = entity->color(); color.a = 0.25f; draw_sphere(color, entity->model()->radius()); gl::pop(); } } } void draw_pass_spacegrid() { if (!(r_grid && r_grid->value())) return; int gridsize = 32; float s = 1.0f / gridsize; float z = -4.0f; float dx = Camera::target().x - floorf(Camera::target().x); float dy = Camera::target().y - floorf(Camera::target().y); gl::push(); gl::translate(Camera::target()); gl::color(0,0, 1.0f); gl::normal(0, 0, 1.0f); gl::begin(gl::Lines); for (int i=-gridsize; i <= gridsize; i++) { gl::color(0,0, 0, 0); gl::vertex(i-dx, -gridsize-dy, z); gl::color(0,0, (gridsize-abs(i))*s, (gridsize-abs(i))*s); gl::vertex(i-dx, -dy, z ); gl::vertex(i-dx, -dy ,z ); gl::color(0,0, 0, 0); gl::vertex(i-dx, gridsize-dy, z); gl::vertex(-gridsize-dx, i-dy, z ); gl::color(0,0, (gridsize-abs(i))*s, (gridsize-abs(i))*s); gl::vertex(-dx, i-dy, z); gl::vertex(-dx, i-dy, z); gl::color(0,0, 0, 0); gl::vertex(gridsize-dx, i-dy, z); } gl::end(); gl::pop(); } /* ----- Main draw routine ----------------------------------------- */ void draw(float seconds) { zone = core::localplayer()->zone(); // calculate client state pass_prepare(seconds); // enable wireframe mode if requested if (r_wireframe && r_wireframe->value()) { glPolygonMode(GL_FRONT, GL_LINE); } else { glPolygonMode(GL_FRONT, GL_FILL); } // set vertex array pointers glVertexPointer(3, GL_FLOAT, 0, vertexarray->vertex()); glNormalPointer(GL_FLOAT, 0, vertexarray->normal()); glColorPointer(3, GL_FLOAT, 0, vertexarray->color()); glTexCoordPointer(3, GL_FLOAT, 0, vertexarray->texture()); // enable vertex arrays glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); gl::enable(GL_DEPTH_TEST); gl::depthmask(GL_FALSE); // disable depth buffer writing draw_pass_sky(); // draw the skysphere gl::depthmask(GL_TRUE); // enable writing to the depth buffer gl::enable(GL_CULL_FACE); // enable culling gl::enable(GL_COLOR_MATERIAL); // enable color tracking gl::enable(GL_LIGHTING); //gl::enable(GL_RESCALE_NORMAL); // rescale normals by the transformation matrix scale factor gl::enable(GL_NORMALIZE); draw_pass_globes(); // draw globes draw_pass_default(); // draw entities without model gl::disable(GL_NORMALIZE); //gl::disable(GL_RESCALE_NORMAL); glEnableClientState(GL_COLOR_ARRAY); draw_pass_model_fragments(); glDisableClientState(GL_COLOR_ARRAY); gl::disable(GL_LIGHTING); gl::enable(GL_BLEND); gl::depthmask(GL_FALSE); // disable depth buffer writing draw_pass_spacegrid(); // draw the blue spacegrid Dust::draw(zone_color); // draw spacedust draw_pass_model_fx(seconds); // draw entity lights and engines gl::enable(GL_LIGHTING); gl::enable(GL_RESCALE_NORMAL); draw_pass_model_corona(); // draw entity radius glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); gl::disable(GL_RESCALE_NORMAL); gl::disable(GL_LIGHTING); gl::disable(GL_COLOR_MATERIAL); // disable color tracking gl::disable(GL_CULL_FACE); // disable culling gl::depthmask(GL_TRUE); // enable depth buffer writing gl::disable(GL_DEPTH_TEST); // disable depth buffer testing // GL_BLEND must be enabled for the GUI } }