diff --git a/Primitives.cpp b/Primitives.cpp index 5fe9b2e..7dbf735 100644 --- a/Primitives.cpp +++ b/Primitives.cpp @@ -16,7 +16,7 @@ -TexturedRectangle::TexturedRectangle(const std::string& resourcepath) +TexturedRectangle::TexturedRectangle(const std::string& resourcepath) : Primitive() { texturepath_ = resourcepath; @@ -48,6 +48,7 @@ TexturedRectangle::TexturedRectangle(const std::string& resourcepath) // setup shader for textured image shader_ = new ImageShader(); + drawingPrimitive_ = GL_TRIANGLE_STRIP; } void TexturedRectangle::draw(glm::mat4 modelview, glm::mat4 projection) @@ -66,7 +67,7 @@ void TexturedRectangle::accept(Visitor& v) } -MediaRectangle::MediaRectangle(const std::string& mediapath) +MediaRectangle::MediaRectangle(const std::string& mediapath) : Primitive() { mediapath_ = mediapath; @@ -98,6 +99,7 @@ MediaRectangle::MediaRectangle(const std::string& mediapath) // setup shader for textured image shader_ = new ImageShader(); + drawingPrimitive_ = GL_TRIANGLE_STRIP; } MediaRectangle::~MediaRectangle() @@ -130,7 +132,7 @@ void MediaRectangle::accept(Visitor& v) v.visit(*this); } -LineStrip::LineStrip(std::vector points, glm::vec3 color) +LineStrip::LineStrip(std::vector points, glm::vec3 color) : Primitive() { for(size_t i = 0; i < points.size(); ++i) { @@ -140,7 +142,15 @@ LineStrip::LineStrip(std::vector points, glm::vec3 color) } shader_ = new Shader(); - drawingPrimitive_ = GL_LINE_STRIP; + + drawingPrimitive_ = GL_LINE_LOOP; + linewidth_ = 2; +} + +void LineStrip::draw(glm::mat4 modelview, glm::mat4 projection) +{ + glLineWidth(linewidth_); + Primitive::draw(modelview, projection); } void LineStrip::accept(Visitor& v) diff --git a/Primitives.h b/Primitives.h index 7744762..2bfb2a9 100644 --- a/Primitives.h +++ b/Primitives.h @@ -46,9 +46,12 @@ public: // Draw a line strip class LineStrip : public Primitive { + int linewidth_; + public: LineStrip(std::vector points, glm::vec3 color); + void draw(glm::mat4 modelview, glm::mat4 projection) override; void accept(Visitor& v) override; std::vector getPoints() { return points_; } diff --git a/Scene.cpp b/Scene.cpp index 714a3de..456dd90 100644 --- a/Scene.cpp +++ b/Scene.cpp @@ -1,4 +1,4 @@ - +#include "defines.h" #include "Scene.h" #include "Shader.h" #include "Primitives.h" @@ -94,7 +94,6 @@ void Primitive::init() glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); - drawingPrimitive_ = GL_TRIANGLE_STRIP; visible_ = true; } @@ -109,7 +108,7 @@ void Primitive::draw(glm::mat4 modelview, glm::mat4 projection) } // - // draw + // draw vertex array object // glBindVertexArray( vao_ ); glDrawElements( drawingPrimitive_, indices_.size(), GL_UNSIGNED_INT, 0 ); @@ -138,12 +137,6 @@ Group::~Group() children_.clear(); } -void Group::accept(Visitor& v) -{ - Node::accept(v); - v.visit(*this); -} - void Group::init() { visible_ = true; @@ -172,10 +165,15 @@ void Group::draw(glm::mat4 modelview, glm::mat4 projection) node != children_.end(); node++) { (*node)->draw ( ctm, projection ); } - } } +void Group::accept(Visitor& v) +{ + Node::accept(v); + v.visit(*this); +} + void Group::addChild(Node *child) { @@ -183,20 +181,58 @@ void Group::addChild(Node *child) child->parent_ = this; } -Node *Group::getChild(int i) +Node *Group::getChild(uint i) { if ( i >= 0 && i < children_.size() ) - return children_[i]; + return children_[i]; else - return nullptr; + return nullptr; } -int Group::numChildren() +uint Group::numChildren() const { return children_.size(); } +void Switch::update( float dt ) +{ + Node::update(dt); -void Scene::accept(Visitor& v) { + // update active child node + children_[active_]->update( dt ); +} + +void Switch::draw(glm::mat4 modelview, glm::mat4 projection) +{ + if ( visible_ ) { + // append the instance transform to the ctm + glm::mat4 ctm = modelview * transform_; + + // draw current child + children_[active_]->draw(ctm, projection); + } +} + +void Switch::accept(Visitor& v) +{ + Group::accept(v); + v.visit(*this); +} + +void Switch::setActiveIndex(uint index) +{ + active_ = CLAMP( index, 0, children_.size() - 1); +} + +Node* Switch::activeNode() +{ + if ( children_.empty() ) + return nullptr; + + return children_[active_]; +} + +void Scene::accept(Visitor& v) +{ v.visit(*this); } diff --git a/Scene.h b/Scene.h index cf77c5d..294f577 100644 --- a/Scene.h +++ b/Scene.h @@ -72,14 +72,31 @@ public: virtual void draw ( glm::mat4 modelview, glm::mat4 projection) override; virtual void accept(Visitor& v) override; - virtual void addChild ( Node *child ); - virtual Node* getChild ( int i ); - virtual int numChildren(); + void addChild ( Node *child ); + Node* getChild ( uint i ); + uint numChildren() const; protected: std::vector< Node* > children_; }; +class Switch : public Group { + +public: + Switch() : Group(), active_(0) {} + + virtual void update ( float dt ) override; + virtual void draw ( glm::mat4 modelview, glm::mat4 projection) override; + virtual void accept(Visitor& v) override; + + void setActiveIndex(uint index); + uint activeIndex() const { return active_; } + Node* activeNode(); + +protected: + uint active_; +}; + // A scene contains a root node and gives a simplified API to add nodes class Scene { diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 717c44a..715bffe 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -12,9 +12,6 @@ #include using namespace tinyxml2; -#ifndef XMLCheckResult - #define XMLCheckResult(a_eResult) if (a_eResult != XML_SUCCESS) { Log::Warning("XML error %i\n", a_eResult); return; } -#endif SessionVisitor::SessionVisitor(std::string filename) : filename_(filename) { @@ -27,7 +24,7 @@ void SessionVisitor::visit(Node &n) XMLElement *newelement = xmlDoc_->NewElement("Node"); // xmlCurrent_->SetAttribute("type", "Undefined"); - XMLElement *transform = XMLElementGLM(xmlDoc_, n.transform_); + XMLElement *transform = XMLElementFromGLM(xmlDoc_, n.transform_); newelement->InsertEndChild(transform); // insert into hierarchy @@ -46,11 +43,19 @@ void SessionVisitor::visit(Group &n) { // recursive n.getChild(i)->accept(*this); + xmlCurrent_->SetAttribute("index", i); // revert to group as current xmlCurrent_ = group; } } +void SessionVisitor::visit(Switch &n) +{ + // Node of a different type + xmlCurrent_->SetAttribute("type", "Switch"); + xmlCurrent_->SetAttribute("active", n.activeIndex()); +} + void SessionVisitor::visit(Primitive &n) { // Node of a different type @@ -107,10 +112,14 @@ void SessionVisitor::visit(Shader &n) // Shader of a simple type xmlCurrent_->SetAttribute("type", "DefaultShader"); - XMLElement *color = XMLElementGLM(xmlDoc_, n.color); + XMLElement *color = XMLElementFromGLM(xmlDoc_, n.color); color->SetAttribute("type", "RGBA"); xmlCurrent_->InsertEndChild(color); + XMLElement *blend = xmlDoc_->NewElement("blending"); + blend->SetAttribute("mode", (int) n.blending); + xmlCurrent_->InsertEndChild(blend); + } void SessionVisitor::visit(ImageShader &n) @@ -130,15 +139,15 @@ void SessionVisitor::visit(LineStrip &n) // Node of a different type xmlCurrent_->SetAttribute("type", "LineStrip"); - XMLElement *color = XMLElementGLM(xmlDoc_, n.getColor()); + XMLElement *color = XMLElementFromGLM(xmlDoc_, n.getColor()); color->SetAttribute("type", "RGBA"); xmlCurrent_->InsertEndChild(color); std::vector points = n.getPoints(); for(size_t i = 0; i < points.size(); ++i) { - XMLElement *p = XMLElementGLM(xmlDoc_, points[i]); - p->SetAttribute("point", (int) i); + XMLElement *p = XMLElementFromGLM(xmlDoc_, points[i]); + p->SetAttribute("index", (int) i); xmlCurrent_->InsertEndChild(p); } } @@ -148,7 +157,7 @@ void SessionVisitor::visit(Scene &n) XMLDeclaration *pDec = xmlDoc_->NewDeclaration(); xmlDoc_->InsertFirstChild(pDec); - XMLElement *pRoot = xmlDoc_->NewElement("Session"); + XMLElement *pRoot = xmlDoc_->NewElement("Scene"); xmlDoc_->InsertEndChild(pRoot); std::string s = "Saved on " + GstToolkit::date_time_string(); diff --git a/SessionVisitor.h b/SessionVisitor.h index 63a574a..d9f9dd0 100644 --- a/SessionVisitor.h +++ b/SessionVisitor.h @@ -16,6 +16,7 @@ public: // Elements of Scene void visit(Node& n) override; void visit(Group& n) override; + void visit(Switch& n) override; void visit(Primitive& n) override; void visit(Scene& n) override; void visit(TexturedRectangle& n) override; diff --git a/Settings.cpp b/Settings.cpp index 42b20b7..60ca584 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -1,5 +1,5 @@ #include "Settings.h" -#include "Log.h" +#include "tinyxml2Toolkit.h" #include using namespace std; @@ -7,10 +7,6 @@ using namespace std; #include using namespace tinyxml2; -#ifndef XMLCheckResult - #define XMLCheckResult(a_eResult) if (a_eResult != XML_SUCCESS) { Log::Warning("XML error %i\n", a_eResult); return; } -#endif - Settings::Application Settings::application; string filename = string("./") + APP_NAME + ".xml"; diff --git a/Shader.cpp b/Shader.cpp index 4645cc0..1ce20d7 100644 --- a/Shader.cpp +++ b/Shader.cpp @@ -22,6 +22,12 @@ ShadingProgram *ShadingProgram::currentProgram_ = nullptr; ShadingProgram simpleShadingProgram("shaders/simple-shader.vs", "shaders/simple-shader.fs"); +// Blending presets for matching with Shader::BlendMode +GLenum blending_equation[6] = { GL_FUNC_ADD, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_ADD}; +GLenum blending_source_function[6] = { GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,GL_SRC_ALPHA,}; +GLenum blending_destination_function[6] = {GL_ONE, GL_ONE, GL_ONE, GL_DST_COLOR, GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA}; + + ShadingProgram::ShadingProgram(const std::string& vertex_file, const std::string& fragment_file) : vertex_id_(0), fragment_id_(0), id_(0) { @@ -154,7 +160,7 @@ void ShadingProgram::checkLinkingErr() } -Shader::Shader() +Shader::Shader() : blending(BLEND_OPACITY) { program_ = &simpleShadingProgram; reset(); @@ -177,6 +183,15 @@ void Shader::use() program_->setUniform("projection", projection); program_->setUniform("modelview", modelview); program_->setUniform("color", color); + + // Blending Function + if ( blending != BLEND_NONE) { + glEnable(GL_BLEND); + glBlendEquation(blending_equation[blending]); + glBlendFunc(blending_source_function[blending], blending_destination_function[blending]); + } + else + glDisable(GL_BLEND); } diff --git a/Shader.h b/Shader.h index e7d91b8..07ef92a 100644 --- a/Shader.h +++ b/Shader.h @@ -49,10 +49,21 @@ public: glm::mat4 modelview; glm::vec4 color; + typedef enum { + BLEND_NONE = 0, + BLEND_ADD, + BLEND_SUBSTRACT, + BLEND_LAYER_ADD, + BLEND_LAYER_SUBSTRACT, + BLEND_OPACITY + } BlendMode; + BlendMode blending; + void setModelview(float x, float y, float angle, float scale, float aspect_ratio); protected: ShadingProgram *program_; + }; #endif /* __SHADER_H_ */ diff --git a/Visitor.h b/Visitor.h index 2c23317..decf871 100644 --- a/Visitor.h +++ b/Visitor.h @@ -6,6 +6,7 @@ // Forward declare different kind of Node class Node; class Group; +class Switch; class Primitive; class Scene; class TexturedRectangle; @@ -22,6 +23,7 @@ public: // Declare overloads for each kind of Node to visit virtual void visit(Node& n) = 0; virtual void visit(Group& n) = 0; + virtual void visit(Switch& n) = 0; virtual void visit(Primitive& n) = 0; virtual void visit(Scene& n) = 0; virtual void visit(TexturedRectangle& n) = 0; diff --git a/main.cpp b/main.cpp index 665ac62..417d063 100644 --- a/main.cpp +++ b/main.cpp @@ -341,23 +341,37 @@ int main(int, char**) MediaRectangle testnode2("file:///home/bhbn/Videos/fish.mp4"); testnode2.init(); + TexturedRectangle testnode3("images/v-mix_256x256.png"); + testnode3.init(); + testnode3.getShader()->blending = Shader::BLEND_SUBSTRACT; + + std::vector points; + points.push_back( glm::vec3( -1.f, -1.f, 0.f ) ); + points.push_back( glm::vec3( -1.f, 1.f, 0.f ) ); + points.push_back( glm::vec3( 1.f, 1.f, 0.f ) ); + points.push_back( glm::vec3( 1.f, -1.f, 0.f ) ); + glm::vec3 color( 1.f, 1.f, 0.f ); + LineStrip border(points, color); + border.init(); + Group g1; g1.init(); g1.transform_ = glm::translate(glm::identity(), glm::vec3(1.f, 1.f, 0.f)); - Group g2; + Switch g2; g2.init(); g2.transform_ = glm::translate(glm::identity(), glm::vec3(-1.f, -1.f, 0.f)); + // build tree g1.addChild(&testnode1); + g1.addChild(&testnode3); scene.root_.addChild(&g1); g2.addChild(&testnode2); + g2.addChild(&border); + g2.setActiveIndex(1); scene.root_.addChild(&g2); - SessionVisitor savetoxml("/home/bhbn/test.vmx"); - scene.accept(savetoxml); - /// /// Main LOOP /// @@ -369,6 +383,9 @@ int main(int, char**) testmedia.Close(); testmedia2.Close(); + SessionVisitor savetoxml("/home/bhbn/test.vmx"); + scene.accept(savetoxml); + UserInterface::manager().Terminate(); Rendering::manager().Terminate(); diff --git a/tinyxml2Toolkit.cpp b/tinyxml2Toolkit.cpp index fbc1ca8..5bf31d2 100644 --- a/tinyxml2Toolkit.cpp +++ b/tinyxml2Toolkit.cpp @@ -1,4 +1,5 @@ #include "tinyxml2Toolkit.h" +#include "Log.h" #include using namespace tinyxml2; @@ -8,35 +9,85 @@ using namespace tinyxml2; #include #include +#include -XMLElement *tinyxml2::XMLElementGLM(XMLDocument *doc, glm::vec3 vector) +XMLElement *tinyxml2::XMLElementFromGLM(XMLDocument *doc, glm::vec3 vector) { XMLElement *newelement = doc->NewElement( "vec3" ); - newelement->SetAttribute("x", vector[0]); - newelement->SetAttribute("y", vector[1]); - newelement->SetAttribute("z", vector[2]); + newelement->SetAttribute("x", vector.x); + newelement->SetAttribute("y", vector.y); + newelement->SetAttribute("z", vector.z); return newelement; } -XMLElement *tinyxml2::XMLElementGLM(XMLDocument *doc, glm::vec4 vector) +XMLElement *tinyxml2::XMLElementFromGLM(XMLDocument *doc, glm::vec4 vector) { XMLElement *newelement = doc->NewElement( "vec4" ); - newelement->SetAttribute("x", vector[0]); - newelement->SetAttribute("y", vector[1]); - newelement->SetAttribute("z", vector[2]); - newelement->SetAttribute("w", vector[3]); + newelement->SetAttribute("x", vector.x); + newelement->SetAttribute("y", vector.y); + newelement->SetAttribute("z", vector.z); + newelement->SetAttribute("w", vector.w); return newelement; } -XMLElement *tinyxml2::XMLElementGLM(XMLDocument *doc, glm::mat4 matrix) +XMLElement *tinyxml2::XMLElementFromGLM(XMLDocument *doc, glm::mat4 matrix) { XMLElement *newelement = doc->NewElement( "mat4" ); for (int r = 0 ; r < 4 ; r ++) { glm::vec4 row = glm::row(matrix, r); - XMLElement *rowxml = XMLElementGLM(doc, row); + XMLElement *rowxml = XMLElementFromGLM(doc, row); rowxml->SetAttribute("row", r); newelement->InsertEndChild(rowxml); } return newelement; } + + +void tinyxml2::XMLElementToGLM(XMLElement *elem, glm::vec3 &vector) +{ + if ( std::string(elem->Name()).find("vec3") == std::string::npos ) + return; + elem->QueryFloatAttribute("x", &vector.x); // If this fails, original value is left as-is + elem->QueryFloatAttribute("y", &vector.y); + elem->QueryFloatAttribute("z", &vector.z); +} + +void tinyxml2::XMLElementToGLM(XMLElement *elem, glm::vec4 &vector) +{ + if ( std::string(elem->Name()).find("vec4") == std::string::npos ) + return; + elem->QueryFloatAttribute("x", &vector.x); // If this fails, original value is left as-is + elem->QueryFloatAttribute("y", &vector.y); + elem->QueryFloatAttribute("z", &vector.z); + elem->QueryFloatAttribute("w", &vector.w); +} + +void tinyxml2::XMLElementToGLM(XMLElement *elem, glm::mat4 &matrix) +{ + if ( std::string(elem->Name()).find("mat4") == std::string::npos ) + return; + + // loop over rows of vec4 + XMLElement* row = elem->FirstChildElement("vec4"); + for( ; row ; row = row->NextSiblingElement()) + { + int r = 0; + row->QueryIntAttribute("row", &r); // which row index are we reading? + glm::vec4 vector = glm::row(matrix, r); // use matrix row as default + XMLElementToGLM(row, vector); // read vec4 values + matrix[0][r] = vector[0]; + matrix[1][r] = vector[1]; + matrix[2][r] = vector[2]; + matrix[3][r] = vector[3]; + } +} + +void tinyxml2::XMLCheckResult(uint r) +{ + XMLError result = (XMLError) r; + if ( result != XML_SUCCESS) + { + Log::Error("XML error %i: %s", r, tinyxml2::XMLDocument::ErrorIDToName(result)); + } +} diff --git a/tinyxml2Toolkit.h b/tinyxml2Toolkit.h index 06c8f96..bff8ddb 100644 --- a/tinyxml2Toolkit.h +++ b/tinyxml2Toolkit.h @@ -8,9 +8,15 @@ namespace tinyxml2 { class XMLDocument; class XMLElement; -XMLElement *XMLElementGLM(XMLDocument *doc, glm::vec3 vector); -XMLElement *XMLElementGLM(XMLDocument *doc, glm::vec4 vector); -XMLElement *XMLElementGLM(XMLDocument *doc, glm::mat4 matrix); +XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::vec3 vector); +XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::vec4 vector); +XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::mat4 matrix); + +void XMLElementToGLM(XMLElement *elem, glm::vec3 &vector); +void XMLElementToGLM(XMLElement *elem, glm::vec4 &vector); +void XMLElementToGLM(XMLElement *elem, glm::mat4 &matrix); + +void XMLCheckResult(uint r); }