Procházet zdrojové kódy

Added memory leak detection support (when GAMEPLAY_MEM_LEAK_DETECTION is defined - off by default) for tracking new/delete allocations and also gameplay::Ref allocations.
Added DebugMem configurations in visual studio project for windows platform, which builds with memory leak detection enabled.
Fixed a number of memory leaks and memory corruption issues throughout the gameplay library and samples.
Fixed a bug where ParticleEmitter was incorrectly changing depth write state outside of StateBlocks, causing StateBlock's "default state" to get out of sync with GL.

Steve Grenier před 14 roky
rodič
revize
420da906ac

+ 13 - 0
gameplay.sln

@@ -28,31 +28,44 @@ EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
 		Debug|Win32 = Debug|Win32
+		DebugMem|Win32 = DebugMem|Win32
 		Release|Win32 = Release|Win32
 		Release|Win32 = Release|Win32
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|Win32.ActiveCfg = Debug|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|Win32.ActiveCfg = Debug|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|Win32.Build.0 = Debug|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|Win32.Build.0 = Debug|Win32
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.ActiveCfg = Release|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.ActiveCfg = Release|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.Build.0 = Release|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.Build.0 = Release|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.Build.0 = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.Build.0 = Debug|Win32
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|Win32.ActiveCfg = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|Win32.ActiveCfg = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|Win32.Build.0 = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|Win32.Build.0 = Release|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|Win32.ActiveCfg = Debug|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|Win32.ActiveCfg = Debug|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|Win32.Build.0 = Debug|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|Win32.Build.0 = Debug|Win32
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|Win32.ActiveCfg = Release|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|Win32.ActiveCfg = Release|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|Win32.Build.0 = Release|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|Win32.Build.0 = Release|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|Win32.ActiveCfg = Debug|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|Win32.ActiveCfg = Debug|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|Win32.Build.0 = Debug|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|Win32.Build.0 = Debug|Win32
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|Win32.ActiveCfg = Release|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|Win32.ActiveCfg = Release|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|Win32.Build.0 = Release|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|Win32.Build.0 = Release|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.Build.0 = Debug|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.Build.0 = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.ActiveCfg = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.Build.0 = Debug|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.ActiveCfg = Release|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.ActiveCfg = Release|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.Build.0 = Release|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	EndGlobalSection

+ 41 - 0
gameplay/gameplay.vcxproj

@@ -1,6 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
   <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="DebugMem|Win32">
+      <Configuration>DebugMem</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
     <ProjectConfiguration Include="Debug|Win32">
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
       <Configuration>Debug</Configuration>
       <Platform>Win32</Platform>
       <Platform>Win32</Platform>
@@ -24,6 +28,7 @@
     <ClCompile Include="src\BoundingSphere.cpp" />
     <ClCompile Include="src\BoundingSphere.cpp" />
     <ClCompile Include="src\Camera.cpp" />
     <ClCompile Include="src\Camera.cpp" />
     <ClCompile Include="src\Curve.cpp" />
     <ClCompile Include="src\Curve.cpp" />
+    <ClCompile Include="src\DebugNew.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\FileSystem.cpp" />
     <ClCompile Include="src\FileSystem.cpp" />
     <ClCompile Include="src\Font.cpp" />
     <ClCompile Include="src\Font.cpp" />
@@ -79,6 +84,7 @@
     <ClInclude Include="src\BoundingSphere.h" />
     <ClInclude Include="src\BoundingSphere.h" />
     <ClInclude Include="src\Camera.h" />
     <ClInclude Include="src\Camera.h" />
     <ClInclude Include="src\Curve.h" />
     <ClInclude Include="src\Curve.h" />
+    <ClInclude Include="src\DebugNew.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\FileSystem.h" />
     <ClInclude Include="src\FileSystem.h" />
     <ClInclude Include="src\Font.h" />
     <ClInclude Include="src\Font.h" />
@@ -155,6 +161,11 @@
     <UseDebugLibraries>true</UseDebugLibraries>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>Unicode</CharacterSet>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <UseDebugLibraries>false</UseDebugLibraries>
@@ -167,6 +178,9 @@
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
   </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
   </ImportGroup>
@@ -174,9 +188,15 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <OutDir>$(Configuration)\</OutDir>
     <OutDir>$(Configuration)\</OutDir>
   </PropertyGroup>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <OutDir>$(Configuration)\</OutDir>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <IntDir>$(Configuration)\</IntDir>
     <IntDir>$(Configuration)\</IntDir>
   </PropertyGroup>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <IntDir>$(Configuration)\</IntDir>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <OutDir>$(Configuration)\</OutDir>
     <OutDir>$(Configuration)\</OutDir>
   </PropertyGroup>
   </PropertyGroup>
@@ -191,11 +211,32 @@
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>
+      </RuntimeTypeInfo>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;GAMEPLAY_MEM_LEAK_DETECTION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Windows</SubSystem>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     </Link>
+    <Lib>
+      <Verbose>
+      </Verbose>
+    </Lib>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <ClCompile>
     <ClCompile>

+ 6 - 0
gameplay/gameplay.vcxproj.filters

@@ -168,6 +168,9 @@
     <ClCompile Include="src\RenderState.cpp">
     <ClCompile Include="src\RenderState.cpp">
       <Filter>src</Filter>
       <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="src\DebugNew.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
     <ClInclude Include="src\Animation.h">
@@ -338,6 +341,9 @@
     <ClInclude Include="src\RenderState.h">
     <ClInclude Include="src\RenderState.h">
       <Filter>src</Filter>
       <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="src\DebugNew.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">
     <None Include="res\shaders\bumped-specular.vsh">

+ 0 - 2
gameplay/src/Animation.cpp

@@ -64,7 +64,6 @@ Animation::Channel::Channel(AnimationTarget* target, int propertyId, Curve* curv
     assert(target->getAnimationPropertyComponentCount(propertyId));
     assert(target->getAnimationPropertyComponentCount(propertyId));
 
 
     _target = target;
     _target = target;
-    _target->addRef();
     _propertyId = propertyId;
     _propertyId = propertyId;
     _curve = curve;
     _curve = curve;
     _duration = duration;
     _duration = duration;
@@ -72,7 +71,6 @@ Animation::Channel::Channel(AnimationTarget* target, int propertyId, Curve* curv
 
 
 Animation::Channel::~Channel()
 Animation::Channel::~Channel()
 {
 {
-    SAFE_RELEASE(_target);
     SAFE_DELETE(_curve);
     SAFE_DELETE(_curve);
 }
 }
 
 

+ 8 - 24
gameplay/src/AnimationClip.cpp

@@ -27,37 +27,21 @@ AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long
 
 
 AnimationClip::~AnimationClip()
 AnimationClip::~AnimationClip()
 {
 {
+    // Explicitly stop this clip if it's currently playing so it gets removed from the controller
+    if (_isPlaying)
+    {
+        stop();
+    }
+
     std::vector<AnimationValue*>::iterator valueIter = _values.begin();
     std::vector<AnimationValue*>::iterator valueIter = _values.begin();
     while (valueIter != _values.end())
     while (valueIter != _values.end())
     {
     {
         SAFE_DELETE(*valueIter);
         SAFE_DELETE(*valueIter);
         valueIter++;
         valueIter++;
     }
     }
-    _values.clear();
-
-    if (_beginListeners)
-    {
-        std::vector<Listener*>::iterator bIter = _beginListeners->begin();
-        while (bIter != _beginListeners->end())
-        {
-            SAFE_DELETE(*bIter);
-            bIter++;
-        }
-        _beginListeners->clear();
-        SAFE_DELETE(_beginListeners);
-    }
 
 
-    if (_endListeners)
-    {
-        std::vector<Listener*>::iterator eIter = _endListeners->begin();
-        while (eIter != _endListeners->end())
-        {
-            SAFE_DELETE(*eIter);
-            eIter++;
-        }
-        _endListeners->clear();
-        SAFE_DELETE(_endListeners);
-    }
+    SAFE_DELETE(_beginListeners);
+    SAFE_DELETE(_endListeners);
 }
 }
 
 
 const char* AnimationClip::getID() const
 const char* AnimationClip::getID() const

+ 3 - 1
gameplay/src/AnimationController.cpp

@@ -113,11 +113,11 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     while (clipIter != _runningClips.end())
     {
     {
         AnimationClip* clip = *clipIter;
         AnimationClip* clip = *clipIter;
-        clipIter = _runningClips.erase(clipIter);
         clip->_isPlaying = false;
         clip->_isPlaying = false;
         SAFE_RELEASE(clip);
         SAFE_RELEASE(clip);
         clipIter++;
         clipIter++;
     }
     }
+    _runningClips.clear();
 
 
     _state = IDLE;
     _state = IDLE;
 }
 }
@@ -229,6 +229,8 @@ void AnimationController::destroyAnimation(Animation* animation)
 
 
 void AnimationController::destroyAllAnimations()
 void AnimationController::destroyAllAnimations()
 {
 {
+    stopAllAnimations();
+
     std::vector<Animation*>::iterator itr = _animations.begin();
     std::vector<Animation*>::iterator itr = _animations.begin();
     
     
     while (itr != _animations.end())
     while (itr != _animations.end())

+ 1 - 2
gameplay/src/AudioSource.cpp

@@ -167,14 +167,13 @@ void AudioSource::setNode(Node* node)
         if (_node)
         if (_node)
         {
         {
             _node->removeListener(this);
             _node->removeListener(this);
-            SAFE_RELEASE(_node);
         }
         }
 
 
         // Connect the new node.
         // Connect the new node.
         _node = node;
         _node = node;
+
         if (_node)
         if (_node)
         {
         {
-            _node->addRef();
             _node->addListener(this);
             _node->addListener(this);
         }
         }
     }
     }

+ 8 - 2
gameplay/src/Base.h

@@ -5,6 +5,8 @@
 #define BASE_H_
 #define BASE_H_
 
 
 // C/C++
 // C/C++
+#include <new>
+#include <cstdio>
 #include <cassert>
 #include <cassert>
 #include <memory>
 #include <memory>
 #include <iostream>
 #include <iostream>
@@ -20,7 +22,6 @@
 #include <hash_map>
 #include <hash_map>
 #include <algorithm>
 #include <algorithm>
 #include <ctime>
 #include <ctime>
-#include <cstdio>
 #include <limits>
 #include <limits>
 #include <functional>
 #include <functional>
 #include <string.h>
 #include <string.h>
@@ -62,6 +63,11 @@ extern void printError(const char* format, ...);
 #define WARN(x) printError(x)
 #define WARN(x) printError(x)
 #define WARN_VARG(x, ...) printError(x, __VA_ARGS__)
 #define WARN_VARG(x, ...) printError(x, __VA_ARGS__)
 
 
+// Debug new for memory leak detection
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#include "DebugNew.h"
+#endif
+
 // Object deletion macro
 // Object deletion macro
 #define SAFE_DELETE(x) \
 #define SAFE_DELETE(x) \
     if (x) \
     if (x) \
@@ -239,4 +245,4 @@ extern GLenum __gl_error_code;
     #pragma warning( disable : 4996 )
     #pragma warning( disable : 4996 )
 #endif
 #endif
 
 
-#endif 
+#endif

+ 1 - 6
gameplay/src/Camera.cpp

@@ -36,7 +36,6 @@ Camera::Camera(float zoomX, float zoomY, float aspectRatio, float nearPlane, flo
 
 
 Camera::~Camera()
 Camera::~Camera()
 {
 {
-    SAFE_RELEASE(_node);
 }
 }
 
 
 Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
 Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
@@ -144,17 +143,13 @@ void Camera::setNode(Node* node)
         if (_node)
         if (_node)
         {
         {
             _node->removeListener(this);
             _node->removeListener(this);
-
-            // Disconnect our current node.
-            SAFE_RELEASE(_node);
         }
         }
 
 
         // Connect the new node.
         // Connect the new node.
         _node = node;
         _node = node;
+
         if (_node)
         if (_node)
         {
         {
-            _node->addRef();
-
             _node->addListener(this);
             _node->addListener(this);
         }
         }
 
 

+ 1 - 0
gameplay/src/Curve.cpp

@@ -31,6 +31,7 @@ Curve::Curve(unsigned int pointCount, unsigned int componentCount)
 Curve::~Curve()
 Curve::~Curve()
 {
 {
     SAFE_DELETE_ARRAY(_points);
     SAFE_DELETE_ARRAY(_points);
+    SAFE_DELETE_ARRAY(_quaternionOffsets);
 }
 }
 
 
 Curve::Point::Point()
 Curve::Point::Point()

+ 162 - 0
gameplay/src/DebugNew.cpp

@@ -0,0 +1,162 @@
+/**
+ * DebugNew.cpp
+ */
+
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+
+#include <new>
+#include <exception>
+#include <cstdio>
+#include <cstdarg>
+
+struct MemoryAllocationRecord
+{
+    unsigned long address;          // address returned to the caller after allocation
+    unsigned int size;              // size of the allocation request
+    const char* file;               // source file of allocation request
+    int line;                       // source line of the allocation request
+    MemoryAllocationRecord* next;
+    MemoryAllocationRecord* prev;
+};
+
+MemoryAllocationRecord* __memoryAllocations = 0;
+int __memoryAllocationCount = 0;
+
+void* debugAlloc(std::size_t size, const char* file, int line);
+void debugFree(void* p);
+
+#ifdef _MSC_VER
+#pragma warning( disable : 4290 )
+#endif
+
+void* operator new (std::size_t size, const char* file, int line)
+{
+    return debugAlloc(size, file, line);
+}
+
+void* operator new[] (std::size_t size, const char* file, int line)
+{
+    return operator new (size, file, line);
+}
+
+void* operator new (std::size_t size) throw(std::bad_alloc)
+{
+    return operator new (size, "", 0);
+}
+
+void* operator new[] (std::size_t size) throw(std::bad_alloc)
+{
+    return operator new (size, "", 0);
+}
+
+void* operator new (std::size_t size, const std::nothrow_t&) throw()
+{
+    return operator new (size, "", 0);
+}
+
+void* operator new[] (std::size_t size, const std::nothrow_t&) throw()
+{
+    return operator new (size, "", 0);
+}
+
+void operator delete (void* p) throw()
+{
+    debugFree(p);
+}
+
+void operator delete[] (void* p) throw()
+{
+    operator delete (p);
+}
+
+void operator delete (void* p, const char* file, int line) throw()
+{
+    operator delete (p);
+}
+
+void operator delete[] (void* p, const char* file, int line) throw()
+{
+    operator delete (p);
+}
+
+#ifdef _MSC_VER
+#pragma warning( default : 4290 )
+#endif
+
+// Include Base.h (needed for logging macros) AFTER new operator impls
+#include "Base.h"
+
+void* debugAlloc(size_t size, const char* file, int line)
+{
+    // Allocate memory + size for a MemoryAlloctionRecord
+    unsigned char* mem = (unsigned char*)malloc(size + sizeof(MemoryAllocationRecord));
+
+    MemoryAllocationRecord* rec = (MemoryAllocationRecord*)mem;
+
+    // Move memory pointer past record
+    mem += sizeof(MemoryAllocationRecord);
+
+    rec->address = (unsigned long)mem;
+    rec->size = size;
+    rec->file = file;
+    rec->line = line;
+    rec->next = __memoryAllocations;
+    rec->prev = 0;
+
+    if (__memoryAllocations)
+        __memoryAllocations->prev = rec;
+    __memoryAllocations = rec;
+    ++__memoryAllocationCount;
+
+    return mem;
+}
+
+void debugFree(void* p)
+{
+    assert(p);
+
+    // Backup passed in pointer to access memory allocation record
+    void* mem = ((unsigned char*)p) - sizeof(MemoryAllocationRecord);
+
+    MemoryAllocationRecord* rec = (MemoryAllocationRecord*)mem;
+
+    // Sanity check: ensure that address in record matches passed in address
+    if (rec->address != (unsigned long)p)
+    {
+        gameplay::printError("[memory] CORRUPTION: Attempting to free memory address with invalid memory allocation record.");
+        return;
+    }
+
+    // Link this item out
+    if (__memoryAllocations == rec)
+        __memoryAllocations = rec->next;
+    if (rec->prev)
+        rec->prev->next = rec->next;
+    if (rec->next)
+        rec->next->prev = rec->prev;
+    --__memoryAllocationCount;
+
+    // Free the address from the original alloc location (before mem allocation record)
+    free(mem);
+}
+
+extern void printMemoryLeaks()
+{
+    // Dump general heap memory leaks
+    if (__memoryAllocationCount == 0)
+    {
+        gameplay::printError("[memory] All HEAP allocations successfully cleaned up (no leaks detected).");
+    }
+    else
+    {
+        gameplay::printError("[memory] WARNING: %d HEAP allocations still active in memory.", __memoryAllocationCount);
+        MemoryAllocationRecord* rec = __memoryAllocations;
+        while (rec)
+        {
+            gameplay::printError("[memory] LEAK: HEAP allocation leak of size %d leak from line %d in file '%s'.", rec->size, rec->line, rec->file);
+            rec = rec->next;
+        }
+    }
+}
+
+#endif

+ 42 - 0
gameplay/src/DebugNew.h

@@ -0,0 +1,42 @@
+/**
+ * DebugNew.h
+ *
+ * Global overrides of the new and delete operators for memory tracking.
+ * This file is only included when memory leak detection is explicitly
+ * request via the pre-processor defintion GAMEPLAY_MEM_LEAK_DETECTION.
+ */
+
+#ifndef DEBUGNEW_H_
+#define DEBUGNEW_H_
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+
+#include <new>
+#include <exception>
+
+// Prints all heap and reference leaks to stderr.
+extern void printMemoryLeaks();
+
+// global new/delete operator overloads
+#ifdef _MSC_VER
+#pragma warning( disable : 4290 ) // C++ exception specification ignored.
+#endif
+void* operator new (std::size_t size, const char* file, int line);
+void* operator new[] (std::size_t size, const char* file, int line);
+void* operator new (std::size_t size) throw(std::bad_alloc);
+void* operator new[] (std::size_t size) throw(std::bad_alloc);
+void* operator new (std::size_t size, const std::nothrow_t&) throw();
+void* operator new[] (std::size_t size, const std::nothrow_t&) throw();
+void operator delete (void* p) throw();
+void operator delete[] (void* p) throw();
+void operator delete (void* p, const char* file, int line) throw();
+void operator delete[] (void* p, const char* file, int line) throw();
+#ifdef _MSC_VER
+#pragma warning( default : 4290 )
+#endif
+
+// Re-define new to use versions with file and line number
+#define DEBUG_NEW new (__FILE__, __LINE__)
+#define new DEBUG_NEW
+
+#endif
+#endif

+ 32 - 13
gameplay/src/Game.cpp

@@ -5,6 +5,7 @@
 #include "Base.h"
 #include "Base.h"
 #include "Game.h"
 #include "Game.h"
 #include "Platform.h"
 #include "Platform.h"
+#include "RenderState.h"
 
 
 // Extern global variables
 // Extern global variables
 GLenum __gl_error_code = GL_NO_ERROR;
 GLenum __gl_error_code = GL_NO_ERROR;
@@ -19,7 +20,8 @@ long Game::_pausedTimeTotal = 0L;
 Game::Game() 
 Game::Game() 
     : _state(UNINITIALIZED), 
     : _state(UNINITIALIZED), 
       _frameLastFPS(0), _frameCount(0), _frameRate(0), 
       _frameLastFPS(0), _frameCount(0), _frameRate(0), 
-      _clearColor(Vector4::zero()), _clearDepth(1.0f), _clearStencil(0)
+      _clearDepth(1.0f), _clearStencil(0),
+      _animationController(NULL), _audioController(NULL)
 {
 {
     assert(__gameInstance == NULL);
     assert(__gameInstance == NULL);
     __gameInstance = this;
     __gameInstance = this;
@@ -33,6 +35,11 @@ Game::~Game()
 {
 {
     // Do not call any virtual functions from the destructor.
     // Do not call any virtual functions from the destructor.
     // Finalization is done from outside this class.
     // Finalization is done from outside this class.
+
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+    Ref::printLeaks();
+    printMemoryLeaks();
+#endif
 }
 }
 
 
 Game* Game::getInstance()
 Game* Game::getInstance()
@@ -92,8 +99,13 @@ bool Game::startup()
     if (_state != UNINITIALIZED)
     if (_state != UNINITIALIZED)
         return false;
         return false;
 
 
-    _animationController.initialize();
-    _audioController.initialize();
+    RenderState::initialize();
+
+    _animationController = new AnimationController();
+    _animationController->initialize();
+
+    _audioController = new AudioController();
+    _audioController->initialize();
 
 
     // Call user initialization.
     // Call user initialization.
     initialize();
     initialize();
@@ -109,8 +121,15 @@ void Game::shutdown()
     {
     {
         finalize();
         finalize();
 
 
-        _animationController.finalize();
-        _audioController.finalize();
+        _animationController->finalize();
+        delete _animationController;
+        _animationController = NULL;
+
+        _audioController->finalize();
+        delete _audioController;
+        _audioController = NULL;
+
+        RenderState::finalize();
     }
     }
 
 
     _state = UNINITIALIZED;
     _state = UNINITIALIZED;
@@ -122,8 +141,8 @@ void Game::pause()
     {
     {
         _state = PAUSED;
         _state = PAUSED;
         _pausedTimeLast = Platform::getAbsoluteTime();
         _pausedTimeLast = Platform::getAbsoluteTime();
-        _animationController.pause();
-        _audioController.pause();
+        _animationController->pause();
+        _audioController->pause();
     }
     }
 }
 }
 
 
@@ -133,8 +152,8 @@ void Game::resume()
     {
     {
         _state = RUNNING;
         _state = RUNNING;
         _pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
         _pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
-        _animationController.resume();
-        _audioController.resume();
+        _animationController->resume();
+        _audioController->resume();
     }
     }
 }
 }
 
 
@@ -155,12 +174,12 @@ void Game::frame()
     lastFrameTime = frameTime;
     lastFrameTime = frameTime;
 
 
     // Update the schedule and running animations.
     // Update the schedule and running animations.
-    _animationController.update(elapsedTime);
+    _animationController->update(elapsedTime);
     // Application Update.
     // Application Update.
     update(elapsedTime);
     update(elapsedTime);
 
 
     // Audio Rendering.
     // Audio Rendering.
-    _audioController.update(elapsedTime);
+    _audioController->update(elapsedTime);
     // Graphics Rendering.
     // Graphics Rendering.
     render(elapsedTime);
     render(elapsedTime);
 
 
@@ -224,10 +243,10 @@ void Game::clear(ClearFlags flags, const Vector4& clearColor, float clearDepth,
 
 
 AnimationController* Game::getAnimationController()
 AnimationController* Game::getAnimationController()
 {
 {
-    return &_animationController;
+    return _animationController;
 }
 }
 
 
-const AudioController& Game::getAudioController() const
+const AudioController* Game::getAudioController() const
 {
 {
     return _audioController;
     return _audioController;
 }
 }

+ 4 - 8
gameplay/src/Game.h

@@ -18,7 +18,6 @@ namespace gameplay
  */
  */
 class Game
 class Game
 {
 {
-
 public:
 public:
 
 
     /**
     /**
@@ -34,8 +33,7 @@ public:
     /**
     /**
      * Flags used when clearing the active frame buffer targets.
      * Flags used when clearing the active frame buffer targets.
      */
      */
-
-     enum ClearFlags
+    enum ClearFlags
     {
     {
         CLEAR_COLOR = GL_COLOR_BUFFER_BIT,
         CLEAR_COLOR = GL_COLOR_BUFFER_BIT,
         CLEAR_DEPTH = GL_DEPTH_BUFFER_BIT,
         CLEAR_DEPTH = GL_DEPTH_BUFFER_BIT,
@@ -46,8 +44,6 @@ public:
         CLEAR_COLOR_DEPTH_STENCIL = CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL
         CLEAR_COLOR_DEPTH_STENCIL = CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL
     };
     };
 
 
-
-
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
@@ -168,7 +164,7 @@ public:
      *
      *
      * @return The audio controller for this game.
      * @return The audio controller for this game.
      */
      */
-    const AudioController& getAudioController() const;
+    const AudioController* getAudioController() const;
 
 
     /**
     /**
      * Gets the animation controller for managing control of animations
      * Gets the animation controller for managing control of animations
@@ -279,8 +275,8 @@ private:
     Vector4 _clearColor;                        // The clear color value last used for clearing the color buffer.
     Vector4 _clearColor;                        // The clear color value last used for clearing the color buffer.
     float _clearDepth;                          // The clear depth value last used for clearing the depth buffer.
     float _clearDepth;                          // The clear depth value last used for clearing the depth buffer.
     int _clearStencil;                          // The clear stencil value last used for clearing the stencil buffer.
     int _clearStencil;                          // The clear stencil value last used for clearing the stencil buffer.
-    AnimationController _animationController;   // Controls the scheduling and running of animations.
-    AudioController _audioController;           // Controls audio sources that are playing in the game.
+    AnimationController* _animationController;  // Controls the scheduling and running of animations.
+    AudioController* _audioController;          // Controls audio sources that are playing in the game.
 };
 };
 
 
 }
 }

+ 2 - 13
gameplay/src/Light.cpp

@@ -70,19 +70,8 @@ Node* Light::getNode() const
 
 
 void Light::setNode(Node* node)
 void Light::setNode(Node* node)
 {
 {
-    if (_node != node)
-    {
-        // Disconnect our current node.
-        SAFE_RELEASE(_node);
-
-        // Connect the new node.
-        _node = node;
-
-        if (_node)
-        {
-            _node->addRef();
-        }
-    }
+    // Connect the new node.
+    _node = node;
 }
 }
 
 
 const Vector3& Light::getColor() const
 const Vector3& Light::getColor() const

+ 2 - 0
gameplay/src/MaterialParameter.h

@@ -269,6 +269,7 @@ void MaterialParameter::bindValue(ClassType* classInstance, ParameterType (Class
     clearValue();
     clearValue();
 
 
     _value.method = new MethodValueBinding<ClassType, ParameterType>(this, classInstance, valueMethod);
     _value.method = new MethodValueBinding<ClassType, ParameterType>(this, classInstance, valueMethod);
+    _dynamic = true;
     _type = MaterialParameter::METHOD;
     _type = MaterialParameter::METHOD;
 }
 }
 
 
@@ -278,6 +279,7 @@ void MaterialParameter::bindValue(ClassType* classInstance, ParameterType (Class
     clearValue();
     clearValue();
 
 
     _value.method = new MethodArrayBinding<ClassType, ParameterType>(this, classInstance, valueMethod, countMethod);
     _value.method = new MethodArrayBinding<ClassType, ParameterType>(this, classInstance, valueMethod, countMethod);
+    _dynamic = true;
     _type = MaterialParameter::METHOD;
     _type = MaterialParameter::METHOD;
 }
 }
 
 

+ 12 - 10
gameplay/src/Matrix.cpp

@@ -44,20 +44,22 @@ Matrix::~Matrix()
 
 
 const Matrix& Matrix::identity()
 const Matrix& Matrix::identity()
 {
 {
-    static Matrix* m = new Matrix( 1, 0, 0, 0,
-                                   0, 1, 0, 0,
-                                   0, 0, 1, 0,
-                                   0, 0, 0, 1 );
-    return *m;
+    static Matrix m(
+        1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        0, 0, 0, 1 );
+    return m;
 }
 }
 
 
 const Matrix& Matrix::zero()
 const Matrix& Matrix::zero()
 {
 {
-    static Matrix* m = new Matrix( 0, 0, 0, 0,
-                                   0, 0, 0, 0,
-                                   0, 0, 0, 0,
-                                   0, 0, 0, 0 );
-    return *m;
+    static Matrix m(
+        0, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 0,
+        0, 0, 0, 0 );
+    return m;
 }
 }
 
 
 void Matrix::createLookAt(const Vector3& eyePosition, const Vector3& targetPosition, const Vector3& up, Matrix* dst)
 void Matrix::createLookAt(const Vector3& eyePosition, const Vector3& targetPosition, const Vector3& up, Matrix* dst)

+ 0 - 11
gameplay/src/MeshSkin.cpp

@@ -80,13 +80,7 @@ void MeshSkin::setJoint(Joint* joint, unsigned int index)
 {
 {
     assert(index < _joints.size());
     assert(index < _joints.size());
 
 
-    if (_joints[index])
-    {
-        SAFE_RELEASE(_joints[index]);
-    }
-
     _joints[index] = joint;
     _joints[index] = joint;
-    joint->addRef();
 }
 }
 
 
 Vector4* MeshSkin::getMatrixPalette() const
 Vector4* MeshSkin::getMatrixPalette() const
@@ -112,11 +106,6 @@ Joint* MeshSkin::getJoint(unsigned int index) const
 
 
 void MeshSkin::clearJoints()
 void MeshSkin::clearJoints()
 {
 {
-    unsigned int prevCount = _joints.size();
-    for (unsigned int i = 0; i < prevCount; i++)
-    {
-        SAFE_RELEASE(_joints[i]);
-    }
     _joints.clear();
     _joints.clear();
 }
 }
 
 

+ 1 - 11
gameplay/src/Model.cpp

@@ -197,17 +197,7 @@ Node* Model::getNode() const
 
 
 void Model::setNode(Node* node)
 void Model::setNode(Node* node)
 {
 {
-    if (_node != node)
-    {
-        SAFE_RELEASE(_node);
-
-        _node = node;
-
-        if (_node)
-        {
-            node->addRef();
-        }
-    }
+    _node = node;
 
 
     // Re-bind node related material parameters
     // Re-bind node related material parameters
     if (node)
     if (node)

+ 23 - 35
gameplay/src/Node.cpp

@@ -80,11 +80,22 @@ void Node::addChild(Node* child)
 {
 {
     assert(child);
     assert(child);
 
 
+    if (child->_parent == this)
+    {
+        // This node is already present in our hierarchy
+        return;
+    }
+
+    child->addRef();
+
     // If the item belongs to another hierarchy, remove it first.
     // If the item belongs to another hierarchy, remove it first.
-    Node* parent = child->_parent;
-    if (parent)
+    if (child->_parent)
     {
     {
-        parent->removeChild(child);
+        child->_parent->removeChild(child);
+    }
+    else if (child->_scene)
+    {
+        child->_scene->removeNode(child);
     }
     }
 
 
     // Order is irrelevant, so add to the beginning of the list.
     // Order is irrelevant, so add to the beginning of the list.
@@ -103,9 +114,10 @@ void Node::addChild(Node* child)
 
 
     ++_childCount;
     ++_childCount;
 
 
-    // Fire events.
-    child->parentChanged(parent);
-    childAdded(child);
+    if (_notifyHierarchyChanged)
+    {
+        hierarchyChanged();
+    }
 }
 }
 
 
 void Node::removeChild(Node* child)
 void Node::removeChild(Node* child)
@@ -118,6 +130,8 @@ void Node::removeChild(Node* child)
 
 
     // Call remove on the child.
     // Call remove on the child.
     child->remove();
     child->remove();
+
+    SAFE_RELEASE(child);
 }
 }
 
 
 void Node::removeAllChildren()
 void Node::removeAllChildren()
@@ -133,7 +147,7 @@ void Node::removeAllChildren()
     hierarchyChanged();
     hierarchyChanged();
 }
 }
 
 
-void Node   ::remove()
+void Node::remove()
 {
 {
     // Re-link our neighbours.
     // Re-link our neighbours.
     if (_prevSibling)
     if (_prevSibling)
@@ -161,11 +175,9 @@ void Node   ::remove()
     _prevSibling = NULL;
     _prevSibling = NULL;
     _parent = NULL;
     _parent = NULL;
 
 
-    // Fire events.
-    if (parent)
+    if (parent && parent->_notifyHierarchyChanged)
     {
     {
-        parentChanged(parent);
-        parent->childRemoved(this);
+        parent->hierarchyChanged();
     }
     }
 }
 }
 
 
@@ -788,28 +800,4 @@ void Node::setParticleEmitter(ParticleEmitter* emitter)
     }
     }
 }
 }
 
 
-void Node::childAdded(Node* child)
-{
-    child->addRef();
-
-    if (_notifyHierarchyChanged)
-    {
-        hierarchyChanged();
-    }
-}
-
-void Node::childRemoved(Node* child)
-{
-    SAFE_RELEASE(child);
-
-    if (_notifyHierarchyChanged)
-    {
-        hierarchyChanged();
-    }
-}
-
-void Node::parentChanged(Node* oldParent)
-{
-}
-
 }
 }

+ 0 - 21
gameplay/src/Node.h

@@ -414,27 +414,6 @@ protected:
      */
      */
     void remove();
     void remove();
 
 
-    /**
-     * Called when a child is added to this item in the tree.
-     * 
-     * @param child The child that was added.
-     */
-    virtual void childAdded(Node* child);
-
-    /**
-     * Called when a child is removed from this item in the tree.
-     *
-     * @param child The child that was removed.
-     */
-    virtual void childRemoved(Node* child);
-
-    /**
-     * Called when the parent of this node changes.
-     *
-     * @param oldParent The previous parent for this node.
-     */
-    virtual void parentChanged(Node* oldParent);
-
     void transformChanged();
     void transformChanged();
 
 
     void hierarchyChanged();
     void hierarchyChanged();

+ 6 - 0
gameplay/src/Package.cpp

@@ -488,6 +488,7 @@ Node* Package::readNode(Scene* sceneContext, Node* nodeContext)
     if (camera)
     if (camera)
     {
     {
         node->setCamera(camera);
         node->setCamera(camera);
+        SAFE_RELEASE(camera);
     }
     }
 
 
     // Read light
     // Read light
@@ -495,6 +496,7 @@ Node* Package::readNode(Scene* sceneContext, Node* nodeContext)
     if (light)
     if (light)
     {
     {
         node->setLight(light);
         node->setLight(light);
+        SAFE_RELEASE(light);
     }
     }
 
 
     // Read model
     // Read model
@@ -502,6 +504,7 @@ Node* Package::readNode(Scene* sceneContext, Node* nodeContext)
     if (model)
     if (model)
     {
     {
         node->setModel(model);
         node->setModel(model);
+        SAFE_RELEASE(model);
     }
     }
 
 
     return node;
     return node;
@@ -639,6 +642,7 @@ Model* Package::readModel(Scene* sceneContext, Node* nodeContext)
         if (mesh)
         if (mesh)
         {
         {
             Model* model = Model::create(mesh);
             Model* model = Model::create(mesh);
+            SAFE_RELEASE(mesh);
 
 
             // Read skin
             // Read skin
             unsigned char hasSkin;
             unsigned char hasSkin;
@@ -1075,10 +1079,12 @@ Mesh* Package::loadMesh(const char* id)
         if (part == NULL)
         if (part == NULL)
         {
         {
             LOG_ERROR_VARG("Failed to create mesh part (i=%d): %s", i, id);
             LOG_ERROR_VARG("Failed to create mesh part (i=%d): %s", i, id);
+            SAFE_DELETE_ARRAY(indexData);
             SAFE_RELEASE(mesh);
             SAFE_RELEASE(mesh);
             return NULL;
             return NULL;
         }
         }
         part->setIndexData(indexData, 0, indexCount);
         part->setIndexData(indexData, 0, indexCount);
+        SAFE_DELETE_ARRAY(indexData);
     }
     }
 
 
     fseek(_file, position, SEEK_SET);
     fseek(_file, position, SEEK_SET);

+ 10 - 23
gameplay/src/ParticleEmitter.cpp

@@ -34,11 +34,12 @@ ParticleEmitter::ParticleEmitter(SpriteBatch* batch, unsigned int particleCountM
     _timePerEmission(EMISSION_RATE_TIME_INTERVAL), _timeLast(0L), _timeRunning(0L)
     _timePerEmission(EMISSION_RATE_TIME_INTERVAL), _timeLast(0L), _timeRunning(0L)
 {
 {
     _particles = new Particle[particleCountMax];
     _particles = new Particle[particleCountMax];
+
+    _spriteBatch->getStateBlock()->setDepthWrite(false);
 }
 }
 
 
 ParticleEmitter::~ParticleEmitter()
 ParticleEmitter::~ParticleEmitter()
 {
 {
-    SAFE_RELEASE(_node);
     SAFE_DELETE(_spriteBatch);
     SAFE_DELETE(_spriteBatch);
     SAFE_DELETE_ARRAY(_particles);
     SAFE_DELETE_ARRAY(_particles);
     SAFE_DELETE_ARRAY(_spriteTextureCoords);
     SAFE_DELETE_ARRAY(_spriteTextureCoords);
@@ -60,6 +61,7 @@ ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlendin
 
 
     // Use default SpriteBatch material.
     // Use default SpriteBatch material.
     SpriteBatch* batch =  SpriteBatch::create(texture, NULL, particleCountMax);
     SpriteBatch* batch =  SpriteBatch::create(texture, NULL, particleCountMax);
+    texture->release(); // batch owns the texture
     assert(batch);
     assert(batch);
 
 
     ParticleEmitter* emitter = new ParticleEmitter(batch, particleCountMax);
     ParticleEmitter* emitter = new ParticleEmitter(batch, particleCountMax);
@@ -71,7 +73,9 @@ ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlendin
     emitter->_spriteTextureHeight = texture->getHeight();
     emitter->_spriteTextureHeight = texture->getHeight();
     emitter->_spriteTextureWidthRatio = 1.0f / (float)texture->getWidth();
     emitter->_spriteTextureWidthRatio = 1.0f / (float)texture->getWidth();
     emitter->_spriteTextureHeightRatio = 1.0f / (float)texture->getHeight();
     emitter->_spriteTextureHeightRatio = 1.0f / (float)texture->getHeight();
-    emitter->setSpriteFrameCoords(1, new Rectangle((float)texture->getWidth(), (float)texture->getHeight()));
+
+    Rectangle texCoord((float)texture->getWidth(), (float)texture->getHeight());
+    emitter->setSpriteFrameCoords(1, &texCoord);
 
 
     return emitter;
     return emitter;
 }
 }
@@ -618,6 +622,8 @@ void ParticleEmitter::setSpriteFrameCoords(unsigned int frameCount, int width, i
     }
     }
 
 
     setSpriteFrameCoords(frameCount, frameCoords);
     setSpriteFrameCoords(frameCount, frameCoords);
+
+    SAFE_DELETE_ARRAY(frameCoords);
 }
 }
 
 
 Node* ParticleEmitter::getNode() const
 Node* ParticleEmitter::getNode() const
@@ -627,19 +633,8 @@ Node* ParticleEmitter::getNode() const
 
 
 void ParticleEmitter::setNode(Node* node)
 void ParticleEmitter::setNode(Node* node)
 {
 {
-    if (_node != node)
-    {
-        // Disconnect our current node.
-        SAFE_RELEASE(_node);
-
-        // Connect the new node.
-        _node = node;
-
-        if (_node)
-        {
-            _node->addRef();
-        }
-    }
+    // Connect the new node.
+    _node = node;
 }
 }
 
 
 void ParticleEmitter::setOrbit(bool orbitPosition, bool orbitVelocity, bool orbitAcceleration)
 void ParticleEmitter::setOrbit(bool orbitPosition, bool orbitVelocity, bool orbitAcceleration)
@@ -889,16 +884,8 @@ void ParticleEmitter::draw()
             }
             }
         }
         }
 
 
-        // Disable writing to the depth buffer.
-        GLboolean depthMask;
-        glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
-        glDepthMask(GL_FALSE);
-
         // Render.
         // Render.
         _spriteBatch->end();
         _spriteBatch->end();
-
-        // Turn the depth mask back on if it was on before.
-        glDepthMask(depthMask);
     }
     }
 }
 }
 
 

+ 5 - 5
gameplay/src/Platform.h

@@ -17,6 +17,11 @@ class Platform
 {
 {
 public:
 public:
 
 
+    /**
+     * Destructor.
+     */
+    ~Platform();
+
     /**
     /**
      * Creates a platform for the specified game which is will interacte with.
      * Creates a platform for the specified game which is will interacte with.
      *
      *
@@ -98,11 +103,6 @@ private:
      */
      */
     Platform(const Platform& copy);
     Platform(const Platform& copy);
 
 
-    /**
-     * Destructor.
-     */
-    ~Platform();
-
     Game* _game;
     Game* _game;
 
 
 };
 };

+ 4 - 4
gameplay/src/Quaternion.cpp

@@ -35,14 +35,14 @@ Quaternion::~Quaternion()
 
 
 const Quaternion& Quaternion::identity()
 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()
 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
 bool Quaternion::isIdentity() const

+ 86 - 0
gameplay/src/Ref.cpp

@@ -4,13 +4,22 @@
 
 
 #include "Base.h"
 #include "Base.h"
 #include "Ref.h"
 #include "Ref.h"
+#include "Game.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+void* trackRef(Ref* ref);
+void untrackRef(Ref* ref, void* record);
+#endif
+
 Ref::Ref() :
 Ref::Ref() :
     _refCount(1)
     _refCount(1)
 {
 {
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+    __record = trackRef(this);
+#endif
 }
 }
 
 
 Ref::~Ref()
 Ref::~Ref()
@@ -26,8 +35,85 @@ void Ref::release()
 {
 {
     if ((--_refCount) <= 0)
     if ((--_refCount) <= 0)
     {
     {
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+        untrackRef(this, __record);
+#endif
         delete this;
         delete this;
     }
     }
 }
 }
 
 
+unsigned int Ref::getRefCount() const
+{
+    return _refCount;
+}
+
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+
+struct RefAllocationRecord
+{
+    Ref* ref;
+    RefAllocationRecord* next;
+    RefAllocationRecord* prev;
+};
+
+RefAllocationRecord* __refAllocations = 0;
+int __refAllocationCount = 0;
+
+void Ref::printLeaks()
+{
+    // Dump Ref object memory leaks
+    if (__refAllocationCount == 0)
+    {
+        printError("[memory] All Ref objects successfully cleaned up (no leaks detected).");
+    }
+    else
+    {
+        printError("[memory] WARNING: %d Ref objects still active in memory.", __refAllocationCount);
+        for (RefAllocationRecord* rec = __refAllocations; rec != NULL; rec = rec->next)
+        {
+            Ref* ref = rec->ref;
+            const char* type = typeid(*ref).name();
+            printError("[memory] LEAK: Ref object '%s' still active with reference count %d.", (type ? type : ""), ref->getRefCount());
+        }
+    }
+}
+
+void* trackRef(Ref* ref)
+{
+    // Create memory allocation record
+    RefAllocationRecord* rec = (RefAllocationRecord*)malloc(sizeof(RefAllocationRecord));
+    rec->ref = ref;
+    rec->next = __refAllocations;
+    rec->prev = 0;
+
+    if (__refAllocations)
+        __refAllocations->prev = rec;
+    __refAllocations = rec;
+    ++__refAllocationCount;
+
+    return rec;
+}
+
+void untrackRef(Ref* ref, void* record)
+{
+    RefAllocationRecord* rec = (RefAllocationRecord*)record;
+    if (rec->ref != ref)
+    {
+        printError("[memory] CORRUPTION: Attempting to free Ref with invalid ref tracking record.");
+        return;
+    }
+
+    // Link this item out
+    if (__refAllocations == rec)
+        __refAllocations = rec->next;
+    if (rec->prev)
+        rec->prev->next = rec->next;
+    if (rec->next)
+        rec->next->prev = rec->prev;
+    free((void*)rec);
+    --__refAllocationCount;
+}
+
+#endif
+
 }
 }

+ 14 - 0
gameplay/src/Ref.h

@@ -40,6 +40,13 @@ public:
      */
      */
     void release();
     void release();
 
 
+    /**
+     * Returns the current reference count of this object.
+     *
+     * @return This object's reference count.
+     */
+    unsigned int getRefCount() const;
+
 protected:
 protected:
 
 
     /**
     /**
@@ -55,6 +62,13 @@ protected:
 private:
 private:
 
 
     unsigned int _refCount;
     unsigned int _refCount;
+
+    // Memory leak diagnostic data (only included when GAMEPLAY_MEM_LEAK_DETECTION is defined)
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+    friend class Game;
+    static void printLeaks();
+    void* __record;
+#endif
 };
 };
 
 
 }
 }

+ 43 - 30
gameplay/src/RenderState.cpp

@@ -18,7 +18,7 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-RenderState::StateBlock RenderState::StateBlock::_defaultState;
+RenderState::StateBlock* RenderState::StateBlock::_defaultState = NULL;
 
 
 RenderState::RenderState()
 RenderState::RenderState()
     : _nodeBinding(NULL), _state(NULL), _parent(NULL)
     : _nodeBinding(NULL), _state(NULL), _parent(NULL)
@@ -44,6 +44,19 @@ RenderState::~RenderState()
     }
     }
 }
 }
 
 
+void RenderState::initialize()
+{
+    if (StateBlock::_defaultState == NULL)
+    {
+        StateBlock::_defaultState = StateBlock::create();
+    }
+}
+
+void RenderState::finalize()
+{
+    SAFE_RELEASE(StateBlock::_defaultState);
+}
+
 MaterialParameter* RenderState::getParameter(const char* name) const
 MaterialParameter* RenderState::getParameter(const char* name) const
 {
 {
     assert(name);
     assert(name);
@@ -305,75 +318,75 @@ void RenderState::StateBlock::bind()
 void RenderState::StateBlock::bindNoRestore()
 void RenderState::StateBlock::bindNoRestore()
 {
 {
     // Update any state that differs from _defaultState and flip _defaultState bits
     // Update any state that differs from _defaultState and flip _defaultState bits
-    if ((_bits & RS_BLEND) && (_blendEnabled != _defaultState._blendEnabled))
+    if ((_bits & RS_BLEND) && (_blendEnabled != _defaultState->_blendEnabled))
     {
     {
         _blendEnabled ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
         _blendEnabled ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
-        _defaultState._blendEnabled = _blendEnabled;
+        _defaultState->_blendEnabled = _blendEnabled;
     }
     }
-    if ((_bits & RS_BLEND_FUNC) && (_srcBlend != _defaultState._srcBlend || _dstBlend != _defaultState._dstBlend))
+    if ((_bits & RS_BLEND_FUNC) && (_srcBlend != _defaultState->_srcBlend || _dstBlend != _defaultState->_dstBlend))
     {
     {
         glBlendFunc((GLenum)_srcBlend, (GLenum)_dstBlend);
         glBlendFunc((GLenum)_srcBlend, (GLenum)_dstBlend);
-        _defaultState._srcBlend = _srcBlend;
-        _defaultState._dstBlend = _dstBlend;
+        _defaultState->_srcBlend = _srcBlend;
+        _defaultState->_dstBlend = _dstBlend;
     }
     }
-    if ((_bits & RS_CULL_FACE) && (_cullFaceEnabled != _defaultState._cullFaceEnabled))
+    if ((_bits & RS_CULL_FACE) && (_cullFaceEnabled != _defaultState->_cullFaceEnabled))
     {
     {
         _cullFaceEnabled ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE);
         _cullFaceEnabled ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE);
-        _defaultState._cullFaceEnabled = _cullFaceEnabled;
+        _defaultState->_cullFaceEnabled = _cullFaceEnabled;
     }
     }
-    if ((_bits & RS_DEPTH_TEST) && (_depthTestEnabled != _defaultState._depthTestEnabled))
+    if ((_bits & RS_DEPTH_TEST) && (_depthTestEnabled != _defaultState->_depthTestEnabled))
     {
     {
         _depthTestEnabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
         _depthTestEnabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
-        _defaultState._depthTestEnabled = _depthTestEnabled;
+        _defaultState->_depthTestEnabled = _depthTestEnabled;
     }
     }
-    if ((_bits & RS_DEPTH_WRITE) && (_depthWriteEnabled != _defaultState._depthWriteEnabled))
+    if ((_bits & RS_DEPTH_WRITE) && (_depthWriteEnabled != _defaultState->_depthWriteEnabled))
     {
     {
         glDepthMask(_depthWriteEnabled);
         glDepthMask(_depthWriteEnabled);
-        _defaultState._depthWriteEnabled = _depthWriteEnabled;
+        _defaultState->_depthWriteEnabled = _depthWriteEnabled;
     }
     }
 
 
-    _defaultState._bits |= _bits;
+    _defaultState->_bits |= _bits;
 }
 }
 
 
 void RenderState::StateBlock::restore(long stateOverrideBits)
 void RenderState::StateBlock::restore(long stateOverrideBits)
 {
 {
     // If there is no state to restore (i.e. no non-default state), do nothing
     // If there is no state to restore (i.e. no non-default state), do nothing
-    if (_defaultState._bits == 0)
+    if (_defaultState->_bits == 0)
     {
     {
         return;
         return;
     }
     }
 
 
     // Restore any state that is not overridden and is not default
     // Restore any state that is not overridden and is not default
-    if (!(stateOverrideBits & RS_BLEND) && (_defaultState._bits & RS_BLEND))
+    if (!(stateOverrideBits & RS_BLEND) && (_defaultState->_bits & RS_BLEND))
     {
     {
         glDisable(GL_BLEND);
         glDisable(GL_BLEND);
-        _defaultState._bits &= ~RS_BLEND;
-        _defaultState._blendEnabled = false;
+        _defaultState->_bits &= ~RS_BLEND;
+        _defaultState->_blendEnabled = false;
     }
     }
-    if (!(stateOverrideBits & RS_BLEND_FUNC) && (_defaultState._bits & RS_BLEND_FUNC))
+    if (!(stateOverrideBits & RS_BLEND_FUNC) && (_defaultState->_bits & RS_BLEND_FUNC))
     {
     {
         glBlendFunc(GL_ONE, GL_ONE);
         glBlendFunc(GL_ONE, GL_ONE);
-        _defaultState._bits &= ~RS_BLEND_FUNC;
-        _defaultState._srcBlend = RenderState::BLEND_ONE;
-        _defaultState._dstBlend = RenderState::BLEND_ONE;
+        _defaultState->_bits &= ~RS_BLEND_FUNC;
+        _defaultState->_srcBlend = RenderState::BLEND_ONE;
+        _defaultState->_dstBlend = RenderState::BLEND_ONE;
     }
     }
-    if (!(stateOverrideBits & RS_CULL_FACE) && (_defaultState._bits & RS_CULL_FACE))
+    if (!(stateOverrideBits & RS_CULL_FACE) && (_defaultState->_bits & RS_CULL_FACE))
     {
     {
         glDisable(GL_CULL_FACE);
         glDisable(GL_CULL_FACE);
-        _defaultState._bits &= ~RS_CULL_FACE;
-        _defaultState._cullFaceEnabled = false;
+        _defaultState->_bits &= ~RS_CULL_FACE;
+        _defaultState->_cullFaceEnabled = false;
     }
     }
-    if (!(stateOverrideBits & RS_DEPTH_TEST) && (_defaultState._bits & RS_DEPTH_TEST))
+    if (!(stateOverrideBits & RS_DEPTH_TEST) && (_defaultState->_bits & RS_DEPTH_TEST))
     {
     {
         glDisable(GL_DEPTH_TEST);
         glDisable(GL_DEPTH_TEST);
-        _defaultState._bits &= ~RS_DEPTH_TEST;
-        _defaultState._depthTestEnabled = false;
+        _defaultState->_bits &= ~RS_DEPTH_TEST;
+        _defaultState->_depthTestEnabled = false;
     }
     }
-    if (!(stateOverrideBits & RS_DEPTH_WRITE) && (_defaultState._bits & RS_DEPTH_WRITE))
+    if (!(stateOverrideBits & RS_DEPTH_WRITE) && (_defaultState->_bits & RS_DEPTH_WRITE))
     {
     {
         glDepthMask(GL_TRUE);
         glDepthMask(GL_TRUE);
-        _defaultState._bits &= ~RS_DEPTH_WRITE;
-        _defaultState._depthWriteEnabled = true;
+        _defaultState->_bits &= ~RS_DEPTH_WRITE;
+        _defaultState->_depthWriteEnabled = true;
     }
     }
 }
 }
 
 

+ 12 - 3
gameplay/src/RenderState.h

@@ -16,6 +16,7 @@ class Pass;
 
 
 class RenderState : public Ref
 class RenderState : public Ref
 {
 {
+    friend class Game;
     friend class Material;
     friend class Material;
     friend class Technique;
     friend class Technique;
     friend class Pass;
     friend class Pass;
@@ -198,7 +199,7 @@ public:
         // State bits
         // State bits
         long _bits;
         long _bits;
 
 
-        static StateBlock _defaultState;
+        static StateBlock* _defaultState;
     };
     };
 
 
     /**
     /**
@@ -279,6 +280,16 @@ protected:
      */
      */
     virtual ~RenderState();
     virtual ~RenderState();
 
 
+    /**
+     * Static initializer that is called during game startup.
+     */
+    static void initialize();
+
+    /**
+     * Static finalizer that is called during game shutdown.
+     */
+    static void finalize();
+
     /**
     /**
      * Sets the node that this render state is bound to.
      * Sets the node that this render state is bound to.
      *
      *
@@ -311,8 +322,6 @@ protected:
     Node* _nodeBinding;
     Node* _nodeBinding;
     mutable StateBlock* _state;
     mutable StateBlock* _state;
     RenderState* _parent;
     RenderState* _parent;
-   
-    static StateBlock* _restoreState;
 };
 };
 
 
 }
 }

+ 37 - 7
gameplay/src/Scene.cpp

@@ -21,6 +21,19 @@ Scene::Scene(const Scene& copy)
 
 
 Scene::~Scene()
 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();
     removeAllNodes();
 }
 }
 
 
@@ -116,6 +129,14 @@ void Scene::addNode(Node* node)
 {
 {
     assert(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 the node is part of another scene, remove it.
     if (node->_scene && node->_scene != this)
     if (node->_scene && node->_scene != this)
     {
     {
@@ -125,7 +146,7 @@ void Scene::addNode(Node* node)
     // If the node is part of another node hierarchy, remove it.
     // If the node is part of another node hierarchy, remove it.
     if (node->getParent())
     if (node->getParent())
     {
     {
-        node->remove();
+        node->getParent()->removeChild(node);
     }
     }
 
 
     // Link the new node into our list.
     // Link the new node into our list.
@@ -142,8 +163,6 @@ void Scene::addNode(Node* node)
 
 
     node->_scene = this;
     node->_scene = this;
 
 
-    node->addRef();
-
     ++_nodeCount;
     ++_nodeCount;
 
 
     // If we don't have an active camera set, then check for one and set it.
     // If we don't have an active camera set, then check for one and set it.
@@ -164,9 +183,6 @@ void Scene::removeNode(Node* node)
     if (node->_scene != this)
     if (node->_scene != this)
         return;
         return;
 
 
-    node->remove();
-    node->_scene = NULL;
-
     if (node == _firstNode)
     if (node == _firstNode)
     {
     {
         _firstNode = node->_nextSibling;
         _firstNode = node->_nextSibling;
@@ -176,6 +192,9 @@ void Scene::removeNode(Node* node)
         _lastNode = node->_prevSibling;
         _lastNode = node->_prevSibling;
     }
     }
 
 
+    node->remove();
+    node->_scene = NULL;
+
     SAFE_RELEASE(node);
     SAFE_RELEASE(node);
 
 
     --_nodeCount;
     --_nodeCount;
@@ -209,16 +228,26 @@ void Scene::setActiveCamera(Camera* camera)
     // Make sure we don't release the camera if the same camera is set twice.
     // Make sure we don't release the camera if the same camera is set twice.
     if (_activeCamera != camera)
     if (_activeCamera != camera)
     {
     {
+        AudioListener* audioListener = AudioListener::getInstance();
+
         if (_activeCamera)
         if (_activeCamera)
         {
         {
+            // Unbind the active camera from the audio listener
+            if (audioListener && (audioListener->getCamera() == _activeCamera))
+            {
+                AudioListener::getInstance()->setCamera(NULL);
+            }
+
             SAFE_RELEASE(_activeCamera);
             SAFE_RELEASE(_activeCamera);
         }
         }
 
 
         _activeCamera = camera;
         _activeCamera = camera;
+
         if (_activeCamera)
         if (_activeCamera)
         {
         {
             _activeCamera->addRef();
             _activeCamera->addRef();
-            if (_bindAudioListenerToCamera && AudioListener::getInstance())
+
+            if (audioListener && _bindAudioListenerToCamera)
             {
             {
                 AudioListener::getInstance()->setCamera(_activeCamera);
                 AudioListener::getInstance()->setCamera(_activeCamera);
             }
             }
@@ -231,6 +260,7 @@ void Scene::bindAudioListenerToCamera(bool bind)
     if (_bindAudioListenerToCamera != bind)
     if (_bindAudioListenerToCamera != bind)
     {
     {
         _bindAudioListenerToCamera = bind;
         _bindAudioListenerToCamera = bind;
+
         if (AudioListener::getInstance())
         if (AudioListener::getInstance())
         {
         {
             AudioListener::getInstance()->setCamera(bind ? _activeCamera : NULL);
             AudioListener::getInstance()->setCamera(bind ? _activeCamera : NULL);

+ 8 - 8
gameplay/src/Vector2.cpp

@@ -39,26 +39,26 @@ Vector2::~Vector2()
 
 
 const Vector2& Vector2::zero()
 const Vector2& Vector2::zero()
 {
 {
-    static Vector2* value = new Vector2(0.0f, 0.0f);
-    return *value;
+    static Vector2 value(0.0f, 0.0f);
+    return value;
 }
 }
 
 
 const Vector2& Vector2::one()
 const Vector2& Vector2::one()
 {
 {
-    static Vector2* value = new Vector2(1.0f, 1.0f);
-    return *value;
+    static Vector2 value(1.0f, 1.0f);
+    return value;
 }
 }
 
 
 const Vector2& Vector2::unitX()
 const Vector2& Vector2::unitX()
 {
 {
-    static Vector2* value = new Vector2(1.0f, 0.0f);
-    return *value;
+    static Vector2 value(1.0f, 0.0f);
+    return value;
 }
 }
 
 
 const Vector2& Vector2::unitY()
 const Vector2& Vector2::unitY()
 {
 {
-    static Vector2* value = new Vector2(0.0f, 1.0f);
-    return *value;
+    static Vector2 value(0.0f, 1.0f);
+    return value;
 }
 }
 
 
 bool Vector2::isZero() const
 bool Vector2::isZero() const

+ 12 - 12
gameplay/src/Vector4.cpp

@@ -54,38 +54,38 @@ Vector4::~Vector4()
 
 
 const Vector4& Vector4::zero()
 const Vector4& Vector4::zero()
 {
 {
-    static Vector4* value = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector4 value(0.0f, 0.0f, 0.0f, 0.0f);
+    return value;
 }
 }
 
 
 const Vector4& Vector4::one()
 const Vector4& Vector4::one()
 {
 {
-    static Vector4* value = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
-    return *value;
+    static Vector4 value(1.0f, 1.0f, 1.0f, 1.0f);
+    return value;
 }
 }
 
 
 const Vector4& Vector4::unitX()
 const Vector4& Vector4::unitX()
 {
 {
-    static Vector4* value = new Vector4(1.0f, 0.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector4 value(1.0f, 0.0f, 0.0f, 0.0f);
+    return value;
 }
 }
 
 
 const Vector4& Vector4::unitY()
 const Vector4& Vector4::unitY()
 {
 {
-    static Vector4* value = new Vector4(0.0f, 1.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector4 value(0.0f, 1.0f, 0.0f, 0.0f);
+    return value;
 }
 }
 
 
 const Vector4& Vector4::unitZ()
 const Vector4& Vector4::unitZ()
 {
 {
-    static Vector4* value = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
-    return *value;
+    static Vector4 value(0.0f, 0.0f, 1.0f, 0.0f);
+    return value;
 }
 }
 
 
 const Vector4& Vector4::unitW()
 const Vector4& Vector4::unitW()
 {
 {
-    static Vector4* value = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);
-    return *value;
+    static Vector4 value(0.0f, 0.0f, 0.0f, 1.0f);
+    return value;
 }
 }
 
 
 bool Vector4::isZero() const
 bool Vector4::isZero() const

+ 3 - 1
gameplay/src/gameplay-main-qnx.h

@@ -15,7 +15,9 @@ int main(int argc, char** argv)
     Game* game = Game::getInstance();
     Game* game = Game::getInstance();
     assert(game != NULL);
     assert(game != NULL);
     Platform* platform = Platform::create(game);
     Platform* platform = Platform::create(game);
-    return platform->enterMessagePump();
+    int result = platform->enterMessagePump();
+    delete platform;
+    return result;
 }
 }
 
 
 
 

+ 3 - 1
gameplay/src/gameplay-main-win32.h

@@ -22,7 +22,9 @@ extern "C" int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LP
     Game* game = Game::getInstance();
     Game* game = Game::getInstance();
     assert(game != NULL);
     assert(game != NULL);
     Platform* platform = Platform::create(game);
     Platform* platform = Platform::create(game);
-    return platform->enterMessagePump();
+    int result = platform->enterMessagePump();
+    delete platform;
+    return result;
 }
 }