Преглед изворни кода

Merge pull request #99 from blackberry/master

Pull master v1.1.0
Sean Paul Taylor пре 14 година
родитељ
комит
0307737d44
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-Profile
 /Device-Release
+/gameplay.xcworkspace/xcuserdata
 /gameplay/Debug
+/gameplay/DebugMem
 /gameplay/Release
 /gameplay/Simulator
 /gameplay/Simulator-Coverage
@@ -22,10 +24,14 @@
 /gameplay/Device-Coverage
 /gameplay/Device-Profile
 /gameplay/Device-Release
+/gameplay/gameplay.xcodeproj/xcuserdata
 /gameplay-encoder/Debug
 /gameplay-encoder/Release
+/gameplay-encoder/gameplay-encoder.xcodeproj/xcuserdata
+/gameplay-internal
 /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-Coverage
 /gameplay-samples/sample00-mesh/Simulator-Profile
@@ -33,8 +39,11 @@
 /gameplay-samples/sample00-mesh/Device-Coverage
 /gameplay-samples/sample00-mesh/Device-Profile
 /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//Release
+/gameplay-samples/sample01-longboard/DebugMem
+/gameplay-samples/sample01-longboard/Release
 /gameplay-samples/sample01-longboard/Simulator
 /gameplay-samples/sample01-longboard/Simulator-Coverage
 /gameplay-samples/sample01-longboard/Simulator-Profile
@@ -42,7 +51,10 @@
 /gameplay-samples/sample01-longboard/Device-Coverage
 /gameplay-samples/sample01-longboard/Device-Profile
 /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/DebugMem
 /gameplay-samples/sample02-spaceship/Release
 /gameplay-samples/sample02-spaceship/Simulator
 /gameplay-samples/sample02-spaceship/Simulator-Coverage
@@ -51,7 +63,10 @@
 /gameplay-samples/sample02-spaceship/Device-Coverage
 /gameplay-samples/sample02-spaceship/Device-Profile
 /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/DebugMem
 /gameplay-samples/sample03-character/Release
 /gameplay-samples/sample03-character/Simulator
 /gameplay-samples/sample03-character/Simulator-Coverage
@@ -59,4 +74,6 @@
 /gameplay-samples/sample03-character/Device-Debug
 /gameplay-samples/sample03-character/Device-Coverage
 /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. 
 
 ## 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
 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).
 
 ## 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 

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

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

@@ -11,17 +11,19 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\gameplay\src\Curve.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\AnimationChannel.cpp" />
     <ClCompile Include="src\Base.cpp" />
+    <ClCompile Include="src\BoundingVolume.cpp" />
     <ClCompile Include="src\Camera.cpp" />
-    <ClCompile Include="src\CameraInstance.cpp" />
     <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\DAEChannelTarget.cpp" />
     <ClCompile Include="src\DAEOptimizer.cpp" />
     <ClCompile Include="src\DAESceneEncoder.cpp" />
     <ClCompile Include="src\DAEUtil.cpp" />
     <ClCompile Include="src\Effect.cpp" />
+    <ClCompile Include="src\FBXSceneEncoder.cpp" />
     <ClCompile Include="src\FileIO.cpp" />
     <ClCompile Include="src\Font.cpp" />
     <ClCompile Include="src\GPBFile.cpp" />
@@ -29,7 +31,6 @@
     <ClCompile Include="src\GPBDecoder.cpp" />
     <ClCompile Include="src\Animations.cpp" />
     <ClCompile Include="src\Light.cpp" />
-    <ClCompile Include="src\LightInstance.cpp" />
     <ClCompile Include="src\main.cpp" />
     <ClCompile Include="src\Material.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
@@ -54,17 +55,19 @@
     <ClCompile Include="src\VertexElement.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\gameplay\src\Curve.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\AnimationChannel.h" />
     <ClInclude Include="src\Base.h" />
+    <ClInclude Include="src\BoundingVolume.h" />
     <ClInclude Include="src\Camera.h" />
-    <ClInclude Include="src\CameraInstance.h" />
     <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\DAEChannelTarget.h" />
     <ClInclude Include="src\DAEOptimizer.h" />
     <ClInclude Include="src\DAESceneEncoder.h" />
     <ClInclude Include="src\DAEUtil.h" />
     <ClInclude Include="src\Effect.h" />
+    <ClInclude Include="src\FBXSceneEncoder.h" />
     <ClInclude Include="src\FileIO.h" />
     <ClInclude Include="src\Font.h" />
     <ClInclude Include="src\GPBFile.h" />
@@ -72,7 +75,6 @@
     <ClInclude Include="src\GPBDecoder.h" />
     <ClInclude Include="src\Animations.h" />
     <ClInclude Include="src\Light.h" />
-    <ClInclude Include="src\LightInstance.h" />
     <ClInclude Include="src\Material.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />
@@ -95,6 +97,11 @@
     <ClInclude Include="src\Vertex.h" />
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="src\Vector2.inl" />
+    <None Include="src\Vector3.inl" />
+    <None Include="src\Vector4.inl" />
+  </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{9D69B743-4872-4DD1-8E30-0087C64298D7}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
@@ -138,17 +145,22 @@
       </PrecompiledHeader>
       <WarningLevel>Level4</WarningLevel>
       <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>
     <Link>
       <SubSystem>Console</SubSystem>
       <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>
     <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>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -160,18 +172,22 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <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>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <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>
     <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>
   </ItemDefinitionGroup>
   <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"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <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">
-      <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 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 Include="src\Font.cpp">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <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 Include="src\Light.cpp">
-      <Filter>Objects\Light</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\LightInstance.cpp">
-      <Filter>Objects\Light</Filter>
+    <ClCompile Include="src\main.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Material.cpp">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\MaterialParameter.cpp">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Matrix.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Mesh.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\MeshPart.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\MeshSkin.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Node.cpp">
-      <Filter>Objects\Node</Filter>
+    <ClCompile Include="src\Model.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Reference.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\Node.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Object.cpp">
-      <Filter>Objects</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Model.cpp">
-      <Filter>Objects\Mesh</Filter>
+    <ClCompile Include="src\Quaternion.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Scene.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\Reference.cpp">
+      <Filter>src</Filter>
     </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 Include="src\AnimationChannel.cpp">
-      <Filter>Objects\Animation</Filter>
+    <ClCompile Include="src\Scene.cpp">
+      <Filter>src</Filter>
     </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 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 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 Include="src\Vector4.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vector2.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Vector3.cpp">
-      <Filter>Math</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector2.cpp">
-      <Filter>Math</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Transform.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vector4.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Matrix.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vertex.cpp">
+      <Filter>src</Filter>
     </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>
   </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 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 Include="src\Font.h">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Glyph.h">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\LightInstance.h">
-      <Filter>Objects\Light</Filter>
+    <ClInclude Include="src\GPBDecoder.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Light.h">
-      <Filter>Objects\Light</Filter>
+    <ClInclude Include="src\GPBFile.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\MaterialParameter.h">
-      <Filter>Objects\Material</Filter>
+    <ClInclude Include="src\Light.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Material.h">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
     </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 Include="src\Mesh.h">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     <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 Include="src\Object.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\MeshSkin.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Model.h">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Scene.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\Node.h">
+      <Filter>src</Filter>
     </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 Include="src\Animation.h">
-      <Filter>Objects\Animation</Filter>
+    <ClInclude Include="src\Quaternion.h">
+      <Filter>src</Filter>
     </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 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 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 Include="src\Vector4.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\StringUtil.h">
+      <Filter>src</Filter>
     </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 Include="src\Vector2.h">
-      <Filter>Math</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Transform.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Vector3.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Matrix.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Vector4.h">
+      <Filter>src</Filter>
     </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>
   </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>
   </ItemGroup>
 </Project>

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

@@ -4,5 +4,10 @@
     <LocalDebuggerCommandArguments>
     </LocalDebuggerCommandArguments>
     <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>
 </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"
 
 namespace gameplay
@@ -26,7 +27,7 @@ void Animation::writeBinary(FILE* file)
     // Animation writes its ID because it is not listed in the ref table.
     write(getId(), 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);
     }
@@ -37,7 +38,7 @@ void Animation::writeText(FILE* file)
     fprintElementStart(file);
     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);
         }
@@ -55,4 +56,9 @@ unsigned int Animation::getAnimationChannelCount() const
     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);
 
     void add(AnimationChannel* animationChannel);
+
     /**
      * Returns the number of animation channels contained in this animation.
      * 
@@ -34,9 +35,16 @@ public:
      */
     unsigned int getAnimationChannelCount() const;
 
+    /**
+     * Returns the specified animation channel.
+     */
+    AnimationChannel* getAnimationChannel(unsigned int index) const;
+
 private:
+
     std::vector<AnimationChannel*> _channels;
 };
 
 }
+
 #endif

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

@@ -1,4 +1,6 @@
+#include "Base.h"
 #include "AnimationChannel.h"
+#include "Transform.h"
 
 namespace gameplay
 {
@@ -27,7 +29,7 @@ void AnimationChannel::writeBinary(FILE* file)
     write(_targetId, file);
     write(_targetAttrib, 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);
     }
@@ -35,7 +37,6 @@ void AnimationChannel::writeBinary(FILE* file)
     write(_tangentsIn, file);
     write(_tangentsOut, file);
     write(_interpolations, file);
-
 }
 
 void AnimationChannel::writeText(FILE* file)
@@ -51,7 +52,48 @@ void AnimationChannel::writeText(FILE* 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;
 }
@@ -86,9 +128,101 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& 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)
@@ -136,4 +270,25 @@ unsigned int AnimationChannel::getInterpolationType(const char* str)
     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 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 setKeyTimes(const std::vector<float>& values);
@@ -44,7 +53,17 @@ public:
     void setTangentsOut(const std::vector<float>& values);
     void setInterpolations(const std::vector<unsigned int>& values);
 
+    unsigned int getTargetAttribute() 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.
@@ -56,7 +75,9 @@ public:
      */
     static unsigned int getInterpolationType(const char* str);
 
+private:
 
+    void deleteRange(size_t begin, size_t end);
 private:
 
     std::string _targetId;
@@ -68,7 +89,6 @@ private:
     std::vector<unsigned int> _interpolations;
 };
 
-
 }
-#endif
 
+#endif

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

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Animations.h"
 
 namespace gameplay
@@ -27,7 +28,7 @@ void Animations::writeBinary(FILE* file)
 {
     Object::writeBinary(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);
     }
@@ -38,7 +39,7 @@ void Animations::writeText(FILE* file)
     fprintElementStart(file);
     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);
         }
@@ -51,4 +52,14 @@ void Animations::add(Animation* 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);
 
     void add(Animation* animation);
+    unsigned int getAnimationCount() const;
+    Animation* getAnimation(unsigned int index) const;
 
 private:
+
     std::vector<Animation*> _animations;
 };
 
 }
+
 #endif

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

@@ -5,30 +5,10 @@ namespace gameplay
 
 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;
     }
 }
 
-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 <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        
-#define M_1_PI                    0.31830988618379067154
+#define M_1_PI                      0.31830988618379067154
 #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
 {
@@ -45,10 +74,18 @@ enum VertexUsage
     TEXCOORD7 = 15
 };
 
-
 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

+ 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"
 
 namespace gameplay

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

@@ -54,4 +54,5 @@ private:
 };
 
 }
+
 #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"
 
-
 namespace gameplay
 {
 
@@ -40,7 +40,7 @@ DAEChannelTarget::DAEChannelTarget(const domChannelRef channelRef) : _channel(ch
                 index = end + 1;
             }
             _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();
 }
 
-}
+}

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

@@ -1,18 +1,6 @@
 #ifndef 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
 {
 

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

@@ -1,8 +1,8 @@
+#include "Base.h"
 #include "DAEOptimizer.h"
 
-#include <algorithm>
-
-#include "StringUtil.h"
+namespace gameplay
+{
 
 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.
 
     // 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);
     }
@@ -46,55 +46,6 @@ void DAEOptimizer::combineAnimations(const std::string& nodeId, const std::strin
     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()
 {
     std::list<domAnimationRef> animations;
@@ -102,12 +53,12 @@ void DAEOptimizer::deleteEmptyAnimations()
     // Get the list of empty animations
     domLibrary_animations_Array& animationLibrary = _dom->getLibrary_animations_array();
     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);
         domAnimation_Array& animationArray = animationsRef->getAnimation_array();
         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);
             if (isEmptyAnimation(animation))
@@ -118,8 +69,10 @@ void DAEOptimizer::deleteEmptyAnimations()
     }
 
     // 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);
     }
-}
+}
+
+}

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

@@ -1,19 +1,11 @@
 #ifndef 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"
 
+namespace gameplay
+{
+
 /**
  * The DAEOptimizer optimizes a COLLADA dom.
  */
@@ -41,14 +33,6 @@ public:
 
 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.
      */
@@ -60,4 +44,6 @@ private:
     std::string _inputPath;
 };
 
+}
+
 #endif

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

@@ -1,15 +1,15 @@
 /*
  * DAESceneEncoder.h
  */
-
-#include <algorithm>
+#include "Base.h"
 
 #include "DAESceneEncoder.h"
 #include "DAEOptimizer.h"
 
 //#define ENCODER_PRINT_TIME 1
 
-using namespace gameplay;
+namespace gameplay
+{
 
 DAESceneEncoder::DAESceneEncoder()
     : _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 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 )
         {
@@ -62,7 +44,7 @@ void DAESceneEncoder::optimizeCOLLADA(const EncoderArguments& arguments, domCOLL
     if (size > 0)
     {
         begin();
-        for (size_t i = 0; i < size; i++)
+        for (size_t i = 0; i < size; ++i)
         {
             optimizer.combineAnimations(groupAnimatioNodeIds[i], groupAnimatioIds[i]);
         }
@@ -82,7 +64,7 @@ void DAESceneEncoder::triangulate(DAE* dae)
     daeDatabase* dataBase = dae->getDatabase();
 
     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.
         domGeometry* domGeometry;
@@ -97,14 +79,14 @@ void DAESceneEncoder::triangulate(DAE* dae)
 
         // Loop over all the polygons elements.
         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.
             domPolygons* domPolygons = domMesh->getPolygons_array()[j];
             // Create the triangles from the polygons
             createTrianglesFromPolygons(domMesh, domPolygons);
         }
-        while(domMesh->getPolygons_array().getCount() > 0)
+        while (domMesh->getPolygons_array().getCount() > 0)
         {
             domPolygons* domPolygons = domMesh->getPolygons_array().get(0);
             // Remove the polygons from the mesh.
@@ -113,14 +95,14 @@ void DAESceneEncoder::triangulate(DAE* dae)
 
         // Loop over all the polylist elements.
         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.
             domPolylist* domPolylist = domMesh->getPolylist_array()[j];
             // Create the triangles from the polygon list
             createTrianglesFromPolylist(domMesh, domPolylist);
         }
-        while(domMesh->getPolylist_array().getCount() > 0)
+        while (domMesh->getPolylist_array().getCount() > 0)
         {
             domPolylist* domPolylist = domMesh->getPolylist_array().get(0);
             // Remove the polylist from the mesh.
@@ -138,7 +120,7 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     
     // 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());
     }
@@ -148,7 +130,7 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
     unsigned int primitiveCount = domPolygons->getP_array().getCount();
     
     // 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).
         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.
             unsigned int index = inputCount;
-            for (unsigned int k = 0; k < triangleCount; k++)
+            for (unsigned int k = 0; k < triangleCount; ++k)
             {
                 // First vertex.
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[l]);
                 }
                 // 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]);
                 }
                 // Third vertex.
                 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]);
                 }
@@ -195,7 +177,7 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     
     // 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());
     }
@@ -208,27 +190,27 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     unsigned int trianglesProcessed = 0;
     
     // 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;
         
         // Write out the primitives as triangles, just fan using the first element as the base.
         int index = inputCount;
-        for (unsigned int k = 0; k < triangleCount; k++)
+        for (unsigned int k = 0; k < triangleCount; ++k)
         {
             // 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]);
             }
             // 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]);
             }
             // Third vertex.
             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]);
             }
@@ -243,7 +225,7 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
 
 void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
 {
-    _begin = std::clock();
+    _begin = clock();
     const char* nodeId = arguments.getNodeId();
     bool text = arguments.textOutputEnabled();
 
@@ -363,12 +345,12 @@ void DAESceneEncoder::loadAnimations(const domCOLLADA* dom)
     // Call loadAnimation on all <animation> elements in all <library_animations>
     const domLibrary_animations_Array& animationLibrarys = dom->getLibrary_animations_array();
     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 domAnimation_Array& animationArray = libraryAnimation->getAnimation_array();
         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);
             loadAnimation(animationRef);
@@ -391,7 +373,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
     // <channel>
     const domChannel_Array& channelArray = animationRef->getChannel_array();
     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();
 
@@ -404,7 +386,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
         // <input>
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         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);
 
@@ -425,7 +407,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
                 if (equals(semantic, "INPUT"))
                 {
                     // 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
                         *k = *k * 1000.0f;
@@ -473,7 +455,7 @@ void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChan
     values.resize(count);
     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));
         }
@@ -482,7 +464,7 @@ void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChan
         // instead of storing the same type for each key frame.
         unsigned int firstType = values[0];
         bool allEqual = true;
-        for (size_t i = 1; i < count; i++)
+        for (size_t i = 1; i < count; ++i)
         {
             if (firstType != values[i])
             {
@@ -512,7 +494,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
     const char* targetId = channelTarget.getTargetId().c_str();
 
     // 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;
         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)
                         std::vector<float> floats(size * 4);
                         // 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;
                             floats[k+0] = x;
@@ -624,7 +606,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                 std::vector<float> floats(newSize);
 
                 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;
                     // 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->setTargetId(channelTarget.getTargetId());
+    //animationChannel->removeDuplicates();
     return true;
 }
 
 void DAESceneEncoder::begin()
 {
     #ifdef ENCODER_PRINT_TIME
-    _begin = std::clock();
+    _begin = clock();
     #endif
 }
 
 void DAESceneEncoder::end(const char* str)
 {
     #ifdef ENCODER_PRINT_TIME
-    clock_t time = std::clock() - _begin;
+    clock_t time = clock() - _begin;
     fprintf(stderr,"%5d %s\n", time, str);
     #endif
 }
@@ -681,7 +664,7 @@ void DAESceneEncoder::copyFloats(const domFloat_array* source, std::vector<float
     size_t count = (size_t)source->getCount();
     t.resize(count);
     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);
     }
@@ -694,7 +677,7 @@ void DAESceneEncoder::loadScene(const domVisual_scene* visualScene)
     const domNode_Array& nodes = visualScene->getNode_array();
     scene->setId(visualScene->getId());
     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));
     }
@@ -716,11 +699,11 @@ Node* DAESceneEncoder::findSceneActiveCameraNode(const domVisual_scene* visualSc
     // Find the active camera
     const domVisual_scene::domEvaluate_scene_Array& evaluateScenes = visualScene->getEvaluate_scene_array();
     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();
         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();
             domNode* nodeRef = daeSafeCast<domNode>(cameraNodeURI.getElement());
@@ -782,7 +765,7 @@ Node* DAESceneEncoder::loadNode(domNode* n, Node* parent)
     // Load child nodes
     const domNode_Array& childNodes = n->getNode_array();
     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);
     }
@@ -830,10 +813,10 @@ void DAESceneEncoder::transformNode(domNode* domNode, Node* node)
 
 void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
 {
-    daeTArray<daeSmartRef<daeElement>> children;
+    daeTArray<daeSmartRef<daeElement> > children;
     domNode->getChildren(children);
     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];
         switch (childElement->getElementType())
@@ -898,7 +881,7 @@ void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
     // Does this node have any camera instances?
     const domInstance_camera_Array& instanceCameras = n->getInstance_camera_array();
     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
         const domInstance_camera* cameraInstanceRef = instanceCameras.get(i);
@@ -907,10 +890,10 @@ void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
 
         if (cameraRef)
         {
-            CameraInstance* cameraInstance = loadCamera(cameraRef);
-            if (cameraInstance)
+            Camera* camera = loadCamera(cameraRef);
+            if (camera)
             {
-                node->setCameraInstance(cameraInstance);
+                node->setCamera(camera);
             }
         }
         else
@@ -925,7 +908,7 @@ void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
     // Does this node have any light instances?
     const domInstance_light_Array& instanceLights = n->getInstance_light_array();
     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
         const domInstance_light* lightInstanceRef = instanceLights.get(i);
@@ -934,10 +917,10 @@ void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
 
         if (lightRef)
         {
-            LightInstance* lightInstance = loadLight(lightRef);
-            if (lightInstance)
+            Light* light = loadLight(lightRef);
+            if (light)
             {
-                node->setLightInstance(lightInstance);
+                node->setLight(light);
             }
         }
         else
@@ -952,7 +935,7 @@ void DAESceneEncoder::loadGeometryInstance(const domNode* n, Node* node)
     // Does this node have any geometry instances?
     const domInstance_geometry_Array& instanceGeometries = n->getInstance_geometry_array();
     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
         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?
     const domInstance_controller_Array& instanceControllers = n->getInstance_controller_array();
     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);
         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)
@@ -1265,9 +1227,9 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
     }
 
     // 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);
         if (obj)
@@ -1301,10 +1263,9 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     domSkin::domJointsRef _joints = skinElement->getJoints();
     domInputLocal_Array& jointInputs = _joints->getInput_array();
 
-
     // Process "JOINT" input semantic first (we need to do this to set the joint count)
     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);
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1315,12 +1276,12 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         if (equals(inputSemantic, "JOINT"))
         {
             // Get the joint Ids's
-            std::list<std::string> list;
+            std::vector<std::string> list;
             getJointNames(source, list);
 
             // 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.
-            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());
                 daeElement* element = resolver.getElement();
@@ -1339,7 +1300,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
             jointCount = list.size();
             _jointInverseBindPoseMatrices.reserve(jointCount);
             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++;
             }
@@ -1355,7 +1316,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     }
 
     // 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);
         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 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),
                               (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();
     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);
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1436,7 +1397,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     int weightOffset = 0;
 
     // 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.
         unsigned int vertexInfluenceCount = (unsigned int)skinVertexInfluenceCounts.get(i);
@@ -1445,7 +1406,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         //vertexInfluences.SetCapacity(vertexInfluenceCount);
 
         // 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]);
             int index = (int)skinVertexJointWeightPairIndices[vOffset];
@@ -1465,7 +1426,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         }
 
         // 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)
             {
@@ -1573,7 +1534,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     unsigned int inputCount = (unsigned int)-1;
 
     // 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 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();
 
-            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);
                 std::string inputSemantic = input->getSemantic();
@@ -1592,7 +1554,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 if (equals(inputSemantic, "VERTEX"))
                 {
                     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);
                         
@@ -1620,6 +1582,14 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                     if (type == -1)
                     {
                         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();
@@ -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 (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];
                 }
                 warning(std::string("Triangles do not all have the same number of input sources for geometry mesh: ") + geometryId);
-                return false;
+                return NULL;
             }
             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.
     // 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.
         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));
 
         // 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)
         ///    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
         // and iterate by its offset.
-        Vertex vertex;
 
+        Vertex vertex;
         for (unsigned int k = 0; k < inputSourceCount && poly < polyIntsCount;)
         {
             const domListOfFloats& source = polygonInputs[k]->sourceValues;
@@ -1701,7 +1671,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             switch (type)
             {
             case POSITION:
-                vertex.reset();
+                vertex = Vertex(); // TODO
                 if (_vertexBlendWeights && _vertexBlendIndices)
                 {
                     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);
                 }
                 break;
+
+            case TEXCOORD1:
+                // TODO
+                break;
+
+            default:
+                break;
             }
 
             // 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;
             }
+            else if (equals(semantic, "TEXTANGENT"))
+            {
+                // Treat TEXTANGENT as TANGENT
+                type = TANGENT;
+            }
+            else if (equals(semantic, "TEXBINORMAL"))
+            {
+                // Treat TEXBINORMAL as BINORMAL
+                type = BINORMAL;
+            }
         case 'B':
             if (equals(semantic, "BINORMAL"))
             {
@@ -1912,4 +1899,6 @@ DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :
 
 DAESceneEncoder::DAEPolygonInput::~DAEPolygonInput(void)
 {
-}
+}
+
+}

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

@@ -1,32 +1,11 @@
-/*
- * DAESceneEncoder.h
- */
-
 #ifndef 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 "Object.h"
 #include "Node.h"
 #include "Camera.h"
-#include "CameraInstance.h"
 #include "Light.h"
-#include "LightInstance.h"
 #include "Mesh.h"
 #include "MeshPart.h"
 #include "MeshSkin.h"
@@ -42,7 +21,8 @@
 #include "DAEUtil.h"
 #include "EncoderArguments.h"
 
-using namespace gameplay;
+namespace gameplay
+{
 
 /**
  * Class for binary encoding a Collada (DAE) file.
@@ -134,8 +114,8 @@ private:
      */
     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* loadGeometry(const domGeometry* geometry, const domBind_materialRef bindMaterial);
 
@@ -223,4 +203,6 @@ private:
     clock_t _begin;
 };
 
+}
+
 #endif

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

@@ -1,5 +1,9 @@
-
+#include "Base.h"
 #include "DAEUtil.h"
+#include "StringUtil.h"
+
+namespace gameplay
+{
 
 /**
  * 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);
 
-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
     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();
         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)));
         }
@@ -32,7 +85,7 @@ void getJointNames(const domSourceRef source, std::list<std::string>& list)
         {
             xsIDREFS& ids = idArray->getValue();
             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()));
             }
@@ -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 domInputLocal_Array& inputArray = joints->getInput_array();
     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 char* semantic = input->getSemantic();
@@ -69,7 +122,7 @@ domSource* getInputSource(const domChannelRef& channel)
         domSampler* sampler = daeSafeCast<domSampler>(element);
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         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);
             if (strcmp(input->getSemantic(), "INPUT") == 0)
@@ -105,7 +158,7 @@ const domSamplerRef getSampler(const domChannelRef& channel)
         
         const domSampler_Array& samplerArray = animation->getSampler_array();
         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);
             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 domSource_Array& sourceArray = animation->getSource_array();
     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);
         if (id.compare(source->getId()) == 0)
@@ -148,10 +201,10 @@ const domName_arrayRef getSourceNameArray(const domSourceRef& source)
     {
         return nameArray;
     }
-    daeTArray<daeSmartRef<daeElement>> children;
+    daeTArray<daeSmartRef<daeElement> > children;
     source->getChildren(children);
     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);
         if (element->getElementType() == COLLADA_TYPE::NAME_ARRAY)
@@ -220,7 +273,7 @@ bool equalKeyTimes(const domSource* s1, const domSource* s2)
         const domListOfFloats& list2 = f2->getValue();
 
         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))
             {
@@ -256,7 +309,7 @@ void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& an
 
         domInputLocal_Array& inputArray = sampler->getInput_array();
         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();
             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();
     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);
         daeElementRef element = skeleton->getValue().getElement();
@@ -301,3 +354,5 @@ int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, con
     }
     return -1;
 }
+
+}

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

@@ -1,25 +1,16 @@
-/*
- * DAEUtil.h
- */
-
 #ifndef 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.
@@ -27,7 +18,7 @@ using namespace gameplay;
  * @param source The source element to search in.
  * @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.
@@ -35,7 +26,7 @@ void getJointNames(const domSourceRef source, std::list<std::string>& list);
  * @param skin The skin element to search in.
  * @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.
@@ -56,7 +47,7 @@ domSource* getInputSource(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.
  * 
  * @param inputLocal The input element within a sampler.
@@ -123,4 +114,6 @@ void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& an
  */
 bool isEmptyAnimation(domAnimationRef& animation);
 
+}
+
 #endif

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

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

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

@@ -33,7 +33,6 @@ private:
     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"
 
 #ifdef WIN32
@@ -7,6 +8,11 @@
     #define realpath(A,B)    _fullpath(B,A,PATH_MAX)
 #endif
 
+namespace gameplay
+{
+
+static EncoderArguments* __instance;
+
 EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
     _fontSize(0),
     _parseError(false),
@@ -14,6 +20,8 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
     _textOutput(false),
     _daeOutput(false)
 {
+    __instance = this;
+
     if (argc > 1)
     {
         size_t filePathIndex = argc - 1;
@@ -24,12 +32,12 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
         
         // read the 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]);
         }
         
-        for (size_t i = 0; i < options.size(); i++)
+        for (size_t i = 0; i < options.size(); ++i)
         {
             if (options[i][0] == '-')
             {
@@ -47,6 +55,11 @@ EncoderArguments::~EncoderArguments(void)
 {
 }
 
+EncoderArguments* EncoderArguments::getInstance()
+{
+    return __instance;
+}
+
 const std::string& EncoderArguments::getFilePath() const
 {
     return _filePath;
@@ -57,6 +70,12 @@ const char* EncoderArguments::getFilePathPointer() const
     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
 {
     return _daeOutputPath;
@@ -72,6 +91,29 @@ const std::vector<std::string>& EncoderArguments::getGroupAnimationAnimationId()
     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
 {
     return _parseError;
@@ -92,14 +134,28 @@ bool EncoderArguments::fileExists() 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);
 }
 
@@ -151,6 +207,10 @@ EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
     {
         return FILEFORMAT_DAE;
     }
+    if (ext.compare("fbx") == 0 || ext.compare("FBX") == 0)
+    {
+        return FILEFORMAT_FBX;
+    }
     if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
     {
         return FILEFORMAT_TTF;
@@ -163,7 +223,7 @@ EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
     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];
     if (str.length() == 0 && str[0] != '-')
@@ -217,6 +277,34 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
             _parseError = true;
             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':
         _fontPreview = true;
         break;
@@ -265,7 +353,7 @@ std::string EncoderArguments::getRealPath(const std::string& filepath)
 
 void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
 {
-    for (; *str != '\0'; str++)
+    for (; *str != '\0'; ++str)
     {
         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_
 #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.
@@ -21,6 +15,7 @@ public:
     {
         FILEFORMAT_UNKNOWN,
         FILEFORMAT_DAE,
+        FILEFORMAT_FBX,
         FILEFORMAT_TTF,
         FILEFORMAT_GPB
     };
@@ -35,6 +30,11 @@ public:
      */
     ~EncoderArguments(void);
 
+    /**
+     * Gets the EncoderArguments instance.
+     */
+    static EncoderArguments* getInstance();
+
     /**
      * 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.
      */
-    const char* EncoderArguments::getFilePathPointer() const;
+    const char* getFilePathPointer() const;
 
     /**
      * 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>& 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.
      */
@@ -115,6 +125,10 @@ private:
 
     std::vector<std::string> _groupAnimationNodeId;
     std::vector<std::string> _groupAnimationAnimationId;
+    std::vector<std::string> _heightmapNodeIds;
+
 };
 
+}
+
 #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 <assert.h>
 
 namespace gameplay
 {
 
-// Writing ot a binary file //
+// Writing out a binary 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)
 {
-    for (int i = 0; i < length; i++)
+    for (int i = 0; i < length; ++i)
     {
         write(values[i], file);
     }
@@ -77,8 +77,8 @@ void writeZero(FILE* file)
 
 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]);
     }
@@ -102,7 +102,7 @@ void fprintfElement(FILE* file, const char* elementName, unsigned int 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)
@@ -144,4 +144,40 @@ void skipUint(FILE* file)
     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_
 #define FILEIO_H_
 
-#include <iostream>
-#include <list>
-#include <vector>
 
-#include "Base.h"
+#include "Vector2.h"
+#include "Vector3.h"
+#include "Vector4.h"
 
 namespace gameplay
 {
 
 /**
  * Writes an XML element to the specified file stream.
+ * 
  * @param file Pointer to a FILE object that identifies the stream.
  * @param elementName Name of the XML element 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>
 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);
     }
@@ -38,9 +38,9 @@ void fprintfElement(FILE* file, const char* format, const char* elementName, std
 template <class T>
 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);
     }
@@ -51,6 +51,7 @@ void fprintfMatrix4f(FILE* file, const float* m);
 
 /**
  * Writes binary data to the given file stream.
+ * 
  * @param value The value to be written
  * @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(float value, 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.
  */
@@ -72,6 +74,7 @@ void writeZero(FILE* file);
 
 /**
  * Writes the length of the list and writes each element value to the binary file stream.
+ * 
  * @param list The list to write.
  * @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
     write(list.size(), file);
     // 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);
     }
@@ -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.
+ * 
  * @param vector The vector to write.
  * @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
     write(vector.size(), file);
     // 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);
     }
 }
 
-
 /**
  * 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.
  * The string is assumed to be a char array.
- * @param The file stream.
+ * 
+ * @param file The file stream.
  */
 void skipString(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"
 
 namespace gameplay
@@ -50,4 +51,4 @@ void Font::writeText(FILE* 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"
 
 namespace gameplay
@@ -42,7 +43,7 @@ bool GPBDecoder::validateHeading()
     const char identifier[] = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' };
 
     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])
         {
@@ -63,7 +64,7 @@ void GPBDecoder::readRefs()
     // read number of refs
     unsigned int refCount;
     assert(read(&refCount));
-    for (size_t i = 0; i < refCount; i++)
+    for (size_t i = 0; i < refCount; ++i)
     {
         readRef();
     }
@@ -113,4 +114,4 @@ std::string GPBDecoder::readString(FILE* fp)
     return result;
 }
 
-};
+}

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

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

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

@@ -1,17 +1,26 @@
+#include "Base.h"
 #include "GPBFile.h"
 
 namespace gameplay
 {
 
+static GPBFile* __instance = NULL;
+
 GPBFile::GPBFile(void)
     : _file(NULL), _animationsAdded(false)
 {
+    __instance = this;
 }
 
 GPBFile::~GPBFile(void)
 {
 }
 
+GPBFile* GPBFile::getInstance()
+{
+    return __instance;
+}
+
 void GPBFile::saveBinary(const std::string& filepath)
 {
     _file = fopen(filepath.c_str(), "w+b");
@@ -21,21 +30,21 @@ void GPBFile::saveBinary(const std::string& filepath)
     fwrite(identifier, 1, sizeof(identifier), _file);
 
     // version
-    fwrite(VERSION, 1, sizeof(VERSION), _file);
+    fwrite(GPB_VERSION, 1, sizeof(GPB_VERSION), _file);
 
     // write refs
     _refTable.writeBinary(_file);
 
     // meshes
     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);
     }
 
     // Objects
     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);
     }
@@ -55,13 +64,13 @@ void GPBFile::saveText(const std::string& filepath)
     _refTable.writeText(_file);
 
     // 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);
     }
 
     // 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);
     }
@@ -146,8 +155,10 @@ bool GPBFile::idExists(const std::string& id)
 
 Camera* GPBFile::getCamera(const char* id)
 {
+    if (!id)
+        return NULL;
     // 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();
         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)
 {
+    if (!id)
+        return NULL;
     // 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();
         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)
 {
+    if (!id)
+        return NULL;
     // 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();
         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)
 {
+    if (!id)
+        return NULL;
     // 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();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -200,10 +217,15 @@ Node* GPBFile::getNode(const char* id)
     return NULL;
 }
 
+Animations* GPBFile::getAnimations()
+{
+    return &_animations;
+}
+
 void GPBFile::adjust()
 {
     // 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;
         if (obj->getTypeId() == Object::SCENE_ID)
@@ -227,5 +249,4 @@ void GPBFile::adjust()
     //   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_
 #define GPBFILE_H_
 
-#include <iostream>
-#include <list>
-
 #include "FileIO.h"
 #include "Object.h"
 #include "Scene.h"
@@ -23,11 +16,12 @@
 
 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.
@@ -46,6 +40,11 @@ public:
      */
     ~GPBFile(void);
 
+    /**
+     * Returns the GPBFile instance.
+     */
+    static GPBFile* getInstance();
+
     /**
      * Saves the GPBFile as a binary file at filepath.
      *
@@ -88,6 +87,8 @@ public:
     Mesh* getMesh(const char* id);
     Node* getNode(const char* id);
 
+    Animations* getAnimations();
+
     /**
      * Adjusts the game play binary file before it is written.
      */
@@ -108,4 +109,5 @@ private:
 };
 
 }
+
 #endif

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

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

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

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

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

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "Light.h"
 #include "DAESceneEncoder.h"
 
@@ -47,7 +48,7 @@ float Light::computeRange(float constantAttenuation, float linearAttenuation, fl
     const float step = 0.01f;
     float range = 0.01f;
     float att = 1.0f;
-    while (att < 0.1f)
+    while (att > 0.01f)
     {
         att = 1 / (constantAttenuation + (range * linearAttenuation) + (range * range * quadraticAttenuation));
         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.
         _outerAngle = _falloffAngle / 2.0f;
         
-        if (_range == -1.0f)
+        if (_innerAngle == -1.0f)
         {
             _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;
 };
 
-
-
 }
-#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"
 
 namespace gameplay
@@ -35,4 +36,4 @@ void Material::writeText(FILE* file)
     fprintElementEnd(file);
 }
 
-}
+}

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

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

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

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

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

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

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

@@ -1,9 +1,9 @@
+#include "Base.h"
 #include "Matrix.h"
 
 namespace gameplay
 {
 
-
 Matrix::Matrix(void)
 {
     setIdentity(m);
@@ -41,6 +41,45 @@ void Matrix::setIdentity(float* matrix)
     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)
 {
     // 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)
     {
         // Not normalized
-        n = sqrtf(n);
+        n = sqrt(n);
         if (n > 0.000001f) // prevent divide too close to zero
         {
             n = 1.0f / n;
@@ -167,6 +206,13 @@ void Matrix::scale(float x, float y, float z)
     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)
 {
     float r[16];
@@ -350,4 +396,12 @@ float Matrix::determinant() const
     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 TODEGREES(radians) (radians * (180.0f / PI))
 
-
 namespace gameplay
 {
 
@@ -31,6 +30,11 @@ class Matrix
 {
 public:
 
+    /**
+     * Matrix colums.
+     */
+    float m[16];
+
     /**
      * Constructor.
      */
@@ -81,6 +85,11 @@ public:
      */
     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.
      */
@@ -121,6 +130,11 @@ public:
      */
     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.
      */
@@ -141,8 +155,15 @@ public:
      */
     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

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

@@ -1,10 +1,11 @@
+#include "Base.h"
 #include "Mesh.h"
-#include <cmath>
+#include "Model.h"
 
 namespace gameplay
 {
 
-Mesh::Mesh(void)
+Mesh::Mesh(void) : model(NULL)
 {
 }
 
@@ -26,8 +27,8 @@ void Mesh::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
     // 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);
     }
@@ -37,6 +38,218 @@ void Mesh::writeBinary(FILE* 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)
 {
     if (vertices.size() > 0)
@@ -47,7 +260,7 @@ void Mesh::writeBinaryVertices(FILE* file)
         write(vertices.size() * vertex.byteSize(), file); // (vertex count) * (vertex size)
 
         // 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
             i->writeBinary(file);
@@ -74,15 +287,15 @@ void Mesh::writeText(FILE* file)
     // for each VertexFormat
     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);
         }
     }
 
     // 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);
     }
@@ -92,19 +305,19 @@ void Mesh::writeText(FILE* file)
     computeBounds();
     fprintf(file, "<bounds>\n");
     fprintf(file, "<min>\n");
-    bounds.min.writeText(file);
+    writeVectorText(bounds.min, file);
     fprintf(file, "</min>\n");
     fprintf(file, "<max>\n");
-    bounds.max.writeText(file);
+    writeVectorText(bounds.max, file);
     fprintf(file, "</max>\n");
     fprintf(file, "<center>\n");
-    bounds.center.writeText(file);
+    writeVectorText(bounds.center, file);
     fprintf(file, "</center>\n");
     fprintf(file, "<radius>%f</radius>\n", bounds.radius);
     fprintf(file, "</bounds>\n");
 
     // 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);
     }
@@ -124,7 +337,7 @@ void Mesh::addMeshPart(Vertex* vertex)
 
 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
@@ -132,6 +345,21 @@ size_t Mesh::getVertexCount() const
     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
 {
     return vertexLookupTable.count(vertex) > 0;
@@ -149,20 +377,26 @@ unsigned int Mesh::getVertexIndex(const Vertex& vertex)
 {
     std::map<Vertex,unsigned int>::iterator it;
     it = vertexLookupTable.find(vertex);
-    // TODO: Remove it from the map because we are going to delete it
     return it->second;
 }
 
 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.max.x = bounds.max.y = bounds.max.z = FLT_MIN;
     bounds.center.x = bounds.center.y = bounds.center.z = 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
         if (i->position.x < bounds.min.x)
@@ -177,22 +411,17 @@ void Mesh::computeBounds()
             bounds.max.y = i->position.y;
         if (i->position.z > bounds.max.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
-    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
     // 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)
         {
             bounds.radius = d;
@@ -200,7 +429,7 @@ void Mesh::computeBounds()
     }
 
     // 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_
 #define MESH_H_
 
+#include "Base.h"
 #include "Object.h"
 #include "MeshPart.h"
 #include "VertexElement.h"
+#include "BoundingVolume.h"
 
 namespace gameplay
 {
 
+class Model;
+
 class Mesh : public Object
 {
+    friend class Model;
+
 public:
 
     /**
@@ -37,6 +43,10 @@ public:
     void addVetexAttribute(unsigned int usage, unsigned int count);
 
     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.
@@ -50,15 +60,15 @@ public:
 
     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<MeshPart*> parts;
-    struct
-    {
-        Vector3 min;
-        Vector3 max;
-        Vector3 center;
-        float radius;
-    } bounds;
+    BoundingVolume bounds;
     std::map<Vertex, unsigned int> vertexLookupTable;
 
 private:
@@ -66,9 +76,10 @@ private:
     void computeBounds();
 
 private:
-    std::vector<VertexElement> _vertexFormats;
+    std::vector<VertexElement> _vertexFormat;
 
 };
 
 }
+
 #endif

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

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "MeshPart.h"
 
 namespace gameplay
@@ -5,7 +6,7 @@ namespace gameplay
 
 MeshPart::MeshPart(void) :
     _primitiveType(TRIANGLES),
-    _indexFormat(INDEX8)
+    _indexFormat(INDEX16)
 {
 }
 
@@ -17,30 +18,33 @@ unsigned int MeshPart::getTypeId(void) const
 {
     return MESHPART_ID;
 }
+
 const char* MeshPart::getElementName(void) const
 {
     return "MeshPart";
 }
+
 void MeshPart::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
 
     write(_primitiveType, file);
-    write(_indexFormat, file);
+    write((unsigned int)_indexFormat, file);
 
     // write the number of bytes
     write(indicesByteSize(), file);
     // 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);
     }
 }
+
 void MeshPart::writeText(FILE* file)
 {
     fprintElementStart(file);
     fprintfElement(file, "primitiveType", _primitiveType);
-    fprintfElement(file, "indexFormat", _indexFormat);
+    fprintfElement(file, "indexFormat", (unsigned int)_indexFormat);
     fprintfElement(file, "%d ", "indices", _indices);
     fprintElementEnd(file);
 }
@@ -67,14 +71,21 @@ unsigned int MeshPart::indexFormatSize() const
     {
     case INDEX32:
         return 4;
-    case INDEX16:
+    default: // INDEX16
         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)
 {
     switch (_indexFormat)
@@ -82,13 +93,9 @@ void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
     case INDEX32:
         write(index, file);
         break;
-    case INDEX16:
+    default: // INDEX16
         write((unsigned short)index, file);
         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_
 #define MESHPART_H_
 
-#include <vector>
-
 #include "Base.h"
 #include "Object.h"
 #include "Vertex.h"
@@ -25,12 +23,10 @@ public:
 
     enum IndexFormat
     {
-        INDEX8  = 0x1401, // GL_UNSIGNED_BYTE
         INDEX16 = 0x1403, // GL_UNSIGNED_SHORT
         INDEX32 = 0x1405  // GL_UNSIGNED_INT
     };
 
-
     /**
      * Constructor.
      */
@@ -56,6 +52,16 @@ public:
      */
     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:
 
     /**
@@ -80,13 +86,12 @@ private:
     void writeBinaryIndex(unsigned int index, FILE* file);
 
 private:
+
     unsigned int _primitiveType;
-    unsigned int _indexFormat;
+    IndexFormat _indexFormat;
     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 "Node.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
 {
@@ -8,7 +15,7 @@ namespace gameplay
 MeshSkin::MeshSkin(void) :
     _vertexInfluenceCount(0)
 {
-    setIdentityMatrix(_bindShape);
+    Matrix::setIdentity(_bindShape);
 }
 
 MeshSkin::~MeshSkin(void)
@@ -30,11 +37,28 @@ void MeshSkin::writeBinary(FILE* file)
     Object::writeBinary(file);
     write(_bindShape, 16, 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);
     }
-    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)
@@ -44,23 +68,27 @@ void MeshSkin::writeText(FILE* file)
     fprintfMatrix4f(file, _bindShape);
     fprintf(file, "</bindShape>");
     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, "</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");
+
     fprintElementEnd(file);
 }
 
 void MeshSkin::setBindShape(const float data[])
 {
-    for (int i = 0; i < 16; i++)
+    for (int i = 0; i < 16; ++i)
     {
         _bindShape[i] = data[i];
     }
@@ -71,36 +99,32 @@ void MeshSkin::setVertexInfluenceCount(unsigned int count)
     _vertexInfluenceCount = count;
 }
 
-void MeshSkin::setJointNames(const std::list<std::string>& list)
+void MeshSkin::setJointNames(const std::vector<std::string>& list)
 {
     _jointNames = list;
 }
 
-const std::list<std::string>& MeshSkin::getJointNames()
+const std::vector<std::string>& MeshSkin::getJointNames()
 {
     return _jointNames;
 }
 
-void MeshSkin::setJoints(const std::list<Node*>& list)
+void MeshSkin::setJoints(const std::vector<Node*>& list)
 {
     _joints = 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)
 {
-    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))
         {
@@ -110,4 +134,307 @@ bool MeshSkin::hasJoint(const char* id)
     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_
 #define MESHSKIN_H_
 
-#include <vector>
-
 #include "Base.h"
 #include "Object.h"
 #include "Matrix.h"
 #include "Animation.h"
+#include "BoundingVolume.h"
 
 namespace gameplay
 {
 
 class Node;
+class Mesh;
 
 class MeshSkin : public Object
 {
+    friend class Model;
+
 public:
 
     /**
@@ -36,11 +38,11 @@ public:
 
     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);
 
@@ -53,16 +55,19 @@ public:
      */
     bool hasJoint(const char* id);
 
+    void computeBounds();
+
 private:
 
+    Mesh* _mesh;
     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;
+    std::vector<BoundingVolume> _jointBounds;
 };
 
 }
+
 #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;
 }
+    
 const char* MeshSubSet::getElementName(void)
 {
     return "MeshSubSet";

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

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

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

-#endif

+}
+
+#endif
+

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

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

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

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

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

@@ -1,4 +1,7 @@
+#include "Base.h"
 #include "Node.h"
+#include "Matrix.h"
+#include "EncoderArguments.h"
 
 #define NODE 1
 #define JOINT 2
@@ -12,7 +15,6 @@ Node::Node(void) :
     _firstChild(NULL), _lastChild(NULL), _parent(NULL),
     _camera(NULL), _light(NULL), _model(NULL), _joint(false)
 {
-    setIdentityMatrix(_transform);
 }
 
 Node::~Node(void)
@@ -37,7 +39,7 @@ void Node::writeBinary(FILE* file)
     unsigned int type = _joint ? JOINT : NODE;
     write(type, file);
 
-    write(_transform, 16, file);
+    write(_transform.m, 16, file);
     // children
     write(getChildCount(), file); // write number of children
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
@@ -72,7 +74,10 @@ void Node::writeBinary(FILE* file)
     {
         writeZero(file);
     }
+
+    generateHeightmap();
 }
+
 void Node::writeText(FILE* file)
 {
     if (isJoint())
@@ -84,7 +89,7 @@ void Node::writeText(FILE* file)
         fprintElementStart(file);
     }
     fprintf(file, "<transform>");
-    fprintfMatrix4f(file, _transform);
+    fprintfMatrix4f(file, _transform.m);
     fprintf(file, "</transform>\n");
 
     // children
@@ -108,6 +113,29 @@ void Node::writeText(FILE* file)
         _model->writeText(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)
@@ -219,25 +247,48 @@ Node* Node::getParent() const
     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)
 {
     _model = model;
 }
 
+const Matrix& Node::getTransformMatrix() const
+{
+    return _transform;
+}
+
 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)
@@ -252,20 +303,12 @@ bool Node::isJoint()
 
 Camera* Node::getCamera() const
 {
-    if (_camera)
-    {
-        return _camera->getCamera();
-    }
-    return NULL;
+    return _camera;
 }
 
 Light* Node::getLight() const
 {
-    if (_light)
-    {
-        return _light->getLight();
-    }
-    return NULL;
+    return _light;
 }
 
 Model* Node::getModel() const
@@ -304,4 +347,4 @@ bool Node::hasLight() const
     return _light != NULL;
 }
 
-}
+}

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

@@ -1,11 +1,9 @@
 #ifndef NODE_H_
 #define NODE_H_
 
-#include <list>
-
 #include "Object.h"
-#include "CameraInstance.h"
-#include "LightInstance.h"
+#include "Camera.h"
+#include "Light.h"
 #include "Model.h"
 
 namespace gameplay
@@ -125,13 +123,28 @@ public:
      */
     Model* getModel() const;
 
+    /**
+     * Returns the transform matrix for the node.
+     */
+    const Matrix& getTransformMatrix() const;
+
     /**
      * Sets the transform for this node.
      */
     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);
 
     /**
@@ -157,7 +170,15 @@ public:
     bool hasLight() const;
     
 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;
     Node* _nextSibling;
@@ -166,14 +187,13 @@ private:
     Node* _lastChild;
     Node* _parent;
 
-    CameraInstance* _camera;
-    LightInstance* _light;
+    Camera* _camera;
+    Light* _light;
     Model* _model;
 
     bool _joint;
 };
 
-
 }
-#endif
 
+#endif

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

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

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

@@ -1,16 +1,11 @@
 #ifndef OBJ_H_
 #define OBJ_H_
 
-#include <iostream>
-#include <string>
-#include <list>
-#include <vector>
-
-#include "Base.h"
 #include "FileIO.h"
 
 namespace gameplay
 {
+
 /**
  * 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,
         ANIMATIONCHANNEL_ID = 5,
         NODEINSTANCE_ID = 8,
-        CAMERAINSTANCE_ID = 9,
-        LIGHTINSTANCE_ID = 10,
         MODEL_ID = 11,
         MATERIAL_ID = 16,
         EFFECT_ID = 17,
@@ -40,7 +33,6 @@ public:
         FONT_ID = 128,
     };
 
-
     /**
      * Constructor.
      */
@@ -118,8 +110,8 @@ public:
         // First write the size of the list
         write(list.size(), file);
         // 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);
         }
@@ -134,14 +126,15 @@ public:
         // First write the size of the vector
         write(vector.size(), file);
         // 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);
         }
     }
 
 private:
+
     /**
      * 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 "Quaternion.h"
 
@@ -162,7 +158,7 @@ void Quaternion::normalize(Quaternion* dst) const
     if (n == 1.0f)
         return;
 
-    n = sqrtf(n);
+    n = sqrt(n);
     // too close to zero
     if (n < 0.000001f)
         return;

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

@@ -1,7 +1,3 @@
-/*
- * Quaternion.h
- */
-
 #ifndef 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"
 
 namespace gameplay
@@ -83,4 +84,4 @@ Object* Reference::getObj()
     return _ref;
 }
 
-}
+}

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

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

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

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "ReferenceTable.h"
 
 namespace gameplay
@@ -30,7 +31,7 @@ Object* ReferenceTable::get(const std::string& xref)
 void ReferenceTable::writeBinary(FILE* 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);
     }
@@ -39,7 +40,7 @@ void ReferenceTable::writeBinary(FILE* file)
 void ReferenceTable::writeText(FILE* file)
 {
     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);
     }
@@ -48,7 +49,7 @@ void ReferenceTable::writeText(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;
         ref.updateOffset(file);
@@ -65,4 +66,4 @@ std::map<std::string, Reference>::iterator ReferenceTable::end()
     return _table.end();
 }
 
-}
+}

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

@@ -1,8 +1,6 @@
 #ifndef REFTABLE_H_
 #define REFTABLE_H_
 
-#include <map>
-
 #include "FileIO.h"
 #include "Reference.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"
 
 namespace gameplay
@@ -40,10 +39,11 @@ void Scene::writeBinary(FILE* file)
     }
     write(_ambientColor, Light::COLOR_SIZE, file);
 }
+
 void Scene::writeText(FILE* 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);
     }
@@ -67,7 +67,7 @@ void Scene::setActiveCameraNode(Node* node)
 
 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();
         if (n)
@@ -81,7 +81,7 @@ Node* Scene::getFirstCameraNode() const
 void Scene::calcAmbientColor()
 {
     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);
     }
@@ -91,6 +91,13 @@ void Scene::calcAmbientColor()
     _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
 {
     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();
 
+    /**
+     * Sets the scene's ambient color.
+     */
+    void setAmbientColor(float red, float green, float blue);
+
 private:
 
     /**
@@ -68,4 +73,5 @@ private:
 };
 
 }
+
 #endif

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

@@ -1,7 +1,6 @@
+#include "Base.h"
 #include "StringUtil.h"
 
-#include <string>
-
 namespace gameplay
 {
 
@@ -90,7 +89,7 @@ bool equalsIgnoreCase(const std::string& a, const char* b)
     {
         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]))
         {
@@ -100,4 +99,23 @@ bool equalsIgnoreCase(const std::string& a, const char* b)
     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_
 #define STRINGUTIL_H_
 
-#include <string>
-
 namespace gameplay
 {
 
@@ -19,5 +17,10 @@ bool equals(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

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

@@ -1,12 +1,16 @@
+#include "Base.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)
 {
     // offset dst bitmap by x,y.
     dstBitmap +=  (x + (y * dstWidth));
 
-    for (int i = 0; i < srcHeight; i++)
+    for (int i = 0; i < srcHeight; ++i)
     {
         memcpy(dstBitmap, (const void*)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.
     
     // 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)
         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.
         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).
             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;
     row = 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).
         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.
     char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
-    char fileVersion[2]    = {1, 0};
     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)
     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_FreeType(library);
     return 0;
-}
+}
+
+}

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

@@ -1,9 +1,4 @@
-#include <stdio.h>
 #include <ft2build.h>
-#include "string.h"
-#include <fstream>
-#include <math.h>
-
 #include FT_FREETYPE_H
 
 #define START_INDEX     32
@@ -11,6 +6,8 @@
 
 #define GLYPH_PADDING   4
 
+namespace gameplay
+{
 
 // Structure of Glyph.
 class Glyph
@@ -21,7 +18,6 @@ public:
     float uvCoords[4];
 };
 
-
 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);
@@ -30,4 +26,6 @@ void writeFloat(FILE* fp, float f);
 
 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
          */
         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).
          */
-        ANIMATE_ROTATE,
+        ANIMATE_ROTATE = 8,
 
         /**
          * 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
          */
-        ANIMATE_ROTATE_TRANSLATE,
+        ANIMATE_ROTATE_TRANSLATE = 16,
         /**
          * 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 "Vector2.h"
-#include "FileIO.h"
 
 namespace gameplay
 {
@@ -14,90 +9,76 @@ Vector2::Vector2()
 {
 }
 
-
 Vector2::Vector2(float x, float y)
 {
     set(x, y);
 }
 
-
 Vector2::Vector2(float* array)
 {
     set(array);
 }
 
-
 Vector2::Vector2(const Vector2& p1, const Vector2& p2)
 {
     set(p1, p2);
 }
 
-
 Vector2::Vector2(const Vector2& copy)
 {
     set(copy);
 }
 
-
 Vector2::~Vector2()
 {
 }
 
-
 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()
 {
-    static Vector2* value = new Vector2(1.0f, 1.0f);
-    return *value;
+    static Vector2 value(1.0f, 1.0f);
+    return value;
 }
 
-
 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()
 {
-    static Vector2* value = new Vector2(0.0f, 1.0f);
-    return *value;
+    static Vector2 value(0.0f, 1.0f);
+    return value;
 }
 
-
 bool Vector2::isZero() const
 {
     return x == 0.0f && y == 0.0f;
 }
 
-
 bool Vector2::isOne() const
 {
     return x == 1.0f && y == 1.0f;
 }
 
-
 float Vector2::angle(const Vector2& v1, const Vector2& v2)
 {
     float dz = v1.x * v2.y - v1.y * v2.x;
     return atan2f(fabsf(dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 
-
 void Vector2::add(const Vector2& v)
 {
     x += v.x;
     y += v.y;
 }
 
-
 void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
 {
     assert(dst);
@@ -106,7 +87,6 @@ void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
     dst->y = v1.y + v2.y;
 }
 
-
 void Vector2::clamp(const Vector2& min, const Vector2& max)
 {
     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;
 }
 
-
 void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Vector2* dst)
 {
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y ));
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     if ( 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;
 }
 
-
-float Vector2::distance(const Vector2& v)
+float Vector2::distance(const Vector2& v) const
 {
     float dx = v.x - x;
     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 dy = v.y - y;
     return (dx * dx + dy * dy);
 }
 
-
 float Vector2::dot(const Vector2& v)
 {
     return (x * v.x + y * v.y);
 }
 
-
 float Vector2::dot(const Vector2& v1, const Vector2& v2)
 {
     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);
 }
 
-
 void Vector2::negate()
 {
     x = -x;
     y = -y;
 }
 
-
 void Vector2::normalize()
 {
     normalize(this);
 }
 
-
 void Vector2::normalize(Vector2* dst)
 {
     assert(dst);
@@ -211,12 +181,12 @@ void Vector2::normalize(Vector2* dst)
     }
 
     float n = x * x + y * y;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
-    n = sqrtf(n);
-    // too close to zero
+    n = sqrt(n);
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
         return;
 
@@ -225,21 +195,18 @@ void Vector2::normalize(Vector2* dst)
     dst->y *= n;
 }
 
-
 void Vector2::scale(float scalar)
 {
     x *= scalar;
     y *= scalar;
 }
 
-
 void Vector2::scale(const Vector2& scale)
 {
     x *= scale.x;
     y *= scale.y;
 }
 
-
 void Vector2::rotate(const Vector2& point, float angle)
 {
     float sinAngle = sin(angle);
@@ -261,14 +228,12 @@ void Vector2::rotate(const Vector2& point, float angle)
     }
 }
 
-
 void Vector2::set(float x, float y)
 {
     this->x = x;
     this->y = y;
 }
 
-
 void Vector2::set(float* array)
 {
     assert(array);
@@ -277,28 +242,24 @@ void Vector2::set(float* array)
     y = array[1];
 }
 
-
 void Vector2::set(const Vector2& v)
 {
     this->x = v.x;
     this->y = v.y;
 }
 
-
 void Vector2::set(const Vector2& p1, const Vector2& p2)
 {
      x = p2.x - p1.x;
      y = p2.y - p1.y;
 }
 
-
 void Vector2::subtract(const Vector2& v)
 {
     x -= v.x;
     y -= v.y;
 }
 
-
 void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
 {
     assert(dst);
@@ -307,17 +268,4 @@ void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
     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_
 #define VECTOR2_H_
 
-
 namespace gameplay
 {
-// Forward declare
+
 class Matrix;
 
 /**
@@ -69,44 +64,44 @@ public:
     ~Vector2();
 
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      * @return The 2-element vector of 0s.
      */
     static const Vector2& zero();
 
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      * @return The 2-element vector of 1s.
      */
     static const Vector2& one();
 
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      * @return The 2-element unit vector along the x axis.
      */
     static const Vector2& unitX();
 
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      * @return The 2-element unit vector along the y axis.
      */
     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;
 
     /**
-     * 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;
 
@@ -116,7 +111,7 @@ public:
      * @param v1 The first 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);
 
@@ -160,9 +155,10 @@ public:
      * @param v The other vector.
      * 
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      */
-    float distance(const Vector2& v);
+    float distance(const Vector2& v) const;
 
     /**
      * Returns the squared distance between this vector and v.
@@ -175,9 +171,10 @@ public:
      * @param v The other vector.
      * 
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      */
-    float distanceSquared(const Vector2& v);
+    float distanceSquared(const Vector2& v) const;
 
     /**
      * Returns the dot product of this vector and the specified vector.
@@ -202,9 +199,10 @@ public:
      * Computes the length of this vector.
      *
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      */
-    float length();
+    float length() const;
 
     /**
      * Returns the squared length of this vector.
@@ -215,9 +213,10 @@ public:
      * instead of length.
      *
      * @return The squared length of the vector.
+     * 
      * @see length
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
     /**
      * Negates this vector.
@@ -242,7 +241,7 @@ public:
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
     void normalize(Vector2* dst);
 
@@ -264,7 +263,7 @@ public:
      * Rotates this vector by angle (specified in radians) around the given point.
      *
      * @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);
 
@@ -292,12 +291,15 @@ public:
 
     /**
      * 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);
 
     /**
      * 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.
      */
@@ -313,30 +315,99 @@ public:
      */
     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

+ 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 "Vector3.h"
-#include "FileIO.h"
 
 namespace gameplay
 {
@@ -14,77 +9,80 @@ Vector3::Vector3()
 {
 }
 
-
 Vector3::Vector3(float x, float y, float z)
 {
     set(x, y, z);
 }
 
-
 Vector3::Vector3(float* array)
 {
     set(array);
 }
 
-
 Vector3::Vector3(const Vector3& p1, const Vector3& p2)
 {
     set(p1, p2);
 }
 
-
 Vector3::Vector3(const Vector3& 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()
 {
 }
 
-
 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()
 {
-    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()
 {
-    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()
 {
-    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()
 {
-    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
 {
     return x == 0.0f && y == 0.0f && z == 0.0f;
 }
 
-
 bool Vector3::isOne() const
 {
     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 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)
 {
     x += v.x;
@@ -107,7 +104,6 @@ void Vector3::add(const Vector3& v)
     z += v.z;
 }
 
-
 void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
     assert(dst);
@@ -117,7 +113,6 @@ void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = v1.z + v2.z;
 }
 
-
 void Vector3::clamp(const Vector3& min, const Vector3& max)
 {
     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;
 }
 
-
 void Vector3::clamp(const Vector3& v, const Vector3& min, const Vector3& max, Vector3* dst)
 {
     assert(dst);
     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;
     if ( 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;
 }
 
-
 void Vector3::cross(const Vector3& v)
 {
     float tx = (y * v.z) - (z * v.y);
@@ -180,7 +173,6 @@ void Vector3::cross(const Vector3& v)
     z = tz;
 }
 
-
 void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
     assert(dst);
@@ -193,18 +185,16 @@ void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = z;
 }
 
-
-float Vector3::distance(const Vector3& v)
+float Vector3::distance(const Vector3& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
     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 dy = v.y - y;
@@ -213,31 +203,26 @@ float Vector3::distanceSquared(const Vector3& v)
     return (dx * dx + dy * dy + dz * dz);
 }
 
-
 float Vector3::dot(const Vector3& v)
 {
     return (x * v.x + y * v.y + z * v.z);
 }
 
-
 float Vector3::dot(const Vector3& v1, const Vector3& v2)
 {
     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);
 }
 
-
 void Vector3::negate()
 {
     x = -x;
@@ -245,13 +230,11 @@ void Vector3::negate()
     z = -z;
 }
 
-
 void Vector3::normalize()
 {
     normalize(this);
 }
 
-
 void Vector3::normalize(Vector3* dst) const
 {
     assert(dst);
@@ -264,12 +247,12 @@ void Vector3::normalize(Vector3* dst) const
     }
 
     float n = x * x + y * y + z * z;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
         return;
 
@@ -279,7 +262,6 @@ void Vector3::normalize(Vector3* dst) const
     dst->z *= n;
 }
 
-
 void Vector3::scale(float scalar)
 {
     x *= scalar;
@@ -287,7 +269,6 @@ void Vector3::scale(float scalar)
     z *= scalar;
 }
 
-
 void Vector3::set(float x, float y, float z)
 {
     this->x = x;
@@ -295,7 +276,6 @@ void Vector3::set(float x, float y, float z)
     this->z = z;
 }
 
-
 void Vector3::set(float* array)
 {
     assert(array);
@@ -305,7 +285,6 @@ void Vector3::set(float* array)
     z = array[2];
 }
 
-
 void Vector3::set(const Vector3& v)
 {
     this->x = v.x;
@@ -313,7 +292,6 @@ void Vector3::set(const Vector3& v)
     this->z = v.z;
 }
 
-
 void Vector3::set(const Vector3& p1, const Vector3& p2)
 {
     x = p2.x - p1.x;
@@ -321,7 +299,6 @@ void Vector3::set(const Vector3& p1, const Vector3& p2)
     z = p2.z - p1.z;
 }
 
-
 void Vector3::subtract(const Vector3& v)
 {
     x -= v.x;
@@ -329,7 +306,6 @@ void Vector3::subtract(const Vector3& v)
     z -= v.z;
 }
 
-
 void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
     assert(dst);
@@ -339,25 +315,4 @@ void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
     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_
 #define VECTOR3_H_
 
-
 namespace gameplay
 {
 
-// Forward declare
 class Matrix;
 class Quaternion;
 
@@ -19,7 +13,7 @@ class Quaternion;
  * When using a vector to represent a surface normal,
  * the vector should typically be normalized.
  * 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.
  */
 class Vector3
@@ -77,57 +71,67 @@ public:
      */
     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.
      */
     ~Vector3();
 
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      * @return The 3-element vector of 0s.
      */
     static const Vector3& zero();
 
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      * @return The 3-element vector of 1s.
      */
     static const Vector3& one();
 
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      * @return The 3-element unit vector along the x axis.
      */
     static const Vector3& unitX();
 
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      * @return The 3-element unit vector along the y axis.
      */
     static const Vector3& unitY();
 
     /**
-     * The unit z vector.
+     * Returns the unit z vector.
      *
      * @return The 3-element unit vector along the z axis.
      */
     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;
 
     /**
-     * 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;
 
@@ -137,7 +141,7 @@ public:
      * @param v1 The first 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);
 
@@ -179,7 +183,7 @@ public:
     /**
      * 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);
 
@@ -198,9 +202,10 @@ public:
      * @param v The other vector.
      * 
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      */
-    float distance(const Vector3& v);
+    float distance(const Vector3& v) const;
 
     /**
      * Returns the squared distance between this vector and v.
@@ -213,9 +218,10 @@ public:
      * @param v The other vector.
      * 
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      */
-    float distanceSquared(const Vector3& v);
+    float distanceSquared(const Vector3& v) const;
 
     /**
      * Returns the dot product of this vector and the specified vector.
@@ -240,9 +246,10 @@ public:
      * Computes the length of this vector.
      *
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      */
-    float length();
+    float length() const;
 
     /**
      * Returns the squared length of this vector.
@@ -253,9 +260,10 @@ public:
      * instead of length.
      *
      * @return The squared length of the vector.
+     * 
      * @see length
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
     /**
      * Negates this vector.
@@ -280,7 +288,7 @@ public:
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
     void normalize(Vector3* dst) const;
 
@@ -321,7 +329,7 @@ public:
 
     /**
      * 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.
      */
@@ -337,36 +345,99 @@ public:
      */
     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

+ 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 "Vector4.h"
-#include "FileIO.h"
 
 namespace gameplay
 {
@@ -14,100 +9,100 @@ Vector4::Vector4()
 {
 }
 
-
 Vector4::Vector4(float x, float y, float z, float w)
 {
     set(x, y, z, w);
 }
 
-
 Vector4::Vector4(float* src)
 {
     set(src);
 }
 
-
 Vector4::Vector4(const Vector4& p1, const Vector4& p2)
 {
     set(p1, p2);
 }
 
-
 Vector4::Vector4(const Vector4& 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()
 {
 }
 
-
 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()
 {
-    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()
 {
-    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()
 {
-    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()
 {
-    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()
 {
-    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
 {
     return x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f;
 }
 
-
 bool Vector4::isOne() const
 {
     return x == 1.0f && y == 1.0f && z == 1.0f && z == 1.0f;
 }
 
-
 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 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;
 
-    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)
 {
     x += v.x;
@@ -116,7 +111,6 @@ void Vector4::add(const Vector4& v)
     w += v.w;
 }
 
-
 void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
 {
     assert(dst);
@@ -127,7 +121,6 @@ void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
     dst->w = v1.w + v2.w;
 }
 
-
 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));
@@ -157,13 +150,12 @@ void Vector4::clamp(const Vector4& min, const Vector4& max)
         w = max.w;
 }
 
-
 void Vector4::clamp(const Vector4& v, const Vector4& min, const Vector4& max, Vector4* dst)
 {
     assert(dst);
     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;
     if ( 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;
 }
 
-
-float Vector4::distance(const Vector4& v)
+float Vector4::distance(const Vector4& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
     float dz = v.z - z;
     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 dy = v.y - y;
@@ -214,31 +204,27 @@ float Vector4::distanceSquared(const Vector4& v)
     return (dx * dx + dy * dy + dz * dz + dw * dw);
 }
 
-
 float Vector4::dot(const Vector4& v)
 {
     return (x * v.x + y * v.y + z * v.z + w * v.w);
 }
 
-
 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);
 }
 
-
-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);
 }
 
-
 void Vector4::negate()
 {
     x = -x;
@@ -247,13 +233,11 @@ void Vector4::negate()
     w = -w;
 }
 
-
 void Vector4::normalize()
 {
     normalize(this);
 }
 
-
 void Vector4::normalize(Vector4* dst)
 {
     assert(dst);
@@ -267,12 +251,12 @@ void Vector4::normalize(Vector4* dst)
     }
 
     float n = x * x + y * y + z * z + w * w;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
         return;
 
@@ -283,7 +267,6 @@ void Vector4::normalize(Vector4* dst)
     dst->w *= n;
 }
 
-
 void Vector4::scale(float scalar)
 {
     x *= scalar;
@@ -292,7 +275,6 @@ void Vector4::scale(float scalar)
     w *= scalar;
 }
 
-
 void Vector4::set(float x, float y, float z, float w)
 {
     this->x = x;
@@ -301,7 +283,6 @@ void Vector4::set(float x, float y, float z, float w)
     this->w = w;
 }
 
-
 void Vector4::set(float* array)
 {
     assert(array);
@@ -312,7 +293,6 @@ void Vector4::set(float* array)
     w = array[3];
 }
 
-
 void Vector4::set(const Vector4& v)
 {
     this->x = v.x;
@@ -321,7 +301,6 @@ void Vector4::set(const Vector4& v)
     this->w = v.w;
 }
 
-
 void Vector4::set(const Vector4& p1, const Vector4& p2)
 {
     x = p2.x - p1.x;
@@ -330,7 +309,6 @@ void Vector4::set(const Vector4& p1, const Vector4& p2)
     w = p2.w - p1.w;
 }
 
-
 void Vector4::subtract(const Vector4& v)
 {
     x -= v.x;
@@ -339,7 +317,6 @@ void Vector4::subtract(const Vector4& v)
     w -= v.w;
 }
 
-
 void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
 {
     assert(dst);
@@ -350,17 +327,4 @@ void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
     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_
 #define VECTOR4_H_
 
-#include "FileIO.h"
-
 namespace gameplay
 {
 
-// Forward declare
 class Matrix;
 
 /**
@@ -79,64 +72,74 @@ public:
      */
     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.
      */
     ~Vector4();
 
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      * @return The 4-element vector of 0s.
      */
     static const Vector4& zero();
 
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      * @return The 4-element vector of 1s.
      */
     static const Vector4& one();
 
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      * @return The 4-element unit vector along the x axis.
      */
     static const Vector4& unitX();
 
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      * @return The 4-element unit vector along the y axis.
      */
     static const Vector4& unitY();
 
     /**
-     * The unit z vector.
+     * Returns the unit z vector.
      *
      * @return The 4-element unit vector along the z axis.
      */
     static const Vector4& unitZ();
 
     /**
-     * The unit w vector.
+     * Returns the unit w vector.
      *
      * @return The 4-element unit vector along the w axis.
      */
     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;
 
     /**
-     * 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;
 
@@ -146,7 +149,7 @@ public:
      * @param v1 The first 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);
 
@@ -190,9 +193,10 @@ public:
      * @param v The other vector.
      * 
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      */
-    float distance(const Vector4& v);
+    float distance(const Vector4& v) const;
 
     /**
      * Returns the squared distance between this vector and v.
@@ -205,9 +209,10 @@ public:
      * @param v The other vector.
      * 
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      */
-    float distanceSquared(const Vector4& v);
+    float distanceSquared(const Vector4& v) const;
 
     /**
      * Returns the dot product of this vector and the specified vector.
@@ -232,9 +237,10 @@ public:
      * Computes the length of this vector.
      *
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      */
-    float length();
+    float length() const;
 
     /**
      * Returns the squared length of this vector.
@@ -245,9 +251,10 @@ public:
      * instead of length.
      *
      * @return The squared length of the vector.
+     * 
      * @see length
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
     /**
      * Negates this vector.
@@ -272,7 +279,7 @@ public:
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
     void normalize(Vector4* dst);
 
@@ -309,12 +316,15 @@ public:
 
     /**
      * 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);
 
     /**
      * 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.
      */
@@ -330,41 +340,99 @@ public:
      */
     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"
 
 namespace gameplay
 {
 
 Vertex::Vertex(void)
+    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasColor(false), hasWeights(false)
 {
-    reset();
 }
 
 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 count = 3;
@@ -40,66 +31,78 @@ unsigned int Vertex::byteSize() const
 
 void Vertex::writeBinary(FILE* file) const
 {
-    position.writeBinary(file);
+    writeVectorBinary(position, file);
     if (hasNormal)
     {
-        normal.writeBinary(file);
+        writeVectorBinary(normal, file);
     }
     if (hasTangent)
     {
-        tangent.writeBinary(file);
+        writeVectorBinary(tangent, file);
     }
     if (hasBinormal)
     {
-        binormal.writeBinary(file);
+        writeVectorBinary(binormal, file);
     }
     if (hasTexCoord)
     {
-        texCoord.writeBinary(file);
+        writeVectorBinary(texCoord, file);
     }
     // TODO add vertex color?
     //if (hasColor)
     //{
-    //    color.writeBinary(file);
+    //    writeVectorBinary(color, file);
     //}
     if (hasWeights)
     {
-        blendWeights.writeBinary(file);
-        blendIndices.writeBinary(file);
+        writeVectorBinary(blendWeights, file);
+        writeVectorBinary(blendIndices, file);
     }
 }
 
 void Vertex::writeText(FILE* file) const
 {
     write("// position\n", file);
-    position.writeText(file);
+    writeVectorText(position, file);
     if (hasNormal)
     {
         write("// normal\n", file);
-        normal.writeText(file);
+        writeVectorText(normal, file);
     }
     if (hasTangent)
     {
         write("// tanget\n", file);
-        tangent.writeText(file);
+        writeVectorText(tangent, file);
     }
     if (hasBinormal)
     {
         write("// binormal\n", file);
-        binormal.writeText(file);
+        writeVectorText(binormal, file);
     }
     if (hasTexCoord)
     {
         write("// texCoord\n", file);
-        texCoord.writeText(file);
+        writeVectorText(texCoord, file);
     }
     if (hasWeights)
     {
         write("// blendWeights\n", file);
-        blendWeights.writeText(file);
+        writeVectorText(blendWeights, 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.
      */
-    virtual ~Vertex(void);
+    ~Vertex(void);
 
     Vector3 position;
     Vector3 normal;
@@ -73,8 +73,6 @@ public:
             blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
 
-    void reset();
-
     /**
      * Returns the size of this vertex in bytes.
      */
@@ -89,7 +87,12 @@ public:
      * Writes this vertex to a text file stream.
      */
     void writeText(FILE* file) const;
-};
 
+    /**
+     * Normalizes the blend weights of this vertex so that they add up to 1.0.
+     */
+    void normalizeBlendWeight();
+};
 }
+
 #endif

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

@@ -1,3 +1,4 @@
+#include "Base.h"
 #include "VertexElement.h"
 
 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

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

@@ -1,6 +1,6 @@
-#include <string>
-
+#include "Base.h"
 #include "DAESceneEncoder.h"
+#include "FBXSceneEncoder.h"
 #include "TTFFontEncoder.h"
 #include "GPBDecoder.h"
 #include "EncoderArguments.h"
@@ -55,21 +55,33 @@ int main(int argc, const char** argv)
     {
     case EncoderArguments::FILEFORMAT_DAE:
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             DAESceneEncoder daeEncoder;
             daeEncoder.write(realpath, arguments);
             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:
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             std::string id = getFileName(realpath);
             writeFont(realpath.c_str(), arguments.getFontSize(), id.c_str(), arguments.fontPreviewEnabled());
             break;
         }
     case EncoderArguments::FILEFORMAT_GPB:
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             GPBDecoder decoder;
             decoder.readBinary(realpath);
             break;
@@ -83,4 +95,3 @@ int main(int argc, const char** argv)
 
     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

Неке датотеке нису приказане због велике количине промена