mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-16 12:49:59 +01:00
Cleanup source tree
Move all C++ source files in the src subfolder. Adapted the cmake process accordingly and cleanup.
This commit is contained in:
515
src/Scene.cpp
Normal file
515
src/Scene.cpp
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* This file is part of vimix - video live mixer
|
||||
*
|
||||
* **Copyright** (C) 2019-2022 Bruno Herbelin <bruno.herbelin@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "defines.h"
|
||||
#include "Shader.h"
|
||||
#include "Primitives.h"
|
||||
#include "Visitor.h"
|
||||
#include "GarbageVisitor.h"
|
||||
#include "Log.h"
|
||||
#include "BaseToolkit.h"
|
||||
#include "GlmToolkit.h"
|
||||
#include "SessionVisitor.h"
|
||||
|
||||
#include "Scene.h"
|
||||
|
||||
#define DEBUG_SCENE 0
|
||||
#if DEBUG_SCENE
|
||||
static int num_nodes_ = 0;
|
||||
#endif
|
||||
|
||||
// Node
|
||||
Node::Node() : initialized_(false), visible_(true), refcount_(0)
|
||||
{
|
||||
// create unique id
|
||||
id_ = BaseToolkit::uniqueId();
|
||||
|
||||
transform_ = glm::identity<glm::mat4>();
|
||||
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<UpdateCallback *>::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)
|
||||
{
|
||||
for (auto iter=update_callbacks_.begin(); iter != update_callbacks_.end(); )
|
||||
{
|
||||
UpdateCallback *callback = *iter;
|
||||
|
||||
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<Node *>::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<Node *>::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);
|
||||
}
|
||||
Reference in New Issue
Block a user