#include #include #include #include #include #include #include "defines.h" #include "Shader.h" #include "Primitives.h" #include "Visitor.h" #include "GarbageVisitor.h" #include "Log.h" #include "GlmToolkit.h" #include "SessionVisitor.h" #include "Scene.h" #define DEBUG_SCENE 0 static int num_nodes_ = 0; // Node Node::Node() : initialized_(false), visible_(true), refcount_(0) { // create unique id id_ = GlmToolkit::uniqueId(); transform_ = glm::identity(); scale_ = glm::vec3(1.f); rotation_ = glm::vec3(0.f); translation_ = glm::vec3(0.f); crop_ = glm::vec3(1.f); #if DEBUG_SCENE num_nodes_++; #endif } Node::~Node () { clearCallbacks(); #if DEBUG_SCENE num_nodes_--; #endif } void Node::clearCallbacks() { std::list::iterator iter; for (iter=update_callbacks_.begin(); iter != update_callbacks_.end(); ) { UpdateCallback *callback = *iter; iter = update_callbacks_.erase(iter); delete callback; } } void Node::copyTransform(const Node *other) { if (!other) return; // transform_ = other->transform_; scale_ = other->scale_; rotation_ = other->rotation_; translation_ = other->translation_; crop_ = other->crop_; } void Node::update( float dt) { std::list::iterator iter; for (iter=update_callbacks_.begin(); iter != update_callbacks_.end(); ) { UpdateCallback *callback = *iter; if (callback->enabled()) callback->update(this, dt); if (callback->finished()) { iter = update_callbacks_.erase(iter); delete callback; } else { ++iter; } } // update transform matrix from attributes transform_ = GlmToolkit::transform(translation_, rotation_, scale_); } void Node::accept(Visitor& v) { v.visit(*this); } // // Primitive // Primitive::~Primitive() { if ( vao_ ) glDeleteVertexArrays ( 1, &vao_); if (shader_) delete shader_; } void Primitive::init() { if ( vao_ ) glDeleteVertexArrays ( 1, &vao_); // Vertex Array glGenVertexArrays( 1, &vao_ ); // Create and initialize buffer objects uint arrayBuffer_; uint elementBuffer_; glGenBuffers( 1, &arrayBuffer_ ); glGenBuffers( 1, &elementBuffer_); glBindVertexArray( vao_ ); // compute the memory needs for points std::size_t sizeofPoints = sizeof(glm::vec3) * points_.size(); std::size_t sizeofColors = sizeof(glm::vec4) * colors_.size(); std::size_t sizeofTexCoords = sizeof(glm::vec2) * texCoords_.size(); // setup the array buffers for vertices glBindBuffer( GL_ARRAY_BUFFER, arrayBuffer_ ); glBufferData( GL_ARRAY_BUFFER, sizeofPoints + sizeofColors + sizeofTexCoords, NULL, GL_STATIC_DRAW); glBufferSubData( GL_ARRAY_BUFFER, 0, sizeofPoints, &points_[0] ); glBufferSubData( GL_ARRAY_BUFFER, sizeofPoints, sizeofColors, &colors_[0] ); if ( sizeofTexCoords ) glBufferSubData( GL_ARRAY_BUFFER, sizeofPoints + sizeofColors, sizeofTexCoords, &texCoords_[0] ); // setup the element array for the triangle indices glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer_); std::size_t sizeofIndices = indices_.size() * sizeof(uint); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeofIndices, &(indices_[0]), GL_STATIC_DRAW); // explain how to read attributes 0, 1 and 2 (for point, color and textcoord respectively) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void *)0 ); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void *)(sizeofPoints) ); glEnableVertexAttribArray(1); if ( sizeofTexCoords ) { glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), (void *)(sizeofPoints + sizeofColors) ); glEnableVertexAttribArray(2); } // done glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); // drawing indications drawCount_ = indices_.size(); // delete temporary buffers if ( arrayBuffer_ ) glDeleteBuffers ( 1, &arrayBuffer_); if ( elementBuffer_ ) glDeleteBuffers ( 1, &elementBuffer_); // compute AxisAlignedBoundingBox bbox_.extend(points_); // arrays of vertices are not needed anymore (STATIC DRAW of vertex object) points_.clear(); colors_.clear(); texCoords_.clear(); indices_.clear(); Node::init(); } void Primitive::draw(glm::mat4 modelview, glm::mat4 projection) { if ( !initialized() ) init(); if ( visible_ ) { // // prepare and use shader // if (shader_) { shader_->projection = projection; shader_->modelview = modelview * transform_; shader_->use(); } // // draw vertex array object // if (vao_) { glBindVertexArray( vao_ ); glDrawElements( drawMode_, drawCount_, GL_UNSIGNED_INT, 0 ); glBindVertexArray(0); } } } void Primitive::accept(Visitor& v) { Node::accept(v); v.visit(*this); } void Primitive::replaceShader( Shader *newshader ) { if (newshader) { glm::mat4 iTransform = newshader->iTransform; glm::vec4 color = newshader->color; if (shader_) { iTransform = shader_->iTransform; color = shader_->color; delete shader_; } shader_ = newshader; shader_->iTransform = iTransform; shader_->color = color; } } // // Group // Group::~Group() { clear(); } void Group::clear() { for(NodeSet::iterator it = children_.begin(); it != children_.end(); ) { // one less ref to this node (*it)->refcount_--; // if this group was the only remaining parent if ( (*it)->refcount_ < 1 ) { // delete delete (*it); } // erase this iterator from the list it = children_.erase(it); } } void Group::attach(Node *child) { if (child != nullptr) { children_.insert(child); child->refcount_++; } } void Group::sort() { // reorder list of nodes NodeSet ordered_children; for(auto it = children_.begin(); it != children_.end(); it++) ordered_children.insert(*it); children_.swap(ordered_children); } void Group::detach(Node *child) { if (child != nullptr) { // find the node with this id, and erase it out of the list of children // NB: do NOT delete with remove : this takes all nodes with same depth (i.e. equal depth in set) NodeSet::iterator it = std::find_if(children_.begin(), children_.end(), hasId(child->id())); if ( it != children_.end()) { // detatch child from group parent children_.erase(it); child->refcount_--; } } } void Group::update( float dt ) { Node::update(dt); // update every child node for (NodeSet::iterator node = children_.begin(); node != children_.end(); ++node) { (*node)->update ( dt ); } } void Group::draw(glm::mat4 modelview, glm::mat4 projection) { if ( !initialized() ) init(); if ( visible_ ) { // append the instance transform to the ctm glm::mat4 ctm = modelview * transform_; // draw every child node for (NodeSet::iterator node = children_.begin(); node != children_.end(); ++node) { (*node)->draw ( ctm, projection ); } } } void Group::accept(Visitor& v) { Node::accept(v); v.visit(*this); } NodeSet::iterator Group::begin() { return children_.begin(); } NodeSet::iterator Group::end() { return children_.end(); } Node *Group::front() { if (!children_.empty()) return *children_.rbegin(); return nullptr; } Node *Group::back() { if (!children_.empty()) return *children_.begin(); return nullptr; } // // Switch node // Switch::~Switch() { clear(); } void Switch::clear() { for(std::vector::iterator it = children_.begin(); it != children_.end(); ) { // one less ref to this node (*it)->refcount_--; // if this group was the only remaining parent if ( (*it)->refcount_ < 1 ) { // delete delete (*it); } // erase this iterator from the list it = children_.erase(it); } // reset active active_ = 0; } void Switch::update( float dt ) { Node::update(dt); // update active child node if (!children_.empty()) (children_[active_])->update( dt ); } void Switch::draw(glm::mat4 modelview, glm::mat4 projection) { if ( !initialized() ) init(); if ( visible_ ) { // draw current child if (!children_.empty()) (children_[active_])->draw( modelview * transform_, projection); } } void Switch::accept(Visitor& v) { Node::accept(v); v.visit(*this); } void Switch::setActive (uint index) { active_ = MINI(index, children_.size() - 1); } Node *Switch::child(uint index) const { if (!children_.empty()) { uint i = MINI(index, children_.size() - 1); return children_.at(i); } return nullptr; } uint Switch::attach(Node *child) { children_.push_back(child); child->refcount_++; // make new child active active_ = children_.size() - 1; return active_; } void Switch::detatch(Node *child) { // if removing the active child, it cannot be active anymore if ( children_.at(active_) == child ) active_ = 0; // find the node with this id, and erase it out of the list of children std::vector::iterator it = std::find_if(children_.begin(), children_.end(), hasId(child->id())); if ( it != children_.end()) { // detatch child from group parent children_.erase(it); child->refcount_--; } } // // Scene // Scene::Scene() { root_ = new Group; background_ = new Group; background_->translation_.z = 0.f; root_->attach(background_); workspace_ = new Group; workspace_->translation_.z = 1.f; root_->attach(workspace_); foreground_ = new Group; foreground_->translation_.z = SCENE_DEPTH -0.1f; root_->attach(foreground_); } Scene::~Scene() { clear(); // bg and fg are deleted as children of root delete root_; #if DEBUG_SCENE Log::Info("Total scene nodes %d", num_nodes_); #endif } void Scene::clear() { clearForeground(); clearWorkspace(); clearBackground(); } void Scene::clearForeground() { foreground_->clear(); } void Scene::clearWorkspace() { workspace_->clear(); } void Scene::clearBackground() { background_->clear(); } void Scene::update(float dt) { root_->update( dt ); } void Scene::accept(Visitor& v) { v.visit(*this); }