Files
OpenSpace/src/scenegraph/scenegraphnode.cpp
Jonas Strandstedt b1eab2cf03 Finalized first draft for the SceneGraph
- Refactored several files
- Implemented PositionInformation subclasses
- Added standard shaders in the shader directory
- Removed SceneGraphLoader, now integrated in the SceneGraph

- TODO: Further testing and improvements to the PowerScale coordinate
system
2014-03-13 11:21:30 -04:00

308 lines
9.9 KiB
C++

/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
// open space includes
#include "scenegraph/scenegraphnode.h"
#include "util/spice.h"
// ghoul includes
#include <ghoul/logging/logmanager.h>
#include <ghoul/logging/consolelog.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/opengl/shadermanager.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/shaderobject.h>
#include <scenegraph/constantpositioninformation.h>
#include <openspaceengine.h>
namespace {
std::string _loggerCat = "SceneGraphNode";
}
namespace openspace {
SceneGraphNode::SceneGraphNode(): _parent(nullptr), _nodeName("Unnamed OpenSpace SceneGraphNode"),
_position(nullptr), _renderable(nullptr),
_renderableVisible(false), _boundingSphereVisible(false) {}
SceneGraphNode::~SceneGraphNode() {
LDEBUG("Deallocating: " << _nodeName);
// deallocate the renderable
if(_renderable != nullptr)
delete _renderable;
// deallocate the child nodes and delete them, iterate c++11 style
for( auto child: _children)
delete child;
}
bool SceneGraphNode::_initialize() {
using ghoul::opengl::ShaderObject;
using ghoul::opengl::ProgramObject;
using ghoul::opengl::ShaderManager;
ShaderObject* powerscale_vs = new ShaderObject(ShaderObject::ShaderType::ShaderTypeVertex,
absPath("${SHADERS}/pscstandard_vs.glsl"),
"PS Vertex"
);
ShaderObject* powerscale_fs = new ShaderObject(ShaderObject::ShaderType::ShaderTypeFragment,
absPath("${SHADERS}/pscstandard_fs.glsl"),
"PS Fragment"
);
ProgramObject* po = new ProgramObject;
po->attachObject(powerscale_vs);
po->attachObject(powerscale_fs);
if( ! po->compileShaderObjects())
return false;
if( ! po->linkProgramObject())
return false;
OsEng.ref().configurationManager().setValue("pscShader", po);
return true;
}
bool SceneGraphNode::initialize() {
if( ! _initialize()) {
return false;
}
_position = new ConstantPositionInformation;
_position->initializeWithDictionary(nullptr);
return true;
}
bool SceneGraphNode::initializeWithDictionary(ghoul::Dictionary* dictionary) {
if( ! _initialize()) {
return false;
}
// set the _nodeName if available
dictionary->getValue("Name", _nodeName);
std::string path;
dictionary->getValue("Path", path);
if(dictionary->hasKey("Renderable")) {
if(safeInitializeWithDictionary<Renderable>(&_renderable, "Renderable", dictionary, path)) {
LDEBUG("Successful initialization of renderable!");
if ( ! _renderable) {
LFATAL("But the renderable is not initialized for " << _nodeName);
}
} else {
LDEBUG("Failed to initialize renderable!");
}
}
if(dictionary->hasKey("Position")) {
if(safeInitializeWithDictionary<PositionInformation>(&_position, "Position", dictionary, path)) {
LDEBUG("Successful initialization of position!");
if ( ! _position) {
LFATAL("But the position is not initialized for " << _nodeName);
}
} else {
LDEBUG("Failed to initialize position!");
}
}
if (_position == nullptr) {
_position = new ConstantPositionInformation;
_position->initializeWithDictionary(nullptr);
}
return true;
}
// essential
void SceneGraphNode::update() {
_position->update();
}
void SceneGraphNode::evaluate(const Camera *camera, const psc& parentPosition) {
const psc thisPosition = parentPosition + _position->position();
const psc camPos = camera->getPosition();
const psc toCamera = thisPosition - camPos;
// init as not visible
_boundingSphereVisible = false;
_renderableVisible = false;
// check if camera is outside the node boundingsphere
if(toCamera.length() > _boundingSphere) {
// check if the boudningsphere is visible before avaluating children
if( ! sphereInsideFrustum(thisPosition, _boundingSphere, camera)) {
// the node is completely outside of the camera view, stop evaluating this node
return;
}
}
// inside boudningsphere or parts of the sphere is visible, individual
// children needs to be evaluated
_boundingSphereVisible = true;
// this node has an renderable
if(_renderable) {
// check if the renderable boundingsphere is visible
_renderableVisible = sphereInsideFrustum(thisPosition, _renderable->getBoundingSphere(), camera);
}
// evaluate all the children, tail-recursive function(?)
for(auto &child: _children) {
child->evaluate(camera,psc());
}
}
void SceneGraphNode::render(const Camera *camera, const psc & parentPosition) {
const psc thisPosition = parentPosition + _position->position();
// check if camera is outside the node boundingsphere
if( ! _boundingSphereVisible) {
return;
}
if(_renderableVisible) {
_renderable->render(camera,thisPosition);
}
// evaluate all the children, tail-recursive function(?)
for(auto &child: _children) {
child->render(camera,thisPosition);
}
}
// set & get
void SceneGraphNode::addNode(SceneGraphNode *child) {
// add a child node and set this node to be the parent
child->setParent(this);
_children.push_back(child);
}
void SceneGraphNode::setName(const std::string &name) {
_nodeName = name;
}
void SceneGraphNode::setParent(SceneGraphNode *parent) {
_parent = parent;
}
const psc &SceneGraphNode::getPosition() const {
return _position->position();
}
psc SceneGraphNode::getWorldPosition() const {
// recursive up the hierarchy if there are parents available
if(_parent) {
return _position->position() + _parent->getWorldPosition();
} else {
return _position->position();
}
}
// bounding sphere
pss SceneGraphNode::calculateBoundingSphere() {
// set the vounding sphere to 0.0
_boundingSphere = 0.0;
if(_children.size() > 0) { // node
pss maxChild;
// loop though all children and find the one furthest away/with the largest bounding sphere
for(size_t i = 0; i < _children.size(); ++i) {
// when positions is dynamix, change this part to fins the most distant position
pss child = _children.at(i)->getPosition().length() +
_children.at(i)->calculateBoundingSphere();
if(child > maxChild) {
maxChild = child;
}
}
_boundingSphere += maxChild;
} else { // leaf
// if has a renderable, use that boundingsphere
if(_renderable)
_boundingSphere += _renderable->getBoundingSphere();
}
return _boundingSphere;
}
// renderable
void SceneGraphNode::setRenderable(Renderable *renderable) {
_renderable = renderable;
update();
}
const Renderable * SceneGraphNode::getRenderable() const{
return _renderable;
}
// private helper methods
bool SceneGraphNode::sphereInsideFrustum(const psc s_pos, const pss & s_rad, const Camera *camera) {
// direction the camera is looking at in power scale
psc psc_camdir = psc(camera->getViewDirection());
// the position of the camera, moved backwards in the view direction to encapsulate the sphere radius
psc U = camera->getPosition() - psc_camdir * s_rad * ( 1.0 / camera->getSinMaxFov());
// the vector to the object from the new position
psc D = s_pos - U;
const double a = psc_camdir.angle(D);
if ( a < camera->getMaxFov())
{
// center is inside K''
D = s_pos - camera->getPosition();
if ( D.length()* psc_camdir.length() *camera->getSinMaxFov() <= -psc_camdir.dot(D)) {
// center is inside K'' and inside K'
return D.length() <= s_rad;
} else {
// center is inside K'' and outside K'
return true;
}
} else {
// outside the maximum angle
return false;
}
}
} // namespace openspace