Просмотр исходного кода

Merge pull request #108 from blackberry-gaming/next-dgough

Next dgough
Sean Paul Taylor 14 лет назад
Родитель
Сommit
170704cbaf

+ 1 - 0
gameplay-encoder/gameplay-encoder.vcxproj

@@ -98,6 +98,7 @@
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="src\Quaternion.inl" />
     <None Include="src\Vector2.inl" />
     <None Include="src\Vector3.inl" />
     <None Include="src\Vector4.inl" />

+ 3 - 0
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -263,6 +263,9 @@
     <None Include="src\Vector4.inl">
       <Filter>src</Filter>
     </None>
+    <None Include="src\Quaternion.inl">
+      <Filter>src</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="src">

+ 81 - 37
gameplay-encoder/src/Quaternion.cpp

@@ -19,6 +19,10 @@ Quaternion::Quaternion(float* array)
     set(array);
 }
 
+Quaternion::Quaternion(const Vector3& axis, float angle)
+{
+    set(axis, angle);
+}
 
 Quaternion::Quaternion(const Quaternion& copy)
 {
@@ -31,14 +35,14 @@ Quaternion::~Quaternion()
 
 const Quaternion& Quaternion::identity()
 {
-    static Quaternion* value = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
-    return *value;
+    static Quaternion value(0.0f, 0.0f, 0.0f, 1.0f);
+    return value;
 }
 
 const Quaternion& Quaternion::zero()
 {
-    static Quaternion* value = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);
-    return *value;
+    static Quaternion value(0.0f, 0.0f, 0.0f, 0.0f);
+    return value;
 }
 
 bool Quaternion::isIdentity() const
@@ -51,13 +55,6 @@ bool Quaternion::isZero() const
     return x == 0.0f && y == 0.0f && z == 0.0f && z == 0.0f;
 }
 
-void Quaternion::createFromRotationMatrix(const Matrix& m, Quaternion* dst)
-{
-    assert(dst);
-
-    m.decompose(NULL, dst, NULL);
-}
-
 void Quaternion::createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst)
 {
     assert(dst);
@@ -154,12 +151,12 @@ void Quaternion::normalize(Quaternion* dst) const
 
     float n = x * x + y * y + z * z + w * w;
 
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < 0.000001f)
         return;
 
@@ -188,6 +185,11 @@ void Quaternion::set(float* array)
     w = array[3];
 }
 
+void Quaternion::set(const Vector3& axis, float angle)
+{
+    Quaternion::createFromAxisAngle(axis, angle, this);
+}
+
 void Quaternion::set(const Quaternion& q)
 {
     this->x = q.x;
@@ -223,6 +225,17 @@ void Quaternion::lerp(const Quaternion& q1, const Quaternion& q2, float t, Quate
     assert(dst);
     assert(!(t < 0.0f || t > 1.0f));
 
+    if (t == 0.0f)
+    {
+        memcpy(dst, &q1, sizeof(float) * 4);
+        return;
+    }
+    else if (t == 1.0f)
+    {
+        memcpy(dst, &q2, sizeof(float) * 4);
+        return;
+    }
+
     float t1 = 1.0f - t;
 
     dst->x = t1 * q1.x + t * q2.x;
@@ -232,21 +245,65 @@ void Quaternion::lerp(const Quaternion& q1, const Quaternion& q2, float t, Quate
 }
 
 void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
+{
+    slerp(q1.x, q1.y, q1.z, q1.w, q2.x, q2.y, q2.z, q2.w, t, &dst->x, &dst->y, &dst->z, &dst->w);
+}
+
+void Quaternion::squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst)
+{
+    assert(dst);
+    assert(!(t < 0.0f || t > 1.0f));
+
+    Quaternion dstQ(0.0f, 0.0f, 0.0f, 1.0f);
+    Quaternion dstS(0.0f, 0.0f, 0.0f, 1.0f);
+
+    slerpForSquad(q1, q2, t, &dstQ);
+    slerpForSquad(s1, s2, t, &dstS);
+    slerpForSquad(dstQ, dstS, 2.0f * t * (1.0f - t), dst);
+}
+
+void Quaternion::slerp(float q1x, float q1y, float q1z, float q1w, float q2x, float q2y, float q2z, float q2w, float t, float* dstx, float* dsty, float* dstz, float* dstw)
 {
     // Fast slerp implementation by kwhatmough:
     // It contains no division operations, no trig, no inverse trig
     // and no sqrt. Not only does this code tolerate small constraint
     // errors in the input quaternions, it actually corrects for them.
-    assert(dst);
+    assert(dstx && dsty && dstz && dstw);
     assert(!(t < 0.0f || t > 1.0f));
 
+    if (t == 0.0f)
+    {
+        *dstx = q1x;
+        *dsty = q1y;
+        *dstz = q1z;
+        *dstw = q1w;
+        return;
+    }
+    else if (t == 1.0f)
+    {
+        *dstx = q2x;
+        *dsty = q2y;
+        *dstz = q2z;
+        *dstw = q2w;
+        return;
+    }
+
+    if (q1x == q2x && q1y == q2y && q1z == q2z && q1w == q2w)
+    {
+        *dstx = q1x;
+        *dsty = q1y;
+        *dstz = q1z;
+        *dstw = q1w;
+        return;
+    }
+
     float halfY, alpha, beta;
     float u, f1, f2a, f2b;
     float ratio1, ratio2;
     float halfSecHalfTheta, versHalfTheta;
     float sqNotU, sqU;
 
-    float cosTheta = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
+    float cosTheta = q1w * q2w + q1x * q2x + q1y * q2y + q1z * q2z;
 
     // As usual in all slerp implementations, we fold theta.
     alpha = cosTheta >= 0 ? 1.0f : -1.0f;
@@ -287,34 +344,21 @@ void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quat
     beta = f1 + f2b;
 
     // Apply final coefficients to a and b as usual.
-    float w = alpha * q1.w + beta * q2.w;
-    float x = alpha * q1.x + beta * q2.x;
-    float y = alpha * q1.y + beta * q2.y;
-    float z = alpha * q1.z + beta * q2.z;
+    float w = alpha * q1w + beta * q2w;
+    float x = alpha * q1x + beta * q2x;
+    float y = alpha * q1y + beta * q2y;
+    float z = alpha * q1z + beta * q2z;
 
     // This final adjustment to the quaternion's length corrects for
-    // any small constraint error in the inputs q1 and q2. But as you
+    // any small constraint error in the inputs q1 and q2 But as you
     // can see, it comes at the cost of 9 additional multiplication
     // operations. If this error-correcting feature is not required,
     // the following code may be removed.
     f1 = 1.5f - 0.5f * (w * w + x * x + y * y + z * z);
-    dst->w = w * f1;
-    dst->x = x * f1;
-    dst->y = y * f1;
-    dst->z = z * f1;
-}
-
-void Quaternion::squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst)
-{
-    assert(dst);
-    assert(!(t < 0.0f || t > 1.0f));
-
-    Quaternion dstQ(0.0f, 0.0f, 0.0f, 1.0f);
-    Quaternion dstS(0.0f, 0.0f, 0.0f, 1.0f);
-
-    slerpForSquad(q1, q2, t, &dstQ);
-    slerpForSquad(s1, s2, t, &dstS);
-    slerpForSquad(dstQ, dstS, 2.0f * t * (1.0f - t), dst);
+    *dstw = w * f1;
+    *dstx = x * f1;
+    *dsty = y * f1;
+    *dstz = z * f1;
 }
 
 void Quaternion::slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)

+ 95 - 39
gameplay-encoder/src/Quaternion.h

@@ -20,41 +20,46 @@ class Matrix;
  * lerp (linear interpolation): the interpolation curve gives a straight line in quaternion space. It is simple and fast to compute. The only problem is that it does not provide constant angular velocity. Note that a constant velocity is not necessarily a requirement for a curve;
  * slerp (spherical linear interpolation): the interpolation curve forms a great arc on the quaternion unit sphere. Slerp provides constant angular velocity;
  * squad (spherical spline interpolation): interpolating between a series of rotations using slerp leads to the following problems:
- * the curve is not smooth at the control points;
- * the angular velocity is not constant;
- * the angular velocity is not continuous at the control points.
+ * - the curve is not smooth at the control points;
+ * - the angular velocity is not constant;
+ * - the angular velocity is not continuous at the control points.
  *
  * Since squad is continuously differentiable, it remedies the first and third problems mentioned above.
  * The slerp method provided here is intended for interpolation of principal rotations. It treats +q and -q as the same principal rotation and is at liberty to use the negative of either input. The resulting path is always the shorter arc.
  *
  * The lerp method provided here interpolates strictly in quaternion space. Note that the resulting path may pass through the origin if interpolating between a quaternion and its exact negative.
  *
- * As an example, consider the following quaternions
+ * As an example, consider the following quaternions:
  *
  * q1 = (0.6, 0.8, 0.0, 0.0),
  * q2 = (0.0, 0.6, 0.8, 0.0),
  * q3 = (0.6, 0.0, 0.8, 0.0), and
  * q4 = (-0.8, 0.0, -0.6, 0.0).
  * For the point p = (1.0, 1.0, 1.0), the following figures show the trajectories of p using lerp, slerp, and squad.
- *
- * @image "http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/math/doc-files/LERP.PNG"
- * @image "http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/math/doc-files/SLERP.PNG"
- * @image "http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/math/doc-files/SQUAD.PNG"
  */
 class Quaternion
 {
+    friend class Curve;
+
 public:
 
-    /** The x-value of the quaternion's vector component. */
+    /**
+     * The x-value of the quaternion's vector component.
+     */
     float x;
-    /** The y-value of the quaternion's vector component. */
+    /**
+     * The y-value of the quaternion's vector component.
+     */
     float y;
-    /** The z-value of the quaternion's vector component. */
+    /**
+     * The z-value of the quaternion's vector component.
+     */
     float z;
-    /** The scalar component of the quaternion. */
+    /**
+     * The scalar component of the quaternion.
+     */
     float w;
 
-
     /**
      * Constructs a quaternion initialized to (0, 0, 0, 1).
      */
@@ -73,14 +78,22 @@ public:
     /**
      * Constructs a new quaternion from the values in the specified array.
      *
-     * @param array
+     * @param array The values for the new quaternion.
      */
     Quaternion(float* array);
 
+    /**
+     * Constructs a quaternion equal to the rotation from the specified axis and angle.
+     *
+     * @param axis A vector describing the axis of rotation.
+     * @param angle The angle of rotation (in radians).
+     */
+    Quaternion(const Vector3& axis, float angle);
+
     /**
      * Constructs a new quaternion that is a copy of the specified one.
      *
-     * @param copy The quaternion to copy
+     * @param copy The quaternion to copy.
      */
     Quaternion(const Quaternion& copy);
 
@@ -92,7 +105,7 @@ public:
     /**
      * Returns the identity quaternion.
      *
-     * @return The quaternion.
+     * @return The identity quaternion.
      */
     static const Quaternion& identity();
 
@@ -104,34 +117,25 @@ public:
     static const Quaternion& zero();
 
     /**
-     * Determines if this quaterion is equal to the identity quaternion.
+     * Determines if this quaternion is equal to the identity quaternion.
      *
-     * @return true if the identity, false otherwise.
+     * @return true if it is the identity quaternion, false otherwise.
      */
     bool isIdentity() const;
 
     /**
-     * Determines if this quaterion is all zeros.
+     * Determines if this quaternion is all zeros.
      *
-     * @return true if zeros, false otherwise.
+     * @return true if this quaternion is all zeros, false otherwise.
      */
     bool isZero() const;
 
-    /**
-     * Create a quaternion equal to the rotational part of the specified matrix
-     * and stores the result in dst.
-     *
-     * @param m The matrix.
-     * @param dst A quaternion to store the conjugate in.
-     */
-    static void createFromRotationMatrix(const Matrix& m, Quaternion* dst);
-
     /**
      * Creates this quaternion equal to the rotation from the specified axis and angle
-     * and store the result in dst.
+     * and stores the result in dst.
      *
      * @param axis A vector describing the axis of rotation.
-     * @param angle The angle of rotation, in radians.
+     * @param angle The angle of rotation (in radians).
      * @param dst A quaternion to store the conjugate in.
      */
     static void createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst);
@@ -226,6 +230,14 @@ public:
      */
     void set(float* array);
 
+    /**
+     * Sets the quaternion equal to the rotation from the specified axis and angle.
+     * 
+     * @param axis The axis of rotation.
+     * @param angle The angle of rotation (in radians).
+     */
+    void set(const Vector3& axis, float angle);
+
     /**
      * Sets the elements of this quaternion to a copy of the specified quaternion.
      *
@@ -256,10 +268,10 @@ public:
      * @param q1 The first quaternion.
      * @param q2 The second quaternion.
      * @param t The interpolation coefficient.
-     * @param dst A quaternion to store the result in
+     * @param dst A quaternion to store the result in.
      */
     static void lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
-
+    
     /**
      * Interpolates between two quaternions using spherical linear interpolation.
      *
@@ -273,10 +285,10 @@ public:
      * @param q1 The first quaternion.
      * @param q2 The second quaternion.
      * @param t The interpolation coefficient.
-     * @param dst A quaternion to store the result in
+     * @param dst A quaternion to store the result in.
      */
     static void slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
-
+    
     /**
      * Interpolates over a series of quaternions using spherical spline interpolation.
      *
@@ -289,20 +301,64 @@ public:
      *
      * @param q1 The first quaternion.
      * @param q2 The second quaternion.
-     * @param s1 The first control point
-     * @param s2 The second control point
+     * @param s1 The first control point.
+     * @param s2 The second control point.
      * @param t The interpolation coefficient.
-     * @param dst A quaternion to store the result in
+     * @param dst A quaternion to store the result in.
      */
     static void squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst);
 
+    /**
+     * Calculates the quaternion product of this quaternion with the given quaternion.
+     * 
+     * Note: this does not modify this quaternion.
+     * 
+     * @param q The quaternion to multiply.
+     * @return The quaternion product.
+     */
+    inline Quaternion operator*(const Quaternion& q) const;
+
+    /**
+     * Multiplies this quaternion with the given quaternion.
+     * 
+     * @param q The quaternion to multiply.
+     * @return This quaternion, after the multiplication occurs.
+     */
+    inline Quaternion& operator*=(const Quaternion& q);
 
 private:
 
-    static void slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
+    /**
+     * Interpolates between two quaternions using spherical linear interpolation.
+     *
+     * Spherical linear interpolation provides smooth transitions between different
+     * orientations and is often useful for animating models or cameras in 3D.
+     *
+     * Note: For accurate interpolation, the input quaternions must be at (or close to) unit length.
+     * This method does not automatically normalize the input quaternions, so it is up to the
+     * caller to ensure they call normalize beforehand, if necessary.
+     *
+     * @param q1x The x component of the first quaternion.
+     * @param q1y The y component of the first quaternion.
+     * @param q1z The z component of the first quaternion.
+     * @param q1w The w component of the first quaternion.
+     * @param q2x The x component of the second quaternion.
+     * @param q2y The y component of the second quaternion.
+     * @param q2z The z component of the second quaternion.
+     * @param q2w The w component of the second quaternion.
+     * @param t The interpolation coefficient.
+     * @param dstx A pointer to store the x component of the slerp in.
+     * @param dsty A pointer to store the y component of the slerp in.
+     * @param dstz A pointer to store the z component of the slerp in.
+     * @param dstw A pointer to store the w component of the slerp in.
+     */
+    static void slerp(float q1x, float q1y, float q1z, float q1w, float q2x, float q2y, float q2z, float q2w, float t, float* dstx, float* dsty, float* dstz, float* dstw);
 
+    static void slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
 };
 
 }
 
+#include "Quaternion.inl"
+
 #endif

+ 19 - 0
gameplay-encoder/src/Quaternion.inl

@@ -0,0 +1,19 @@
+#include "Quaternion.h"
+
+namespace gameplay
+{
+
+inline Quaternion Quaternion::operator*(const Quaternion& q) const
+{
+    Quaternion result(*this);
+    result.multiply(q);
+    return result;
+}
+
+inline Quaternion& Quaternion::operator*=(const Quaternion& q)
+{
+    multiply(q);
+    return *this;
+}
+
+}

+ 5 - 5
gameplay-template/src/TemplateGame.cpp

@@ -58,15 +58,15 @@ bool TemplateGame::drawScene(Node* node, void* cookie)
     return true;
 }
 
-void TemplateGame::touch(int x, int y, int touchEvent)
+void TemplateGame::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
-    switch (touchEvent)
+    switch (evt)
     {
-    case Input::TOUCHEVENT_PRESS:
+    case Touch::TOUCH_PRESS:
         break;
-    case Input::TOUCHEVENT_RELEASE:
+    case Touch::TOUCH_RELEASE:
         break;
-    case Input::TOUCHEVENT_MOVE:
+    case Touch::TOUCH_MOVE:
         break;
     };
 }

+ 1 - 1
gameplay-template/src/TemplateGame.h

@@ -20,7 +20,7 @@ public:
     /**
      * Touch event handler.
      */
-    void touch(int x, int y, int touchEvent);
+    void touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
 protected:
 

+ 1 - 0
gameplay/gameplay.vcxproj

@@ -115,6 +115,7 @@
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\Material.h" />
     <ClInclude Include="src\MeshBatch.h" />
+    <ClInclude Include="src\Mouse.h" />
     <ClInclude Include="src\Pass.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />

+ 3 - 0
gameplay/gameplay.vcxproj.filters

@@ -434,6 +434,9 @@
     <ClInclude Include="src\MeshBatch.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Mouse.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">

+ 3 - 3
gameplay/src/BoundingBox.cpp

@@ -69,9 +69,9 @@ bool BoundingBox::intersects(const BoundingSphere& sphere) const
 
 bool BoundingBox::intersects(const BoundingBox& box) const
 {
-    return ((min.x >= box.min.x && min.x <= max.x) || (box.min.x >= min.x && box.min.x <= max.x)) &&
-            ((min.y >= box.min.y && min.y <= max.y) || (box.min.y >= min.y && box.min.y <= max.y)) &&
-            ((min.z >= box.min.z && min.z <= max.z) || (box.min.z >= min.z && box.min.z <= max.z));
+    return ((min.x >= box.min.x && min.x <= box.max.x) || (box.min.x >= min.x && box.min.x <= max.x)) &&
+            ((min.y >= box.min.y && min.y <= box.max.y) || (box.min.y >= min.y && box.min.y <= max.y)) &&
+            ((min.z >= box.min.z && min.z <= box.max.z) || (box.min.z >= min.z && box.min.z <= max.z));
 }
 
 bool BoundingBox::intersects(const Frustum& frustum) const

+ 77 - 0
gameplay/src/FileSystem.cpp

@@ -1,6 +1,14 @@
 #include "Base.h"
 #include "FileSystem.h"
 
+#ifdef WIN32
+    #include <windows.h>
+    #include <tchar.h>
+    #include <stdio.h>
+#else
+    #include <dirent.h>
+#endif
+
 namespace gameplay
 {
 
@@ -24,6 +32,75 @@ const char* FileSystem::getResourcePath()
     return __resourcePath.c_str();
 }
 
+bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
+{
+    // TODO make this method work with absolute and relative paths.
+#ifdef WIN32
+    std::string path(FileSystem::getResourcePath());
+    if (dirPath && strlen(dirPath) > 0)
+    {
+        path.append(dirPath);
+    }
+    path.append("/*");
+    // Convert char to wchar
+    std::basic_string<TCHAR> wPath;
+    wPath.assign(path.begin(), path.end());
+
+    WIN32_FIND_DATA FindFileData;
+    HANDLE hFind = FindFirstFile(wPath.c_str(), &FindFileData);
+    if (hFind == INVALID_HANDLE_VALUE) 
+    {
+        return false;
+    }
+    do
+    {
+        // Add to the list if this is not a directory
+        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+        {
+            // Convert wchar to char
+            std::basic_string<TCHAR> wfilename(FindFileData.cFileName);
+            std::string filename;
+            filename.assign(wfilename.begin(), wfilename.end());
+            files.push_back(filename);
+        }
+    } while(FindNextFile(hFind, &FindFileData) != 0);
+
+    FindClose(hFind);
+    return true;
+#else
+    std::string path(FileSystem::getResourcePath());
+    if (dirPath && strlen(dirPath) > 0)
+	{
+		path.append(dirPath);
+	}
+    path.append("/.");
+    struct dirent* dp;
+    DIR* dir = opendir(path.c_str());
+    if (!dir)
+    {
+        return false;
+    }
+	while ((dp = readdir(dir)) != NULL)
+	{
+		std::string filepath(path);
+		filepath.append("/");
+		filepath.append(dp->d_name);
+
+		struct stat buf;
+		if (!stat(filepath.c_str(), &buf))
+		{
+            // Add to the list if this is not a directory
+			if (!S_ISDIR(buf.st_mode))
+			{
+				files.push_back(dp->d_name);
+			}
+		}
+	}
+	closedir(dir);
+    return true;
+#endif
+}
+
 FILE* FileSystem::openFile(const char* path, const char* mode)
 {
     std::string fullPath(__resourcePath);

+ 10 - 0
gameplay/src/FileSystem.h

@@ -33,6 +33,16 @@ public:
      */
     static const char* getResourcePath();
 
+    /**
+     * Lists the files in the specified directory and adds the files to the vector. Excludes directories.
+     * 
+     * @param dirPath Directory path relative to the path set in <code>setResourcePath(const char*)</code>.
+     * @param files The vector to append the files to.
+     * 
+     * @return True if successful, false if error.
+     */
+    static bool listFiles(const char* dirPath, std::vector<std::string>& files);
+
     /**
      * Opens the specified file.
      *

+ 9 - 0
gameplay/src/Game.cpp

@@ -250,4 +250,13 @@ void Game::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactI
 {
 }
 
+bool Game::mouseEvent(Mouse::MouseEvent evt, int x, int y)
+{
+    return false;
+}
+
+void Game::mouseWheelEvent(int x, int y, int delta)
+{
+}
+
 }

+ 24 - 0
gameplay/src/Game.h

@@ -3,6 +3,7 @@
 
 #include "Keyboard.h"
 #include "Touch.h"
+#include "Mouse.h"
 #include "AudioController.h"
 #include "AnimationController.h"
 #include "PhysicsController.h"
@@ -208,6 +209,29 @@ public:
      */
     virtual void touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Mouse callback on mouse events. If the game does not consume the mouse move event or left mouse click event
+     * then it is interpreted as a touch event instead.
+     *
+     * @param evt The mouse event that occurred.
+     * @param x The x position of the mouse in pixels. Left edge is zero.
+     * @param y The y position of the mouse in pixels. Top edge is zero.
+     *
+     * @return True if the mouse event is consumed or false if it is not consumed.
+     *
+     * @see Mouse::MouseEvent
+     */
+    virtual bool mouseEvent(Mouse::MouseEvent evt, int x, int y);
+
+    /**
+     * Mouse callback on mouse wheel events.
+     *
+     * @param x The x position of the mouse in pixels. Left edge is zero.
+     * @param y The y position of the mouse in pixels. Top edge is zero.
+     * @param delta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
+     */
+    virtual void mouseWheelEvent(int x, int y, int delta);
+
     /**
      * Sets muli-touch is to be enabled/disabled. Default is disabled.
      *

+ 39 - 0
gameplay/src/Mouse.h

@@ -0,0 +1,39 @@
+#ifndef MOUSE_H_
+#define MOUSE_H_
+
+namespace gameplay
+{
+
+/**
+ * Mouse event
+ */
+class Mouse
+{
+public:
+
+    /**
+     * The mouse event type.
+     */
+    enum MouseEvent
+    {
+        MOUSE_LEFT_BUTTON_PRESS,
+        MOUSE_LEFT_BUTTON_RELEASE,
+        MOUSE_MIDDLE_BUTTON_PRESS,
+        MOUSE_MIDDLE_BUTTON_RELEASE,
+        MOUSE_RIGHT_BUTTON_PRESS,
+        MOUSE_RIGHT_BUTTON_RELEASE,
+        MOUSE_MOVE
+    };
+
+
+private:
+
+    /**
+     * Constructor. Used internally.
+     */
+    Mouse();
+};
+
+}
+
+#endif

+ 105 - 2
gameplay/src/PlatformQNX.cpp

@@ -665,6 +665,23 @@ long timespec2millis(struct timespec *a)
     return a->tv_sec*1000 + a->tv_nsec/1000000;
 }
 
+/**
+ * Fires a mouse event or a touch event on the game.
+ * If the mouse event is not consumed, a touch event is fired instead.
+ *
+ * @param mouseEvent The mouse event to fire.
+ * @param touchEvent The touch event to fire.
+ * @param x The x position of the touch in pixels.
+ * @param y The y position of the touch in pixels.
+ */
+void mouseOrTouchEvent(Mouse::MouseEvent mouseEvent, Touch::TouchEvent touchEvent, int x, int y)
+{
+    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y))
+    {
+        Game::getInstance()->touchEvent(touchEvent, x, y, 0);
+    }
+}
+
 int Platform::enterMessagePump()
 {
     int rc;
@@ -710,7 +727,7 @@ int Platform::enterMessagePump()
                         if (!__multiTouch)
                         {
                             screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_POSITION, position);
-                           Game::getInstance()->touchEvent(Touch::TOUCH_PRESS, position[0], position[1], 0);
+                            Game::getInstance()->touchEvent(Touch::TOUCH_PRESS, position[0], position[1], 0);
                         }
                         else
                         {
@@ -725,7 +742,7 @@ int Platform::enterMessagePump()
                         if (!__multiTouch)
                         {
                             screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_POSITION, position);
-                           Game::getInstance()->touchEvent(Touch::TOUCH_RELEASE, position[0], position[1], 0);
+                            Game::getInstance()->touchEvent(Touch::TOUCH_RELEASE, position[0], position[1], 0);
                         }
                         else
                         {
@@ -751,6 +768,92 @@ int Platform::enterMessagePump()
                         break;
                     }
 
+                    case SCREEN_EVENT_POINTER:
+                    {
+                        static int mouse_pressed = 0;
+                        int buttons;
+                        int wheel;
+                        // A move event will be fired unless a button state changed.
+                        bool move = true;
+                        bool left_move = false;
+                        //This is a mouse move event, it is applicable to a device with a usb mouse or simulator
+                        screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
+                        screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
+                        screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
+
+                        // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
+                        if (buttons & SCREEN_LEFT_MOUSE_BUTTON)
+                        {
+                            if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON)
+                            {
+                                left_move = true;
+                            }
+                            else
+                            {
+                                move = false;
+                                mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
+                                mouseOrTouchEvent(Mouse::MOUSE_LEFT_BUTTON_PRESS, Touch::TOUCH_PRESS, position[0], position[1]);
+                            }
+                        }
+                        else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON)
+                        {
+                            move = false;
+                            mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
+                            mouseOrTouchEvent(Mouse::MOUSE_LEFT_BUTTON_RELEASE, Touch::TOUCH_RELEASE, position[0], position[1]);
+                        }
+
+                        // Handle right mouse
+                        if (buttons & SCREEN_RIGHT_MOUSE_BUTTON)
+                        {
+                            if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON == 0)
+                            {
+                                move = false;
+                                mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
+                                Game::getInstance()->mouseEvent(Mouse::MOUSE_RIGHT_BUTTON_PRESS, position[0], position[1]);
+                            }
+                        }
+                        else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON)
+                        {
+                            move = false;
+                            mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_RIGHT_BUTTON_RELEASE, position[0], position[1]);
+                        }
+
+                        // Handle middle mouse
+                        if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON)
+                        {
+                            if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON == 0)
+                            {
+                                move = false;
+                                mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
+                                Game::getInstance()->mouseEvent(Mouse::MOUSE_MIDDLE_BUTTON_PRESS, position[0], position[1]);
+                            }
+                        }
+                        else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON)
+                        {
+                            move = false;
+                            mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_MIDDLE_BUTTON_RELEASE, position[0], position[1]);
+                        }
+
+                        // Fire a move event if none of the buttons changed.
+                        if (left_move)
+                        {
+                            mouseOrTouchEvent(Mouse::MOUSE_MOVE, Touch::TOUCH_MOVE, position[0], position[1]);
+                        }
+                        else if (move)
+                        {
+                            Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, position[0], position[1]);
+                        }
+
+                        // Handle mouse wheel events
+                        if (wheel)
+                        {
+                            Game::getInstance()->mouseWheelEvent(position[0], position[1], -wheel);
+                        }
+                        break;
+                    }
+
                     case SCREEN_EVENT_KEYBOARD:
                     {
                         screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);

+ 27 - 3
gameplay/src/PlatformWin32.cpp

@@ -267,26 +267,43 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         return 0;
 
     case WM_LBUTTONDOWN:
-        gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
+        if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_LEFT_BUTTON_PRESS, LOWORD(lParam), HIWORD(lParam)))
+        {
+            gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
+        }
         lMouseDown = true;
         return 0;
 
     case WM_LBUTTONUP:
         lMouseDown = false;
-        gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
+        if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_LEFT_BUTTON_RELEASE, LOWORD(lParam), HIWORD(lParam)))
+        {
+            gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
+        }
         return 0;
 
     case WM_RBUTTONDOWN:
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RIGHT_BUTTON_PRESS, LOWORD(lParam), HIWORD(lParam));
         rMouseDown = true;
         lx = LOWORD(lParam);
         ly = HIWORD(lParam);
         break;
 
     case WM_RBUTTONUP:
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RIGHT_BUTTON_RELEASE, LOWORD(lParam), HIWORD(lParam));
         rMouseDown = false;
         break;
 
+    case WM_MBUTTONDOWN:
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MIDDLE_BUTTON_PRESS, LOWORD(lParam), HIWORD(lParam));
+        break;
+
+    case WM_MBUTTONUP:
+        gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MIDDLE_BUTTON_RELEASE, LOWORD(lParam), HIWORD(lParam));
+        break;
+
     case WM_MOUSEMOVE:
+    {
         if (!hasMouse)
         {
             hasMouse = true;
@@ -299,8 +316,10 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             TrackMouseEvent(&tme);
         }
 
-        if (lMouseDown)
+        bool consumed = gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_MOVE, LOWORD(lParam), HIWORD(lParam));
+        if (lMouseDown && !consumed)
         {
+            // Mouse move events should be interpreted as touch move only if left mouse is held and the game did not consume the mouse event.
             gameplay::Game::getInstance()->touchEvent(gameplay::Touch::TOUCH_MOVE, LOWORD(lParam), HIWORD(lParam), 0);
             return 0;
         }
@@ -319,6 +338,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             ly = HIWORD(lParam);
         }
         break;
+    }
 
     case WM_MOUSELEAVE:
         hasMouse = false;
@@ -326,6 +346,10 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         rMouseDown = false;
         break;
 
+    case WM_MOUSEWHEEL:
+        gameplay::Game::getInstance()->mouseWheelEvent(LOWORD(lParam), HIWORD(lParam), GET_WHEEL_DELTA_WPARAM(wParam) / 120);
+        break;
+
     case WM_KEYDOWN:
         if (wParam == VK_LSHIFT || wParam == VK_RSHIFT)
             shiftDown = true;

+ 1 - 0
gameplay/src/gameplay.h

@@ -4,6 +4,7 @@
 #include "Game.h"
 #include "Keyboard.h"
 #include "Touch.h"
+#include "Mouse.h"
 #include "FileSystem.h"
 #include "Package.h"