ソースを参照

Added support for defining Lights within a .scene file.
Fixed issue with Node::getBoundingSphere returning an empty sphere for nodes that have terrain attached to them.
Added Frustum::getNearCorners and Frustum::getFarCorners methods to allow fewer computations when only the near or far plane corners are needed.

Steve Grenier 13 年 前
コミット
17eeb40c19

+ 16 - 4
gameplay/src/Frustum.cpp

@@ -62,6 +62,12 @@ void Frustum::getMatrix(Matrix* dst) const
 }
 
 void Frustum::getCorners(Vector3* corners) const
+{
+    getNearCorners(corners);
+    getFarCorners(corners + 4);
+}
+
+void Frustum::getNearCorners(Vector3* corners) const
 {
     GP_ASSERT(corners);
 
@@ -69,10 +75,16 @@ void Frustum::getCorners(Vector3* corners) const
     Plane::intersection(_near, _left, _bottom, &corners[1]);
     Plane::intersection(_near, _right, _bottom, &corners[2]);
     Plane::intersection(_near, _right, _top, &corners[3]);
-    Plane::intersection(_far, _right, _top, &corners[4]);
-    Plane::intersection(_far, _right, _bottom, &corners[5]);
-    Plane::intersection(_far, _left, _bottom, &corners[6]);
-    Plane::intersection(_far, _left, _top, &corners[7]);
+}
+
+void Frustum::getFarCorners(Vector3* corners) const
+{
+    GP_ASSERT(corners);
+
+    Plane::intersection(_far, _right, _top, &corners[0]);
+    Plane::intersection(_far, _right, _bottom, &corners[1]);
+    Plane::intersection(_far, _left, _bottom, &corners[2]);
+    Plane::intersection(_far, _left, _top, &corners[3]);
 }
 
 bool Frustum::intersects(const Vector3& point) const

+ 21 - 1
gameplay/src/Frustum.h

@@ -109,10 +109,30 @@ public:
      * (N-near, F-far, L-left, R-right, B-bottom, T-top)
      * LTN, LBN, RBN, RTN, RTF, RBF, LBF, LTF.
      * 
-     * @param corners The array to store the corners in.
+     * @param corners The array (of at least size 8) to store the corners in.
      */
     void getCorners(Vector3* corners) const;
 
+    /**
+     * Gets the corners of the frustum's near plane in the specified array.
+     *
+     * The corners are stored in the following order:
+     * left-top, left-bottom, right-bottom, right-top.
+     *
+     * @param corners The array (of at least size 4) to store the corners in.
+     */
+    void getNearCorners(Vector3* corners) const;
+
+    /**
+     * Gets the corners of the frustum's far plane in the specified array.
+     *
+     * The corners are stored in the following order:
+     * right-top, right-bottom, left-bottom, left-top.
+     *
+     * @param corners The array (of at least size 4) to store the corners in.
+     */
+    void getFarCorners(Vector3* corners) const;
+
     /**
      * Tests whether this frustum intersects the specified point.
      *

+ 79 - 0
gameplay/src/Light.cpp

@@ -72,6 +72,85 @@ Light* Light::createSpot(float red, float green, float blue, float range, float
     return new Light(SPOT, Vector3(red, green, blue), range, innerAngle, outerAngle);
 }
 
+Light* Light::create(Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    // Read light type
+    std::string typeStr;
+    if (properties->exists("type"))
+        typeStr = properties->getString("type");
+    Light::Type type;
+    if (typeStr == "DIRECTIONAL")
+    {
+        type = Light::DIRECTIONAL;
+    }
+    else if (typeStr == "POINT")
+    {
+        type = Light::POINT;
+    }
+    else if (typeStr == "SPOT")
+    {
+        type = Light::SPOT;
+    }
+    else
+    {
+        GP_ERROR("Invalid 'type' parameter for light definition.");
+        return NULL;
+    }
+
+    // Read common parameters
+    Vector3 color;
+    if (!properties->getVector3("color", &color))
+    {
+        GP_ERROR("Missing valid 'color' parameter for light definition.");
+        return NULL;
+    }
+
+    // Read light-specific parameters
+    Light* light = NULL;
+    switch (type)
+    {
+    case DIRECTIONAL:
+        light = createDirectional(color);
+        break;
+    case POINT:
+        {
+            float range = properties->getFloat("range");
+            if (range == 0.0f)
+            {
+                GP_ERROR("Missing valid 'range' parameter for point light definition.");
+                return NULL;
+            }
+            light = createPoint(color, range);
+        }
+        break;
+    case SPOT:
+            float range = properties->getFloat("range");
+            if (range == 0.0f)
+            {
+                GP_ERROR("Missing valid 'range' parameter for spot light definition.");
+                return NULL;
+            }
+            float innerAngle = properties->getFloat("innerAngle");
+            if (innerAngle == 0.0f)
+            {
+                GP_ERROR("Missing valid 'innerAngle' parameter for spot light definition.");
+                return NULL;
+            }
+            float outerAngle = properties->getFloat("outerAngle");
+            if (outerAngle == 0.0f)
+            {
+                GP_ERROR("Missing valid 'outerAngle' parameter for spot light definition.");
+                return NULL;
+            }
+            light = createSpot(color, range, innerAngle, outerAngle);
+        break;
+    }
+
+    return light;
+}
+
 Light::Type Light::getLightType() const
 {
     return _type;

+ 14 - 0
gameplay/src/Light.h

@@ -3,6 +3,7 @@
 
 #include "Ref.h"
 #include "Vector3.h"
+#include "Properties.h"
 
 namespace gameplay
 {
@@ -103,6 +104,19 @@ public:
      */
     static Light* createSpot(float red, float green, float blue, float range, float innerAngle, float outerAngle);
 
+    /**
+     * Creates a light from a properties definition.
+     *
+     * The properties object must contain a "type" parameter, specifying one of the
+     * supported Light::Type values. In addition, values must be supplied for all
+     * parameters of the corresponding light-specific creation method.
+     *
+     * @param properties The properties definition of the Light.
+     *
+     * @return The new Light.
+     */
+    static Light* create(Properties* properties);
+
     /**
      * Destructor.
      */

+ 1 - 1
gameplay/src/Node.cpp

@@ -874,7 +874,7 @@ const BoundingSphere& Node::getBoundingSphere() const
                 _bounds.merge(_model->getMesh()->getBoundingSphere());
             }
         }
-        else
+        if (empty)
         {
             // Empty bounding sphere, set the world translation with zero radius
             worldMatrix.getTranslation(&_bounds.center);

+ 20 - 0
gameplay/src/SceneLoader.cpp

@@ -4,6 +4,7 @@
 #include "Bundle.h"
 #include "SceneLoader.h"
 #include "Terrain.h"
+#include "Light.h"
 
 namespace gameplay
 {
@@ -81,6 +82,7 @@ Scene* SceneLoader::loadInternal(const char* url)
         SceneNodeProperty::MATERIAL | 
         SceneNodeProperty::PARTICLE |
         SceneNodeProperty::TERRAIN |
+        SceneNodeProperty::LIGHT |
         SceneNodeProperty::CAMERA |
         SceneNodeProperty::ROTATE |
         SceneNodeProperty::SCALE |
@@ -211,6 +213,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
         snp._type == SceneNodeProperty::MATERIAL ||
         snp._type == SceneNodeProperty::PARTICLE ||
         snp._type == SceneNodeProperty::TERRAIN ||
+        snp._type == SceneNodeProperty::LIGHT ||
         snp._type == SceneNodeProperty::CAMERA ||
         snp._type == SceneNodeProperty::COLLISION_OBJECT)
     {
@@ -261,6 +264,13 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             SAFE_RELEASE(terrain);
             break;
         }
+        case SceneNodeProperty::LIGHT:
+        {
+            Light* light = Light::create(p);
+            node->setLight(light);
+            SAFE_RELEASE(light);
+            break;
+        }
         case SceneNodeProperty::CAMERA:
         {
             Camera* camera = Camera::create(p);
@@ -575,6 +585,12 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::TERRAIN, propertyUrl.c_str());
                     _properties[propertyUrl] = subns;
                 }
+                else if (strcmp(subns->getNamespace(), "light") == 0)
+                {
+                    propertyUrl += "light/" + std::string(subns->getId());
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::LIGHT, propertyUrl.c_str());
+                    _properties[propertyUrl] = subns;
+                }
                 else if (strcmp(subns->getNamespace(), "camera") == 0)
                 {
                     propertyUrl += "camera/" + std::string(subns->getId());
@@ -631,6 +647,10 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::TERRAIN, ns->getString());
                 }
+                else if (strcmp(name, "light") == 0)
+                {
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::LIGHT, ns->getString());
+                }
                 else if (strcmp(name, "camera") == 0)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::CAMERA, ns->getString());

+ 7 - 6
gameplay/src/SceneLoader.h

@@ -50,12 +50,13 @@ private:
             MATERIAL = 2,
             PARTICLE = 4,
             TERRAIN = 8,
-            CAMERA = 16,
-            COLLISION_OBJECT = 32,
-            TRANSLATE = 64,
-            ROTATE = 128,
-            SCALE = 256,
-            URL = 512
+            LIGHT = 16,
+            CAMERA = 32,
+            COLLISION_OBJECT = 64,
+            TRANSLATE = 128,
+            ROTATE = 256,
+            SCALE = 512,
+            URL = 1024
         };
 
         SceneNodeProperty(Type type, const std::string& url, int index);