| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- #include "Base.h"
- #include "AudioListener.h"
- #include "Scene.h"
- #include "SceneLoader.h"
- #include "MeshSkin.h"
- #include "Joint.h"
- namespace gameplay
- {
- Scene::Scene() : _activeCamera(NULL), _firstNode(NULL), _lastNode(NULL), _nodeCount(0), _bindAudioListenerToCamera(true), _debugBatch(NULL)
- {
- }
- Scene::Scene(const Scene& copy)
- {
- }
- Scene::~Scene()
- {
- // Unbind our active camera from the audio listener
- if (_activeCamera)
- {
- AudioListener* audioListener = AudioListener::getInstance();
- if (audioListener && (audioListener->getCamera() == _activeCamera))
- {
- audioListener->setCamera(NULL);
- }
- SAFE_RELEASE(_activeCamera);
- }
- // Remove all nodes from the scene
- removeAllNodes();
- }
- Scene* Scene::createScene()
- {
- return new Scene();
- }
- Scene* Scene::load(const char* filePath)
- {
- return SceneLoader::load(filePath);
- }
- const char* Scene::getId() const
- {
- return _id.c_str();
- }
- void Scene::setId(const char* id)
- {
- if (id)
- {
- _id = id;
- }
- }
- Node* Scene::findNode(const char* id, bool recursive, bool exactMatch) const
- {
- assert(id);
- // Search immediate children first.
- for (Node* child = getFirstNode(); child != NULL; child = child->getNextSibling())
- {
- // Does this child's ID match?
- if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
- {
- return child;
- }
- }
- // Recurse.
- if (recursive)
- {
- for (Node* child = getFirstNode(); child != NULL; child = child->getNextSibling())
- {
- Node* match = child->findNode(id, true, exactMatch);
- if (match)
- {
- return match;
- }
- }
- }
- return NULL;
- }
- unsigned int Scene::findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch) const
- {
- assert(id);
- unsigned int count = 0;
- // Search immediate children first.
- for (Node* child = getFirstNode(); child != NULL; child = child->getNextSibling())
- {
- // Does this child's ID match?
- if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
- {
- nodes.push_back(child);
- ++count;
- }
- }
- // Recurse.
- if (recursive)
- {
- for (Node* child = getFirstNode(); child != NULL; child = child->getNextSibling())
- {
- count += child->findNodes(id, nodes, true, exactMatch);
- }
- }
- return count;
- }
- Node* Scene::addNode(const char* id)
- {
- Node* node = Node::create(id);
- addNode(node);
- // Call release to decrement the ref count to 1 before returning.
- node->release();
- return node;
- }
- void Scene::addNode(Node* node)
- {
- assert(node);
- if (node->_scene == this)
- {
- // The node is already a member of this scene.
- return;
- }
- node->addRef();
- // If the node is part of another scene, remove it.
- if (node->_scene && node->_scene != this)
- {
- node->_scene->removeNode(node);
- }
- // If the node is part of another node hierarchy, remove it.
- if (node->getParent())
- {
- node->getParent()->removeChild(node);
- }
- // Link the new node into our list.
- if (_lastNode)
- {
- _lastNode->_nextSibling = node;
- node->_prevSibling = _lastNode;
- _lastNode = node;
- }
- else
- {
- _firstNode = _lastNode = node;
- }
- node->_scene = this;
- ++_nodeCount;
- // If we don't have an active camera set, then check for one and set it.
- if (_activeCamera == NULL)
- {
- Camera* camera = node->getCamera();
- if (camera)
- {
- setActiveCamera(camera);
- }
- }
- }
- void Scene::removeNode(Node* node)
- {
- assert(node);
- if (node->_scene != this)
- return;
- if (node == _firstNode)
- {
- _firstNode = node->_nextSibling;
- }
- if (node == _lastNode)
- {
- _lastNode = node->_prevSibling;
- }
- node->remove();
- node->_scene = NULL;
- SAFE_RELEASE(node);
- --_nodeCount;
- }
- void Scene::removeAllNodes()
- {
- while (_lastNode)
- {
- removeNode(_lastNode);
- }
- }
- unsigned int Scene::getNodeCount() const
- {
- return _nodeCount;
- }
- Node* Scene::getFirstNode() const
- {
- return _firstNode;
- }
- Camera* Scene::getActiveCamera() const
- {
- return _activeCamera;
- }
- void Scene::setActiveCamera(Camera* camera)
- {
- // Make sure we don't release the camera if the same camera is set twice.
- if (_activeCamera != camera)
- {
- AudioListener* audioListener = AudioListener::getInstance();
- if (_activeCamera)
- {
- // Unbind the active camera from the audio listener
- if (audioListener && (audioListener->getCamera() == _activeCamera))
- {
- AudioListener::getInstance()->setCamera(NULL);
- }
- SAFE_RELEASE(_activeCamera);
- }
- _activeCamera = camera;
- if (_activeCamera)
- {
- _activeCamera->addRef();
- if (audioListener && _bindAudioListenerToCamera)
- {
- AudioListener::getInstance()->setCamera(_activeCamera);
- }
- }
- }
- }
- void Scene::bindAudioListenerToCamera(bool bind)
- {
- if (_bindAudioListenerToCamera != bind)
- {
- _bindAudioListenerToCamera = bind;
- if (AudioListener::getInstance())
- {
- AudioListener::getInstance()->setCamera(bind ? _activeCamera : NULL);
- }
- }
- }
- const Viewport& Scene::getViewport() const
- {
- return _viewport;
- }
- void Scene::setViewport(const Viewport& viewport)
- {
- _viewport = viewport;
- }
- const Vector3& Scene::getAmbientColor() const
- {
- return _ambientColor;
- }
- void Scene::setAmbientColor(float red, float green, float blue)
- {
- _ambientColor.set(red, green, blue);
- }
- Material* createDebugMaterial()
- {
- // Vertex shader for drawing colored lines.
- const char* vs_str =
- {
- "uniform mat4 u_viewProjectionMatrix;\n"
- "attribute vec4 a_position;\n"
- "attribute vec4 a_color;\n"
- "varying vec4 v_color;\n"
- "void main(void) {\n"
- " v_color = a_color;\n"
- " gl_Position = u_viewProjectionMatrix * a_position;\n"
- "}"
- };
- // Fragment shader for drawing colored lines.
- const char* fs_str =
- {
- #ifdef OPENGL_ES
- "precision highp float;\n"
- #endif
- "varying vec4 v_color;\n"
- "void main(void) {\n"
- " gl_FragColor = v_color;\n"
- "}"
- };
- Effect* effect = Effect::createFromSource(vs_str, fs_str);
- Material* material = Material::create(effect);
- material->getStateBlock()->setDepthTest(true);
- SAFE_RELEASE(effect);
- return material;
- }
- struct DebugVertex
- {
- float x, y, z;
- float r, g, b, a;
- };
- void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point2, const Vector3& color)
- {
- static DebugVertex verts[2];
- verts[0].x = point1.x;
- verts[0].y = point1.y;
- verts[0].z = point1.z;
- verts[0].r = color.x;
- verts[0].g = color.y;
- verts[0].b = color.z;
- verts[0].a = 1.0f;
- verts[1].x = point2.x;
- verts[1].y = point2.y;
- verts[1].z = point2.z;
- verts[1].r = color.x;
- verts[1].g = color.y;
- verts[1].b = color.z;
- verts[1].a = 1.0f;
- batch->add(verts, 2);
- }
- #define DEBUG_BOX_COLOR Vector3(0, 1, 0)
- #define DEBUG_SPHERE_COLOR Vector3(0, 1, 0)
- void drawDebugBox(MeshBatch* batch, const BoundingBox& box, const Matrix& matrix)
- {
- // Transform box into world space (since we only store local boxes on mesh)
- BoundingBox worldSpaceBox(box);
- worldSpaceBox.transform(matrix);
- // Get box corners
- static Vector3 corners[8];
- worldSpaceBox.getCorners(corners);
- // Draw box lines
- drawDebugLine(batch, corners[0], corners[1], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[1], corners[2], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[2], corners[3], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[3], corners[0], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[4], corners[5], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[5], corners[6], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[6], corners[7], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[7], corners[4], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[0], corners[7], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[1], corners[6], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[2], corners[5], DEBUG_BOX_COLOR);
- drawDebugLine(batch, corners[3], corners[4], DEBUG_BOX_COLOR);
- }
- void drawDebugSphere(MeshBatch* batch, const BoundingSphere& sphere)
- {
- // Draw three rings for the sphere (one for the x, y and z axes)
- Vector3 pos1, pos2;
- float step = MATH_PI * 0.2f;
- float max = MATH_PIX2 + step;
- // X ring
- for (float r = 0.0f; r < max; r += step)
- {
- pos2.x = sphere.center.x;
- pos2.y = sphere.center.y + std::cos(r) * sphere.radius;
- pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
- if (r > 0)
- drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
- pos1 = pos2;
- }
- // Y ring
- for (float r = 0.0f; r < max; r += step)
- {
- pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
- pos2.y = sphere.center.y;
- pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
- if (r > 0)
- drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
- pos1 = pos2;
- }
- // Z ring
- for (float r = 0.0f; r < max; r += step)
- {
- pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
- pos2.y = sphere.center.y + std::sin(r) * sphere.radius;
- pos2.z = sphere.center.z;
- if (r > 0)
- drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
- pos1 = pos2;
- }
- }
- void drawDebugNode(MeshBatch* batch, Node* node, unsigned int debugFlags)
- {
- Model* model = node->getModel();
- if ((debugFlags & Scene::DEBUG_BOXES) && model)
- {
- MeshSkin* skin = model->getSkin();
- if (skin && skin->getRootJoint()->getParent())
- {
- // For skinned meshes that have a parent node to the skin's root joint,
- // we need to transform the bounding volume by that parent node's transform
- // as well to get the full skinned bounding volume.
- drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix() * skin->getRootJoint()->getParent()->getWorldMatrix());
- }
- else
- {
- drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix());
- }
- }
- if ((debugFlags & Scene::DEBUG_SPHERES) && model)
- {
- drawDebugSphere(batch, node->getBoundingSphere());
- }
- Node* child = node->getFirstChild();
- while (child)
- {
- drawDebugNode(batch, child, debugFlags);
- child = child->getNextSibling();
- }
- }
- void Scene::drawDebug(unsigned int debugFlags)
- {
- if (_debugBatch == NULL)
- {
- Material* material = createDebugMaterial();
- VertexFormat::Element elements[] =
- {
- VertexFormat::Element(VertexFormat::POSITION, 3),
- VertexFormat::Element(VertexFormat::COLOR, 4)
- };
- _debugBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
- SAFE_RELEASE(material);
- }
- _debugBatch->begin();
- Node* node = _firstNode;
- while (node)
- {
- drawDebugNode(_debugBatch, node, debugFlags);
- node = node->_nextSibling;
- }
- _debugBatch->end();
- if (_activeCamera)
- _debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
- _debugBatch->draw();
- }
- }
|