Преглед на файлове

Merge pull request #10 from blackberry/next

Next
Sean Paul Taylor преди 14 години
родител
ревизия
753d2331d6
променени са 100 файла, в които са добавени 5715 реда и са изтрити 1526 реда
  1. 20 3
      .gitignore
  2. 11 13
      README.md
  3. 155 0
      gameplay-codestyle.xml
  4. 57 0
      gameplay-encoder/README.md
  5. 3 1
      gameplay-encoder/gameplay-binary.txt
  6. 29 13
      gameplay-encoder/gameplay-encoder.vcxproj
  7. 192 145
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  8. 5 0
      gameplay-encoder/gameplay-encoder.vcxproj.user
  9. 583 0
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  10. 8 2
      gameplay-encoder/src/Animation.cpp
  11. 8 0
      gameplay-encoder/src/Animation.h
  12. 160 5
      gameplay-encoder/src/AnimationChannel.cpp
  13. 23 3
      gameplay-encoder/src/AnimationChannel.h
  14. 13 2
      gameplay-encoder/src/Animations.cpp
  15. 4 0
      gameplay-encoder/src/Animations.h
  16. 1 21
      gameplay-encoder/src/Base.cpp
  17. 58 21
      gameplay-encoder/src/Base.h
  18. 137 0
      gameplay-encoder/src/BoundingVolume.cpp
  19. 57 0
      gameplay-encoder/src/BoundingVolume.h
  20. 1 1
      gameplay-encoder/src/Camera.cpp
  21. 1 0
      gameplay-encoder/src/Camera.h
  22. 0 53
      gameplay-encoder/src/CameraInstance.cpp
  23. 0 36
      gameplay-encoder/src/CameraInstance.h
  24. 3 3
      gameplay-encoder/src/DAEChannelTarget.cpp
  25. 0 12
      gameplay-encoder/src/DAEChannelTarget.h
  26. 10 57
      gameplay-encoder/src/DAEOptimizer.cpp
  27. 5 19
      gameplay-encoder/src/DAEOptimizer.h
  28. 240 251
      gameplay-encoder/src/DAESceneEncoder.cpp
  29. 6 24
      gameplay-encoder/src/DAESceneEncoder.h
  30. 69 14
      gameplay-encoder/src/DAEUtil.cpp
  31. 14 21
      gameplay-encoder/src/DAEUtil.h
  32. 4 1
      gameplay-encoder/src/Effect.cpp
  33. 1 2
      gameplay-encoder/src/Effect.h
  34. 103 13
      gameplay-encoder/src/EncoderArguments.cpp
  35. 24 10
      gameplay-encoder/src/EncoderArguments.h
  36. 1336 0
      gameplay-encoder/src/FBXSceneEncoder.cpp
  37. 222 0
      gameplay-encoder/src/FBXSceneEncoder.h
  38. 43 7
      gameplay-encoder/src/FileIO.cpp
  39. 33 17
      gameplay-encoder/src/FileIO.h
  40. 2 1
      gameplay-encoder/src/Font.cpp
  41. 1 2
      gameplay-encoder/src/Font.h
  42. 4 3
      gameplay-encoder/src/GPBDecoder.cpp
  43. 1 8
      gameplay-encoder/src/GPBDecoder.h
  44. 33 12
      gameplay-encoder/src/GPBFile.cpp
  45. 14 12
      gameplay-encoder/src/GPBFile.h
  46. 5 3
      gameplay-encoder/src/Glyph.cpp
  47. 1 0
      gameplay-encoder/src/Glyph.h
  48. 4 3
      gameplay-encoder/src/Light.cpp
  49. 1 3
      gameplay-encoder/src/Light.h
  50. 0 55
      gameplay-encoder/src/LightInstance.cpp
  51. 0 40
      gameplay-encoder/src/LightInstance.h
  52. 2 1
      gameplay-encoder/src/Material.cpp
  53. 1 2
      gameplay-encoder/src/Material.h
  54. 2 1
      gameplay-encoder/src/MaterialParameter.cpp
  55. 1 2
      gameplay-encoder/src/MaterialParameter.h
  56. 57 3
      gameplay-encoder/src/Matrix.cpp
  57. 23 2
      gameplay-encoder/src/Matrix.h
  58. 257 28
      gameplay-encoder/src/Mesh.cpp
  59. 19 8
      gameplay-encoder/src/Mesh.h
  60. 21 14
      gameplay-encoder/src/MeshPart.cpp
  61. 13 8
      gameplay-encoder/src/MeshPart.h
  62. 346 19
      gameplay-encoder/src/MeshSkin.cpp
  63. 15 10
      gameplay-encoder/src/MeshSkin.h
  64. 2 1
      gameplay-encoder/src/MeshSubSet.cpp
  65. 10 7
      gameplay-encoder/src/MeshSubSet.h
  66. 31 7
      gameplay-encoder/src/Model.cpp
  67. 4 4
      gameplay-encoder/src/Model.h
  68. 63 20
      gameplay-encoder/src/Node.cpp
  69. 31 11
      gameplay-encoder/src/Node.h
  70. 2 1
      gameplay-encoder/src/Object.cpp
  71. 6 13
      gameplay-encoder/src/Object.h
  72. 1 5
      gameplay-encoder/src/Quaternion.cpp
  73. 2 5
      gameplay-encoder/src/Quaternion.h
  74. 2 1
      gameplay-encoder/src/Reference.cpp
  75. 1 0
      gameplay-encoder/src/Reference.h
  76. 5 4
      gameplay-encoder/src/ReferenceTable.cpp
  77. 1 3
      gameplay-encoder/src/ReferenceTable.h
  78. 13 6
      gameplay-encoder/src/Scene.cpp
  79. 6 0
      gameplay-encoder/src/Scene.h
  80. 22 4
      gameplay-encoder/src/StringUtil.cpp
  81. 5 2
      gameplay-encoder/src/StringUtil.h
  82. 12 7
      gameplay-encoder/src/TTFFontEncoder.cpp
  83. 5 7
      gameplay-encoder/src/TTFFontEncoder.h
  84. 2 0
      gameplay-encoder/src/Transform.cpp
  85. 20 16
      gameplay-encoder/src/Transform.h
  86. 18 70
      gameplay-encoder/src/Vector2.cpp
  87. 109 38
      gameplay-encoder/src/Vector2.h
  88. 77 0
      gameplay-encoder/src/Vector2.inl
  89. 34 79
      gameplay-encoder/src/Vector3.cpp
  90. 115 44
      gameplay-encoder/src/Vector3.h
  91. 82 0
      gameplay-encoder/src/Vector3.inl
  92. 36 72
      gameplay-encoder/src/Vector4.cpp
  93. 119 51
      gameplay-encoder/src/Vector4.h
  94. 89 0
      gameplay-encoder/src/Vector4.inl
  95. 30 27
      gameplay-encoder/src/Vertex.cpp
  96. 7 4
      gameplay-encoder/src/Vertex.h
  97. 2 1
      gameplay-encoder/src/VertexElement.cpp
  98. 1 0
      gameplay-encoder/src/VertexElement.h
  99. 17 6
      gameplay-encoder/src/main.cpp
  100. 271 0
      gameplay-newproject.bat

+ 20 - 3
.gitignore

@@ -13,7 +13,9 @@
 /Device-Coverage
 /Device-Coverage
 /Device-Profile
 /Device-Profile
 /Device-Release
 /Device-Release
+/gameplay.xcworkspace/xcuserdata
 /gameplay/Debug
 /gameplay/Debug
+/gameplay/DebugMem
 /gameplay/Release
 /gameplay/Release
 /gameplay/Simulator
 /gameplay/Simulator
 /gameplay/Simulator-Coverage
 /gameplay/Simulator-Coverage
@@ -22,10 +24,14 @@
 /gameplay/Device-Coverage
 /gameplay/Device-Coverage
 /gameplay/Device-Profile
 /gameplay/Device-Profile
 /gameplay/Device-Release
 /gameplay/Device-Release
+/gameplay/gameplay.xcodeproj/xcuserdata
 /gameplay-encoder/Debug
 /gameplay-encoder/Debug
 /gameplay-encoder/Release
 /gameplay-encoder/Release
+/gameplay-encoder/gameplay-encoder.xcodeproj/xcuserdata
+/gameplay-internal
 /gameplay-samples/sample00-mesh/Debug
 /gameplay-samples/sample00-mesh/Debug
-/gameplay-samples/sample00-mesh//Release
+/gameplay-samples/sample00-mesh/DebugMem
+/gameplay-samples/sample00-mesh/Release
 /gameplay-samples/sample00-mesh/Simulator
 /gameplay-samples/sample00-mesh/Simulator
 /gameplay-samples/sample00-mesh/Simulator-Coverage
 /gameplay-samples/sample00-mesh/Simulator-Coverage
 /gameplay-samples/sample00-mesh/Simulator-Profile
 /gameplay-samples/sample00-mesh/Simulator-Profile
@@ -33,8 +39,11 @@
 /gameplay-samples/sample00-mesh/Device-Coverage
 /gameplay-samples/sample00-mesh/Device-Coverage
 /gameplay-samples/sample00-mesh/Device-Profile
 /gameplay-samples/sample00-mesh/Device-Profile
 /gameplay-samples/sample00-mesh/Device-Release
 /gameplay-samples/sample00-mesh/Device-Release
+/gameplay-samples/sample00-mesh/res/shaders
+/gameplay-samples/sample00-mesh/sample00-mesh.xcodeproj/xcuserdata
 /gameplay-samples/sample01-longboard/Debug
 /gameplay-samples/sample01-longboard/Debug
-/gameplay-samples/sample01-longboard//Release
+/gameplay-samples/sample01-longboard/DebugMem
+/gameplay-samples/sample01-longboard/Release
 /gameplay-samples/sample01-longboard/Simulator
 /gameplay-samples/sample01-longboard/Simulator
 /gameplay-samples/sample01-longboard/Simulator-Coverage
 /gameplay-samples/sample01-longboard/Simulator-Coverage
 /gameplay-samples/sample01-longboard/Simulator-Profile
 /gameplay-samples/sample01-longboard/Simulator-Profile
@@ -42,7 +51,10 @@
 /gameplay-samples/sample01-longboard/Device-Coverage
 /gameplay-samples/sample01-longboard/Device-Coverage
 /gameplay-samples/sample01-longboard/Device-Profile
 /gameplay-samples/sample01-longboard/Device-Profile
 /gameplay-samples/sample01-longboard/Device-Release
 /gameplay-samples/sample01-longboard/Device-Release
+/gameplay-samples/sample01-longboard/res/shaders
+/gameplay-samples/sample01-longboard/sample01-longboard.xcodeproj/xcuserdata
 /gameplay-samples/sample02-spaceship/Debug
 /gameplay-samples/sample02-spaceship/Debug
+/gameplay-samples/sample02-spaceship/DebugMem
 /gameplay-samples/sample02-spaceship/Release
 /gameplay-samples/sample02-spaceship/Release
 /gameplay-samples/sample02-spaceship/Simulator
 /gameplay-samples/sample02-spaceship/Simulator
 /gameplay-samples/sample02-spaceship/Simulator-Coverage
 /gameplay-samples/sample02-spaceship/Simulator-Coverage
@@ -51,7 +63,10 @@
 /gameplay-samples/sample02-spaceship/Device-Coverage
 /gameplay-samples/sample02-spaceship/Device-Coverage
 /gameplay-samples/sample02-spaceship/Device-Profile
 /gameplay-samples/sample02-spaceship/Device-Profile
 /gameplay-samples/sample02-spaceship/Device-Release
 /gameplay-samples/sample02-spaceship/Device-Release
+/gameplay-samples/sample02-spaceship/res/shaders
+/gameplay-samples/sample02-spaceship/sample02-spaceship.xcodeproj/xcuserdata
 /gameplay-samples/sample03-character/Debug
 /gameplay-samples/sample03-character/Debug
+/gameplay-samples/sample03-character/DebugMem
 /gameplay-samples/sample03-character/Release
 /gameplay-samples/sample03-character/Release
 /gameplay-samples/sample03-character/Simulator
 /gameplay-samples/sample03-character/Simulator
 /gameplay-samples/sample03-character/Simulator-Coverage
 /gameplay-samples/sample03-character/Simulator-Coverage
@@ -59,4 +74,6 @@
 /gameplay-samples/sample03-character/Device-Debug
 /gameplay-samples/sample03-character/Device-Debug
 /gameplay-samples/sample03-character/Device-Coverage
 /gameplay-samples/sample03-character/Device-Coverage
 /gameplay-samples/sample03-character/Device-Profile
 /gameplay-samples/sample03-character/Device-Profile
-/gameplay-samples/sample03-character/Device-Release
+/gameplay-samples/sample03-character/Device-Release
+/gameplay-samples/sample03-character/res/shaders
+/gameplay-samples/sample03-character/sample03-character.xcodeproj/xcuserdata

+ 11 - 13
README.md

@@ -1,19 +1,18 @@
-## GamePlay v1.0.1
+## GamePlay v1.1.0
 GamePlay is a open-source, cross-platform 3D native gaming framework making it easy to learn and write mobile and desktop games. 
 GamePlay is a open-source, cross-platform 3D native gaming framework making it easy to learn and write mobile and desktop games. 
 
 
 ## Supported Platforms
 ## Supported Platforms
-- Microsoft Windows 7 (using Microsoft Visual Studio 2010)
- * Requires OpenAL 1.1 (http://connect.creativelabs.com/openal/Downloads/Forms/AllItems.aspx)
-- BlackBerry PlayBook 1.0/2.0 (using BlackBerry Native SDK 1.0)
+- BlackBerry PlayBook 1.0/2.0 (using BlackBerry Native SDK 1.0/2.0)
+- Apple MacOS X (using Apple XCode 4.0)
+- Microsoft Windows 7 (using Microsoft Visual Studio 2010 Pro/Express)
+	* Requires OpenAL 1.1 (http://connect.creativelabs.com/openal/Downloads/Forms/AllItems.aspx)
 
 
-## Roadmap
-- Apple Mac OS X support (using XCode 4.0)
-- Physics support with Bullet Physics
-- Encoded audio support with Ogg Vorbis
-- FrameBuffer's (RenderTarget + DepthStencilTarget)
-- Shadow and Light map generation.
-- Spatial Partitioning with Octree (Visibility Testing and Light Determination)
-- UI Forms
+## Roadmap for 'next' branch
+- UI Forms with Themed Overlays.
+- Improvements to Lighting.
+- Developer Guide.
+- More Samples and Tutorials.
+- Apple iOS 5 Support.
 
 
 ## Bug Reporting and Feature Requests
 ## Bug Reporting and Feature Requests
 If you find a bug in a Sample, or have an enhancement request, simply file an 
 If you find a bug in a Sample, or have an enhancement request, simply file an 
@@ -22,7 +21,6 @@ to the Committers to the project to let them know that you have filed
 an [Issue](https://github.com/blackberry/GamePlay/issues).
 an [Issue](https://github.com/blackberry/GamePlay/issues).
 
 
 ## Disclaimer
 ## Disclaimer
-
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 

+ 155 - 0
gameplay-codestyle.xml

@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<profiles version="1">
+<profile kind="CodeFormatterProfile" name="BSD/Allman Gaming" version="1">
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="1024"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_enumerator_list" value="49"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_declarator_list" value="16"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_expression_list" value="0"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_compact_if" value="0"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration" value="80"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="4"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="next_line"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket" value="do not insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters" value="insert"/>
+<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments" value="do not insert"/>
+</profile>
+</profiles>

+ 57 - 0
gameplay-encoder/README.md

@@ -0,0 +1,57 @@
+## GamePlay Encoder
+GamePlay Encoder is a command-line tool for encoding/packaging games assets like fonts and 3D scene files
+into a binary package file format for the GamePlay runtime framework. 
+
+## TrueType Font Support
+TrueType Fonts conversion is enabled/built-in by default into gameplay-encoder via freetype 2 library.
+
+## COLLADA Scene Support
+COLLADA is enabled/built-in by default into gameplay-encoder via COLLADA-DOM library.
+Most major 3D DCC tools support the export of COLLADA 1.4.
+We also recommend you download and use OpenCOLADA (http://opencollada.org/)
+for Autodesk Maya and 3DS Max.
+
+## FBX Scene Support
+FBX support can easily be enabled in gameplay-encoder but requires an 
+additional installation of Autodesk FBX SDK. (http://www.autodesk.com/fbx).
+You must then rebuild gameplay-encoder with the follow platform/tooling instructions:
+
+### Building FBX Support on Windows 7 using Visual Studio 2010
+- Download and install the FBX SDK for Window VS2010. (http://www.autodesk.com/fbx)
+- Edit the project properties of "gameplay-encoder"
+- Add Preprocessor Definition "USE_FBX" (C++/Preprocessor)
+- Add the FBX SDK include directory to Additional Include Directories (C++/General)
+  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/include
+- Add the FBX lib directory to the Additional Library Directories (Linker/General)
+  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86
+- Add "fbxsdk-2012.2-mdd.lib" and "wininet.lib" to the Additional Dependencies (Linker/Input)
+  * Example: fbxsdk-2012.2-mdd.lib;wininet.lib
+- Add a post build event to copy the DLL (Build Events/Post-Build Event)
+  * Example: copy /Y "C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86/fbxsdk-2012.2d.dll" "$(TargetDir)"
+- Build gameplay-encoder
+
+### Building FBX Support on Mac OS X using XCode 4
+- Download and install the FBX SDK for Mac OS X (http://www.autodesk.com/fbx)
+- Edit the project properties of target "gameplay-encoder".
+- Add Preprocessor Macro "USE_FBX" to both Debug/Release sections. (Build Settings)
+- Add the FBX include directory to Header Search Paths: (Build Settings)
+  * Example: /Applications/Autodesk/FBXSDK20122/include
+- Add the FBX library and dependency Library/Frameworks: (Build Phases -> Link Binary with Libraries)
+  * Example: /Applications/Autodesk/FBXSDK20122/lib/gcc4/ub/libfbxsdk-2012.2-static.a  (Add Other)
+  * Example: libiconv.dylib, Cocoa.framework, SystemConfiguration.framework
+- Build gameplay-encoder
+
+## Binary Format
+The GamePlay binary package format is well defined in the gameplay-encoder/gameplay-binary.txt file.
+
+## Binary Loading
+GamePlay binary package files can easily be loaded using the gameplay/Package.h which is part
+of the GamePlay runtime framework.
+
+## Disclaimer
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
+OTHER DEALINGS IN THE SOFTWARE.

+ 3 - 1
gameplay-encoder/gameplay-binary.txt

@@ -16,7 +16,7 @@ Section      Name            Type
 ------------------------------------------------------------------------------------------------------
 ------------------------------------------------------------------------------------------------------
 Header
 Header
              Identifier      byte[9]     = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' } 
              Identifier      byte[9]     = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' } 
-             Version         byte[2]     = { 1, 0 }
+             Version         byte[2]     = { 1, 1 }
              References      Reference[]
              References      Reference[]
 Data
 Data
              Objects         Object[]
              Objects         Object[]
@@ -211,6 +211,8 @@ Reference
                 bindShape               float[16]
                 bindShape               float[16]
                 joints                  xref:Node[]
                 joints                  xref:Node[]
                 jointsBindPoses         float[] // 16 * joints.length
                 jointsBindPoses         float[] // 16 * joints.length
+                boundingBox             BoundingBox { float[3] min, float[3] max }
+                boundingSphere          BoundingSphere { float[3] center, float radius }
 ------------------------------------------------------------------------------------------------------
 ------------------------------------------------------------------------------------------------------
 128->Font
 128->Font
                 family                  string
                 family                  string

+ 29 - 13
gameplay-encoder/gameplay-encoder.vcxproj

@@ -11,17 +11,19 @@
     </ProjectConfiguration>
     </ProjectConfiguration>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\gameplay\src\Curve.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\AnimationChannel.cpp" />
     <ClCompile Include="src\AnimationChannel.cpp" />
     <ClCompile Include="src\Base.cpp" />
     <ClCompile Include="src\Base.cpp" />
+    <ClCompile Include="src\BoundingVolume.cpp" />
     <ClCompile Include="src\Camera.cpp" />
     <ClCompile Include="src\Camera.cpp" />
-    <ClCompile Include="src\CameraInstance.cpp" />
     <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\DAEChannelTarget.cpp" />
     <ClCompile Include="src\DAEChannelTarget.cpp" />
     <ClCompile Include="src\DAEOptimizer.cpp" />
     <ClCompile Include="src\DAEOptimizer.cpp" />
     <ClCompile Include="src\DAESceneEncoder.cpp" />
     <ClCompile Include="src\DAESceneEncoder.cpp" />
     <ClCompile Include="src\DAEUtil.cpp" />
     <ClCompile Include="src\DAEUtil.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\Effect.cpp" />
+    <ClCompile Include="src\FBXSceneEncoder.cpp" />
     <ClCompile Include="src\FileIO.cpp" />
     <ClCompile Include="src\FileIO.cpp" />
     <ClCompile Include="src\Font.cpp" />
     <ClCompile Include="src\Font.cpp" />
     <ClCompile Include="src\GPBFile.cpp" />
     <ClCompile Include="src\GPBFile.cpp" />
@@ -29,7 +31,6 @@
     <ClCompile Include="src\GPBDecoder.cpp" />
     <ClCompile Include="src\GPBDecoder.cpp" />
     <ClCompile Include="src\Animations.cpp" />
     <ClCompile Include="src\Animations.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\Light.cpp" />
-    <ClCompile Include="src\LightInstance.cpp" />
     <ClCompile Include="src\main.cpp" />
     <ClCompile Include="src\main.cpp" />
     <ClCompile Include="src\Material.cpp" />
     <ClCompile Include="src\Material.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
@@ -54,17 +55,19 @@
     <ClCompile Include="src\VertexElement.cpp" />
     <ClCompile Include="src\VertexElement.cpp" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\gameplay\src\Curve.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\AnimationChannel.h" />
     <ClInclude Include="src\AnimationChannel.h" />
     <ClInclude Include="src\Base.h" />
     <ClInclude Include="src\Base.h" />
+    <ClInclude Include="src\BoundingVolume.h" />
     <ClInclude Include="src\Camera.h" />
     <ClInclude Include="src\Camera.h" />
-    <ClInclude Include="src\CameraInstance.h" />
     <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\DAEChannelTarget.h" />
     <ClInclude Include="src\DAEChannelTarget.h" />
     <ClInclude Include="src\DAEOptimizer.h" />
     <ClInclude Include="src\DAEOptimizer.h" />
     <ClInclude Include="src\DAESceneEncoder.h" />
     <ClInclude Include="src\DAESceneEncoder.h" />
     <ClInclude Include="src\DAEUtil.h" />
     <ClInclude Include="src\DAEUtil.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\Effect.h" />
+    <ClInclude Include="src\FBXSceneEncoder.h" />
     <ClInclude Include="src\FileIO.h" />
     <ClInclude Include="src\FileIO.h" />
     <ClInclude Include="src\Font.h" />
     <ClInclude Include="src\Font.h" />
     <ClInclude Include="src\GPBFile.h" />
     <ClInclude Include="src\GPBFile.h" />
@@ -72,7 +75,6 @@
     <ClInclude Include="src\GPBDecoder.h" />
     <ClInclude Include="src\GPBDecoder.h" />
     <ClInclude Include="src\Animations.h" />
     <ClInclude Include="src\Animations.h" />
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\Light.h" />
-    <ClInclude Include="src\LightInstance.h" />
     <ClInclude Include="src\Material.h" />
     <ClInclude Include="src\Material.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />
     <ClInclude Include="src\Matrix.h" />
@@ -95,6 +97,11 @@
     <ClInclude Include="src\Vertex.h" />
     <ClInclude Include="src\Vertex.h" />
     <ClInclude Include="src\VertexElement.h" />
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="src\Vector2.inl" />
+    <None Include="src\Vector3.inl" />
+    <None Include="src\Vector4.inl" />
+  </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{9D69B743-4872-4DD1-8E30-0087C64298D7}</ProjectGuid>
     <ProjectGuid>{9D69B743-4872-4DD1-8E30-0087C64298D7}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
@@ -138,17 +145,22 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level4</WarningLevel>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;USE_FBX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4;../external-deps/libpng/include;../external-deps/zlib/include;C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/include</AdditionalIncludeDirectories>
+      <DisableLanguageExtensions>
+      </DisableLanguageExtensions>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalLibraryDirectories>;../external-deps/freetype2/lib;../external-deps/collada-dom/lib</AdditionalLibraryDirectories>
-      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32;C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86</AdditionalLibraryDirectories>
+      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;fbxsdk-2012.2-mdd.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
     </Link>
     </Link>
     <PostBuildEvent>
     <PostBuildEvent>
-      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\*.dll" "$(TargetDir)"</Command>
+      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\win32\*.dll" "$(TargetDir)"
+copy /Y "$(ProjectDir)..\external-deps\zlib\lib\win32\*.dll" "$(TargetDir)"
+</Command>
     </PostBuildEvent>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -160,18 +172,22 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4;../external-deps/libpng/include;../external-deps/zlib/include</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>;../external-deps/freetype2/lib;../external-deps/collada-dom/lib</AdditionalLibraryDirectories>
+      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32</AdditionalLibraryDirectories>
+      <IgnoreSpecificDefaultLibraries>
+      </IgnoreSpecificDefaultLibraries>
     </Link>
     </Link>
     <PostBuildEvent>
     <PostBuildEvent>
-      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\*.dll" "$(TargetDir)"</Command>
+      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\win32\*.dll" "$(TargetDir)"
+copy /Y "$(ProjectDir)..\external-deps\zlib\lib\win32\*.dll" "$(TargetDir)"
+</Command>
     </PostBuildEvent>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 192 - 145
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -1,225 +1,272 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
   <ItemGroup>
-    <ClCompile Include="src\DAESceneEncoder.cpp" />
-    <ClCompile Include="src\main.cpp" />
-    <ClCompile Include="src\ReferenceTable.cpp" />
-    <ClCompile Include="src\TTFFontEncoder.cpp" />
+    <ClCompile Include="src\Animation.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AnimationChannel.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Animations.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Base.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\BoundingVolume.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
     <ClCompile Include="src\Camera.cpp">
     <ClCompile Include="src\Camera.cpp">
-      <Filter>Objects\Camera</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\gameplay\src\Curve.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DAEChannelTarget.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\CameraInstance.cpp">
-      <Filter>Objects\Camera</Filter>
+    <ClCompile Include="src\DAEOptimizer.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DAESceneEncoder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DAEUtil.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Effect.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\EncoderArguments.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FBXSceneEncoder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FileIO.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Font.cpp">
     <ClCompile Include="src\Font.cpp">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Glyph.cpp">
     <ClCompile Include="src\Glyph.cpp">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\GPBDecoder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\GPBFile.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Light.cpp">
     <ClCompile Include="src\Light.cpp">
-      <Filter>Objects\Light</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\LightInstance.cpp">
-      <Filter>Objects\Light</Filter>
+    <ClCompile Include="src\main.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Material.cpp">
     <ClCompile Include="src\Material.cpp">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\MaterialParameter.cpp">
     <ClCompile Include="src\MaterialParameter.cpp">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Matrix.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Mesh.cpp">
     <ClCompile Include="src\Mesh.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\MeshPart.cpp">
     <ClCompile Include="src\MeshPart.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\MeshSkin.cpp">
     <ClCompile Include="src\MeshSkin.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Node.cpp">
-      <Filter>Objects\Node</Filter>
+    <ClCompile Include="src\Model.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Reference.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\Node.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Object.cpp">
     <ClCompile Include="src\Object.cpp">
-      <Filter>Objects</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Model.cpp">
-      <Filter>Objects\Mesh</Filter>
+    <ClCompile Include="src\Quaternion.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Scene.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\Reference.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\GPBDecoder.cpp" />
-    <ClCompile Include="src\Animation.cpp">
-      <Filter>Objects\Animation</Filter>
+    <ClCompile Include="src\ReferenceTable.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\AnimationChannel.cpp">
-      <Filter>Objects\Animation</Filter>
+    <ClCompile Include="src\Scene.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\GPBFile.cpp" />
-    <ClCompile Include="src\DAEChannelTarget.cpp" />
-    <ClCompile Include="src\Base.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\StringUtil.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\FileIO.cpp" />
-    <ClCompile Include="src\StringUtil.cpp" />
-    <ClCompile Include="src\Effect.cpp">
-      <Filter>Objects\Material</Filter>
+    <ClCompile Include="src\Transform.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Vertex.cpp" />
-    <ClCompile Include="src\VertexElement.cpp" />
-    <ClCompile Include="src\Quaternion.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\TTFFontEncoder.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Vector4.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vector2.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="src\Vector3.cpp">
     <ClCompile Include="src\Vector3.cpp">
-      <Filter>Math</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector2.cpp">
-      <Filter>Math</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Transform.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vector4.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\Matrix.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vertex.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="src\DAEOptimizer.cpp" />
-    <ClCompile Include="src\DAEUtil.cpp" />
-    <ClCompile Include="src\EncoderArguments.cpp" />
-    <ClCompile Include="src\Animations.cpp">
-      <Filter>Objects\Animation</Filter>
+    <ClCompile Include="src\VertexElement.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
-    <ClInclude Include="src\DAESceneEncoder.h" />
-    <ClInclude Include="src\ReferenceTable.h" />
-    <ClInclude Include="src\TTFFontEncoder.h" />
-    <ClInclude Include="src\CameraInstance.h">
-      <Filter>Objects\Camera</Filter>
+    <ClInclude Include="src\VertexElement.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Animation.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AnimationChannel.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Animations.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Base.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\BoundingVolume.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Camera.h">
     <ClInclude Include="src\Camera.h">
-      <Filter>Objects\Camera</Filter>
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\gameplay\src\Curve.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAEChannelTarget.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAEOptimizer.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAESceneEncoder.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAEUtil.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Effect.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\EncoderArguments.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FBXSceneEncoder.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FileIO.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Font.h">
     <ClInclude Include="src\Font.h">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Glyph.h">
     <ClInclude Include="src\Glyph.h">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\LightInstance.h">
-      <Filter>Objects\Light</Filter>
+    <ClInclude Include="src\GPBDecoder.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Light.h">
-      <Filter>Objects\Light</Filter>
+    <ClInclude Include="src\GPBFile.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\MaterialParameter.h">
-      <Filter>Objects\Material</Filter>
+    <ClInclude Include="src\Light.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Material.h">
     <ClInclude Include="src\Material.h">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\MeshSkin.h">
-      <Filter>Objects\Mesh</Filter>
+    <ClInclude Include="src\MaterialParameter.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Matrix.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Mesh.h">
     <ClInclude Include="src\Mesh.h">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\MeshPart.h">
     <ClInclude Include="src\MeshPart.h">
-      <Filter>Objects\Mesh</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Node.h">
-      <Filter>Objects\Node</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Reference.h">
-      <Filter>Objects</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Object.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\MeshSkin.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Model.h">
     <ClInclude Include="src\Model.h">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Scene.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\Node.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\GPBDecoder.h" />
-    <ClInclude Include="src\AnimationChannel.h">
-      <Filter>Objects\Animation</Filter>
+    <ClInclude Include="src\Object.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Animation.h">
-      <Filter>Objects\Animation</Filter>
+    <ClInclude Include="src\Quaternion.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\GPBFile.h" />
-    <ClInclude Include="src\DAEChannelTarget.h" />
-    <ClInclude Include="src\Base.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\Reference.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\FileIO.h" />
-    <ClInclude Include="src\StringUtil.h" />
-    <ClInclude Include="src\Effect.h">
-      <Filter>Objects\Material</Filter>
+    <ClInclude Include="src\ReferenceTable.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Vertex.h" />
-    <ClInclude Include="src\VertexElement.h" />
-    <ClInclude Include="src\Quaternion.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Scene.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Vector4.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\StringUtil.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Vector3.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Transform.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\TTFFontEncoder.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="src\Vector2.h">
     <ClInclude Include="src\Vector2.h">
-      <Filter>Math</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Transform.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Vector3.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\Matrix.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Vector4.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="src\DAEOptimizer.h" />
-    <ClInclude Include="src\DAEUtil.h" />
-    <ClInclude Include="src\EncoderArguments.h" />
-    <ClInclude Include="src\Animations.h">
-      <Filter>Objects\Animation</Filter>
+    <ClInclude Include="src\Vertex.h">
+      <Filter>src</Filter>
     </ClInclude>
     </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
-    <Filter Include="Objects">
-      <UniqueIdentifier>{3be0a9f1-9de7-42e9-b264-89400ccf3236}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Camera">
-      <UniqueIdentifier>{d2b8cf21-20ee-4838-8bb6-5adab779dc10}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Font">
-      <UniqueIdentifier>{1c4dbad5-5351-4fd0-b498-745f7afcf866}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Light">
-      <UniqueIdentifier>{c41a1929-d921-4d2a-9713-12831c0e3ce1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Material">
-      <UniqueIdentifier>{1d8618d6-dbed-40c0-bb22-43350b195ee1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Mesh">
-      <UniqueIdentifier>{80e09f25-6954-4415-b712-62a4a64174c3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Node">
-      <UniqueIdentifier>{a74ab546-c248-4bf8-b212-b590514e23e0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Animation">
-      <UniqueIdentifier>{dc9b3d2e-25ae-4613-83ce-844abf4f9bf5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Math">
-      <UniqueIdentifier>{4368ed2b-7fce-423a-a9cb-76a0fdc42858}</UniqueIdentifier>
+    <None Include="src\Vector2.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector3.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector4.inl">
+      <Filter>src</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{6393521c-00fb-48f6-b480-87f8d978a74f}</UniqueIdentifier>
     </Filter>
     </Filter>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 5 - 0
gameplay-encoder/gameplay-encoder.vcxproj.user

@@ -4,5 +4,10 @@
     <LocalDebuggerCommandArguments>
     <LocalDebuggerCommandArguments>
     </LocalDebuggerCommandArguments>
     </LocalDebuggerCommandArguments>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+    <LocalDebuggerEnvironment>PATH=%PATH%;../external-deps/zlib/lib/win32;../external-deps/libpng/lib/win32</LocalDebuggerEnvironment>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LocalDebuggerEnvironment>PATH=%PATH%;../external-deps/zlib/lib/win32;../external-deps/libpng/lib/win32</LocalDebuggerEnvironment>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
   </PropertyGroup>
   </PropertyGroup>
 </Project>
 </Project>

+ 583 - 0
gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj

@@ -0,0 +1,583 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		42475D7C14720ECE00610A6A /* libdom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42475D7B14720ECE00610A6A /* libdom.a */; };
+		42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */; };
+		4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4283905714896E6C00E2B2F5 /* BoundingVolume.cpp */; };
+		4283906314896F1600E2B2F5 /* Curve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4283906114896F1600E2B2F5 /* Curve.cpp */; };
+		42C8EE0A14724CD700E43619 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB714724CD700E43619 /* Animation.cpp */; };
+		42C8EE0B14724CD700E43619 /* AnimationChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB914724CD700E43619 /* AnimationChannel.cpp */; };
+		42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBB14724CD700E43619 /* Animations.cpp */; };
+		42C8EE0D14724CD700E43619 /* Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBD14724CD700E43619 /* Base.cpp */; };
+		42C8EE0E14724CD700E43619 /* Camera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBF14724CD700E43619 /* Camera.cpp */; };
+		42C8EE1014724CD700E43619 /* DAEChannelTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */; };
+		42C8EE1114724CD700E43619 /* DAEOptimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */; };
+		42C8EE1214724CD700E43619 /* DAESceneEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC714724CD700E43619 /* DAESceneEncoder.cpp */; };
+		42C8EE1314724CD700E43619 /* DAEUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC914724CD700E43619 /* DAEUtil.cpp */; };
+		42C8EE1414724CD700E43619 /* Effect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDCB14724CD700E43619 /* Effect.cpp */; };
+		42C8EE1514724CD700E43619 /* EncoderArguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDCD14724CD700E43619 /* EncoderArguments.cpp */; };
+		42C8EE1614724CD700E43619 /* FileIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDCF14724CD700E43619 /* FileIO.cpp */; };
+		42C8EE1714724CD700E43619 /* Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD114724CD700E43619 /* Font.cpp */; };
+		42C8EE1814724CD700E43619 /* Glyph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD314724CD700E43619 /* Glyph.cpp */; };
+		42C8EE1914724CD700E43619 /* GPBDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD514724CD700E43619 /* GPBDecoder.cpp */; };
+		42C8EE1A14724CD700E43619 /* GPBFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD714724CD700E43619 /* GPBFile.cpp */; };
+		42C8EE1B14724CD700E43619 /* Light.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD914724CD700E43619 /* Light.cpp */; };
+		42C8EE1D14724CD700E43619 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDDD14724CD700E43619 /* main.cpp */; };
+		42C8EE1E14724CD700E43619 /* Material.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDDE14724CD700E43619 /* Material.cpp */; };
+		42C8EE1F14724CD700E43619 /* MaterialParameter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDE014724CD700E43619 /* MaterialParameter.cpp */; };
+		42C8EE2014724CD700E43619 /* Matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDE214724CD700E43619 /* Matrix.cpp */; };
+		42C8EE2114724CD700E43619 /* Mesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDE414724CD700E43619 /* Mesh.cpp */; };
+		42C8EE2214724CD700E43619 /* MeshPart.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDE614724CD700E43619 /* MeshPart.cpp */; };
+		42C8EE2314724CD700E43619 /* MeshSkin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDE814724CD700E43619 /* MeshSkin.cpp */; };
+		42C8EE2414724CD700E43619 /* MeshSubSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDEA14724CD700E43619 /* MeshSubSet.cpp */; };
+		42C8EE2514724CD700E43619 /* Model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDEC14724CD700E43619 /* Model.cpp */; };
+		42C8EE2614724CD700E43619 /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDEE14724CD700E43619 /* Node.cpp */; };
+		42C8EE2714724CD700E43619 /* Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDF014724CD700E43619 /* Object.cpp */; };
+		42C8EE2814724CD700E43619 /* Quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDF214724CD700E43619 /* Quaternion.cpp */; };
+		42C8EE2914724CD700E43619 /* Reference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDF414724CD700E43619 /* Reference.cpp */; };
+		42C8EE2A14724CD700E43619 /* ReferenceTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDF614724CD700E43619 /* ReferenceTable.cpp */; };
+		42C8EE2B14724CD700E43619 /* Scene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDF814724CD700E43619 /* Scene.cpp */; };
+		42C8EE2C14724CD700E43619 /* StringUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDFA14724CD700E43619 /* StringUtil.cpp */; };
+		42C8EE2D14724CD700E43619 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDFC14724CD700E43619 /* Transform.cpp */; };
+		42C8EE2E14724CD700E43619 /* TTFFontEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDFE14724CD700E43619 /* TTFFontEncoder.cpp */; };
+		42C8EE2F14724CD700E43619 /* Vector2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EE0014724CD700E43619 /* Vector2.cpp */; };
+		42C8EE3014724CD700E43619 /* Vector3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EE0214724CD700E43619 /* Vector3.cpp */; };
+		42C8EE3114724CD700E43619 /* Vector4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EE0414724CD700E43619 /* Vector4.cpp */; };
+		42C8EE3214724CD700E43619 /* Vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EE0614724CD700E43619 /* Vertex.cpp */; };
+		42C8EE3314724CD700E43619 /* VertexElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EE0814724CD700E43619 /* VertexElement.cpp */; };
+		42C8EE351472B60100E43619 /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C8EE341472B60100E43619 /* libfreetype.a */; };
+		42C8EE371472D7E700E43619 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C8EE361472D7E700E43619 /* libxml2.dylib */; };
+		42C8EE391472DAA300E43619 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C8EE381472DAA300E43619 /* libz.dylib */; };
+		42C8EE3B1472DAAE00E43619 /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C8EE3A1472DAAE00E43619 /* libbz2.dylib */; };
+		42D277591472EFA700D867A4 /* libpcre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42D277571472EFA700D867A4 /* libpcre.a */; };
+		42D2775A1472EFA700D867A4 /* libpcrecpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42D277581472EFA700D867A4 /* libpcrecpp.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		42475CE4147208A000610A6A /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		42475CE6147208A000610A6A /* gameplay-encoder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gameplay-encoder"; sourceTree = BUILT_PRODUCTS_DIR; };
+		42475D7B14720ECE00610A6A /* libdom.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdom.a; path = "../external-deps/collada-dom/lib/macos/libdom.a"; sourceTree = "<group>"; };
+		4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FBXSceneEncoder.cpp; path = src/FBXSceneEncoder.cpp; sourceTree = SOURCE_ROOT; };
+		4278341F148D6F7500A6E27F /* FBXSceneEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FBXSceneEncoder.h; path = src/FBXSceneEncoder.h; sourceTree = SOURCE_ROOT; };
+		42783420148D6F7500A6E27F /* Vector2.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Vector2.inl; path = src/Vector2.inl; sourceTree = SOURCE_ROOT; };
+		42783421148D6F7500A6E27F /* Vector3.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Vector3.inl; path = src/Vector3.inl; sourceTree = SOURCE_ROOT; };
+		42783422148D6F7500A6E27F /* Vector4.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Vector4.inl; path = src/Vector4.inl; sourceTree = SOURCE_ROOT; };
+		4283905714896E6C00E2B2F5 /* BoundingVolume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoundingVolume.cpp; path = src/BoundingVolume.cpp; sourceTree = SOURCE_ROOT; };
+		4283905814896E6C00E2B2F5 /* BoundingVolume.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BoundingVolume.h; path = src/BoundingVolume.h; sourceTree = SOURCE_ROOT; };
+		4283906114896F1600E2B2F5 /* Curve.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Curve.cpp; path = ../gameplay/src/Curve.cpp; sourceTree = "<group>"; };
+		4283906214896F1600E2B2F5 /* Curve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Curve.h; path = ../gameplay/src/Curve.h; sourceTree = "<group>"; };
+		42C8EDB714724CD700E43619 /* Animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Animation.cpp; path = src/Animation.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDB814724CD700E43619 /* Animation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Animation.h; path = src/Animation.h; sourceTree = SOURCE_ROOT; };
+		42C8EDB914724CD700E43619 /* AnimationChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnimationChannel.cpp; path = src/AnimationChannel.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDBA14724CD700E43619 /* AnimationChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnimationChannel.h; path = src/AnimationChannel.h; sourceTree = SOURCE_ROOT; };
+		42C8EDBB14724CD700E43619 /* Animations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Animations.cpp; path = src/Animations.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDBC14724CD700E43619 /* Animations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Animations.h; path = src/Animations.h; sourceTree = SOURCE_ROOT; };
+		42C8EDBD14724CD700E43619 /* Base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Base.cpp; path = src/Base.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDBE14724CD700E43619 /* Base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Base.h; path = src/Base.h; sourceTree = SOURCE_ROOT; };
+		42C8EDBF14724CD700E43619 /* Camera.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Camera.cpp; path = src/Camera.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDC014724CD700E43619 /* Camera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Camera.h; path = src/Camera.h; sourceTree = SOURCE_ROOT; };
+		42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DAEChannelTarget.cpp; path = src/DAEChannelTarget.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDC414724CD700E43619 /* DAEChannelTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAEChannelTarget.h; path = src/DAEChannelTarget.h; sourceTree = SOURCE_ROOT; };
+		42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DAEOptimizer.cpp; path = src/DAEOptimizer.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDC614724CD700E43619 /* DAEOptimizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAEOptimizer.h; path = src/DAEOptimizer.h; sourceTree = SOURCE_ROOT; };
+		42C8EDC714724CD700E43619 /* DAESceneEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DAESceneEncoder.cpp; path = src/DAESceneEncoder.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDC814724CD700E43619 /* DAESceneEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAESceneEncoder.h; path = src/DAESceneEncoder.h; sourceTree = SOURCE_ROOT; };
+		42C8EDC914724CD700E43619 /* DAEUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DAEUtil.cpp; path = src/DAEUtil.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDCA14724CD700E43619 /* DAEUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAEUtil.h; path = src/DAEUtil.h; sourceTree = SOURCE_ROOT; };
+		42C8EDCB14724CD700E43619 /* Effect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Effect.cpp; path = src/Effect.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDCC14724CD700E43619 /* Effect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Effect.h; path = src/Effect.h; sourceTree = SOURCE_ROOT; };
+		42C8EDCD14724CD700E43619 /* EncoderArguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = EncoderArguments.cpp; path = src/EncoderArguments.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDCE14724CD700E43619 /* EncoderArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EncoderArguments.h; path = src/EncoderArguments.h; sourceTree = SOURCE_ROOT; };
+		42C8EDCF14724CD700E43619 /* FileIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileIO.cpp; path = src/FileIO.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDD014724CD700E43619 /* FileIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileIO.h; path = src/FileIO.h; sourceTree = SOURCE_ROOT; };
+		42C8EDD114724CD700E43619 /* Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Font.cpp; path = src/Font.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDD214724CD700E43619 /* Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Font.h; path = src/Font.h; sourceTree = SOURCE_ROOT; };
+		42C8EDD314724CD700E43619 /* Glyph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Glyph.cpp; path = src/Glyph.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDD414724CD700E43619 /* Glyph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Glyph.h; path = src/Glyph.h; sourceTree = SOURCE_ROOT; };
+		42C8EDD514724CD700E43619 /* GPBDecoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GPBDecoder.cpp; path = src/GPBDecoder.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDD614724CD700E43619 /* GPBDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPBDecoder.h; path = src/GPBDecoder.h; sourceTree = SOURCE_ROOT; };
+		42C8EDD714724CD700E43619 /* GPBFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GPBFile.cpp; path = src/GPBFile.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDD814724CD700E43619 /* GPBFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPBFile.h; path = src/GPBFile.h; sourceTree = SOURCE_ROOT; };
+		42C8EDD914724CD700E43619 /* Light.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Light.cpp; path = src/Light.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDDA14724CD700E43619 /* Light.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Light.h; path = src/Light.h; sourceTree = SOURCE_ROOT; };
+		42C8EDDD14724CD700E43619 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = src/main.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDDE14724CD700E43619 /* Material.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Material.cpp; path = src/Material.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDDF14724CD700E43619 /* Material.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Material.h; path = src/Material.h; sourceTree = SOURCE_ROOT; };
+		42C8EDE014724CD700E43619 /* MaterialParameter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MaterialParameter.cpp; path = src/MaterialParameter.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDE114724CD700E43619 /* MaterialParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MaterialParameter.h; path = src/MaterialParameter.h; sourceTree = SOURCE_ROOT; };
+		42C8EDE214724CD700E43619 /* Matrix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Matrix.cpp; path = src/Matrix.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDE314724CD700E43619 /* Matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Matrix.h; path = src/Matrix.h; sourceTree = SOURCE_ROOT; };
+		42C8EDE414724CD700E43619 /* Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mesh.cpp; path = src/Mesh.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDE514724CD700E43619 /* Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mesh.h; path = src/Mesh.h; sourceTree = SOURCE_ROOT; };
+		42C8EDE614724CD700E43619 /* MeshPart.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MeshPart.cpp; path = src/MeshPart.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDE714724CD700E43619 /* MeshPart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MeshPart.h; path = src/MeshPart.h; sourceTree = SOURCE_ROOT; };
+		42C8EDE814724CD700E43619 /* MeshSkin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MeshSkin.cpp; path = src/MeshSkin.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDE914724CD700E43619 /* MeshSkin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MeshSkin.h; path = src/MeshSkin.h; sourceTree = SOURCE_ROOT; };
+		42C8EDEA14724CD700E43619 /* MeshSubSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MeshSubSet.cpp; path = src/MeshSubSet.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDEB14724CD700E43619 /* MeshSubSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MeshSubSet.h; path = src/MeshSubSet.h; sourceTree = SOURCE_ROOT; };
+		42C8EDEC14724CD700E43619 /* Model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Model.cpp; path = src/Model.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDED14724CD700E43619 /* Model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Model.h; path = src/Model.h; sourceTree = SOURCE_ROOT; };
+		42C8EDEE14724CD700E43619 /* Node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Node.cpp; path = src/Node.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDEF14724CD700E43619 /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Node.h; path = src/Node.h; sourceTree = SOURCE_ROOT; };
+		42C8EDF014724CD700E43619 /* Object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Object.cpp; path = src/Object.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDF114724CD700E43619 /* Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Object.h; path = src/Object.h; sourceTree = SOURCE_ROOT; };
+		42C8EDF214724CD700E43619 /* Quaternion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Quaternion.cpp; path = src/Quaternion.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDF314724CD700E43619 /* Quaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Quaternion.h; path = src/Quaternion.h; sourceTree = SOURCE_ROOT; };
+		42C8EDF414724CD700E43619 /* Reference.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Reference.cpp; path = src/Reference.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDF514724CD700E43619 /* Reference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Reference.h; path = src/Reference.h; sourceTree = SOURCE_ROOT; };
+		42C8EDF614724CD700E43619 /* ReferenceTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ReferenceTable.cpp; path = src/ReferenceTable.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDF714724CD700E43619 /* ReferenceTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ReferenceTable.h; path = src/ReferenceTable.h; sourceTree = SOURCE_ROOT; };
+		42C8EDF814724CD700E43619 /* Scene.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Scene.cpp; path = src/Scene.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDF914724CD700E43619 /* Scene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Scene.h; path = src/Scene.h; sourceTree = SOURCE_ROOT; };
+		42C8EDFA14724CD700E43619 /* StringUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringUtil.cpp; path = src/StringUtil.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDFB14724CD700E43619 /* StringUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringUtil.h; path = src/StringUtil.h; sourceTree = SOURCE_ROOT; };
+		42C8EDFC14724CD700E43619 /* Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Transform.cpp; path = src/Transform.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDFD14724CD700E43619 /* Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Transform.h; path = src/Transform.h; sourceTree = SOURCE_ROOT; };
+		42C8EDFE14724CD700E43619 /* TTFFontEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TTFFontEncoder.cpp; path = src/TTFFontEncoder.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EDFF14724CD700E43619 /* TTFFontEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TTFFontEncoder.h; path = src/TTFFontEncoder.h; sourceTree = SOURCE_ROOT; };
+		42C8EE0014724CD700E43619 /* Vector2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vector2.cpp; path = src/Vector2.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EE0114724CD700E43619 /* Vector2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vector2.h; path = src/Vector2.h; sourceTree = SOURCE_ROOT; };
+		42C8EE0214724CD700E43619 /* Vector3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vector3.cpp; path = src/Vector3.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EE0314724CD700E43619 /* Vector3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vector3.h; path = src/Vector3.h; sourceTree = SOURCE_ROOT; };
+		42C8EE0414724CD700E43619 /* Vector4.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vector4.cpp; path = src/Vector4.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EE0514724CD700E43619 /* Vector4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vector4.h; path = src/Vector4.h; sourceTree = SOURCE_ROOT; };
+		42C8EE0614724CD700E43619 /* Vertex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vertex.cpp; path = src/Vertex.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EE0714724CD700E43619 /* Vertex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vertex.h; path = src/Vertex.h; sourceTree = SOURCE_ROOT; };
+		42C8EE0814724CD700E43619 /* VertexElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VertexElement.cpp; path = src/VertexElement.cpp; sourceTree = SOURCE_ROOT; };
+		42C8EE0914724CD700E43619 /* VertexElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexElement.h; path = src/VertexElement.h; sourceTree = SOURCE_ROOT; };
+		42C8EE341472B60100E43619 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = "../external-deps/freetype2/lib/macos/libfreetype.a"; sourceTree = "<group>"; };
+		42C8EE361472D7E700E43619 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
+		42C8EE381472DAA300E43619 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+		42C8EE3A1472DAAE00E43619 /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; };
+		42D277571472EFA700D867A4 /* libpcre.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcre.a; path = "../external-deps/pcre/lib/macos/libpcre.a"; sourceTree = "<group>"; };
+		42D277581472EFA700D867A4 /* libpcrecpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcrecpp.a; path = "../external-deps/pcre/lib/macos/libpcrecpp.a"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		42475CE3147208A000610A6A /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				42D277591472EFA700D867A4 /* libpcre.a in Frameworks */,
+				42D2775A1472EFA700D867A4 /* libpcrecpp.a in Frameworks */,
+				42C8EE351472B60100E43619 /* libfreetype.a in Frameworks */,
+				42475D7C14720ECE00610A6A /* libdom.a in Frameworks */,
+				42C8EE3B1472DAAE00E43619 /* libbz2.dylib in Frameworks */,
+				42C8EE391472DAA300E43619 /* libz.dylib in Frameworks */,
+				42C8EE371472D7E700E43619 /* libxml2.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		42475CDB147208A000610A6A = {
+			isa = PBXGroup;
+			children = (
+				4283906414896F3000E2B2F5 /* gameplay */,
+				42475CE9147208A000610A6A /* src */,
+				427D4F44147DC9080076760E /* Libraries */,
+				42475CE7147208A000610A6A /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		42475CE7147208A000610A6A /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				42475CE6147208A000610A6A /* gameplay-encoder */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		42475CE9147208A000610A6A /* src */ = {
+			isa = PBXGroup;
+			children = (
+				42C8EDB714724CD700E43619 /* Animation.cpp */,
+				42C8EDB814724CD700E43619 /* Animation.h */,
+				42C8EDB914724CD700E43619 /* AnimationChannel.cpp */,
+				42C8EDBA14724CD700E43619 /* AnimationChannel.h */,
+				42C8EDBB14724CD700E43619 /* Animations.cpp */,
+				42C8EDBC14724CD700E43619 /* Animations.h */,
+				42C8EDBD14724CD700E43619 /* Base.cpp */,
+				42C8EDBE14724CD700E43619 /* Base.h */,
+				4283905714896E6C00E2B2F5 /* BoundingVolume.cpp */,
+				4283905814896E6C00E2B2F5 /* BoundingVolume.h */,
+				42C8EDBF14724CD700E43619 /* Camera.cpp */,
+				42C8EDC014724CD700E43619 /* Camera.h */,
+				42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */,
+				42C8EDC414724CD700E43619 /* DAEChannelTarget.h */,
+				42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */,
+				42C8EDC614724CD700E43619 /* DAEOptimizer.h */,
+				42C8EDC714724CD700E43619 /* DAESceneEncoder.cpp */,
+				42C8EDC814724CD700E43619 /* DAESceneEncoder.h */,
+				42C8EDC914724CD700E43619 /* DAEUtil.cpp */,
+				42C8EDCA14724CD700E43619 /* DAEUtil.h */,
+				42C8EDCB14724CD700E43619 /* Effect.cpp */,
+				42C8EDCC14724CD700E43619 /* Effect.h */,
+				42C8EDCD14724CD700E43619 /* EncoderArguments.cpp */,
+				42C8EDCE14724CD700E43619 /* EncoderArguments.h */,
+				4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */,
+				4278341F148D6F7500A6E27F /* FBXSceneEncoder.h */,
+				42C8EDCF14724CD700E43619 /* FileIO.cpp */,
+				42C8EDD014724CD700E43619 /* FileIO.h */,
+				42C8EDD114724CD700E43619 /* Font.cpp */,
+				42C8EDD214724CD700E43619 /* Font.h */,
+				42C8EDD314724CD700E43619 /* Glyph.cpp */,
+				42C8EDD414724CD700E43619 /* Glyph.h */,
+				42C8EDD514724CD700E43619 /* GPBDecoder.cpp */,
+				42C8EDD614724CD700E43619 /* GPBDecoder.h */,
+				42C8EDD714724CD700E43619 /* GPBFile.cpp */,
+				42C8EDD814724CD700E43619 /* GPBFile.h */,
+				42C8EDD914724CD700E43619 /* Light.cpp */,
+				42C8EDDA14724CD700E43619 /* Light.h */,
+				42C8EDDD14724CD700E43619 /* main.cpp */,
+				42C8EDDE14724CD700E43619 /* Material.cpp */,
+				42C8EDDF14724CD700E43619 /* Material.h */,
+				42C8EDE014724CD700E43619 /* MaterialParameter.cpp */,
+				42C8EDE114724CD700E43619 /* MaterialParameter.h */,
+				42C8EDE214724CD700E43619 /* Matrix.cpp */,
+				42C8EDE314724CD700E43619 /* Matrix.h */,
+				42C8EDE414724CD700E43619 /* Mesh.cpp */,
+				42C8EDE514724CD700E43619 /* Mesh.h */,
+				42C8EDE614724CD700E43619 /* MeshPart.cpp */,
+				42C8EDE714724CD700E43619 /* MeshPart.h */,
+				42C8EDE814724CD700E43619 /* MeshSkin.cpp */,
+				42C8EDE914724CD700E43619 /* MeshSkin.h */,
+				42C8EDEA14724CD700E43619 /* MeshSubSet.cpp */,
+				42C8EDEB14724CD700E43619 /* MeshSubSet.h */,
+				42C8EDEC14724CD700E43619 /* Model.cpp */,
+				42C8EDED14724CD700E43619 /* Model.h */,
+				42C8EDEE14724CD700E43619 /* Node.cpp */,
+				42C8EDEF14724CD700E43619 /* Node.h */,
+				42C8EDF014724CD700E43619 /* Object.cpp */,
+				42C8EDF114724CD700E43619 /* Object.h */,
+				42C8EDF214724CD700E43619 /* Quaternion.cpp */,
+				42C8EDF314724CD700E43619 /* Quaternion.h */,
+				42C8EDF414724CD700E43619 /* Reference.cpp */,
+				42C8EDF514724CD700E43619 /* Reference.h */,
+				42C8EDF614724CD700E43619 /* ReferenceTable.cpp */,
+				42C8EDF714724CD700E43619 /* ReferenceTable.h */,
+				42C8EDF814724CD700E43619 /* Scene.cpp */,
+				42C8EDF914724CD700E43619 /* Scene.h */,
+				42C8EDFA14724CD700E43619 /* StringUtil.cpp */,
+				42C8EDFB14724CD700E43619 /* StringUtil.h */,
+				42C8EDFC14724CD700E43619 /* Transform.cpp */,
+				42C8EDFD14724CD700E43619 /* Transform.h */,
+				42C8EDFE14724CD700E43619 /* TTFFontEncoder.cpp */,
+				42C8EDFF14724CD700E43619 /* TTFFontEncoder.h */,
+				42C8EE0014724CD700E43619 /* Vector2.cpp */,
+				42C8EE0114724CD700E43619 /* Vector2.h */,
+				42783420148D6F7500A6E27F /* Vector2.inl */,
+				42C8EE0214724CD700E43619 /* Vector3.cpp */,
+				42C8EE0314724CD700E43619 /* Vector3.h */,
+				42783421148D6F7500A6E27F /* Vector3.inl */,
+				42C8EE0414724CD700E43619 /* Vector4.cpp */,
+				42C8EE0514724CD700E43619 /* Vector4.h */,
+				42783422148D6F7500A6E27F /* Vector4.inl */,
+				42C8EE0614724CD700E43619 /* Vertex.cpp */,
+				42C8EE0714724CD700E43619 /* Vertex.h */,
+				42C8EE0814724CD700E43619 /* VertexElement.cpp */,
+				42C8EE0914724CD700E43619 /* VertexElement.h */,
+			);
+			name = src;
+			path = "gameplay-encoder";
+			sourceTree = "<group>";
+		};
+		427D4F44147DC9080076760E /* Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				42D277571472EFA700D867A4 /* libpcre.a */,
+				42D277581472EFA700D867A4 /* libpcrecpp.a */,
+				42C8EE3A1472DAAE00E43619 /* libbz2.dylib */,
+				42C8EE381472DAA300E43619 /* libz.dylib */,
+				42C8EE361472D7E700E43619 /* libxml2.dylib */,
+				42C8EE341472B60100E43619 /* libfreetype.a */,
+				42475D7B14720ECE00610A6A /* libdom.a */,
+			);
+			name = Libraries;
+			sourceTree = "<group>";
+		};
+		4283906414896F3000E2B2F5 /* gameplay */ = {
+			isa = PBXGroup;
+			children = (
+				4283906114896F1600E2B2F5 /* Curve.cpp */,
+				4283906214896F1600E2B2F5 /* Curve.h */,
+			);
+			name = gameplay;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		42475CE5147208A000610A6A /* gameplay-encoder */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 42475CF0147208A100610A6A /* Build configuration list for PBXNativeTarget "gameplay-encoder" */;
+			buildPhases = (
+				42475CE2147208A000610A6A /* Sources */,
+				42475CE3147208A000610A6A /* Frameworks */,
+				42475CE4147208A000610A6A /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "gameplay-encoder";
+			productName = "gameplay-encoder";
+			productReference = 42475CE6147208A000610A6A /* gameplay-encoder */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		42475CDD147208A000610A6A /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0420;
+			};
+			buildConfigurationList = 42475CE0147208A000610A6A /* Build configuration list for PBXProject "gameplay-encoder" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 42475CDB147208A000610A6A;
+			productRefGroup = 42475CE7147208A000610A6A /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				42475CE5147208A000610A6A /* gameplay-encoder */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		42475CE2147208A000610A6A /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				42C8EE0A14724CD700E43619 /* Animation.cpp in Sources */,
+				42C8EE0B14724CD700E43619 /* AnimationChannel.cpp in Sources */,
+				42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */,
+				42C8EE0D14724CD700E43619 /* Base.cpp in Sources */,
+				42C8EE0E14724CD700E43619 /* Camera.cpp in Sources */,
+				42C8EE1014724CD700E43619 /* DAEChannelTarget.cpp in Sources */,
+				42C8EE1114724CD700E43619 /* DAEOptimizer.cpp in Sources */,
+				42C8EE1214724CD700E43619 /* DAESceneEncoder.cpp in Sources */,
+				42C8EE1314724CD700E43619 /* DAEUtil.cpp in Sources */,
+				42C8EE1414724CD700E43619 /* Effect.cpp in Sources */,
+				42C8EE1514724CD700E43619 /* EncoderArguments.cpp in Sources */,
+				42C8EE1614724CD700E43619 /* FileIO.cpp in Sources */,
+				42C8EE1714724CD700E43619 /* Font.cpp in Sources */,
+				42C8EE1814724CD700E43619 /* Glyph.cpp in Sources */,
+				42C8EE1914724CD700E43619 /* GPBDecoder.cpp in Sources */,
+				42C8EE1A14724CD700E43619 /* GPBFile.cpp in Sources */,
+				42C8EE1B14724CD700E43619 /* Light.cpp in Sources */,
+				42C8EE1D14724CD700E43619 /* main.cpp in Sources */,
+				42C8EE1E14724CD700E43619 /* Material.cpp in Sources */,
+				42C8EE1F14724CD700E43619 /* MaterialParameter.cpp in Sources */,
+				42C8EE2014724CD700E43619 /* Matrix.cpp in Sources */,
+				42C8EE2114724CD700E43619 /* Mesh.cpp in Sources */,
+				42C8EE2214724CD700E43619 /* MeshPart.cpp in Sources */,
+				42C8EE2314724CD700E43619 /* MeshSkin.cpp in Sources */,
+				42C8EE2414724CD700E43619 /* MeshSubSet.cpp in Sources */,
+				42C8EE2514724CD700E43619 /* Model.cpp in Sources */,
+				42C8EE2614724CD700E43619 /* Node.cpp in Sources */,
+				42C8EE2714724CD700E43619 /* Object.cpp in Sources */,
+				42C8EE2814724CD700E43619 /* Quaternion.cpp in Sources */,
+				42C8EE2914724CD700E43619 /* Reference.cpp in Sources */,
+				42C8EE2A14724CD700E43619 /* ReferenceTable.cpp in Sources */,
+				42C8EE2B14724CD700E43619 /* Scene.cpp in Sources */,
+				42C8EE2C14724CD700E43619 /* StringUtil.cpp in Sources */,
+				42C8EE2D14724CD700E43619 /* Transform.cpp in Sources */,
+				42C8EE2E14724CD700E43619 /* TTFFontEncoder.cpp in Sources */,
+				42C8EE2F14724CD700E43619 /* Vector2.cpp in Sources */,
+				42C8EE3014724CD700E43619 /* Vector3.cpp in Sources */,
+				42C8EE3114724CD700E43619 /* Vector4.cpp in Sources */,
+				42C8EE3214724CD700E43619 /* Vertex.cpp in Sources */,
+				42C8EE3314724CD700E43619 /* VertexElement.cpp in Sources */,
+				4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */,
+				4283906314896F1600E2B2F5 /* Curve.cpp in Sources */,
+				42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		42475CEE147208A100610A6A /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				COPY_PHASE_STRIP = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					DOM_INCLUDE_LIBXML,
+					NO_BOOST,
+					NO_ZAE,
+					"DEBUG=1",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					"../external-deps/freetype/include",
+					"../external-deps/collada-dom/include",
+					"../external-deps/collada-dom/include/1.4",
+				);
+				INFOPLIST_PREPROCESSOR_DEFINITIONS = "";
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				ONLY_ACTIVE_ARCH = YES;
+				OTHER_TEST_FLAGS = "";
+				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
+				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4";
+				WARNING_CFLAGS = "";
+			};
+			name = Debug;
+		};
+		42475CEF147208A100610A6A /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					DOM_INCLUDE_LIBXML,
+					NO_BOOST,
+					NO_ZAE,
+				);
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					"../external-deps/freetype/include",
+					"../external-deps/collada-dom/include",
+					"../external-deps/collada-dom/include/1.4",
+				);
+				INFOPLIST_PREPROCESSOR_DEFINITIONS = "";
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				OTHER_TEST_FLAGS = "";
+				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
+				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4";
+				WARNING_CFLAGS = "";
+			};
+			name = Release;
+		};
+		42475CF1147208A100610A6A /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
+				CLANG_CXX_LIBRARY = "compiler-default";
+				GCC_C_LANGUAGE_STANDARD = "compiler-default";
+				GCC_ENABLE_CPP_EXCEPTIONS = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					"../external-deps/freetype2/include",
+					"../external-deps/collada-dom/include",
+					"../external-deps/collada-dom/include/1.4",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)/../external-deps/freetype2/lib/macos\"",
+					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macos\"",
+					"\"$(SRCROOT)/../external-deps/pcre/lib/macos\"",
+					"\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
+					"\"$(SYSTEM_APPS_DIR)/Autodesk/FBXSDK20122/lib/gcc4/ub\"",
+				);
+				MACH_O_TYPE = mh_execute;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype2/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 /Applications/Autodesk/FBXSDK20122/include";
+			};
+			name = Debug;
+		};
+		42475CF2147208A100610A6A /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
+				CLANG_CXX_LIBRARY = "compiler-default";
+				GCC_C_LANGUAGE_STANDARD = "compiler-default";
+				GCC_ENABLE_CPP_EXCEPTIONS = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					"../external-deps/freetype2/include",
+					"../external-deps/collada-dom/include",
+					"../external-deps/collada-dom/include/1.4",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)/../external-deps/freetype2/lib/macos\"",
+					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macos\"",
+					"\"$(SRCROOT)/../external-deps/pcre/lib/macos\"",
+					"\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
+					"\"$(SYSTEM_APPS_DIR)/Autodesk/FBXSDK20122/lib/gcc4/ub\"",
+				);
+				MACH_O_TYPE = mh_execute;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype2/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 /Applications/Autodesk/FBXSDK20122/include";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		42475CE0147208A000610A6A /* Build configuration list for PBXProject "gameplay-encoder" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				42475CEE147208A100610A6A /* Debug */,
+				42475CEF147208A100610A6A /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		42475CF0147208A100610A6A /* Build configuration list for PBXNativeTarget "gameplay-encoder" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				42475CF1147208A100610A6A /* Debug */,
+				42475CF2147208A100610A6A /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 42475CDD147208A000610A6A /* Project object */;
+}

+ 8 - 2
gameplay-encoder/src/Animation.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Animation.h"
 #include "Animation.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -26,7 +27,7 @@ void Animation::writeBinary(FILE* file)
     // Animation writes its ID because it is not listed in the ref table.
     // Animation writes its ID because it is not listed in the ref table.
     write(getId(), file);
     write(getId(), file);
     write(_channels.size(), file);
     write(_channels.size(), file);
-    for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); i++)
+    for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); ++i)
     {
     {
         (*i)->writeBinary(file);
         (*i)->writeBinary(file);
     }
     }
@@ -37,7 +38,7 @@ void Animation::writeText(FILE* file)
     fprintElementStart(file);
     fprintElementStart(file);
     if (_channels.size() > 0 )
     if (_channels.size() > 0 )
     {
     {
-        for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); i++)
+        for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); ++i)
         {
         {
             (*i)->writeText(file);
             (*i)->writeText(file);
         }
         }
@@ -55,4 +56,9 @@ unsigned int Animation::getAnimationChannelCount() const
     return _channels.size();
     return _channels.size();
 }
 }
 
 
+AnimationChannel* Animation::getAnimationChannel(unsigned int index) const
+{
+    return _channels[index];
+}
+
 }
 }

+ 8 - 0
gameplay-encoder/src/Animation.h

@@ -27,6 +27,7 @@ public:
     virtual void writeText(FILE* file);
     virtual void writeText(FILE* file);
 
 
     void add(AnimationChannel* animationChannel);
     void add(AnimationChannel* animationChannel);
+
     /**
     /**
      * Returns the number of animation channels contained in this animation.
      * Returns the number of animation channels contained in this animation.
      * 
      * 
@@ -34,9 +35,16 @@ public:
      */
      */
     unsigned int getAnimationChannelCount() const;
     unsigned int getAnimationChannelCount() const;
 
 
+    /**
+     * Returns the specified animation channel.
+     */
+    AnimationChannel* getAnimationChannel(unsigned int index) const;
+
 private:
 private:
+
     std::vector<AnimationChannel*> _channels;
     std::vector<AnimationChannel*> _channels;
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 160 - 5
gameplay-encoder/src/AnimationChannel.cpp

@@ -1,4 +1,6 @@
+#include "Base.h"
 #include "AnimationChannel.h"
 #include "AnimationChannel.h"
+#include "Transform.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -27,7 +29,7 @@ void AnimationChannel::writeBinary(FILE* file)
     write(_targetId, file);
     write(_targetId, file);
     write(_targetAttrib, file);
     write(_targetAttrib, file);
     write(_keytimes.size(), file);
     write(_keytimes.size(), file);
-    for (std::vector<float>::const_iterator i = _keytimes.begin(); i != _keytimes.end(); i++)
+    for (std::vector<float>::const_iterator i = _keytimes.begin(); i != _keytimes.end(); ++i)
     {
     {
         write((unsigned long)*i, file);
         write((unsigned long)*i, file);
     }
     }
@@ -35,7 +37,6 @@ void AnimationChannel::writeBinary(FILE* file)
     write(_tangentsIn, file);
     write(_tangentsIn, file);
     write(_tangentsOut, file);
     write(_tangentsOut, file);
     write(_interpolations, file);
     write(_interpolations, file);
-
 }
 }
 
 
 void AnimationChannel::writeText(FILE* file)
 void AnimationChannel::writeText(FILE* file)
@@ -51,7 +52,48 @@ void AnimationChannel::writeText(FILE* file)
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
-void AnimationChannel::setTargetId(const std::string str)
+void AnimationChannel::setInterpolation(unsigned int interpolation)
+{
+    _interpolations.clear();
+    _interpolations.push_back(interpolation);
+}
+
+const std::string& AnimationChannel::getTargetId() const
+{
+    return _targetId;
+}
+
+unsigned int AnimationChannel::getTargetAttribute() const
+{
+    return _targetAttrib;
+}
+
+const std::vector<float>& AnimationChannel::getKeyValues() const
+{
+    return _keyValues;
+}
+
+const std::vector<float>& AnimationChannel::getKeyTimes() const
+{
+    return _keytimes;
+}
+
+const std::vector<float>& AnimationChannel::getTangentsIn() const
+{
+    return _tangentsIn;
+}
+
+const std::vector<float>& AnimationChannel::getTangentsOut() const
+{
+    return _tangentsOut;
+}
+
+const std::vector<unsigned int>& AnimationChannel::getInterpolationTypes() const
+{
+    return _interpolations;
+}
+
+void AnimationChannel::setTargetId(const std::string& str)
 {
 {
     _targetId = str;
     _targetId = str;
 }
 }
@@ -86,9 +128,101 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values
     _interpolations = values;
     _interpolations = values;
 }
 }
 
 
-const std::vector<float>& AnimationChannel::getKeyValues() const
+void AnimationChannel::removeDuplicates()
 {
 {
-    return _keyValues;
+    if (_targetAttrib == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+    {
+        size_t prevIndex = 0;
+
+        std::vector<float>::iterator prevStart = _keyValues.begin();
+        std::vector<float>::iterator prevEnd   = _keyValues.begin() + 9;
+        
+        size_t i = 1;
+        for (i = 1; i < _keytimes.size(); ++i)
+        {
+            std::vector<float>::iterator start = _keyValues.begin() + i * 10;
+            std::vector<float>::iterator end = _keyValues.begin() + (i * 10 + 9);
+
+            if (!equal(prevStart, prevEnd, start))
+            {
+                if (i - prevIndex > 2)
+                {
+                    deleteRange(prevIndex+1, i);
+                    i = prevIndex;
+                    prevStart = _keyValues.begin() + i * 10;
+                    prevEnd = _keyValues.begin() + (i * 10 + 9);
+                }
+                else
+                {
+                    prevStart = start;
+                    prevEnd = end;
+                    prevIndex = i;
+                }
+            }
+        }
+        if (i - 1 - prevIndex >= 2)
+        {
+            deleteRange(prevIndex+1, i);
+        }
+    }
+}
+
+void AnimationChannel::convertToQuaternion()
+{
+    if (_targetAttrib == Transform::ANIMATE_ROTATE_X ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Y ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Z)
+    {
+        std::vector<float> newKeyValues;
+        newKeyValues.resize(_keyValues.size() * 4);
+        const size_t count = _keyValues.size();
+
+        float x = _targetAttrib == Transform::ANIMATE_ROTATE_X ? 1.0f : 0.0f;
+        float y = _targetAttrib == Transform::ANIMATE_ROTATE_Y ? 1.0f : 0.0f;
+        float z = _targetAttrib == Transform::ANIMATE_ROTATE_Z ? 1.0f : 0.0f;
+        for (size_t i = 0; i < count; ++i)
+        {
+            size_t j = i << 2;
+            newKeyValues[j] = x;
+            newKeyValues[j+1] = y;
+            newKeyValues[j+2] = z;
+            newKeyValues[j+3] = _keyValues[i];
+        }
+        setKeyValues(newKeyValues);
+        setTargetAttribute(Transform::ANIMATE_ROTATE);
+    }
+}
+
+void AnimationChannel::convertToTransform()
+{
+    if (_targetAttrib == Transform::ANIMATE_ROTATE_X ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Y ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Z)
+    {
+        std::vector<float> newKeyValues;
+        newKeyValues.resize(_keyValues.size() * 10);
+        const size_t count = _keyValues.size();
+
+        float x = _targetAttrib == Transform::ANIMATE_ROTATE_X ? 1.0f : 0.0f;
+        float y = _targetAttrib == Transform::ANIMATE_ROTATE_Y ? 1.0f : 0.0f;
+        float z = _targetAttrib == Transform::ANIMATE_ROTATE_Z ? 1.0f : 0.0f;
+        for (size_t i = 0; i < count; ++i)
+        {
+            size_t j = i << 2;
+            newKeyValues[j+0] = 1.0f;
+            newKeyValues[j+1] = 1.0f;
+            newKeyValues[j+2] = 1.0f;
+            newKeyValues[j+3] = x;
+            newKeyValues[j+4] = y;
+            newKeyValues[j+5] = z;
+            newKeyValues[j+6] = _keyValues[i];
+            newKeyValues[j+7] = 0.0f;
+            newKeyValues[j+8] = 0.0f;
+            newKeyValues[j+9] = 0.0f;
+        }
+        setKeyValues(newKeyValues);
+        setTargetAttribute(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE);
+    }
 }
 }
 
 
 unsigned int AnimationChannel::getInterpolationType(const char* str)
 unsigned int AnimationChannel::getInterpolationType(const char* str)
@@ -136,4 +270,25 @@ unsigned int AnimationChannel::getInterpolationType(const char* str)
     return value;
     return value;
 }
 }
 
 
+void AnimationChannel::deleteRange(size_t begin, size_t end)
+{
+    // delete range
+    printf("delete %lu to %lu\n", begin, end - 1);
+
+    std::vector<float>::iterator a = _keyValues.begin() + begin * 10;
+    std::vector<float>::iterator b = _keyValues.begin() + end * 10;
+    _keyValues.erase(a, b);
+
+    a = _keytimes.begin() + begin;
+    b = _keytimes.begin() + end;
+    _keytimes.erase(a, b);
+
+    if (_interpolations.size() > 1)
+    {
+        std::vector<unsigned int>::iterator a = _interpolations.begin() + begin;
+        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * 10;
+        _interpolations.erase(a, b);
+    }
+}
+
 }
 }

+ 23 - 3
gameplay-encoder/src/AnimationChannel.h

@@ -35,7 +35,16 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
     virtual void writeText(FILE* file);
 
 
-    void setTargetId(const std::string str);
+    const std::string& getTargetId() const;
+
+    /**
+     * Sets the interpolation type of the entire animation channel.
+     * 
+     * @param interpolation The interpolation type from InterpolationTypes enum.
+     */
+    void setInterpolation(unsigned int interpolation);
+
+    void setTargetId(const std::string& str);
     void setTargetAttribute(unsigned int attrib);
     void setTargetAttribute(unsigned int attrib);
 
 
     void setKeyTimes(const std::vector<float>& values);
     void setKeyTimes(const std::vector<float>& values);
@@ -44,7 +53,17 @@ public:
     void setTangentsOut(const std::vector<float>& values);
     void setTangentsOut(const std::vector<float>& values);
     void setInterpolations(const std::vector<unsigned int>& values);
     void setInterpolations(const std::vector<unsigned int>& values);
 
 
+    unsigned int getTargetAttribute() const;
     const std::vector<float>& getKeyValues() const;
     const std::vector<float>& getKeyValues() const;
+    const std::vector<float>& getKeyTimes() const;
+    const std::vector<float>& getTangentsIn() const;
+    const std::vector<float>& getTangentsOut() const;
+    const std::vector<unsigned int>& getInterpolationTypes() const;
+
+    void removeDuplicates();
+
+    void convertToQuaternion();
+    void convertToTransform();
 
 
     /**
     /**
      * Returns the interpolation type value for the given string or zero if not valid.
      * Returns the interpolation type value for the given string or zero if not valid.
@@ -56,7 +75,9 @@ public:
      */
      */
     static unsigned int getInterpolationType(const char* str);
     static unsigned int getInterpolationType(const char* str);
 
 
+private:
 
 
+    void deleteRange(size_t begin, size_t end);
 private:
 private:
 
 
     std::string _targetId;
     std::string _targetId;
@@ -68,7 +89,6 @@ private:
     std::vector<unsigned int> _interpolations;
     std::vector<unsigned int> _interpolations;
 };
 };
 
 
-
 }
 }
-#endif
 
 
+#endif

+ 13 - 2
gameplay-encoder/src/Animations.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Animations.h"
 #include "Animations.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -27,7 +28,7 @@ void Animations::writeBinary(FILE* file)
 {
 {
     Object::writeBinary(file);
     Object::writeBinary(file);
     write(_animations.size(), file);
     write(_animations.size(), file);
-    for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); i++)
+    for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); ++i)
     {
     {
         (*i)->writeBinary(file);
         (*i)->writeBinary(file);
     }
     }
@@ -38,7 +39,7 @@ void Animations::writeText(FILE* file)
     fprintElementStart(file);
     fprintElementStart(file);
     if (_animations.size() > 0 )
     if (_animations.size() > 0 )
     {
     {
-        for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); i++)
+        for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); ++i)
         {
         {
             (*i)->writeText(file);
             (*i)->writeText(file);
         }
         }
@@ -51,4 +52,14 @@ void Animations::add(Animation* animation)
     _animations.push_back(animation);
     _animations.push_back(animation);
 }
 }
 
 
+unsigned int Animations::getAnimationCount() const
+{
+    return _animations.size();
+}
+
+Animation* Animations::getAnimation(unsigned int index) const
+{
+    return _animations[index];
+}
+
 }
 }

+ 4 - 0
gameplay-encoder/src/Animations.h

@@ -30,10 +30,14 @@ public:
     virtual void writeText(FILE* file);
     virtual void writeText(FILE* file);
 
 
     void add(Animation* animation);
     void add(Animation* animation);
+    unsigned int getAnimationCount() const;
+    Animation* getAnimation(unsigned int index) const;
 
 
 private:
 private:
+
     std::vector<Animation*> _animations;
     std::vector<Animation*> _animations;
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 1 - 21
gameplay-encoder/src/Base.cpp

@@ -5,30 +5,10 @@ namespace gameplay
 
 
 void fillArray(float values[], float value, size_t length)
 void fillArray(float values[], float value, size_t length)
 {
 {
-    for (size_t i = 0; i < length; i++)
+    for (size_t i = 0; i < length; ++i)
     {
     {
         values[i] = value;
         values[i] = value;
     }
     }
 }
 }
 
 
-void setIdentityMatrix(float values[])
-{
-    values[0] = 1.0f;
-    values[1] = 0.0f;
-    values[2] = 0.0f;
-    values[3] = 0.0f;
-    values[4] = 0.0f;
-    values[5] = 1.0f;
-    values[6] = 0.0f;
-    values[7] = 0.0f;
-    values[8] = 0.0f;
-    values[9] = 0.0f;
-    values[10] = 1.0f;
-    values[11] = 0.0f;
-    values[12] = 0.0f;
-    values[13] = 0.0f;
-    values[14] = 0.0f;
-    values[15] = 1.0f;
-}
-
 }
 }

+ 58 - 21
gameplay-encoder/src/Base.h

@@ -1,26 +1,55 @@
-#ifndef COMMON_H_
-#define COMMON_H_
+#ifndef BASE_H_
+#define BASE_H_
 
 
-#include <assert.h>
+// C++ includes
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdarg>
+#include <cassert>
+#include <cmath>
+#include <cfloat>
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <list>
 #include <map>
 #include <map>
+#include <algorithm>
+#include <sys/stat.h>
 
 
+// PNG
+#include <png.h>
+
+// Collada includes
+#include <dae.h>
+#include <dae/daeSIDResolver.h>
+#include <dae/domAny.h>
+#include <dom/domCOLLADA.h>
+#include <dom/domConstants.h>
+#include <dom/domElements.h>
+#include <dom/domCamera.h>
+#include <dom/domProfile_COMMON.h>
+
+// Defines
 #ifndef M_1_PI        
 #ifndef M_1_PI        
-#define M_1_PI                    0.31830988618379067154
+#define M_1_PI                      0.31830988618379067154
 #endif
 #endif
-#define MATH_FLOAT_SMALL        1.0e-37f
-#define MATH_TOLERANCE            2e-37f
-#define MATH_E                     2.71828182845904523536f
-#define MATH_LOG10E                0.4342944819032518f
-#define MATH_LOG2E                1.442695040888963387f
-#define MATH_PI                    3.14159265358979323846f
-#define MATH_PIOOVER2            1.57079632679489661923f
-#define MATH_PIOOVER4             M_PI_4
-#define MATH_PIX2                 6.28318530717958647693f
-#define MATH_EPSILON            0.000001f
-#define MATH_DEG_TO_RAD(x)         ((x) * 0.0174532925f)
-#define MATH_RAD_TO_DEG(x)        ((x)* 57.29577951f)
-#define MATH_RANDOM_MINUS1_1()  ((2.0f*((float)rand()/RAND_MAX))-1.0f) // Returns a random float between -1 and 1.
-#define MATH_RANDOM_0_1()       ((float)rand()/RAND_MAX) // Returns a random float between 0 and 1.
+#define MATH_FLOAT_SMALL            1.0e-37f
+#define MATH_TOLERANCE              2e-37f
+#define MATH_E                      2.71828182845904523536f
+#define MATH_LOG10E                 0.4342944819032518f
+#define MATH_LOG2E                  1.442695040888963387f
+#define MATH_PI                     3.14159265358979323846f
+#define MATH_PIOOVER2               1.57079632679489661923f
+#define MATH_PIOOVER4               M_PI_4
+#define MATH_PIX2                   6.28318530717958647693f
+#define MATH_EPSILON                0.000001f
+#define MATH_DEG_TO_RAD(x)          ((x) * 0.0174532925f)
+#define MATH_RAD_TO_DEG(x)          ((x)* 57.29577951f)
+#define MATH_RANDOM_MINUS1_1()      ((2.0f*((float)rand()/RAND_MAX))-1.0f) // Returns a random float between -1 and 1.
+#define MATH_RANDOM_0_1()           ((float)rand()/RAND_MAX) // Returns a random float between 0 and 1.
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -45,10 +74,18 @@ enum VertexUsage
     TEXCOORD7 = 15
     TEXCOORD7 = 15
 };
 };
 
 
-
 void fillArray(float values[], float value, size_t length);
 void fillArray(float values[], float value, size_t length);
-void setIdentityMatrix(float values[]);
 
 
-}
+#define ISZERO(x) (fabs(x) < 0.000001f)
+
+#ifdef NDEBUG
+#define DEBUGPRINT(x)
+#define DEBUGPRINT_VARG(x, ...)
+#else
+#define DEBUGPRINT(x)  printf(x)
+#define DEBUGPRINT_VARG(x, ...) printf(x, __VA_ARGS__)
 #endif
 #endif
 
 
+}
+
+#endif

+ 137 - 0
gameplay-encoder/src/BoundingVolume.cpp

@@ -0,0 +1,137 @@
+#include "Base.h"
+#include "BoundingVolume.h"
+
+namespace gameplay
+{
+
+BoundingVolume::BoundingVolume()
+    : radius(0.0f)
+{
+}
+
+void updateMinMax(Vector3* point, Vector3* min, Vector3* max)
+{
+    // Leftmost point.
+    if (point->x < min->x)
+    {
+        min->x = point->x;
+    }
+
+    // Rightmost point.
+    if (point->x > max->x)
+    {
+        max->x = point->x;
+    }
+
+    // Lowest point.
+    if (point->y < min->y)
+    {
+        min->y = point->y;
+    }
+
+    // Highest point.
+    if (point->y > max->y)
+    {
+        max->y = point->y;
+    }
+
+    // Farthest point.
+    if (point->z < min->z)
+    {
+        min->z = point->z;
+    }
+
+    // Nearest point.
+    if (point->z > max->z)
+    {
+        max->z = point->z;
+    }
+}
+
+void BoundingVolume::transform(const Matrix& m)
+{
+    // Transform the bounding sphere
+    m.transformPoint(center, &center);
+    Vector3 translate;
+    m.decompose(&translate, NULL, NULL);
+    float r = radius * translate.x;
+    r = std::max(radius, radius * translate.y);
+    r = std::max(radius, radius * translate.z);
+    radius = r;
+
+    // Transform the bounding box
+    Vector3 corners[8];
+    corners[0].set(min.x, max.y, max.z);
+    // Left-bottom-front.
+    corners[1].set(min.x, min.y, max.z);
+    // Right-bottom-front.
+    corners[2].set(max.x, min.y, max.z);
+    // Right-top-front.
+    corners[3].set(max.x, max.y, max.z);
+    // Right-top-back.
+    corners[4].set(max.x, max.y, min.z);
+    // Right-bottom-back.
+    corners[5].set(max.x, min.y, min.z);
+    // Left-bottom-back.
+    corners[6].set(min.x, min.y, min.z);
+    // Left-top-back.
+    corners[7].set(min.x, max.y, min.z);
+
+    // Transform the corners, recalculating the min and max points along the way.
+    m.transformPoint(corners[0], &corners[0]);
+    Vector3 newMin = corners[0];
+    Vector3 newMax = corners[0];
+    for (int i = 1; i < 8; i++)
+    {
+        m.transformPoint(corners[i], &corners[i]);
+        updateMinMax(&corners[i], &newMin, &newMax);
+    }
+    min = newMin;
+    max = newMax;
+}
+
+void BoundingVolume::merge(const BoundingVolume& v)
+{
+    // Calculate the distance between the two centers.
+    float vx = center.x - v.center.x;
+    float vy = center.y - v.center.y;
+    float vz = center.z - v.center.z;
+    float d = sqrt(vx * vx + vy * vy + vz * vz);
+
+    // If one sphere is contained inside the other, set to the larger sphere.
+    if (d <= (v.radius - radius))
+    {
+        // Use targert volume
+        radius = v.radius;
+        center = v.center;
+    }
+    else if (d <= (radius - v.radius))
+    {
+        // No change
+    }
+    else
+    {
+        // Calculate the unit vector between the two centers.
+        float dI = 1.0f / d;
+        vx *= dI;
+        vy *= dI;
+        vz *= dI;
+
+        // Calculate the new radius.
+        float r = (radius + v.radius + d) * 0.5f;
+
+        // Calculate the new center.
+        float scaleFactor = (r - v.radius);
+        vx = vx * scaleFactor + v.center.x;
+        vy = vy * scaleFactor + v.center.y;
+        vz = vz * scaleFactor + v.center.z;
+
+        // Set the new center and radius.
+        center.x = vx;
+        center.y = vy;
+        center.z = vz;
+        radius = r;
+    }
+}
+
+}

+ 57 - 0
gameplay-encoder/src/BoundingVolume.h

@@ -0,0 +1,57 @@
+#ifndef BOUNDINGVOLUME_H_
+#define BOUNDINGVOLUME_H_
+
+#include "Vector3.h"
+#include "Matrix.h"
+
+namespace gameplay
+{
+
+/**
+ * Represents a 3D bounding volumes, which defines both a
+ * bounding sphere and an axis-aligned bounding box (AABB).
+ */
+class BoundingVolume
+{
+public:
+
+    /**
+     * Radius of the bounding sphere.
+     */
+    float radius;
+
+    /**
+     * Center point of the bounding sphere.
+     */
+    Vector3 center;
+
+    /**
+     * Minimum point of the AABB.
+     */
+    Vector3 min;
+
+    /**
+     * Maximum point of the AABB.
+     */
+    Vector3 max;
+
+    /**
+     * Constructor.
+     */
+    BoundingVolume();
+
+    /**
+     * Transforms this bounding volume by the specified matrix.
+     */
+    void transform(const Matrix& m);
+
+    /**
+     * Merges this bounding volume with the specified one and
+     * stores the result in this BoundingVolume.
+     */
+    void merge(const BoundingVolume& v);
+};
+
+}
+
+#endif

+ 1 - 1
gameplay-encoder/src/Camera.cpp

@@ -1,4 +1,4 @@
-#include <assert.h>
+#include "Base.h"
 #include "Camera.h"
 #include "Camera.h"
 
 
 namespace gameplay
 namespace gameplay

+ 1 - 0
gameplay-encoder/src/Camera.h

@@ -54,4 +54,5 @@ private:
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 0 - 53
gameplay-encoder/src/CameraInstance.cpp

@@ -1,53 +0,0 @@
-#include "CameraInstance.h"
-
-namespace gameplay
-{
-
-CameraInstance::CameraInstance(void) : _ref(NULL)
-{
-
-}
-
-CameraInstance::~CameraInstance(void)
-{
-}
-
-unsigned int CameraInstance::getTypeId(void) const
-{
-    return CAMERAINSTANCE_ID;
-}
-const char* CameraInstance::getElementName(void) const
-{
-    return "CameraInstance";
-}
-
-void CameraInstance::writeBinary(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeBinary(file);
-    }
-    else
-    {
-        write((unsigned int)0, file);
-    }
-}
-void CameraInstance::writeText(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeText(file);
-    }
-}
-
-Camera* CameraInstance::getCamera()
-{
-    return _ref;
-}
-
-void CameraInstance::setCamera(Camera* camera)
-{
-    _ref = camera;
-}
-
-}

+ 0 - 36
gameplay-encoder/src/CameraInstance.h

@@ -1,36 +0,0 @@
-#ifndef CAMERAINSTANCE_H_
-#define CAMERAINSTANCE_H_
-
-#include "Object.h"
-#include "Camera.h"
-
-namespace gameplay
-{
-
-class CameraInstance : public Object
-{
-public:
-
-    /**
-     * Constructor.
-     */
-    CameraInstance(void);
-
-    /**
-     * Destructor.
-     */
-    virtual ~CameraInstance(void);
-
-    virtual unsigned int getTypeId(void) const;
-    virtual const char* getElementName(void) const;
-    virtual void writeBinary(FILE* file);
-    virtual void writeText(FILE* file);
-
-    Camera* getCamera();
-    void setCamera(Camera* camera);
-private:
-    Camera* _ref;
-};
-
-}
-#endif

+ 3 - 3
gameplay-encoder/src/DAEChannelTarget.cpp

@@ -1,7 +1,7 @@
 
 
+#include "Base.h"
 #include "DAEChannelTarget.h"
 #include "DAEChannelTarget.h"
 
 
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -40,7 +40,7 @@ DAEChannelTarget::DAEChannelTarget(const domChannelRef channelRef) : _channel(ch
                 index = end + 1;
                 index = end + 1;
             }
             }
             _attributeIds.push_back(sub);
             _attributeIds.push_back(sub);
-        } while(end != std::string::npos);
+        } while (end != std::string::npos);
     }
     }
 
 
 }
 }
@@ -98,4 +98,4 @@ void DAEChannelTarget::getPropertyName(size_t index, std::string* str)
     str->clear();
     str->clear();
 }
 }
 
 
-}
+}

+ 0 - 12
gameplay-encoder/src/DAEChannelTarget.h

@@ -1,18 +1,6 @@
 #ifndef DAECHANNELTARGET_H_
 #ifndef DAECHANNELTARGET_H_
 #define DAECHANNELTARGET_H_
 #define DAECHANNELTARGET_H_
 
 
-#include <dae.h>
-#include <dae/daeSIDResolver.h>
-#include <dae/domAny.h>
-#include <dom/domCOLLADA.h>
-#include <dom/domConstants.h>
-#include <dom/domElements.h>
-#include <dom/domProfile_COMMON.h>
-
-#include <vector>
-
-#include "Base.h"
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 

+ 10 - 57
gameplay-encoder/src/DAEOptimizer.cpp

@@ -1,8 +1,8 @@
+#include "Base.h"
 #include "DAEOptimizer.h"
 #include "DAEOptimizer.h"
 
 
-#include <algorithm>
-
-#include "StringUtil.h"
+namespace gameplay
+{
 
 
 DAEOptimizer::DAEOptimizer(domCOLLADA* dom)
 DAEOptimizer::DAEOptimizer(domCOLLADA* dom)
 {
 {
@@ -37,7 +37,7 @@ void DAEOptimizer::combineAnimations(const std::string& nodeId, const std::strin
     // TODO: Make sure that there doesn't already exist an animation with this ID.
     // TODO: Make sure that there doesn't already exist an animation with this ID.
 
 
     // Move each of the channels to this animation
     // Move each of the channels to this animation
-    for (std::list<domChannelRef>::iterator i = channels.begin(); i != channels.end(); i++)
+    for (std::list<domChannelRef>::iterator i = channels.begin(); i != channels.end(); ++i)
     {
     {
         moveChannelAndSouresToAnimation(*i, animation);
         moveChannelAndSouresToAnimation(*i, animation);
     }
     }
@@ -46,55 +46,6 @@ void DAEOptimizer::combineAnimations(const std::string& nodeId, const std::strin
     deleteEmptyAnimations();
     deleteEmptyAnimations();
 }
 }
 
 
-void DAEOptimizer::getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels)
-{
-    assert(node->getId());
-    std::string nodeIdSlash (node->getId());
-    nodeIdSlash.append("/");
-
-    domCOLLADA* root = (domCOLLADA*)node->getDocument()->getDomRoot();
-
-    domLibrary_animations_Array& animationLibrary = root->getLibrary_animations_array();
-    size_t animationLibraryCount = animationLibrary.getCount();
-    for (size_t i = 0; i < animationLibraryCount; i++)
-    {
-        domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
-        domAnimation_Array& animationArray = animationsRef->getAnimation_array();
-        size_t animationCount = animationArray.getCount();
-        for (size_t j = 0; j < animationCount; j++)
-        {
-            domAnimationRef& animationRef = animationArray.get(j);
-            domChannel_Array& channelArray = animationRef->getChannel_array();
-            size_t channelArrayCount = channelArray.getCount();
-            for (size_t k = 0; k < channelArrayCount; k++)
-            {
-                domChannelRef& channel = channelArray.get(k);
-                const char* target = channel->getTarget();
-
-                // TODO: Assumes only one target per channel?
-                if (startsWith(target, nodeIdSlash.c_str()))
-                {
-                    channels.push_back(channel);
-                }
-            }
-        }
-    }
-
-    // Recursively do the same for all nodes
-    daeTArray<daeSmartRef<daeElement>> children;
-    node->getChildren(children);
-    size_t childCount = children.getCount();
-    for (size_t i = 0; i < childCount; i++)
-    {
-        daeElementRef childElement = children[i];
-        if (childElement->getElementType() == COLLADA_TYPE::NODE)
-        {
-            domNodeRef childNode = daeSafeCast<domNode>(childElement);
-            getAnimationChannels(childNode, channels);
-        }
-    }
-}
-
 void DAEOptimizer::deleteEmptyAnimations()
 void DAEOptimizer::deleteEmptyAnimations()
 {
 {
     std::list<domAnimationRef> animations;
     std::list<domAnimationRef> animations;
@@ -102,12 +53,12 @@ void DAEOptimizer::deleteEmptyAnimations()
     // Get the list of empty animations
     // Get the list of empty animations
     domLibrary_animations_Array& animationLibrary = _dom->getLibrary_animations_array();
     domLibrary_animations_Array& animationLibrary = _dom->getLibrary_animations_array();
     size_t animationLibraryCount = animationLibrary.getCount();
     size_t animationLibraryCount = animationLibrary.getCount();
-    for (size_t i = 0; i < animationLibraryCount; i++)
+    for (size_t i = 0; i < animationLibraryCount; ++i)
     {
     {
         domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
         domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
         domAnimation_Array& animationArray = animationsRef->getAnimation_array();
         domAnimation_Array& animationArray = animationsRef->getAnimation_array();
         size_t animationCount = animationArray.getCount();
         size_t animationCount = animationArray.getCount();
-        for (size_t j = 0; j < animationCount; j++)
+        for (size_t j = 0; j < animationCount; ++j)
         {
         {
             domAnimationRef& animation = animationArray.get(j);
             domAnimationRef& animation = animationArray.get(j);
             if (isEmptyAnimation(animation))
             if (isEmptyAnimation(animation))
@@ -118,8 +69,10 @@ void DAEOptimizer::deleteEmptyAnimations()
     }
     }
 
 
     // Delete all of the empty animations
     // Delete all of the empty animations
-    for (std::list<domAnimationRef>::iterator i = animations.begin(); i != animations.end(); i++)
+    for (std::list<domAnimationRef>::iterator i = animations.begin(); i != animations.end(); ++i)
     {
     {
         daeElement::removeFromParent(*i);
         daeElement::removeFromParent(*i);
     }
     }
-}
+}
+
+}

+ 5 - 19
gameplay-encoder/src/DAEOptimizer.h

@@ -1,19 +1,11 @@
 #ifndef DAEOPTIMIZER_H_
 #ifndef DAEOPTIMIZER_H_
 #define DAEOPTIMIZER_H_
 #define DAEOPTIMIZER_H_
 
 
-#include <dae.h>
-#include <dae/daeSIDResolver.h>
-#include <dae/domAny.h>
-#include <dom/domCOLLADA.h>
-#include <dom/domConstants.h>
-#include <dom/domElements.h>
-#include <dom/domProfile_COMMON.h>
-
-#include <vector>
-
-#include "Base.h"
 #include "DAEUtil.h"
 #include "DAEUtil.h"
 
 
+namespace gameplay
+{
+
 /**
 /**
  * The DAEOptimizer optimizes a COLLADA dom.
  * The DAEOptimizer optimizes a COLLADA dom.
  */
  */
@@ -41,14 +33,6 @@ public:
 
 
 private:
 private:
 
 
-    /**
-     * Gets all of the animation channels that target the given node and appends them to the list.
-     * 
-     * @param node The node that the animation channels target.
-     * @param channels The list of channels to append to.
-     */
-    void getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels);
-
     /**
     /**
      * Deletes all of the empty animations in the dom.
      * Deletes all of the empty animations in the dom.
      */
      */
@@ -60,4 +44,6 @@ private:
     std::string _inputPath;
     std::string _inputPath;
 };
 };
 
 
+}
+
 #endif
 #endif

+ 240 - 251
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -1,15 +1,15 @@
 /*
 /*
  * DAESceneEncoder.h
  * DAESceneEncoder.h
  */
  */
-
-#include <algorithm>
+#include "Base.h"
 
 
 #include "DAESceneEncoder.h"
 #include "DAESceneEncoder.h"
 #include "DAEOptimizer.h"
 #include "DAEOptimizer.h"
 
 
 //#define ENCODER_PRINT_TIME 1
 //#define ENCODER_PRINT_TIME 1
 
 
-using namespace gameplay;
+namespace gameplay
+{
 
 
 DAESceneEncoder::DAESceneEncoder()
 DAESceneEncoder::DAESceneEncoder()
     : _collada(NULL), _dom(NULL), file(NULL), _vertexBlendWeights(NULL), _vertexBlendIndices(NULL)
     : _collada(NULL), _dom(NULL), file(NULL), _vertexBlendWeights(NULL), _vertexBlendIndices(NULL)
@@ -20,28 +20,10 @@ DAESceneEncoder::~DAESceneEncoder()
 {
 {
 }
 }
 
 
-std::string getFilenameFromFilePath(const std::string& filepath)
-{
-    if (filepath.find_last_of("/") != std::string::npos)
-    {
-        return filepath.substr(filepath.find_last_of("/")+1);
-    }
-    return "";
-}
-
-std::string getFilenameNoExt(const std::string& filename)
-{
-    if (filename.find_last_of(".") != std::string::npos)
-    {
-        return filename.substr(0, filename.find_last_of("."));
-    }
-    return filename;
-}
-
 unsigned int getMaxOffset(domInputLocalOffset_Array& inputArray)
 unsigned int getMaxOffset(domInputLocalOffset_Array& inputArray)
 {
 {
     unsigned int maxOffset = 0;
     unsigned int maxOffset = 0;
-    for (unsigned int i = 0; i < (int)inputArray.getCount(); i++ )
+    for (unsigned int i = 0; i < (int)inputArray.getCount(); ++i)
     {
     {
         if ( inputArray[i]->getOffset() > maxOffset )
         if ( inputArray[i]->getOffset() > maxOffset )
         {
         {
@@ -62,7 +44,7 @@ void DAESceneEncoder::optimizeCOLLADA(const EncoderArguments& arguments, domCOLL
     if (size > 0)
     if (size > 0)
     {
     {
         begin();
         begin();
-        for (size_t i = 0; i < size; i++)
+        for (size_t i = 0; i < size; ++i)
         {
         {
             optimizer.combineAnimations(groupAnimatioNodeIds[i], groupAnimatioIds[i]);
             optimizer.combineAnimations(groupAnimatioNodeIds[i], groupAnimatioIds[i]);
         }
         }
@@ -82,7 +64,7 @@ void DAESceneEncoder::triangulate(DAE* dae)
     daeDatabase* dataBase = dae->getDatabase();
     daeDatabase* dataBase = dae->getDatabase();
 
 
     int geometryCount = (int)(dataBase->getElementCount(0, "geometry"));
     int geometryCount = (int)(dataBase->getElementCount(0, "geometry"));
-    for (int i = 0; i < geometryCount; i++)
+    for (int i = 0; i < geometryCount; ++i)
     {
     {
         // Find the next geometry element.
         // Find the next geometry element.
         domGeometry* domGeometry;
         domGeometry* domGeometry;
@@ -97,14 +79,14 @@ void DAESceneEncoder::triangulate(DAE* dae)
 
 
         // Loop over all the polygons elements.
         // Loop over all the polygons elements.
         int polygonsCount = (int)(domMesh->getPolygons_array().getCount());
         int polygonsCount = (int)(domMesh->getPolygons_array().getCount());
-        for (int j = 0; j < polygonsCount; j++)
+        for (int j = 0; j < polygonsCount; ++j)
         {
         {
             // Get the polygons out of the mesh.
             // Get the polygons out of the mesh.
             domPolygons* domPolygons = domMesh->getPolygons_array()[j];
             domPolygons* domPolygons = domMesh->getPolygons_array()[j];
             // Create the triangles from the polygons
             // Create the triangles from the polygons
             createTrianglesFromPolygons(domMesh, domPolygons);
             createTrianglesFromPolygons(domMesh, domPolygons);
         }
         }
-        while(domMesh->getPolygons_array().getCount() > 0)
+        while (domMesh->getPolygons_array().getCount() > 0)
         {
         {
             domPolygons* domPolygons = domMesh->getPolygons_array().get(0);
             domPolygons* domPolygons = domMesh->getPolygons_array().get(0);
             // Remove the polygons from the mesh.
             // Remove the polygons from the mesh.
@@ -113,14 +95,14 @@ void DAESceneEncoder::triangulate(DAE* dae)
 
 
         // Loop over all the polylist elements.
         // Loop over all the polylist elements.
         int polylistCount = (int)(domMesh->getPolylist_array().getCount());
         int polylistCount = (int)(domMesh->getPolylist_array().getCount());
-        for (int j = 0; j < polylistCount; j++)
+        for (int j = 0; j < polylistCount; ++j)
         {
         {
             // Get the polylist out of the mesh.
             // Get the polylist out of the mesh.
             domPolylist* domPolylist = domMesh->getPolylist_array()[j];
             domPolylist* domPolylist = domMesh->getPolylist_array()[j];
             // Create the triangles from the polygon list
             // Create the triangles from the polygon list
             createTrianglesFromPolylist(domMesh, domPolylist);
             createTrianglesFromPolylist(domMesh, domPolylist);
         }
         }
-        while(domMesh->getPolylist_array().getCount() > 0)
+        while (domMesh->getPolylist_array().getCount() > 0)
         {
         {
             domPolylist* domPolylist = domMesh->getPolylist_array().get(0);
             domPolylist* domPolylist = domMesh->getPolylist_array().get(0);
             // Remove the polylist from the mesh.
             // Remove the polylist from the mesh.
@@ -138,7 +120,7 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     
     
     // Give the new <triangles> the same <_dae> and <parameters> as the old  <polygons>.
     // Give the new <triangles> the same <_dae> and <parameters> as the old  <polygons>.
-    for (unsigned int i = 0; i < domPolygons->getInput_array().getCount(); i++)
+    for (unsigned int i = 0; i < domPolygons->getInput_array().getCount(); ++i)
     {
     {
         triangles->placeElement(domPolygons->getInput_array()[i]->clone());
         triangles->placeElement(domPolygons->getInput_array()[i]->clone());
     }
     }
@@ -148,7 +130,7 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
     unsigned int primitiveCount = domPolygons->getP_array().getCount();
     unsigned int primitiveCount = domPolygons->getP_array().getCount();
     
     
     // Triangulate all the primitives, this generates all the triangles in a single <p> element.
     // Triangulate all the primitives, this generates all the triangles in a single <p> element.
-    for (unsigned int j = 0; j < primitiveCount; j++)
+    for (unsigned int j = 0; j < primitiveCount; ++j)
     {
     {
         // Check the polygons for consistancy (some exported files have had the wrong number of indices).
         // Check the polygons for consistancy (some exported files have had the wrong number of indices).
         domP* domCurrentP = domPolygons->getP_array()[j];
         domP* domCurrentP = domPolygons->getP_array()[j];
@@ -163,21 +145,21 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
             
             
             // Write out the primitives as triangles, just fan using the first element as the base.
             // Write out the primitives as triangles, just fan using the first element as the base.
             unsigned int index = inputCount;
             unsigned int index = inputCount;
-            for (unsigned int k = 0; k < triangleCount; k++)
+            for (unsigned int k = 0; k < triangleCount; ++k)
             {
             {
                 // First vertex.
                 // First vertex.
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[l]);
                     domTrianglesP->getValue().append(domCurrentP->getValue()[l]);
                 }
                 }
                 // Second vertex.
                 // Second vertex.
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
                     domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
                 }
                 }
                 // Third vertex.
                 // Third vertex.
                 index += inputCount;
                 index += inputCount;
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
                     domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
                 }
                 }
@@ -195,7 +177,7 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     
     
     // Give the new <triangles> the same <_dae> and <parameters> as the old <polylist>.
     // Give the new <triangles> the same <_dae> and <parameters> as the old <polylist>.
-    for (int i = 0; i < (int)(domPolylist->getInput_array().getCount()); i++)
+    for (int i = 0; i < (int)(domPolylist->getInput_array().getCount()); ++i)
     {
     {
         triangles->placeElement(domPolylist->getInput_array()[i]->clone());
         triangles->placeElement(domPolylist->getInput_array()[i]->clone());
     }
     }
@@ -208,27 +190,27 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     unsigned int trianglesProcessed = 0;
     unsigned int trianglesProcessed = 0;
     
     
     // Triangulate all the primitives, this generates all the triangles in a single <p> element.
     // Triangulate all the primitives, this generates all the triangles in a single <p> element.
-    for (unsigned int j = 0; j < primitiveCount; j++)
+    for (unsigned int j = 0; j < primitiveCount; ++j)
     {
     {
         unsigned int triangleCount = (unsigned int)domPolylist->getVcount()->getValue()[j] - 2;
         unsigned int triangleCount = (unsigned int)domPolylist->getVcount()->getValue()[j] - 2;
         
         
         // Write out the primitives as triangles, just fan using the first element as the base.
         // Write out the primitives as triangles, just fan using the first element as the base.
         int index = inputCount;
         int index = inputCount;
-        for (unsigned int k = 0; k < triangleCount; k++)
+        for (unsigned int k = 0; k < triangleCount; ++k)
         {
         {
             // First vertex.
             // First vertex.
-            for (unsigned int l = 0; l < inputCount; l++)
+            for (unsigned int l = 0; l < inputCount; ++l)
             {
             {
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + l]);
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + l]);
             }
             }
             // Second vertex.
             // Second vertex.
-            for (unsigned int l = 0; l < inputCount; l++)
+            for (unsigned int l = 0; l < inputCount; ++l)
             {
             {
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
             }
             }
             // Third vertex.
             // Third vertex.
             index += inputCount;
             index += inputCount;
-            for (unsigned int l = 0; l < inputCount; l++)
+            for (unsigned int l = 0; l < inputCount; ++l)
             {
             {
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
             }
             }
@@ -243,7 +225,7 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
 
 
 void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
 void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
 {
 {
-    _begin = std::clock();
+    _begin = clock();
     const char* nodeId = arguments.getNodeId();
     const char* nodeId = arguments.getNodeId();
     bool text = arguments.textOutputEnabled();
     bool text = arguments.textOutputEnabled();
 
 
@@ -363,12 +345,12 @@ void DAESceneEncoder::loadAnimations(const domCOLLADA* dom)
     // Call loadAnimation on all <animation> elements in all <library_animations>
     // Call loadAnimation on all <animation> elements in all <library_animations>
     const domLibrary_animations_Array& animationLibrarys = dom->getLibrary_animations_array();
     const domLibrary_animations_Array& animationLibrarys = dom->getLibrary_animations_array();
     size_t animationLibrarysCount = animationLibrarys.getCount();
     size_t animationLibrarysCount = animationLibrarys.getCount();
-    for (size_t i = 0; i < animationLibrarysCount; i++)
+    for (size_t i = 0; i < animationLibrarysCount; ++i)
     {
     {
         const domLibrary_animationsRef& libraryAnimation = animationLibrarys.get(i);
         const domLibrary_animationsRef& libraryAnimation = animationLibrarys.get(i);
         const domAnimation_Array& animationArray = libraryAnimation->getAnimation_array();
         const domAnimation_Array& animationArray = libraryAnimation->getAnimation_array();
         size_t animationCount = animationArray.getCount();
         size_t animationCount = animationArray.getCount();
-        for (size_t j = 0; j < animationCount; j++)
+        for (size_t j = 0; j < animationCount; ++j)
         {
         {
             const domAnimationRef& animationRef = animationArray.get(j);
             const domAnimationRef& animationRef = animationArray.get(j);
             loadAnimation(animationRef);
             loadAnimation(animationRef);
@@ -391,7 +373,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
     // <channel>
     // <channel>
     const domChannel_Array& channelArray = animationRef->getChannel_array();
     const domChannel_Array& channelArray = animationRef->getChannel_array();
     size_t channelArrayCount = channelArray.getCount();
     size_t channelArrayCount = channelArray.getCount();
-    for (size_t i = 0; i < channelArrayCount; i++)
+    for (size_t i = 0; i < channelArrayCount; ++i)
     {
     {
         AnimationChannel* animationChannel = new AnimationChannel();
         AnimationChannel* animationChannel = new AnimationChannel();
 
 
@@ -404,7 +386,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
         // <input>
         // <input>
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         size_t inputArrayCount = inputArray.getCount();
         size_t inputArrayCount = inputArray.getCount();
-        for (size_t j = 0; j < inputArrayCount; j++)
+        for (size_t j = 0; j < inputArrayCount; ++j)
         {
         {
             const domInputLocalRef& inputLocal = inputArray.get(j);
             const domInputLocalRef& inputLocal = inputArray.get(j);
 
 
@@ -425,7 +407,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
                 if (equals(semantic, "INPUT"))
                 if (equals(semantic, "INPUT"))
                 {
                 {
                     // TODO: Ensure param name is TIME?
                     // TODO: Ensure param name is TIME?
-                    for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); k++)
+                    for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); ++k)
                     {
                     {
                         // Convert seconds to milliseconds
                         // Convert seconds to milliseconds
                         *k = *k * 1000.0f;
                         *k = *k * 1000.0f;
@@ -473,7 +455,7 @@ void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChan
     values.resize(count);
     values.resize(count);
     if (count > 0)
     if (count > 0)
     {
     {
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; ++i)
         {
         {
             values[i] = AnimationChannel::getInterpolationType(names.get(i));
             values[i] = AnimationChannel::getInterpolationType(names.get(i));
         }
         }
@@ -482,7 +464,7 @@ void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChan
         // instead of storing the same type for each key frame.
         // instead of storing the same type for each key frame.
         unsigned int firstType = values[0];
         unsigned int firstType = values[0];
         bool allEqual = true;
         bool allEqual = true;
-        for (size_t i = 1; i < count; i++)
+        for (size_t i = 1; i < count; ++i)
         {
         {
             if (firstType != values[i])
             if (firstType != values[i])
             {
             {
@@ -512,7 +494,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
     const char* targetId = channelTarget.getTargetId().c_str();
     const char* targetId = channelTarget.getTargetId().c_str();
 
 
     // TODO: Do we want to support more than one? If yes then this needs to be fixed.
     // TODO: Do we want to support more than one? If yes then this needs to be fixed.
-    for (size_t i = 0; i < channelTarget.getTargetAttributeCount(); i++)
+    for (size_t i = 0; i < channelTarget.getTargetAttributeCount(); ++i)
     {
     {
         std::string prop;
         std::string prop;
         channelTarget.getPropertyName(i, &prop);
         channelTarget.getPropertyName(i, &prop);
@@ -548,7 +530,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                         // Convert (ANGLE ANGLE ANGLE) to (X Y Z ANGLE X Y Z ANGLE X Y Z ANGLE)
                         // Convert (ANGLE ANGLE ANGLE) to (X Y Z ANGLE X Y Z ANGLE X Y Z ANGLE)
                         std::vector<float> floats(size * 4);
                         std::vector<float> floats(size * 4);
                         // Duplicate rotation axis. We will replace only the angle that COLLADA is targeting.
                         // Duplicate rotation axis. We will replace only the angle that COLLADA is targeting.
-                        for (size_t j = 0; j < size; j++)
+                        for (size_t j = 0; j < size; ++j)
                         {
                         {
                             size_t k = j * 4;
                             size_t k = j * 4;
                             floats[k+0] = x;
                             floats[k+0] = x;
@@ -624,7 +606,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                 std::vector<float> floats(newSize);
                 std::vector<float> floats(newSize);
 
 
                 size_t matrixCount = keyValues.size() / 16;
                 size_t matrixCount = keyValues.size() / 16;
-                for (size_t i = 0; i < matrixCount; i++)
+                for (size_t i = 0; i < matrixCount; ++i)
                 {
                 {
                     size_t j = i * 16;
                     size_t j = i * 16;
                     // COLLADA used row-major but the Matrix class uses column-major
                     // COLLADA used row-major but the Matrix class uses column-major
@@ -656,20 +638,21 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
     }
     }
     animationChannel->setTargetAttribute(targetProperty);
     animationChannel->setTargetAttribute(targetProperty);
     animationChannel->setTargetId(channelTarget.getTargetId());
     animationChannel->setTargetId(channelTarget.getTargetId());
+    //animationChannel->removeDuplicates();
     return true;
     return true;
 }
 }
 
 
 void DAESceneEncoder::begin()
 void DAESceneEncoder::begin()
 {
 {
     #ifdef ENCODER_PRINT_TIME
     #ifdef ENCODER_PRINT_TIME
-    _begin = std::clock();
+    _begin = clock();
     #endif
     #endif
 }
 }
 
 
 void DAESceneEncoder::end(const char* str)
 void DAESceneEncoder::end(const char* str)
 {
 {
     #ifdef ENCODER_PRINT_TIME
     #ifdef ENCODER_PRINT_TIME
-    clock_t time = std::clock() - _begin;
+    clock_t time = clock() - _begin;
     fprintf(stderr,"%5d %s\n", time, str);
     fprintf(stderr,"%5d %s\n", time, str);
     #endif
     #endif
 }
 }
@@ -681,7 +664,7 @@ void DAESceneEncoder::copyFloats(const domFloat_array* source, std::vector<float
     size_t count = (size_t)source->getCount();
     size_t count = (size_t)source->getCount();
     t.resize(count);
     t.resize(count);
     const domListOfFloats& listOfFloats = source->getValue();
     const domListOfFloats& listOfFloats = source->getValue();
-    for (size_t i = 0; i < count; i++)
+    for (size_t i = 0; i < count; ++i)
     {
     {
         t[i] = (float)listOfFloats.get(i);
         t[i] = (float)listOfFloats.get(i);
     }
     }
@@ -694,7 +677,7 @@ void DAESceneEncoder::loadScene(const domVisual_scene* visualScene)
     const domNode_Array& nodes = visualScene->getNode_array();
     const domNode_Array& nodes = visualScene->getNode_array();
     scene->setId(visualScene->getId());
     scene->setId(visualScene->getId());
     size_t childCount = nodes.getCount();
     size_t childCount = nodes.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
     {
         scene->add(loadNode(nodes[i], NULL));
         scene->add(loadNode(nodes[i], NULL));
     }
     }
@@ -716,11 +699,11 @@ Node* DAESceneEncoder::findSceneActiveCameraNode(const domVisual_scene* visualSc
     // Find the active camera
     // Find the active camera
     const domVisual_scene::domEvaluate_scene_Array& evaluateScenes = visualScene->getEvaluate_scene_array();
     const domVisual_scene::domEvaluate_scene_Array& evaluateScenes = visualScene->getEvaluate_scene_array();
     size_t evaluateSceneCount = evaluateScenes.getCount();
     size_t evaluateSceneCount = evaluateScenes.getCount();
-    for (size_t i = 0; i < evaluateSceneCount; i++)
+    for (size_t i = 0; i < evaluateSceneCount; ++i)
     {
     {
         const domVisual_scene::domEvaluate_scene::domRender_Array& renders = evaluateScenes[i]->getRender_array();
         const domVisual_scene::domEvaluate_scene::domRender_Array& renders = evaluateScenes[i]->getRender_array();
         size_t renderCount = renders.getCount();
         size_t renderCount = renders.getCount();
-        for (size_t j = 0; j < renderCount; j++)
+        for (size_t j = 0; j < renderCount; ++j)
         {
         {
             xsAnyURI cameraNodeURI = renders[i]->getCamera_node();
             xsAnyURI cameraNodeURI = renders[i]->getCamera_node();
             domNode* nodeRef = daeSafeCast<domNode>(cameraNodeURI.getElement());
             domNode* nodeRef = daeSafeCast<domNode>(cameraNodeURI.getElement());
@@ -782,7 +765,7 @@ Node* DAESceneEncoder::loadNode(domNode* n, Node* parent)
     // Load child nodes
     // Load child nodes
     const domNode_Array& childNodes = n->getNode_array();
     const domNode_Array& childNodes = n->getNode_array();
     size_t childCount = childNodes.getCount();
     size_t childCount = childNodes.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
     {
         loadNode(childNodes.get(i), node);
         loadNode(childNodes.get(i), node);
     }
     }
@@ -830,10 +813,10 @@ void DAESceneEncoder::transformNode(domNode* domNode, Node* node)
 
 
 void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
 void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
 {
 {
-    daeTArray<daeSmartRef<daeElement>> children;
+    daeTArray<daeSmartRef<daeElement> > children;
     domNode->getChildren(children);
     domNode->getChildren(children);
     size_t childCount = children.getCount();
     size_t childCount = children.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
     {
         daeElementRef childElement = children[i];
         daeElementRef childElement = children[i];
         switch (childElement->getElementType())
         switch (childElement->getElementType())
@@ -898,7 +881,7 @@ void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
     // Does this node have any camera instances?
     // Does this node have any camera instances?
     const domInstance_camera_Array& instanceCameras = n->getInstance_camera_array();
     const domInstance_camera_Array& instanceCameras = n->getInstance_camera_array();
     size_t instanceCameraCount = instanceCameras.getCount();
     size_t instanceCameraCount = instanceCameras.getCount();
-    for (size_t i = 0; i < instanceCameraCount; i++)
+    for (size_t i = 0; i < instanceCameraCount; ++i)
     {
     {
         // Get the camrea object
         // Get the camrea object
         const domInstance_camera* cameraInstanceRef = instanceCameras.get(i);
         const domInstance_camera* cameraInstanceRef = instanceCameras.get(i);
@@ -907,10 +890,10 @@ void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
 
 
         if (cameraRef)
         if (cameraRef)
         {
         {
-            CameraInstance* cameraInstance = loadCamera(cameraRef);
-            if (cameraInstance)
+            Camera* camera = loadCamera(cameraRef);
+            if (camera)
             {
             {
-                node->setCameraInstance(cameraInstance);
+                node->setCamera(camera);
             }
             }
         }
         }
         else
         else
@@ -925,7 +908,7 @@ void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
     // Does this node have any light instances?
     // Does this node have any light instances?
     const domInstance_light_Array& instanceLights = n->getInstance_light_array();
     const domInstance_light_Array& instanceLights = n->getInstance_light_array();
     size_t instanceLightCount = instanceLights.getCount();
     size_t instanceLightCount = instanceLights.getCount();
-    for (size_t i = 0; i < instanceLightCount; i++)
+    for (size_t i = 0; i < instanceLightCount; ++i)
     {
     {
         // Get the camrea object
         // Get the camrea object
         const domInstance_light* lightInstanceRef = instanceLights.get(i);
         const domInstance_light* lightInstanceRef = instanceLights.get(i);
@@ -934,10 +917,10 @@ void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
 
 
         if (lightRef)
         if (lightRef)
         {
         {
-            LightInstance* lightInstance = loadLight(lightRef);
-            if (lightInstance)
+            Light* light = loadLight(lightRef);
+            if (light)
             {
             {
-                node->setLightInstance(lightInstance);
+                node->setLight(light);
             }
             }
         }
         }
         else
         else
@@ -952,7 +935,7 @@ void DAESceneEncoder::loadGeometryInstance(const domNode* n, Node* node)
     // Does this node have any geometry instances?
     // Does this node have any geometry instances?
     const domInstance_geometry_Array& instanceGeometries = n->getInstance_geometry_array();
     const domInstance_geometry_Array& instanceGeometries = n->getInstance_geometry_array();
     size_t instanceGeometryCount = instanceGeometries.getCount();
     size_t instanceGeometryCount = instanceGeometries.getCount();
-    for (size_t i = 0; i < instanceGeometryCount; i++)
+    for (size_t i = 0; i < instanceGeometryCount; ++i)
     {
     {
         // Get the geometry object
         // Get the geometry object
         const domInstance_geometryRef geometryInstanceRef = instanceGeometries.get(i);
         const domInstance_geometryRef geometryInstanceRef = instanceGeometries.get(i);
@@ -980,7 +963,7 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
     // Does this node have any controller instances?
     // Does this node have any controller instances?
     const domInstance_controller_Array& instanceControllers = n->getInstance_controller_array();
     const domInstance_controller_Array& instanceControllers = n->getInstance_controller_array();
     size_t instanceControllerCount = instanceControllers.getCount();
     size_t instanceControllerCount = instanceControllers.getCount();
-    for (size_t i = 0; i < instanceControllerCount; i++)
+    for (size_t i = 0; i < instanceControllerCount; ++i)
     {
     {
         const domInstance_controllerRef instanceControllerRef = instanceControllers.get(i);
         const domInstance_controllerRef instanceControllerRef = instanceControllers.get(i);
         xsAnyURI controllerURI = instanceControllerRef->getUrl();
         xsAnyURI controllerURI = instanceControllerRef->getUrl();
@@ -1019,202 +1002,181 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
     }
     }
 }
 }
 
 
-CameraInstance* DAESceneEncoder::loadCamera(const domCamera* cameraRef)
+Camera* DAESceneEncoder::loadCamera(const domCamera* cameraRef)
 {
 {
-    ///////////////////////////// CAMERA
+    Camera* camera = new Camera();
+    camera->setId(cameraRef->getId());
 
 
-    // check if camera is already added to gamePlayFile
-    const char* id = cameraRef->getId();
-    Camera* camera = _gamePlayFile.getCamera(id);
-    if (camera == NULL)
+    // Optics
+    const domCamera::domOpticsRef opticsRef = cameraRef->getOptics();
+    if (opticsRef.cast())
     {
     {
-        camera = new Camera();
-        camera->setId(id);
+        const domCamera::domOptics::domTechnique_commonRef techRef = opticsRef->getTechnique_common();
 
 
-        // Optics
-        const domCamera::domOpticsRef opticsRef = cameraRef->getOptics();
-        if (opticsRef.cast())
+        // Orthographics
+        const domCamera::domOptics::domTechnique_common::domOrthographicRef orthographicRef = techRef->getOrthographic();
+        if (orthographicRef.cast())
         {
         {
-            const domCamera::domOptics::domTechnique_commonRef techRef = opticsRef->getTechnique_common();
-
-            // Orthographics
-            const domCamera::domOptics::domTechnique_common::domOrthographicRef orthographicRef = techRef->getOrthographic();
-            if (orthographicRef.cast())
+            camera->setOrthographic();
+            camera->setAspectRatio((float)orthographicRef->getAspect_ratio()->getValue());
+            camera->setNearPlane((float)orthographicRef->getZnear()->getValue());
+            camera->setFarPlane((float)orthographicRef->getZfar()->getValue());
+
+            const domTargetableFloatRef xmag = orthographicRef->getXmag();
+            const domTargetableFloatRef ymag = orthographicRef->getYmag();
+            // Viewport width
+            if (xmag.cast())
             {
             {
-                camera->setOrthographic();
-                camera->setNearPlane((float)orthographicRef->getZnear()->getValue());
-                camera->setFarPlane((float)orthographicRef->getZfar()->getValue());
-
-                const domTargetableFloatRef xmag = orthographicRef->getXmag();
-                const domTargetableFloatRef ymag = orthographicRef->getYmag();
-                // Viewport width
-                if (xmag.cast())
-                {
-                    camera->setViewportWidth((float)xmag->getValue());
-                }
-                // Viewport height
-                if (ymag.cast())
-                {
-                    camera->setViewportHeight((float)ymag->getValue());
-                }
-                // TODO: Viewport x and y?
+                camera->setViewportWidth((float)xmag->getValue());
             }
             }
-
-            // Perspective
-            const domCamera::domOptics::domTechnique_common::domPerspectiveRef perspectiveRef = techRef->getPerspective();
-            if (perspectiveRef.cast())
+            // Viewport height
+            if (ymag.cast())
             {
             {
-                camera->setPerspective();
-                camera->setNearPlane((float)perspectiveRef->getZnear()->getValue());
-                camera->setFarPlane((float)perspectiveRef->getZfar()->getValue());
+                camera->setViewportHeight((float)ymag->getValue());
+            }
+            // TODO: Viewport x and y?
+        }
 
 
-                float aspectRatio = -1.0f;
-                if (perspectiveRef->getAspect_ratio().cast())
-                {
-                    aspectRatio = (float)perspectiveRef->getAspect_ratio()->getValue();
-                    camera->setAspectRatio(aspectRatio);
-                }
-                if (perspectiveRef->getYfov().cast())
-                {
-                    camera->setFieldOfView((float)perspectiveRef->getYfov()->getValue());
-                }
-                else if (perspectiveRef->getXfov().cast() && aspectRatio > 0.0f)
-                {
-                    // The gameplaybinary stores the yfov but collada might have specified
-                    // an xfov and an aspect ratio. So use those to calculate the yfov.
-                    float xfov = (float)perspectiveRef->getXfov()->getValue();
-                    float yfov = xfov / aspectRatio;
-                    camera->setFieldOfView(yfov);
-                }
+        // Perspective
+        const domCamera::domOptics::domTechnique_common::domPerspectiveRef perspectiveRef = techRef->getPerspective();
+        if (perspectiveRef.cast())
+        {
+            camera->setPerspective();
+            camera->setNearPlane((float)perspectiveRef->getZnear()->getValue());
+            camera->setFarPlane((float)perspectiveRef->getZfar()->getValue());
+
+            float aspectRatio = -1.0f;
+            if (perspectiveRef->getAspect_ratio().cast())
+            {
+                aspectRatio = (float)perspectiveRef->getAspect_ratio()->getValue();
+                camera->setAspectRatio(aspectRatio);
+            }
+            if (perspectiveRef->getYfov().cast())
+            {
+                camera->setFieldOfView((float)perspectiveRef->getYfov()->getValue());
+            }
+            else if (perspectiveRef->getXfov().cast() && aspectRatio > 0.0f)
+            {
+                // The gameplaybinary stores the yfov but collada might have specified
+                // an xfov and an aspect ratio. So use those to calculate the yfov.
+                float xfov = (float)perspectiveRef->getXfov()->getValue();
+                float yfov = xfov / aspectRatio;
+                camera->setFieldOfView(yfov);
             }
             }
         }
         }
-        _gamePlayFile.addCamera(camera);
     }
     }
-    CameraInstance* cameraInstance = new CameraInstance();
-    cameraInstance->setCamera(camera);
-    return cameraInstance;
+    _gamePlayFile.addCamera(camera);
+    return camera;
 }
 }
 
 
-LightInstance* DAESceneEncoder::loadLight(const domLight* lightRef)
+Light* DAESceneEncoder::loadLight(const domLight* lightRef)
 {
 {
-    ///////////////////////////// LIGHT
-
-    // check if light is already added to gamePlayFile
-    const char* id = lightRef->getId();
-    Light* light = _gamePlayFile.getLight(id);
-    if (light == NULL)
-    {
-        light = new Light();
-        light->setId(lightRef->getId());
+    Light* light = new Light();
+    light->setId(lightRef->getId());
 
 
-        const domLight::domTechnique_commonRef techRef = lightRef->getTechnique_common();
+    const domLight::domTechnique_commonRef techRef = lightRef->getTechnique_common();
 
 
-        // Ambient light
+    // Ambient light
+    {
+        const domLight::domTechnique_common::domAmbientRef ambientRef = techRef->getAmbient();
+        if (ambientRef.cast())
         {
         {
-            const domLight::domTechnique_common::domAmbientRef ambientRef = techRef->getAmbient();
-            if (ambientRef.cast())
-            {
-                light->setAmbientLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = ambientRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-            }
+            light->setAmbientLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = ambientRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
         }
         }
+    }
 
 
-        // Directional light
+    // Directional light
+    {
+        const domLight::domTechnique_common::domDirectionalRef direcitonalRef = techRef->getDirectional();
+        if (direcitonalRef.cast())
         {
         {
-            const domLight::domTechnique_common::domDirectionalRef direcitonalRef = techRef->getDirectional();
-            if (direcitonalRef.cast())
-            {
-                light->setDirectionalLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = direcitonalRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-            }
+            light->setDirectionalLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = direcitonalRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
         }
         }
+    }
 
 
-        // Spot light
+    // Spot light
+    {
+        const domLight::domTechnique_common::domSpotRef spotRef = techRef->getSpot();
+        if (spotRef.cast())
         {
         {
-            const domLight::domTechnique_common::domSpotRef spotRef = techRef->getSpot();
-            if (spotRef.cast())
-            {
-                light->setSpotLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = spotRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
+            light->setSpotLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = spotRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
                 
                 
-                const domTargetableFloatRef& constAtt = spotRef->getConstant_attenuation();
-                if (constAtt.cast())
-                {
-                    light->setConstantAttenuation((float)constAtt->getValue());
-                }
-
-                const domTargetableFloatRef& linearAtt = spotRef->getLinear_attenuation();
-                if (linearAtt.cast())
-                {
-                    light->setLinearAttenuation((float)linearAtt->getValue());
-                }
+            const domTargetableFloatRef& constAtt = spotRef->getConstant_attenuation();
+            if (constAtt.cast())
+            {
+                light->setConstantAttenuation((float)constAtt->getValue());
+            }
 
 
-                const domTargetableFloatRef& quadAtt = spotRef->getQuadratic_attenuation();
-                if (quadAtt.cast())
-                {
-                    light->setQuadraticAttenuation((float)quadAtt->getValue());
-                }
+            const domTargetableFloatRef& linearAtt = spotRef->getLinear_attenuation();
+            if (linearAtt.cast())
+            {
+                light->setLinearAttenuation((float)linearAtt->getValue());
+            }
 
 
-                const domTargetableFloatRef& falloffAngle = spotRef->getFalloff_angle();
-                if (falloffAngle.cast())
-                {
-                    light->setFalloffAngle((float)falloffAngle->getValue());
-                }
+            const domTargetableFloatRef& quadAtt = spotRef->getQuadratic_attenuation();
+            if (quadAtt.cast())
+            {
+                light->setQuadraticAttenuation((float)quadAtt->getValue());
+            }
 
 
-                const domTargetableFloatRef& falloffExp = spotRef->getFalloff_exponent();
-                if (falloffExp.cast())
-                {
-                    light->setFalloffExponent((float)falloffExp->getValue());
-                }
+            const domTargetableFloatRef& falloffAngle = spotRef->getFalloff_angle();
+            if (falloffAngle.cast())
+            {
+                light->setFalloffAngle((float)falloffAngle->getValue());
+            }
 
 
+            const domTargetableFloatRef& falloffExp = spotRef->getFalloff_exponent();
+            if (falloffExp.cast())
+            {
+                light->setFalloffExponent((float)falloffExp->getValue());
             }
             }
         }
         }
+    }
 
 
-        // Point light
+    // Point light
+    {
+        const domLight::domTechnique_common::domPointRef pointRef = techRef->getPoint();
+        if (pointRef.cast())
         {
         {
-            const domLight::domTechnique_common::domPointRef pointRef = techRef->getPoint();
-            if (pointRef.cast())
+            light->setPointLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = pointRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
+
+            const domTargetableFloatRef& constAtt = pointRef->getConstant_attenuation();
+            if (constAtt.cast())
             {
             {
-                light->setPointLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = pointRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-
-                const domTargetableFloatRef& constAtt = pointRef->getConstant_attenuation();
-                if (constAtt.cast())
-                {
-                    light->setConstantAttenuation((float)constAtt->getValue());
-                }
+                light->setConstantAttenuation((float)constAtt->getValue());
+            }
 
 
-                const domTargetableFloatRef& linearAtt = pointRef->getLinear_attenuation();
-                if (linearAtt.cast())
-                {
-                    light->setLinearAttenuation((float)linearAtt->getValue());
-                }
+            const domTargetableFloatRef& linearAtt = pointRef->getLinear_attenuation();
+            if (linearAtt.cast())
+            {
+                light->setLinearAttenuation((float)linearAtt->getValue());
+            }
 
 
-                const domTargetableFloatRef& quadAtt = pointRef->getQuadratic_attenuation();
-                if (quadAtt.cast())
-                {
-                    light->setQuadraticAttenuation((float)quadAtt->getValue());
-                }
+            const domTargetableFloatRef& quadAtt = pointRef->getQuadratic_attenuation();
+            if (quadAtt.cast())
+            {
+                light->setQuadraticAttenuation((float)quadAtt->getValue());
             }
             }
         }
         }
-
-        _gamePlayFile.addLight(light);
     }
     }
-    LightInstance* lightInstance = new LightInstance();
-    lightInstance->setLight(light);
-    return lightInstance;
+    _gamePlayFile.addLight(light);
+    return light;
 }
 }
 
 
 void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin)
 void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin)
@@ -1265,9 +1227,9 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
     }
     }
 
 
     // Resolve and set joints array for skin
     // Resolve and set joints array for skin
-    std::list<Node*> _joints;
-    const std::list<std::string>& jointNames = skin->getJointNames();
-    for (std::list<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
+    std::vector<Node*> _joints;
+    const std::vector<std::string>& jointNames = skin->getJointNames();
+    for (std::vector<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
     {
     {
         Object* obj = _gamePlayFile.getFromRefTable(*i);
         Object* obj = _gamePlayFile.getFromRefTable(*i);
         if (obj)
         if (obj)
@@ -1301,10 +1263,9 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     domSkin::domJointsRef _joints = skinElement->getJoints();
     domSkin::domJointsRef _joints = skinElement->getJoints();
     domInputLocal_Array& jointInputs = _joints->getInput_array();
     domInputLocal_Array& jointInputs = _joints->getInput_array();
 
 
-
     // Process "JOINT" input semantic first (we need to do this to set the joint count)
     // Process "JOINT" input semantic first (we need to do this to set the joint count)
     unsigned int jointCount = 0;
     unsigned int jointCount = 0;
-    for (unsigned int i = 0; i < jointInputs.getCount(); i++)
+    for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
     {
     {
         domInputLocalRef input = jointInputs.get(i);
         domInputLocalRef input = jointInputs.get(i);
         std::string inputSemantic = std::string(input->getSemantic());
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1315,12 +1276,12 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         if (equals(inputSemantic, "JOINT"))
         if (equals(inputSemantic, "JOINT"))
         {
         {
             // Get the joint Ids's
             // Get the joint Ids's
-            std::list<std::string> list;
+            std::vector<std::string> list;
             getJointNames(source, list);
             getJointNames(source, list);
 
 
             // Go through the joint list and conver them from sid to id because the sid information is
             // Go through the joint list and conver them from sid to id because the sid information is
             // lost when converting to the gameplay binary format.
             // lost when converting to the gameplay binary format.
-            for (std::list<std::string>::iterator i = list.begin(); i != list.end(); i++)
+            for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); i++)
             {
             {
                 daeSIDResolver resolver(source->getDocument()->getDomRoot(), i->c_str());
                 daeSIDResolver resolver(source->getDocument()->getDomRoot(), i->c_str());
                 daeElement* element = resolver.getElement();
                 daeElement* element = resolver.getElement();
@@ -1339,7 +1300,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
             jointCount = list.size();
             jointCount = list.size();
             _jointInverseBindPoseMatrices.reserve(jointCount);
             _jointInverseBindPoseMatrices.reserve(jointCount);
             unsigned int j = 0;
             unsigned int j = 0;
-            for (std::list<std::string>::const_iterator i = list.begin(); i != list.end(); i++)
+            for (std::vector<std::string>::const_iterator i = list.begin(); i != list.end(); i++)
             {
             {
                 _jointLookupTable[*i] = j++;
                 _jointLookupTable[*i] = j++;
             }
             }
@@ -1355,7 +1316,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     }
     }
 
 
     // Process "INV_BIND_MATRIX" next
     // Process "INV_BIND_MATRIX" next
-    for (unsigned int i = 0; i < jointInputs.getCount(); i++)
+    for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
     {
     {
         domInputLocalRef input = jointInputs.get(i);
         domInputLocalRef input = jointInputs.get(i);
         std::string inputSemantic = std::string(input->getSemantic());
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1369,7 +1330,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
             //unsigned int matrixFloatsCount = (unsigned int)source->getFloat_array()->getCount();
             //unsigned int matrixFloatsCount = (unsigned int)source->getFloat_array()->getCount();
             unsigned int jointIndex = 0;
             unsigned int jointIndex = 0;
 
 
-            for (unsigned int j = 0; j < jointCount; j++)
+            for (unsigned int j = 0; j < jointCount; ++j)
             {
             {
                 Matrix matrix((float)matrixFloats.get(jointIndex + 0), (float)matrixFloats.get(jointIndex + 4), (float)matrixFloats.get(jointIndex + 8), (float)matrixFloats.get(jointIndex + 12),
                 Matrix matrix((float)matrixFloats.get(jointIndex + 0), (float)matrixFloats.get(jointIndex + 4), (float)matrixFloats.get(jointIndex + 8), (float)matrixFloats.get(jointIndex + 12),
                               (float)matrixFloats.get(jointIndex + 1), (float)matrixFloats.get(jointIndex + 5), (float)matrixFloats.get(jointIndex + 9), (float)matrixFloats.get(jointIndex + 13),
                               (float)matrixFloats.get(jointIndex + 1), (float)matrixFloats.get(jointIndex + 5), (float)matrixFloats.get(jointIndex + 9), (float)matrixFloats.get(jointIndex + 13),
@@ -1390,7 +1351,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     unsigned int vertexWeightsCount = (unsigned int)vertexWeights->getCount();
     unsigned int vertexWeightsCount = (unsigned int)vertexWeights->getCount();
     domListOfFloats jointWeights;
     domListOfFloats jointWeights;
 
 
-    for (unsigned int i = 0; i < jointInputs.getCount(); i++)
+    for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
     {
     {
         domInputLocalOffsetRef input = vertexWeightsInputs.get(i);
         domInputLocalOffsetRef input = vertexWeightsInputs.get(i);
         std::string inputSemantic = std::string(input->getSemantic());
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1436,7 +1397,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     int weightOffset = 0;
     int weightOffset = 0;
 
 
     // Go through all the skin vertex influence weights from the indexed data.
     // Go through all the skin vertex influence weights from the indexed data.
-    for (int i = 0; i < skinVertexInfluenceCountTotal; i++)
+    for (int i = 0; i < skinVertexInfluenceCountTotal; ++i)
     {
     {
         // Get the influence count and directly get the vertext blend weights and indices.
         // Get the influence count and directly get the vertext blend weights and indices.
         unsigned int vertexInfluenceCount = (unsigned int)skinVertexInfluenceCounts.get(i);
         unsigned int vertexInfluenceCount = (unsigned int)skinVertexInfluenceCounts.get(i);
@@ -1445,7 +1406,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         //vertexInfluences.SetCapacity(vertexInfluenceCount);
         //vertexInfluences.SetCapacity(vertexInfluenceCount);
 
 
         // Get the index/weight pairs and some the weight totals while at it.
         // Get the index/weight pairs and some the weight totals while at it.
-        for (unsigned int j = 0; j < vertexInfluenceCount; j++)
+        for (unsigned int j = 0; j < vertexInfluenceCount; ++j)
         {
         {
             float weight = (float)jointWeights.get((unsigned int)skinVertexJointWeightPairIndices[vOffset + 1]);
             float weight = (float)jointWeights.get((unsigned int)skinVertexJointWeightPairIndices[vOffset + 1]);
             int index = (int)skinVertexJointWeightPairIndices[vOffset];
             int index = (int)skinVertexJointWeightPairIndices[vOffset];
@@ -1465,7 +1426,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         }
         }
 
 
         // Get up the the maximum vertex weight influence count.
         // Get up the the maximum vertex weight influence count.
-         for (unsigned int j = 0; j < maxVertexInfluencesCount; j++)
+         for (unsigned int j = 0; j < maxVertexInfluencesCount; ++j)
         {
         {
             if (j < vertexInfluenceCount)
             if (j < vertexInfluenceCount)
             {
             {
@@ -1573,7 +1534,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     unsigned int inputCount = (unsigned int)-1;
     unsigned int inputCount = (unsigned int)-1;
 
 
     // Loop through our set of triangle lists (each list of triangles corresponds to a single MeshPart)
     // Loop through our set of triangle lists (each list of triangles corresponds to a single MeshPart)
-    for (unsigned int i = 0; i < trianglesArrayCount; i++)
+    for (unsigned int i = 0; i < trianglesArrayCount; ++i)
     {
     {
         const domTrianglesRef& triangles = trianglesArray.get(i);
         const domTrianglesRef& triangles = trianglesArray.get(i);
         const domInputLocalOffset_Array& inputArray = triangles->getInput_array();
         const domInputLocalOffset_Array& inputArray = triangles->getInput_array();
@@ -1583,7 +1544,8 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
         {
         {
             inputCount = (unsigned int)inputArray.getCount();
             inputCount = (unsigned int)inputArray.getCount();
 
 
-            for (unsigned int j = 0; j < inputCount; j++)
+            int texCoordCount = 0;
+            for (unsigned int j = 0; j < inputCount; ++j)
             {
             {
                 const domInputLocalOffsetRef& input = inputArray.get(j);
                 const domInputLocalOffsetRef& input = inputArray.get(j);
                 std::string inputSemantic = input->getSemantic();
                 std::string inputSemantic = input->getSemantic();
@@ -1592,7 +1554,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 if (equals(inputSemantic, "VERTEX"))
                 if (equals(inputSemantic, "VERTEX"))
                 {
                 {
                     unsigned int vertexArrayCount = (unsigned int)vertexArray.getCount();
                     unsigned int vertexArrayCount = (unsigned int)vertexArray.getCount();
-                    for (unsigned int k = 0; k < vertexArrayCount; k++)
+                    for (unsigned int k = 0; k < vertexArrayCount; ++k)
                     {
                     {
                         const domInputLocalRef& vertexInput = vertexArray.get(k);
                         const domInputLocalRef& vertexInput = vertexArray.get(k);
                         
                         
@@ -1620,6 +1582,14 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                     if (type == -1)
                     if (type == -1)
                     {
                     {
                         warning(std::string("Semantic (") + semantic + ") is invalid/unsupported for geometry mesh: " + geometryId);
                         warning(std::string("Semantic (") + semantic + ") is invalid/unsupported for geometry mesh: " + geometryId);
+                        break;
+                    }
+                    if (type == TEXCOORD0)
+                    {
+                        // Some meshes have multiple texture coordinates
+                        assert(texCoordCount <= 7);
+                        type += texCoordCount;
+                        ++texCoordCount;
                     }
                     }
 
 
                     DAEPolygonInput* polygonInput = new DAEPolygonInput();
                     DAEPolygonInput* polygonInput = new DAEPolygonInput();
@@ -1647,12 +1617,12 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             // If there is a triangle array with a different number of inputs, this is not supported.
             // If there is a triangle array with a different number of inputs, this is not supported.
             if (inputCount != (unsigned int)inputArray.getCount())
             if (inputCount != (unsigned int)inputArray.getCount())
             {
             {
-                for (size_t j = 0; j < polygonInputs.size(); j++)
+                for (size_t j = 0; j < polygonInputs.size(); ++j)
                 {
                 {
                     delete polygonInputs[j];
                     delete polygonInputs[j];
                 }
                 }
                 warning(std::string("Triangles do not all have the same number of input sources for geometry mesh: ") + geometryId);
                 warning(std::string("Triangles do not all have the same number of input sources for geometry mesh: ") + geometryId);
-                return false;
+                return NULL;
             }
             }
             else
             else
             {
             {
@@ -1663,7 +1633,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     
     
     // Now we have validated that all input in all triangles are the same and in the same input layout.
     // Now we have validated that all input in all triangles are the same and in the same input layout.
     // Lets start to read them and build our subsets.
     // Lets start to read them and build our subsets.
-    for (unsigned int i = 0; i < trianglesArrayCount; i++)
+    for (unsigned int i = 0; i < trianglesArrayCount; ++i)
     {
     {
         // Subset to be built.
         // Subset to be built.
         MeshPart* subset = new MeshPart();
         MeshPart* subset = new MeshPart();
@@ -1672,7 +1642,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
         domTriangles* triangles = daeSafeCast<domTriangles>(trianglesArray.get(i));
         domTriangles* triangles = daeSafeCast<domTriangles>(trianglesArray.get(i));
 
 
         // Parse the material for this subset
         // Parse the material for this subset
-        //std::string materialName = triangles->getMaterial() == NULL ? _T("") : triangles->getMaterial();
+        //string materialName = triangles->getMaterial() == NULL ? _T("") : triangles->getMaterial();
         //if (materialName.size() > 0)
         //if (materialName.size() > 0)
         ///    subset->material = ParseMaterial(bindMaterial, materialName);
         ///    subset->material = ParseMaterial(bindMaterial, materialName);
 
 
@@ -1685,8 +1655,8 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
 
 
         // Go through the polygon indices for each input source retrieve the values
         // Go through the polygon indices for each input source retrieve the values
         // and iterate by its offset.
         // and iterate by its offset.
-        Vertex vertex;
 
 
+        Vertex vertex;
         for (unsigned int k = 0; k < inputSourceCount && poly < polyIntsCount;)
         for (unsigned int k = 0; k < inputSourceCount && poly < polyIntsCount;)
         {
         {
             const domListOfFloats& source = polygonInputs[k]->sourceValues;
             const domListOfFloats& source = polygonInputs[k]->sourceValues;
@@ -1701,7 +1671,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             switch (type)
             switch (type)
             {
             {
             case POSITION:
             case POSITION:
-                vertex.reset();
+                vertex = Vertex(); // TODO
                 if (_vertexBlendWeights && _vertexBlendIndices)
                 if (_vertexBlendWeights && _vertexBlendIndices)
                 {
                 {
                     vertex.hasWeights = true;
                     vertex.hasWeights = true;
@@ -1769,6 +1739,13 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                     vertex.texCoord.y = (float)source.get(polyIndex * 2 + 1);
                     vertex.texCoord.y = (float)source.get(polyIndex * 2 + 1);
                 }
                 }
                 break;
                 break;
+
+            case TEXCOORD1:
+                // TODO
+                break;
+
+            default:
+                break;
             }
             }
 
 
             // On the last input source attempt to add the vertex or index an existing one.
             // On the last input source attempt to add the vertex or index an existing one.
@@ -1891,6 +1868,16 @@ int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
             {
             {
                 type = TEXCOORD0;
                 type = TEXCOORD0;
             }
             }
+            else if (equals(semantic, "TEXTANGENT"))
+            {
+                // Treat TEXTANGENT as TANGENT
+                type = TANGENT;
+            }
+            else if (equals(semantic, "TEXBINORMAL"))
+            {
+                // Treat TEXBINORMAL as BINORMAL
+                type = BINORMAL;
+            }
         case 'B':
         case 'B':
             if (equals(semantic, "BINORMAL"))
             if (equals(semantic, "BINORMAL"))
             {
             {
@@ -1912,4 +1899,6 @@ DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :
 
 
 DAESceneEncoder::DAEPolygonInput::~DAEPolygonInput(void)
 DAESceneEncoder::DAEPolygonInput::~DAEPolygonInput(void)
 {
 {
-}
+}
+
+}

+ 6 - 24
gameplay-encoder/src/DAESceneEncoder.h

@@ -1,32 +1,11 @@
-/*
- * DAESceneEncoder.h
- */
-
 #ifndef DAESCENEEENCODER_H_
 #ifndef DAESCENEEENCODER_H_
 #define DAESCENEEENCODER_H_
 #define DAESCENEEENCODER_H_
 
 
-#include <iostream>
-#include <list>
-#include <vector>
-#include <ctime>
-
-#include <dae.h>
-#include <dae/daeSIDResolver.h>
-#include <dae/domAny.h>
-#include <dom/domCOLLADA.h>
-#include <dom/domConstants.h>
-#include <dom/domElements.h>
-#include <dom/domProfile_COMMON.h>
-#include <dom/domCamera.h>
-
-#include "Base.h"
 #include "StringUtil.h"
 #include "StringUtil.h"
 #include "Object.h"
 #include "Object.h"
 #include "Node.h"
 #include "Node.h"
 #include "Camera.h"
 #include "Camera.h"
-#include "CameraInstance.h"
 #include "Light.h"
 #include "Light.h"
-#include "LightInstance.h"
 #include "Mesh.h"
 #include "Mesh.h"
 #include "MeshPart.h"
 #include "MeshPart.h"
 #include "MeshSkin.h"
 #include "MeshSkin.h"
@@ -42,7 +21,8 @@
 #include "DAEUtil.h"
 #include "DAEUtil.h"
 #include "EncoderArguments.h"
 #include "EncoderArguments.h"
 
 
-using namespace gameplay;
+namespace gameplay
+{
 
 
 /**
 /**
  * Class for binary encoding a Collada (DAE) file.
  * Class for binary encoding a Collada (DAE) file.
@@ -134,8 +114,8 @@ private:
      */
      */
     void loadAnimation(const domAnimationRef animationRef);
     void loadAnimation(const domAnimationRef animationRef);
 
 
-    CameraInstance* loadCamera(const domCamera* cameraRef);
-    LightInstance* loadLight(const domLight* lightRef);
+    Camera* loadCamera(const domCamera* cameraRef);
+    Light* loadLight(const domLight* lightRef);
     Model* loadSkin(const domSkin* skinElement);
     Model* loadSkin(const domSkin* skinElement);
     Model* loadGeometry(const domGeometry* geometry, const domBind_materialRef bindMaterial);
     Model* loadGeometry(const domGeometry* geometry, const domBind_materialRef bindMaterial);
 
 
@@ -223,4 +203,6 @@ private:
     clock_t _begin;
     clock_t _begin;
 };
 };
 
 
+}
+
 #endif
 #endif

+ 69 - 14
gameplay-encoder/src/DAEUtil.cpp

@@ -1,5 +1,9 @@
-
+#include "Base.h"
 #include "DAEUtil.h"
 #include "DAEUtil.h"
+#include "StringUtil.h"
+
+namespace gameplay
+{
 
 
 /**
 /**
  * Returns the index of the skeleton in skeletonArray that points to the given node.
  * Returns the index of the skeleton in skeletonArray that points to the given node.
@@ -11,7 +15,56 @@
  */
  */
 int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node);
 int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node);
 
 
-void getJointNames(const domSourceRef source, std::list<std::string>& list)
+void getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels)
+{
+    assert(node->getId());
+    std::string nodeIdSlash (node->getId());
+    nodeIdSlash.append("/");
+
+    domCOLLADA* root = (domCOLLADA*)node->getDocument()->getDomRoot();
+
+    domLibrary_animations_Array& animationLibrary = root->getLibrary_animations_array();
+    size_t animationLibraryCount = animationLibrary.getCount();
+    for (size_t i = 0; i < animationLibraryCount; ++i)
+    {
+        domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
+        domAnimation_Array& animationArray = animationsRef->getAnimation_array();
+        size_t animationCount = animationArray.getCount();
+        for (size_t j = 0; j < animationCount; ++j)
+        {
+            domAnimationRef& animationRef = animationArray.get(j);
+            domChannel_Array& channelArray = animationRef->getChannel_array();
+            size_t channelArrayCount = channelArray.getCount();
+            for (size_t k = 0; k < channelArrayCount; ++k)
+            {
+                domChannelRef& channel = channelArray.get(k);
+                const char* target = channel->getTarget();
+
+                // TODO: Assumes only one target per channel?
+                if (startsWith(target, nodeIdSlash.c_str()))
+                {
+                    channels.push_back(channel);
+                }
+            }
+        }
+    }
+
+    // Recursively do the same for all nodes
+    daeTArray< daeSmartRef<daeElement> > children;
+    node->getChildren(children);
+    size_t childCount = children.getCount();
+    for (size_t i = 0; i < childCount; ++i)
+    {
+        daeElementRef childElement = children[i];
+        if (childElement->getElementType() == COLLADA_TYPE::NODE)
+        {
+            domNodeRef childNode = daeSafeCast<domNode>(childElement);
+            getAnimationChannels(childNode, channels);
+        }
+    }
+}
+
+void getJointNames(const domSourceRef source, std::vector<std::string>& list)
 {
 {
     // BLENDER used name_array
     // BLENDER used name_array
     const domName_arrayRef& nameArray = source->getName_array();
     const domName_arrayRef& nameArray = source->getName_array();
@@ -19,7 +72,7 @@ void getJointNames(const domSourceRef source, std::list<std::string>& list)
     {
     {
         domListOfNames& ids = nameArray->getValue();
         domListOfNames& ids = nameArray->getValue();
         size_t jointCount = (size_t)nameArray->getCount();
         size_t jointCount = (size_t)nameArray->getCount();
-        for (size_t j = 0; j < jointCount; j++)
+        for (size_t j = 0; j < jointCount; ++j)
         {
         {
             list.push_back(std::string(ids.get(j)));
             list.push_back(std::string(ids.get(j)));
         }
         }
@@ -32,7 +85,7 @@ void getJointNames(const domSourceRef source, std::list<std::string>& list)
         {
         {
             xsIDREFS& ids = idArray->getValue();
             xsIDREFS& ids = idArray->getValue();
             size_t jointCount = (size_t)idArray->getCount();
             size_t jointCount = (size_t)idArray->getCount();
-            for (size_t j = 0; j < jointCount; j++)
+            for (size_t j = 0; j < jointCount; ++j)
             {
             {
                 list.push_back(std::string(ids.get(j).getID()));
                 list.push_back(std::string(ids.get(j).getID()));
             }
             }
@@ -40,12 +93,12 @@ void getJointNames(const domSourceRef source, std::list<std::string>& list)
     }
     }
 }
 }
 
 
-void getJointNames(const domSkin* skin, std::list<std::string>& list)
+void getJointNames(const domSkin* skin, std::vector<std::string>& list)
 {
 {
     const domSkin::domJointsRef& joints = skin->getJoints();
     const domSkin::domJointsRef& joints = skin->getJoints();
     const domInputLocal_Array& inputArray = joints->getInput_array();
     const domInputLocal_Array& inputArray = joints->getInput_array();
     size_t inputCount = inputArray.getCount();
     size_t inputCount = inputArray.getCount();
-    for (size_t i = 0; i < inputCount; i++)
+    for (size_t i = 0; i < inputCount; ++i)
     {
     {
         const domInputLocalRef input = inputArray.get(i);
         const domInputLocalRef input = inputArray.get(i);
         const char* semantic = input->getSemantic();
         const char* semantic = input->getSemantic();
@@ -69,7 +122,7 @@ domSource* getInputSource(const domChannelRef& channel)
         domSampler* sampler = daeSafeCast<domSampler>(element);
         domSampler* sampler = daeSafeCast<domSampler>(element);
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         size_t inputArrayCount = inputArray.getCount();
         size_t inputArrayCount = inputArray.getCount();
-        for (size_t i = 0; i < inputArrayCount; i++)
+        for (size_t i = 0; i < inputArrayCount; ++i)
         {
         {
             const domInputLocalRef& input = inputArray.get(i);
             const domInputLocalRef& input = inputArray.get(i);
             if (strcmp(input->getSemantic(), "INPUT") == 0)
             if (strcmp(input->getSemantic(), "INPUT") == 0)
@@ -105,7 +158,7 @@ const domSamplerRef getSampler(const domChannelRef& channel)
         
         
         const domSampler_Array& samplerArray = animation->getSampler_array();
         const domSampler_Array& samplerArray = animation->getSampler_array();
         size_t count = samplerArray.getCount();
         size_t count = samplerArray.getCount();
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; ++i)
         {
         {
             const domSamplerRef& sampler = samplerArray.get(i);
             const domSamplerRef& sampler = samplerArray.get(i);
             if (id.compare(sampler->getId()) == 0)
             if (id.compare(sampler->getId()) == 0)
@@ -130,7 +183,7 @@ const domSourceRef getSource(const domInputLocalRef& inputLocal, const domAnimat
     const std::string& id = uri.id();
     const std::string& id = uri.id();
     const domSource_Array& sourceArray = animation->getSource_array();
     const domSource_Array& sourceArray = animation->getSource_array();
     size_t count = sourceArray.getCount();
     size_t count = sourceArray.getCount();
-    for (size_t i = 0; i < count; i++)
+    for (size_t i = 0; i < count; ++i)
     {
     {
         const domSourceRef source = sourceArray.get(i);
         const domSourceRef source = sourceArray.get(i);
         if (id.compare(source->getId()) == 0)
         if (id.compare(source->getId()) == 0)
@@ -148,10 +201,10 @@ const domName_arrayRef getSourceNameArray(const domSourceRef& source)
     {
     {
         return nameArray;
         return nameArray;
     }
     }
-    daeTArray<daeSmartRef<daeElement>> children;
+    daeTArray<daeSmartRef<daeElement> > children;
     source->getChildren(children);
     source->getChildren(children);
     size_t childCount = children.getCount();
     size_t childCount = children.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
     {
         const daeElementRef element = children.get(i);
         const daeElementRef element = children.get(i);
         if (element->getElementType() == COLLADA_TYPE::NAME_ARRAY)
         if (element->getElementType() == COLLADA_TYPE::NAME_ARRAY)
@@ -220,7 +273,7 @@ bool equalKeyTimes(const domSource* s1, const domSource* s2)
         const domListOfFloats& list2 = f2->getValue();
         const domListOfFloats& list2 = f2->getValue();
 
 
         size_t count = (size_t)f1->getCount();
         size_t count = (size_t)f1->getCount();
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; ++i)
         {
         {
             if (list1.get(i) != list2.get(i))
             if (list1.get(i) != list2.get(i))
             {
             {
@@ -256,7 +309,7 @@ void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& an
 
 
         domInputLocal_Array& inputArray = sampler->getInput_array();
         domInputLocal_Array& inputArray = sampler->getInput_array();
         size_t inputArrayCount = inputArray.getCount();
         size_t inputArrayCount = inputArray.getCount();
-        for (size_t i = 0; i < inputArrayCount; i++)
+        for (size_t i = 0; i < inputArrayCount; ++i)
         {
         {
             inputArray = sampler->getInput_array();
             inputArray = sampler->getInput_array();
             const domInputLocalRef& input = inputArray.get(i);
             const domInputLocalRef& input = inputArray.get(i);
@@ -286,7 +339,7 @@ int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, con
 {
 {
     const std::string nodeId = node->getId();
     const std::string nodeId = node->getId();
     size_t count = skeletonArray.getCount();
     size_t count = skeletonArray.getCount();
-    for (size_t i = 0; i < count; i++)
+    for (size_t i = 0; i < count; ++i)
     {
     {
         const domInstance_controller::domSkeletonRef& skeleton = skeletonArray.get(i);
         const domInstance_controller::domSkeletonRef& skeleton = skeletonArray.get(i);
         daeElementRef element = skeleton->getValue().getElement();
         daeElementRef element = skeleton->getValue().getElement();
@@ -301,3 +354,5 @@ int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, con
     }
     }
     return -1;
     return -1;
 }
 }
+
+}

+ 14 - 21
gameplay-encoder/src/DAEUtil.h

@@ -1,25 +1,16 @@
-/*
- * DAEUtil.h
- */
-
 #ifndef DAEUTIL_H_
 #ifndef DAEUTIL_H_
 #define DAEUTIL_H_
 #define DAEUTIL_H_
 
 
-#include <iostream>
-#include <list>
-#include <vector>
-
-#include <dae.h>
-#include <dae/daeSIDResolver.h>
-#include <dae/domAny.h>
-#include <dom/domCOLLADA.h>
-#include <dom/domConstants.h>
-#include <dom/domElements.h>
-#include <dom/domProfile_COMMON.h>
-
-#include "Base.h"
+namespace gameplay
+{
 
 
-using namespace gameplay;
+/**
+ * Gets all of the animation channels that target the given node and appends them to the list.
+ * 
+ * @param node The node that the animation channels target.
+ * @param channels The list of channels to append to.
+ */
+void getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels);
 
 
 /**
 /**
  * Gets the joint names for the given source and appends them to the given list.
  * Gets the joint names for the given source and appends them to the given list.
@@ -27,7 +18,7 @@ using namespace gameplay;
  * @param source The source element to search in.
  * @param source The source element to search in.
  * @param list The list to append the joint names to.
  * @param list The list to append the joint names to.
  */
  */
-void getJointNames(const domSourceRef source, std::list<std::string>& list);
+void getJointNames(const domSourceRef source, std::vector<std::string>& list);
 
 
 /**
 /**
  * Gets the joint names for the given skin and appends them to the given list.
  * Gets the joint names for the given skin and appends them to the given list.
@@ -35,7 +26,7 @@ void getJointNames(const domSourceRef source, std::list<std::string>& list);
  * @param skin The skin element to search in.
  * @param skin The skin element to search in.
  * @param list The list to append the joint names to.
  * @param list The list to append the joint names to.
  */
  */
-void getJointNames(const domSkin* skin, std::list<std::string>& list);
+void getJointNames(const domSkin* skin, std::vector<std::string>& list);
 
 
 /**
 /**
  * Gets the input source from the given channel.
  * Gets the input source from the given channel.
@@ -56,7 +47,7 @@ domSource* getInputSource(const domChannelRef& channel);
 const domSamplerRef getSampler(const domChannelRef& channel);
 const domSamplerRef getSampler(const domChannelRef& channel);
 
 
 /**
 /**
- * Returns the source from the given sampler input. 
+ * Returns the source from the given sampler input.
  * Searchs within the given animation.
  * Searchs within the given animation.
  * 
  * 
  * @param inputLocal The input element within a sampler.
  * @param inputLocal The input element within a sampler.
@@ -123,4 +114,6 @@ void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& an
  */
  */
 bool isEmptyAnimation(domAnimationRef& animation);
 bool isEmptyAnimation(domAnimationRef& animation);
 
 
+}
+
 #endif
 #endif

+ 4 - 1
gameplay-encoder/src/Effect.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Effect.h"
 #include "Effect.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -15,6 +16,7 @@ unsigned int Effect::getTypeId(void) const
 {
 {
     return EFFECT_ID;
     return EFFECT_ID;
 }
 }
+
 const char* Effect::getElementName(void) const
 const char* Effect::getElementName(void) const
 {
 {
     return "Effect";
     return "Effect";
@@ -26,6 +28,7 @@ void Effect::writeBinary(FILE* file)
     write(_vertexShader, file);
     write(_vertexShader, file);
     write(_fragmentShader, file);
     write(_fragmentShader, file);
 }
 }
+
 void Effect::writeText(FILE* file)
 void Effect::writeText(FILE* file)
 {
 {
     fprintElementStart(file);
     fprintElementStart(file);
@@ -34,4 +37,4 @@ void Effect::writeText(FILE* file)
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
-}
+}

+ 1 - 2
gameplay-encoder/src/Effect.h

@@ -33,7 +33,6 @@ private:
     std::string _fragmentShader;
     std::string _fragmentShader;
 };
 };
 
 
-
 }
 }
-#endif
 
 
+#endif

+ 103 - 13
gameplay-encoder/src/EncoderArguments.cpp

@@ -1,5 +1,6 @@
-#include "EncoderArguments.h"
+#include "Base.h"
 
 
+#include "EncoderArguments.h"
 #include "StringUtil.h"
 #include "StringUtil.h"
 
 
 #ifdef WIN32
 #ifdef WIN32
@@ -7,6 +8,11 @@
     #define realpath(A,B)    _fullpath(B,A,PATH_MAX)
     #define realpath(A,B)    _fullpath(B,A,PATH_MAX)
 #endif
 #endif
 
 
+namespace gameplay
+{
+
+static EncoderArguments* __instance;
+
 EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
 EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
     _fontSize(0),
     _fontSize(0),
     _parseError(false),
     _parseError(false),
@@ -14,6 +20,8 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
     _textOutput(false),
     _textOutput(false),
     _daeOutput(false)
     _daeOutput(false)
 {
 {
+    __instance = this;
+
     if (argc > 1)
     if (argc > 1)
     {
     {
         size_t filePathIndex = argc - 1;
         size_t filePathIndex = argc - 1;
@@ -24,12 +32,12 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
         
         
         // read the options
         // read the options
         std::vector<std::string> options;
         std::vector<std::string> options;
-        for (size_t i = 1; i < filePathIndex; i++)
+        for (size_t i = 1; i < filePathIndex; ++i)
         {
         {
             options.push_back(argv[i]);
             options.push_back(argv[i]);
         }
         }
         
         
-        for (size_t i = 0; i < options.size(); i++)
+        for (size_t i = 0; i < options.size(); ++i)
         {
         {
             if (options[i][0] == '-')
             if (options[i][0] == '-')
             {
             {
@@ -47,6 +55,11 @@ EncoderArguments::~EncoderArguments(void)
 {
 {
 }
 }
 
 
+EncoderArguments* EncoderArguments::getInstance()
+{
+    return __instance;
+}
+
 const std::string& EncoderArguments::getFilePath() const
 const std::string& EncoderArguments::getFilePath() const
 {
 {
     return _filePath;
     return _filePath;
@@ -57,6 +70,12 @@ const char* EncoderArguments::getFilePathPointer() const
     return _filePath.c_str();
     return _filePath.c_str();
 }
 }
 
 
+std::string EncoderArguments::getOutputPath() const
+{
+    int pos = _filePath.find_last_of('/');
+    return (pos == -1 ? _filePath : _filePath.substr(0, pos));
+}
+
 const std::string& EncoderArguments::getDAEOutputPath() const
 const std::string& EncoderArguments::getDAEOutputPath() const
 {
 {
     return _daeOutputPath;
     return _daeOutputPath;
@@ -72,6 +91,29 @@ const std::vector<std::string>& EncoderArguments::getGroupAnimationAnimationId()
     return _groupAnimationAnimationId;
     return _groupAnimationAnimationId;
 }
 }
 
 
+bool EncoderArguments::containsGroupNodeId(const std::string& nodeId) const
+{
+    return find(_groupAnimationNodeId.begin(), _groupAnimationNodeId.end(), nodeId) != _groupAnimationNodeId.end();
+}
+
+const std::string EncoderArguments::getAnimationId(const std::string& nodeId) const
+{
+    std::vector<std::string>::const_iterator it = find(_groupAnimationNodeId.begin(), _groupAnimationNodeId.end(), nodeId);
+    for (size_t i = 0, size = _groupAnimationNodeId.size(); i < size; ++i)
+    {
+        if (_groupAnimationNodeId[i].compare(nodeId) == 0)
+        {
+            return _groupAnimationAnimationId[i];
+        }
+    }
+    return "";
+}
+
+const std::vector<std::string>& EncoderArguments::getHeightmapNodeIds() const
+{
+    return _heightmapNodeIds;
+}
+
 bool EncoderArguments::parseErrorOccured() const
 bool EncoderArguments::parseErrorOccured() const
 {
 {
     return _parseError;
     return _parseError;
@@ -92,14 +134,28 @@ bool EncoderArguments::fileExists() const
 
 
 void EncoderArguments::printUsage() const
 void EncoderArguments::printUsage() const
 {
 {
-    fprintf(stderr,"Usage: gameplay-encoder [options] <filepath>\n");
-    fprintf(stderr,".dae file options:\n");
-    fprintf(stderr," -i <id>\tFilter by node ID\n");
-    fprintf(stderr," -t\tWrite text/xml\n");
-    fprintf(stderr," -groupAnimations <nodeID> <animationID>\tGroup all animation channels targetting the nodes into a new animation\n");
-    fprintf(stderr," -dae <filepath>\tOutput optimized DAE\n");
-    fprintf(stderr,".ttf file options:\n");
-    fprintf(stderr," -s <size of font> -p \n");
+    fprintf(stderr,"Usage: gameplay-encoder [options] <filepath>\n\n");
+    fprintf(stderr,"Supported file extensions:\n");
+    fprintf(stderr,"  .dae\t(COLLADA)\n");
+    fprintf(stderr,"  .fbx\t(FBX)\n");
+    fprintf(stderr,"  .ttf\t(TrueType Font)\n");
+    fprintf(stderr,"\n");
+    fprintf(stderr,"COLLADA and FBX file options:\n");
+    fprintf(stderr,"  -i<id>\t\tFilter by node ID.\n");
+    fprintf(stderr,"  -t\t\t\tWrite text/xml.\n");
+    fprintf(stderr,"  -groupAnimations <node id> <animation id>\n" \
+        "\t\t\tGroup all animation channels targetting the nodes into a new animation.\n");
+    fprintf(stderr,"  -heightmaps \"<node ids>\"\n" \
+        "\t\t\tList of nodes to generate heightmaps for.\n" \
+        "\t\t\tNode id list should be in quotes with a space between each id.\n" \
+        "\t\t\tHeightmaps will be saved in files named <nodeid>.png.\n");
+    fprintf(stderr,"\n");
+    fprintf(stderr,"COLLADA file options:\n");
+    fprintf(stderr,"  -dae <filepath>\tOutput optimized DAE.\n");
+    fprintf(stderr,"\n");
+    fprintf(stderr,"TTF file options:\n");
+    fprintf(stderr,"  -s <size of font>\tSize of the font.\n");
+    fprintf(stderr,"  -p\t\t\tOutput font preview.\n");
     exit(8);
     exit(8);
 }
 }
 
 
@@ -151,6 +207,10 @@ EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
     {
     {
         return FILEFORMAT_DAE;
         return FILEFORMAT_DAE;
     }
     }
+    if (ext.compare("fbx") == 0 || ext.compare("FBX") == 0)
+    {
+        return FILEFORMAT_FBX;
+    }
     if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
     if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
     {
     {
         return FILEFORMAT_TTF;
         return FILEFORMAT_TTF;
@@ -163,7 +223,7 @@ EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
     return FILEFORMAT_UNKNOWN;
     return FILEFORMAT_UNKNOWN;
 }
 }
 
 
-void EncoderArguments::readOption(const std::vector<std::string>& options, size_t *index)
+void EncoderArguments::readOption(const std::vector<std::string>& options, size_t* index)
 {
 {
     const std::string& str = options[*index];
     const std::string& str = options[*index];
     if (str.length() == 0 && str[0] != '-')
     if (str.length() == 0 && str[0] != '-')
@@ -217,6 +277,34 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
             _parseError = true;
             _parseError = true;
             return;
             return;
         }
         }
+        break;
+    case 'h':
+        {
+            if (str.compare("-heightmaps") == 0)
+            {
+                (*index)++;
+                if (*index < options.size())
+                {
+                    // Split node id list into tokens
+                    unsigned int length = options[*index].size() + 1;
+                    char* nodeIds = new char[length];
+                    strcpy(nodeIds, options[*index].c_str());
+                    nodeIds[length-1] = 0;
+                    char* id = strtok(nodeIds, " ");
+                    while (id)
+                    {
+                        _heightmapNodeIds.push_back(id);
+                        id = strtok(NULL, " ");
+                    }
+                    delete[] nodeIds;
+                }
+                else
+                {
+                    fprintf(stderr, "Error: missing argument for -heightmaps.\n");
+                }
+            }
+        }
+        break;
     case 'p':
     case 'p':
         _fontPreview = true;
         _fontPreview = true;
         break;
         break;
@@ -265,7 +353,7 @@ std::string EncoderArguments::getRealPath(const std::string& filepath)
 
 
 void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
 void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
 {
 {
-    for (; *str != '\0'; str++)
+    for (; *str != '\0'; ++str)
     {
     {
         if (*str == oldChar)
         if (*str == oldChar)
         {
         {
@@ -273,3 +361,5 @@ void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
         }
         }
     }
     }
 }
 }
+
+}

+ 24 - 10
gameplay-encoder/src/EncoderArguments.h

@@ -1,14 +1,8 @@
 #ifndef ENCODERARGUMENTS_H_
 #ifndef ENCODERARGUMENTS_H_
 #define ENCODERARGUMENTS_H_
 #define ENCODERARGUMENTS_H_
 
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <iostream>
-#include <string>
-#include <sys/stat.h>
-#include <vector>
-
-#include "Base.h"
+namespace gameplay
+{
 
 
 /**
 /**
  * EncoderArguments handles parsing the command line arguments for the GamePlay Encoder.
  * EncoderArguments handles parsing the command line arguments for the GamePlay Encoder.
@@ -21,6 +15,7 @@ public:
     {
     {
         FILEFORMAT_UNKNOWN,
         FILEFORMAT_UNKNOWN,
         FILEFORMAT_DAE,
         FILEFORMAT_DAE,
+        FILEFORMAT_FBX,
         FILEFORMAT_TTF,
         FILEFORMAT_TTF,
         FILEFORMAT_GPB
         FILEFORMAT_GPB
     };
     };
@@ -35,6 +30,11 @@ public:
      */
      */
     ~EncoderArguments(void);
     ~EncoderArguments(void);
 
 
+    /**
+     * Gets the EncoderArguments instance.
+     */
+    static EncoderArguments* getInstance();
+
     /**
     /**
      * Gets the file format from the file path based on the extension.
      * Gets the file format from the file path based on the extension.
      */
      */
@@ -48,16 +48,26 @@ public:
     /**
     /**
      * Returns the char pointer to the file path string.
      * Returns the char pointer to the file path string.
      */
      */
-    const char* EncoderArguments::getFilePathPointer() const;
+    const char* getFilePathPointer() const;
 
 
     /**
     /**
      * Returns the path to where the DAE output should be written to.
      * Returns the path to where the DAE output should be written to.
      */
      */
-    const std::string& EncoderArguments::getDAEOutputPath() const;
+    const std::string& getDAEOutputPath() const;
+
+    /**
+     * Returns the output path/folder.
+     */
+    std::string getOutputPath() const;
 
 
     const std::vector<std::string>& getGroupAnimationNodeId() const;
     const std::vector<std::string>& getGroupAnimationNodeId() const;
     const std::vector<std::string>& getGroupAnimationAnimationId() const;
     const std::vector<std::string>& getGroupAnimationAnimationId() const;
 
 
+    bool containsGroupNodeId(const std::string& nodeId) const;
+    const std::string getAnimationId(const std::string& nodeId) const;
+
+    const std::vector<std::string>& getHeightmapNodeIds() const;
+
     /**
     /**
      * Returns true if an error occured while parsing the command line arguments.
      * Returns true if an error occured while parsing the command line arguments.
      */
      */
@@ -115,6 +125,10 @@ private:
 
 
     std::vector<std::string> _groupAnimationNodeId;
     std::vector<std::string> _groupAnimationNodeId;
     std::vector<std::string> _groupAnimationAnimationId;
     std::vector<std::string> _groupAnimationAnimationId;
+    std::vector<std::string> _heightmapNodeIds;
+
 };
 };
 
 
+}
+
 #endif
 #endif

+ 1336 - 0
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -0,0 +1,1336 @@
+#ifdef USE_FBX
+
+#include <algorithm>
+#include <string>
+
+#include "FBXSceneEncoder.h"
+#include "EncoderArguments.h"
+
+using namespace gameplay;
+
+/**
+ * Returns the aspect ratio from the given camera.
+ * 
+ * @param fbxCamera The FBX camera to get the aspect ratio from.
+ * 
+ * @return The aspect ratio from the camera.
+ */
+float getAspectRatio(KFbxCamera* fbxCamera);
+
+/**
+ * Returns the field of view Y from the given camera.
+ * 
+ * @param fbxCamera The camera to get the fiew of view from.
+ * 
+ * @return The field of view Y.
+ */
+float getFieldOfView(KFbxCamera* fbxCamera);
+
+/**
+ * Loads the texture coordinates from given mesh's polygon part into the vertex.
+ * 
+ * @param fbxMesh The mesh to get the polygon from.
+ * @param polyIndex The index of the polygon.
+ * @param posInPoly The position in the polygon.
+ * @param vertex The vertex to copy the texture coordinates to.
+ */
+void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex);
+
+/**
+ * Loads the normal from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to get the polygon from.
+ * @param vertexIndex The vertex index in the mesh.
+ * @param vertex The vertex to copy to.
+ */
+void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the tangent from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param vertexIndex The index of the vertex within fbxMesh.
+ * @param vertex The vertex to copy to.
+ */
+void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the binormal from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param vertexIndex The index of the vertex within fbxMesh.
+ * @param vertex The vertex to copy to.
+ */
+void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the blend weight and blend indices data into the vertex.
+ * 
+ * @param vertexWeights List of vertex weights. The x member contains the blendIndices. The y member contains the blendWeights.
+ * @param vertex The vertex to copy the blend data to.
+ */
+void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
+
+/**
+ * Loads the blend weights and blend indices from the given mesh.
+ * 
+ * Each element of weights is a list of Vector2s where "x" is the blend index and "y" is the blend weight.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param weights List of blend weights and blend indices for each vertex.
+ * 
+ * @return True if this mesh has a mesh skin, false otherwise.
+ */
+bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
+
+/**
+ * Copies from an FBX matrix to a float[16] array.
+ */
+void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix);
+
+/**
+ * Copies from an FBX matrix to a gameplay matrix.
+ */
+void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
+
+/**
+ * Finds the min and max start time and stop time of the given animation curve.
+ * 
+ * startTime is updated if the animation curve contains a start time that is less than startTime.
+ * stopTime is updated if the animation curve contains a stop time that is greater than stopTime.
+ * frameRate is updated if the animation curve contains a frame rate that is greater than frameRate.
+ * 
+ * @param animCurve The animation curve to read from.
+ * @param startTime The min start time. (in/out)
+ * @param stopTime The max stop time. (in/out)
+ * @param frameRate The frame rate. (in/out)
+ */
+void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
+
+/**
+ * Appends a key frame of the given node's transform at the given time.
+ * 
+ * @param fbxNode The node to get the matrix transform from.
+ * @param time The key time to add and the time to get the transform from.
+ * @param keyTimes The list of key times to append to.
+ * @param keyValues The list of key values to append to.
+ */
+void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes, std::vector<float>* keyValues);
+
+/**
+ * Decomposes the given node's matrix transform at the given time and copies to scale, rotation and translation.
+ * 
+ * @param fbxNode The node to get the matrix transform from.
+ * @param time The time to get the matrix transform from.
+ * @param scale The scale to copy to.
+ * @param rotation The rotation to copy to.
+ * @param translation The translation to copy to.
+ */
+void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation);
+
+/**
+ * Creates an animation channel that targets the given node and target attribute using the given key times and key values.
+ * 
+ * @param fbxNode The node to target.
+ * @param targetAttrib The attribute type to target.
+ * @param keyTimes The key times for the animation channel.
+ * @param keyValues The key values for the animation channel.
+ * 
+ * @return The newly created animation channel.
+ */
+AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
+
+void addScaleChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime);
+
+void addTranslateChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime);
+
+
+////////////////////////////////////
+// Member Functions
+////////////////////////////////////
+
+FBXSceneEncoder::FBXSceneEncoder()
+    : _groupAnimation(NULL)
+{
+}
+
+FBXSceneEncoder::~FBXSceneEncoder()
+{
+}
+
+void FBXSceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
+{
+    KFbxSdkManager* sdkManager = KFbxSdkManager::Create();
+    KFbxIOSettings *ios = KFbxIOSettings::Create(sdkManager, IOSROOT);
+    sdkManager->SetIOSettings(ios);
+    KFbxImporter* importer = KFbxImporter::Create(sdkManager,"");
+    
+    if (!importer->Initialize(filepath.c_str(), -1, sdkManager->GetIOSettings()))
+    {
+        printf("Call to KFbxImporter::Initialize() failed.\n");
+        printf("Error returned: %s\n\n", importer->GetLastErrorString());
+        exit(-1);
+    }
+    
+    KFbxScene* fbxScene = KFbxScene::Create(sdkManager,"__FBX_SCENE__");
+
+    print("Loading FBX file.");
+    importer->Import(fbxScene);
+    importer->Destroy();
+    print("Loading Scene.");
+    loadScene(fbxScene);
+    print("Loading animations.");
+    loadAnimations(fbxScene, arguments);
+    sdkManager->Destroy();
+
+    print("Optimizing GamePlay Binary.");
+    _gamePlayFile.adjust();
+    
+    std::string filenameOnly = getFilenameFromFilePath(filepath);
+    std::string dstFilename = filepath.substr(0, filepath.find_last_of('/'));
+    dstFilename.append(1, '/');
+    dstFilename.append(getFilenameNoExt(filenameOnly));
+    
+    if (arguments.textOutputEnabled())
+    {
+        std::string outFile = dstFilename + ".xml";
+        fprintf(stderr, "Saving debug file: %s\n", outFile.c_str());
+        _gamePlayFile.saveText(outFile);
+    }
+    else
+    {
+        std::string outFile = dstFilename + ".gpb";
+        fprintf(stderr, "Saving binary file: %s\n", outFile.c_str());
+        _gamePlayFile.saveBinary(outFile);
+    }
+}
+
+void FBXSceneEncoder::loadScene(KFbxScene* fbxScene)
+{
+    Scene* scene = new Scene();
+    scene->setId(fbxScene->GetName());
+    if (scene->getId().length() == 0)
+    {
+        scene->setId("__SCENE__");
+    }
+
+    // Load all of the nodes and their contents.
+    KFbxNode* rootNode = fbxScene->GetRootNode();
+    if (rootNode)
+    {
+        print("Triangulate.");
+        triangulateRecursive(rootNode);
+
+        print("Load nodes.");
+        // Don't include the FBX root node in the GPB.
+        const int childCount = rootNode->GetChildCount();
+        for (int i = 0; i < childCount; ++i)
+        {
+            Node* node = loadNode(rootNode->GetChild(i));
+            if (node)
+            {
+                scene->add(node);
+            }
+        }
+    }
+
+    // Load the MeshSkin information from the scene's poses.
+    loadBindShapes(fbxScene);
+
+    // Find the ambient light of the scene
+    KFbxColor ambientColor = fbxScene->GetGlobalSettings().GetAmbientColor();
+    scene->setAmbientColor((float)ambientColor.mRed, (float)ambientColor.mGreen, (float)ambientColor.mBlue);
+
+    _gamePlayFile.addScene(scene);
+}
+
+void FBXSceneEncoder::loadAnimationChannels(KFbxAnimLayer* animLayer, KFbxNode* fbxNode, Animation* animation)
+{
+    const std::string* targetId = NULL;
+
+    const char* name = fbxNode->GetName();
+    Node* node = _gamePlayFile.getNode(name);
+    if (node)
+    {
+        targetId = &node->getId();
+    }
+    
+    // Determine which properties are animated on this node
+    // Find the transform at each key frame
+    // TODO: Ignore properties that are not animated (scale, rotation, translation)
+    // This should result in only one animation channel per animated node.
+
+    float startTime = FLT_MAX, stopTime = -1.0f, frameRate = FLT_MIN;
+    bool tx = false, ty = false, tz = false, rx = false, ry = false, rz = false, sx = false, sy = false, sz = false;
+    KFbxAnimCurve* animCurve = NULL;
+    animCurve = fbxNode->LclTranslation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_T_X);
+    if (animCurve)
+    {
+        tx = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclTranslation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_T_Y);
+    if (animCurve)
+    {
+        ty = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclTranslation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_T_Z);
+    if (animCurve)
+    {
+        tz = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclRotation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_R_X);
+    if (animCurve)
+    {
+        rx = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclRotation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_R_Y);
+    if (animCurve)
+    {
+        ry = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclRotation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_R_Z);
+    if (animCurve)
+    {
+        rz = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclScaling.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_S_X);
+    if (animCurve)
+    {
+        sx = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclScaling.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_S_Y);
+    if (animCurve)
+    {
+        sy = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclScaling.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_S_Z);
+    if (animCurve)
+    {
+        sz = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+
+    bool translate = tx | ty | tz;
+    bool scale = sx | sy | sz;
+    bool rotate = rx | ry | rz;
+
+    if (translate || rotate || scale)
+    {
+        assert(startTime != FLT_MAX);
+        assert(stopTime >= 0.0f);
+        AnimationChannel* channel = new AnimationChannel();
+        channel->setTargetId(name);
+        channel->setTargetAttribute(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE);
+        
+        float increment = 1000.0f / frameRate;
+        std::vector<float> keyTimes;
+        std::vector<float> keyValues;
+        for (float time = startTime; time < stopTime; time += increment)
+        {
+            appendKeyFrame(fbxNode, time, &keyTimes, &keyValues);
+        }
+        // Add the last key frame at exactly stopTime
+        appendKeyFrame(fbxNode, stopTime, &keyTimes, &keyValues);
+
+        channel->setKeyTimes(keyTimes);
+        /*
+        std::vector<float> newKeyValues;
+        for (size_t i = 0, size = keyValues.size(); i < size; i += 10)
+        {
+            if (translate)
+            {
+                newKeyValues.push_back(keyValues[i+0]);
+                newKeyValues.push_back(keyValues[i+1]);
+                newKeyValues.push_back(keyValues[i+2]);
+            }
+            if (rotate)
+            {
+                newKeyValues.push_back(keyValues[i+3]);
+                newKeyValues.push_back(keyValues[i+4]);
+                newKeyValues.push_back(keyValues[i+5]);
+                newKeyValues.push_back(keyValues[i+6]);
+            }
+            if (scale)
+            {
+                newKeyValues.push_back(keyValues[i+7]);
+                newKeyValues.push_back(keyValues[i+8]);
+                newKeyValues.push_back(keyValues[i+9]);
+            }
+        }
+        channel->setKeyValues(newKeyValues);
+        */
+        channel->setKeyValues(keyValues);
+        channel->setInterpolation(AnimationChannel::LINEAR);
+        animation->add(channel);
+        /*
+        if (!translate)
+        {
+            addTranslateChannel(animation, fbxNode, startTime, stopTime);
+        }
+        if (!rotate)
+        {
+            printf("rotate?\n"); // TODO
+        }
+        if (!scale)
+        {
+            addScaleChannel(animation, fbxNode, startTime, stopTime);
+        }
+        */
+        if (_groupAnimation != animation)
+        {
+            // TODO explains
+            _gamePlayFile.addAnimation(animation);
+        }
+    }
+}
+
+void FBXSceneEncoder::loadAnimationLayer(KFbxAnimLayer* fbxAnimLayer, KFbxNode* fbxNode, const EncoderArguments& arguments)
+{
+    bool animationGroupId = false;
+    const char* name = fbxNode->GetName();
+    // Check if this node's animations are supposed to be grouped
+    if (name)
+    {
+        std::string str = name;
+        if (arguments.containsGroupNodeId(str))
+        {
+            animationGroupId = true;
+            _groupAnimation = new Animation();
+            _groupAnimation->setId(arguments.getAnimationId(str));
+        }
+    }
+    Animation* animation = _groupAnimation;
+    if (!_groupAnimation)
+    {
+        animation = new Animation();
+        animation->setId(name);
+    }
+    loadAnimationChannels(fbxAnimLayer, fbxNode, animation);
+
+    const int childCount = fbxNode->GetChildCount();
+    for (int modelCount = 0; modelCount < childCount; ++modelCount)
+    {
+        loadAnimationLayer(fbxAnimLayer, fbxNode->GetChild(modelCount), arguments);
+    }
+    if (animationGroupId)
+    {
+        _gamePlayFile.addAnimation(_groupAnimation);
+        _groupAnimation = NULL;
+    }
+}
+
+void FBXSceneEncoder::loadAnimations(KFbxScene* fbxScene, const EncoderArguments& arguments)
+{
+    KFbxAnimEvaluator* evaluator = fbxScene->GetEvaluator();
+    if (!evaluator)
+        return;
+    KFbxAnimStack* animStack = evaluator->GetContext();
+    if (!animStack)
+        return;
+
+    for (int i = 0; i < fbxScene->GetSrcObjectCount(FBX_TYPE(KFbxAnimStack)); ++i)
+    {
+        KFbxAnimStack* animStack = KFbxCast<KFbxAnimStack>(fbxScene->GetSrcObject(FBX_TYPE(KFbxAnimStack), i));
+        int nbAnimLayers = animStack->GetMemberCount(FBX_TYPE(KFbxAnimLayer));
+        for (int l = 0; l < nbAnimLayers; ++l)
+        {
+            KFbxAnimLayer* animLayer = animStack->GetMember(FBX_TYPE(KFbxAnimLayer), l);
+            loadAnimationLayer(animLayer, fbxScene->GetRootNode(), arguments);
+        }
+    }
+}
+
+Node* FBXSceneEncoder::loadNode(KFbxNode* fbxNode)
+{
+    Node* node = NULL;
+
+    // Check if this node has already been loaded
+    const char* id = fbxNode->GetName();
+    if (id && strlen(id) > 0)
+    {
+        node = _gamePlayFile.getNode(fbxNode->GetName());
+        if (node)
+        {
+            return node;
+        }
+    }
+    node = new Node();
+    if (id)
+    {
+        node->setId(id);
+    }
+    _gamePlayFile.addNode(node);
+
+    transformNode(fbxNode, node);
+    
+    loadCamera(fbxNode, node);
+    loadLight(fbxNode, node);
+    loadModel(fbxNode, node);
+
+    if (fbxNode->GetSkeleton())
+    {
+        // Indicate that this is a joint node for the purpose of debugging.
+        // The XML debug output will print that this node is a joint.
+        node->setIsJoint(true);
+    }
+
+    // Load child nodes
+    const int childCount = fbxNode->GetChildCount();
+    for (int i = 0; i < childCount; ++i)
+    {
+        Node* child = loadNode(fbxNode->GetChild(i));
+        if (child)
+        {
+            node->addChild(child);
+        }
+    }
+    return node;
+}
+
+Mesh* FBXSceneEncoder::getMesh(size_t meshId)
+{
+    // Check if this mesh was already loaded.
+    std::map<size_t, Mesh*>::iterator it = _meshes.find(meshId);
+    if (it != _meshes.end())
+    {
+        return it->second;
+    }
+    return NULL;
+}
+
+void FBXSceneEncoder::saveMesh(size_t meshId, Mesh* mesh)
+{
+    assert(mesh);
+    if (!getMesh(meshId))
+    {
+        _meshes[meshId] = mesh;
+    }
+}
+
+void FBXSceneEncoder::print(const char* str)
+{
+    fprintf(stderr,"%s\n", str);
+}
+
+void FBXSceneEncoder::transformNode(KFbxNode* fbxNode, Node* node)
+{
+    KFbxXMatrix matrix;
+    if (fbxNode->GetCamera() || fbxNode->GetLight())
+    {
+        // TODO: Why is this necessary for Camera and Light?
+        matrix.SetTRS(fbxNode->LclTranslation.Get(), fbxNode->LclRotation.Get(), fbxNode->LclScaling.Get());
+    }
+    else
+    {
+        matrix = fbxNode->EvaluateLocalTransform();
+    }
+
+    float m[16];
+    copyMatrix(matrix, m);
+    int i = 0;
+    for (int row = 0; row < 4; ++row)
+    {
+        for (int col = 0; col < 4; ++col)
+        {
+            m[i++] = (float)matrix.Get(row, col);
+        }
+    }
+    node->setTransformMatrix(m);
+}
+
+void FBXSceneEncoder::loadBindShapes(KFbxScene* fbxScene)
+{
+    float m[16];
+    const int poseCount = fbxScene->GetPoseCount();
+    for (int i = 0; i < poseCount; ++i)
+    {
+        KFbxPose* pose = fbxScene->GetPose(i);
+        assert(pose);
+        if (pose->IsBindPose() && pose->GetCount() > 0)
+        {
+            KFbxNode* fbxNode = pose->GetNode(0);
+            if (fbxNode->GetMesh() != NULL)
+            {
+                Node* node = _gamePlayFile.getNode(fbxNode->GetName());
+                assert(node && node->getModel());
+
+                Model* model = node->getModel();
+                if (model && model->getSkin())
+                {
+                    MeshSkin* skin = model->getSkin();
+                    copyMatrix(pose->GetMatrix(0), m);
+                    skin->setBindShape(m);
+                }
+            }
+        }
+    }
+}
+
+void FBXSceneEncoder::loadCamera(KFbxNode* fbxNode, Node* node)
+{
+    KFbxCamera* fbxCamera = fbxNode->GetCamera();
+    if (!fbxCamera)
+    {
+        return;
+    }
+    Camera* camera = new Camera();
+    const char* name = fbxNode->GetName();
+    if (name)
+    {
+        std::string id(name);
+        id.append("_Camera");
+        camera->setId(id);
+    }
+    camera->setAspectRatio(getAspectRatio(fbxCamera));
+    camera->setNearPlane((float)fbxCamera->NearPlane.Get());
+    camera->setFarPlane((float)fbxCamera->FarPlane.Get());
+
+    if (fbxCamera->ProjectionType.Get() == KFbxCamera::eORTHOGONAL)
+    {
+        camera->setOrthographic();
+        camera->setViewportWidth((float)fbxCamera->GetApertureWidth());
+        camera->setViewportWidth((float)fbxCamera->GetApertureHeight());
+        // xmag in FBX can be calculated from: OrthoZoom * 30.0 / 2.0
+        camera->setViewportWidth((float)fbxCamera->OrthoZoom.Get() * 15.0f);
+    }
+    else if (fbxCamera->ProjectionType.Get() == KFbxCamera::ePERSPECTIVE)
+    {
+        camera->setPerspective();
+        camera->setFieldOfView(getFieldOfView(fbxCamera));
+    }
+    else
+    {
+        warning("Unknown camera type in node");
+        return;
+    }
+    _gamePlayFile.addCamera(camera);
+    node->setCamera(camera);
+}
+
+void FBXSceneEncoder::loadLight(KFbxNode* fbxNode, Node* node)
+{
+    KFbxLight* fbxLight = fbxNode->GetLight();
+    if (!fbxLight)
+    {
+        return;
+    }
+    Light* light = new Light();
+    const char* name = fbxNode->GetName();
+    if (name)
+    {
+        std::string id(name);
+        id.append("_Light");
+        light->setId(id);
+    }
+
+    fbxDouble3 color = fbxLight->Color.Get();
+    light->setColor((float)color[0], (float)color[1], (float)color[2]);
+    
+    switch (fbxLight->LightType.Get())
+    {
+    case KFbxLight::ePOINT:
+        light->setPointLight();
+        // TODO: range
+        break;
+    case KFbxLight::eDIRECTIONAL:
+        light->setDirectionalLight();
+        break;
+    case KFbxLight::eSPOT:
+        light->setSpotLight();
+        // TODO: range and angles
+        break;
+    default:
+        warning("Unknown light type in node.");
+        return;
+    }
+
+    _gamePlayFile.addLight(light);
+    node->setLight(light);
+}
+
+void FBXSceneEncoder::loadModel(KFbxNode* fbxNode, Node* node)
+{
+    KFbxMesh* fbxMesh = fbxNode->GetMesh();
+    if (!fbxMesh)
+    {
+        return;
+    }
+    if (fbxMesh->IsTriangleMesh())
+    {
+        Mesh* mesh = loadMesh(fbxMesh);
+        Model* model = new Model();
+        model->setMesh(mesh);
+        node->setModel(model);
+        loadSkin(fbxMesh, model);
+        if (model->getSkin())
+        {
+            // TODO: explain
+            node->resetTransformMatrix();
+        }
+    }
+}
+
+void FBXSceneEncoder::loadSkin(KFbxMesh* fbxMesh, Model* model)
+{
+    const int deformerCount = fbxMesh->GetDeformerCount();
+    for (int i = 0; i < deformerCount; ++i)
+    {
+        KFbxDeformer* deformer = fbxMesh->GetDeformer(i);
+        if (deformer->GetDeformerType() == KFbxDeformer::eSKIN)
+        {
+            KFbxSkin* fbxSkin = static_cast<KFbxSkin*>(deformer);
+
+            MeshSkin* skin = new MeshSkin();
+
+            std::vector<std::string> jointNames;
+            std::vector<Node*> joints;
+            std::vector<Matrix> bindPoses;
+
+            const int clusterCount = fbxSkin->GetClusterCount();
+            for (int j = 0; j < clusterCount; ++j)
+            {
+                KFbxCluster* cluster = fbxSkin->GetCluster(j);
+                assert(cluster);
+                KFbxNode* linkedNode = cluster->GetLink();
+                assert(linkedNode);
+                if (linkedNode->GetSkeleton())
+                {
+                    const char* jointName = linkedNode->GetName();
+                    assert(jointName);
+                    jointNames.push_back(jointName);
+                    Node* joint = loadNode(linkedNode);
+                    assert(joint);
+                    joints.push_back(joint);
+
+                    KFbxXMatrix matrix;
+                    cluster->GetTransformLinkMatrix(matrix);
+                    Matrix m;
+                    copyMatrix(matrix.Inverse(), m);
+                    bindPoses.push_back(m);
+                }
+            }
+            skin->setJointNames(jointNames);
+            skin->setJoints(joints);
+            skin->setBindPoses(bindPoses);
+            model->setSkin(skin);
+            break;
+        }
+    }
+}
+
+Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
+{
+    // Check if this mesh has already been loaded.
+    Mesh* mesh = getMesh(fbxMesh->GetUniqueID());
+    if (mesh)
+    {
+        return mesh;
+    }
+    mesh = new Mesh();
+    // GamePlay requires that a mesh have a unique ID but KFbxMesh doesn't have a string ID.
+    const char* name = fbxMesh->GetNode()->GetName();
+    if (name)
+    {
+        std::string id(name);
+        id.append("_Mesh");
+        mesh->setId(id);
+    }
+
+    // The number of mesh parts is equal to the number of materials that affect this mesh.
+    // There is always at least one mesh part.
+    std::vector<MeshPart*> meshParts;
+    const int materialCount = fbxMesh->GetNode()->GetMaterialCount();
+    int meshPartSize = (materialCount > 0) ? materialCount : 1;
+    for (int i = 0; i < meshPartSize; ++i)
+    {
+        meshParts.push_back(new MeshPart());
+    }
+
+    // Find the blend weights and blend indices if this mesh is skinned.
+    std::vector<std::vector<Vector2> > weights;
+    bool hasSkin = loadBlendWeights(fbxMesh, weights);
+    
+    int vertexIndex = 0;
+    KFbxVector4* controlPoints = fbxMesh->GetControlPoints();
+    const int polygonCount = fbxMesh->GetPolygonCount();
+    for (int polyIndex = 0; polyIndex < polygonCount; ++polyIndex)
+    {
+        const int polygonSize = fbxMesh->GetPolygonSize(polyIndex);
+        for (int posInPoly = 0; posInPoly < polygonSize; ++posInPoly)
+        {
+            int controlPointIndex = fbxMesh->GetPolygonVertex(polyIndex, posInPoly);
+            Vertex vertex;
+
+            KFbxVector4& position = controlPoints[controlPointIndex];
+            vertex.position.x = (float)position[0];
+            vertex.position.y = (float)position[1];
+            vertex.position.z = (float)position[2];
+
+            loadTextureCoords(fbxMesh, polyIndex, posInPoly, &vertex);
+            loadNormal(fbxMesh, vertexIndex, &vertex);
+            loadTangent(fbxMesh, vertexIndex, &vertex);
+            loadBinormal(fbxMesh, vertexIndex, &vertex);
+            // TODO: loadDiffuseColors
+
+            if (hasSkin)
+            {
+                loadBlendData(weights[controlPointIndex], &vertex);
+            }
+
+            // Determine which mesh part this vertex index should be added to based on the material that affects it.
+            int meshPartIndex = 0;
+            const int elementMatrialCount = fbxMesh->GetElementMaterialCount();
+            for (int k = 0; k < elementMatrialCount; ++k)
+            {
+                KFbxGeometryElementMaterial* elementMaterial = fbxMesh->GetElementMaterial(k);
+                meshPartIndex = elementMaterial->GetIndexArray().GetAt(polyIndex);
+            }
+
+            // Add the vertex to the mesh if it hasn't already been added and find the vertex index.
+            unsigned int index;
+            if (mesh->contains(vertex))
+            {
+                index = mesh->getVertexIndex(vertex);
+            }
+            else
+            {
+                index = mesh->addVertex(vertex);
+            }
+            meshParts[meshPartIndex]->addIndex(index);
+            vertexIndex++;
+        }
+    }
+
+    const size_t meshpartsSize = meshParts.size();
+    for (size_t i = 0; i < meshpartsSize; ++i)
+    {
+        mesh->addMeshPart(meshParts[i]);
+    }
+
+    // The order that the vertex elements are add to the list matters.
+    // It should be the same order as how the Vertex data is written.
+
+    // Position
+    mesh->addVetexAttribute(POSITION, 3);
+
+    const Vertex& vertex = mesh->vertices[0];
+    // Normals
+    if (vertex.hasNormal)
+    {
+        mesh->addVetexAttribute(NORMAL, 3);
+    }
+    // Tangents
+    if (vertex.hasTangent)
+    {
+        mesh->addVetexAttribute(TANGENT, 3);
+    }
+    // Binormals
+    if (vertex.hasBinormal)
+    {
+        mesh->addVetexAttribute(BINORMAL, 3);
+    }
+    // Texture Coordinates
+    if (vertex.hasTexCoord)
+    {
+        mesh->addVetexAttribute(TEXCOORD0, 2);
+    }
+    // Diffuse Color
+    if (vertex.hasColor)
+    {
+        mesh->addVetexAttribute(COLOR, 3);
+    }
+    // Skinning BlendWeights BlendIndices
+    if (vertex.hasWeights)
+    {
+        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
+        mesh->addVetexAttribute(BLENDINDICES, 4);
+    }
+
+    _gamePlayFile.addMesh(mesh);
+    saveMesh(fbxMesh->GetUniqueID(), mesh);
+    return mesh;
+}
+
+void FBXSceneEncoder::triangulateRecursive(KFbxNode* fbxNode)
+{
+    // Triangulate all NURBS, patch and mesh under this node recursively.
+    KFbxNodeAttribute* nodeAttribute = fbxNode->GetNodeAttribute();
+
+    if (nodeAttribute)
+    {
+        if (nodeAttribute->GetAttributeType() == KFbxNodeAttribute::eMESH ||
+            nodeAttribute->GetAttributeType() == KFbxNodeAttribute::eNURB ||
+            nodeAttribute->GetAttributeType() == KFbxNodeAttribute::eNURBS_SURFACE ||
+            nodeAttribute->GetAttributeType() == KFbxNodeAttribute::ePATCH)
+        {
+            KFbxGeometryConverter converter(fbxNode->GetFbxSdkManager());
+            converter.TriangulateInPlace(fbxNode);
+        }
+    }
+
+    const int childCount = fbxNode->GetChildCount();
+    for (int childIndex = 0; childIndex < childCount; ++childIndex)
+    {
+        triangulateRecursive(fbxNode->GetChild(childIndex));
+    }
+}
+
+void FBXSceneEncoder::warning(const std::string& message)
+{
+    printf("Warning: %s\n", message.c_str());
+}
+
+void FBXSceneEncoder::warning(const char* message)
+{
+    printf("Warning: %s\n", message);
+}
+
+////////////////////////////////////
+// Functions
+////////////////////////////////////
+
+float getAspectRatio(KFbxCamera* fbxCamera)
+{
+    return (float)fbxCamera->FilmAspectRatio.Get();
+    /*
+    KFbxCamera::ECameraAspectRatioMode camAspectRatioMode = fbxCamera->GetAspectRatioMode();
+    double aspectX = fbxCamera->AspectWidth.Get();
+    double aspectY = fbxCamera->AspectHeight.Get();
+    double aspectRatio = 1.333333;
+    switch ( camAspectRatioMode)
+    {
+    case KFbxCamera::eWINDOW_SIZE:
+        aspectRatio = aspectX / aspectY;
+        break;
+    case KFbxCamera::eFIXED_RATIO:
+        aspectRatio = aspectX;
+        break;
+    case KFbxCamera::eFIXED_RESOLUTION:
+        aspectRatio = aspectX / aspectY * fbxCamera->GetPixelRatio();
+        break;
+    case KFbxCamera::eFIXED_WIDTH:
+        aspectRatio = fbxCamera->GetPixelRatio() / aspectY;
+        break;
+    case KFbxCamera::eFIXED_HEIGHT:
+        aspectRatio = fbxCamera->GetPixelRatio() * aspectX;
+        break;
+    default:
+        break;
+    }
+    return (float)aspectRatio;
+    */
+}
+
+inline double vfov(double hfov, double aspect)
+{
+    static const double MATH_PI_180 = 0.01745329251994329576923690768489;
+    static const double MATH_180_PI = 57.295779513082320876798154814105;
+    return (2.0 * atan((aspect) * tan( (hfov * MATH_PI_180) * 0.5)) * MATH_180_PI);
+}
+
+float getFieldOfView(KFbxCamera* fbxCamera)
+{
+    double fieldOfViewX = 0.0;
+    double fieldOfViewY = 0.0;
+    double filmHeight = fbxCamera->GetApertureHeight();
+    double filmWidth = fbxCamera->GetApertureWidth() * fbxCamera->GetSqueezeRatio();
+    double apertureRatio = filmHeight / filmWidth;
+    if ( fbxCamera->GetApertureMode() == KFbxCamera::eVERTICAL)
+    {
+        fieldOfViewY = fbxCamera->FieldOfView.Get();
+    }
+    else if (fbxCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL)
+    {
+        fieldOfViewX = fbxCamera->FieldOfView.Get();
+        fieldOfViewY = vfov( fieldOfViewX, apertureRatio);
+    }
+    else if (fbxCamera->GetApertureMode() == KFbxCamera::eFOCAL_LENGTH)
+    {
+        fieldOfViewX = fbxCamera->ComputeFieldOfView(fbxCamera->FocalLength.Get());
+        fieldOfViewY = vfov( fieldOfViewX, apertureRatio);
+    }
+    else if (fbxCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL_AND_VERTICAL)
+    {
+        fieldOfViewY = fbxCamera->FieldOfViewY.Get();
+    }
+    else
+    {
+        fieldOfViewY = 45.0;
+    }
+    return (float)fieldOfViewY;
+}
+
+void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex)
+{
+    assert(fbxMesh && polyIndex >=0 && posInPoly >= 0);
+    if (fbxMesh->GetElementUVCount() > 0)
+    {
+        // Get only the first UV coordinates.
+        KFbxGeometryElementUV* leUV = fbxMesh->GetElementUV(0);
+        switch (leUV->GetMappingMode())
+        {
+        case KFbxGeometryElement::eBY_CONTROL_POINT:
+            switch (leUV->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                vertex->hasTexCoord = true;
+                vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(polyIndex)[0];
+                vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(polyIndex)[1];
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leUV->GetIndexArray().GetAt(polyIndex);
+                    vertex->hasTexCoord = true;
+                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(id)[0];
+                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(id)[1];
+                }
+                break;
+            default:
+                break;
+            }
+            break;
+        case KFbxGeometryElement::eBY_POLYGON_VERTEX:
+            {
+                int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
+                switch (leUV->GetReferenceMode())
+                {
+                case KFbxGeometryElement::eDIRECT:
+                case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                    vertex->hasTexCoord = true;
+                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(lTextureUVIndex)[0];
+                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(lTextureUVIndex)[1];
+                    break;
+                default:
+                    break;
+                }
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementNormalCount() > 0)
+    {
+        // Get only the first
+        KFbxGeometryElementNormal* leNormal = fbxMesh->GetElementNormal(0);
+        if (leNormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (leNormal->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(vertexIndex);
+                    vertex->hasNormal = true;
+                    vertex->normal.x = (float)vec4[0];
+                    vertex->normal.y = (float)vec4[1];
+                    vertex->normal.z = (float)vec4[2];
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leNormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(id);
+                    vertex->hasNormal = true;
+                    vertex->normal.x = (float)vec4[0];
+                    vertex->normal.y = (float)vec4[1];
+                    vertex->normal.z = (float)vec4[2];
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementTangentCount() > 0)
+    {
+        // Get only the first tangent
+        KFbxGeometryElementTangent* leTangent = fbxMesh->GetElementTangent(0);
+        if (leTangent->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (leTangent->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(vertexIndex);
+                    vertex->hasTangent = true;
+                    vertex->tangent.x = (float)vec4[0];
+                    vertex->tangent.y = (float)vec4[1];
+                    vertex->tangent.z = (float)vec4[2];
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leTangent->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(id);
+                    vertex->hasTangent = true;
+                    vertex->tangent.x = (float)vec4[0];
+                    vertex->tangent.y = (float)vec4[1];
+                    vertex->tangent.z = (float)vec4[2];
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementBinormalCount() > 0)
+    {
+        // Get only the first binormal.
+        KFbxGeometryElementBinormal* leBinormal = fbxMesh->GetElementBinormal(0);
+        if (leBinormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (leBinormal->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(vertexIndex);
+                    vertex->hasBinormal = true;
+                    vertex->binormal.x = (float)vec4[0];
+                    vertex->binormal.y = (float)vec4[1];
+                    vertex->binormal.z = (float)vec4[2];
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leBinormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(id);
+                    vertex->hasBinormal = true;
+                    vertex->binormal.x = (float)vec4[0];
+                    vertex->binormal.y = (float)vec4[1];
+                    vertex->binormal.z = (float)vec4[2];
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
+{
+    size_t size = vertexWeights.size();
+
+    if (size >= 1)
+    {
+        vertex->hasWeights= true;
+        vertex->blendIndices.x = vertexWeights[0].x;
+        vertex->blendWeights.x = vertexWeights[0].y;
+    }
+    if (size >= 2)
+    {
+        vertex->blendIndices.y = vertexWeights[1].x;
+        vertex->blendWeights.y = vertexWeights[1].y;
+    }
+    if (size >= 3)
+    {
+        vertex->blendIndices.z = vertexWeights[2].x;
+        vertex->blendWeights.z = vertexWeights[2].y;
+    }
+    if (size >= 4)
+    {
+        vertex->blendIndices.w = vertexWeights[3].x;
+        vertex->blendWeights.w = vertexWeights[3].y;
+    }
+    //vertex->normalizeBlendWeight();
+}
+
+bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights)
+{
+    assert(fbxMesh);
+    const int vertexCount = fbxMesh->GetControlPointsCount();
+
+    KFbxSkin* fbxSkin = NULL;
+    const int deformerCount = fbxMesh->GetDeformerCount();
+    for (int i = 0; i < deformerCount; ++i)
+    {
+        KFbxDeformer* deformer = fbxMesh->GetDeformer(i);
+        if (deformer->GetDeformerType() == KFbxDeformer::eSKIN)
+        {
+            fbxSkin = static_cast<KFbxSkin*>(deformer);
+            weights.resize(vertexCount);
+
+            const int clusterCount = fbxSkin->GetClusterCount();
+            for (int j = 0; j < clusterCount; ++j)
+            {
+                KFbxCluster* cluster = fbxSkin->GetCluster(j);
+                assert(cluster);
+                KFbxNode* linkedNode = cluster->GetLink();
+                assert(linkedNode);
+
+                const int vertexIndexCount = cluster->GetControlPointIndicesCount();
+                for (int k = 0; k < vertexIndexCount; ++k)
+                {
+                    int index = cluster->GetControlPointIndices()[k];
+                    if (index >= vertexCount)
+                    {
+                        continue;
+                    }
+
+                    double weight = cluster->GetControlPointWeights()[k];
+                    if (weight == 0.0)
+                    {
+                        continue;
+                    }
+                    weights[index].push_back(Vector2((float)j, (float)weight));
+                }
+            }
+            // Only the first skin deformer will be loaded.
+            // There probably won't be more than one.
+            break;
+        }
+    }
+    return fbxSkin != NULL;
+}
+
+void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate)
+{
+    KTime start, stop;
+    animCurve->GetTimeInterval(start, stop);
+    *startTime = std::min(*startTime, (float)start.GetMilliSeconds());
+    *stopTime = std::max(*stopTime, (float)stop.GetMilliSeconds());
+    *frameRate = std::max(*frameRate, (float)stop.GetFrameRate(KTime::eDEFAULT_MODE));
+}
+
+void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes, std::vector<float>* keyValues)
+{
+    KFbxXMatrix fbxMatrix;
+    Matrix matrix;
+    KTime kTime;
+    kTime.SetMilliSeconds((kLongLong)time);
+    fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
+    copyMatrix(fbxMatrix, matrix);
+
+    Vector3 scale;
+    Quaternion rotation;
+    Vector3 translation;
+    matrix.decompose(&scale, &rotation, &translation);
+
+    keyTimes->push_back(time);
+    keyValues->push_back(scale.x);
+    keyValues->push_back(scale.y);
+    keyValues->push_back(scale.z);
+    keyValues->push_back(rotation.x);
+    keyValues->push_back(rotation.y);
+    keyValues->push_back(rotation.z);
+    keyValues->push_back(rotation.w);
+    keyValues->push_back(translation.x);
+    keyValues->push_back(translation.y);
+    keyValues->push_back(translation.z);
+}
+
+void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation)
+{
+    KFbxXMatrix fbxMatrix;
+    Matrix matrix;
+    KTime kTime;
+    kTime.SetMilliSeconds((kLongLong)time);
+    fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
+    copyMatrix(fbxMatrix, matrix);
+    matrix.decompose(scale, rotation, translation);
+}
+
+AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues)
+{
+    AnimationChannel* channel = new AnimationChannel();
+    channel->setTargetId(fbxNode->GetName());
+    channel->setKeyTimes(keyTimes);
+    channel->setKeyValues(keyValues);
+    channel->setInterpolation(AnimationChannel::LINEAR);
+    channel->setTargetAttribute(targetAttrib);
+    return channel;
+}
+
+void addScaleChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime)
+{
+    std::vector<float> keyTimes;
+    std::vector<float> keyValues;
+    Vector3 scale;
+    Quaternion rotation;
+    Vector3 translation;
+
+    decompose(fbxNode, startTime, &scale, &rotation, &translation);
+    keyTimes.push_back(startTime);
+    keyValues.push_back(scale.x);
+    keyValues.push_back(scale.y);
+    keyValues.push_back(scale.z);
+
+    decompose(fbxNode, stopTime, &scale, &rotation, &translation);
+    keyTimes.push_back(stopTime);
+    keyValues.push_back(scale.x);
+    keyValues.push_back(scale.y);
+    keyValues.push_back(scale.z);
+
+    AnimationChannel* channel = createAnimationChannel(fbxNode, Transform::ANIMATE_SCALE, keyTimes, keyValues);
+    animation->add(channel);
+}
+
+void addTranslateChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime)
+{
+    std::vector<float> keyTimes;
+    std::vector<float> keyValues;
+    Vector3 scale;
+    Quaternion rotation;
+    Vector3 translation;
+
+    decompose(fbxNode, startTime, &scale, &rotation, &translation);
+    keyTimes.push_back(startTime);
+    keyValues.push_back(translation.x);
+    keyValues.push_back(translation.y);
+    keyValues.push_back(translation.z);
+
+    decompose(fbxNode, stopTime, &scale, &rotation, &translation);
+    keyTimes.push_back(stopTime);
+    keyValues.push_back(translation.x);
+    keyValues.push_back(translation.y);
+    keyValues.push_back(translation.z);
+
+    AnimationChannel* channel = createAnimationChannel(fbxNode, Transform::ANIMATE_TRANSLATE, keyTimes, keyValues);
+    animation->add(channel);
+}
+
+void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix)
+{
+    int i = 0;
+    for (int row = 0; row < 4; ++row)
+    {
+        for (int col = 0; col < 4; ++col)
+        {
+            matrix[i++] = (float)fbxMatrix.Get(row, col);
+        }
+    }
+}
+
+void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix)
+{
+    int i = 0;
+    for (int row = 0; row < 4; ++row)
+    {
+        for (int col = 0; col < 4; ++col)
+        {
+            matrix.m[i++] = (float)fbxMatrix.Get(row, col);
+        }
+    }
+}
+
+#endif

+ 222 - 0
gameplay-encoder/src/FBXSceneEncoder.h

@@ -0,0 +1,222 @@
+#ifndef FBXSCENEEENCODER_H_
+#define FBXSCENEEENCODER_H_
+
+#ifdef USE_FBX
+
+#include <iostream>
+#include <list>
+#include <vector>
+#include <ctime>
+#ifdef WIN32
+    #pragma warning( disable : 4100 )
+    #pragma warning( disable : 4512 )
+#endif
+#include <fbxsdk.h>
+
+#include "Base.h"
+#include "StringUtil.h"
+#include "Object.h"
+#include "Node.h"
+#include "Camera.h"
+#include "Light.h"
+#include "Mesh.h"
+#include "MeshPart.h"
+#include "MeshSkin.h"
+#include "Model.h"
+#include "Scene.h"
+#include "Animation.h"
+#include "AnimationChannel.h"
+#include "Vertex.h"
+#include "Matrix.h"
+#include "Transform.h"
+#include "GPBFile.h"
+#include "EncoderArguments.h"
+
+using namespace gameplay;
+
+/**
+ * Class for binary encoding an FBX file.
+ */
+class FBXSceneEncoder
+{
+public:
+
+    static const unsigned int SCENE_SKIN_VERTEXINFLUENCES_MAX = 4;
+    
+    /**
+     * Constructor.
+     */
+    FBXSceneEncoder();
+
+    /**
+     * Destructor.
+     */
+    ~FBXSceneEncoder();
+    
+    /**
+     * Writes out encoded FBX file.
+     */
+    void write(const std::string& filepath, const EncoderArguments& arguments);
+
+private:
+
+    /**
+     * Loads the scene.
+     * 
+     * @param fbxScene The FBX scene to load.
+     */
+    void loadScene(KFbxScene* fbxScene);
+
+    /**
+     * Loads all of the animatiosn from the given FBX scene.
+     * 
+     * @param fbxScene The scene to load animations from.
+     * @param arguments The command line arguments passed to the encoder.
+     */
+    void loadAnimations(KFbxScene* fbxScene, const EncoderArguments& arguments);
+
+    /**
+     * Loads the animations from the given FBX animation layer recursively starting from fbxNode.
+     * 
+     * @param fbxAnimLayer The FBX animation layer to load from.
+     * @param fbxNode The node to start loading animations from.
+     * @param arguments The command line arguments passed to the encoder.
+     */
+    void loadAnimationLayer(KFbxAnimLayer* fbxAnimLayer, KFbxNode* fbxNode, const EncoderArguments& arguments);
+
+    /**
+     * Loads animation channels from the given node and adds the channels to the given animation.
+     * 
+     * @param pAnimLayer The FBX animation layer to load from.
+     * @param fbxNode The node to load animation channels from.
+     * @param animation The animation to add the channels to.
+     */
+    void loadAnimationChannels(KFbxAnimLayer* pAnimLayer, KFbxNode* fbxNode, Animation* animation);
+
+    /**
+     * Loads the bind shape for all mesh skins that have be loaded so far.
+     * 
+     * @param fbxScene The FBX scene to read the bind shapes from.
+     */
+    void loadBindShapes(KFbxScene* fbxScene);
+
+    /**
+     * Loads the camera from the given FBX node and adds to it to the given GamePlay node.
+     * 
+     * @param fbxNode The FBX node to load from.
+     * @param node The GamePlay node to add to.
+     */
+    void loadCamera(KFbxNode* fbxNode, Node* node);
+
+    /**
+     * Loads the light from the given FBX node and adds to it to the given GamePlay node.
+     * 
+     * @param fbxNode The FBX node to load from.
+     * @param node The GamePlay node to add to.
+     */
+    void loadLight(KFbxNode* fbxNode, Node* node);
+    
+    /**
+     * Loads the model from the given FBX node and adds to it to the given GamePlay node.
+     *
+     * @param fbxNode The FBX node to load from.
+     * @param node The GamePlay node to add to.
+     */
+    void loadModel(KFbxNode* fbxNode, Node* node);
+
+    /**
+     * Loads the mesh skin from the given FBX mesh and adds it to the given GamePlay model.
+     *
+     * @param fbxMesh The FBX mesh to load the skin from.
+     * @param model The model to add the skin to.
+     */
+    void loadSkin(KFbxMesh* fbxMesh, Model* model);
+    
+    /**
+     * Loads the FBX Node and creates a GamePlay Node.
+     * 
+     * @param fbxNode The FBX Node to load.
+     * 
+     * @return The newly created Node or NULL if the node could not be loaded.
+     */
+    Node* loadNode(KFbxNode* fbxNode);
+    
+    /**
+     * Loads the FbxMesh and returns a GamePlay mesh.
+     * If the fbxMesh has already been loaded then the same instance of mesh will be returned.
+     * 
+     * @param fbxMesh The FBX Mesh to load.
+     * 
+     * @return The GamePlay mesh that was loaded from the FBX Mesh.
+     */
+    Mesh* loadMesh(KFbxMesh* fbxMesh);
+
+    /**
+     * Gets the Mesh that was saved with the given ID. Returns NULL if a match is not found.
+     * 
+     * @param meshId The ID of the FbxMesh to search for.
+     * 
+     * @return The mesh that was saved with the ID or NULL if none was found.
+     */
+    Mesh* getMesh(size_t meshId);
+
+    /**
+     * Saves the Mesh with the given id.
+     * 
+     * @param meshId The ID of the FbxMesh to use as a key.
+     * @param mesh The mesh to save.
+     */
+    void saveMesh(size_t meshId, Mesh* mesh);
+    
+    /**
+     * Prints a message.
+     *
+     * @param str The string to print.
+     */
+    void print(const char* str);
+
+    /**
+     * Transforms the GamePlay Node using the transform data from the FBX Node.
+     * 
+     * @param fbxNode The FBX node to get the transfrom data from
+     * @param node The GamePlay Node to copy the transform to.
+     */
+    void transformNode(KFbxNode* fbxNode, Node* node);
+
+    /**
+     * Recursively triangules the meshes starting from the given node.
+     * 
+     * @param fbxNode The node to start triangulating from.
+     */
+    static void triangulateRecursive(KFbxNode* fbxNode);
+
+    /**
+     * Prints a warning message.
+     */
+    static void warning(const std::string& message);
+
+    /**
+     * Prints a warning message.
+     */
+    static void warning(const char* message);
+
+private:
+
+    /**
+     * The GamePlay file that is populated while reading the FBX file.
+     */
+    GPBFile _gamePlayFile;
+
+    /**
+     * The collection of meshes for the purpose of making sure that the same model is not loaded twice. (Mesh instancing)
+     */
+    std::map<size_t, Mesh*> _meshes;
+
+    /**
+     * The animation that channels should be added to it the user is using the -groupAnimation command line argument. May be NULL.
+     */
+    Animation* _groupAnimation;
+};
+
+#endif
+#endif

+ 43 - 7
gameplay-encoder/src/FileIO.cpp

@@ -1,10 +1,10 @@
+#include "Base.h"
 #include "FileIO.h"
 #include "FileIO.h"
-#include <assert.h>
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-// Writing ot a binary file //
+// Writing out a binary file //
 
 
 void write(unsigned char value, FILE* file)
 void write(unsigned char value, FILE* file)
 {
 {
@@ -55,7 +55,7 @@ void write(float value, FILE* file)
 }
 }
 void write(const float* values, int length, FILE* file)
 void write(const float* values, int length, FILE* file)
 {
 {
-    for (int i = 0; i < length; i++)
+    for (int i = 0; i < length; ++i)
     {
     {
         write(values[i], file);
         write(values[i], file);
     }
     }
@@ -77,8 +77,8 @@ void writeZero(FILE* file)
 
 
 void fprintfElement(FILE* file, const char* elementName, const float values[], int length)
 void fprintfElement(FILE* file, const char* elementName, const float values[], int length)
 {
 {
-    fprintf(file, "<%s>", elementName);
-    for (int i = 0; i < length; i++)
+    fprintf(file, "<%s count=\"%d\">", elementName, length);
+    for (int i = 0; i < length; ++i)
     {
     {
         fprintf(file, "%f ", values[i]);
         fprintf(file, "%f ", values[i]);
     }
     }
@@ -102,7 +102,7 @@ void fprintfElement(FILE* file, const char* elementName, unsigned int value)
 }
 }
 void fprintfElement(FILE* file, const char* elementName, unsigned char value)
 void fprintfElement(FILE* file, const char* elementName, unsigned char value)
 {
 {
-    fprintf(file, "<%s>%u</%s>\n", elementName, value, (unsigned int)elementName);
+    fprintf(file, "<%s>%u</%s>\n", elementName, value, elementName);
 }
 }
 
 
 void fprintfMatrix4f(FILE* file, const float* m)
 void fprintfMatrix4f(FILE* file, const float* m)
@@ -144,4 +144,40 @@ void skipUint(FILE* file)
     fseek(file, sizeof(unsigned int), SEEK_CUR);
     fseek(file, sizeof(unsigned int), SEEK_CUR);
 }
 }
 
 
-}
+void writeVectorBinary(const Vector2& v, FILE* file)
+{
+    write(v.x, file);
+    write(v.y, file);
+}
+
+void writeVectorText(const Vector2& v, FILE* file)
+{
+    fprintf(file, "%f %f\n", v.x, v.y);
+}
+
+void writeVectorBinary(const Vector3& v, FILE* file)
+{
+    write(v.x, file);
+    write(v.y, file);
+    write(v.z, file);
+}
+
+void writeVectorText(const Vector3& v, FILE* file)
+{
+    fprintf(file, "%f %f %f\n", v.x, v.y, v.z);
+}
+
+void writeVectorBinary(const Vector4& v, FILE* file)
+{
+    write(v.x, file);
+    write(v.y, file);
+    write(v.z, file);
+    write(v.w, file);
+}
+
+void writeVectorText(const Vector4& v, FILE* file)
+{
+    fprintf(file, "%f %f %f %f\n", v.x, v.y, v.z, v.w);
+}
+
+}

+ 33 - 17
gameplay-encoder/src/FileIO.h

@@ -1,17 +1,17 @@
 #ifndef FILEIO_H_
 #ifndef FILEIO_H_
 #define FILEIO_H_
 #define FILEIO_H_
 
 
-#include <iostream>
-#include <list>
-#include <vector>
 
 
-#include "Base.h"
+#include "Vector2.h"
+#include "Vector3.h"
+#include "Vector4.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 /**
 /**
  * Writes an XML element to the specified file stream.
  * Writes an XML element to the specified file stream.
+ * 
  * @param file Pointer to a FILE object that identifies the stream.
  * @param file Pointer to a FILE object that identifies the stream.
  * @param elementName Name of the XML element to write.
  * @param elementName Name of the XML element to write.
  * @param value Value to write.
  * @param value Value to write.
@@ -26,9 +26,9 @@ void fprintfElement(FILE* file, const char* elementName, const float values[], i
 template <class T>
 template <class T>
 void fprintfElement(FILE* file, const char* format, const char* elementName, std::vector<T> list)
 void fprintfElement(FILE* file, const char* format, const char* elementName, std::vector<T> list)
 {
 {
-    fprintf(file, "<%s>", elementName);
-    std::vector<T>::const_iterator i;
-    for (i = list.begin(); i != list.end(); i++)
+    fprintf(file, "<%s count=\"%lu\">", elementName, list.size());
+    typename std::vector<T>::const_iterator i;
+    for (i = list.begin(); i != list.end(); ++i)
     {
     {
         fprintf(file, format, *i);
         fprintf(file, format, *i);
     }
     }
@@ -38,9 +38,9 @@ void fprintfElement(FILE* file, const char* format, const char* elementName, std
 template <class T>
 template <class T>
 void fprintfElement(FILE* file, const char* format, const char* elementName, std::list<T> list)
 void fprintfElement(FILE* file, const char* format, const char* elementName, std::list<T> list)
 {
 {
-    fprintf(file, "<%s>", elementName);
-    std::list<T>::const_iterator i;
-    for (i = list.begin(); i != list.end(); i++)
+    fprintf(file, "<%s count=\"%lu\">", elementName, list.size());
+    typename std::list<T>::const_iterator i;
+    for (i = list.begin(); i != list.end(); ++i)
     {
     {
         fprintf(file, format, *i);
         fprintf(file, format, *i);
     }
     }
@@ -51,6 +51,7 @@ void fprintfMatrix4f(FILE* file, const float* m);
 
 
 /**
 /**
  * Writes binary data to the given file stream.
  * Writes binary data to the given file stream.
+ * 
  * @param value The value to be written
  * @param value The value to be written
  * @param file The binary file stream.
  * @param file The binary file stream.
  */
  */
@@ -63,6 +64,7 @@ void write(unsigned short value, FILE* file);
 void write(bool value, FILE* file);
 void write(bool value, FILE* file);
 void write(float value, FILE* file);
 void write(float value, FILE* file);
 void write(const float* values, int length, FILE* file);
 void write(const float* values, int length, FILE* file);
+
 /**
 /**
  * Writes the length of the string and the string bytes to the binary file stream.
  * Writes the length of the string and the string bytes to the binary file stream.
  */
  */
@@ -72,6 +74,7 @@ void writeZero(FILE* file);
 
 
 /**
 /**
  * Writes the length of the list and writes each element value to the binary file stream.
  * Writes the length of the list and writes each element value to the binary file stream.
+ * 
  * @param list The list to write.
  * @param list The list to write.
  * @param file The binary file stream.
  * @param file The binary file stream.
  */
  */
@@ -81,8 +84,8 @@ void write(std::list<T> list, FILE* file)
     // First write the size of the list
     // First write the size of the list
     write(list.size(), file);
     write(list.size(), file);
     // Then write each element
     // Then write each element
-    std::list<T>::const_iterator i;
-    for (i = list.begin(); i != list.end(); i++)
+    typename std::list<T>::const_iterator i;
+    for (i = list.begin(); i != list.end(); ++i)
     {
     {
         write(*i, file);
         write(*i, file);
     }
     }
@@ -90,6 +93,7 @@ void write(std::list<T> list, FILE* file)
 
 
 /**
 /**
  * Writes the length of the vector and writes each element value to the binary file stream.
  * Writes the length of the vector and writes each element value to the binary file stream.
+ * 
  * @param vector The vector to write.
  * @param vector The vector to write.
  * @param file The binary file stream.
  * @param file The binary file stream.
  */
  */
@@ -99,24 +103,36 @@ void write(std::vector<T> vector, FILE* file)
     // First write the size of the vector
     // First write the size of the vector
     write(vector.size(), file);
     write(vector.size(), file);
     // Then write each element
     // Then write each element
-    std::vector<T>::const_iterator i;
-    for (i = vector.begin(); i != vector.end(); i++)
+    typename std::vector<T>::const_iterator i;
+    for (i = vector.begin(); i != vector.end(); ++i)
     {
     {
         write(*i, file);
         write(*i, file);
     }
     }
 }
 }
 
 
-
 /**
 /**
  * Skips over the string at the current file stream offset by moving the file position.
  * Skips over the string at the current file stream offset by moving the file position.
  * Assumes the current position points to the unsigned int length of the string.
  * Assumes the current position points to the unsigned int length of the string.
  * The string is assumed to be a char array.
  * The string is assumed to be a char array.
- * @param The file stream.
+ * 
+ * @param file The file stream.
  */
  */
 void skipString(FILE* file);
 void skipString(FILE* file);
 
 
 void skipUint(FILE* file);
 void skipUint(FILE* file);
 
 
+void writeVectorBinary(const Vector2& v, FILE* file);
+
+void writeVectorText(const Vector2& v, FILE* file);
+
+void writeVectorBinary(const Vector3& v, FILE* file);
+
+void writeVectorText(const Vector3& v, FILE* file);
+
+void writeVectorBinary(const Vector4& v, FILE* file);
+
+void writeVectorText(const Vector4& v, FILE* file);
+
 }
 }
-#endif
 
 
+#endif

+ 2 - 1
gameplay-encoder/src/Font.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Font.h"
 #include "Font.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -50,4 +51,4 @@ void Font::writeText(FILE* file)
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
-}
+}

+ 1 - 2
gameplay-encoder/src/Font.h

@@ -44,7 +44,6 @@ public:
     };
     };
 };
 };
 
 
-
 }
 }
-#endif
 
 
+#endif

+ 4 - 3
gameplay-encoder/src/GPBDecoder.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "GPBDecoder.h"
 #include "GPBDecoder.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -42,7 +43,7 @@ bool GPBDecoder::validateHeading()
     const char identifier[] = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' };
     const char identifier[] = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' };
 
 
     char heading[HEADING_SIZE];
     char heading[HEADING_SIZE];
-    for (size_t i = 0; i < HEADING_SIZE; i++)
+    for (size_t i = 0; i < HEADING_SIZE; ++i)
     {
     {
         if (heading[i] != identifier[i])
         if (heading[i] != identifier[i])
         {
         {
@@ -63,7 +64,7 @@ void GPBDecoder::readRefs()
     // read number of refs
     // read number of refs
     unsigned int refCount;
     unsigned int refCount;
     assert(read(&refCount));
     assert(read(&refCount));
-    for (size_t i = 0; i < refCount; i++)
+    for (size_t i = 0; i < refCount; ++i)
     {
     {
         readRef();
         readRef();
     }
     }
@@ -113,4 +114,4 @@ std::string GPBDecoder::readString(FILE* fp)
     return result;
     return result;
 }
 }
 
 
-};
+}

+ 1 - 8
gameplay-encoder/src/GPBDecoder.h

@@ -1,14 +1,6 @@
-/*
- * GamePlayFile.h
- */
-
 #ifndef GPBDECODER_H_
 #ifndef GPBDECODER_H_
 #define GPBDECODER_H_
 #define GPBDECODER_H_
 
 
-#include <iostream>
-#include <list>
-#include <assert.h>
-
 #include "FileIO.h"
 #include "FileIO.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -40,6 +32,7 @@ public:
     std::string readString(FILE* fp);
     std::string readString(FILE* fp);
 
 
 private:
 private:
+
     FILE* _file;
     FILE* _file;
     FILE* _outFile;
     FILE* _outFile;
 };
 };

+ 33 - 12
gameplay-encoder/src/GPBFile.cpp

@@ -1,17 +1,26 @@
+#include "Base.h"
 #include "GPBFile.h"
 #include "GPBFile.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+static GPBFile* __instance = NULL;
+
 GPBFile::GPBFile(void)
 GPBFile::GPBFile(void)
     : _file(NULL), _animationsAdded(false)
     : _file(NULL), _animationsAdded(false)
 {
 {
+    __instance = this;
 }
 }
 
 
 GPBFile::~GPBFile(void)
 GPBFile::~GPBFile(void)
 {
 {
 }
 }
 
 
+GPBFile* GPBFile::getInstance()
+{
+    return __instance;
+}
+
 void GPBFile::saveBinary(const std::string& filepath)
 void GPBFile::saveBinary(const std::string& filepath)
 {
 {
     _file = fopen(filepath.c_str(), "w+b");
     _file = fopen(filepath.c_str(), "w+b");
@@ -21,21 +30,21 @@ void GPBFile::saveBinary(const std::string& filepath)
     fwrite(identifier, 1, sizeof(identifier), _file);
     fwrite(identifier, 1, sizeof(identifier), _file);
 
 
     // version
     // version
-    fwrite(VERSION, 1, sizeof(VERSION), _file);
+    fwrite(GPB_VERSION, 1, sizeof(GPB_VERSION), _file);
 
 
     // write refs
     // write refs
     _refTable.writeBinary(_file);
     _refTable.writeBinary(_file);
 
 
     // meshes
     // meshes
     write(_geometry.size(), _file);
     write(_geometry.size(), _file);
-    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); i++)
+    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); ++i)
     {
     {
         (*i)->writeBinary(_file);
         (*i)->writeBinary(_file);
     }
     }
 
 
     // Objects
     // Objects
     write(_objects.size(), _file);
     write(_objects.size(), _file);
-    for (std::list<Object*>::const_iterator i = _objects.begin(); i != _objects.end(); i++)
+    for (std::list<Object*>::const_iterator i = _objects.begin(); i != _objects.end(); ++i)
     {
     {
         (*i)->writeBinary(_file);
         (*i)->writeBinary(_file);
     }
     }
@@ -55,13 +64,13 @@ void GPBFile::saveText(const std::string& filepath)
     _refTable.writeText(_file);
     _refTable.writeText(_file);
 
 
     // meshes
     // meshes
-    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); i++)
+    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); ++i)
     {
     {
         (*i)->writeText(_file);
         (*i)->writeText(_file);
     }
     }
 
 
     // Objects
     // Objects
-    for (std::list<Object*>::const_iterator i = _objects.begin(); i != _objects.end(); i++)
+    for (std::list<Object*>::const_iterator i = _objects.begin(); i != _objects.end(); ++i)
     {
     {
         (*i)->writeText(_file);
         (*i)->writeText(_file);
     }
     }
@@ -146,8 +155,10 @@ bool GPBFile::idExists(const std::string& id)
 
 
 Camera* GPBFile::getCamera(const char* id)
 Camera* GPBFile::getCamera(const char* id)
 {
 {
+    if (!id)
+        return NULL;
     // TODO: O(n) search is not ideal
     // TODO: O(n) search is not ideal
-    for (std::list<Camera*>::const_iterator i = _cameras.begin(); i != _cameras.end(); i++)
+    for (std::list<Camera*>::const_iterator i = _cameras.begin(); i != _cameras.end(); ++i)
     {
     {
         const std::string& _id = (*i)->getId();
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -160,8 +171,10 @@ Camera* GPBFile::getCamera(const char* id)
 
 
 Light* GPBFile::getLight(const char* id)
 Light* GPBFile::getLight(const char* id)
 {
 {
+    if (!id)
+        return NULL;
     // TODO: O(n) search is not ideal
     // TODO: O(n) search is not ideal
-    for (std::list<Light*>::const_iterator i = _lights.begin(); i != _lights.end(); i++)
+    for (std::list<Light*>::const_iterator i = _lights.begin(); i != _lights.end(); ++i)
     {
     {
         const std::string& _id = (*i)->getId();
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -174,8 +187,10 @@ Light* GPBFile::getLight(const char* id)
 
 
 Mesh* GPBFile::getMesh(const char* id)
 Mesh* GPBFile::getMesh(const char* id)
 {
 {
+    if (!id)
+        return NULL;
     // TODO: O(n) search is not ideal
     // TODO: O(n) search is not ideal
-    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); i++)
+    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); ++i)
     {
     {
         const std::string& _id = (*i)->getId();
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -188,8 +203,10 @@ Mesh* GPBFile::getMesh(const char* id)
 
 
 Node* GPBFile::getNode(const char* id)
 Node* GPBFile::getNode(const char* id)
 {
 {
+    if (!id)
+        return NULL;
     // TODO: O(n) search is not ideal
     // TODO: O(n) search is not ideal
-    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
     {
     {
         const std::string& _id = (*i)->getId();
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -200,10 +217,15 @@ Node* GPBFile::getNode(const char* id)
     return NULL;
     return NULL;
 }
 }
 
 
+Animations* GPBFile::getAnimations()
+{
+    return &_animations;
+}
+
 void GPBFile::adjust()
 void GPBFile::adjust()
 {
 {
     // calculate the ambient color for each scene
     // calculate the ambient color for each scene
-    for (std::list<Object*>::iterator i = _objects.begin(); i != _objects.end(); i++)
+    for (std::list<Object*>::iterator i = _objects.begin(); i != _objects.end(); ++i)
     {
     {
         Object* obj = *i;
         Object* obj = *i;
         if (obj->getTypeId() == Object::SCENE_ID)
         if (obj->getTypeId() == Object::SCENE_ID)
@@ -227,5 +249,4 @@ void GPBFile::adjust()
     //   This can be merged into one animation. Same for scale animations.
     //   This can be merged into one animation. Same for scale animations.
 }
 }
 
 
-
-}
+}

+ 14 - 12
gameplay-encoder/src/GPBFile.h

@@ -1,13 +1,6 @@
-/*
- * GPBFile.h
- */
-
 #ifndef GPBFILE_H_
 #ifndef GPBFILE_H_
 #define GPBFILE_H_
 #define GPBFILE_H_
 
 
-#include <iostream>
-#include <list>
-
 #include "FileIO.h"
 #include "FileIO.h"
 #include "Object.h"
 #include "Object.h"
 #include "Scene.h"
 #include "Scene.h"
@@ -23,11 +16,12 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    /**
-     * Increment the version number when making a change that break binary compatibility.
-     * [0] is major, [1] is minor.
-     */
-    const unsigned char VERSION[2] = {1, 0};
+
+/**
+ * Increment the version number when making a change that break binary compatibility.
+ * [0] is major, [1] is minor.
+ */
+const unsigned char GPB_VERSION[2] = {1, 1};
 
 
 /**
 /**
  * The GamePlay Binary file class handles writing the GamePlay Binary file.
  * The GamePlay Binary file class handles writing the GamePlay Binary file.
@@ -46,6 +40,11 @@ public:
      */
      */
     ~GPBFile(void);
     ~GPBFile(void);
 
 
+    /**
+     * Returns the GPBFile instance.
+     */
+    static GPBFile* getInstance();
+
     /**
     /**
      * Saves the GPBFile as a binary file at filepath.
      * Saves the GPBFile as a binary file at filepath.
      *
      *
@@ -88,6 +87,8 @@ public:
     Mesh* getMesh(const char* id);
     Mesh* getMesh(const char* id);
     Node* getNode(const char* id);
     Node* getNode(const char* id);
 
 
+    Animations* getAnimations();
+
     /**
     /**
      * Adjusts the game play binary file before it is written.
      * Adjusts the game play binary file before it is written.
      */
      */
@@ -108,4 +109,5 @@ private:
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 5 - 3
gameplay-encoder/src/Glyph.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Glyph.h"
 #include "Glyph.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -10,10 +11,10 @@ Glyph::Glyph(void) :
     fillArray(uvCoords, 0.0f, 4);
     fillArray(uvCoords, 0.0f, 4);
 }
 }
 
 
-
-Glyph::~Glyph(void)
+    Glyph::~Glyph(void)
 {
 {
 }
 }
+
 const char* Glyph::getElementName(void) const
 const char* Glyph::getElementName(void) const
 {
 {
     return "Glyph";
     return "Glyph";
@@ -28,6 +29,7 @@ void Glyph::writeBinary(FILE* file)
     write(uvCoords, 4, file);
     write(uvCoords, 4, file);
 
 
 }
 }
+
 void Glyph::writeText(FILE* file)
 void Glyph::writeText(FILE* file)
 {
 {
     fprintElementStart(file);
     fprintElementStart(file);
@@ -37,4 +39,4 @@ void Glyph::writeText(FILE* file)
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
-}
+}

+ 1 - 0
gameplay-encoder/src/Glyph.h

@@ -30,4 +30,5 @@ public:
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 4 - 3
gameplay-encoder/src/Light.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Light.h"
 #include "Light.h"
 #include "DAESceneEncoder.h"
 #include "DAESceneEncoder.h"
 
 
@@ -47,7 +48,7 @@ float Light::computeRange(float constantAttenuation, float linearAttenuation, fl
     const float step = 0.01f;
     const float step = 0.01f;
     float range = 0.01f;
     float range = 0.01f;
     float att = 1.0f;
     float att = 1.0f;
-    while (att < 0.1f)
+    while (att > 0.01f)
     {
     {
         att = 1 / (constantAttenuation + (range * linearAttenuation) + (range * range * quadraticAttenuation));
         att = 1 / (constantAttenuation + (range * linearAttenuation) + (range * range * quadraticAttenuation));
         range += step;
         range += step;
@@ -111,7 +112,7 @@ void Light::writeBinary(FILE* file)
         // Compute an approximate inner angle of the spot light using Collada's outer angle.
         // Compute an approximate inner angle of the spot light using Collada's outer angle.
         _outerAngle = _falloffAngle / 2.0f;
         _outerAngle = _falloffAngle / 2.0f;
         
         
-        if (_range == -1.0f)
+        if (_innerAngle == -1.0f)
         {
         {
             _innerAngle = computeInnerAngle(_outerAngle);
             _innerAngle = computeInnerAngle(_outerAngle);
         }
         }
@@ -227,4 +228,4 @@ void Light::setFalloffExponent(float value)
     }
     }
 }
 }
 
 
-}
+}

+ 1 - 3
gameplay-encoder/src/Light.h

@@ -77,8 +77,6 @@ private:
     float _outerAngle;
     float _outerAngle;
 };
 };
 
 
-
-
 }
 }
-#endif
 
 
+#endif

+ 0 - 55
gameplay-encoder/src/LightInstance.cpp

@@ -1,55 +0,0 @@
-#include "LightInstance.h"
-#include "assert.h"
-
-namespace gameplay
-{
-
-LightInstance::LightInstance(void) : _ref(NULL)
-{
-
-}
-
-LightInstance::~LightInstance(void)
-{
-}
-
-unsigned int LightInstance::getTypeId(void) const
-{
-    return LIGHTINSTANCE_ID;
-}
-const char* LightInstance::getElementName(void) const
-{
-    return "LightInstance";
-}
-
-void LightInstance::writeBinary(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeBinary(file);
-    }
-}
-void LightInstance::writeText(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeText(file);
-    }
-}
-
-Light* LightInstance::getLight() const
-{
-    return _ref;
-}
-
-void LightInstance::setLight(Light* light)
-{
-    _ref = light;
-}
-
-bool LightInstance::isAmbient() const
-{
-    return _ref != NULL && _ref->isAmbient();
-}
-
-}

+ 0 - 40
gameplay-encoder/src/LightInstance.h

@@ -1,40 +0,0 @@
-#ifndef LIGHTINSTANCE_H_
-#define LIGHTINSTANCE_H_
-
-#include "Object.h"
-#include "Light.h"
-
-namespace gameplay
-{
-
-class LightInstance : public Object
-{
-public:
-
-    /**
-     * Constructor.
-     */
-    LightInstance(void);
-
-    /**
-     * Destructor.
-     */
-    virtual ~LightInstance(void);
-
-    virtual unsigned int getTypeId(void) const;
-    virtual const char* getElementName(void) const;
-    virtual void writeBinary(FILE* file);
-    virtual void writeText(FILE* file);
-
-    Light* getLight() const;
-    void setLight(Light* light);
-
-    bool isAmbient() const;
-
-private:
-    Light* _ref;
-};
-
-}
-#endif
-

+ 2 - 1
gameplay-encoder/src/Material.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Material.h"
 #include "Material.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -35,4 +36,4 @@ void Material::writeText(FILE* file)
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
-}
+}

+ 1 - 2
gameplay-encoder/src/Material.h

@@ -32,7 +32,6 @@ private:
     Effect* _effect;
     Effect* _effect;
 };
 };
 
 
-
 }
 }
-#endif
 
 
+#endif

+ 2 - 1
gameplay-encoder/src/MaterialParameter.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "MaterialParameter.h"
 #include "MaterialParameter.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -35,4 +36,4 @@ void MaterialParameter::writeText(FILE* file)
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
-}
+}

+ 1 - 2
gameplay-encoder/src/MaterialParameter.h

@@ -30,7 +30,6 @@ private:
     unsigned int _type;
     unsigned int _type;
 };
 };
 
 
-
 }
 }
-#endif
 
 
+#endif

+ 57 - 3
gameplay-encoder/src/Matrix.cpp

@@ -1,9 +1,9 @@
+#include "Base.h"
 #include "Matrix.h"
 #include "Matrix.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-
 Matrix::Matrix(void)
 Matrix::Matrix(void)
 {
 {
     setIdentity(m);
     setIdentity(m);
@@ -41,6 +41,45 @@ void Matrix::setIdentity(float* matrix)
     memcpy(matrix, MATRIX4F_IDENTITY, MATRIX4F_SIZE);
     memcpy(matrix, MATRIX4F_IDENTITY, MATRIX4F_SIZE);
 }
 }
 
 
+void Matrix::createRotation(const Quaternion& q, float* dst)
+{
+    assert(dst);
+
+    float x2 = q.x + q.x;
+    float y2 = q.y + q.y;
+    float z2 = q.z + q.z;
+
+    float xx2 = q.x * x2;
+    float yy2 = q.y * y2;
+    float zz2 = q.z * z2;
+    float xy2 = q.x * y2;
+    float xz2 = q.x * z2;
+    float yz2 = q.y * z2;
+    float wx2 = q.w * x2;
+    float wy2 = q.w * y2;
+    float wz2 = q.w * z2;
+
+    dst[0] = 1.0f - yy2 - zz2;
+    dst[1] = xy2 + wz2;
+    dst[2] = xz2 - wy2;
+    dst[3] = 0.0f;
+
+    dst[4] = xy2 - wz2;
+    dst[5] = 1.0f - xx2 - zz2;
+    dst[6] = yz2 + wx2;
+    dst[7] = 0.0f;
+
+    dst[8] = xz2 + wy2;
+    dst[9] = yz2 - wx2;
+    dst[10] = 1.0f - xx2 - yy2;
+    dst[11] = 0.0f;
+
+    dst[12] = 0.0f;
+    dst[13] = 0.0f;
+    dst[14] = 0.0f;
+    dst[15] = 1.0f;
+}
+
 void Matrix::createRotation(float x, float y, float z, float angle, float* dst)
 void Matrix::createRotation(float x, float y, float z, float angle, float* dst)
 {
 {
     // Make sure the input axis is normalized
     // Make sure the input axis is normalized
@@ -48,7 +87,7 @@ void Matrix::createRotation(float x, float y, float z, float angle, float* dst)
     if (n != 1.0f)
     if (n != 1.0f)
     {
     {
         // Not normalized
         // Not normalized
-        n = sqrtf(n);
+        n = sqrt(n);
         if (n > 0.000001f) // prevent divide too close to zero
         if (n > 0.000001f) // prevent divide too close to zero
         {
         {
             n = 1.0f / n;
             n = 1.0f / n;
@@ -167,6 +206,13 @@ void Matrix::scale(float x, float y, float z)
     multiply(m, s, m);
     multiply(m, s, m);
 }
 }
 
 
+void Matrix::rotate(const Quaternion& q)
+{
+    float r[16];
+    createRotation(q, r);
+    multiply(m, r, m);
+}
+
 void Matrix::rotate(float x, float y, float z, float angle)
 void Matrix::rotate(float x, float y, float z, float angle)
 {
 {
     float r[16];
     float r[16];
@@ -350,4 +396,12 @@ float Matrix::determinant() const
     return (a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0);
     return (a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0);
 }
 }
 
 
-}
+void Matrix::transformPoint(const Vector3& p, Vector3* dst) const
+{
+    dst->set(
+        p.x * m[0] + p.y * m[4] + p.z * m[8] +  m[12],
+        p.x * m[1] + p.y * m[5] + p.z * m[9] +  m[13],
+        p.x * m[2] + p.y * m[6] + p.z * m[10] + m[14] );
+}
+
+}

+ 23 - 2
gameplay-encoder/src/Matrix.h

@@ -12,7 +12,6 @@
 #define TORADIANS(degrees) (degrees * (PI / 180.0f))
 #define TORADIANS(degrees) (degrees * (PI / 180.0f))
 #define TODEGREES(radians) (radians * (180.0f / PI))
 #define TODEGREES(radians) (radians * (180.0f / PI))
 
 
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -31,6 +30,11 @@ class Matrix
 {
 {
 public:
 public:
 
 
+    /**
+     * Matrix colums.
+     */
+    float m[16];
+
     /**
     /**
      * Constructor.
      * Constructor.
      */
      */
@@ -81,6 +85,11 @@ public:
      */
      */
     static void createScale(float x, float y, float z, float* dst);
     static void createScale(float x, float y, float z, float* dst);
 
 
+    /**
+     * Creates a rotation matrix from the given quaternion.
+     */
+    static void createRotation(const Quaternion& q, float* dst);
+
     /**
     /**
      * Creates a rotation matrix from the given axis and angle in degrees.
      * Creates a rotation matrix from the given axis and angle in degrees.
      */
      */
@@ -121,6 +130,11 @@ public:
      */
      */
     void scale(float x, float y, float z);
     void scale(float x, float y, float z);
 
 
+    /**
+     * Rotates the matrix by the given Quaternion.
+     */
+    void rotate(const Quaternion& q);
+
     /**
     /**
      * Rotates the matrix by the axies specified and angle.
      * Rotates the matrix by the axies specified and angle.
      */
      */
@@ -141,8 +155,15 @@ public:
      */
      */
     void rotateZ(float angle);
     void rotateZ(float angle);
 
 
-    float m[16];
+    /**
+     * Transforms the specified point by this matrix.
+     *
+     * Note that the input vector is treated as a point and NOT a vector.
+     */
+    void transformPoint(const Vector3& p, Vector3* dst) const;
+
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 257 - 28
gameplay-encoder/src/Mesh.cpp

@@ -1,10 +1,11 @@
+#include "Base.h"
 #include "Mesh.h"
 #include "Mesh.h"
-#include <cmath>
+#include "Model.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-Mesh::Mesh(void)
+Mesh::Mesh(void) : model(NULL)
 {
 {
 }
 }
 
 
@@ -26,8 +27,8 @@ void Mesh::writeBinary(FILE* file)
 {
 {
     Object::writeBinary(file);
     Object::writeBinary(file);
     // vertex formats
     // vertex formats
-    write(_vertexFormats.size(), file);
-    for (std::vector<VertexElement>::iterator i = _vertexFormats.begin(); i != _vertexFormats.end(); i++)
+    write(_vertexFormat.size(), file);
+    for (std::vector<VertexElement>::iterator i = _vertexFormat.begin(); i != _vertexFormat.end(); i++)
     {
     {
         i->writeBinary(file);
         i->writeBinary(file);
     }
     }
@@ -37,6 +38,218 @@ void Mesh::writeBinary(FILE* file)
     writeBinaryObjects(parts, file);
     writeBinaryObjects(parts, file);
 }
 }
 
 
+/////////////////////////////////////////////////////////////
+// 
+// Fast, Minimum Storage Ray-Triangle Intersection
+// 
+// Authors: Tomas Möller, Ben Trumbore
+// http://jgt.akpeters.com/papers/MollerTrumbore97
+//
+// Implementation of algorithm from Real-Time Rendering (vol 1), pg. 305.
+//
+// Adapted slightly for use here.
+// 
+#define EPSILON 0.000001
+#define CROSS(dest,v1,v2) \
+          dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
+          dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
+          dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
+#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
+#define SUB(dest,v1,v2) \
+          dest[0]=v1[0]-v2[0]; \
+          dest[1]=v1[1]-v2[1]; \
+          dest[2]=v1[2]-v2[2]; 
+
+int
+intersect_triangle(const float orig[3], const float dir[3],
+                   const float vert0[3], const float vert1[3], const float vert2[3],
+                   float *t, float *u, float *v)
+{
+   float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+   float det,inv_det;
+
+   /* find vectors for two edges sharing vert0 */
+   SUB(edge1, vert1, vert0);
+   SUB(edge2, vert2, vert0);
+
+   /* begin calculating determinant - also used to calculate U parameter */
+   CROSS(pvec, dir, edge2);
+
+   /* if determinant is near zero, ray lies in plane of triangle */
+   det = DOT(edge1, pvec);
+
+   if (det > -EPSILON && det < EPSILON)
+     return 0;
+   inv_det = 1.0f / det;
+
+   /* calculate distance from vert0 to ray origin */
+   SUB(tvec, orig, vert0);
+
+   /* calculate U parameter and test bounds */
+   *u = DOT(tvec, pvec) * inv_det;
+   if (*u < 0.0 || *u > 1.0)
+     return 0;
+
+   /* prepare to test V parameter */
+   CROSS(qvec, tvec, edge1);
+
+   /* calculate V parameter and test bounds */
+   *v = DOT(dir, qvec) * inv_det;
+   if (*v < 0.0 || *u + *v > 1.0)
+     return 0;
+
+   /* calculate t, ray intersects triangle */
+   *t = DOT(edge2, qvec) * inv_det;
+
+   return 1;
+}
+
+// Performs an intersection test between a ray and the given mesh part
+// and stores the result in "point".
+bool intersect(const Vector3& rayOrigin, const Vector3& rayDirection, const std::vector<Vertex>& vertices, const std::vector<MeshPart*>& parts, Vector3* point)
+{
+    const float* orig = &rayOrigin.x;
+    const float* dir = &rayDirection.x;
+
+    for (unsigned int i = 0, partCount = parts.size(); i < partCount; ++i)
+    {
+        MeshPart* part = parts[i];
+
+        for (unsigned int j = 0, indexCount = part->getIndicesCount(); j < indexCount; j += 3)
+        {
+            const float* v0 = &vertices[part->getIndex( j )].position.x;
+            const float* v1 = &vertices[part->getIndex(j+1)].position.x;
+            const float* v2 = &vertices[part->getIndex(j+2)].position.x;
+
+            float t, u, v;
+            if (intersect_triangle(orig, dir, v0, v1, v2, &t, &u, &v))
+            {
+                // Found an intersection!
+                if (point)
+                {
+                    Vector3 rd(rayDirection);
+                    rd.scale(t);
+                    Vector3::add(rayOrigin, rd, point);
+                }
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+void Mesh::generateHeightmap(const char* filename)
+{
+    // Shoot rays down from a point just above the max Y position of the mesh.
+    // Compute ray-triangle intersection tests against the ray and this mesh to 
+    // generate heightmap data.
+    Vector3 rayOrigin(0, bounds.max.y + 10, 0);
+    Vector3 rayDirection(0, -1, 0);
+    Vector3 intersectionPoint;
+    int minX = (int)ceil(bounds.min.x);
+    int maxX = (int)floor(bounds.max.x);
+    int minZ = (int)ceil(bounds.min.z);
+    int maxZ = (int)floor(bounds.max.z);
+    int width = maxX - minX + 1;
+    int height = maxZ - minZ + 1;
+    float* heights = new float[width * height];
+    int index = 0;
+    float minHeight = FLT_MAX;
+    float maxHeight = FLT_MIN;
+    for (int z = minZ; z <= maxZ; z++)
+    {
+        rayOrigin.z = (float)z;
+        for (int x = minX; x <= maxX; x++)
+        {
+            float h;
+            rayOrigin.x = (float)x;
+            if (intersect(rayOrigin, rayDirection, vertices, parts, &intersectionPoint))
+            {
+                h = intersectionPoint.y;
+            }
+            else
+            {
+                h = 0;
+                fprintf(stderr, "Warning: Heightmap triangle intersection failed for (%d, %d).\n", x, z);
+            }
+            if (h < minHeight)
+                minHeight = h;
+            if (h > maxHeight)
+                maxHeight = h;
+            heights[index++] = h;
+        }
+    }
+    
+    // Normalize the max height value
+    maxHeight = maxHeight - minHeight;
+
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+    png_bytep row = NULL;
+
+    FILE* fp = fopen(filename, "wb");
+    if (fp == NULL)
+    {
+        fprintf(stderr, "Error: Failed to open file for writing: %s\n", filename);
+        goto error;
+    }
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (png_ptr == NULL)
+    {
+        fprintf(stderr, "Error: Write struct creation failed: %s\n", filename);
+        goto error;
+    }
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+    {
+        fprintf(stderr, "Error: Info struct creation failed: %s\n", filename);
+        goto error;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_write_info(png_ptr, info_ptr);
+
+    // Allocate memory for a single row of image data
+    row = (png_bytep)malloc(3 * width * sizeof(png_byte));
+
+    for (int y = 0; y < height; y++)
+    {
+        for (int x = 0; x < width; x++)
+        {
+            // Write height value normalized between 0-255 (between min and max height)
+            float h = heights[y*width + x];
+            float nh = (h - minHeight) / maxHeight;
+            png_byte b = (png_byte)(nh * 255.0f);
+            
+            int pos = x*3;
+            row[pos] = row[pos+1] = row[pos+2] = b;
+        }
+        png_write_row(png_ptr, row);
+    }
+
+    png_write_end(png_ptr, NULL);
+    DEBUGPRINT_VARG("> Saved heightmap: %s\n", filename);
+
+error:
+    if (heights)
+        delete[] heights;
+    if (fp)
+        fclose(fp);
+    if (row)
+        free(row);
+    if (info_ptr)
+        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+    if (png_ptr)
+        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+
+}
+
 void Mesh::writeBinaryVertices(FILE* file)
 void Mesh::writeBinaryVertices(FILE* file)
 {
 {
     if (vertices.size() > 0)
     if (vertices.size() > 0)
@@ -47,7 +260,7 @@ void Mesh::writeBinaryVertices(FILE* file)
         write(vertices.size() * vertex.byteSize(), file); // (vertex count) * (vertex size)
         write(vertices.size() * vertex.byteSize(), file); // (vertex count) * (vertex size)
 
 
         // for each vertex
         // for each vertex
-        for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); i++)
+        for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
         {
         {
             // Write this vertex
             // Write this vertex
             i->writeBinary(file);
             i->writeBinary(file);
@@ -74,15 +287,15 @@ void Mesh::writeText(FILE* file)
     // for each VertexFormat
     // for each VertexFormat
     if (vertices.size() > 0 )
     if (vertices.size() > 0 )
     {
     {
-        for (std::vector<VertexElement>::iterator i = _vertexFormats.begin(); i != _vertexFormats.end(); i++)
+        for (std::vector<VertexElement>::iterator i = _vertexFormat.begin(); i != _vertexFormat.end(); i++)
         {
         {
             i->writeText(file);
             i->writeText(file);
         }
         }
     }
     }
 
 
     // for each Vertex
     // for each Vertex
-    fprintf(file, "<vertices count=\"%u\">\n", vertices.size());
-    for (std::vector<Vertex>::iterator i = vertices.begin(); i != vertices.end(); i++)
+    fprintf(file, "<vertices count=\"%lu\">\n", vertices.size());
+    for (std::vector<Vertex>::iterator i = vertices.begin(); i != vertices.end(); ++i)
     {
     {
         i->writeText(file);
         i->writeText(file);
     }
     }
@@ -92,19 +305,19 @@ void Mesh::writeText(FILE* file)
     computeBounds();
     computeBounds();
     fprintf(file, "<bounds>\n");
     fprintf(file, "<bounds>\n");
     fprintf(file, "<min>\n");
     fprintf(file, "<min>\n");
-    bounds.min.writeText(file);
+    writeVectorText(bounds.min, file);
     fprintf(file, "</min>\n");
     fprintf(file, "</min>\n");
     fprintf(file, "<max>\n");
     fprintf(file, "<max>\n");
-    bounds.max.writeText(file);
+    writeVectorText(bounds.max, file);
     fprintf(file, "</max>\n");
     fprintf(file, "</max>\n");
     fprintf(file, "<center>\n");
     fprintf(file, "<center>\n");
-    bounds.center.writeText(file);
+    writeVectorText(bounds.center, file);
     fprintf(file, "</center>\n");
     fprintf(file, "</center>\n");
     fprintf(file, "<radius>%f</radius>\n", bounds.radius);
     fprintf(file, "<radius>%f</radius>\n", bounds.radius);
     fprintf(file, "</bounds>\n");
     fprintf(file, "</bounds>\n");
 
 
     // for each MeshPart
     // for each MeshPart
-    for (std::vector<MeshPart*>::iterator i = parts.begin(); i != parts.end(); i++)
+    for (std::vector<MeshPart*>::iterator i = parts.begin(); i != parts.end(); ++i)
     {
     {
         (*i)->writeText(file);
         (*i)->writeText(file);
     }
     }
@@ -124,7 +337,7 @@ void Mesh::addMeshPart(Vertex* vertex)
 
 
 void Mesh::addVetexAttribute(unsigned int usage, unsigned int count)
 void Mesh::addVetexAttribute(unsigned int usage, unsigned int count)
 {
 {
-    _vertexFormats.push_back(VertexElement(usage, count));
+    _vertexFormat.push_back(VertexElement(usage, count));
 }
 }
 
 
 size_t Mesh::getVertexCount() const
 size_t Mesh::getVertexCount() const
@@ -132,6 +345,21 @@ size_t Mesh::getVertexCount() const
     return vertices.size();
     return vertices.size();
 }
 }
 
 
+const Vertex& Mesh::getVertex(unsigned int index) const
+{
+    return vertices[index];
+}
+
+size_t Mesh::getVertexElementCount() const
+{
+    return _vertexFormat.size();
+}
+
+const VertexElement& Mesh::getVertexElement(unsigned int index) const
+{
+    return _vertexFormat[index];
+}
+
 bool Mesh::contains(const Vertex& vertex) const
 bool Mesh::contains(const Vertex& vertex) const
 {
 {
     return vertexLookupTable.count(vertex) > 0;
     return vertexLookupTable.count(vertex) > 0;
@@ -149,20 +377,26 @@ unsigned int Mesh::getVertexIndex(const Vertex& vertex)
 {
 {
     std::map<Vertex,unsigned int>::iterator it;
     std::map<Vertex,unsigned int>::iterator it;
     it = vertexLookupTable.find(vertex);
     it = vertexLookupTable.find(vertex);
-    // TODO: Remove it from the map because we are going to delete it
     return it->second;
     return it->second;
 }
 }
 
 
 void Mesh::computeBounds()
 void Mesh::computeBounds()
 {
 {
+    // If we have a Model with a MeshSkin associated with it,
+    // compute the bounds from the skin - otherwise compute
+    // it from the local mesh data.
+    if (model && model->getSkin())
+    {
+        model->getSkin()->computeBounds();
+        return;
+    }
+
     bounds.min.x = bounds.min.y = bounds.min.z = FLT_MAX;
     bounds.min.x = bounds.min.y = bounds.min.z = FLT_MAX;
     bounds.max.x = bounds.max.y = bounds.max.z = FLT_MIN;
     bounds.max.x = bounds.max.y = bounds.max.z = FLT_MIN;
     bounds.center.x = bounds.center.y = bounds.center.z = 0.0f;
     bounds.center.x = bounds.center.y = bounds.center.z = 0.0f;
     bounds.radius = 0.0f;
     bounds.radius = 0.0f;
-    
-    // for each vertex
-    Vector3 avgPos;
-    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); i++)
+
+    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
     {
     {
         // Update min/max for this vertex
         // Update min/max for this vertex
         if (i->position.x < bounds.min.x)
         if (i->position.x < bounds.min.x)
@@ -177,22 +411,17 @@ void Mesh::computeBounds()
             bounds.max.y = i->position.y;
             bounds.max.y = i->position.y;
         if (i->position.z > bounds.max.z)
         if (i->position.z > bounds.max.z)
             bounds.max.z = i->position.z;
             bounds.max.z = i->position.z;
-
-        avgPos.x += i->position.x;
-        avgPos.y += i->position.y;
-        avgPos.z += i->position.z;
     }
     }
 
 
     // Compute center point
     // Compute center point
-    bounds.center.x = avgPos.x / (float)vertices.size();
-    bounds.center.y = avgPos.y / (float)vertices.size();
-    bounds.center.z = avgPos.z / (float)vertices.size();
+    Vector3::add(bounds.min, bounds.max, &bounds.center);
+    bounds.center.scale(0.5f);
 
 
     // Compute radius by looping through all points again and finding the max
     // Compute radius by looping through all points again and finding the max
     // distance between the center point and each vertex position
     // distance between the center point and each vertex position
-    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); i++)
+    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
     {
     {
-        float d = Vector3::distanceSquared(bounds.center, i->position);
+        float d = bounds.center.distanceSquared(i->position);
         if (d > bounds.radius)
         if (d > bounds.radius)
         {
         {
             bounds.radius = d;
             bounds.radius = d;
@@ -200,7 +429,7 @@ void Mesh::computeBounds()
     }
     }
 
 
     // Convert squared distance to distance for radius
     // Convert squared distance to distance for radius
-    bounds.radius = std::sqrtf(bounds.radius);
+    bounds.radius = sqrt(bounds.radius);
 }
 }
 
 
 }
 }

+ 19 - 8
gameplay-encoder/src/Mesh.h

@@ -1,15 +1,21 @@
 #ifndef MESH_H_
 #ifndef MESH_H_
 #define MESH_H_
 #define MESH_H_
 
 
+#include "Base.h"
 #include "Object.h"
 #include "Object.h"
 #include "MeshPart.h"
 #include "MeshPart.h"
 #include "VertexElement.h"
 #include "VertexElement.h"
+#include "BoundingVolume.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+class Model;
+
 class Mesh : public Object
 class Mesh : public Object
 {
 {
+    friend class Model;
+
 public:
 public:
 
 
     /**
     /**
@@ -37,6 +43,10 @@ public:
     void addVetexAttribute(unsigned int usage, unsigned int count);
     void addVetexAttribute(unsigned int usage, unsigned int count);
 
 
     size_t getVertexCount() const;
     size_t getVertexCount() const;
+    const Vertex& getVertex(unsigned int index) const;
+
+    size_t getVertexElementCount() const;
+    const VertexElement& getVertexElement(unsigned int index) const;
 
 
     /**
     /**
      * Returns true if this MeshPart contains the given Vertex.
      * Returns true if this MeshPart contains the given Vertex.
@@ -50,15 +60,15 @@ public:
 
 
     unsigned int getVertexIndex(const Vertex& vertex);
     unsigned int getVertexIndex(const Vertex& vertex);
 
 
+    /**
+     * Generates a heightmap with the given filename for this mesh.
+     */
+    void generateHeightmap(const char* filename);
+
+    Model* model;
     std::vector<Vertex> vertices;
     std::vector<Vertex> vertices;
     std::vector<MeshPart*> parts;
     std::vector<MeshPart*> parts;
-    struct
-    {
-        Vector3 min;
-        Vector3 max;
-        Vector3 center;
-        float radius;
-    } bounds;
+    BoundingVolume bounds;
     std::map<Vertex, unsigned int> vertexLookupTable;
     std::map<Vertex, unsigned int> vertexLookupTable;
 
 
 private:
 private:
@@ -66,9 +76,10 @@ private:
     void computeBounds();
     void computeBounds();
 
 
 private:
 private:
-    std::vector<VertexElement> _vertexFormats;
+    std::vector<VertexElement> _vertexFormat;
 
 
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 21 - 14
gameplay-encoder/src/MeshPart.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "MeshPart.h"
 #include "MeshPart.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -5,7 +6,7 @@ namespace gameplay
 
 
 MeshPart::MeshPart(void) :
 MeshPart::MeshPart(void) :
     _primitiveType(TRIANGLES),
     _primitiveType(TRIANGLES),
-    _indexFormat(INDEX8)
+    _indexFormat(INDEX16)
 {
 {
 }
 }
 
 
@@ -17,30 +18,33 @@ unsigned int MeshPart::getTypeId(void) const
 {
 {
     return MESHPART_ID;
     return MESHPART_ID;
 }
 }
+
 const char* MeshPart::getElementName(void) const
 const char* MeshPart::getElementName(void) const
 {
 {
     return "MeshPart";
     return "MeshPart";
 }
 }
+
 void MeshPart::writeBinary(FILE* file)
 void MeshPart::writeBinary(FILE* file)
 {
 {
     Object::writeBinary(file);
     Object::writeBinary(file);
 
 
     write(_primitiveType, file);
     write(_primitiveType, file);
-    write(_indexFormat, file);
+    write((unsigned int)_indexFormat, file);
 
 
     // write the number of bytes
     // write the number of bytes
     write(indicesByteSize(), file);
     write(indicesByteSize(), file);
     // for each index
     // for each index
-    for (std::vector<unsigned int>::const_iterator i = _indices.begin(); i != _indices.end(); i++)
+    for (std::vector<unsigned int>::const_iterator i = _indices.begin(); i != _indices.end(); ++i)
     {
     {
         writeBinaryIndex(*i, file);
         writeBinaryIndex(*i, file);
     }
     }
 }
 }
+
 void MeshPart::writeText(FILE* file)
 void MeshPart::writeText(FILE* file)
 {
 {
     fprintElementStart(file);
     fprintElementStart(file);
     fprintfElement(file, "primitiveType", _primitiveType);
     fprintfElement(file, "primitiveType", _primitiveType);
-    fprintfElement(file, "indexFormat", _indexFormat);
+    fprintfElement(file, "indexFormat", (unsigned int)_indexFormat);
     fprintfElement(file, "%d ", "indices", _indices);
     fprintfElement(file, "%d ", "indices", _indices);
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
@@ -67,14 +71,21 @@ unsigned int MeshPart::indexFormatSize() const
     {
     {
     case INDEX32:
     case INDEX32:
         return 4;
         return 4;
-    case INDEX16:
+    default: // INDEX16
         return 2;
         return 2;
-    case INDEX8:
-    default:
-        return 1;
     }
     }
 }
 }
 
 
+MeshPart::IndexFormat MeshPart::getIndexFormat() const
+{
+    return _indexFormat;
+}
+
+unsigned int MeshPart::getIndex(unsigned int i) const
+{
+    return _indices[i];
+}
+
 void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
 void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
 {
 {
     switch (_indexFormat)
     switch (_indexFormat)
@@ -82,13 +93,9 @@ void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
     case INDEX32:
     case INDEX32:
         write(index, file);
         write(index, file);
         break;
         break;
-    case INDEX16:
+    default: // INDEX16
         write((unsigned short)index, file);
         write((unsigned short)index, file);
         break;
         break;
-    case INDEX8:
-    default:
-        write((unsigned char)index, file);
-        break;
     }
     }
 }
 }
 
 
@@ -104,4 +111,4 @@ void MeshPart::updateIndexFormat(unsigned int newIndex)
     }
     }
 }
 }
 
 
-}
+}

+ 13 - 8
gameplay-encoder/src/MeshPart.h

@@ -1,8 +1,6 @@
 #ifndef MESHPART_H_
 #ifndef MESHPART_H_
 #define MESHPART_H_
 #define MESHPART_H_
 
 
-#include <vector>
-
 #include "Base.h"
 #include "Base.h"
 #include "Object.h"
 #include "Object.h"
 #include "Vertex.h"
 #include "Vertex.h"
@@ -25,12 +23,10 @@ public:
 
 
     enum IndexFormat
     enum IndexFormat
     {
     {
-        INDEX8  = 0x1401, // GL_UNSIGNED_BYTE
         INDEX16 = 0x1403, // GL_UNSIGNED_SHORT
         INDEX16 = 0x1403, // GL_UNSIGNED_SHORT
         INDEX32 = 0x1405  // GL_UNSIGNED_INT
         INDEX32 = 0x1405  // GL_UNSIGNED_INT
     };
     };
 
 
-
     /**
     /**
      * Constructor.
      * Constructor.
      */
      */
@@ -56,6 +52,16 @@ public:
      */
      */
     size_t getIndicesCount() const;
     size_t getIndicesCount() const;
 
 
+    /**
+     * Returns the index format.
+     */
+    IndexFormat getIndexFormat() const;
+
+    /**
+     * Gets the value of the index at the specificied location.
+     */
+    unsigned int getIndex(unsigned int i) const;
+
 private:
 private:
 
 
     /**
     /**
@@ -80,13 +86,12 @@ private:
     void writeBinaryIndex(unsigned int index, FILE* file);
     void writeBinaryIndex(unsigned int index, FILE* file);
 
 
 private:
 private:
+
     unsigned int _primitiveType;
     unsigned int _primitiveType;
-    unsigned int _indexFormat;
+    IndexFormat _indexFormat;
     std::vector<unsigned int> _indices;
     std::vector<unsigned int> _indices;
 };
 };
 
 
-
-
 }
 }
-#endif
 
 
+#endif

+ 346 - 19
gameplay-encoder/src/MeshSkin.cpp

@@ -1,6 +1,13 @@
+#include "Base.h"
 #include "MeshSkin.h"
 #include "MeshSkin.h"
 #include "Node.h"
 #include "Node.h"
 #include "StringUtil.h"
 #include "StringUtil.h"
+#include "Mesh.h"
+#include "GPBFile.h"
+#include "Animations.h"
+#include "Transform.h"
+#include "../../gameplay/src/Curve.h"
+#include "Matrix.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -8,7 +15,7 @@ namespace gameplay
 MeshSkin::MeshSkin(void) :
 MeshSkin::MeshSkin(void) :
     _vertexInfluenceCount(0)
     _vertexInfluenceCount(0)
 {
 {
-    setIdentityMatrix(_bindShape);
+    Matrix::setIdentity(_bindShape);
 }
 }
 
 
 MeshSkin::~MeshSkin(void)
 MeshSkin::~MeshSkin(void)
@@ -30,11 +37,28 @@ void MeshSkin::writeBinary(FILE* file)
     Object::writeBinary(file);
     Object::writeBinary(file);
     write(_bindShape, 16, file);
     write(_bindShape, 16, file);
     write(_joints.size(), file);
     write(_joints.size(), file);
-    for (std::list<Node*>::const_iterator i = _joints.begin(); i != _joints.end(); i++)
+    for (std::vector<Node*>::const_iterator i = _joints.begin(); i != _joints.end(); i++)
     {
     {
         (*i)->writeBinaryXref(file);
         (*i)->writeBinaryXref(file);
     }
     }
-    write(_bindPoses, file);
+    write(_bindPoses.size() * 16, file);
+    for (std::vector<Matrix>::const_iterator i = _bindPoses.begin(); i != _bindPoses.end(); i++)
+    {
+        write(i->m, 16, file);
+    }
+
+    /*
+    // Write joint bounding spheres
+    write((unsigned int)_jointBounds.size(), file);
+    for (unsigned int i = 0; i < _jointBounds.size(); ++i)
+    {
+        BoundingVolume& v = _jointBounds[i];
+        write(v.center.x, file);
+        write(v.center.y, file);
+        write(v.center.z, file);
+        write(v.radius, file);
+    }
+    */
 }
 }
 
 
 void MeshSkin::writeText(FILE* file)
 void MeshSkin::writeText(FILE* file)
@@ -44,23 +68,27 @@ void MeshSkin::writeText(FILE* file)
     fprintfMatrix4f(file, _bindShape);
     fprintfMatrix4f(file, _bindShape);
     fprintf(file, "</bindShape>");
     fprintf(file, "</bindShape>");
     fprintf(file, "<joints>");
     fprintf(file, "<joints>");
-    for (std::list<std::string>::const_iterator i = _jointNames.begin(); i != _jointNames.end(); i++)
+    for (std::vector<std::string>::const_iterator i = _jointNames.begin(); i != _jointNames.end(); i++)
     {
     {
         fprintf(file, "%s ", i->c_str());
         fprintf(file, "%s ", i->c_str());
     }
     }
     fprintf(file, "</joints>\n");
     fprintf(file, "</joints>\n");
-    fprintf(file, "<bindPoses count=\"%u\">", _bindPoses.size());
-    for (std::list<float>::const_iterator i = _bindPoses.begin(); i != _bindPoses.end(); i++)
+    fprintf(file, "<bindPoses count=\"%lu\">", _bindPoses.size() * 16);
+    for (std::vector<Matrix>::const_iterator i = _bindPoses.begin(); i != _bindPoses.end(); i++)
     {
     {
-        fprintf(file, "%f ", *i);
+        for (unsigned int j = 0; j < 16; ++j)
+        {
+            fprintf(file, "%f ", i->m[j]);
+        }
     }
     }
     fprintf(file, "</bindPoses>\n");
     fprintf(file, "</bindPoses>\n");
+
     fprintElementEnd(file);
     fprintElementEnd(file);
 }
 }
 
 
 void MeshSkin::setBindShape(const float data[])
 void MeshSkin::setBindShape(const float data[])
 {
 {
-    for (int i = 0; i < 16; i++)
+    for (int i = 0; i < 16; ++i)
     {
     {
         _bindShape[i] = data[i];
         _bindShape[i] = data[i];
     }
     }
@@ -71,36 +99,32 @@ void MeshSkin::setVertexInfluenceCount(unsigned int count)
     _vertexInfluenceCount = count;
     _vertexInfluenceCount = count;
 }
 }
 
 
-void MeshSkin::setJointNames(const std::list<std::string>& list)
+void MeshSkin::setJointNames(const std::vector<std::string>& list)
 {
 {
     _jointNames = list;
     _jointNames = list;
 }
 }
 
 
-const std::list<std::string>& MeshSkin::getJointNames()
+const std::vector<std::string>& MeshSkin::getJointNames()
 {
 {
     return _jointNames;
     return _jointNames;
 }
 }
 
 
-void MeshSkin::setJoints(const std::list<Node*>& list)
+void MeshSkin::setJoints(const std::vector<Node*>& list)
 {
 {
     _joints = list;
     _joints = list;
 }
 }
 
 
 void MeshSkin::setBindPoses(std::vector<Matrix>& list)
 void MeshSkin::setBindPoses(std::vector<Matrix>& list)
 {
 {
-    for (std::vector<Matrix>::iterator i = list.begin(); i != list.end(); i++)
+    for (std::vector<Matrix>::iterator i = list.begin(); i != list.end(); ++i)
     {
     {
-        float* a = i->m;
-        for (int j = 0; j < 16; j++)
-        {
-            _bindPoses.push_back(a[j]);
-        }
+        _bindPoses.push_back(*i);
     }
     }
 }
 }
 
 
 bool MeshSkin::hasJoint(const char* id)
 bool MeshSkin::hasJoint(const char* id)
 {
 {
-    for (std::list<std::string>::iterator i = _jointNames.begin(); i != _jointNames.end(); i++)
+    for (std::vector<std::string>::iterator i = _jointNames.begin(); i != _jointNames.end(); i++)
     {
     {
         if (equals(*i, id))
         if (equals(*i, id))
         {
         {
@@ -110,4 +134,307 @@ bool MeshSkin::hasJoint(const char* id)
     return false;
     return false;
 }
 }
 
 
-}
+void MeshSkin::computeBounds()
+{
+    // Find the offset of the blend indices and blend weights within the mesh vertices
+    int blendIndexOffset = -1;
+    int blendWeightOffset = -1;
+    for (unsigned int i = 0, count = _mesh->getVertexElementCount(); i < count; ++i)
+    {
+        const VertexElement& e = _mesh->getVertexElement(i);
+        switch (e.usage)
+        {
+        case BLENDINDICES:
+            blendIndexOffset = i;
+            break;
+        case BLENDWEIGHTS:
+            blendWeightOffset = i;
+            break;
+        }
+    }
+    if (blendIndexOffset == -1 || blendWeightOffset == -1)
+    {
+        // Need blend indices and blend weights to calculate skinned bounding volume
+        return;
+    }
+
+    DEBUGPRINT_VARG("\nComputing bounds for skin of mesh: %s\n", _mesh->getId().c_str());
+
+    Node* joint;
+
+    // Get the root joint
+    Node* rootJoint = _joints[0];
+    Node* parent = rootJoint->getParent();
+    while (parent)
+    {
+        // Is this parent in the list of joints that form the skeleton?
+        // If not, then it's simply a parent node to the root joint
+        if (find(_joints.begin(), _joints.end(), parent) != _joints.end())
+        {
+            rootJoint = parent;
+        }
+        parent = parent->getParent();
+    }
+
+    // If the root joint has a parent node, temporarily detach it so that its transform is
+    // not included in the bounding volume calculation below
+    Node* rootJointParent = rootJoint->getParent();
+    if (rootJointParent)
+    {
+        rootJointParent->removeChild(rootJoint);
+    }
+
+    unsigned int jointCount = _joints.size();
+    unsigned int vertexCount = _mesh->getVertexCount();
+
+    DEBUGPRINT_VARG("> %d joints found.\n", jointCount);
+
+    std::vector<AnimationChannel*> channels;
+    std::vector<Node*> channelTargets;
+    std::vector<Curve*> curves;
+    std::vector<Vector3> vertices;
+    _jointBounds.resize(jointCount);
+
+    // Construct a list of all animation channels that target the joints affecting this mesh skin
+    DEBUGPRINT("> Collecting animations...\n");
+    DEBUGPRINT("> 0%%\r");
+    for (unsigned int i = 0; i < jointCount; ++i)
+    {
+        joint = _joints[i];
+
+        // Find all animations that target this joint
+        Animations* animations = GPBFile::getInstance()->getAnimations();
+        for (unsigned int j = 0, animationCount = animations->getAnimationCount(); j < animationCount; ++j)
+        {
+            Animation* animation = animations->getAnimation(j);
+            for (unsigned int k = 0, channelCount = animation->getAnimationChannelCount(); k < channelCount; ++k)
+            {
+                AnimationChannel* channel = animation->getAnimationChannel(k);
+                if (channel->getTargetId() == joint->getId())
+                {
+                    if (find(channels.begin(), channels.end(), channel) == channels.end())
+                    {
+                        channels.push_back(channel);
+                        channelTargets.push_back(joint);
+                    }
+                }
+            }
+        }
+
+        // Calculate the local bounding volume for this joint
+        vertices.clear();
+        BoundingVolume jointBounds;
+        jointBounds.min.set(FLT_MAX, FLT_MAX, FLT_MAX);
+        jointBounds.max.set(FLT_MIN, FLT_MIN, FLT_MIN);
+        for (unsigned int j = 0; j < vertexCount; ++j)
+        {
+            const Vertex& v = _mesh->getVertex(j);
+
+            if ((v.blendIndices.x == i && !ISZERO(v.blendWeights.x)) ||
+                (v.blendIndices.y == i && !ISZERO(v.blendWeights.y)) ||
+                (v.blendIndices.z == i && !ISZERO(v.blendWeights.z)) ||
+                (v.blendIndices.w == i && !ISZERO(v.blendWeights.w)))
+            {
+                vertices.push_back(v.position);
+                // Update box min/max
+                if (v.position.x < jointBounds.min.x)
+                    jointBounds.min.x = v.position.x;
+                if (v.position.y < jointBounds.min.y)
+                    jointBounds.min.y = v.position.y;
+                if (v.position.z < jointBounds.min.z)
+                    jointBounds.min.z = v.position.z;
+                if (v.position.x > jointBounds.max.x)
+                    jointBounds.max.x = v.position.x;
+                if (v.position.y > jointBounds.max.y)
+                    jointBounds.max.y = v.position.y;
+                if (v.position.z > jointBounds.max.z)
+                    jointBounds.max.z = v.position.z;
+            }
+        }
+        if (vertices.size() > 0)
+        {
+            // Compute center point
+            Vector3::add(jointBounds.min, jointBounds.max, &jointBounds.center);
+            jointBounds.center.scale(0.5f);
+            // Compute radius
+            for (unsigned int j = 0, jointVertexCount = vertices.size(); j < jointVertexCount; ++j)
+            {
+                float d = jointBounds.center.distanceSquared(vertices[j]);
+                if (d > jointBounds.radius)
+                    jointBounds.radius = d;
+            }
+            jointBounds.radius = sqrt(jointBounds.radius);
+        }
+        _jointBounds[i] = jointBounds;
+
+        DEBUGPRINT_VARG("> %d%%\r", (int)((float)(i+1) / (float)jointCount * 100.0f));
+    }
+    DEBUGPRINT("\n");
+
+    unsigned int channelCount = channels.size();
+
+    // Create a Curve for each animation channel
+    float maxDuration = 0.0f;
+    DEBUGPRINT("> Building animation curves...\n");
+    DEBUGPRINT("> 0%%\r");
+    for (unsigned int i = 0; i < channelCount; ++i)
+    {
+        AnimationChannel* channel = channels[i];
+
+        const std::vector<float>& keyTimes = channel->getKeyTimes();
+        unsigned int keyCount = keyTimes.size();
+        if (keyCount == 0)
+            continue;
+
+        // Create a curve for this animation channel
+        Curve* curve = NULL;
+        switch (channel->getTargetAttribute())
+        {
+        case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
+            curve = new Curve(keyCount, 10);
+            curve->setQuaternionOffset(3);
+            break;
+        }
+        if (curve == NULL)
+        {
+            // Unsupported/not implemented curve type 
+            continue;
+        }
+
+        // Copy key values into a temporary array
+        unsigned int keyValuesCount = channel->getKeyValues().size();
+        float* keyValues = new float[keyValuesCount];
+        for (unsigned int j = 0; j < keyValuesCount; ++j)
+            keyValues[j] = channel->getKeyValues()[j];
+
+        // Determine animation duration
+        float startTime = keyTimes[0];
+        float duration = keyTimes[keyCount-1] - startTime;
+        if (duration > maxDuration)
+            maxDuration = duration;
+
+        // Set curve points
+        float* keyValuesPtr = keyValues;
+        for (unsigned int j = 0; j < keyCount; ++j)
+        {
+            // Store time normalized, between 0-1
+            float t = (keyTimes[j] - startTime) / duration;
+
+            // Set the curve point
+            // TODO: Handle other interpolation types
+            curve->setPoint(j, t, keyValuesPtr, gameplay::Curve::LINEAR);
+
+            // Move to the next point on the curve
+            keyValuesPtr += curve->getComponentCount();
+        }
+
+        delete[] keyValues;
+        keyValues = NULL;
+
+        curves.push_back(curve);
+
+        DEBUGPRINT_VARG("> %d%%\r", (int)((float)(i+1) / (float)channelCount * 100.0f));
+    }
+    DEBUGPRINT("\n");
+
+    // Compute a total combined bounding volume for the MeshSkin that contains all possible
+    // vertex positions for all animations targetting the skin. This rough approximation allows
+    // us to store a volume that can be used for rough intersection tests (such as for visibility
+    // determination) efficiently at runtime.
+
+    // Backup existing node transforms so we can restore them when we are finished
+    Matrix* oldTransforms = new Matrix[jointCount];
+    for (unsigned int i = 0; i < jointCount; ++i)
+    {
+        memcpy(oldTransforms[i].m, _joints[i]->getTransformMatrix().m, 16 * sizeof(float));
+    }
+
+    float time = 0.0f;
+    float srt[10];
+    Matrix temp;
+    Matrix* jointTransforms = new Matrix[jointCount];
+    _mesh->bounds.min.set(FLT_MAX, FLT_MAX, FLT_MAX);
+    _mesh->bounds.max.set(FLT_MIN, FLT_MIN, FLT_MIN);
+    _mesh->bounds.center.set(0, 0, 0);
+    _mesh->bounds.radius = 0;
+    Vector3 skinnedPos;
+    Vector3 tempPos;
+    DEBUGPRINT("> Evaluating joints...\n");
+    DEBUGPRINT("> 0%%\r");
+    BoundingVolume finalBounds;
+    while (time <= maxDuration)
+    {
+        // Evaluate joint transforms at this time interval
+        for (unsigned int i = 0, curveCount = curves.size(); i < curveCount; ++i)
+        {
+            Node* joint = channelTargets[i];
+            Curve* curve = curves[i];
+
+            // Evalulate the curve at this time to get the new value
+            float tn = time / maxDuration;
+            if (tn > 1.0f)
+                tn = 1.0f;
+            curve->evaluate(tn, srt);
+
+            // Update the joint's local transform
+            Matrix::createTranslation(srt[7], srt[8], srt[9], temp.m);
+            temp.rotate(*((Quaternion*)&srt[3]));
+            temp.scale(srt[0], srt[1], srt[2]);
+            joint->setTransformMatrix(temp.m);
+        }
+
+        // Store the final matrix pallette of resovled world space joint matrices
+        std::vector<Matrix>::const_iterator bindPoseItr = _bindPoses.begin();
+        for (unsigned int i = 0; i < jointCount; ++i, bindPoseItr++)
+        {
+            BoundingVolume bounds = _jointBounds[i];
+            if (ISZERO(bounds.radius))
+                continue;
+
+            Matrix& m = jointTransforms[i];
+            Matrix::multiply(_joints[i]->getWorldMatrix().m, bindPoseItr->m, m.m);
+            Matrix::multiply(m.m, _bindShape, m.m);
+
+            // Get a world-space bounding volume for this joint
+            bounds.transform(m);
+            if (ISZERO(finalBounds.radius))
+                finalBounds = bounds;
+            else
+                finalBounds.merge(bounds);
+        }
+
+        // Increment time by 1/30th of second (~ 33 ms)
+        if (time < maxDuration && (time + 33.0f) > maxDuration)
+            time = maxDuration;
+        else
+            time += 33.0f;
+
+        DEBUGPRINT_VARG("> %d%%\r", (int)(time / maxDuration * 100.0f));
+    }
+    DEBUGPRINT("\n");
+
+    // Update the bounding sphere for the mesh
+    _mesh->bounds = finalBounds;
+
+    // Restore original joint transforms
+    for (unsigned int i = 0; i < jointCount; ++i)
+    {
+        _joints[i]->setTransformMatrix(oldTransforms[i].m);
+    }
+
+    // Cleanup
+    for (unsigned int i = 0, curveCount = curves.size(); i < curveCount; ++i)
+    {
+        delete curves[i];
+    }
+    delete[] oldTransforms;
+    delete[] jointTransforms;
+
+    // Restore removed joints
+    if (rootJointParent)
+    {
+        rootJointParent->addChild(rootJoint);
+    }
+}
+
+}

+ 15 - 10
gameplay-encoder/src/MeshSkin.h

@@ -1,20 +1,22 @@
 #ifndef MESHSKIN_H_
 #ifndef MESHSKIN_H_
 #define MESHSKIN_H_
 #define MESHSKIN_H_
 
 
-#include <vector>
-
 #include "Base.h"
 #include "Base.h"
 #include "Object.h"
 #include "Object.h"
 #include "Matrix.h"
 #include "Matrix.h"
 #include "Animation.h"
 #include "Animation.h"
+#include "BoundingVolume.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 class Node;
 class Node;
+class Mesh;
 
 
 class MeshSkin : public Object
 class MeshSkin : public Object
 {
 {
+    friend class Model;
+
 public:
 public:
 
 
     /**
     /**
@@ -36,11 +38,11 @@ public:
 
 
     void setVertexInfluenceCount(unsigned int count);
     void setVertexInfluenceCount(unsigned int count);
 
 
-    void setJointNames(const std::list<std::string>& list);
+    void setJointNames(const std::vector<std::string>& list);
 
 
-    const std::list<std::string>& getJointNames();
+    const std::vector<std::string>& getJointNames();
 
 
-    void setJoints(const std::list<Node*>& list);
+    void setJoints(const std::vector<Node*>& list);
 
 
     void setBindPoses(std::vector<Matrix>& list);
     void setBindPoses(std::vector<Matrix>& list);
 
 
@@ -53,16 +55,19 @@ public:
      */
      */
     bool hasJoint(const char* id);
     bool hasJoint(const char* id);
 
 
+    void computeBounds();
+
 private:
 private:
 
 
+    Mesh* _mesh;
     float _bindShape[16];
     float _bindShape[16];
-    std::list<Node*> _joints;
-    std::list<float> _bindPoses;
-
-    std::list<std::string> _jointNames;
-
+    std::vector<Node*> _joints;
+    std::vector<Matrix> _bindPoses;
+    std::vector<std::string> _jointNames;
     unsigned int _vertexInfluenceCount;
     unsigned int _vertexInfluenceCount;
+    std::vector<BoundingVolume> _jointBounds;
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 2 - 1
gameplay-encoder/src/MeshSubSet.cpp

@@ -13,10 +13,11 @@ MeshSubSet::~MeshSubSet(void)
 {
 {
 }
 }
 
 
-byte MeshSubSet::getTypeId(void)
+unsigned int MeshSubSet::getTypeId(void)
 {
 {
     return MESHPART_ID;
     return MESHPART_ID;
 }
 }
+    
 const char* MeshSubSet::getElementName(void)
 const char* MeshSubSet::getElementName(void)
 {
 {
     return "MeshSubSet";
     return "MeshSubSet";

+ 10 - 7
gameplay-encoder/src/MeshSubSet.h

@@ -1,19 +1,20 @@
-#ifndef MESHSUBSET_H_

+#ifndef MESHSUBSET_H_
 #define MESHSUBSET_H_
 #define MESHSUBSET_H_
 
 
-#include <vector>
-
-#include "Common.h"
+#include "Base.h"
 #include "Object.h"
 #include "Object.h"
 #include "Vertex.h"
 #include "Vertex.h"
 
 
+namespace gameplay 
+{
+
 class MeshSubSet : public Object
 class MeshSubSet : public Object
 {
 {
 public:
 public:
     MeshSubSet(void);
     MeshSubSet(void);
     virtual ~MeshSubSet(void);
     virtual ~MeshSubSet(void);
 
 
-    virtual byte getTypeId(void);
+    virtual unsigned int getTypeId(void);
     virtual const char* getElementName(void);
     virtual const char* getElementName(void);
     virtual void writeBinary(FILE* file);
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
     virtual void writeText(FILE* file);
@@ -24,5 +25,7 @@ public:
     std::map<Vertex, int> vertexLookupTable;
     std::map<Vertex, int> vertexLookupTable;
 };
 };
 
 
-

-#endif

+}
+
+#endif
+

+ 31 - 7
gameplay-encoder/src/Model.cpp

@@ -1,10 +1,11 @@
+#include "Base.h"
 #include "Model.h"
 #include "Model.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 Model::Model(void) :
 Model::Model(void) :
-    _ref(NULL),
+    _mesh(NULL),
     _meshSkin(NULL)
     _meshSkin(NULL)
 {
 {
 }
 }
@@ -26,9 +27,9 @@ void Model::writeBinary(FILE* file)
     Object::writeBinary(file);
     Object::writeBinary(file);
 
 
     // xref:Mesh
     // xref:Mesh
-    if (_ref != NULL)
+    if (_mesh != NULL)
     {
     {
-        _ref->writeBinaryXref(file);
+        _mesh->writeBinaryXref(file);
     }
     }
     else
     else
     {
     {
@@ -49,12 +50,15 @@ void Model::writeBinary(FILE* file)
     writeBinaryObjects(_materials, file);
     writeBinaryObjects(_materials, file);
 
 
 }
 }
+
 void Model::writeText(FILE* file)
 void Model::writeText(FILE* file)
 {
 {
+    // Compute mesh bounds before writing
+
     fprintElementStart(file);
     fprintElementStart(file);
-    if (_ref != NULL)
+    if (_mesh != NULL)
     {
     {
-        fprintfElement(file, "ref", _ref->getId());
+        fprintfElement(file, "ref", _mesh->getId());
     }
     }
     if (_meshSkin != NULL)
     if (_meshSkin != NULL)
     {
     {
@@ -68,14 +72,34 @@ MeshSkin* Model::getSkin()
     return _meshSkin;
     return _meshSkin;
 }
 }
 
 
+Mesh* Model::getMesh()
+{
+    return _mesh;
+}
+
 void Model::setMesh(Mesh* mesh)
 void Model::setMesh(Mesh* mesh)
 {
 {
-    _ref = mesh;
+    _mesh = mesh;
+
+    if (mesh)
+    {
+        mesh->model = this;
+    }
+
+    if (_mesh && _meshSkin)
+    {
+        _meshSkin->_mesh = _mesh;
+    }
 }
 }
 
 
 void Model::setSkin(MeshSkin* skin)
 void Model::setSkin(MeshSkin* skin)
 {
 {
     _meshSkin = skin;
     _meshSkin = skin;
+
+    if (_meshSkin)
+    {
+        _meshSkin->_mesh = _mesh;
+    }
 }
 }
 
 
-}
+}

+ 4 - 4
gameplay-encoder/src/Model.h

@@ -1,8 +1,6 @@
 #ifndef MODEL_H_
 #ifndef MODEL_H_
 #define MODEL_H_
 #define MODEL_H_
 
 
-#include <list>
-
 #include "Object.h"
 #include "Object.h"
 #include "Mesh.h"
 #include "Mesh.h"
 #include "MeshSkin.h"
 #include "MeshSkin.h"
@@ -30,16 +28,18 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
     virtual void writeText(FILE* file);
 
 
+    Mesh* getMesh();
     void setMesh(Mesh* mesh);
     void setMesh(Mesh* mesh);
     MeshSkin* getSkin();
     MeshSkin* getSkin();
     void setSkin(MeshSkin* skin);
     void setSkin(MeshSkin* skin);
 
 
 private:
 private:
-    Mesh* _ref;
+
+    Mesh* _mesh;
     MeshSkin* _meshSkin;
     MeshSkin* _meshSkin;
     std::list<Material*> _materials;
     std::list<Material*> _materials;
 };
 };
 
 
 }
 }
-#endif
 
 
+#endif

+ 63 - 20
gameplay-encoder/src/Node.cpp

@@ -1,4 +1,7 @@
+#include "Base.h"
 #include "Node.h"
 #include "Node.h"
+#include "Matrix.h"
+#include "EncoderArguments.h"
 
 
 #define NODE 1
 #define NODE 1
 #define JOINT 2
 #define JOINT 2
@@ -12,7 +15,6 @@ Node::Node(void) :
     _firstChild(NULL), _lastChild(NULL), _parent(NULL),
     _firstChild(NULL), _lastChild(NULL), _parent(NULL),
     _camera(NULL), _light(NULL), _model(NULL), _joint(false)
     _camera(NULL), _light(NULL), _model(NULL), _joint(false)
 {
 {
-    setIdentityMatrix(_transform);
 }
 }
 
 
 Node::~Node(void)
 Node::~Node(void)
@@ -37,7 +39,7 @@ void Node::writeBinary(FILE* file)
     unsigned int type = _joint ? JOINT : NODE;
     unsigned int type = _joint ? JOINT : NODE;
     write(type, file);
     write(type, file);
 
 
-    write(_transform, 16, file);
+    write(_transform.m, 16, file);
     // children
     // children
     write(getChildCount(), file); // write number of children
     write(getChildCount(), file); // write number of children
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
@@ -72,7 +74,10 @@ void Node::writeBinary(FILE* file)
     {
     {
         writeZero(file);
         writeZero(file);
     }
     }
+
+    generateHeightmap();
 }
 }
+
 void Node::writeText(FILE* file)
 void Node::writeText(FILE* file)
 {
 {
     if (isJoint())
     if (isJoint())
@@ -84,7 +89,7 @@ void Node::writeText(FILE* file)
         fprintElementStart(file);
         fprintElementStart(file);
     }
     }
     fprintf(file, "<transform>");
     fprintf(file, "<transform>");
-    fprintfMatrix4f(file, _transform);
+    fprintfMatrix4f(file, _transform.m);
     fprintf(file, "</transform>\n");
     fprintf(file, "</transform>\n");
 
 
     // children
     // children
@@ -108,6 +113,29 @@ void Node::writeText(FILE* file)
         _model->writeText(file);
         _model->writeText(file);
     }
     }
     fprintElementEnd(file);
     fprintElementEnd(file);
+
+    generateHeightmap();
+}
+
+void Node::generateHeightmap()
+{
+    // Is this node flagged to have a heightmap generated for it?
+    const std::vector<std::string>& heightmapNodes = EncoderArguments::getInstance()->getHeightmapNodeIds();
+    if (std::find(heightmapNodes.begin(), heightmapNodes.end(), getId()) != heightmapNodes.end())
+    {
+        Mesh* mesh = _model ? _model->getMesh() : NULL;
+        if (mesh)
+        {
+            DEBUGPRINT_VARG("> Generating heightmap for node: %s\n", getId().c_str());
+
+            std::string heightmapFilename(EncoderArguments::getInstance()->getOutputPath());
+            heightmapFilename += "/heightmap_";
+            heightmapFilename += getId();
+            heightmapFilename += ".png";
+
+            mesh->generateHeightmap(heightmapFilename.c_str());
+        }
+    }
 }
 }
 
 
 void Node::addChild(Node* child)
 void Node::addChild(Node* child)
@@ -219,25 +247,48 @@ Node* Node::getParent() const
     return _parent;
     return _parent;
 }
 }
 
 
-void Node::setCameraInstance(CameraInstance* cameraInstance)
+void Node::setCamera(Camera* camera)
 {
 {
-    _camera = cameraInstance;
+    _camera = camera;
 }
 }
-void Node::setLightInstance(LightInstance* lightInstance)
+
+void Node::setLight(Light* light)
 {
 {
-    _light = lightInstance;
+    _light = light;
 }
 }
+
 void Node::setModel(Model* model)
 void Node::setModel(Model* model)
 {
 {
     _model = model;
     _model = model;
 }
 }
 
 
+const Matrix& Node::getTransformMatrix() const
+{
+    return _transform;
+}
+
 void Node::setTransformMatrix(float matrix[])
 void Node::setTransformMatrix(float matrix[])
 {
 {
-    for (int i = 0; i < 16; i++)
+    memcpy(_transform.m, matrix, 16 * sizeof(float));
+}
+
+const Matrix& Node::getWorldMatrix() const
+{
+    if (_parent)
     {
     {
-        _transform[i] = matrix[i];
+        Matrix::multiply(_parent->getWorldMatrix().m, _transform.m, _worldTransform.m);
     }
     }
+    else
+    {
+        memcpy(_worldTransform.m, _transform.m, 16 * sizeof(float));
+    }
+
+    return _worldTransform;
+}
+
+void Node::resetTransformMatrix()
+{
+    Matrix::setIdentity(_transform.m);
 }
 }
 
 
 void Node::setIsJoint(bool value)
 void Node::setIsJoint(bool value)
@@ -252,20 +303,12 @@ bool Node::isJoint()
 
 
 Camera* Node::getCamera() const
 Camera* Node::getCamera() const
 {
 {
-    if (_camera)
-    {
-        return _camera->getCamera();
-    }
-    return NULL;
+    return _camera;
 }
 }
 
 
 Light* Node::getLight() const
 Light* Node::getLight() const
 {
 {
-    if (_light)
-    {
-        return _light->getLight();
-    }
-    return NULL;
+    return _light;
 }
 }
 
 
 Model* Node::getModel() const
 Model* Node::getModel() const
@@ -304,4 +347,4 @@ bool Node::hasLight() const
     return _light != NULL;
     return _light != NULL;
 }
 }
 
 
-}
+}

+ 31 - 11
gameplay-encoder/src/Node.h

@@ -1,11 +1,9 @@
 #ifndef NODE_H_
 #ifndef NODE_H_
 #define NODE_H_
 #define NODE_H_
 
 
-#include <list>
-
 #include "Object.h"
 #include "Object.h"
-#include "CameraInstance.h"
-#include "LightInstance.h"
+#include "Camera.h"
+#include "Light.h"
 #include "Model.h"
 #include "Model.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -125,13 +123,28 @@ public:
      */
      */
     Model* getModel() const;
     Model* getModel() const;
 
 
+    /**
+     * Returns the transform matrix for the node.
+     */
+    const Matrix& getTransformMatrix() const;
+
     /**
     /**
      * Sets the transform for this node.
      * Sets the transform for this node.
      */
      */
     void setTransformMatrix(float matrix[]);
     void setTransformMatrix(float matrix[]);
 
 
-    void setCameraInstance(CameraInstance* cameraInstance);
-    void setLightInstance(LightInstance* lightInstance);
+    /**
+     * Returns the resolved world matrix for the node.
+     */
+    const Matrix& getWorldMatrix() const;
+
+    /*
+     * Resets the node's transform matrix to the identity matrix.
+     */
+    void resetTransformMatrix();
+
+    void setCamera(Camera* camera);
+    void setLight(Light* light);
     void setModel(Model* model);
     void setModel(Model* model);
 
 
     /**
     /**
@@ -157,7 +170,15 @@ public:
     bool hasLight() const;
     bool hasLight() const;
     
     
 private:
 private:
-    float _transform[16];
+
+    /**
+     * Internal method to generate heightmap for a node's mesh data
+     * if the node was flagged as a heightmap via encoder arguments.
+     */
+    void generateHeightmap();
+
+    Matrix _transform;
+    mutable Matrix _worldTransform;
 
 
     int _childCount;
     int _childCount;
     Node* _nextSibling;
     Node* _nextSibling;
@@ -166,14 +187,13 @@ private:
     Node* _lastChild;
     Node* _lastChild;
     Node* _parent;
     Node* _parent;
 
 
-    CameraInstance* _camera;
-    LightInstance* _light;
+    Camera* _camera;
+    Light* _light;
     Model* _model;
     Model* _model;
 
 
     bool _joint;
     bool _joint;
 };
 };
 
 
-
 }
 }
-#endif
 
 
+#endif

+ 2 - 1
gameplay-encoder/src/Object.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Object.h"
 #include "Object.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -76,4 +77,4 @@ void Object::writeBinaryXref(FILE* file)
     write(xref, file);
     write(xref, file);
 }
 }
 
 
-}
+}

+ 6 - 13
gameplay-encoder/src/Object.h

@@ -1,16 +1,11 @@
 #ifndef OBJ_H_
 #ifndef OBJ_H_
 #define OBJ_H_
 #define OBJ_H_
 
 
-#include <iostream>
-#include <string>
-#include <list>
-#include <vector>
-
-#include "Base.h"
 #include "FileIO.h"
 #include "FileIO.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
+
 /**
 /**
  * Object is the abstract base class of all the objects that can be written in the GamePlay Binary file.
  * Object is the abstract base class of all the objects that can be written in the GamePlay Binary file.
  */
  */
@@ -27,8 +22,6 @@ public:
         ANIMATION_ID = 4,
         ANIMATION_ID = 4,
         ANIMATIONCHANNEL_ID = 5,
         ANIMATIONCHANNEL_ID = 5,
         NODEINSTANCE_ID = 8,
         NODEINSTANCE_ID = 8,
-        CAMERAINSTANCE_ID = 9,
-        LIGHTINSTANCE_ID = 10,
         MODEL_ID = 11,
         MODEL_ID = 11,
         MATERIAL_ID = 16,
         MATERIAL_ID = 16,
         EFFECT_ID = 17,
         EFFECT_ID = 17,
@@ -40,7 +33,6 @@ public:
         FONT_ID = 128,
         FONT_ID = 128,
     };
     };
 
 
-
     /**
     /**
      * Constructor.
      * Constructor.
      */
      */
@@ -118,8 +110,8 @@ public:
         // First write the size of the list
         // First write the size of the list
         write(list.size(), file);
         write(list.size(), file);
         // Then write each element
         // Then write each element
-        std::list<T>::const_iterator i;
-        for (i = list.begin(); i != list.end(); i++)
+        typename std::list<T>::const_iterator i;
+        for (i = list.begin(); i != list.end(); ++i)
         {
         {
             (*i)->writeBinary(file);
             (*i)->writeBinary(file);
         }
         }
@@ -134,14 +126,15 @@ public:
         // First write the size of the vector
         // First write the size of the vector
         write(vector.size(), file);
         write(vector.size(), file);
         // Then write each element
         // Then write each element
-        std::vector<T>::const_iterator i;
-        for (i = vector.begin(); i != vector.end(); i++)
+        typename std::vector<T>::const_iterator i;
+        for (i = vector.begin(); i != vector.end(); ++i)
         {
         {
             (*i)->writeBinary(file);
             (*i)->writeBinary(file);
         }
         }
     }
     }
 
 
 private:
 private:
+
     /**
     /**
      * Saves where this object was written to in the binary file.
      * Saves where this object was written to in the binary file.
      */
      */

+ 1 - 5
gameplay-encoder/src/Quaternion.cpp

@@ -1,7 +1,3 @@
-/*
- * Quaternion.cpp
- */
-
 #include "Base.h"
 #include "Base.h"
 #include "Quaternion.h"
 #include "Quaternion.h"
 
 
@@ -162,7 +158,7 @@ void Quaternion::normalize(Quaternion* dst) const
     if (n == 1.0f)
     if (n == 1.0f)
         return;
         return;
 
 
-    n = sqrtf(n);
+    n = sqrt(n);
     // too close to zero
     // too close to zero
     if (n < 0.000001f)
     if (n < 0.000001f)
         return;
         return;

+ 2 - 5
gameplay-encoder/src/Quaternion.h

@@ -1,7 +1,3 @@
-/*
- * Quaternion.h
- */
-
 #ifndef QUATERNION_H_
 #ifndef QUATERNION_H_
 #define QUATERNION_H_
 #define QUATERNION_H_
 
 
@@ -308,4 +304,5 @@ private:
 };
 };
 
 
 }
 }
-#endif /* QUATERNION_H_ */
+
+#endif

+ 2 - 1
gameplay-encoder/src/Reference.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Reference.h"
 #include "Reference.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -83,4 +84,4 @@ Object* Reference::getObj()
     return _ref;
     return _ref;
 }
 }
 
 
-}
+}

+ 1 - 0
gameplay-encoder/src/Reference.h

@@ -53,4 +53,5 @@ private:
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 5 - 4
gameplay-encoder/src/ReferenceTable.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "ReferenceTable.h"
 #include "ReferenceTable.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -30,7 +31,7 @@ Object* ReferenceTable::get(const std::string& xref)
 void ReferenceTable::writeBinary(FILE* file)
 void ReferenceTable::writeBinary(FILE* file)
 {
 {
     write(_table.size(), file);
     write(_table.size(), file);
-    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); i++ )
+    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); ++i)
     {
     {
         i->second.writeBinary(file);
         i->second.writeBinary(file);
     }
     }
@@ -39,7 +40,7 @@ void ReferenceTable::writeBinary(FILE* file)
 void ReferenceTable::writeText(FILE* file)
 void ReferenceTable::writeText(FILE* file)
 {
 {
     fprintf(file, "<RefTable>\n");
     fprintf(file, "<RefTable>\n");
-    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); i++ )
+    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); ++i)
     {
     {
         i->second.writeText(file);
         i->second.writeText(file);
     }
     }
@@ -48,7 +49,7 @@ void ReferenceTable::writeText(FILE* file)
 
 
 void ReferenceTable::updateOffsets(FILE* file)
 void ReferenceTable::updateOffsets(FILE* file)
 {
 {
-    for (std::map<std::string, Reference>::iterator i = _table.begin(); i != _table.end(); i++)
+    for (std::map<std::string, Reference>::iterator i = _table.begin(); i != _table.end(); ++i)
     {
     {
         Reference& ref = i->second;
         Reference& ref = i->second;
         ref.updateOffset(file);
         ref.updateOffset(file);
@@ -65,4 +66,4 @@ std::map<std::string, Reference>::iterator ReferenceTable::end()
     return _table.end();
     return _table.end();
 }
 }
 
 
-}
+}

+ 1 - 3
gameplay-encoder/src/ReferenceTable.h

@@ -1,8 +1,6 @@
 #ifndef REFTABLE_H_
 #ifndef REFTABLE_H_
 #define REFTABLE_H_
 #define REFTABLE_H_
 
 
-#include <map>
-
 #include "FileIO.h"
 #include "FileIO.h"
 #include "Reference.h"
 #include "Reference.h"
 #include "Object.h"
 #include "Object.h"
@@ -56,5 +54,5 @@ private:
 };
 };
 
 
 }
 }
-#endif
 
 
+#endif

+ 13 - 6
gameplay-encoder/src/Scene.cpp

@@ -1,5 +1,4 @@
-#include <algorithm>
-
+#include "Base.h"
 #include "Scene.h"
 #include "Scene.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -40,10 +39,11 @@ void Scene::writeBinary(FILE* file)
     }
     }
     write(_ambientColor, Light::COLOR_SIZE, file);
     write(_ambientColor, Light::COLOR_SIZE, file);
 }
 }
+
 void Scene::writeText(FILE* file)
 void Scene::writeText(FILE* file)
 {
 {
     fprintElementStart(file);
     fprintElementStart(file);
-    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
     {
     {
         (*i)->writeText(file);
         (*i)->writeText(file);
     }
     }
@@ -67,7 +67,7 @@ void Scene::setActiveCameraNode(Node* node)
 
 
 Node* Scene::getFirstCameraNode() const
 Node* Scene::getFirstCameraNode() const
 {
 {
-    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
     {
     {
         Node* n = (*i)->getFirstCameraNode();
         Node* n = (*i)->getFirstCameraNode();
         if (n)
         if (n)
@@ -81,7 +81,7 @@ Node* Scene::getFirstCameraNode() const
 void Scene::calcAmbientColor()
 void Scene::calcAmbientColor()
 {
 {
     float values[3] = {0.0f, 0.0f, 0.0f};
     float values[3] = {0.0f, 0.0f, 0.0f};
-    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
     {
     {
         calcAmbientColor(*i, values);
         calcAmbientColor(*i, values);
     }
     }
@@ -91,6 +91,13 @@ void Scene::calcAmbientColor()
     _ambientColor[2] = std::min(values[2], 1.0f);
     _ambientColor[2] = std::min(values[2], 1.0f);
 }
 }
 
 
+void Scene::setAmbientColor(float red, float green, float blue)
+{
+    _ambientColor[0] = red;
+    _ambientColor[1] = green;
+    _ambientColor[2] = blue;
+}
+
 void Scene::calcAmbientColor(const Node* node, float* values) const
 void Scene::calcAmbientColor(const Node* node, float* values) const
 {
 {
     if (!node)
     if (!node)
@@ -113,4 +120,4 @@ void Scene::calcAmbientColor(const Node* node, float* values) const
     }
     }
 }
 }
 
 
-}
+}

+ 6 - 0
gameplay-encoder/src/Scene.h

@@ -50,6 +50,11 @@ public:
      */
      */
     void calcAmbientColor();
     void calcAmbientColor();
 
 
+    /**
+     * Sets the scene's ambient color.
+     */
+    void setAmbientColor(float red, float green, float blue);
+
 private:
 private:
 
 
     /**
     /**
@@ -68,4 +73,5 @@ private:
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 22 - 4
gameplay-encoder/src/StringUtil.cpp

@@ -1,7 +1,6 @@
+#include "Base.h"
 #include "StringUtil.h"
 #include "StringUtil.h"
 
 
-#include <string>
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -90,7 +89,7 @@ bool equalsIgnoreCase(const std::string& a, const char* b)
     {
     {
         return false;
         return false;
     }
     }
-    for (size_t i = 0; i < bLength; i++)
+    for (size_t i = 0; i < bLength; ++i)
     {
     {
         if (lowercase(a[i]) != lowercase(b[i]))
         if (lowercase(a[i]) != lowercase(b[i]))
         {
         {
@@ -100,4 +99,23 @@ bool equalsIgnoreCase(const std::string& a, const char* b)
     return true;
     return true;
 }
 }
 
 
-}
+std::string getFilenameFromFilePath(const std::string& filepath)
+{
+    if (filepath.find_last_of("/") != std::string::npos)
+    {
+        return filepath.substr(filepath.find_last_of("/")+1);
+    }
+    return "";
+}
+
+
+std::string getFilenameNoExt(const std::string& filename)
+{
+    if (filename.find_last_of(".") != std::string::npos)
+    {
+        return filename.substr(0, filename.find_last_of("."));
+    }
+    return filename;
+}
+
+}

+ 5 - 2
gameplay-encoder/src/StringUtil.h

@@ -1,8 +1,6 @@
 #ifndef STRINGUTIL_H_
 #ifndef STRINGUTIL_H_
 #define STRINGUTIL_H_
 #define STRINGUTIL_H_
 
 
-#include <string>
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -19,5 +17,10 @@ bool equals(const std::string& a, const char* b);
  */
  */
 bool equalsIgnoreCase(const std::string& a, const char* b);
 bool equalsIgnoreCase(const std::string& a, const char* b);
 
 
+std::string getFilenameFromFilePath(const std::string& filepath);
+
+std::string getFilenameNoExt(const std::string& filename);
+
 }
 }
+
 #endif
 #endif

+ 12 - 7
gameplay-encoder/src/TTFFontEncoder.cpp

@@ -1,12 +1,16 @@
+#include "Base.h"
 #include "TTFFontEncoder.h"
 #include "TTFFontEncoder.h"
+#include "GPBFile.h"
 
 
+namespace gameplay
+{
 
 
 void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight)
 void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight)
 {
 {
     // offset dst bitmap by x,y.
     // offset dst bitmap by x,y.
     dstBitmap +=  (x + (y * dstWidth));
     dstBitmap +=  (x + (y * dstWidth));
 
 
-    for (int i = 0; i < srcHeight; i++)
+    for (int i = 0; i < srcHeight; ++i)
     {
     {
         memcpy(dstBitmap, (const void*)srcBitmap, srcWidth);
         memcpy(dstBitmap, (const void*)srcBitmap, srcWidth);
         srcBitmap += srcWidth;
         srcBitmap += srcWidth;
@@ -87,7 +91,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     int rowSize = 0; // Stores the total number of rows required to all glyphs.
     int rowSize = 0; // Stores the total number of rows required to all glyphs.
     
     
     // Find the width of the image.
     // Find the width of the image.
-    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
+    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
     {
     {
         // Load glyph image into the slot (erase previous one)
         // Load glyph image into the slot (erase previous one)
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
@@ -132,7 +136,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
 
 
         // Find out the squared texture size that would fit all the require font glyphs.
         // Find out the squared texture size that would fit all the require font glyphs.
         i = 0;
         i = 0;
-        for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
+        for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
         {
         {
             // Load glyph image into the slot (erase the previous one).
             // Load glyph image into the slot (erase the previous one).
             error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
             error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
@@ -199,7 +203,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     penY = 0;
     penY = 0;
     row = 0;
     row = 0;
     i = 0;
     i = 0;
-    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
+    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
     {
     {
         // Load glyph image into the slot (erase the previous one).
         // Load glyph image into the slot (erase the previous one).
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
@@ -263,9 +267,8 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     
     
     // File header and version.
     // File header and version.
     char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
     char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
-    char fileVersion[2]    = {1, 0};
     fwrite(fileHeader, sizeof(char), 9, gpbFp);
     fwrite(fileHeader, sizeof(char), 9, gpbFp);
-    fwrite(fileVersion, sizeof(char), 2, gpbFp);
+    fwrite(gameplay::GPB_VERSION, sizeof(char), 2, gpbFp);
 
 
     // Write Ref table (for a single font)
     // Write Ref table (for a single font)
     writeUint(gpbFp, 1);                // Ref[] count
     writeUint(gpbFp, 1);                // Ref[] count
@@ -326,4 +329,6 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     FT_Done_Face(face);
     FT_Done_Face(face);
     FT_Done_FreeType(library);
     FT_Done_FreeType(library);
     return 0;
     return 0;
-}
+}
+
+}

+ 5 - 7
gameplay-encoder/src/TTFFontEncoder.h

@@ -1,9 +1,4 @@
-#include <stdio.h>
 #include <ft2build.h>
 #include <ft2build.h>
-#include "string.h"
-#include <fstream>
-#include <math.h>
-
 #include FT_FREETYPE_H
 #include FT_FREETYPE_H
 
 
 #define START_INDEX     32
 #define START_INDEX     32
@@ -11,6 +6,8 @@
 
 
 #define GLYPH_PADDING   4
 #define GLYPH_PADDING   4
 
 
+namespace gameplay
+{
 
 
 // Structure of Glyph.
 // Structure of Glyph.
 class Glyph
 class Glyph
@@ -21,7 +18,6 @@ public:
     float uvCoords[4];
     float uvCoords[4];
 };
 };
 
 
-
 void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight);
 void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight);
 
 
 void writeUint(FILE* fp, unsigned int i);
 void writeUint(FILE* fp, unsigned int i);
@@ -30,4 +26,6 @@ void writeFloat(FILE* fp, float f);
 
 
 void writeString(FILE* fp, const char* str);
 void writeString(FILE* fp, const char* str);
 
 
-int writeFont(const char* filename, unsigned int fontSize, const char* id, bool fontpreview);
+int writeFont(const char* filename, unsigned int fontSize, const char* id, bool fontpreview);
+
+}

+ 2 - 0
gameplay-encoder/src/Transform.cpp

@@ -0,0 +1,2 @@
+#include "Base.h"
+#include "Transform.h"

+ 20 - 16
gameplay-encoder/src/Transform.h

@@ -14,37 +14,41 @@ public:
          * Scale animation property. Data=sx,sy,sz
          * Scale animation property. Data=sx,sy,sz
          */
          */
         ANIMATE_SCALE = 1,
         ANIMATE_SCALE = 1,
-        ANIMATE_SCALE_X,
-        ANIMATE_SCALE_Y,
-        ANIMATE_SCALE_Z,
-        ANIMATE_SCALE_XY,
-        ANIMATE_SCALE_XZ,
-        ANIMATE_SCALE_YZ,
+        ANIMATE_SCALE_X = 2,
+        ANIMATE_SCALE_Y = 3,
+        ANIMATE_SCALE_Z = 4,
+        ANIMATE_SCALE_XY = 5,
+        ANIMATE_SCALE_XZ = 6,
+        ANIMATE_SCALE_YZ = 7,
 
 
         /**
         /**
          * Rotation animation property. Data=qx,qy,qz,qw (as quaternion).
          * Rotation animation property. Data=qx,qy,qz,qw (as quaternion).
          */
          */
-        ANIMATE_ROTATE,
+        ANIMATE_ROTATE = 8,
 
 
         /**
         /**
          * Translation animation property. Data=tx,ty,tz
          * Translation animation property. Data=tx,ty,tz
          */
          */
-        ANIMATE_TRANSLATE,
-        ANIMATE_TRANSLATE_X,
-        ANIMATE_TRANSLATE_Y,
-        ANIMATE_TRANSLATE_Z,
-        ANIMATE_TRANSLATE_XY,
-        ANIMATE_TRANSLATE_XZ,
-        ANIMATE_TRANSLATE_YZ,
+        ANIMATE_TRANSLATE = 9,
+        ANIMATE_TRANSLATE_X = 10,
+        ANIMATE_TRANSLATE_Y = 11,
+        ANIMATE_TRANSLATE_Z = 12,
+        ANIMATE_TRANSLATE_XY = 13,
+        ANIMATE_TRANSLATE_XZ = 14,
+        ANIMATE_TRANSLATE_YZ = 15,
 
 
         /**
         /**
          * Rotation + Translation animation property(Rigid Body). Data=qx,qy,qz,qw,tx,ty,tz
          * Rotation + Translation animation property(Rigid Body). Data=qx,qy,qz,qw,tx,ty,tz
          */
          */
-        ANIMATE_ROTATE_TRANSLATE,
+        ANIMATE_ROTATE_TRANSLATE = 16,
         /**
         /**
          * Scale, Rotation + Translation animation property. Data=sx,sy,sz,qx,qy,qz,qw,tx,ty,tz
          * Scale, Rotation + Translation animation property. Data=sx,sy,sz,qx,qy,qz,qw,tx,ty,tz
          */
          */
-        ANIMATE_SCALE_ROTATE_TRANSLATE
+        ANIMATE_SCALE_ROTATE_TRANSLATE = 17,
+
+        ANIMATE_ROTATE_X = 18,
+        ANIMATE_ROTATE_Y = 19,
+        ANIMATE_ROTATE_Z = 20
     };
     };
 };
 };
 
 

+ 18 - 70
gameplay-encoder/src/Vector2.cpp

@@ -1,10 +1,5 @@
-/*
- * Vector2.cpp
- */
-
 #include "Base.h"
 #include "Base.h"
 #include "Vector2.h"
 #include "Vector2.h"
-#include "FileIO.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -14,90 +9,76 @@ Vector2::Vector2()
 {
 {
 }
 }
 
 
-
 Vector2::Vector2(float x, float y)
 Vector2::Vector2(float x, float y)
 {
 {
     set(x, y);
     set(x, y);
 }
 }
 
 
-
 Vector2::Vector2(float* array)
 Vector2::Vector2(float* array)
 {
 {
     set(array);
     set(array);
 }
 }
 
 
-
 Vector2::Vector2(const Vector2& p1, const Vector2& p2)
 Vector2::Vector2(const Vector2& p1, const Vector2& p2)
 {
 {
     set(p1, p2);
     set(p1, p2);
 }
 }
 
 
-
 Vector2::Vector2(const Vector2& copy)
 Vector2::Vector2(const Vector2& copy)
 {
 {
     set(copy);
     set(copy);
 }
 }
 
 
-
 Vector2::~Vector2()
 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
 {
 {
     return x == 0.0f && y == 0.0f;
     return x == 0.0f && y == 0.0f;
 }
 }
 
 
-
 bool Vector2::isOne() const
 bool Vector2::isOne() const
 {
 {
     return x == 1.0f && y == 1.0f;
     return x == 1.0f && y == 1.0f;
 }
 }
 
 
-
 float Vector2::angle(const Vector2& v1, const Vector2& v2)
 float Vector2::angle(const Vector2& v1, const Vector2& v2)
 {
 {
     float dz = v1.x * v2.y - v1.y * v2.x;
     float dz = v1.x * v2.y - v1.y * v2.x;
     return atan2f(fabsf(dz) + MATH_FLOAT_SMALL, dot(v1, v2));
     return atan2f(fabsf(dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 }
 
 
-
 void Vector2::add(const Vector2& v)
 void Vector2::add(const Vector2& v)
 {
 {
     x += v.x;
     x += v.x;
     y += v.y;
     y += v.y;
 }
 }
 
 
-
 void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
 void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -106,7 +87,6 @@ void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
     dst->y = v1.y + v2.y;
     dst->y = v1.y + v2.y;
 }
 }
 
 
-
 void Vector2::clamp(const Vector2& min, const Vector2& max)
 void Vector2::clamp(const Vector2& min, const Vector2& max)
 {
 {
     assert(!( min.x > max.x || min.y > max.y ));
     assert(!( min.x > max.x || min.y > max.y ));
@@ -124,13 +104,12 @@ void Vector2::clamp(const Vector2& min, const Vector2& max)
         y = max.y;
         y = max.y;
 }
 }
 
 
-
 void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Vector2* dst)
 void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Vector2* dst)
 {
 {
     assert(dst);
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y ));
     assert(!( min.x > max.x || min.y > max.y ));
 
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     dst->x = v.x;
     if ( dst->x < min.x )
     if ( dst->x < min.x )
         dst->x = min.x;
         dst->x = min.x;
@@ -145,61 +124,52 @@ void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Ve
         dst->y = max.y;
         dst->y = max.y;
 }
 }
 
 
-
-float Vector2::distance(const Vector2& v)
+float Vector2::distance(const Vector2& v) const
 {
 {
     float dx = v.x - x;
     float dx = v.x - x;
     float dy = v.y - y;
     float dy = v.y - y;
 
 
-    return sqrtf(dx * dx + dy * dy);
+    return sqrt(dx * dx + dy * dy);
 }
 }
 
 
-
-float Vector2::distanceSquared(const Vector2& v)
+float Vector2::distanceSquared(const Vector2& v) const
 {
 {
     float dx = v.x - x;
     float dx = v.x - x;
     float dy = v.y - y;
     float dy = v.y - y;
     return (dx * dx + dy * dy);
     return (dx * dx + dy * dy);
 }
 }
 
 
-
 float Vector2::dot(const Vector2& v)
 float Vector2::dot(const Vector2& v)
 {
 {
     return (x * v.x + y * v.y);
     return (x * v.x + y * v.y);
 }
 }
 
 
-
 float Vector2::dot(const Vector2& v1, const Vector2& v2)
 float Vector2::dot(const Vector2& v1, const Vector2& v2)
 {
 {
     return (v1.x * v2.x + v1.y * v2.y);
     return (v1.x * v2.x + v1.y * v2.y);
 }
 }
 
 
-
-float Vector2::length()
+float Vector2::length() const
 {
 {
-    return sqrtf(x * x + y * y);
+    return sqrt(x * x + y * y);
 }
 }
 
 
-
-float Vector2::lengthSquared()
+float Vector2::lengthSquared() const
 {
 {
     return (x * x + y * y);
     return (x * x + y * y);
 }
 }
 
 
-
 void Vector2::negate()
 void Vector2::negate()
 {
 {
     x = -x;
     x = -x;
     y = -y;
     y = -y;
 }
 }
 
 
-
 void Vector2::normalize()
 void Vector2::normalize()
 {
 {
     normalize(this);
     normalize(this);
 }
 }
 
 
-
 void Vector2::normalize(Vector2* dst)
 void Vector2::normalize(Vector2* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -211,12 +181,12 @@ void Vector2::normalize(Vector2* dst)
     }
     }
 
 
     float n = x * x + y * y;
     float n = x * x + y * y;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
     if (n == 1.0f)
         return;
         return;
 
 
-    n = sqrtf(n);
-    // too close to zero
+    n = sqrt(n);
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
     if (n < MATH_TOLERANCE)
         return;
         return;
 
 
@@ -225,21 +195,18 @@ void Vector2::normalize(Vector2* dst)
     dst->y *= n;
     dst->y *= n;
 }
 }
 
 
-
 void Vector2::scale(float scalar)
 void Vector2::scale(float scalar)
 {
 {
     x *= scalar;
     x *= scalar;
     y *= scalar;
     y *= scalar;
 }
 }
 
 
-
 void Vector2::scale(const Vector2& scale)
 void Vector2::scale(const Vector2& scale)
 {
 {
     x *= scale.x;
     x *= scale.x;
     y *= scale.y;
     y *= scale.y;
 }
 }
 
 
-
 void Vector2::rotate(const Vector2& point, float angle)
 void Vector2::rotate(const Vector2& point, float angle)
 {
 {
     float sinAngle = sin(angle);
     float sinAngle = sin(angle);
@@ -261,14 +228,12 @@ void Vector2::rotate(const Vector2& point, float angle)
     }
     }
 }
 }
 
 
-
 void Vector2::set(float x, float y)
 void Vector2::set(float x, float y)
 {
 {
     this->x = x;
     this->x = x;
     this->y = y;
     this->y = y;
 }
 }
 
 
-
 void Vector2::set(float* array)
 void Vector2::set(float* array)
 {
 {
     assert(array);
     assert(array);
@@ -277,28 +242,24 @@ void Vector2::set(float* array)
     y = array[1];
     y = array[1];
 }
 }
 
 
-
 void Vector2::set(const Vector2& v)
 void Vector2::set(const Vector2& v)
 {
 {
     this->x = v.x;
     this->x = v.x;
     this->y = v.y;
     this->y = v.y;
 }
 }
 
 
-
 void Vector2::set(const Vector2& p1, const Vector2& p2)
 void Vector2::set(const Vector2& p1, const Vector2& p2)
 {
 {
      x = p2.x - p1.x;
      x = p2.x - p1.x;
      y = p2.y - p1.y;
      y = p2.y - p1.y;
 }
 }
 
 
-
 void Vector2::subtract(const Vector2& v)
 void Vector2::subtract(const Vector2& v)
 {
 {
     x -= v.x;
     x -= v.x;
     y -= v.y;
     y -= v.y;
 }
 }
 
 
-
 void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
 void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -307,17 +268,4 @@ void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
     dst->y = v1.y - v2.y;
     dst->y = v1.y - v2.y;
 }
 }
 
 
-void Vector2::writeBinary(FILE* file) const
-{
-    write(x, file);
-    write(y, file);
 }
 }
-
-void Vector2::writeText(FILE* file) const
-{
-    fprintf(file, "%f %f\n", x, y);
-}
-
-}
-
-

+ 109 - 38
gameplay-encoder/src/Vector2.h

@@ -1,14 +1,9 @@
-/*
- * Vector2.h
- */
-
 #ifndef VECTOR2_H_
 #ifndef VECTOR2_H_
 #define VECTOR2_H_
 #define VECTOR2_H_
 
 
-
 namespace gameplay
 namespace gameplay
 {
 {
-// Forward declare
+
 class Matrix;
 class Matrix;
 
 
 /**
 /**
@@ -69,44 +64,44 @@ public:
     ~Vector2();
     ~Vector2();
 
 
     /**
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      *
      * @return The 2-element vector of 0s.
      * @return The 2-element vector of 0s.
      */
      */
     static const Vector2& zero();
     static const Vector2& zero();
 
 
     /**
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      *
      * @return The 2-element vector of 1s.
      * @return The 2-element vector of 1s.
      */
      */
     static const Vector2& one();
     static const Vector2& one();
 
 
     /**
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      *
      * @return The 2-element unit vector along the x axis.
      * @return The 2-element unit vector along the x axis.
      */
      */
     static const Vector2& unitX();
     static const Vector2& unitX();
 
 
     /**
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      *
      * @return The 2-element unit vector along the y axis.
      * @return The 2-element unit vector along the y axis.
      */
      */
     static const Vector2& unitY();
     static const Vector2& unitY();
 
 
     /**
     /**
-     * Is this vector the all zeros.
+     * Indicates whether this vector contains all zeros.
      *
      *
-     * @return true if all zeros, false if otherwise.
+     * @return true if this vector contains all zeros, false otherwise.
      */
      */
     bool isZero() const;
     bool isZero() const;
 
 
     /**
     /**
-     * Is this vector all ones.
+     * Indicates whether this vector contains all ones.
      *
      *
-     * @return true if all ones, false if otherwise.
+     * @return true if this vector contains all ones, false otherwise.
      */
      */
     bool isOne() const;
     bool isOne() const;
 
 
@@ -116,7 +111,7 @@ public:
      * @param v1 The first vector.
      * @param v1 The first vector.
      * @param v2 The second vector.
      * @param v2 The second vector.
      * 
      * 
-     * @return The angle between the two vectors, in radians.
+     * @return The angle between the two vectors (in radians).
      */
      */
     static float angle(const Vector2& v1, const Vector2& v2);
     static float angle(const Vector2& v1, const Vector2& v2);
 
 
@@ -160,9 +155,10 @@ public:
      * @param v The other vector.
      * @param v The other vector.
      * 
      * 
      * @return The distance between this vector and v.
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      * @see distanceSquared
      */
      */
-    float distance(const Vector2& v);
+    float distance(const Vector2& v) const;
 
 
     /**
     /**
      * Returns the squared distance between this vector and v.
      * Returns the squared distance between this vector and v.
@@ -175,9 +171,10 @@ public:
      * @param v The other vector.
      * @param v The other vector.
      * 
      * 
      * @return The squared distance between this vector and v.
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      * @see distance
      */
      */
-    float distanceSquared(const Vector2& v);
+    float distanceSquared(const Vector2& v) const;
 
 
     /**
     /**
      * Returns the dot product of this vector and the specified vector.
      * Returns the dot product of this vector and the specified vector.
@@ -202,9 +199,10 @@ public:
      * Computes the length of this vector.
      * Computes the length of this vector.
      *
      *
      * @return The length of the vector.
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      * @see lengthSquared
      */
      */
-    float length();
+    float length() const;
 
 
     /**
     /**
      * Returns the squared length of this vector.
      * Returns the squared length of this vector.
@@ -215,9 +213,10 @@ public:
      * instead of length.
      * instead of length.
      *
      *
      * @return The squared length of the vector.
      * @return The squared length of the vector.
+     * 
      * @see length
      * @see length
      */
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
 
     /**
     /**
      * Negates this vector.
      * Negates this vector.
@@ -242,7 +241,7 @@ public:
      * of the vector is zero, this method simply copies the
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      * current vector into dst.
      *
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
      */
     void normalize(Vector2* dst);
     void normalize(Vector2* dst);
 
 
@@ -264,7 +263,7 @@ public:
      * Rotates this vector by angle (specified in radians) around the given point.
      * Rotates this vector by angle (specified in radians) around the given point.
      *
      *
      * @param point The point to rotate around.
      * @param point The point to rotate around.
-     * @param angle The angle to rotate by, in radians.
+     * @param angle The angle to rotate by (in radians).
      */
      */
     void rotate(const Vector2& point, float angle);
     void rotate(const Vector2& point, float angle);
 
 
@@ -292,12 +291,15 @@ public:
 
 
     /**
     /**
      * Sets this vector to the directional vector between the specified points.
      * Sets this vector to the directional vector between the specified points.
+     * 
+     * @param p1 The first point.
+     * @param p2 The second point.
      */
      */
     void set(const Vector2& p1, const Vector2& p2);
     void set(const Vector2& p1, const Vector2& p2);
 
 
     /**
     /**
      * Subtracts this vector and the specified vector as (this - v)
      * Subtracts this vector and the specified vector as (this - v)
-     * and stores the result in this.
+     * and stores the result in this vector.
      *
      *
      * @param v The vector to subtract.
      * @param v The vector to subtract.
      */
      */
@@ -313,30 +315,99 @@ public:
      */
      */
     static void subtract(const Vector2& v1, const Vector2& v2, Vector2* dst);
     static void subtract(const Vector2& v1, const Vector2& v2, Vector2* dst);
 
 
-    inline bool operator<(const Vector2& v) const
-    {
-        if (x == v.x)
-        {
-            return y < v.y;
-        }
-        return x < v.x;
-    }
-    inline bool operator==(const Vector2& v) const
-    {
-        return x==v.x && y==v.y;
-    }
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector2 operator+(const Vector2& v);
+
+    /**
+     * Adds the given vector to this vector.
+     * 
+     * @param v The vector to add.
+     * @return This vector, after the addition occurs.
+     */
+    inline Vector2& operator+=(const Vector2& v);
 
 
     /**
     /**
-     * Writes this vector to the binary file stream.
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
      */
      */
-    void writeBinary(FILE* file) const;
+    inline Vector2 operator-(const Vector2& v);
 
 
     /**
     /**
-     * Writes this vector to a text file stream.
+     * Subtracts the given vector from this vector.
+     * 
+     * @param v The vector to subtract.
+     * @return This vector, after the subtraction occurs.
      */
      */
-    void writeText(FILE* file) const;
+    inline Vector2& operator-=(const Vector2& v);
+
+    /**
+     * Calculates the negation of this vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @return The negation of this vector.
+     */
+    inline Vector2 operator-();
+
+    /**
+     * Calculates the scalar product of this vector with the given value.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param x The value to scale by.
+     * @return The scaled vector.
+     */
+    inline Vector2 operator*(float x);
+
+    /**
+     * Scales this vector by the given value.
+     * 
+     * @param x The value to scale by.
+     * @return This vector, after the scale occurs.
+     */
+    inline Vector2& operator*=(float x);
+
+    /**
+     * Determines if this vector is less than the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is less than the given vector, false otherwise.
+     */
+    inline bool operator<(const Vector2& v) const;
+
+    /**
+     * Determines if this vector is equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is equal to the given vector, false otherwise.
+     */
+    inline bool operator==(const Vector2& v) const;
 };
 };
 
 
+/**
+ * Calculates the scalar product of the given vector with the given value.
+ * 
+ * @param x The value to scale by.
+ * @param v The vector to scale.
+ * @return The scaled vector.
+ */
+inline Vector2 operator*(float x, const Vector2& v);
+
 }
 }
 
 
+#include "Vector2.inl"
+
 #endif
 #endif

+ 77 - 0
gameplay-encoder/src/Vector2.inl

@@ -0,0 +1,77 @@
+/** 
+ * Vector2.inl
+ */
+
+#include "Vector2.h"
+
+namespace gameplay
+{
+
+inline Vector2 Vector2::operator+(const Vector2& v)
+{
+    Vector2 result(*this);
+    result.add(v);
+    return result;
+}
+
+inline Vector2& Vector2::operator+=(const Vector2& v)
+{
+    add(v);
+    return *this;
+}
+
+inline Vector2 Vector2::operator-(const Vector2& v)
+{
+    Vector2 result(*this);
+    result.subtract(v);
+    return result;
+}
+
+inline Vector2& Vector2::operator-=(const Vector2& v)
+{
+    subtract(v);
+    return *this;
+}
+
+inline Vector2 Vector2::operator-()
+{
+    Vector2 result(*this);
+    result.negate();
+    return result;
+}
+
+inline Vector2 Vector2::operator*(float x)
+{
+    Vector2 result(*this);
+    result.scale(x);
+    return result;
+}
+
+inline Vector2& Vector2::operator*=(float x)
+{
+    scale(x);
+    return *this;
+}
+
+inline bool Vector2::operator<(const Vector2& v) const
+{
+    if (x == v.x)
+    {
+        return y < v.y;
+    }
+    return x < v.x;
+}
+
+inline bool Vector2::operator==(const Vector2& v) const
+{
+    return x==v.x && y==v.y;
+}
+
+inline Vector2 operator*(float x, const Vector2& v)
+{
+    Vector2 result(v);
+    result.scale(x);
+    return result;
+}
+
+}

+ 34 - 79
gameplay-encoder/src/Vector3.cpp

@@ -1,10 +1,5 @@
-/*
- * Vector3.cpp
- */
-
 #include "Base.h"
 #include "Base.h"
 #include "Vector3.h"
 #include "Vector3.h"
-#include "FileIO.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -14,77 +9,80 @@ Vector3::Vector3()
 {
 {
 }
 }
 
 
-
 Vector3::Vector3(float x, float y, float z)
 Vector3::Vector3(float x, float y, float z)
 {
 {
     set(x, y, z);
     set(x, y, z);
 }
 }
 
 
-
 Vector3::Vector3(float* array)
 Vector3::Vector3(float* array)
 {
 {
     set(array);
     set(array);
 }
 }
 
 
-
 Vector3::Vector3(const Vector3& p1, const Vector3& p2)
 Vector3::Vector3(const Vector3& p1, const Vector3& p2)
 {
 {
     set(p1, p2);
     set(p1, p2);
 }
 }
 
 
-
 Vector3::Vector3(const Vector3& copy)
 Vector3::Vector3(const Vector3& copy)
 {
 {
     set(copy);
     set(copy);
 }
 }
 
 
+Vector3 Vector3::fromColor(unsigned int color)
+{
+    float components[3];
+    int componentIndex = 0;
+    for (int i = 2; i >= 0; --i)
+    {
+        int component = (color >> i*8) & 0x0000ff;
+
+        components[componentIndex++] = static_cast<float>(component) / 255.0f;
+    }
+
+    Vector3 value(components);
+    return value;
+}
 
 
 Vector3::~Vector3()
 Vector3::~Vector3()
 {
 {
 }
 }
 
 
-
 const Vector3& Vector3::zero()
 const Vector3& Vector3::zero()
 {
 {
-    static Vector3* value = new Vector3(0.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector3 value(0.0f, 0.0f, 0.0f);
+    return value;
 }
 }
 
 
-
 const Vector3& Vector3::one()
 const Vector3& Vector3::one()
 {
 {
-    static Vector3* value = new Vector3(1.0f, 1.0f, 1.0f);
-    return *value;
+    static Vector3 value(1.0f, 1.0f, 1.0f);
+    return value;
 }
 }
 
 
-
 const Vector3& Vector3::unitX()
 const Vector3& Vector3::unitX()
 {
 {
-    static Vector3* value = new Vector3(1.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector3 value(1.0f, 0.0f, 0.0f);
+    return value;
 }
 }
 
 
-
 const Vector3& Vector3::unitY()
 const Vector3& Vector3::unitY()
 {
 {
-    static Vector3* value = new Vector3(0.0f, 1.0f, 0.0f);
-    return *value;
+    static Vector3 value(0.0f, 1.0f, 0.0f);
+    return value;
 }
 }
 
 
-
 const Vector3& Vector3::unitZ()
 const Vector3& Vector3::unitZ()
 {
 {
-    static Vector3* value = new Vector3(0.0f, 0.0f, 1.0f);
-    return *value;
+    static Vector3 value(0.0f, 0.0f, 1.0f);
+    return value;
 }
 }
 
 
-
 bool Vector3::isZero() const
 bool Vector3::isZero() const
 {
 {
     return x == 0.0f && y == 0.0f && z == 0.0f;
     return x == 0.0f && y == 0.0f && z == 0.0f;
 }
 }
 
 
-
 bool Vector3::isOne() const
 bool Vector3::isOne() const
 {
 {
     return x == 1.0f && y == 1.0f && z == 1.0f;
     return x == 1.0f && y == 1.0f && z == 1.0f;
@@ -96,10 +94,9 @@ float Vector3::angle(const Vector3& v1, const Vector3& v2)
     float dy = v1.z * v2.x - v1.x * v2.z;
     float dy = v1.z * v2.x - v1.x * v2.z;
     float dz = v1.x * v2.y - v1.y * v2.x;
     float dz = v1.x * v2.y - v1.y * v2.x;
 
 
-    return atan2f(sqrtf(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
+    return atan2f(sqrt(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 }
 
 
-
 void Vector3::add(const Vector3& v)
 void Vector3::add(const Vector3& v)
 {
 {
     x += v.x;
     x += v.x;
@@ -107,7 +104,6 @@ void Vector3::add(const Vector3& v)
     z += v.z;
     z += v.z;
 }
 }
 
 
-
 void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
 void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -117,7 +113,6 @@ void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = v1.z + v2.z;
     dst->z = v1.z + v2.z;
 }
 }
 
 
-
 void Vector3::clamp(const Vector3& min, const Vector3& max)
 void Vector3::clamp(const Vector3& min, const Vector3& max)
 {
 {
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z));
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z));
@@ -141,13 +136,12 @@ void Vector3::clamp(const Vector3& min, const Vector3& max)
         z = max.z;
         z = max.z;
 }
 }
 
 
-
 void Vector3::clamp(const Vector3& v, const Vector3& min, const Vector3& max, Vector3* dst)
 void Vector3::clamp(const Vector3& v, const Vector3& min, const Vector3& max, Vector3* dst)
 {
 {
     assert(dst);
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z));
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z));
 
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     dst->x = v.x;
     if ( dst->x < min.x )
     if ( dst->x < min.x )
         dst->x = min.x;
         dst->x = min.x;
@@ -169,7 +163,6 @@ void Vector3::clamp(const Vector3& v, const Vector3& min, const Vector3& max, Ve
         dst->z = max.z;
         dst->z = max.z;
 }
 }
 
 
-
 void Vector3::cross(const Vector3& v)
 void Vector3::cross(const Vector3& v)
 {
 {
     float tx = (y * v.z) - (z * v.y);
     float tx = (y * v.z) - (z * v.y);
@@ -180,7 +173,6 @@ void Vector3::cross(const Vector3& v)
     z = tz;
     z = tz;
 }
 }
 
 
-
 void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
 void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -193,18 +185,16 @@ void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = z;
     dst->z = z;
 }
 }
 
 
-
-float Vector3::distance(const Vector3& v)
+float Vector3::distance(const Vector3& v) const
 {
 {
     float dx = v.x - x;
     float dx = v.x - x;
     float dy = v.y - y;
     float dy = v.y - y;
     float dz = v.z - z;
     float dz = v.z - z;
 
 
-    return sqrtf(dx * dx + dy * dy + dz * dz);
+    return sqrt(dx * dx + dy * dy + dz * dz);
 }
 }
 
 
-
-float Vector3::distanceSquared(const Vector3& v)
+float Vector3::distanceSquared(const Vector3& v) const
 {
 {
     float dx = v.x - x;
     float dx = v.x - x;
     float dy = v.y - y;
     float dy = v.y - y;
@@ -213,31 +203,26 @@ float Vector3::distanceSquared(const Vector3& v)
     return (dx * dx + dy * dy + dz * dz);
     return (dx * dx + dy * dy + dz * dz);
 }
 }
 
 
-
 float Vector3::dot(const Vector3& v)
 float Vector3::dot(const Vector3& v)
 {
 {
     return (x * v.x + y * v.y + z * v.z);
     return (x * v.x + y * v.y + z * v.z);
 }
 }
 
 
-
 float Vector3::dot(const Vector3& v1, const Vector3& v2)
 float Vector3::dot(const Vector3& v1, const Vector3& v2)
 {
 {
     return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
     return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
 }
 }
 
 
-
-float Vector3::length()
+float Vector3::length() const
 {
 {
-    return sqrtf(x * x + y * y + z * z);
+    return sqrt(x * x + y * y + z * z);
 }
 }
 
 
-
-float Vector3::lengthSquared()
+float Vector3::lengthSquared() const
 {
 {
     return (x * x + y * y + z * z);
     return (x * x + y * y + z * z);
 }
 }
 
 
-
 void Vector3::negate()
 void Vector3::negate()
 {
 {
     x = -x;
     x = -x;
@@ -245,13 +230,11 @@ void Vector3::negate()
     z = -z;
     z = -z;
 }
 }
 
 
-
 void Vector3::normalize()
 void Vector3::normalize()
 {
 {
     normalize(this);
     normalize(this);
 }
 }
 
 
-
 void Vector3::normalize(Vector3* dst) const
 void Vector3::normalize(Vector3* dst) const
 {
 {
     assert(dst);
     assert(dst);
@@ -264,12 +247,12 @@ void Vector3::normalize(Vector3* dst) const
     }
     }
 
 
     float n = x * x + y * y + z * z;
     float n = x * x + y * y + z * z;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
     if (n == 1.0f)
         return;
         return;
 
 
     n = sqrt(n);
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
     if (n < MATH_TOLERANCE)
         return;
         return;
 
 
@@ -279,7 +262,6 @@ void Vector3::normalize(Vector3* dst) const
     dst->z *= n;
     dst->z *= n;
 }
 }
 
 
-
 void Vector3::scale(float scalar)
 void Vector3::scale(float scalar)
 {
 {
     x *= scalar;
     x *= scalar;
@@ -287,7 +269,6 @@ void Vector3::scale(float scalar)
     z *= scalar;
     z *= scalar;
 }
 }
 
 
-
 void Vector3::set(float x, float y, float z)
 void Vector3::set(float x, float y, float z)
 {
 {
     this->x = x;
     this->x = x;
@@ -295,7 +276,6 @@ void Vector3::set(float x, float y, float z)
     this->z = z;
     this->z = z;
 }
 }
 
 
-
 void Vector3::set(float* array)
 void Vector3::set(float* array)
 {
 {
     assert(array);
     assert(array);
@@ -305,7 +285,6 @@ void Vector3::set(float* array)
     z = array[2];
     z = array[2];
 }
 }
 
 
-
 void Vector3::set(const Vector3& v)
 void Vector3::set(const Vector3& v)
 {
 {
     this->x = v.x;
     this->x = v.x;
@@ -313,7 +292,6 @@ void Vector3::set(const Vector3& v)
     this->z = v.z;
     this->z = v.z;
 }
 }
 
 
-
 void Vector3::set(const Vector3& p1, const Vector3& p2)
 void Vector3::set(const Vector3& p1, const Vector3& p2)
 {
 {
     x = p2.x - p1.x;
     x = p2.x - p1.x;
@@ -321,7 +299,6 @@ void Vector3::set(const Vector3& p1, const Vector3& p2)
     z = p2.z - p1.z;
     z = p2.z - p1.z;
 }
 }
 
 
-
 void Vector3::subtract(const Vector3& v)
 void Vector3::subtract(const Vector3& v)
 {
 {
     x -= v.x;
     x -= v.x;
@@ -329,7 +306,6 @@ void Vector3::subtract(const Vector3& v)
     z -= v.z;
     z -= v.z;
 }
 }
 
 
-
 void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
 void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -339,25 +315,4 @@ void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = v1.z - v2.z;
     dst->z = v1.z - v2.z;
 }
 }
 
 
-float Vector3::distanceSquared(const Vector3& v1, const Vector3& v2)
-{
-    float dx = v2.x - v1.x;
-    float dy = v2.y - v1.y;
-    float dz = v2.z - v1.z;
-
-    return (dx * dx + dy * dy + dz * dz);
-}
-
-void Vector3::writeBinary(FILE* file) const
-{
-    write(x, file);
-    write(y, file);
-    write(z, file);
-}
-
-void Vector3::writeText(FILE* file) const
-{
-    fprintf(file, "%f %f %f\n", x, y, z);
-}
-
 }
 }

+ 115 - 44
gameplay-encoder/src/Vector3.h

@@ -1,15 +1,9 @@
-/*
- * Vector3.h
- */
-
 #ifndef VECTOR3_H_
 #ifndef VECTOR3_H_
 #define VECTOR3_H_
 #define VECTOR3_H_
 
 
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-// Forward declare
 class Matrix;
 class Matrix;
 class Quaternion;
 class Quaternion;
 
 
@@ -19,7 +13,7 @@ class Quaternion;
  * When using a vector to represent a surface normal,
  * When using a vector to represent a surface normal,
  * the vector should typically be normalized.
  * the vector should typically be normalized.
  * Other uses of directional vectors may wish to leave
  * Other uses of directional vectors may wish to leave
- * the magnitude of the vector in-tact. When used as a point,
+ * the magnitude of the vector intact. When used as a point,
  * the elements of the vector represent a position in 3D space.
  * the elements of the vector represent a position in 3D space.
  */
  */
 class Vector3
 class Vector3
@@ -77,57 +71,67 @@ public:
      */
      */
     Vector3(const Vector3& copy);
     Vector3(const Vector3& copy);
 
 
+    /**
+     * Creates a new vector from an integer interpreted as an RGB value.
+     * E.g. 0xff0000 represents red or the vector (1, 0, 0).
+     *
+     * @param color The integer to interpret as an RGB value.
+     *
+     * @return A vector corresponding to the interpreted RGB color.
+     */
+    static Vector3 fromColor(unsigned int color);
+
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
     ~Vector3();
     ~Vector3();
 
 
     /**
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      *
      * @return The 3-element vector of 0s.
      * @return The 3-element vector of 0s.
      */
      */
     static const Vector3& zero();
     static const Vector3& zero();
 
 
     /**
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      *
      * @return The 3-element vector of 1s.
      * @return The 3-element vector of 1s.
      */
      */
     static const Vector3& one();
     static const Vector3& one();
 
 
     /**
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      *
      * @return The 3-element unit vector along the x axis.
      * @return The 3-element unit vector along the x axis.
      */
      */
     static const Vector3& unitX();
     static const Vector3& unitX();
 
 
     /**
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      *
      * @return The 3-element unit vector along the y axis.
      * @return The 3-element unit vector along the y axis.
      */
      */
     static const Vector3& unitY();
     static const Vector3& unitY();
 
 
     /**
     /**
-     * The unit z vector.
+     * Returns the unit z vector.
      *
      *
      * @return The 3-element unit vector along the z axis.
      * @return The 3-element unit vector along the z axis.
      */
      */
     static const Vector3& unitZ();
     static const Vector3& unitZ();
 
 
     /**
     /**
-     * Is this vector the all zeros.
+     * Indicates whether this vector contains all zeros.
      *
      *
-     * @return true if all zeros, false if otherwise.
+     * @return true if this vector contains all zeros, false otherwise.
      */
      */
     bool isZero() const;
     bool isZero() const;
 
 
     /**
     /**
-     * Is this vector all ones.
+     * Indicates whether this vector contains all ones.
      *
      *
-     * @return true if all ones, false if otherwise.
+     * @return true if this vector contains all ones, false otherwise.
      */
      */
     bool isOne() const;
     bool isOne() const;
 
 
@@ -137,7 +141,7 @@ public:
      * @param v1 The first vector.
      * @param v1 The first vector.
      * @param v2 The second vector.
      * @param v2 The second vector.
      * 
      * 
-     * @return The angle between the two vectors, in radians.
+     * @return The angle between the two vectors (in radians).
      */
      */
     static float angle(const Vector3& v1, const Vector3& v2);
     static float angle(const Vector3& v1, const Vector3& v2);
 
 
@@ -179,7 +183,7 @@ public:
     /**
     /**
      * Sets this vector to the cross product between itself and the specified vector.
      * Sets this vector to the cross product between itself and the specified vector.
      *
      *
-     * @param v the vector to compute the cross product with.
+     * @param v The vector to compute the cross product with.
      */
      */
     void cross(const Vector3& v);
     void cross(const Vector3& v);
 
 
@@ -198,9 +202,10 @@ public:
      * @param v The other vector.
      * @param v The other vector.
      * 
      * 
      * @return The distance between this vector and v.
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      * @see distanceSquared
      */
      */
-    float distance(const Vector3& v);
+    float distance(const Vector3& v) const;
 
 
     /**
     /**
      * Returns the squared distance between this vector and v.
      * Returns the squared distance between this vector and v.
@@ -213,9 +218,10 @@ public:
      * @param v The other vector.
      * @param v The other vector.
      * 
      * 
      * @return The squared distance between this vector and v.
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      * @see distance
      */
      */
-    float distanceSquared(const Vector3& v);
+    float distanceSquared(const Vector3& v) const;
 
 
     /**
     /**
      * Returns the dot product of this vector and the specified vector.
      * Returns the dot product of this vector and the specified vector.
@@ -240,9 +246,10 @@ public:
      * Computes the length of this vector.
      * Computes the length of this vector.
      *
      *
      * @return The length of the vector.
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      * @see lengthSquared
      */
      */
-    float length();
+    float length() const;
 
 
     /**
     /**
      * Returns the squared length of this vector.
      * Returns the squared length of this vector.
@@ -253,9 +260,10 @@ public:
      * instead of length.
      * instead of length.
      *
      *
      * @return The squared length of the vector.
      * @return The squared length of the vector.
+     * 
      * @see length
      * @see length
      */
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
 
     /**
     /**
      * Negates this vector.
      * Negates this vector.
@@ -280,7 +288,7 @@ public:
      * of the vector is zero, this method simply copies the
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      * current vector into dst.
      *
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
      */
     void normalize(Vector3* dst) const;
     void normalize(Vector3* dst) const;
 
 
@@ -321,7 +329,7 @@ public:
 
 
     /**
     /**
      * Subtracts this vector and the specified vector as (this - v)
      * Subtracts this vector and the specified vector as (this - v)
-     * and stores the result in this.
+     * and stores the result in this vector.
      *
      *
      * @param v The vector to subtract.
      * @param v The vector to subtract.
      */
      */
@@ -337,36 +345,99 @@ public:
      */
      */
     static void subtract(const Vector3& v1, const Vector3& v2, Vector3* dst);
     static void subtract(const Vector3& v1, const Vector3& v2, Vector3* dst);
 
 
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector3 operator+(const Vector3& v);
+
+    /**
+     * Adds the given vector to this vector.
+     * 
+     * @param v The vector to add.
+     * @return This vector, after the addition occurs.
+     */
+    inline Vector3& operator+=(const Vector3& v);
+
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector3 operator-(const Vector3& v);
 
 
+    /**
+     * Subtracts the given vector from this vector.
+     * 
+     * @param v The vector to subtract.
+     * @return This vector, after the subtraction occurs.
+     */
+    inline Vector3& operator-=(const Vector3& v);
 
 
-    inline bool operator<(const Vector3& v) const
-    {
-        if (x == v.x)
-        {
-            if (y == v.y)
-            {
-                return z < v.z;
-            }
-            return y < v.y;
-        }
-        return x < v.x;
-    }
+    /**
+     * Calculates the negation of this vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @return The negation of this vector.
+     */
+    inline Vector3 operator-();
 
 
-    inline bool operator==(const Vector3& v) const
-    {
-        return x==v.x && y==v.y && z==v.z;
-    }
+    /**
+     * Calculates the scalar product of this vector with the given value.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param x The value to scale by.
+     * @return The scaled vector.
+     */
+    inline Vector3 operator*(float x);
 
 
-    static float distanceSquared(const Vector3& v1, const Vector3& v2);
+    /**
+     * Scales this vector by the given value.
+     * 
+     * @param x The value to scale by.
+     * @return This vector, after the scale occurs.
+     */
+    inline Vector3& operator*=(float x);
 
 
     /**
     /**
-     * Writes this vector to the binary file stream.
+     * Determines if this vector is less than the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is less than the given vector, false otherwise.
      */
      */
-    void writeBinary(FILE* file) const;
+    inline bool operator<(const Vector3& v) const;
 
 
-    void writeText(FILE* file) const;
+    /**
+     * Determines if this vector is equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is equal to the given vector, false otherwise.
+     */
+    inline bool operator==(const Vector3& v) const;
 };
 };
 
 
+/**
+ * Calculates the scalar product of the given vector with the given value.
+ * 
+ * @param x The value to scale by.
+ * @param v The vector to scale.
+ * @return The scaled vector.
+ */
+inline Vector3 operator*(float x, const Vector3& v);
+
 }
 }
 
 
+#include "Vector3.inl"
+
 #endif
 #endif

+ 82 - 0
gameplay-encoder/src/Vector3.inl

@@ -0,0 +1,82 @@
+/** 
+ * Vector3.inl
+ */
+
+#include "Vector3.h"
+#include "Matrix.h"
+
+namespace gameplay
+{
+
+inline Vector3 Vector3::operator+(const Vector3& v)
+{
+    Vector3 result(*this);
+    result.add(v);
+    return result;
+}
+
+inline Vector3& Vector3::operator+=(const Vector3& v)
+{
+    add(v);
+    return *this;
+}
+
+inline Vector3 Vector3::operator-(const Vector3& v)
+{
+    Vector3 result(*this);
+    result.subtract(v);
+    return result;
+}
+
+inline Vector3& Vector3::operator-=(const Vector3& v)
+{
+    subtract(v);
+    return *this;
+}
+
+inline Vector3 Vector3::operator-()
+{
+    Vector3 result(*this);
+    result.negate();
+    return result;
+}
+
+inline Vector3 Vector3::operator*(float x)
+{
+    Vector3 result(*this);
+    result.scale(x);
+    return result;
+}
+
+inline Vector3& Vector3::operator*=(float x)
+{
+    scale(x);
+    return *this;
+}
+
+inline bool Vector3::operator<(const Vector3& v) const
+{
+    if (x == v.x)
+    {
+        if (y == v.y)
+        {
+            return z < v.z;
+        }
+        return y < v.y;
+    }
+    return x < v.x;
+}
+
+inline bool Vector3::operator==(const Vector3& v) const
+{
+    return x==v.x && y==v.y && z==v.z;
+}
+
+inline Vector3 operator*(float x, const Vector3& v)
+{
+    Vector3 result(v);
+    result.scale(x);
+    return result;
+}
+
+}

+ 36 - 72
gameplay-encoder/src/Vector4.cpp

@@ -1,10 +1,5 @@
-/*
- * Vector4.cpp
- */
-
 #include "Base.h"
 #include "Base.h"
 #include "Vector4.h"
 #include "Vector4.h"
-#include "FileIO.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -14,100 +9,100 @@ Vector4::Vector4()
 {
 {
 }
 }
 
 
-
 Vector4::Vector4(float x, float y, float z, float w)
 Vector4::Vector4(float x, float y, float z, float w)
 {
 {
     set(x, y, z, w);
     set(x, y, z, w);
 }
 }
 
 
-
 Vector4::Vector4(float* src)
 Vector4::Vector4(float* src)
 {
 {
     set(src);
     set(src);
 }
 }
 
 
-
 Vector4::Vector4(const Vector4& p1, const Vector4& p2)
 Vector4::Vector4(const Vector4& p1, const Vector4& p2)
 {
 {
     set(p1, p2);
     set(p1, p2);
 }
 }
 
 
-
 Vector4::Vector4(const Vector4& copy)
 Vector4::Vector4(const Vector4& copy)
 {
 {
     set(copy);
     set(copy);
 }
 }
 
 
+Vector4 Vector4::fromColor(unsigned int color)
+{
+    float components[4];
+    int componentIndex = 0;
+    for (int i = 3; i >= 0; --i)
+    {
+        int component = (color >> i*8) & 0x000000ff;
+
+        components[componentIndex++] = static_cast<float>(component) / 255.0f;
+    }
+
+    Vector4 value(components);
+    return value;
+}
 
 
 Vector4::~Vector4()
 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
 {
 {
     return x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f;
     return x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f;
 }
 }
 
 
-
 bool Vector4::isOne() const
 bool Vector4::isOne() const
 {
 {
     return x == 1.0f && y == 1.0f && z == 1.0f && z == 1.0f;
     return x == 1.0f && y == 1.0f && z == 1.0f && z == 1.0f;
 }
 }
 
 
-
 float Vector4::angle(const Vector4& v1, const Vector4& v2)
 float Vector4::angle(const Vector4& v1, const Vector4& v2)
 {
 {
     float dx = v1.w * v2.x - v1.x * v2.w - v1.y * v2.z + v1.z * v2.y;
     float dx = v1.w * v2.x - v1.x * v2.w - v1.y * v2.z + v1.z * v2.y;
     float dy = v1.w * v2.y - v1.y * v2.w - v1.z * v2.x + v1.x * v2.z;
     float dy = v1.w * v2.y - v1.y * v2.w - v1.z * v2.x + v1.x * v2.z;
     float dz = v1.w * v2.z - v1.z * v2.w - v1.x * v2.y + v1.y * v2.x;
     float dz = v1.w * v2.z - v1.z * v2.w - v1.x * v2.y + v1.y * v2.x;
 
 
-    return atan2f(sqrtf(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
+    return atan2f(sqrt(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 }
 
 
-
 void Vector4::add(const Vector4& v)
 void Vector4::add(const Vector4& v)
 {
 {
     x += v.x;
     x += v.x;
@@ -116,7 +111,6 @@ void Vector4::add(const Vector4& v)
     w += v.w;
     w += v.w;
 }
 }
 
 
-
 void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
 void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -127,7 +121,6 @@ void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
     dst->w = v1.w + v2.w;
     dst->w = v1.w + v2.w;
 }
 }
 
 
-
 void Vector4::clamp(const Vector4& min, const Vector4& max)
 void Vector4::clamp(const Vector4& min, const Vector4& max)
 {
 {
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z || min.w > max.w));
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z || min.w > max.w));
@@ -157,13 +150,12 @@ void Vector4::clamp(const Vector4& min, const Vector4& max)
         w = max.w;
         w = max.w;
 }
 }
 
 
-
 void Vector4::clamp(const Vector4& v, const Vector4& min, const Vector4& max, Vector4* dst)
 void Vector4::clamp(const Vector4& v, const Vector4& min, const Vector4& max, Vector4* dst)
 {
 {
     assert(dst);
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z || min.w > max.w));
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z || min.w > max.w));
 
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     dst->x = v.x;
     if ( dst->x < min.x )
     if ( dst->x < min.x )
         dst->x = min.x;
         dst->x = min.x;
@@ -192,19 +184,17 @@ void Vector4::clamp(const Vector4& v, const Vector4& min, const Vector4& max, Ve
         dst->w = max.w;
         dst->w = max.w;
 }
 }
 
 
-
-float Vector4::distance(const Vector4& v)
+float Vector4::distance(const Vector4& v) const
 {
 {
     float dx = v.x - x;
     float dx = v.x - x;
     float dy = v.y - y;
     float dy = v.y - y;
     float dz = v.z - z;
     float dz = v.z - z;
     float dw = v.w - w;
     float dw = v.w - w;
 
 
-    return sqrtf(dx * dx + dy * dy + dz * dz + dw * dw);
+    return sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
 }
 }
 
 
-
-float Vector4::distanceSquared(const Vector4& v)
+float Vector4::distanceSquared(const Vector4& v) const
 {
 {
     float dx = v.x - x;
     float dx = v.x - x;
     float dy = v.y - y;
     float dy = v.y - y;
@@ -214,31 +204,27 @@ float Vector4::distanceSquared(const Vector4& v)
     return (dx * dx + dy * dy + dz * dz + dw * dw);
     return (dx * dx + dy * dy + dz * dz + dw * dw);
 }
 }
 
 
-
 float Vector4::dot(const Vector4& v)
 float Vector4::dot(const Vector4& v)
 {
 {
     return (x * v.x + y * v.y + z * v.z + w * v.w);
     return (x * v.x + y * v.y + z * v.z + w * v.w);
 }
 }
 
 
-
 float Vector4::dot(const Vector4& v1, const Vector4& v2)
 float Vector4::dot(const Vector4& v1, const Vector4& v2)
 {
 {
     return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
     return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
 }
 }
 
 
-
-float Vector4::length()
+float Vector4::length() const
 {
 {
-    return sqrtf(x * x + y * y + z * z + w * w);
+    return sqrt(x * x + y * y + z * z + w * w);
 }
 }
 
 
 
 
-float Vector4::lengthSquared()
+float Vector4::lengthSquared() const
 {
 {
     return (x * x + y * y + z * z + w * w);
     return (x * x + y * y + z * z + w * w);
 }
 }
 
 
-
 void Vector4::negate()
 void Vector4::negate()
 {
 {
     x = -x;
     x = -x;
@@ -247,13 +233,11 @@ void Vector4::negate()
     w = -w;
     w = -w;
 }
 }
 
 
-
 void Vector4::normalize()
 void Vector4::normalize()
 {
 {
     normalize(this);
     normalize(this);
 }
 }
 
 
-
 void Vector4::normalize(Vector4* dst)
 void Vector4::normalize(Vector4* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -267,12 +251,12 @@ void Vector4::normalize(Vector4* dst)
     }
     }
 
 
     float n = x * x + y * y + z * z + w * w;
     float n = x * x + y * y + z * z + w * w;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
     if (n == 1.0f)
         return;
         return;
 
 
     n = sqrt(n);
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
     if (n < MATH_TOLERANCE)
         return;
         return;
 
 
@@ -283,7 +267,6 @@ void Vector4::normalize(Vector4* dst)
     dst->w *= n;
     dst->w *= n;
 }
 }
 
 
-
 void Vector4::scale(float scalar)
 void Vector4::scale(float scalar)
 {
 {
     x *= scalar;
     x *= scalar;
@@ -292,7 +275,6 @@ void Vector4::scale(float scalar)
     w *= scalar;
     w *= scalar;
 }
 }
 
 
-
 void Vector4::set(float x, float y, float z, float w)
 void Vector4::set(float x, float y, float z, float w)
 {
 {
     this->x = x;
     this->x = x;
@@ -301,7 +283,6 @@ void Vector4::set(float x, float y, float z, float w)
     this->w = w;
     this->w = w;
 }
 }
 
 
-
 void Vector4::set(float* array)
 void Vector4::set(float* array)
 {
 {
     assert(array);
     assert(array);
@@ -312,7 +293,6 @@ void Vector4::set(float* array)
     w = array[3];
     w = array[3];
 }
 }
 
 
-
 void Vector4::set(const Vector4& v)
 void Vector4::set(const Vector4& v)
 {
 {
     this->x = v.x;
     this->x = v.x;
@@ -321,7 +301,6 @@ void Vector4::set(const Vector4& v)
     this->w = v.w;
     this->w = v.w;
 }
 }
 
 
-
 void Vector4::set(const Vector4& p1, const Vector4& p2)
 void Vector4::set(const Vector4& p1, const Vector4& p2)
 {
 {
     x = p2.x - p1.x;
     x = p2.x - p1.x;
@@ -330,7 +309,6 @@ void Vector4::set(const Vector4& p1, const Vector4& p2)
     w = p2.w - p1.w;
     w = p2.w - p1.w;
 }
 }
 
 
-
 void Vector4::subtract(const Vector4& v)
 void Vector4::subtract(const Vector4& v)
 {
 {
     x -= v.x;
     x -= v.x;
@@ -339,7 +317,6 @@ void Vector4::subtract(const Vector4& v)
     w -= v.w;
     w -= v.w;
 }
 }
 
 
-
 void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
 void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -350,17 +327,4 @@ void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
     dst->w = v1.w - v2.w;
     dst->w = v1.w - v2.w;
 }
 }
 
 
-void Vector4::writeBinary(FILE* file) const
-{
-    write(x, file);
-    write(y, file);
-    write(z, file);
-    write(w, file);
-}
-
-void Vector4::writeText(FILE* file) const
-{
-    fprintf(file, "%f %f %f %f\n", x, y, z, w);
-}
-
 }
 }

+ 119 - 51
gameplay-encoder/src/Vector4.h

@@ -1,16 +1,9 @@
-/*
- * Vector4.h
- */
-
 #ifndef VECTOR4_H_
 #ifndef VECTOR4_H_
 #define VECTOR4_H_
 #define VECTOR4_H_
 
 
-#include "FileIO.h"
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
-// Forward declare
 class Matrix;
 class Matrix;
 
 
 /**
 /**
@@ -79,64 +72,74 @@ public:
      */
      */
     Vector4(const Vector4& copy);
     Vector4(const Vector4& copy);
 
 
+    /**
+     * Creates a new vector from an integer interpreted as an RGBA value.
+     * E.g. 0xff0000ff represents opaque red or the vector (1, 0, 0, 1).
+     *
+     * @param color The integer to interpret as an RGBA value.
+     *
+     * @return A vector corresponding to the interpreted RGBA color.
+     */
+    static Vector4 fromColor(unsigned int color);
+
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
     ~Vector4();
     ~Vector4();
 
 
     /**
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      *
      * @return The 4-element vector of 0s.
      * @return The 4-element vector of 0s.
      */
      */
     static const Vector4& zero();
     static const Vector4& zero();
 
 
     /**
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      *
      * @return The 4-element vector of 1s.
      * @return The 4-element vector of 1s.
      */
      */
     static const Vector4& one();
     static const Vector4& one();
 
 
     /**
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      *
      * @return The 4-element unit vector along the x axis.
      * @return The 4-element unit vector along the x axis.
      */
      */
     static const Vector4& unitX();
     static const Vector4& unitX();
 
 
     /**
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      *
      * @return The 4-element unit vector along the y axis.
      * @return The 4-element unit vector along the y axis.
      */
      */
     static const Vector4& unitY();
     static const Vector4& unitY();
 
 
     /**
     /**
-     * The unit z vector.
+     * Returns the unit z vector.
      *
      *
      * @return The 4-element unit vector along the z axis.
      * @return The 4-element unit vector along the z axis.
      */
      */
     static const Vector4& unitZ();
     static const Vector4& unitZ();
 
 
     /**
     /**
-     * The unit w vector.
+     * Returns the unit w vector.
      *
      *
      * @return The 4-element unit vector along the w axis.
      * @return The 4-element unit vector along the w axis.
      */
      */
     static const Vector4& unitW();
     static const Vector4& unitW();
 
 
     /**
     /**
-     * Is this vector the all zeros.
+     * Indicates whether this vector contains all zeros.
      *
      *
-     * @return true if all zeros, false if otherwise.
+     * @return true if this vector contains all zeros, false otherwise.
      */
      */
     bool isZero() const;
     bool isZero() const;
 
 
     /**
     /**
-     * Is this vector all ones.
+     * Indicates whether this vector contains all ones.
      *
      *
-     * @return true if all ones, false if otherwise.
+     * @return true if this vector contains all ones, false otherwise.
      */
      */
     bool isOne() const;
     bool isOne() const;
 
 
@@ -146,7 +149,7 @@ public:
      * @param v1 The first vector.
      * @param v1 The first vector.
      * @param v2 The second vector.
      * @param v2 The second vector.
      * 
      * 
-     * @return The angle between the two vectors, in radians.
+     * @return The angle between the two vectors (in radians).
      */
      */
     static float angle(const Vector4& v1, const Vector4& v2);
     static float angle(const Vector4& v1, const Vector4& v2);
 
 
@@ -190,9 +193,10 @@ public:
      * @param v The other vector.
      * @param v The other vector.
      * 
      * 
      * @return The distance between this vector and v.
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      * @see distanceSquared
      */
      */
-    float distance(const Vector4& v);
+    float distance(const Vector4& v) const;
 
 
     /**
     /**
      * Returns the squared distance between this vector and v.
      * Returns the squared distance between this vector and v.
@@ -205,9 +209,10 @@ public:
      * @param v The other vector.
      * @param v The other vector.
      * 
      * 
      * @return The squared distance between this vector and v.
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      * @see distance
      */
      */
-    float distanceSquared(const Vector4& v);
+    float distanceSquared(const Vector4& v) const;
 
 
     /**
     /**
      * Returns the dot product of this vector and the specified vector.
      * Returns the dot product of this vector and the specified vector.
@@ -232,9 +237,10 @@ public:
      * Computes the length of this vector.
      * Computes the length of this vector.
      *
      *
      * @return The length of the vector.
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      * @see lengthSquared
      */
      */
-    float length();
+    float length() const;
 
 
     /**
     /**
      * Returns the squared length of this vector.
      * Returns the squared length of this vector.
@@ -245,9 +251,10 @@ public:
      * instead of length.
      * instead of length.
      *
      *
      * @return The squared length of the vector.
      * @return The squared length of the vector.
+     * 
      * @see length
      * @see length
      */
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
 
     /**
     /**
      * Negates this vector.
      * Negates this vector.
@@ -272,7 +279,7 @@ public:
      * of the vector is zero, this method simply copies the
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      * current vector into dst.
      *
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
      */
     void normalize(Vector4* dst);
     void normalize(Vector4* dst);
 
 
@@ -309,12 +316,15 @@ public:
 
 
     /**
     /**
      * Sets this vector to the directional vector between the specified points.
      * Sets this vector to the directional vector between the specified points.
+     * 
+     * @param p1 The first point.
+     * @param p2 The second point.
      */
      */
     void set(const Vector4& p1, const Vector4& p2);
     void set(const Vector4& p1, const Vector4& p2);
 
 
     /**
     /**
      * Subtracts this vector and the specified vector as (this - v)
      * Subtracts this vector and the specified vector as (this - v)
-     * and stores the result in this.
+     * and stores the result in this vector.
      *
      *
      * @param v The vector to subtract.
      * @param v The vector to subtract.
      */
      */
@@ -330,41 +340,99 @@ public:
      */
      */
     static void subtract(const Vector4& v1, const Vector4& v2, Vector4* dst);
     static void subtract(const Vector4& v1, const Vector4& v2, Vector4* dst);
 
 
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector4 operator+(const Vector4& v);
+
+    /**
+     * Adds the given vector to this vector.
+     * 
+     * @param v The vector to add.
+     * @return This vector, after the addition occurs.
+     */
+    inline Vector4& operator+=(const Vector4& v);
+
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector4 operator-(const Vector4& v);
+
+    /**
+     * Subtracts the given vector from this vector.
+     * 
+     * @param v The vector to subtract.
+     * @return This vector, after the subtraction occurs.
+     */
+    inline Vector4& operator-=(const Vector4& v);
 
 
+    /**
+     * Calculates the negation of this vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @return The negation of this vector.
+     */
+    inline Vector4 operator-();
 
 
-    inline bool operator<(const Vector4& v) const
-    {
-        if (x == v.x)
-        {
-            if (y == v.y)
-            {
-                if (z < v.z)
-                {
-                    if (w < v.w)
-                    {
-                        return w < v.w;
-                    }
-                }
-                return z < v.z;
-            }
-            return y < v.y;
-        }
-        return x < v.x;
-    }
+    /**
+     * Calculates the scalar product of this vector with the given value.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param x The value to scale by.
+     * @return The scaled vector.
+     */
+    inline Vector4 operator*(float x);
 
 
-    inline bool operator==(const Vector4& v) const
-    {
-        return x==v.x && y==v.y && z==v.z && w==v.w;
-    }
+    /**
+     * Scales this vector by the given value.
+     * 
+     * @param x The value to scale by.
+     * @return This vector, after the scale occurs.
+     */
+    inline Vector4& operator*=(float x);
 
 
     /**
     /**
-     * Writes this vector to the binary file stream.
+     * Determines if this vector is less than the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is less than the given vector, false otherwise.
      */
      */
-    void writeBinary(FILE* file) const;
+    inline bool operator<(const Vector4& v) const;
 
 
-    void writeText(FILE* file) const;
+    /**
+     * Determines if this vector is equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is equal to the given vector, false otherwise.
+     */
+    inline bool operator==(const Vector4& v) const;
 };
 };
 
 
+/**
+ * Calculates the scalar product of the given vector with the given value.
+ * 
+ * @param x The value to scale by.
+ * @param v The vector to scale.
+ * @return The scaled vector.
+ */
+inline Vector4 operator*(float x, const Vector4& v);
+
 }
 }
 
 
-#endif
+#include "Vector4.inl"
+
+#endif

+ 89 - 0
gameplay-encoder/src/Vector4.inl

@@ -0,0 +1,89 @@
+/** 
+ * Vector4.inl
+ */
+
+#include "Matrix.h"
+#include "Vector4.h"
+
+namespace gameplay
+{
+
+inline Vector4 Vector4::operator+(const Vector4& v)
+{
+    Vector4 result(*this);
+    result.add(v);
+    return result;
+}
+
+inline Vector4& Vector4::operator+=(const Vector4& v)
+{
+    add(v);
+    return *this;
+}
+
+inline Vector4 Vector4::operator-(const Vector4& v)
+{
+    Vector4 result(*this);
+    result.subtract(v);
+    return result;
+}
+
+inline Vector4& Vector4::operator-=(const Vector4& v)
+{
+    subtract(v);
+    return *this;
+}
+
+inline Vector4 Vector4::operator-()
+{
+    Vector4 result(*this);
+    result.negate();
+    return result;
+}
+
+inline Vector4 Vector4::operator*(float x)
+{
+    Vector4 result(*this);
+    result.scale(x);
+    return result;
+}
+
+inline Vector4& Vector4::operator*=(float x)
+{
+    scale(x);
+    return *this;
+}
+
+inline bool Vector4::operator<(const Vector4& v) const
+{
+    if (x == v.x)
+    {
+        if (y == v.y)
+        {
+            if (z < v.z)
+            {
+                if (w < v.w)
+                {
+                    return w < v.w;
+                }
+            }
+            return z < v.z;
+        }
+        return y < v.y;
+    }
+    return x < v.x;
+}
+
+inline bool Vector4::operator==(const Vector4& v) const
+{
+    return x==v.x && y==v.y && z==v.z && w==v.w;
+}
+
+inline Vector4 operator*(float x, const Vector4& v)
+{
+    Vector4 result(v);
+    result.scale(x);
+    return result;
+}
+
+}

+ 30 - 27
gameplay-encoder/src/Vertex.cpp

@@ -1,27 +1,18 @@
+#include "Base.h"
 #include "Vertex.h"
 #include "Vertex.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 Vertex::Vertex(void)
 Vertex::Vertex(void)
+    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasColor(false), hasWeights(false)
 {
 {
-    reset();
 }
 }
 
 
 Vertex::~Vertex(void)
 Vertex::~Vertex(void)
 {
 {
 }
 }
 
 
-void Vertex::reset()
-{
-    hasNormal = false;
-    hasTangent = false;
-    hasBinormal = false;
-    hasTexCoord = false;
-    hasColor = false;
-    hasWeights = false;
-}
-
 unsigned int Vertex::byteSize() const
 unsigned int Vertex::byteSize() const
 {
 {
     unsigned int count = 3;
     unsigned int count = 3;
@@ -40,66 +31,78 @@ unsigned int Vertex::byteSize() const
 
 
 void Vertex::writeBinary(FILE* file) const
 void Vertex::writeBinary(FILE* file) const
 {
 {
-    position.writeBinary(file);
+    writeVectorBinary(position, file);
     if (hasNormal)
     if (hasNormal)
     {
     {
-        normal.writeBinary(file);
+        writeVectorBinary(normal, file);
     }
     }
     if (hasTangent)
     if (hasTangent)
     {
     {
-        tangent.writeBinary(file);
+        writeVectorBinary(tangent, file);
     }
     }
     if (hasBinormal)
     if (hasBinormal)
     {
     {
-        binormal.writeBinary(file);
+        writeVectorBinary(binormal, file);
     }
     }
     if (hasTexCoord)
     if (hasTexCoord)
     {
     {
-        texCoord.writeBinary(file);
+        writeVectorBinary(texCoord, file);
     }
     }
     // TODO add vertex color?
     // TODO add vertex color?
     //if (hasColor)
     //if (hasColor)
     //{
     //{
-    //    color.writeBinary(file);
+    //    writeVectorBinary(color, file);
     //}
     //}
     if (hasWeights)
     if (hasWeights)
     {
     {
-        blendWeights.writeBinary(file);
-        blendIndices.writeBinary(file);
+        writeVectorBinary(blendWeights, file);
+        writeVectorBinary(blendIndices, file);
     }
     }
 }
 }
 
 
 void Vertex::writeText(FILE* file) const
 void Vertex::writeText(FILE* file) const
 {
 {
     write("// position\n", file);
     write("// position\n", file);
-    position.writeText(file);
+    writeVectorText(position, file);
     if (hasNormal)
     if (hasNormal)
     {
     {
         write("// normal\n", file);
         write("// normal\n", file);
-        normal.writeText(file);
+        writeVectorText(normal, file);
     }
     }
     if (hasTangent)
     if (hasTangent)
     {
     {
         write("// tanget\n", file);
         write("// tanget\n", file);
-        tangent.writeText(file);
+        writeVectorText(tangent, file);
     }
     }
     if (hasBinormal)
     if (hasBinormal)
     {
     {
         write("// binormal\n", file);
         write("// binormal\n", file);
-        binormal.writeText(file);
+        writeVectorText(binormal, file);
     }
     }
     if (hasTexCoord)
     if (hasTexCoord)
     {
     {
         write("// texCoord\n", file);
         write("// texCoord\n", file);
-        texCoord.writeText(file);
+        writeVectorText(texCoord, file);
     }
     }
     if (hasWeights)
     if (hasWeights)
     {
     {
         write("// blendWeights\n", file);
         write("// blendWeights\n", file);
-        blendWeights.writeText(file);
+        writeVectorText(blendWeights, file);
         write("// blendIndices\n", file);
         write("// blendIndices\n", file);
-        blendIndices.writeText(file);
+        writeVectorText(blendIndices, file);
     }
     }
 }
 }
 
 
-}
+void Vertex::normalizeBlendWeight()
+{
+    float total = blendWeights.x + blendWeights.y + blendWeights.z + blendWeights.w;
+    if (total > 0.0f)
+    {
+        blendWeights.x = blendWeights.x / total;
+        blendWeights.y = blendWeights.y / total;
+        blendWeights.z = blendWeights.z / total;
+        blendWeights.w = blendWeights.w / total;
+    }   
+}
+
+}

+ 7 - 4
gameplay-encoder/src/Vertex.h

@@ -21,7 +21,7 @@ public:
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
-    virtual ~Vertex(void);
+    ~Vertex(void);
 
 
     Vector3 position;
     Vector3 position;
     Vector3 normal;
     Vector3 normal;
@@ -73,8 +73,6 @@ public:
             blendWeights==v.blendWeights && blendIndices==v.blendIndices;
             blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
     }
 
 
-    void reset();
-
     /**
     /**
      * Returns the size of this vertex in bytes.
      * Returns the size of this vertex in bytes.
      */
      */
@@ -89,7 +87,12 @@ public:
      * Writes this vertex to a text file stream.
      * Writes this vertex to a text file stream.
      */
      */
     void writeText(FILE* file) const;
     void writeText(FILE* file) const;
-};
 
 
+    /**
+     * Normalizes the blend weights of this vertex so that they add up to 1.0.
+     */
+    void normalizeBlendWeight();
+};
 }
 }
+
 #endif
 #endif

+ 2 - 1
gameplay-encoder/src/VertexElement.cpp

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "VertexElement.h"
 #include "VertexElement.h"
 
 
 namespace gameplay
 namespace gameplay
@@ -72,4 +73,4 @@ const char* VertexElement::usageStr(unsigned int usage)
     }
     }
 }
 }
 
 
-}
+}

+ 1 - 0
gameplay-encoder/src/VertexElement.h

@@ -31,4 +31,5 @@ public:
 };
 };
 
 
 }
 }
+
 #endif
 #endif

+ 17 - 6
gameplay-encoder/src/main.cpp

@@ -1,6 +1,6 @@
-#include <string>
-
+#include "Base.h"
 #include "DAESceneEncoder.h"
 #include "DAESceneEncoder.h"
+#include "FBXSceneEncoder.h"
 #include "TTFFontEncoder.h"
 #include "TTFFontEncoder.h"
 #include "GPBDecoder.h"
 #include "GPBDecoder.h"
 #include "EncoderArguments.h"
 #include "EncoderArguments.h"
@@ -55,21 +55,33 @@ int main(int argc, const char** argv)
     {
     {
     case EncoderArguments::FILEFORMAT_DAE:
     case EncoderArguments::FILEFORMAT_DAE:
         {
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             DAESceneEncoder daeEncoder;
             DAESceneEncoder daeEncoder;
             daeEncoder.write(realpath, arguments);
             daeEncoder.write(realpath, arguments);
             break;
             break;
         }
         }
+    case EncoderArguments::FILEFORMAT_FBX:
+        {
+#ifdef USE_FBX
+            std::string realpath(arguments.getFilePath());
+            FBXSceneEncoder fbxEncoder;
+            fbxEncoder.write(realpath, arguments);
+            break;
+#else
+            fprintf(stderr, "Error: FBX not enabled. Install the FBX SDK and use the preprocessor definition USE_FBX.\n");
+            return -1;
+#endif
+        }
     case EncoderArguments::FILEFORMAT_TTF:
     case EncoderArguments::FILEFORMAT_TTF:
         {
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             std::string id = getFileName(realpath);
             std::string id = getFileName(realpath);
             writeFont(realpath.c_str(), arguments.getFontSize(), id.c_str(), arguments.fontPreviewEnabled());
             writeFont(realpath.c_str(), arguments.getFontSize(), id.c_str(), arguments.fontPreviewEnabled());
             break;
             break;
         }
         }
     case EncoderArguments::FILEFORMAT_GPB:
     case EncoderArguments::FILEFORMAT_GPB:
         {
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             GPBDecoder decoder;
             GPBDecoder decoder;
             decoder.readBinary(realpath);
             decoder.readBinary(realpath);
             break;
             break;
@@ -83,4 +95,3 @@ int main(int argc, const char** argv)
 
 
     return 0;
     return 0;
 }
 }
-

+ 271 - 0
gameplay-newproject.bat

@@ -0,0 +1,271 @@
+@echo off
+
+REM ********************************************************************
+REM
+REM generate-project.bat
+REM
+REM This windows batch script generates a set of gameplay project files.
+REM The new project will be based of the gameplay-template project and 
+REM it will be generated with the name and location that is specified
+REM as input parameters.
+REM
+REM IMPORTANT: This script must be run from the root of the gameplay
+REM source tree.
+REM
+REM ********************************************************************
+
+echo.
+echo 1. Enter a name for the new project.
+echo.
+echo    This name will be given to the project 
+echo    executable and a folder with this name
+echo    will be created to store all project files.
+echo.
+set /p projName=Project name: 
+if "%projName%" == "" (
+    echo.
+    echo ERROR: No project name specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 2. Enter a game title.
+echo.
+echo    On some platforms, this title is used to
+echo    identify the game during installation and
+echo    on shortcuts/icons.
+echo.
+set /p title=Title: 
+if "%title%" == "" (
+    echo.
+    echo ERROR: No game title specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 3. Enter a short game description.
+echo.
+set /p desc=Description: 
+if "%desc%" == "" (
+    set desc=%title%
+)
+echo.
+
+echo.
+echo 4. Enter a unique identifier for your project.
+echo.
+echo    This should be a human readable package name,
+echo    containing at least two words separated by a
+echo    period (eg. com.surname.gamename).
+echo.
+set /p uuid=Unique ID: 
+if "%uuid%" == "" (
+    echo.
+    echo ERROR: No uuid specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 5. Enter author name.
+echo.
+echo    On BlackBerry targets, this is used for
+echo    signing and must match the developer name
+echo    of your development certificate.
+echo.
+set /p author=Author: 
+if "%author%" == "" (
+    echo.
+    echo ERROR: No author specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 6. Enter your game's main class name.
+echo.
+echo    Your initial game header and source file
+echo    will be given this name and a class with 
+echo    this name will be created in these files.
+echo.
+set /p className=Class name: 
+if "%className%" == "" (
+    echo.
+    echo ERROR: No class name specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 7. Enter the project path.
+echo.
+echo    This can be a relative path, absolute path,
+echo    or empty for the current folder. Note that
+echo    a project folder named %projName% will also
+echo    be created inside this folder.
+echo.
+set /p location=Path: 
+if "%location%" == "" (
+    set projPath=%projName%
+) else (
+    set projPath=%location%\%projName%
+)
+echo.
+
+call:replacevar projPath "/" "\"
+
+REM Does this path already exist?
+if exist %projPath% (
+    echo.
+    echo ERROR: Path '%projPath%' already exists, aborting.
+    echo.
+    pause
+    goto done
+
+REM Disabling following code which prompts to overwrite existing path,
+REM since this could be potentially damaging if the user specifies
+REM an important path and then types 'y', without thinking.
+REM
+REM    set /p owd=Directory '%projPath%' exists, overwrite [Y,N]? 
+REM    if not "!owd!" == "Y" (
+REM        if not "!owd!" == "y" (
+REM            echo Aborting.
+REM            pause
+REM            goto done
+REM        )
+REM    )
+REM    rmdir /S /Q %projPath%
+)
+
+REM Generate relative path from project folder to GamePlay folder
+set gpPath=%cd%
+call:makerelative gpPath %projPath%\
+call:replacevar gpPath "\" "/"
+
+mkdir %projPath%
+mkdir %projPath%\src
+mkdir %projPath%\res
+
+REM Copy Microsoft Visual Studio project files
+copy gameplay-template\gameplay-template.vcxproj %projPath%\%projName%.vcxproj
+call:replace %projPath%\%projName%.vcxproj TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\%projName%.vcxproj TemplateGame "%className%"
+call:replace %projPath%\%projName%.vcxproj GAMEPLAY_PATH "%gpPath%"
+
+copy gameplay-template\gameplay-template.vcxproj.filters %projPath%\%projName%.vcxproj.filters
+call:replace %projPath%\%projName%.vcxproj.filters TemplateGame "%className%"
+
+copy gameplay-template\gameplay-template.vcxproj.user %projPath%\%projName%.vcxproj.user
+call:replace %projPath%\%projName%.vcxproj.user GAMEPLAY_PATH "%gpPath%"
+
+REM Copy Apple XCode project files
+mkdir %projPath%\%projName%.xcodeproj
+copy gameplay-template\gameplay-template.xcodeproj\project.pbxproj %projPath%\%projName%.xcodeproj\project.pbxproj
+call:replace %projPath%\%projName%.xcodeproj\project.pbxproj GAMEPLAY_PATH "%gpPath%"
+call:replace %projPath%\%projName%.xcodeproj\project.pbxproj TemplateGame "%className%"
+call:replace %projPath%\%projName%.xcodeproj\project.pbxproj TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\gameplay-template-macos.plist %projPath%\%projName%-macos.plist
+call:replace %projPath%\%projName%-macos.plist TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\%projName%-macos.plist TEMPLATE_AUTHOR "%author%"
+
+REM Copy BlackBerry NDK project files
+copy gameplay-template\template.cproject %projPath%\.cproject
+call:replace %projPath%\.cproject TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\.cproject TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\.cproject GAMEPLAY_PATH "%gpPath%"
+
+copy gameplay-template\template.project %projPath%\.project
+call:replace %projPath%\.project TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\template.bar-descriptor.xml %projPath%\bar-descriptor.xml
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_TITLE "%title%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_AUTHOR "%author%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_DESCRIPTION "%desc%"
+
+REM Copy source files
+copy gameplay-template\src\TemplateGame.h %projPath%\src\%className%.h
+copy gameplay-template\src\TemplateGame.cpp %projPath%\src\%className%.cpp
+call:replace %projPath%\src\%className%.h TemplateGame "%className%"
+call:replace %projPath%\src\%className%.cpp TemplateGame "%className%"
+
+REM Copy resource files
+copy gameplay-template\res\* %projPath%\res\
+copy gameplay\res\shaders\colored.* %projPath%\res\
+
+REM Copy icon
+copy gameplay-template\icon.png %projPath%\icon.png
+
+REM Open new project folder
+start %projPath%
+
+goto done
+
+:replace
+set rtemp=%1.rtemp
+if exist %rtemp% del /Q %rtemp%
+for /f "tokens=1* eol=€ delims=€]" %%j in ('type "%1" ^| find /V /N ""') do (
+    set line=%%k
+    setlocal EnableDelayedExpansion
+    if "!line!" == "" (
+        echo.>>%rtemp%
+    ) else (
+        set linput=!line!
+        set loutput=!linput:%~2=%~3!
+        echo.!loutput!>>%rtemp%
+    )
+    endlocal
+)
+copy /Y %rtemp% %1
+del /Q %rtemp%
+exit /b
+goto done
+
+:replacevar
+setlocal EnableDelayedExpansion
+echo !%~1!>.replacevar.tmp
+endlocal
+call:replace .replacevar.tmp "%~2" "%~3"
+set /p replaced=<.replacevar.tmp
+set %~1=%replaced%
+del /Q .replacevar.tmp
+exit /b
+goto done
+
+:makerelative
+setlocal EnableDelayedExpansion
+set src=%~1
+if defined %1 set src=!%~1!
+set bas=%~2
+if not defined bas set bas=%cd%
+for /f "tokens=*" %%a in ("%src%") do set src=%%~fa
+for /f "tokens=*" %%a in ("%bas%") do set bas=%%~fa
+set mat=&rem variable to store matching part of the name
+set upp=&rem variable to reference a parent
+for /f "tokens=*" %%a in ('echo.%bas:\=^&echo.%') do (
+    set sub=!sub!%%a\
+    call set tmp=%%src:!sub!=%%
+    if "!tmp!" NEQ "!src!" (set mat=!sub!)ELSE (set upp=!upp!..\)
+)
+set src=%upp%!src:%mat%=!
+( endlocal & REM RETURN VALUES
+    IF defined %1 (SET %~1=%src%) ELSE ECHO.%src%
+)
+exit /b
+goto done
+
+:done

Някои файлове не бяха показани, защото твърде много файлове са промени