Quellcode durchsuchen

Merge branch 'next' of https://github.com/blackberry-gaming/GamePlay into next-ablake

Conflicts:
	gameplay-api/html/_animation_8h_source.html
	gameplay-api/html/_animation_clip_8h_source.html
	gameplay-api/html/_animation_controller_8h_source.html
	gameplay-api/html/_animation_target_8h_source.html
	gameplay-api/html/_animation_value_8h_source.html
	gameplay-api/html/_audio_buffer_8h_source.html
	gameplay-api/html/_audio_controller_8h_source.html
	gameplay-api/html/_audio_listener_8h_source.html
	gameplay-api/html/_audio_source_8h_source.html
	gameplay-api/html/_base_8h_source.html
	gameplay-api/html/_bounding_box_8h_source.html
	gameplay-api/html/_bounding_sphere_8h_source.html
	gameplay-api/html/_camera_8h_source.html
	gameplay-api/html/_control_8h_source.html
	gameplay-api/html/_curve_8h_source.html
	gameplay-api/html/_debug_new_8h_source.html
	gameplay-api/html/_depth_stencil_target_8h_source.html
	gameplay-api/html/_effect_8h_source.html
	gameplay-api/html/_file_system_8h_source.html
	gameplay-api/html/_flow_layout_8h_source.html
	gameplay-api/html/_font_8h_source.html
	gameplay-api/html/_form_8h_source.html
	gameplay-api/html/_frame_buffer_8h_source.html
	gameplay-api/html/_frustum_8h_source.html
	gameplay-api/html/_game_8h_source.html
	gameplay-api/html/_image_8h_source.html
	gameplay-api/html/_joint_8h_source.html
	gameplay-api/html/_keyboard_8h_source.html
	gameplay-api/html/_label_8h_source.html
	gameplay-api/html/_light_8h_source.html
	gameplay-api/html/_material_8h_source.html
	gameplay-api/html/_material_parameter_8h_source.html
	gameplay-api/html/_matrix_8h_source.html
	gameplay-api/html/_mesh_8h_source.html
	gameplay-api/html/_mesh_batch_8h_source.html
	gameplay-api/html/_mesh_part_8h_source.html
	gameplay-api/html/_mesh_skin_8h_source.html
	gameplay-api/html/_model_8h_source.html
	gameplay-api/html/_mouse_8h_source.html
	gameplay-api/html/_node_8h_source.html
	gameplay-api/html/_package_8h_source.html
	gameplay-api/html/_particle_emitter_8h_source.html
	gameplay-api/html/_pass_8h_source.html
	gameplay-api/html/_physics_constraint_8h_source.html
	gameplay-api/html/_physics_controller_8h_source.html
	gameplay-api/html/_physics_fixed_constraint_8h_source.html
	gameplay-api/html/_physics_generic_constraint_8h_source.html
	gameplay-api/html/_physics_hinge_constraint_8h_source.html
	gameplay-api/html/_physics_motion_state_8h_source.html
	gameplay-api/html/_physics_rigid_body_8h_source.html
	gameplay-api/html/_physics_socket_constraint_8h_source.html
	gameplay-api/html/_physics_spring_constraint_8h_source.html
	gameplay-api/html/_plane_8h_source.html
	gameplay-api/html/_platform_8h_source.html
	gameplay-api/html/_properties_8h_source.html
	gameplay-api/html/_quaternion_8h_source.html
	gameplay-api/html/_ray_8h_source.html
	gameplay-api/html/_rectangle_8h_source.html
	gameplay-api/html/_ref_8h_source.html
	gameplay-api/html/_render_state_8h_source.html
	gameplay-api/html/_render_target_8h_source.html
	gameplay-api/html/_scene_8h_source.html
	gameplay-api/html/_scene_loader_8h_source.html
	gameplay-api/html/_sprite_batch_8h_source.html
	gameplay-api/html/_technique_8h_source.html
	gameplay-api/html/_texture_8h_source.html
	gameplay-api/html/_touch_8h_source.html
	gameplay-api/html/_transform_8h_source.html
	gameplay-api/html/_vector2_8h_source.html
	gameplay-api/html/_vector3_8h_source.html
	gameplay-api/html/_vector4_8h_source.html
	gameplay-api/html/_vertex_attribute_binding_8h_source.html
	gameplay-api/html/_vertex_format_8h_source.html
	gameplay-api/html/_vertical_layout_8h_source.html
	gameplay-api/html/_viewport_8h_source.html
	gameplay-api/html/annotated.html
	gameplay-api/html/classes.html
	gameplay-api/html/classgameplay_1_1_animation-members.html
	gameplay-api/html/classgameplay_1_1_animation.html
	gameplay-api/html/classgameplay_1_1_animation_clip-members.html
	gameplay-api/html/classgameplay_1_1_animation_clip.html
	gameplay-api/html/classgameplay_1_1_animation_clip_1_1_listener-members.html
	gameplay-api/html/classgameplay_1_1_animation_clip_1_1_listener.html
	gameplay-api/html/classgameplay_1_1_animation_controller-members.html
	gameplay-api/html/classgameplay_1_1_animation_controller.html
	gameplay-api/html/classgameplay_1_1_animation_target-members.html
	gameplay-api/html/classgameplay_1_1_animation_target.html
	gameplay-api/html/classgameplay_1_1_animation_value-members.html
	gameplay-api/html/classgameplay_1_1_animation_value.html
	gameplay-api/html/classgameplay_1_1_audio_buffer-members.html
	gameplay-api/html/classgameplay_1_1_audio_buffer.html
	gameplay-api/html/classgameplay_1_1_audio_controller-members.html
	gameplay-api/html/classgameplay_1_1_audio_controller.html
	gameplay-api/html/classgameplay_1_1_audio_listener-members.html
	gameplay-api/html/classgameplay_1_1_audio_listener.html
	gameplay-api/html/classgameplay_1_1_audio_source-members.html
	gameplay-api/html/classgameplay_1_1_audio_source.html
	gameplay-api/html/classgameplay_1_1_bounding_box-members.html
	gameplay-api/html/classgameplay_1_1_bounding_box.html
	gameplay-api/html/classgameplay_1_1_bounding_sphere-members.html
	gameplay-api/html/classgameplay_1_1_bounding_sphere.html
	gameplay-api/html/classgameplay_1_1_button-members.html
	gameplay-api/html/classgameplay_1_1_button.png
	gameplay-api/html/classgameplay_1_1_camera-members.html
	gameplay-api/html/classgameplay_1_1_camera.html
	gameplay-api/html/classgameplay_1_1_control.png
	gameplay-api/html/classgameplay_1_1_curve-members.html
	gameplay-api/html/classgameplay_1_1_curve.html
	gameplay-api/html/classgameplay_1_1_depth_stencil_target-members.html
	gameplay-api/html/classgameplay_1_1_depth_stencil_target.html
	gameplay-api/html/classgameplay_1_1_effect-members.html
	gameplay-api/html/classgameplay_1_1_effect.html
	gameplay-api/html/classgameplay_1_1_file_system-members.html
	gameplay-api/html/classgameplay_1_1_file_system.html
	gameplay-api/html/classgameplay_1_1_font-members.html
	gameplay-api/html/classgameplay_1_1_font.html
	gameplay-api/html/classgameplay_1_1_font_1_1_glyph-members.html
	gameplay-api/html/classgameplay_1_1_font_1_1_glyph.html
	gameplay-api/html/classgameplay_1_1_form.html
	gameplay-api/html/classgameplay_1_1_form.png
	gameplay-api/html/classgameplay_1_1_frame_buffer-members.html
	gameplay-api/html/classgameplay_1_1_frame_buffer.html
	gameplay-api/html/classgameplay_1_1_frustum-members.html
	gameplay-api/html/classgameplay_1_1_frustum.html
	gameplay-api/html/classgameplay_1_1_game-members.html
	gameplay-api/html/classgameplay_1_1_game.html
	gameplay-api/html/classgameplay_1_1_image-members.html
	gameplay-api/html/classgameplay_1_1_image.html
	gameplay-api/html/classgameplay_1_1_joint-members.html
	gameplay-api/html/classgameplay_1_1_joint.html
	gameplay-api/html/classgameplay_1_1_keyboard-members.html
	gameplay-api/html/classgameplay_1_1_keyboard.html
	gameplay-api/html/classgameplay_1_1_label-members.html
	gameplay-api/html/classgameplay_1_1_label.png
	gameplay-api/html/classgameplay_1_1_light-members.html
	gameplay-api/html/classgameplay_1_1_light.html
	gameplay-api/html/classgameplay_1_1_material-members.html
	gameplay-api/html/classgameplay_1_1_material.html
	gameplay-api/html/classgameplay_1_1_material_parameter-members.html
	gameplay-api/html/classgameplay_1_1_material_parameter.html
	gameplay-api/html/classgameplay_1_1_matrix-members.html
	gameplay-api/html/classgameplay_1_1_matrix.html
	gameplay-api/html/classgameplay_1_1_mesh-members.html
	gameplay-api/html/classgameplay_1_1_mesh.html
	gameplay-api/html/classgameplay_1_1_mesh_batch-members.html
	gameplay-api/html/classgameplay_1_1_mesh_batch.html
	gameplay-api/html/classgameplay_1_1_mesh_part-members.html
	gameplay-api/html/classgameplay_1_1_mesh_part.html
	gameplay-api/html/classgameplay_1_1_mesh_skin-members.html
	gameplay-api/html/classgameplay_1_1_mesh_skin.html
	gameplay-api/html/classgameplay_1_1_model-members.html
	gameplay-api/html/classgameplay_1_1_model.html
	gameplay-api/html/classgameplay_1_1_node-members.html
	gameplay-api/html/classgameplay_1_1_node.html
	gameplay-api/html/classgameplay_1_1_package-members.html
	gameplay-api/html/classgameplay_1_1_package.html
	gameplay-api/html/classgameplay_1_1_particle_emitter-members.html
	gameplay-api/html/classgameplay_1_1_particle_emitter.html
	gameplay-api/html/classgameplay_1_1_pass-members.html
	gameplay-api/html/classgameplay_1_1_pass.html
	gameplay-api/html/classgameplay_1_1_physics_constraint-members.html
	gameplay-api/html/classgameplay_1_1_physics_constraint.html
	gameplay-api/html/classgameplay_1_1_physics_controller-members.html
	gameplay-api/html/classgameplay_1_1_physics_controller.html
	gameplay-api/html/classgameplay_1_1_physics_controller_1_1_listener-members.html
	gameplay-api/html/classgameplay_1_1_physics_controller_1_1_listener.html
	gameplay-api/html/classgameplay_1_1_physics_fixed_constraint-members.html
	gameplay-api/html/classgameplay_1_1_physics_fixed_constraint.html
	gameplay-api/html/classgameplay_1_1_physics_generic_constraint-members.html
	gameplay-api/html/classgameplay_1_1_physics_generic_constraint.html
	gameplay-api/html/classgameplay_1_1_physics_hinge_constraint-members.html
	gameplay-api/html/classgameplay_1_1_physics_hinge_constraint.html
	gameplay-api/html/classgameplay_1_1_physics_motion_state-members.html
	gameplay-api/html/classgameplay_1_1_physics_motion_state.html
	gameplay-api/html/classgameplay_1_1_physics_rigid_body-members.html
	gameplay-api/html/classgameplay_1_1_physics_rigid_body.html
	gameplay-api/html/classgameplay_1_1_physics_rigid_body_1_1_collision_pair-members.html
	gameplay-api/html/classgameplay_1_1_physics_rigid_body_1_1_collision_pair.html
	gameplay-api/html/classgameplay_1_1_physics_rigid_body_1_1_listener-members.html
	gameplay-api/html/classgameplay_1_1_physics_rigid_body_1_1_listener.html
	gameplay-api/html/classgameplay_1_1_physics_socket_constraint-members.html
	gameplay-api/html/classgameplay_1_1_physics_socket_constraint.html
	gameplay-api/html/classgameplay_1_1_physics_spring_constraint-members.html
	gameplay-api/html/classgameplay_1_1_physics_spring_constraint.html
	gameplay-api/html/classgameplay_1_1_plane-members.html
	gameplay-api/html/classgameplay_1_1_plane.html
	gameplay-api/html/classgameplay_1_1_platform-members.html
	gameplay-api/html/classgameplay_1_1_platform.html
	gameplay-api/html/classgameplay_1_1_properties-members.html
	gameplay-api/html/classgameplay_1_1_properties.html
	gameplay-api/html/classgameplay_1_1_quaternion-members.html
	gameplay-api/html/classgameplay_1_1_quaternion.html
	gameplay-api/html/classgameplay_1_1_ray-members.html
	gameplay-api/html/classgameplay_1_1_ray.html
	gameplay-api/html/classgameplay_1_1_rectangle-members.html
	gameplay-api/html/classgameplay_1_1_rectangle.html
	gameplay-api/html/classgameplay_1_1_ref-members.html
	gameplay-api/html/classgameplay_1_1_ref.html
	gameplay-api/html/classgameplay_1_1_ref.png
	gameplay-api/html/classgameplay_1_1_render_state-members.html
	gameplay-api/html/classgameplay_1_1_render_state.html
	gameplay-api/html/classgameplay_1_1_render_state_1_1_state_block-members.html
	gameplay-api/html/classgameplay_1_1_render_state_1_1_state_block.html
	gameplay-api/html/classgameplay_1_1_render_target-members.html
	gameplay-api/html/classgameplay_1_1_render_target.html
	gameplay-api/html/classgameplay_1_1_scene-members.html
	gameplay-api/html/classgameplay_1_1_scene.html
	gameplay-api/html/classgameplay_1_1_scene_loader-members.html
	gameplay-api/html/classgameplay_1_1_scene_loader.html
	gameplay-api/html/classgameplay_1_1_sprite_batch-members.html
	gameplay-api/html/classgameplay_1_1_sprite_batch.html
	gameplay-api/html/classgameplay_1_1_technique-members.html
	gameplay-api/html/classgameplay_1_1_technique.html
	gameplay-api/html/classgameplay_1_1_texture-members.html
	gameplay-api/html/classgameplay_1_1_texture.html
	gameplay-api/html/classgameplay_1_1_texture_1_1_sampler-members.html
	gameplay-api/html/classgameplay_1_1_texture_1_1_sampler.html
	gameplay-api/html/classgameplay_1_1_touch-members.html
	gameplay-api/html/classgameplay_1_1_touch.html
	gameplay-api/html/classgameplay_1_1_transform-members.html
	gameplay-api/html/classgameplay_1_1_transform.html
	gameplay-api/html/classgameplay_1_1_transform_1_1_listener-members.html
	gameplay-api/html/classgameplay_1_1_transform_1_1_listener.html
	gameplay-api/html/classgameplay_1_1_uniform-members.html
	gameplay-api/html/classgameplay_1_1_uniform.html
	gameplay-api/html/classgameplay_1_1_vector2-members.html
	gameplay-api/html/classgameplay_1_1_vector2.html
	gameplay-api/html/classgameplay_1_1_vector3-members.html
	gameplay-api/html/classgameplay_1_1_vector3.html
	gameplay-api/html/classgameplay_1_1_vector4-members.html
	gameplay-api/html/classgameplay_1_1_vector4.html
	gameplay-api/html/classgameplay_1_1_vertex_attribute_binding-members.html
	gameplay-api/html/classgameplay_1_1_vertex_attribute_binding.html
	gameplay-api/html/classgameplay_1_1_vertex_format-members.html
	gameplay-api/html/classgameplay_1_1_vertex_format.html
	gameplay-api/html/classgameplay_1_1_vertex_format_1_1_element-members.html
	gameplay-api/html/classgameplay_1_1_vertex_format_1_1_element.html
	gameplay-api/html/classgameplay_1_1_viewport-members.html
	gameplay-api/html/classgameplay_1_1_viewport.html
	gameplay-api/html/files.html
	gameplay-api/html/functions.html
	gameplay-api/html/functions_0x61.html
	gameplay-api/html/functions_0x62.html
	gameplay-api/html/functions_0x63.html
	gameplay-api/html/functions_0x64.html
	gameplay-api/html/functions_0x65.html
	gameplay-api/html/functions_0x66.html
	gameplay-api/html/functions_0x67.html
	gameplay-api/html/functions_0x68.html
	gameplay-api/html/functions_0x69.html
	gameplay-api/html/functions_0x6a.html
	gameplay-api/html/functions_0x6b.html
	gameplay-api/html/functions_0x6c.html
	gameplay-api/html/functions_0x6d.html
	gameplay-api/html/functions_0x6e.html
	gameplay-api/html/functions_0x6f.html
	gameplay-api/html/functions_0x70.html
	gameplay-api/html/functions_0x71.html
	gameplay-api/html/functions_0x72.html
	gameplay-api/html/functions_0x73.html
	gameplay-api/html/functions_0x74.html
	gameplay-api/html/functions_0x75.html
	gameplay-api/html/functions_0x76.html
	gameplay-api/html/functions_0x77.html
	gameplay-api/html/functions_0x78.html
	gameplay-api/html/functions_0x79.html
	gameplay-api/html/functions_0x7a.html
	gameplay-api/html/functions_0x7e.html
	gameplay-api/html/functions_enum.html
	gameplay-api/html/functions_eval.html
	gameplay-api/html/functions_func.html
	gameplay-api/html/functions_func_0x62.html
	gameplay-api/html/functions_func_0x63.html
	gameplay-api/html/functions_func_0x64.html
	gameplay-api/html/functions_func_0x65.html
	gameplay-api/html/functions_func_0x66.html
	gameplay-api/html/functions_func_0x67.html
	gameplay-api/html/functions_func_0x69.html
	gameplay-api/html/functions_func_0x6a.html
	gameplay-api/html/functions_func_0x6b.html
	gameplay-api/html/functions_func_0x6c.html
	gameplay-api/html/functions_func_0x6d.html
	gameplay-api/html/functions_func_0x6e.html
	gameplay-api/html/functions_func_0x6f.html
	gameplay-api/html/functions_func_0x70.html
	gameplay-api/html/functions_func_0x71.html
	gameplay-api/html/functions_func_0x72.html
	gameplay-api/html/functions_func_0x73.html
	gameplay-api/html/functions_func_0x74.html
	gameplay-api/html/functions_func_0x75.html
	gameplay-api/html/functions_func_0x76.html
	gameplay-api/html/functions_func_0x7a.html
	gameplay-api/html/functions_func_0x7e.html
	gameplay-api/html/functions_vars.html
	gameplay-api/html/gameplay-main-qnx_8h_source.html
	gameplay-api/html/gameplay-main-win32_8h_source.html
	gameplay-api/html/gameplay_8h_source.html
	gameplay-api/html/hierarchy.html
	gameplay-api/html/index.html
	gameplay-api/html/namespacegameplay.html
	gameplay-api/html/namespacemembers.html
	gameplay-api/html/namespacemembers_func.html
	gameplay-api/html/namespaces.html
	gameplay-api/html/navtree.js
	gameplay-api/html/search/all_61.html
	gameplay-api/html/search/all_62.html
	gameplay-api/html/search/all_63.html
	gameplay-api/html/search/all_64.html
	gameplay-api/html/search/all_65.html
	gameplay-api/html/search/all_66.html
	gameplay-api/html/search/all_67.html
	gameplay-api/html/search/all_69.html
	gameplay-api/html/search/all_6c.html
	gameplay-api/html/search/all_6d.html
	gameplay-api/html/search/all_6f.html
	gameplay-api/html/search/all_70.html
	gameplay-api/html/search/all_72.html
	gameplay-api/html/search/all_73.html
	gameplay-api/html/search/all_74.html
	gameplay-api/html/search/all_76.html
	gameplay-api/html/search/all_7e.html
	gameplay-api/html/search/classes_6c.html
	gameplay-api/html/search/classes_6d.html
	gameplay-api/html/search/classes_73.html
	gameplay-api/html/search/classes_74.html
	gameplay-api/html/search/functions_61.html
	gameplay-api/html/search/functions_63.html
	gameplay-api/html/search/functions_64.html
	gameplay-api/html/search/functions_67.html
	gameplay-api/html/search/functions_69.html
	gameplay-api/html/search/functions_6c.html
	gameplay-api/html/search/functions_72.html
	gameplay-api/html/search/functions_73.html
	gameplay-api/html/search/functions_74.html
	gameplay-api/html/search/functions_7e.html
	gameplay-api/html/search/search.js
	gameplay-api/html/search/variables_61.html
	gameplay-api/html/structgameplay_1_1_physics_controller_1_1_debug_drawer_1_1_debug_vertex.html
	gameplay-api/html/structgameplay_1_1_sprite_vertex-members.html
	gameplay-api/html/structgameplay_1_1_sprite_vertex.html
	gameplay-api/html/structgameplay_1_1_transform_1_1_transform_listener-members.html
	gameplay-api/html/structgameplay_1_1_transform_1_1_transform_listener.html
	gameplay/gameplay.vcxproj.filters
	gameplay/src/Font.cpp
	gameplay/src/Font.h
	gameplay/src/PlatformMacOS.mm
	gameplay/src/PlatformQNX.cpp
	gameplay/src/PlatformWin32.cpp
	gameplay/src/gameplay.dox
	gameplay/src/gameplay.h
Adam Blake vor 14 Jahren
Ursprung
Commit
ad0e8c5b47
100 geänderte Dateien mit 4495 neuen und 1117 gelöschten Zeilen
  1. 60 1
      .gitignore
  2. 16 12
      README.md
  3. 1 1
      gameplay-encoder/README.md
  4. 5 4
      gameplay-encoder/gameplay-encoder.vcxproj
  5. 3 0
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  6. 84 0
      gameplay-encoder/gameplay-encoder.xcodeproj/xcshareddata/xcschemes/gameplay-encoder.xcscheme
  7. 10 0
      gameplay-encoder/src/Animation.cpp
  8. 17 1
      gameplay-encoder/src/Animation.h
  9. 19 14
      gameplay-encoder/src/AnimationChannel.cpp
  10. 12 1
      gameplay-encoder/src/AnimationChannel.h
  11. 8 0
      gameplay-encoder/src/Base.h
  12. 86 44
      gameplay-encoder/src/DAESceneEncoder.cpp
  13. 1 1
      gameplay-encoder/src/EncoderArguments.cpp
  14. 103 53
      gameplay-encoder/src/FBXSceneEncoder.cpp
  15. 154 0
      gameplay-encoder/src/GPBFile.cpp
  16. 19 0
      gameplay-encoder/src/GPBFile.h
  17. 0 2
      gameplay-encoder/src/Mesh.cpp
  18. 2 4
      gameplay-encoder/src/Mesh.h
  19. 2 2
      gameplay-encoder/src/Node.cpp
  20. 1 1
      gameplay-encoder/src/Node.h
  21. 81 37
      gameplay-encoder/src/Quaternion.cpp
  22. 95 39
      gameplay-encoder/src/Quaternion.h
  23. 19 0
      gameplay-encoder/src/Quaternion.inl
  24. 89 0
      gameplay-encoder/src/Transform.cpp
  25. 11 0
      gameplay-encoder/src/Transform.h
  26. 18 12
      gameplay-encoder/src/Vertex.cpp
  27. 21 7
      gameplay-encoder/src/Vertex.h
  28. 31 0
      gameplay-newproject.bat
  29. 245 0
      gameplay-newproject.sh
  30. 32 0
      gameplay-template/TEMPLATE_PROJECT-ios.plist
  31. 0 0
      gameplay-template/TEMPLATE_PROJECT-macos.plist
  32. 1 0
      gameplay-template/android/jni/Application.mk
  33. 62 0
      gameplay-template/android/jni/template.Android.mk
  34. 4 0
      gameplay-template/android/res/values/template.strings.xml
  35. 32 0
      gameplay-template/android/template.AndroidManifest.xml
  36. 92 0
      gameplay-template/android/template.build.xml
  37. 210 35
      gameplay-template/gameplay-template.xcodeproj/project.pbxproj
  38. 2 2
      gameplay-template/res/box.material
  39. 5 5
      gameplay-template/src/TemplateGame.cpp
  40. 1 1
      gameplay-template/src/TemplateGame.h
  41. 2 2
      gameplay.doxyfile
  42. 8 0
      gameplay.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
  43. 1 3
      gameplay/.cproject
  44. 0 12
      gameplay/.project
  45. 14 0
      gameplay/android/AndroidManifest.xml
  46. 85 0
      gameplay/android/build.xml
  47. 25 0
      gameplay/android/jni/Android.mk
  48. 2 0
      gameplay/android/jni/Application.mk
  49. 5 0
      gameplay/gameplay.vcxproj
  50. 15 0
      gameplay/gameplay.vcxproj.filters
  51. 578 45
      gameplay/gameplay.xcodeproj/project.pbxproj
  52. 57 0
      gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-MacOSX.xcscheme
  53. 57 0
      gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-iOS.xcscheme
  54. 4 2
      gameplay/src/Animation.cpp
  55. 225 227
      gameplay/src/AnimationClip.cpp
  56. 100 29
      gameplay/src/AnimationClip.h
  57. 31 21
      gameplay/src/AnimationController.cpp
  58. 4 2
      gameplay/src/AnimationController.h
  59. 1 2
      gameplay/src/AnimationTarget.cpp
  60. 4 3
      gameplay/src/AnimationTarget.h
  61. 7 9
      gameplay/src/AnimationValue.cpp
  62. 2 3
      gameplay/src/AnimationValue.h
  63. 108 7
      gameplay/src/AudioBuffer.cpp
  64. 14 1
      gameplay/src/AudioBuffer.h
  65. 141 1
      gameplay/src/AudioController.cpp
  66. 9 0
      gameplay/src/AudioController.h
  67. 238 3
      gameplay/src/AudioSource.cpp
  68. 21 0
      gameplay/src/AudioSource.h
  69. 74 17
      gameplay/src/Base.h
  70. 3 3
      gameplay/src/BoundingBox.cpp
  71. 1 1
      gameplay/src/BoundingBox.h
  72. 1 1
      gameplay/src/BoundingBox.inl
  73. 1 1
      gameplay/src/BoundingSphere.h
  74. 1 1
      gameplay/src/BoundingSphere.inl
  75. 14 12
      gameplay/src/Curve.cpp
  76. 11 6
      gameplay/src/Curve.h
  77. 1 1
      gameplay/src/Curve.inl
  78. 2 1
      gameplay/src/DebugNew.cpp
  79. 146 3
      gameplay/src/FileSystem.cpp
  80. 10 0
      gameplay/src/FileSystem.h
  81. 1 1
      gameplay/src/Font.cpp
  82. 15 2
      gameplay/src/Game.cpp
  83. 32 4
      gameplay/src/Game.h
  84. 5 0
      gameplay/src/Game.inl
  85. 158 156
      gameplay/src/Keyboard.h
  86. 98 18
      gameplay/src/MaterialParameter.cpp
  87. 5 1
      gameplay/src/MaterialParameter.h
  88. 1 3
      gameplay/src/Matrix.cpp
  89. 9 9
      gameplay/src/Matrix.h
  90. 6 6
      gameplay/src/Matrix.inl
  91. 40 0
      gameplay/src/Mouse.h
  92. 60 46
      gameplay/src/Package.cpp
  93. 23 0
      gameplay/src/Package.h
  94. 1 1
      gameplay/src/PhysicsConstraint.cpp
  95. 289 139
      gameplay/src/PhysicsController.cpp
  96. 57 14
      gameplay/src/PhysicsController.h
  97. 3 3
      gameplay/src/PhysicsGenericConstraint.cpp
  98. 8 8
      gameplay/src/PhysicsGenericConstraint.inl
  99. 3 3
      gameplay/src/PhysicsHingeConstraint.cpp
  100. 4 5
      gameplay/src/PhysicsMotionState.cpp

+ 60 - 1
.gitignore

@@ -1,6 +1,10 @@
 *.suo
 *.sdf
-*.opensdf
+*.opensdf
+.DS_Store*
+ehthumbs.db
+Icon?
+Thumbs.db
 /.metadata
 /169.254.0.1
 /ipch
@@ -77,3 +81,58 @@
 /gameplay-samples/sample03-character/Device-Release
 /gameplay-samples/sample03-character/res/shaders
 /gameplay-samples/sample03-character/sample03-character.xcodeproj/xcuserdata
+
+/gameplay-android/obj
+/gameplay-android/NUL
+/gameplay-samples/sample00-mesh/android/src
+/gameplay-samples/sample00-mesh/android/assets
+/gameplay-samples/sample00-mesh/android/bin
+/gameplay-samples/sample00-mesh/android/gen
+/gameplay-samples/sample00-mesh/android/libs
+/gameplay-samples/sample00-mesh/android/obj
+/gameplay-android/local.properties
+/gameplay-android/proguard.cfg
+/gameplay-android/project.properties
+/gameplay-samples/sample00-mesh/android/NUL
+/gameplay-samples/sample00-mesh/android/local.properties
+/gameplay-samples/sample00-mesh/android/proguard.cfg
+/gameplay-samples/sample00-mesh/android/project.properties
+/gameplay-samples/sample01-longboard/android/NUL
+/gameplay-samples/sample01-longboard/android/src
+/gameplay-samples/sample01-longboard/android/assets
+/gameplay-samples/sample01-longboard/android/bin
+/gameplay-samples/sample01-longboard/android/gen
+/gameplay-samples/sample01-longboard/android/libs
+/gameplay-samples/sample01-longboard/android/obj
+/gameplay-samples/sample01-longboard/android/project.properties
+/gameplay-samples/sample01-longboard/android/local.properties
+/gameplay-samples/sample02-spaceship/android/project.properties
+/gameplay-samples/sample02-spaceship/android/assets
+/gameplay-samples/sample02-spaceship/android/bin
+/gameplay-samples/sample02-spaceship/android/gen
+/gameplay-samples/sample02-spaceship/android/libs
+/gameplay-samples/sample02-spaceship/android/obj
+/gameplay-samples/sample02-spaceship/android/src
+/gameplay-samples/sample02-spaceship/android/proguard.cfg
+/gameplay-samples/sample02-spaceship/android/local.properties
+/gameplay-samples/sample03-character/android/project.properties
+/gameplay-samples/sample03-character/android/proguard.cfg
+/gameplay-samples/sample03-character/android/local.properties
+/gameplay-samples/sample01-longboard/android/proguard.cfg
+/gameplay-samples/sample02-spaceship/android/NUL
+/gameplay-samples/sample01-longboard/android/proguard.cfg
+/gameplay-samples/sample03-character/android/src
+/gameplay-samples/sample03-character/android/assets
+/gameplay-samples/sample03-character/android/bin
+/gameplay-samples/sample03-character/android/gen
+/gameplay-samples/sample03-character/android/libs
+/gameplay-samples/sample03-character/android/obj
+/gameplay-samples/sample03-character/android/NUL
+/gameplay-samples/sample01-longboard/NUL
+
+/gameplay/android/NUL
+/gameplay/android/proguard.cfg
+/gameplay/android/local.properties
+/gameplay/android/project.properties
+/gameplay/android/obj
+

+ 16 - 12
README.md

@@ -1,18 +1,23 @@
-## GamePlay v1.1.0
+## GamePlay v1.2.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
-- 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)
+## Supported Mobile Platforms
+- BlackBerry PlayBook 1/2 (using BlackBerry Native SDK 2)
+- Google Android 4 (using Google Android NDK 7)
+- Apple iOS 4/5 (using Apple XCode 4)
+
+## Supported Desktop Platforms
+- Apple MacOS X (using Apple XCode 4)
+- Microsoft Windows XP/7 (using Microsoft Visual Studio 2010)
+    * Requires [Creative OpenAL 1.1] (http://connect.creativelabs.com/openal/Downloads/Forms/AllItems.aspx)
 
 ## Roadmap for 'next' branch
-- UI Forms with Themed Overlays.
-- Improvements to Lighting.
-- Developer Guide.
-- More Samples and Tutorials.
-- Apple iOS 5 Support.
+- UI Overlays
+- Improvements to Lighting
+- More Samples and Tutorials
+
+## Licence
+The project is open sourced under the Apache 2.0 license.
 
 ## Bug Reporting and Feature Requests
 If you find a bug in a Sample, or have an enhancement request, simply file an 
@@ -27,4 +32,3 @@ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIG
 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.
-

+ 1 - 1
gameplay-encoder/README.md

@@ -27,7 +27,7 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
 - 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)"
+  * 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

+ 5 - 4
gameplay-encoder/gameplay-encoder.vcxproj

@@ -98,6 +98,7 @@
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="src\Quaternion.inl" />
     <None Include="src\Vector2.inl" />
     <None Include="src\Vector3.inl" />
     <None Include="src\Vector4.inl" />
@@ -145,16 +146,16 @@
       </PrecompiledHeader>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <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>
+      <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;../external-deps/libpng/include;../external-deps/zlib/include</AdditionalIncludeDirectories>
       <DisableLanguageExtensions>
       </DisableLanguageExtensions>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <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>
+      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32</AdditionalLibraryDirectories>
+      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
     </Link>
     <PostBuildEvent>

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

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

+ 84 - 0
gameplay-encoder/gameplay-encoder.xcodeproj/xcshareddata/xcschemes/gameplay-encoder.xcscheme

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "42475CE5147208A000610A6A"
+               BuildableName = "gameplay-encoder"
+               BlueprintName = "gameplay-encoder"
+               ReferencedContainer = "container:gameplay-encoder.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "42475CE5147208A000610A6A"
+            BuildableName = "gameplay-encoder"
+            BlueprintName = "gameplay-encoder"
+            ReferencedContainer = "container:gameplay-encoder.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "42475CE5147208A000610A6A"
+            BuildableName = "gameplay-encoder"
+            BlueprintName = "gameplay-encoder"
+            ReferencedContainer = "container:gameplay-encoder.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "42475CE5147208A000610A6A"
+            BuildableName = "gameplay-encoder"
+            BlueprintName = "gameplay-encoder"
+            ReferencedContainer = "container:gameplay-encoder.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 10 - 0
gameplay-encoder/src/Animation.cpp

@@ -51,6 +51,15 @@ void Animation::add(AnimationChannel* animationChannel)
     _channels.push_back(animationChannel);
 }
 
+void Animation::remove(AnimationChannel* animationChannel)
+{
+    std::vector<AnimationChannel*>::iterator it = std::find(_channels.begin(), _channels.end(), animationChannel);
+    if (it != _channels.end())
+    {
+        _channels.erase(it);
+    }
+}
+
 unsigned int Animation::getAnimationChannelCount() const
 {
     return _channels.size();
@@ -58,6 +67,7 @@ unsigned int Animation::getAnimationChannelCount() const
 
 AnimationChannel* Animation::getAnimationChannel(unsigned int index) const
 {
+    assert(index < _channels.size());
     return _channels[index];
 }
 

+ 17 - 1
gameplay-encoder/src/Animation.h

@@ -26,8 +26,20 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
 
+    /**
+     * Adds the given animation channel to this animation.
+     * 
+     * @param animationChannel The animation channel to add.
+     */
     void add(AnimationChannel* animationChannel);
 
+    /**
+     * Removes the given animation channel from this animation.
+     * 
+     * @param animationChannel The animation channel to remove.
+     */
+    void remove(AnimationChannel* animationChannel);
+
     /**
      * Returns the number of animation channels contained in this animation.
      * 
@@ -36,7 +48,11 @@ public:
     unsigned int getAnimationChannelCount() const;
 
     /**
-     * Returns the specified animation channel.
+     * Returns the animation channel at the given index.
+     * 
+     * @param index The index of the animation channel to get.
+     * 
+     * @return The pointer to the animation channel or NULL if not found.
      */
     AnimationChannel* getAnimationChannel(unsigned int index) const;
 

+ 19 - 14
gameplay-encoder/src/AnimationChannel.cpp

@@ -43,7 +43,7 @@ void AnimationChannel::writeText(FILE* file)
 {
     fprintElementStart(file);
     fprintfElement(file, "targetId", _targetId);
-    fprintfElement(file, "targetAttrib", _targetAttrib);
+    fprintf(file, "<%s>%u %s</%s>\n", "targetAttrib", _targetAttrib, Transform::getPropertyString(_targetAttrib), "targetAttrib");
     fprintfElement(file, "%f ", "keytimes", _keytimes);
     fprintfElement(file, "%f ", "values", _keyValues);
     fprintfElement(file, "%f ", "tangentsIn", _tangentsIn);
@@ -130,27 +130,29 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values
 
 void AnimationChannel::removeDuplicates()
 {
-    if (_targetAttrib == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+    size_t propSize = Transform::getPropertySize(_targetAttrib);
+
+    if (propSize > 1 && !_interpolations.empty() && _interpolations[0] == LINEAR)
     {
         size_t prevIndex = 0;
 
         std::vector<float>::iterator prevStart = _keyValues.begin();
-        std::vector<float>::iterator prevEnd   = _keyValues.begin() + 9;
+        std::vector<float>::iterator prevEnd = prevStart + propSize - 1;
         
         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);
+            std::vector<float>::iterator start = _keyValues.begin() + i * propSize;
+            std::vector<float>::iterator end = start + propSize - 1;
 
-            if (!equal(prevStart, prevEnd, start))
+            if (!equal(prevStart, prevEnd, start) || i == _keytimes.size() - 1)
             {
                 if (i - prevIndex > 2)
                 {
-                    deleteRange(prevIndex+1, i);
+                    deleteRange(prevIndex+1, i, propSize);
                     i = prevIndex;
-                    prevStart = _keyValues.begin() + i * 10;
-                    prevEnd = _keyValues.begin() + (i * 10 + 9);
+                    prevStart = _keyValues.begin() + i * propSize;
+                    prevEnd = prevStart + propSize - 1;
                 }
                 else
                 {
@@ -162,7 +164,7 @@ void AnimationChannel::removeDuplicates()
         }
         if (i - 1 - prevIndex >= 2)
         {
-            deleteRange(prevIndex+1, i);
+            deleteRange(prevIndex+1, i, propSize);
         }
     }
 }
@@ -270,13 +272,14 @@ unsigned int AnimationChannel::getInterpolationType(const char* str)
     return value;
 }
 
-void AnimationChannel::deleteRange(size_t begin, size_t end)
+void AnimationChannel::deleteRange(size_t begin, size_t end, size_t propSize)
 {
+    assert(end > begin);
     // 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;
+    std::vector<float>::iterator a = _keyValues.begin() + begin * propSize;
+    std::vector<float>::iterator b = _keyValues.begin() + end * propSize;
     _keyValues.erase(a, b);
 
     a = _keytimes.begin() + begin;
@@ -286,9 +289,11 @@ void AnimationChannel::deleteRange(size_t begin, size_t end)
     if (_interpolations.size() > 1)
     {
         std::vector<unsigned int>::iterator a = _interpolations.begin() + begin;
-        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * 10;
+        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * propSize;
         _interpolations.erase(a, b);
     }
+
+    // TODO: also remove key frames from _tangentsIn and _tangentsOut once other curve types are supported.
 }
 
 }

+ 12 - 1
gameplay-encoder/src/AnimationChannel.h

@@ -60,6 +60,9 @@ public:
     const std::vector<float>& getTangentsOut() const;
     const std::vector<unsigned int>& getInterpolationTypes() const;
 
+    /**
+     * Removes duplicate key frames from the animation channel.
+     */
     void removeDuplicates();
 
     void convertToQuaternion();
@@ -77,7 +80,15 @@ public:
 
 private:
 
-    void deleteRange(size_t begin, size_t end);
+    /**
+     * Deletes all key frames from key time index begin to key time index end (exclusive).
+     * 
+     * @param begin The start index to delete.
+     * @param end The index to delete up to but not including.
+     * @param propSize The size of the animation propery to delete. Example: Translate(x,y,z) is size 3.
+     */
+    void deleteRange(size_t begin, size_t end, size_t propSize);
+
 private:
 
     std::string _targetId;

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

@@ -78,6 +78,14 @@ void fillArray(float values[], float value, size_t length);
 
 #define ISZERO(x) (fabs(x) < 0.000001f)
 
+// Object deletion macro
+#define SAFE_DELETE(x) \
+    if (x) \
+    { \
+        delete x; \
+        x = NULL; \
+    }
+
 #ifdef NDEBUG
 #define DEBUGPRINT(x)
 #define DEBUGPRINT_VARG(x, ...)

+ 86 - 44
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -272,23 +272,31 @@ void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments&
         {
             if (nodeId == NULL)
             {
-                // If the -n <node_id> parameter was not passed then write out the entire scene.
+                // If the -i <node_id> parameter was not passed then write out the entire scene.
                 begin();
                 loadScene((domVisual_scene*)scene);
                 end("load scene");
             }
             else
             {
-                // Resolve/Search for the node the user specified with the -n <node_id> parameter.
+                // Resolve/Search for the node the user specified with the -i <node_id> parameter.
                 daeSIDResolver resolver(scene, nodeId);
-                const domNode* node = daeSafeCast<domNode>(resolver.getElement());
-                if (node)
+                domNode* nodeElement = daeSafeCast<domNode>(resolver.getElement());
+                if (nodeElement)
                 {
-                    //createNode(node, NULL);
+                    Node* node = loadNode(nodeElement, NULL);
+                    if (node)
+                    {
+                        _gamePlayFile.addScenelessNode(node);
+                    }
+                    else
+                    {
+                        fprintf(stderr,"COLLADA File loaded to the dom, but failed to load node %s.\n", nodeId);
+                    }
                 }
                 else
                 {
-                    fprintf(stderr,"COLLADA File loaded to the dom, but node was not found with -n%s.\n", nodeId);
+                    fprintf(stderr,"COLLADA File loaded to the dom, but node was not found with node ID %s.\n", nodeId);
                 }
             }
         }
@@ -619,6 +627,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                     Quaternion rotation;
                     Vector3 translation;
                     matrix.decompose(&scale, &rotation, &translation);
+                    rotation.normalize();
 
                     size_t k = i * 10;
                     floats[k+0] = scale.x;
@@ -1232,9 +1241,9 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
     for (std::vector<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
     {
         Object* obj = _gamePlayFile.getFromRefTable(*i);
-        if (obj)
+        if (obj && obj->getTypeId() == Object::NODE_ID)
         {
-            Node* node = (Node*)obj;
+            Node* node = static_cast<Node*>(obj);
             _joints.push_back(node);
         }
     }
@@ -1665,10 +1674,9 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             {
                 maxOffset = offset;
             }
-            int type = polygonInputs[k]->type;
-
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
-            switch (type)
+
+            switch (polygonInputs[k]->type)
             {
             case POSITION:
                 vertex = Vertex(); // TODO
@@ -1699,16 +1707,52 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 vertex.normal.z = (float)source.get(polyIndex * 3 + 2);
                 break;
 
-            // TODO: Handle reading of per-vertex colors.
-            // HOW do we know how many color components to read?
-            // We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
-//            case Color:
-//                vertex.hasColor = true;
-//                vertex.Diffuse.R = (float)source.get(polyIndex * 3);
-//                vertex.Diffuse.G = (float)source.get(polyIndex * 3 + 1);
-//                vertex.Diffuse.B = (float)source.get(polyIndex * 3 + 2);
-//                vertex.Diffuse.A = (float)source.get(polyIndex * 3 + 3);
-//                break;
+            // TODO: We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
+            case COLOR:
+            {
+                domAccessor* accessor = polygonInputs[k]->accessor;
+                if (accessor)
+                {
+                    vertex.hasDiffuse = true;
+                    vertex.diffuse.w = 1.0f;
+                    unsigned int stride = (unsigned int)polygonInputs[k]->accessor->getStride();
+                    unsigned int index = polyIndex * stride;
+
+                    const domParam_Array& paramArray = accessor->getParam_array();
+                    const size_t paramArrayCount = paramArray.getCount();
+
+                    for (size_t i = 0; i < paramArrayCount; ++i)
+                    {
+                        const domParamRef& param = paramArray.get(i);
+                        const char* name = param->getName();
+                        if (name)
+                        {
+                            switch (name[0])
+                            {
+                            case 'r':
+                            case 'R':
+                                vertex.diffuse.x = (float)source.get(index + i); // red
+                                break;
+                            case 'g':
+                            case 'G':
+                                vertex.diffuse.y = (float)source.get(index + i); // green
+                                break;
+                            case 'b':
+                            case 'B':
+                                vertex.diffuse.z = (float)source.get(index + i); // blue
+                                break;
+                            case 'a':
+                            case 'A':
+                                vertex.diffuse.w = (float)source.get(index + i); // alpha
+                                break;
+                            default:
+                                break;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
 
             case TANGENT:
                 vertex.hasTangent = true;
@@ -1778,7 +1822,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     }
     
     bool hasNormals = mesh->vertices[0].hasNormal;
-    bool hasColors = mesh->vertices[0].hasColor;
+    bool hasDiffuses = mesh->vertices[0].hasDiffuse;
     bool hasTangents = mesh->vertices[0].hasTangent;
     bool hasBinormals = mesh->vertices[0].hasBinormal;
     bool hasTexCoords = mesh->vertices[0].hasTexCoord;
@@ -1788,38 +1832,38 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     // It should be the same order as how the Vertex data is written.
 
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
     
     // Normals
     if (hasNormals)
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     // Tangents
     if (hasTangents)
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     // Binormals
     if (hasBinormals)
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     // Texture Coordinates
     if (hasTexCoords)
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     // Diffuse Color
-    if (hasColors)
+    if (hasDiffuses)
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     // Skinning BlendWeights BlendIndices
-    if (hasWeights /*_vertexBlendWeights && _vertexBlendIndices*/)
+    if (hasWeights)
     {
-        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
-        mesh->addVetexAttribute(BLENDINDICES, 4);
+        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
+        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
     }
 
     _gamePlayFile.addMesh(mesh);
@@ -1838,7 +1882,6 @@ void DAESceneEncoder::warning(const char* message)
 
 int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
 {
-    int type = -1;
     if (semantic.length() > 0)
     {
         switch (semantic[0])
@@ -1846,48 +1889,47 @@ int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
         case 'P':
             if (equals(semantic, "POSITION"))
             {
-                type = POSITION;
+                return POSITION;
             }
-            break;
         case 'N':
             if (equals(semantic, "NORMAL"))
             {
-                type = NORMAL;
+                return NORMAL;
             }
         case 'C':
             if (equals(semantic, "COLOR"))
             {
-                type = COLOR;
+                return COLOR;
             }
         case 'T':
             if (equals(semantic, "TANGENT"))
             {
-                type = TANGENT;
+                return TANGENT;
             }
             else if (equals(semantic, "TEXCOORD"))
             {
-                type = TEXCOORD0;
+                return TEXCOORD0;
             }
             else if (equals(semantic, "TEXTANGENT"))
             {
                 // Treat TEXTANGENT as TANGENT
-                type = TANGENT;
+                return TANGENT;
             }
             else if (equals(semantic, "TEXBINORMAL"))
             {
                 // Treat TEXBINORMAL as BINORMAL
-                type = BINORMAL;
+                return BINORMAL;
             }
         case 'B':
             if (equals(semantic, "BINORMAL"))
             {
-                type = BINORMAL;
+                return BINORMAL;
             }
         default:
-            break;
+            return -1;
         }
     }
-    return type;
+    return -1;
 }
 
 DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :

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

@@ -141,7 +141,7 @@ void EncoderArguments::printUsage() const
     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,"  -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");

+ 103 - 53
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -15,7 +15,7 @@ using namespace gameplay;
  * 
  * @return The aspect ratio from the camera.
  */
-float getAspectRatio(KFbxCamera* fbxCamera);
+static float getAspectRatio(KFbxCamera* fbxCamera);
 
 /**
  * Returns the field of view Y from the given camera.
@@ -24,7 +24,7 @@ float getAspectRatio(KFbxCamera* fbxCamera);
  * 
  * @return The field of view Y.
  */
-float getFieldOfView(KFbxCamera* fbxCamera);
+static float getFieldOfView(KFbxCamera* fbxCamera);
 
 /**
  * Loads the texture coordinates from given mesh's polygon part into the vertex.
@@ -34,7 +34,7 @@ float getFieldOfView(KFbxCamera* fbxCamera);
  * @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);
+static void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex);
 
 /**
  * Loads the normal from the mesh and adds it to the given vertex.
@@ -43,7 +43,7 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
  * @param vertexIndex The vertex index in the mesh.
  * @param vertex The vertex to copy to.
  */
-void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 /**
  * Loads the tangent from the mesh and adds it to the given vertex.
@@ -52,7 +52,7 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertex The vertex to copy to.
  */
-void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 /**
  * Loads the binormal from the mesh and adds it to the given vertex.
@@ -61,7 +61,16 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertex The vertex to copy to.
  */
-void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the vertex diffuse color 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.
+ */
+static void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 /**
  * Loads the blend weight and blend indices data into the vertex.
@@ -69,7 +78,7 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* 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);
+static void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
 
 /**
  * Loads the blend weights and blend indices from the given mesh.
@@ -81,17 +90,17 @@ void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
  * 
  * @return True if this mesh has a mesh skin, false otherwise.
  */
-bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
+static 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);
+static void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix);
 
 /**
  * Copies from an FBX matrix to a gameplay matrix.
  */
-void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
+static void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
 
 /**
  * Finds the min and max start time and stop time of the given animation curve.
@@ -105,7 +114,7 @@ void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
  * @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);
+static void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
 
 /**
  * Appends a key frame of the given node's transform at the given time.
@@ -115,7 +124,7 @@ void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime,
  * @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);
+static 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.
@@ -126,7 +135,7 @@ void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes,
  * @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);
+static 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.
@@ -138,7 +147,7 @@ void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotati
  * 
  * @return The newly created animation channel.
  */
-AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
+static 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);
 
@@ -778,7 +787,7 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
             loadNormal(fbxMesh, vertexIndex, &vertex);
             loadTangent(fbxMesh, vertexIndex, &vertex);
             loadBinormal(fbxMesh, vertexIndex, &vertex);
-            // TODO: loadDiffuseColors
+            loadVertexColor(fbxMesh, vertexIndex, &vertex);
 
             if (hasSkin)
             {
@@ -819,39 +828,39 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
     // It should be the same order as how the Vertex data is written.
 
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
 
     const Vertex& vertex = mesh->vertices[0];
     // Normals
     if (vertex.hasNormal)
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     // Tangents
     if (vertex.hasTangent)
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     // Binormals
     if (vertex.hasBinormal)
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     // Texture Coordinates
     if (vertex.hasTexCoord)
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     // Diffuse Color
-    if (vertex.hasColor)
+    if (vertex.hasDiffuse)
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     // Skinning BlendWeights BlendIndices
     if (vertex.hasWeights)
     {
-        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
-        mesh->addVetexAttribute(BLENDINDICES, 4);
+        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
+        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
     }
 
     _gamePlayFile.addMesh(mesh);
@@ -974,23 +983,23 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
     if (fbxMesh->GetElementUVCount() > 0)
     {
         // Get only the first UV coordinates.
-        KFbxGeometryElementUV* leUV = fbxMesh->GetElementUV(0);
-        switch (leUV->GetMappingMode())
+        KFbxGeometryElementUV* uv = fbxMesh->GetElementUV(0);
+        switch (uv->GetMappingMode())
         {
         case KFbxGeometryElement::eBY_CONTROL_POINT:
-            switch (leUV->GetReferenceMode())
+            switch (uv->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];
+                vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(polyIndex)[0];
+                vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(polyIndex)[1];
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leUV->GetIndexArray().GetAt(polyIndex);
+                    int id = uv->GetIndexArray().GetAt(polyIndex);
                     vertex->hasTexCoord = true;
-                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(id)[0];
-                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(id)[1];
+                    vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(id)[0];
+                    vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(id)[1];
                 }
                 break;
             default:
@@ -1000,13 +1009,13 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
         case KFbxGeometryElement::eBY_POLYGON_VERTEX:
             {
                 int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
-                switch (leUV->GetReferenceMode())
+                switch (uv->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];
+                    vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(lTextureUVIndex)[0];
+                    vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(lTextureUVIndex)[1];
                     break;
                 default:
                     break;
@@ -1024,14 +1033,14 @@ 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)
+        KFbxGeometryElementNormal* normal = fbxMesh->GetElementNormal(0);
+        if (normal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
-            switch (leNormal->GetReferenceMode())
+            switch (normal->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 {
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
@@ -1040,8 +1049,8 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leNormal->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(id);
+                    int id = normal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
@@ -1060,14 +1069,14 @@ 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)
+        KFbxGeometryElementTangent* tangent = fbxMesh->GetElementTangent(0);
+        if (tangent->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
-            switch (leTangent->GetReferenceMode())
+            switch (tangent->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 {
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
@@ -1076,8 +1085,8 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leTangent->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(id);
+                    int id = tangent->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(id);
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
@@ -1096,14 +1105,14 @@ 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)
+        KFbxGeometryElementBinormal* binormal = fbxMesh->GetElementBinormal(0);
+        if (binormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
-            switch (leBinormal->GetReferenceMode())
+            switch (binormal->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 {
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
@@ -1112,8 +1121,8 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leBinormal->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(id);
+                    int id = binormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(id);
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
@@ -1127,6 +1136,46 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     }
 }
 
+void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementVertexColorCount() > 0)
+    {
+        // Get only the first vertex color.
+        KFbxGeometryElementVertexColor* vertexColor = fbxMesh->GetElementVertexColor(0);
+        if (vertexColor->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (vertexColor->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxColor color = vertexColor->GetDirectArray().GetAt(vertexIndex);
+
+                    vertex->hasDiffuse = true;
+                    vertex->diffuse.x = (float)color.mRed;
+                    vertex->diffuse.y = (float)color.mGreen;
+                    vertex->diffuse.z = (float)color.mBlue;
+                    vertex->diffuse.w = (float)color.mAlpha;
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = vertexColor->GetIndexArray().GetAt(vertexIndex);
+                    KFbxColor color = vertexColor->GetDirectArray().GetAt(id);
+
+                    vertex->hasDiffuse = true;
+                    vertex->diffuse.x = (float)color.mRed;
+                    vertex->diffuse.y = (float)color.mGreen;
+                    vertex->diffuse.z = (float)color.mBlue;
+                    vertex->diffuse.w = (float)color.mAlpha;
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
 void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
 {
     size_t size = vertexWeights.size();
@@ -1225,6 +1274,7 @@ void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes,
     Quaternion rotation;
     Vector3 translation;
     matrix.decompose(&scale, &rotation, &translation);
+    rotation.normalize();
 
     keyTimes->push_back(time);
     keyValues->push_back(scale.x);

+ 154 - 0
gameplay-encoder/src/GPBFile.cpp

@@ -1,11 +1,19 @@
 #include "Base.h"
 #include "GPBFile.h"
+#include "Transform.h"
+
+#define EPSILON 1.2e-7f;
 
 namespace gameplay
 {
 
 static GPBFile* __instance = NULL;
 
+/**
+ * Returns true if the given value is close to one.
+ */
+static bool isAlmostOne(float value);
+
 GPBFile::GPBFile(void)
     : _file(NULL), _animationsAdded(false)
 {
@@ -115,6 +123,16 @@ void GPBFile::addNode(Node* node)
     _nodes.push_back(node);
 }
 
+void GPBFile::addScenelessNode(Node* node)
+{
+    addToRefTable(node);
+    _nodes.push_back(node);
+    // Nodes are normally written to file as part of a scene. 
+    // Nodes that don't belong to a scene need to be written on their own (outside a scene).
+    // That is why node is added to the list of objects here.
+    _objects.push_back(node);
+}
+
 void GPBFile::addAnimation(Animation* animation)
 {
     _animations.add(animation);
@@ -235,6 +253,14 @@ void GPBFile::adjust()
         }
     }
 
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
+    {
+        computeBounds(*i);
+    }
+
+    // try to convert joint transform animations into rotation animations
+    //optimizeTransformAnimations();
+
     // TODO:
     // remove ambient _lights
     // for each node
@@ -249,4 +275,132 @@ void GPBFile::adjust()
     //   This can be merged into one animation. Same for scale animations.
 }
 
+void GPBFile::computeBounds(Node* node)
+{
+    assert(node);
+    if (Model* model = node->getModel())
+    {
+        if (Mesh* mesh = model->getMesh())
+        {
+            mesh->computeBounds();
+        }
+        if (MeshSkin* skin = model->getSkin())
+        {
+            skin->computeBounds();
+        }
+    }
+    for (Node* child = node->getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        computeBounds(child);
+    }
+}
+
+void GPBFile::optimizeTransformAnimations()
+{
+    const unsigned int animationCount = _animations.getAnimationCount();
+    for (unsigned int animationIndex = 0; animationIndex < animationCount; ++animationIndex)
+    {
+        Animation* animation = _animations.getAnimation(animationIndex);
+        assert(animation);
+        const int channelCount = animation->getAnimationChannelCount();
+        // loop backwards because we will be adding and removing channels
+        for (int channelIndex = channelCount -1; channelIndex >= 0 ; --channelIndex)
+        {
+            AnimationChannel* channel = animation->getAnimationChannel(channelIndex);
+            assert(channel);
+            // get target node
+            const Object* obj = _refTable.get(channel->getTargetId());
+            if (obj && obj->getTypeId() == Object::NODE_ID)
+            {
+                const Node* node = static_cast<const Node*>(obj);
+                if (node->isJoint() && channel->getTargetAttribute() == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+                {
+                    decomposeTransformAnimationChannel(animation, channel);
+
+                    animation->remove(channel);
+                    SAFE_DELETE(channel);
+                }
+            }
+        }
+    }
+}
+
+
+void GPBFile::decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel)
+{
+    const std::vector<float>& keyTimes = channel->getKeyTimes();
+    const std::vector<float>& keyValues = channel->getKeyValues();
+    const size_t keyTimesSize = keyTimes.size();
+    const size_t keyValuesSize = keyValues.size();
+
+    std::vector<float> scaleKeyValues;
+    std::vector<float> rotateKeyValues;
+    std::vector<float> translateKeyValues;
+                    
+    scaleKeyValues.reserve(keyTimesSize * 3);
+    rotateKeyValues.reserve(keyTimesSize * 4);
+    translateKeyValues.reserve(keyTimesSize * 3);
+
+    for (size_t kv = 0; kv < keyValuesSize; kv += 10)
+    {
+        scaleKeyValues.push_back(keyValues[kv]);
+        scaleKeyValues.push_back(keyValues[kv+1]);
+        scaleKeyValues.push_back(keyValues[kv+2]);
+
+        rotateKeyValues.push_back(keyValues[kv+3]);
+        rotateKeyValues.push_back(keyValues[kv+4]);
+        rotateKeyValues.push_back(keyValues[kv+5]);
+        rotateKeyValues.push_back(keyValues[kv+6]);
+
+        translateKeyValues.push_back(keyValues[kv+7]);
+        translateKeyValues.push_back(keyValues[kv+8]);
+        translateKeyValues.push_back(keyValues[kv+9]);
+    }
+
+    // replace transform animation channel with translate, rotate and scale animation channels
+
+    // Don't add the scale channel if all the key values are close to 1.0
+    size_t oneCount = (size_t)std::count_if(scaleKeyValues.begin(), scaleKeyValues.end(), isAlmostOne);
+    if (scaleKeyValues.size() != oneCount)
+    {
+        AnimationChannel* scaleChannel = new AnimationChannel();
+        scaleChannel->setTargetId(channel->getTargetId());
+        scaleChannel->setKeyTimes(channel->getKeyTimes());
+        scaleChannel->setTangentsIn(channel->getTangentsIn());
+        scaleChannel->setTangentsOut(channel->getTangentsOut());
+        scaleChannel->setInterpolations(channel->getInterpolationTypes());
+        scaleChannel->setTargetAttribute(Transform::ANIMATE_SCALE);
+        scaleChannel->setKeyValues(scaleKeyValues);
+        scaleChannel->removeDuplicates();
+        animation->add(scaleChannel);
+    }
+
+    AnimationChannel* rotateChannel = new AnimationChannel();
+    rotateChannel->setTargetId(channel->getTargetId());
+    rotateChannel->setKeyTimes(channel->getKeyTimes());
+    rotateChannel->setTangentsIn(channel->getTangentsIn());
+    rotateChannel->setTangentsOut(channel->getTangentsOut());
+    rotateChannel->setInterpolations(channel->getInterpolationTypes());
+    rotateChannel->setTargetAttribute(Transform::ANIMATE_ROTATE);
+    rotateChannel->setKeyValues(rotateKeyValues);
+    rotateChannel->removeDuplicates();
+    animation->add(rotateChannel);
+
+    AnimationChannel* translateChannel = new AnimationChannel();
+    translateChannel->setTargetId(channel->getTargetId());
+    translateChannel->setKeyTimes(channel->getKeyTimes());
+    translateChannel->setTangentsIn(channel->getTangentsIn());
+    translateChannel->setTangentsOut(channel->getTangentsOut());
+    translateChannel->setInterpolations(channel->getInterpolationTypes());
+    translateChannel->setTargetAttribute(Transform::ANIMATE_TRANSLATE);
+    translateChannel->setKeyValues(translateKeyValues);
+    translateChannel->removeDuplicates();
+    animation->add(translateChannel);
+}
+
+static bool isAlmostOne(float value)
+{
+    return std::abs(value - 1.0f) < EPSILON;
+}
+
 }

+ 19 - 0
gameplay-encoder/src/GPBFile.h

@@ -65,6 +65,10 @@ public:
     void addLight(Light* light);
     void addMesh(Mesh* mesh);
     void addNode(Node* node);
+    /**
+     * Adds a node that does not belong to a scene.
+     */
+    void addScenelessNode(Node* node);
     void addAnimation(Animation* animation);
 
     /**
@@ -94,6 +98,21 @@ public:
      */
     void adjust();
 
+private:
+    /**
+     * Computes the bounds of all meshes in the node hierarchy.
+     */
+    void computeBounds(Node* node);
+    void optimizeTransformAnimations();
+
+    /**
+     * Decomposes an ANIMATE_SCALE_ROTATE_TRANSLATE channel into 3 new channels. (Scale, Rotate and Translate)
+     * 
+     * @param animation The animation that the channel belongs to.
+     * @param channel The animation channel to decompose.
+     */
+    void decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel);
+
 private:
 
     FILE* _file;

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

@@ -273,7 +273,6 @@ void Mesh::writeBinaryVertices(FILE* file)
     }
 
     // Write bounds
-    computeBounds();
     write(&bounds.min.x, 3, file);
     write(&bounds.max.x, 3, file);
     write(&bounds.center.x, 3, file);
@@ -302,7 +301,6 @@ void Mesh::writeText(FILE* file)
     fprintf(file, "</vertices>\n");
 
     // write bounds
-    computeBounds();
     fprintf(file, "<bounds>\n");
     fprintf(file, "<min>\n");
     writeVectorText(bounds.min, file);

+ 2 - 4
gameplay-encoder/src/Mesh.h

@@ -65,16 +65,14 @@ public:
      */
     void generateHeightmap(const char* filename);
 
+    void computeBounds();
+
     Model* model;
     std::vector<Vertex> vertices;
     std::vector<MeshPart*> parts;
     BoundingVolume bounds;
     std::map<Vertex, unsigned int> vertexLookupTable;
 
-private:
-
-    void computeBounds();
-
 private:
     std::vector<VertexElement> _vertexFormat;
 

+ 2 - 2
gameplay-encoder/src/Node.cpp

@@ -296,7 +296,7 @@ void Node::setIsJoint(bool value)
     _joint = value;
 }
 
-bool Node::isJoint()
+bool Node::isJoint() const
 {
     return _joint;
 }
@@ -324,7 +324,7 @@ Node* Node::getFirstCameraNode() const
 {
     if (hasCamera())
     {
-        return (Node*)this;
+        return const_cast<Node*>(this);
     }
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
     {

+ 1 - 1
gameplay-encoder/src/Node.h

@@ -155,7 +155,7 @@ public:
     /**
      * Returns true if this is a joint node.
      */
-    bool isJoint();
+    bool isJoint() const;
 
     Node* getFirstCameraNode() const;
 

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

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

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

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

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

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

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

@@ -1,2 +1,91 @@
 #include "Base.h"
 #include "Transform.h"
+
+namespace gameplay
+{
+
+const char* Transform::getPropertyString(unsigned int prop)
+{
+    switch (prop)
+    {
+        case ANIMATE_SCALE:
+            return "ANIMATE_SCALE";
+        case ANIMATE_SCALE_X:
+            return "ANIMATE_SCALE_X";
+        case ANIMATE_SCALE_Y: 
+            return "ANIMATE_SCALE_Y";
+        case ANIMATE_SCALE_Z:
+            return "ANIMATE_SCALE_Z";
+        case ANIMATE_SCALE_XY: 
+            return "ANIMATE_SCALE_XY";
+        case ANIMATE_SCALE_XZ: 
+            return "ANIMATE_SCALE_XZ";
+        case ANIMATE_SCALE_YZ:
+            return "ANIMATE_SCALE_YZ";
+        case ANIMATE_ROTATE:
+            return "ANIMATE_ROTATE";
+        case ANIMATE_TRANSLATE: 
+            return "ANIMATE_TRANSLATE";
+        case ANIMATE_TRANSLATE_X:
+            return "ANIMATE_TRANSLATE_X";
+        case ANIMATE_TRANSLATE_Y: 
+            return "ANIMATE_TRANSLATE_Y";
+        case ANIMATE_TRANSLATE_Z: 
+            return "ANIMATE_TRANSLATE_Z";
+        case ANIMATE_TRANSLATE_XY: 
+            return "ANIMATE_TRANSLATE_XY";
+        case ANIMATE_TRANSLATE_XZ: 
+            return "ANIMATE_TRANSLATE_XZ";
+        case ANIMATE_TRANSLATE_YZ: 
+            return "ANIMATE_TRANSLATE_YZ";
+        case ANIMATE_ROTATE_TRANSLATE: 
+            return "ANIMATE_ROTATE_TRANSLATE";
+        case ANIMATE_SCALE_ROTATE_TRANSLATE: 
+            return "ANIMATE_SCALE_ROTATE_TRANSLATE";
+        case ANIMATE_ROTATE_X: 
+            return "ANIMATE_ROTATE_X";
+        case ANIMATE_ROTATE_Y: 
+            return "ANIMATE_ROTATE_Y";
+        case ANIMATE_ROTATE_Z: 
+            return "ANIMATE_ROTATE_Z";
+        default:
+            return "";
+    }
+}
+
+unsigned int Transform::getPropertySize(unsigned int prop)
+{
+    switch (prop)
+    {
+        case ANIMATE_SCALE_ROTATE_TRANSLATE: 
+            return 10;
+        case ANIMATE_ROTATE_TRANSLATE: 
+            return 7;
+        case ANIMATE_ROTATE:
+            return 4;
+        case ANIMATE_SCALE:
+        case ANIMATE_TRANSLATE: 
+            return 3;   
+        case ANIMATE_SCALE_XY: 
+        case ANIMATE_SCALE_XZ: 
+        case ANIMATE_SCALE_YZ:
+        case ANIMATE_TRANSLATE_XY: 
+        case ANIMATE_TRANSLATE_XZ: 
+        case ANIMATE_TRANSLATE_YZ: 
+            return 2;
+        case ANIMATE_SCALE_X:
+        case ANIMATE_SCALE_Y:
+        case ANIMATE_SCALE_Z:
+        case ANIMATE_TRANSLATE_X:
+        case ANIMATE_TRANSLATE_Y:
+        case ANIMATE_TRANSLATE_Z:
+        case ANIMATE_ROTATE_X: 
+        case ANIMATE_ROTATE_Y: 
+        case ANIMATE_ROTATE_Z: 
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+}

+ 11 - 0
gameplay-encoder/src/Transform.h

@@ -50,6 +50,17 @@ public:
         ANIMATE_ROTATE_Y = 19,
         ANIMATE_ROTATE_Z = 20
     };
+
+    /**
+     * Returns the string representation of the given TransformProperty.
+     */
+    static const char* getPropertyString(unsigned int prop);
+
+    /**
+     * Returns the number of floats for the given property or zero if not a valid property.
+     */
+    static unsigned int getPropertySize(unsigned int prop);
+
 };
 
 }

+ 18 - 12
gameplay-encoder/src/Vertex.cpp

@@ -5,7 +5,7 @@ namespace gameplay
 {
 
 Vertex::Vertex(void)
-    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasColor(false), hasWeights(false)
+    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasDiffuse(false), hasWeights(false)
 {
 }
 
@@ -15,17 +15,19 @@ Vertex::~Vertex(void)
 
 unsigned int Vertex::byteSize() const
 {
-    unsigned int count = 3;
+    unsigned int count = POSITION_COUNT;
     if (hasNormal)
-        count += 3;
+        count += NORMAL_COUNT;
     if (hasTangent)
-        count += 3;
+        count += TANGENT_COUNT;
     if (hasBinormal)
-        count += 3;
+        count += BINORMAL_COUNT;
     if (hasTexCoord)
-        count += 2;
+        count += TEXCOORD_COUNT;
     if (hasWeights)
-        count += 8;
+        count += BLEND_WEIGHTS_COUNT + BLEND_INDICES_COUNT;
+    if (hasDiffuse)
+        count += DIFFUSE_COUNT;
     return count * sizeof(float);
 }
 
@@ -48,11 +50,10 @@ void Vertex::writeBinary(FILE* file) const
     {
         writeVectorBinary(texCoord, file);
     }
-    // TODO add vertex color?
-    //if (hasColor)
-    //{
-    //    writeVectorBinary(color, file);
-    //}
+    if (hasDiffuse)
+    {
+        writeVectorBinary(diffuse, file);
+    }
     if (hasWeights)
     {
         writeVectorBinary(blendWeights, file);
@@ -84,6 +85,11 @@ void Vertex::writeText(FILE* file) const
         write("// texCoord\n", file);
         writeVectorText(texCoord, file);
     }
+    if (hasDiffuse)
+    {
+        write("// diffuse\n", file);
+        writeVectorText(diffuse, file);
+    }
     if (hasWeights)
     {
         write("// blendWeights\n", file);

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

@@ -13,6 +13,15 @@ class Vertex
 {
 public:
 
+    static const unsigned int POSITION_COUNT = 3;
+    static const unsigned int NORMAL_COUNT = 3;
+    static const unsigned int TANGENT_COUNT = 3;
+    static const unsigned int BINORMAL_COUNT = 3;
+    static const unsigned int TEXCOORD_COUNT = 2;
+    static const unsigned int DIFFUSE_COUNT = 4;
+    static const unsigned int BLEND_WEIGHTS_COUNT = 4;
+    static const unsigned int BLEND_INDICES_COUNT = 4;
+
     /**
      * Constructor.
      */
@@ -28,11 +37,12 @@ public:
     Vector3 tangent;
     Vector3 binormal;
     Vector2 texCoord;
+    Vector4 diffuse;
 
     Vector4 blendWeights;
     Vector4 blendIndices;
 
-    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasColor, hasWeights;
+    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasDiffuse, hasWeights;
 
     inline bool operator<(const Vertex& v) const
     {
@@ -46,15 +56,19 @@ public:
                     {
                         if (texCoord == v.texCoord)
                         {
-                            if (blendWeights == v.blendWeights)
+                            if (diffuse == v.diffuse)
                             {
-                                if (blendIndices == v.blendIndices)
+                                if (blendWeights == v.blendWeights)
                                 {
-                                    return false;
+                                    if (blendIndices == v.blendIndices)
+                                    {
+                                        return false;
+                                    }
+                                    return blendIndices < v.blendIndices;
                                 }
-                                return blendIndices < v.blendIndices;
+                                return blendWeights < v.blendWeights;
                             }
-                            return blendWeights < v.blendWeights;
+                            return diffuse < v.diffuse;
                         }
                         return texCoord < v.texCoord;
                     }
@@ -70,7 +84,7 @@ public:
     inline bool operator==(const Vertex& v) const
     {
         return position==v.position && normal==v.normal && tangent==v.tangent && binormal==v.binormal && texCoord==v.texCoord &&
-            blendWeights==v.blendWeights && blendIndices==v.blendIndices;
+            diffuse==v.diffuse && blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
 
     /**

+ 31 - 0
gameplay-newproject.bat

@@ -197,6 +197,37 @@ 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 Android NDK project files
+mkdir %projPath%\android
+
+copy gameplay-template\android\template.AndroidManifest.xml %projPath%\android\AndroidManifest.xml
+call:replace %projPath%\android\AndroidManifest.xml TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\android\AndroidManifest.xml TEMPLATE_UUID "%uuid%"
+
+copy gameplay-template\android\template.build.xml %projPath%\android\build.xml
+call:replace %projPath%\android\build.xml TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\android\template.project %projPath%\android\.project
+call:replace %projPath%\android\.project TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\android\template.classpath %projPath%\android\.classpath
+
+mkdir %projPath%\android\jni
+
+copy gameplay-template\android\jni\Application.mk %projPath%\android\jni\Application.mk
+
+copy gameplay-template\android\jni\template.Android.mk %projPath%\android\jni\Android.mk
+call:replace %projPath%\android\jni\Android.mk TemplateGame "%className%"
+call:replace %projPath%\android\jni\Android.mk TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\android\jni\main.cpp %projPath%\android\jni\main.cpp
+
+mkdir %projPath%\android\res\values
+
+copy gameplay-template\android\res\values\template.strings.xml %projPath%\android\res\values\strings.xml
+call:replace %projPath%\android\res\values\strings.xml TEMPLATE_TITLE "%title%"
+
+
 REM Copy source files
 copy gameplay-template\src\TemplateGame.h %projPath%\src\%className%.h
 copy gameplay-template\src\TemplateGame.cpp %projPath%\src\%className%.cpp

+ 245 - 0
gameplay-newproject.sh

@@ -0,0 +1,245 @@
+#/bin/bash
+# ********************************************************************
+#
+# generate-project.sh
+#
+# This script generates a set of gameplay project files.
+# The new project will be based of the gameplay-template project and 
+# it will be generated with the name and location that is specified
+# as input parameters.
+#
+# IMPORTANT: This script must be run from the root of the gameplay
+# source tree.
+#
+# ********************************************************************
+
+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
+read -p "Project Name: " "" projName 
+if [[ "$projName" == "" ]]; then
+	echo
+	echo "ERROR: No project name specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Title: " "" title 
+if [[ "$title" == "" ]]; then
+	echo
+	echo "ERROR: No game title specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "3. Enter a short game description."
+echo
+read -p "Description: " "" desc
+if [[ "$desc" == "" ]]; then
+	desc=$title
+fi
+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
+read -p "Unique ID: " "" uuid
+if [[ "$uuid" == "" ]]; then
+	echo
+	echo "ERROR: No uuid specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Author: " "" author
+if [[ "$author" == "" ]]; then
+	echo
+	echo "ERROR: No author specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Class name: " "" className
+if [[ "$className" == "" ]]; then
+	echo
+	echo "ERROR: No class name specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Path: " "" location
+if [[ "$location" == "" ]]; then
+	projPath=$projName
+else
+	projPath="$location/$projName"
+fi
+echo
+
+
+# Verify Path and eliminate double '//'
+projPath=`echo "$projPath" | sed 's_//_/_g'`
+if [ -e $projPath ]; then
+	echo
+	echo "ERROR: Path '$projPath' already exists, aborting."
+	echo
+	exit -2
+fi
+
+# Generate relative path from project folder to gameplay folder
+gpPathAbs=`pwd`
+common_path=$projPath
+back=
+while [ "${gpPathAbs#$common_path}" = "${gpPathAbs}" ]; do
+	common_path=$(dirname $common_path)
+	back="../${back}"
+done
+gpPath=${back}${gpPathAbs#$common_path/}
+
+# Make required source folder directories
+mkdir -p "$projPath/src"
+mkdir -p "$projPath/res"
+
+# Below does copy, then uses 'sed' with -i for inplace editing
+# Alternative below uses sed to do a input then output skipping the copy
+# sed "s/TEMPLATE_PROJECT/$projectName/g" "gameplay-template/gameplay-template.vcxproj" > "$projPath/$projName.vcxproj"
+
+#############################################
+# Copy Microsoft Virtual Studio project files
+cp "gameplay-template/gameplay-template.vcxproj" "$projPath/$projName.vcxproj"
+sed -i "" "s*TEMPLATE_PROJECT*$projectName*g" "$projPath/$projName.vcxproj"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.vcxproj"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.vcxproj"
+
+cp "gameplay-template/gameplay-template.vcxproj.filters" "$projPath/$projName.vcxproj.filters"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.vcxproj.filters"
+
+cp "gameplay-template/gameplay-template.vcxproj.user" "$projPath/$projName.vcxproj.user"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.vcxproj.user"
+
+
+#############################################
+# Copy Apple XCode project files
+mkdir -p "$projPath/$projName.xcodeproj"
+cp "gameplay-template/gameplay-template.xcodeproj/project.pbxproj" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+
+cp "gameplay-template/TEMPLATE_PROJECT-macos.plist" "$projPath/$projName-macos.plist"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/$projName-macos.plist"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/$projName-macos.plist"
+
+cp "gameplay-template/TEMPLATE_PROJECT-ios.plist" "$projPath/$projName-ios.plist"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/$projName-ios.plist"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/$projName-ios.plist"
+
+#############################################
+# Copy BlackBerry NDK project files
+cp "gameplay-template/template.cproject" "$projPath/.cproject"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/.cproject"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/.cproject"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/.cproject"
+
+cp "gameplay-template/template.project" "$projPath/.project"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/.project"
+
+cp "gameplay-template/template.bar-descriptor.xml" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_TITLE*$title*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_DESCRIPTION*$desc*g" "$projPath/bar-descriptor.xml"
+
+#############################################
+# Copy Android NDK project files
+mkdir -p "$projPath/android"
+mkdir -p "$projPath/android/jni"
+mkdir -p "$projPath/android/res/values"
+
+cp "gameplay-template/android/template.AndroidManifest.xml" "$projPath/android/AndroidManifest.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/AndroidManifest.xml"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/android/AndroidManifest.xml"
+
+cp "gameplay-template/android/template.build.xml" "$projPath/android/build.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/build.xml"
+
+# Does not exist
+#cp "gameplay-template/android/template.project" "$projPath/android/.project"
+#sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/.project"
+
+#cp "gameplay-template/android/template.classpath" "$projPath/android/.classpath"
+
+cp "gameplay-template/android/jni/Application.mk" "$projPath/android/jni/Application.mk"
+
+cp "gameplay-template/android/jni/template.Android.mk" "$projPath/android/jni/Android.mk"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/jni/Android.mk"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/android/jni/Android.mk"
+
+#cp "gameplay-template/android/jni/main.cpp" "$projPath/android/jni/main.cpp"
+
+cp "gameplay-template/android/res/values/template.strings.xml" "$projPath/android/res/values/strings.xml"
+sed -i "" "s*TEMPLATE_TITLE*$title*g" "$projPath/android/res/values/strings.xml"
+
+
+#############################################
+# Copy source files
+#############################################
+cp "gameplay-template/src/TemplateGame.h" "$projPath/src/$className.h"
+cp "gameplay-template/src/TemplateGame.cpp" "$projPath/src/$className.cpp"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/src/$className.h"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/src/$className.cpp"
+
+# Copy resource files
+cp "gameplay-template/res/"* "$projPath/res/"
+#cp "gameplay-template/res/shaders/colored."* "$projPath/res/"
+
+# Copy icon
+cp "gameplay-template/icon.png" "$projPath/icon.png"
+
+# Open the new project folder
+open $projPath
+
+exit 0

+ 32 - 0
gameplay-template/TEMPLATE_PROJECT-ios.plist

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>icon.png</string>
+	<key>CFBundleIdentifier</key>
+	<string>TEMPLATE_UUID</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSApplicationCategoryType</key>
+	<string>public.app-category.games</string>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+</dict>
+</plist>

+ 0 - 0
gameplay-template/gameplay-template-macos.plist → gameplay-template/TEMPLATE_PROJECT-macos.plist


+ 1 - 0
gameplay-template/android/jni/Application.mk

@@ -0,0 +1 @@
+APP_STL     := stlport_static

+ 62 - 0
gameplay-template/android/jni/template.Android.mk

@@ -0,0 +1,62 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+SAMPLE_PATH := $(call my-dir)/../../src
+LIBPNG_PATH := $(call my-dir)/../../../../external-deps/libpng/lib/android/arm
+ZLIB_PATH := $(call my-dir)/../../../../external-deps/zlib/lib/android/arm
+BULLET_PATH := $(call my-dir)/../../../../external-deps/bullet/lib/android/arm
+
+# gameplay
+LOCAL_PATH := $(call my-dir)/../../../../gameplay/android/obj/local/armeabi
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libgameplay
+LOCAL_SRC_FILES := libgameplay.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# libpng
+LOCAL_PATH := $(LIBPNG_PATH)
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libpng 
+LOCAL_SRC_FILES := libpng.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# libzlib
+LOCAL_PATH := $(ZLIB_PATH)
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libzlib
+LOCAL_SRC_FILES := libzlib.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# libbullet
+LOCAL_PATH := $(BULLET_PATH)
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libbullet
+LOCAL_SRC_FILES := libbullet.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# TEMPLATE_PROJECT
+LOCAL_PATH := $(SAMPLE_PATH)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := TEMPLATE_PROJECT
+LOCAL_SRC_FILES := ../../../gameplay/src/gameplay-main-android.cpp TemplateGame.cpp
+
+LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv2 -lOpenSLES
+LOCAL_CFLAGS    := -D__ANDROID__ -I"../../../external-deps/bullet/include" -I"../../../external-deps/libpng/include" -I"../../../gameplay/src"
+
+LOCAL_STATIC_LIBRARIES := android_native_app_glue libgameplay libpng libzlib libbullet
+
+include $(BUILD_SHARED_LIBRARY)
+$(call import-module,android/native_app_glue)

+ 4 - 0
gameplay-template/android/res/values/template.strings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">TEMPLATE_TITLE</string>
+</resources>

+ 32 - 0
gameplay-template/android/template.AndroidManifest.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="TEMPLATE_UUID"
+        android:versionCode="1"
+        android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+        
+    <!-- This is the platform API where the app was introduced. -->
+    <uses-sdk android:minSdkVersion="9" />
+	<uses-feature android:glEsVersion="0x00020000"/>
+
+    <application android:label="@string/app_name" android:hasCode="true">
+
+        <!-- Our activity is the built-in NativeActivity framework class.
+             This will take care of integrating with our NDK code. -->
+        <activity android:name="android.app.NativeActivity"
+                android:label="@string/app_name"
+                android:configChanges="orientation|keyboardHidden"
+				android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+				android:screenOrientation="landscape">
+            <!-- Tell NativeActivity the name of or .so -->
+            <meta-data android:name="android.app.lib_name"
+                    android:value="TEMPLATE_PROJECT" />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest> 

+ 92 - 0
gameplay-template/android/template.build.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="TEMPLATE_PROJECT" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
+            unless="sdk.dir"
+    />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+     in between standard targets -->
+
+    <target name="-pre-build">
+		<mkdir dir="src"/>
+    </target>
+	
+<!--
+    <target name="-pre-compile">
+    </target>
+
+    /* This is typically used for code obfuscation.
+       Compiled code location: ${out.classes.absolute.dir}
+       If this is not done in place, override ${out.dex.input.absolute.dir} */
+       -->
+    <target name="-post-compile">
+        <copy file="../res/box.gpb" tofile="assets/res/box.gpb"/>
+        <copy file="../res/box.material" tofile="assets/res/box.material"/>
+        <copy file="../../../gameplay/res/shaders/colored.vsh" tofile="assets/res/shaders/colored.vsh"/>
+        <copy file="../../../gameplay/res/shaders/colored.fsh" tofile="assets/res/shaders/colored.fsh"/>
+    </target>
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

+ 210 - 35
gameplay-template/gameplay-template.xcodeproj/project.pbxproj

@@ -7,14 +7,14 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		42C932F11491A5160098216A /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
+		42438B531491AD2000D218B8 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
+		42C932C11491A0DB0098216A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C932C01491A0DB0098216A /* Cocoa.framework */; };
 		42C932EE1491A4CB0098216A /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 42C932ED1491A4CB0098216A /* icon.png */; };
+		42C932F11491A5160098216A /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
 		42C932F31491A53E0098216A /* res in Resources */ = {isa = PBXBuildFile; fileRef = 42C932F21491A53E0098216A /* res */; };
-		42C932C11491A0DB0098216A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C932C01491A0DB0098216A /* Cocoa.framework */; };
-		42C9331D1491A6750098216A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9331C1491A6750098216A /* QuartzCore.framework */; };
 		42C933171491A5EB0098216A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933161491A5EB0098216A /* OpenGL.framework */; };
+		42C9331D1491A6750098216A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9331C1491A6750098216A /* QuartzCore.framework */; };
 		42C9331F1491A67F0098216A /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9331E1491A67F0098216A /* OpenAL.framework */; };
-		42438B531491AD2000D218B8 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
 		42C933211491A6C70098216A /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933201491A6C70098216A /* libbullet.a */; };
 		42C933261491A6E50098216A /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933221491A6E50098216A /* libogg.a */; };
 		42C933271491A6E50098216A /* libvorbis.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933231491A6E50098216A /* libvorbis.a */; };
@@ -22,20 +22,37 @@
 		42C933291491A6E50098216A /* libvorbisfile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933251491A6E50098216A /* libvorbisfile.a */; };
 		42C9332C1491A7680098216A /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332A1491A7390098216A /* libpng.a */; };
 		42C9332F1491A78D0098216A /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332D1491A7810098216A /* libz.dylib */; };
+		5B61611314CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */; };
+		5B61611614CCC24C0073B857 /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
+		5B61611814CCC24C0073B857 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
+		5B61611914CCC24C0073B857 /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933201491A6C70098216A /* libbullet.a */; };
+		5B61611A14CCC24C0073B857 /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933221491A6E50098216A /* libogg.a */; };
+		5B61611B14CCC24C0073B857 /* libvorbis.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933231491A6E50098216A /* libvorbis.a */; };
+		5B61611C14CCC24C0073B857 /* libvorbisenc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933241491A6E50098216A /* libvorbisenc.a */; };
+		5B61611D14CCC24C0073B857 /* libvorbisfile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933251491A6E50098216A /* libvorbisfile.a */; };
+		5B61611E14CCC24C0073B857 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332A1491A7390098216A /* libpng.a */; };
+		5B61611F14CCC24C0073B857 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332D1491A7810098216A /* libz.dylib */; };
+		5B61612614CCC24C0073B857 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 42C932ED1491A4CB0098216A /* icon.png */; };
+		5B61612714CCC24C0073B857 /* res in Resources */ = {isa = PBXBuildFile; fileRef = 42C932F21491A53E0098216A /* res */; };
+		5B61612814CCC24C0073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */; };
+		5B61613114CCC33A0073B857 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61612F14CCC33A0073B857 /* OpenAL.framework */; };
+		5B61613214CCC33A0073B857 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613014CCC33A0073B857 /* OpenGLES.framework */; };
+		5B61613414CCC3420073B857 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613314CCC3420073B857 /* UIKit.framework */; };
+		5B61613614CCC34A0073B857 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613514CCC3490073B857 /* CoreMotion.framework */; };
+		5B61613814CCC3500073B857 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613714CCC3500073B857 /* QuartzCore.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT.app"; sourceTree = BUILT_PRODUCTS_DIR; };
-		42C9336B1491AA0E0098216A /* TEMPLATE_PROJECT-macos.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-macos.plist"; sourceTree = "<group>"; };
+		42438B521491AD2000D218B8 /* libgameplay.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgameplay.a; path = "~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug/libgameplay.a"; sourceTree = "<group>"; };
+		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-MacOSX.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		42C932C01491A0DB0098216A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		42C932ED1491A4CB0098216A /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
-		42C932F21491A53E0098216A /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
 		42C932EF1491A5160098216A /* TemplateGame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateGame.cpp; path = src/TemplateGame.cpp; sourceTree = SOURCE_ROOT; };
 		42C932F01491A5160098216A /* TemplateGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemplateGame.h; path = src/TemplateGame.h; sourceTree = SOURCE_ROOT; };
-		42C932C01491A0DB0098216A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
-		42C9331C1491A6750098216A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		42C932F21491A53E0098216A /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
 		42C933161491A5EB0098216A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		42C9331C1491A6750098216A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 		42C9331E1491A67F0098216A /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
-		42438B521491AD2000D218B8 /* libgameplay.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgameplay.a; path = "~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug/libgameplay.a"; sourceTree = "<group>"; };
 		42C933201491A6C70098216A /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "GAMEPLAY_PATH/external-deps/bullet/lib/macos/libbullet.a"; sourceTree = "<group>"; };
 		42C933221491A6E50098216A /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libogg.a"; sourceTree = "<group>"; };
 		42C933231491A6E50098216A /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libvorbis.a"; sourceTree = "<group>"; };
@@ -43,6 +60,14 @@
 		42C933251491A6E50098216A /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libvorbisfile.a"; sourceTree = "<group>"; };
 		42C9332A1491A7390098216A /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "GAMEPLAY_PATH/external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
 		42C9332D1491A7810098216A /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+		5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-macos.plist"; sourceTree = "<group>"; };
+		5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		5B61612E14CCC24D0073B857 /* TEMPLATE_PROJECT-ios.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "TEMPLATE_PROJECT-ios.plist"; path = "/Users/bslack/src/git/GamePlay/gameplay-template/TEMPLATE_PROJECT-ios.plist"; sourceTree = "<absolute>"; };
+		5B61612F14CCC33A0073B857 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		5B61613014CCC33A0073B857 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
+		5B61613314CCC3420073B857 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		5B61613514CCC3490073B857 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
+		5B61613714CCC3500073B857 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -65,13 +90,34 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B61611714CCC24C0073B857 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B61613814CCC3500073B857 /* QuartzCore.framework in Frameworks */,
+				5B61613614CCC34A0073B857 /* CoreMotion.framework in Frameworks */,
+				5B61613414CCC3420073B857 /* UIKit.framework in Frameworks */,
+				5B61613114CCC33A0073B857 /* OpenAL.framework in Frameworks */,
+				5B61613214CCC33A0073B857 /* OpenGLES.framework in Frameworks */,
+				5B61611814CCC24C0073B857 /* libgameplay.a in Frameworks */,
+				5B61611914CCC24C0073B857 /* libbullet.a in Frameworks */,
+				5B61611A14CCC24C0073B857 /* libogg.a in Frameworks */,
+				5B61611B14CCC24C0073B857 /* libvorbis.a in Frameworks */,
+				5B61611C14CCC24C0073B857 /* libvorbisenc.a in Frameworks */,
+				5B61611D14CCC24C0073B857 /* libvorbisfile.a in Frameworks */,
+				5B61611E14CCC24C0073B857 /* libpng.a in Frameworks */,
+				5B61611F14CCC24C0073B857 /* libz.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 		42C932B11491A0DB0098216A = {
 			isa = PBXGroup;
 			children = (
-				42C9336B1491AA0E0098216A /* TEMPLATE_PROJECT-macos.plist */,
+				5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */,
+				5B61612E14CCC24D0073B857 /* TEMPLATE_PROJECT-ios.plist */,
 				42C932ED1491A4CB0098216A /* icon.png */,
 				42C932F21491A53E0098216A /* res */,
 				42C932C61491A0DB0098216A /* src */,
@@ -84,7 +130,8 @@
 		42C932BD1491A0DB0098216A /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */,
+				42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */,
+				5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -92,10 +139,8 @@
 		42C932BF1491A0DB0098216A /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				42C932C01491A0DB0098216A /* Cocoa.framework */,
-				42C9331C1491A6750098216A /* QuartzCore.framework */,
-				42C933161491A5EB0098216A /* OpenGL.framework */,
-				42C9331E1491A67F0098216A /* OpenAL.framework */,
+				5B61613A14CCC3590073B857 /* Mac OS X */,
+				5B61613914CCC3560073B857 /* iOS */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -106,8 +151,7 @@
 				42C932EF1491A5160098216A /* TemplateGame.cpp */,
 				42C932F01491A5160098216A /* TemplateGame.h */,
 			);
-			name = src;
-			path = "src";
+			path = src;
 			sourceTree = "<group>";
 		};
 		42C932DD1491A1050098216A /* Libraries */ = {
@@ -125,12 +169,35 @@
 			name = Libraries;
 			sourceTree = "<group>";
 		};
+		5B61613914CCC3560073B857 /* iOS */ = {
+			isa = PBXGroup;
+			children = (
+				5B61613714CCC3500073B857 /* QuartzCore.framework */,
+				5B61613514CCC3490073B857 /* CoreMotion.framework */,
+				5B61613314CCC3420073B857 /* UIKit.framework */,
+				5B61612F14CCC33A0073B857 /* OpenAL.framework */,
+				5B61613014CCC33A0073B857 /* OpenGLES.framework */,
+			);
+			name = iOS;
+			sourceTree = "<group>";
+		};
+		5B61613A14CCC3590073B857 /* Mac OS X */ = {
+			isa = PBXGroup;
+			children = (
+				42C932C01491A0DB0098216A /* Cocoa.framework */,
+				42C9331C1491A6750098216A /* QuartzCore.framework */,
+				42C933161491A5EB0098216A /* OpenGL.framework */,
+				42C9331E1491A67F0098216A /* OpenAL.framework */,
+			);
+			name = "Mac OS X";
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT */ = {
+		42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT" */;
+			buildConfigurationList = 42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-MacOSX" */;
 			buildPhases = (
 				42C932B81491A0DB0098216A /* Sources */,
 				42C932B91491A0DB0098216A /* Frameworks */,
@@ -141,9 +208,27 @@
 			);
 			dependencies = (
 			);
-			name = "TEMPLATE_PROJECT";
-			productName = "TEMPLATE_PROJECT";
-			productReference = 42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */;
+			name = "TEMPLATE_PROJECT-MacOSX";
+			productName = TEMPLATE_PROJECT;
+			productReference = 42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */;
+			productType = "com.apple.product-type.application";
+		};
+		5B61611414CCC24C0073B857 /* TEMPLATE_PROJECT-iOS */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 5B61612914CCC24C0073B857 /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-iOS" */;
+			buildPhases = (
+				5B61611514CCC24C0073B857 /* Sources */,
+				5B61611714CCC24C0073B857 /* Frameworks */,
+				5B61612414CCC24C0073B857 /* ShellScript */,
+				5B61612514CCC24C0073B857 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "TEMPLATE_PROJECT-iOS";
+			productName = TEMPLATE_PROJECT;
+			productReference = 5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */;
 			productType = "com.apple.product-type.application";
 		};
 /* End PBXNativeTarget section */
@@ -154,7 +239,7 @@
 			attributes = {
 				LastUpgradeCheck = 0420;
 			};
-			buildConfigurationList = 42C932B61491A0DB0098216A /* Build configuration list for PBXProject "TEMPLATE_PROJECT" */;
+			buildConfigurationList = 42C932B61491A0DB0098216A /* Build configuration list for PBXProject "gameplay-template" */;
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
@@ -166,7 +251,8 @@
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT */,
+				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX */,
+				5B61611414CCC24C0073B857 /* TEMPLATE_PROJECT-iOS */,
 			);
 		};
 /* End PBXProject section */
@@ -178,6 +264,17 @@
 			files = (
 				42C932EE1491A4CB0098216A /* icon.png in Resources */,
 				42C932F31491A53E0098216A /* res in Resources */,
+				5B61611314CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		5B61612514CCC24C0073B857 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B61612614CCC24C0073B857 /* icon.png in Resources */,
+				5B61612714CCC24C0073B857 /* res in Resources */,
+				5B61612814CCC24C0073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -197,6 +294,19 @@
 			shellPath = /bin/sh;
 			shellScript = "touch -cm ${SRCROOT}/res";
 		};
+		5B61612414CCC24C0073B857 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "touch -cm ${SRCROOT}/res";
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -208,6 +318,14 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B61611514CCC24C0073B857 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B61611614CCC24C0073B857 /* TemplateGame.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
@@ -265,23 +383,22 @@
 		42C932DB1491A0DB0098216A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				GCC_PRECOMPILE_PREFIX_HEADER = NO;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
-					"GAMEPLAY_PATH/gameplay/src",
+					GAMEPLAY_PATH/gameplay/src,
 					"GAMEPLAY_PATH/external-deps/libpng/include",
 					"GAMEPLAY_PATH/external-deps/bullet/include",
 					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
 				);
-				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				INFOPLIST_FILE = "gameplay-template-macos.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macos\"",
 					"\"GAMEPLAY_PATH/external-deps/bullet/lib/macos\"",
 					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos\"",
-					"\"~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
 				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "";
@@ -292,23 +409,22 @@
 		42C932DC1491A0DB0098216A /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				GCC_PRECOMPILE_PREFIX_HEADER = NO;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
-					"GAMEPLAY_PATH/gameplay/src",
+					GAMEPLAY_PATH/gameplay/src,
 					"GAMEPLAY_PATH/external-deps/libpng/include",
 					"GAMEPLAY_PATH/external-deps/bullet/include",
 					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
 				);
-				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				INFOPLIST_FILE = "gameplay-template-macos.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macos\"",
 					"\"GAMEPLAY_PATH/external-deps/bullet/lib/macos\"",
 					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos\"",
-					"\"~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
 				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "";
@@ -316,10 +432,60 @@
 			};
 			name = Release;
 		};
+		5B61612A14CCC24C0073B857 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_PRECOMPILE_PREFIX_HEADER = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					GAMEPLAY_PATH/gameplay/src,
+					"GAMEPLAY_PATH/external-deps/libpng/include",
+					"GAMEPLAY_PATH/external-deps/bullet/include",
+					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
+				);
+				INFOPLIST_FILE = "gameplay-template-ios.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/ios/$(CURRENT_ARCH)\"",
+				);
+				SDKROOT = iphoneos;
+				USER_HEADER_SEARCH_PATHS = "";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		5B61612B14CCC24C0073B857 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_PRECOMPILE_PREFIX_HEADER = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					GAMEPLAY_PATH/gameplay/src,
+					"GAMEPLAY_PATH/external-deps/libpng/include",
+					"GAMEPLAY_PATH/external-deps/bullet/include",
+					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
+				);
+				INFOPLIST_FILE = "gameplay-template-ios.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/ios/$(CURRENT_ARCH)\"",
+				);
+				SDKROOT = iphoneos;
+				USER_HEADER_SEARCH_PATHS = "";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		42C932B61491A0DB0098216A /* Build configuration list for PBXProject "TEMPLATE_PROJECT" */ = {
+		42C932B61491A0DB0098216A /* Build configuration list for PBXProject "gameplay-template" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				42C932D81491A0DB0098216A /* Debug */,
@@ -328,7 +494,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT" */ = {
+		42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-MacOSX" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				42C932DB1491A0DB0098216A /* Debug */,
@@ -337,6 +503,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		5B61612914CCC24C0073B857 /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-iOS" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				5B61612A14CCC24C0073B857 /* Debug */,
+				5B61612B14CCC24C0073B857 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
 	};
 	rootObject = 42C932B31491A0DB0098216A /* Project object */;

+ 2 - 2
gameplay-template/res/box.material

@@ -5,8 +5,8 @@ material box
         pass
         {
             // shaders
-            vertexShader = res/colored.vsh
-            fragmentShader = res/colored.fsh
+            vertexShader = res/shaders/colored.vsh
+            fragmentShader = res/shaders/colored.fsh
             
             // uniforms
             u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX

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

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

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

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

+ 2 - 2
gameplay.doxyfile

@@ -26,13 +26,13 @@ DOXYFILE_ENCODING      = UTF-8
 # identify the project. Note that if you do not use Doxywizard you need 
 # to put quotes around the project name if it contains spaces.
 
-PROJECT_NAME           = GamePlay
+PROJECT_NAME           = gameplay
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 
-PROJECT_NUMBER         = 1.1.0
+PROJECT_NUMBER         = 1.2.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description 
 # for a project that appears at the top of each page and should give viewer 

+ 8 - 0
gameplay.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
+	<true/>
+</dict>
+</plist>

+ 1 - 3
gameplay/.cproject

@@ -9,8 +9,6 @@
 				<extensions>
 					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
 				</extensions>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -19,7 +17,7 @@
 						<toolChain id="com.qnx.qcc.toolChain.staticLib.debug.1686166742" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
 							<option id="com.qnx.qcc.option.cpu.545743487" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
 							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.158841187" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="cdt.managedbuild.target.gnu.builder.base.2098111998" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="org.eclipse.cdt.build.core.internal.builder.159190287" superClass="org.eclipse.cdt.build.core.internal.builder"/>
 							<tool id="com.qnx.qcc.tool.compiler.96907942" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
 								<option id="com.qnx.qcc.option.compile.debug.1765481355" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>

+ 0 - 12
gameplay/.project

@@ -17,10 +17,6 @@
 					<key>org.eclipse.cdt.make.core.append_environment</key>
 					<value>true</value>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
-					<value>all</value>
-				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.buildArguments</key>
 					<value></value>
@@ -33,10 +29,6 @@
 					<key>org.eclipse.cdt.make.core.buildLocation</key>
 					<value>${workspace_loc:/gameplay/Device-Debug}</value>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
-					<value>clean</value>
-				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.contents</key>
 					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
@@ -53,10 +45,6 @@
 					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
 					<value>true</value>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
-					<value>all</value>
-				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.stopOnError</key>
 					<value>true</value>

+ 14 - 0
gameplay/android/AndroidManifest.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.gameplay"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="15" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name" >
+    </application>
+
+</manifest>

+ 85 - 0
gameplay/android/build.xml

@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="gameplay-android" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
+            unless="sdk.dir"
+    />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+     in between standard targets -->
+<!--
+    <target name="-pre-build">
+    </target>
+    <target name="-pre-compile">
+    </target>
+
+    /* This is typically used for code obfuscation.
+       Compiled code location: ${out.classes.absolute.dir}
+       If this is not done in place, override ${out.dex.input.absolute.dir} */
+    <target name="-post-compile">
+    </target>
+-->
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

+ 25 - 0
gameplay/android/jni/Android.mk

@@ -0,0 +1,25 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)/../../src
+
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libgameplay
+LOCAL_SRC_FILES := Animation.cpp DepthStencilTarget.cpp MeshBatch.cpp PhysicsRigidBody.cpp SceneLoader.cpp AnimationClip.cpp Effect.cpp MeshPart.cpp PhysicsSocketConstraint.cpp SpriteBatch.cpp AnimationController.cpp FileSystem.cpp MeshSkin.cpp PhysicsSpringConstraint.cpp Technique.cpp AnimationTarget.cpp Font.cpp Model.cpp Plane.cpp Texture.cpp AnimationValue.cpp FrameBuffer.cpp Node.cpp PlatformAndroid.cpp PlatformQNX.cpp AudioBuffer.cpp Frustum.cpp Package.cpp PlatformWin32.cpp Transform.cpp AudioController.cpp Game.cpp ParticleEmitter.cpp Properties.cpp Vector2.cpp AudioListener.cpp Image.cpp Pass.cpp Quaternion.cpp Vector3.cpp AudioSource.cpp Joint.cpp PhysicsConstraint.cpp Ray.cpp Vector4.cpp BoundingBox.cpp Light.cpp PhysicsController.cpp Rectangle.cpp VertexAttributeBinding.cpp BoundingSphere.cpp Material.cpp PhysicsFixedConstraint.cpp Ref.cpp VertexFormat.cpp Camera.cpp MaterialParameter.cpp PhysicsGenericConstraint.cpp RenderState.cpp Viewport.cpp Curve.cpp Matrix.cpp PhysicsHingeConstraint.cpp RenderTarget.cpp DebugNew.cpp Mesh.cpp PhysicsMotionState.cpp Scene.cpp
+LOCAL_CFLAGS := -D__ANDROID__ -I"../../external-deps/bullet/include" -I"../../external-deps/libpng/include"
+LOCAL_STATIC_LIBRARIES := android_native_app_glue
+
+include $(BUILD_STATIC_LIBRARY)
+
+$(call import-module,android/native_app_glue)

+ 2 - 0
gameplay/android/jni/Application.mk

@@ -0,0 +1,2 @@
+APP_STL     := stlport_static
+APP_MODULES := libgameplay

+ 5 - 0
gameplay/gameplay.vcxproj

@@ -42,6 +42,7 @@
     <ClCompile Include="src\FrameBuffer.cpp" />
     <ClCompile Include="src\Frustum.cpp" />
     <ClCompile Include="src\Game.cpp" />
+    <ClCompile Include="src\gameplay-main-android.cpp" />
     <ClCompile Include="src\gameplay-main-qnx.cpp" />
     <ClCompile Include="src\gameplay-main-win32.cpp" />
     <ClCompile Include="src\Image.cpp" />
@@ -70,6 +71,7 @@
     <ClCompile Include="src\PhysicsSocketConstraint.cpp" />
     <ClCompile Include="src\PhysicsSpringConstraint.cpp" />
     <ClCompile Include="src\Plane.cpp" />
+    <ClCompile Include="src\PlatformAndroid.cpp" />
     <ClCompile Include="src\PlatformQNX.cpp" />
     <ClCompile Include="src\PlatformWin32.cpp" />
     <ClCompile Include="src\Properties.cpp" />
@@ -135,6 +137,7 @@
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\Material.h" />
     <ClInclude Include="src\MeshBatch.h" />
+    <ClInclude Include="src\Mouse.h" />
     <ClInclude Include="src\Pass.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />
@@ -208,11 +211,13 @@
     <None Include="src\BoundingSphere.inl" />
     <None Include="src\Curve.inl" />
     <None Include="src\Game.inl" />
+    <None Include="src\gameplay-main-ios.mm" />
     <None Include="src\gameplay-main-macos.mm" />
     <None Include="src\Image.inl" />
     <None Include="src\Matrix.inl" />
     <None Include="src\MeshBatch.inl" />
     <None Include="src\Plane.inl" />
+    <None Include="src\PlatformiOS.mm" />
     <None Include="src\PlatformMacOS.mm" />
     <None Include="src\Quaternion.inl" />
     <None Include="src\Ray.inl" />

+ 15 - 0
gameplay/gameplay.vcxproj.filters

@@ -222,6 +222,12 @@
     <ClCompile Include="src\MeshBatch.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\gameplay-main-android.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PlatformAndroid.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
     <ClCompile Include="src\AbsoluteLayout.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -470,6 +476,9 @@
     <ClInclude Include="src\MeshBatch.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Mouse.h">
+      <Filter>src</Filter>
+    </ClInclude>
     <ClInclude Include="src\AbsoluteLayout.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -592,6 +601,12 @@
     <None Include="src\MeshBatch.inl">
       <Filter>src</Filter>
     </None>
+    <None Include="src\gameplay-main-ios.mm">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\PlatformiOS.mm">
+      <Filter>src</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\PhysicsFixedConstraint.inl">

+ 578 - 45
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -19,7 +19,6 @@
 		4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
 		4299EFA9146AC94300FF4A73 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4299EFA8146AC94300FF4A73 /* OpenGL.framework */; };
 		4299EFAB146AC94B00FF4A73 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4299EFAA146AC94B00FF4A73 /* OpenAL.framework */; };
-		42CCD554146EC1DD00353661 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD553146EC1DD00353661 /* libz.dylib */; };
 		42CCD556146EC1EB00353661 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
 		42CD0DAB147D8EA80000361E /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA6147D8EA80000361E /* libbullet.a */; };
 		42CD0DAC147D8EA80000361E /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA7147D8EA80000361E /* libogg.a */; };
@@ -70,8 +69,6 @@
 		42CD0E6F147D8FF60000361E /* Game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDC147D8FF50000361E /* Game.cpp */; };
 		42CD0E70147D8FF60000361E /* Game.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DDD147D8FF50000361E /* Game.h */; };
 		42CD0E71147D8FF60000361E /* gameplay-main-macos.mm in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */; };
-		42CD0E72147D8FF60000361E /* gameplay-main-qnx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */; };
-		42CD0E73147D8FF60000361E /* gameplay-main-win32.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */; };
 		42CD0E74147D8FF60000361E /* gameplay.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE1147D8FF50000361E /* gameplay.h */; };
 		42CD0E77147D8FF60000361E /* Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE4147D8FF50000361E /* Joint.cpp */; };
 		42CD0E78147D8FF60000361E /* Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE5147D8FF50000361E /* Joint.h */; };
@@ -121,8 +118,6 @@
 		42CD0EA4147D8FF60000361E /* Plane.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E17147D8FF50000361E /* Plane.h */; };
 		42CD0EA5147D8FF60000361E /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E19147D8FF50000361E /* Platform.h */; };
 		42CD0EA6147D8FF60000361E /* PlatformMacOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */; };
-		42CD0EA7147D8FF60000361E /* PlatformQNX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */; };
-		42CD0EA8147D8FF60000361E /* PlatformWin32.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */; };
 		42CD0EA9147D8FF60000361E /* Properties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1D147D8FF50000361E /* Properties.cpp */; };
 		42CD0EAA147D8FF60000361E /* Properties.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E1E147D8FF50000361E /* Properties.h */; };
 		42CD0EAB147D8FF60000361E /* Quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1F147D8FF50000361E /* Quaternion.cpp */; };
@@ -159,6 +154,159 @@
 		42CD0ECA147D8FF60000361E /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
 		42CD0ECB147D8FF60000361E /* Viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E44147D8FF50000361E /* Viewport.cpp */; };
 		42CD0ECC147D8FF60000361E /* Viewport.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E45147D8FF50000361E /* Viewport.h */; };
+		5B04C52D14BFCFE100EB0071 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB1147D8FF50000361E /* Animation.cpp */; };
+		5B04C52E14BFCFE100EB0071 /* AnimationClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB3147D8FF50000361E /* AnimationClip.cpp */; };
+		5B04C52F14BFCFE100EB0071 /* AnimationController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB5147D8FF50000361E /* AnimationController.cpp */; };
+		5B04C53014BFCFE100EB0071 /* AnimationTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB7147D8FF50000361E /* AnimationTarget.cpp */; };
+		5B04C53114BFCFE100EB0071 /* AnimationValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB9147D8FF50000361E /* AnimationValue.cpp */; };
+		5B04C53214BFCFE100EB0071 /* AudioBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DBB147D8FF50000361E /* AudioBuffer.cpp */; };
+		5B04C53314BFCFE100EB0071 /* AudioController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DBD147D8FF50000361E /* AudioController.cpp */; };
+		5B04C53414BFCFE100EB0071 /* AudioListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DBF147D8FF50000361E /* AudioListener.cpp */; };
+		5B04C53514BFCFE100EB0071 /* AudioSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DC1147D8FF50000361E /* AudioSource.cpp */; };
+		5B04C53614BFCFE100EB0071 /* BoundingBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DC4147D8FF50000361E /* BoundingBox.cpp */; };
+		5B04C53714BFCFE100EB0071 /* BoundingSphere.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DC7147D8FF50000361E /* BoundingSphere.cpp */; };
+		5B04C53814BFCFE100EB0071 /* Camera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DCA147D8FF50000361E /* Camera.cpp */; };
+		5B04C53914BFCFE100EB0071 /* Curve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DCC147D8FF50000361E /* Curve.cpp */; };
+		5B04C53A14BFCFE100EB0071 /* DebugNew.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DCE147D8FF50000361E /* DebugNew.cpp */; };
+		5B04C53B14BFCFE100EB0071 /* DepthStencilTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DD0147D8FF50000361E /* DepthStencilTarget.cpp */; };
+		5B04C53C14BFCFE100EB0071 /* Effect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DD2147D8FF50000361E /* Effect.cpp */; };
+		5B04C53D14BFCFE100EB0071 /* FileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DD4147D8FF50000361E /* FileSystem.cpp */; };
+		5B04C53E14BFCFE100EB0071 /* Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DD6147D8FF50000361E /* Font.cpp */; };
+		5B04C53F14BFCFE100EB0071 /* FrameBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DD8147D8FF50000361E /* FrameBuffer.cpp */; };
+		5B04C54014BFCFE100EB0071 /* Frustum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDA147D8FF50000361E /* Frustum.cpp */; };
+		5B04C54114BFCFE100EB0071 /* Game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDC147D8FF50000361E /* Game.cpp */; };
+		5B04C54514BFCFE100EB0071 /* Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE4147D8FF50000361E /* Joint.cpp */; };
+		5B04C54614BFCFE100EB0071 /* Light.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE6147D8FF50000361E /* Light.cpp */; };
+		5B04C54714BFCFE100EB0071 /* Material.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE8147D8FF50000361E /* Material.cpp */; };
+		5B04C54814BFCFE100EB0071 /* MaterialParameter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DEA147D8FF50000361E /* MaterialParameter.cpp */; };
+		5B04C54914BFCFE100EB0071 /* Matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DEC147D8FF50000361E /* Matrix.cpp */; };
+		5B04C54A14BFCFE100EB0071 /* Mesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DEF147D8FF50000361E /* Mesh.cpp */; };
+		5B04C54B14BFCFE100EB0071 /* MeshPart.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF1147D8FF50000361E /* MeshPart.cpp */; };
+		5B04C54C14BFCFE100EB0071 /* MeshSkin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF3147D8FF50000361E /* MeshSkin.cpp */; };
+		5B04C54D14BFCFE100EB0071 /* Model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF5147D8FF50000361E /* Model.cpp */; };
+		5B04C54E14BFCFE100EB0071 /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF7147D8FF50000361E /* Node.cpp */; };
+		5B04C54F14BFCFE100EB0071 /* Package.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF9147D8FF50000361E /* Package.cpp */; };
+		5B04C55014BFCFE100EB0071 /* ParticleEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */; };
+		5B04C55114BFCFE100EB0071 /* Pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFD147D8FF50000361E /* Pass.cpp */; };
+		5B04C55214BFCFE100EB0071 /* PhysicsConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */; };
+		5B04C55314BFCFE100EB0071 /* PhysicsController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E02147D8FF50000361E /* PhysicsController.cpp */; };
+		5B04C55414BFCFE100EB0071 /* PhysicsFixedConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E04147D8FF50000361E /* PhysicsFixedConstraint.cpp */; };
+		5B04C55514BFCFE100EB0071 /* PhysicsGenericConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E07147D8FF50000361E /* PhysicsGenericConstraint.cpp */; };
+		5B04C55614BFCFE100EB0071 /* PhysicsHingeConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E0A147D8FF50000361E /* PhysicsHingeConstraint.cpp */; };
+		5B04C55714BFCFE100EB0071 /* PhysicsMotionState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E0C147D8FF50000361E /* PhysicsMotionState.cpp */; };
+		5B04C55814BFCFE100EB0071 /* PhysicsRigidBody.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E0E147D8FF50000361E /* PhysicsRigidBody.cpp */; };
+		5B04C55914BFCFE100EB0071 /* PhysicsSocketConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E11147D8FF50000361E /* PhysicsSocketConstraint.cpp */; };
+		5B04C55A14BFCFE100EB0071 /* PhysicsSpringConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E13147D8FF50000361E /* PhysicsSpringConstraint.cpp */; };
+		5B04C55B14BFCFE100EB0071 /* Plane.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E16147D8FF50000361E /* Plane.cpp */; };
+		5B04C55F14BFCFE100EB0071 /* Properties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1D147D8FF50000361E /* Properties.cpp */; };
+		5B04C56014BFCFE100EB0071 /* Quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1F147D8FF50000361E /* Quaternion.cpp */; };
+		5B04C56114BFCFE100EB0071 /* Ray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E22147D8FF50000361E /* Ray.cpp */; };
+		5B04C56214BFCFE100EB0071 /* Rectangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E25147D8FF50000361E /* Rectangle.cpp */; };
+		5B04C56314BFCFE100EB0071 /* Ref.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E27147D8FF50000361E /* Ref.cpp */; };
+		5B04C56414BFCFE100EB0071 /* RenderState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E29147D8FF50000361E /* RenderState.cpp */; };
+		5B04C56514BFCFE100EB0071 /* RenderTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E2B147D8FF50000361E /* RenderTarget.cpp */; };
+		5B04C56614BFCFE100EB0071 /* Scene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E2D147D8FF50000361E /* Scene.cpp */; };
+		5B04C56714BFCFE100EB0071 /* SpriteBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */; };
+		5B04C56814BFCFE100EB0071 /* Technique.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E31147D8FF50000361E /* Technique.cpp */; };
+		5B04C56914BFCFE100EB0071 /* Texture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E33147D8FF50000361E /* Texture.cpp */; };
+		5B04C56A14BFCFE100EB0071 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E35147D8FF50000361E /* Transform.cpp */; };
+		5B04C56B14BFCFE100EB0071 /* Vector2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E37147D8FF50000361E /* Vector2.cpp */; };
+		5B04C56C14BFCFE100EB0071 /* Vector3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E3A147D8FF50000361E /* Vector3.cpp */; };
+		5B04C56D14BFCFE100EB0071 /* Vector4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E3D147D8FF50000361E /* Vector4.cpp */; };
+		5B04C56E14BFCFE100EB0071 /* VertexAttributeBinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E40147D8FF50000361E /* VertexAttributeBinding.cpp */; };
+		5B04C56F14BFCFE100EB0071 /* VertexFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E42147D8FF50000361E /* VertexFormat.cpp */; };
+		5B04C57014BFCFE100EB0071 /* Viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E44147D8FF50000361E /* Viewport.cpp */; };
+		5B04C57114BFCFE100EB0071 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
+		5B04C57214BFCFE100EB0071 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4208DEE614A4079F00D3C511 /* Image.cpp */; };
+		5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4201818D14A41B18008C3F56 /* MeshBatch.cpp */; };
+		5B04C57514BFCFE100EB0071 /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA6147D8EA80000361E /* libbullet.a */; };
+		5B04C57614BFCFE100EB0071 /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA7147D8EA80000361E /* libogg.a */; };
+		5B04C57714BFCFE100EB0071 /* libvorbis.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA8147D8EA80000361E /* libvorbis.a */; };
+		5B04C57814BFCFE100EB0071 /* libvorbisenc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA9147D8EA80000361E /* libvorbisenc.a */; };
+		5B04C57914BFCFE100EB0071 /* libvorbisfile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DAA147D8EA80000361E /* libvorbisfile.a */; };
+		5B04C57A14BFCFE100EB0071 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
+		5B04C58114BFCFE100EB0071 /* Animation.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DB2147D8FF50000361E /* Animation.h */; };
+		5B04C58214BFCFE100EB0071 /* AnimationClip.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DB4147D8FF50000361E /* AnimationClip.h */; };
+		5B04C58314BFCFE100EB0071 /* AnimationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DB6147D8FF50000361E /* AnimationController.h */; };
+		5B04C58414BFCFE100EB0071 /* AnimationTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DB8147D8FF50000361E /* AnimationTarget.h */; };
+		5B04C58514BFCFE100EB0071 /* AnimationValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DBA147D8FF50000361E /* AnimationValue.h */; };
+		5B04C58614BFCFE100EB0071 /* AudioBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DBC147D8FF50000361E /* AudioBuffer.h */; };
+		5B04C58714BFCFE100EB0071 /* AudioController.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DBE147D8FF50000361E /* AudioController.h */; };
+		5B04C58814BFCFE100EB0071 /* AudioListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DC0147D8FF50000361E /* AudioListener.h */; };
+		5B04C58914BFCFE100EB0071 /* AudioSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DC2147D8FF50000361E /* AudioSource.h */; };
+		5B04C58A14BFCFE100EB0071 /* Base.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DC3147D8FF50000361E /* Base.h */; };
+		5B04C58B14BFCFE100EB0071 /* BoundingBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DC5147D8FF50000361E /* BoundingBox.h */; };
+		5B04C58C14BFCFE100EB0071 /* BoundingSphere.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DC8147D8FF50000361E /* BoundingSphere.h */; };
+		5B04C58D14BFCFE100EB0071 /* Camera.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DCB147D8FF50000361E /* Camera.h */; };
+		5B04C58E14BFCFE100EB0071 /* Curve.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DCD147D8FF50000361E /* Curve.h */; };
+		5B04C58F14BFCFE100EB0071 /* DebugNew.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DCF147D8FF50000361E /* DebugNew.h */; };
+		5B04C59014BFCFE100EB0071 /* DepthStencilTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DD1147D8FF50000361E /* DepthStencilTarget.h */; };
+		5B04C59114BFCFE100EB0071 /* Effect.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DD3147D8FF50000361E /* Effect.h */; };
+		5B04C59214BFCFE100EB0071 /* FileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DD5147D8FF50000361E /* FileSystem.h */; };
+		5B04C59314BFCFE100EB0071 /* Font.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DD7147D8FF50000361E /* Font.h */; };
+		5B04C59414BFCFE100EB0071 /* FrameBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DD9147D8FF50000361E /* FrameBuffer.h */; };
+		5B04C59514BFCFE100EB0071 /* Frustum.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DDB147D8FF50000361E /* Frustum.h */; };
+		5B04C59614BFCFE100EB0071 /* Game.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DDD147D8FF50000361E /* Game.h */; };
+		5B04C59714BFCFE100EB0071 /* gameplay.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE1147D8FF50000361E /* gameplay.h */; };
+		5B04C59814BFCFE100EB0071 /* Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE5147D8FF50000361E /* Joint.h */; };
+		5B04C59914BFCFE100EB0071 /* Light.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE7147D8FF50000361E /* Light.h */; };
+		5B04C59A14BFCFE100EB0071 /* Material.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE9147D8FF50000361E /* Material.h */; };
+		5B04C59B14BFCFE100EB0071 /* MaterialParameter.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DEB147D8FF50000361E /* MaterialParameter.h */; };
+		5B04C59C14BFCFE100EB0071 /* Matrix.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DED147D8FF50000361E /* Matrix.h */; };
+		5B04C59D14BFCFE100EB0071 /* Mesh.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF0147D8FF50000361E /* Mesh.h */; };
+		5B04C59E14BFCFE100EB0071 /* MeshPart.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF2147D8FF50000361E /* MeshPart.h */; };
+		5B04C59F14BFCFE100EB0071 /* MeshSkin.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF4147D8FF50000361E /* MeshSkin.h */; };
+		5B04C5A014BFCFE100EB0071 /* Model.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF6147D8FF50000361E /* Model.h */; };
+		5B04C5A114BFCFE100EB0071 /* Node.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF8147D8FF50000361E /* Node.h */; };
+		5B04C5A214BFCFE100EB0071 /* Package.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFA147D8FF50000361E /* Package.h */; };
+		5B04C5A314BFCFE100EB0071 /* ParticleEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFC147D8FF50000361E /* ParticleEmitter.h */; };
+		5B04C5A414BFCFE100EB0071 /* Pass.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFE147D8FF50000361E /* Pass.h */; };
+		5B04C5A514BFCFE100EB0071 /* PhysicsConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E00147D8FF50000361E /* PhysicsConstraint.h */; };
+		5B04C5A614BFCFE100EB0071 /* PhysicsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E03147D8FF50000361E /* PhysicsController.h */; };
+		5B04C5A714BFCFE100EB0071 /* PhysicsFixedConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E05147D8FF50000361E /* PhysicsFixedConstraint.h */; };
+		5B04C5A814BFCFE100EB0071 /* PhysicsGenericConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E08147D8FF50000361E /* PhysicsGenericConstraint.h */; };
+		5B04C5A914BFCFE100EB0071 /* PhysicsHingeConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E0B147D8FF50000361E /* PhysicsHingeConstraint.h */; };
+		5B04C5AA14BFCFE100EB0071 /* PhysicsMotionState.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E0D147D8FF50000361E /* PhysicsMotionState.h */; };
+		5B04C5AB14BFCFE100EB0071 /* PhysicsRigidBody.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E0F147D8FF50000361E /* PhysicsRigidBody.h */; };
+		5B04C5AC14BFCFE100EB0071 /* PhysicsSocketConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E12147D8FF50000361E /* PhysicsSocketConstraint.h */; };
+		5B04C5AD14BFCFE100EB0071 /* PhysicsSpringConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E14147D8FF50000361E /* PhysicsSpringConstraint.h */; };
+		5B04C5AE14BFCFE100EB0071 /* Plane.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E17147D8FF50000361E /* Plane.h */; };
+		5B04C5AF14BFCFE100EB0071 /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E19147D8FF50000361E /* Platform.h */; };
+		5B04C5B014BFCFE100EB0071 /* Properties.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E1E147D8FF50000361E /* Properties.h */; };
+		5B04C5B114BFCFE100EB0071 /* Quaternion.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E20147D8FF50000361E /* Quaternion.h */; };
+		5B04C5B214BFCFE100EB0071 /* Ray.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E23147D8FF50000361E /* Ray.h */; };
+		5B04C5B314BFCFE100EB0071 /* Rectangle.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E26147D8FF50000361E /* Rectangle.h */; };
+		5B04C5B414BFCFE100EB0071 /* Ref.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E28147D8FF50000361E /* Ref.h */; };
+		5B04C5B514BFCFE100EB0071 /* RenderState.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E2A147D8FF50000361E /* RenderState.h */; };
+		5B04C5B614BFCFE100EB0071 /* RenderTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E2C147D8FF50000361E /* RenderTarget.h */; };
+		5B04C5B714BFCFE100EB0071 /* Scene.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E2E147D8FF50000361E /* Scene.h */; };
+		5B04C5B814BFCFE100EB0071 /* SpriteBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E30147D8FF50000361E /* SpriteBatch.h */; };
+		5B04C5B914BFCFE100EB0071 /* Technique.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E32147D8FF50000361E /* Technique.h */; };
+		5B04C5BA14BFCFE100EB0071 /* Texture.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E34147D8FF50000361E /* Texture.h */; };
+		5B04C5BB14BFCFE100EB0071 /* Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E36147D8FF50000361E /* Transform.h */; };
+		5B04C5BC14BFCFE100EB0071 /* Vector2.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E38147D8FF50000361E /* Vector2.h */; };
+		5B04C5BD14BFCFE100EB0071 /* Vector3.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E3B147D8FF50000361E /* Vector3.h */; };
+		5B04C5BE14BFCFE100EB0071 /* Vector4.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E3E147D8FF50000361E /* Vector4.h */; };
+		5B04C5BF14BFCFE100EB0071 /* VertexAttributeBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */; };
+		5B04C5C014BFCFE100EB0071 /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
+		5B04C5C114BFCFE100EB0071 /* Viewport.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E45147D8FF50000361E /* Viewport.h */; };
+		5B04C5C214BFCFE100EB0071 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
+		5B04C5C314BFCFE100EB0071 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEE714A4079F00D3C511 /* Image.h */; };
+		5B04C5C414BFCFE100EB0071 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
+		5B04C5C514BFCFE100EB0071 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
+		5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4201818E14A41B18008C3F56 /* MeshBatch.h */; };
+		5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */; };
+		5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */; };
+		5B04C5F614BFE50100EB0071 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F514BFE50100EB0071 /* UIKit.framework */; };
+		5B04C5F814BFE50B00EB0071 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */; };
+		5B04C5FA14BFE51100EB0071 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F914BFE51000EB0071 /* OpenGLES.framework */; };
+		5B04C5FC14BFE51600EB0071 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5FB14BFE51600EB0071 /* OpenAL.framework */; };
+		5B5ADCE314C22DF900AC6109 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADCE214C22DF900AC6109 /* libz.dylib */; };
+		5B5ADCE514C22E1F00AC6109 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADCE414C22E1F00AC6109 /* libz.dylib */; };
+		5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADD2E14C2439700AC6109 /* Foundation.framework */; };
+		5BB0823D14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
+		5BB0823E14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
+		5BD776FD14C77E1F001CADA0 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -179,7 +327,6 @@
 		4299EFA8146AC94300FF4A73 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenGL.framework; sourceTree = DEVELOPER_DIR; };
 		4299EFAA146AC94B00FF4A73 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
 		42C932AF14919FD10098216A /* Game.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Game.inl; path = src/Game.inl; sourceTree = SOURCE_ROOT; };
-		42CCD553146EC1DD00353661 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.7.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
 		42CCD555146EC1EB00353661 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
 		42CD0DA6147D8EA80000361E /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/macos/libbullet.a"; sourceTree = "<group>"; };
 		42CD0DA7147D8EA80000361E /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "../external-deps/oggvorbis/lib/macos/libogg.a"; sourceTree = "<group>"; };
@@ -333,6 +480,27 @@
 		42CD0E43147D8FF50000361E /* VertexFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexFormat.h; path = src/VertexFormat.h; sourceTree = SOURCE_ROOT; };
 		42CD0E44147D8FF50000361E /* Viewport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Viewport.cpp; path = src/Viewport.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0E45147D8FF50000361E /* Viewport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Viewport.h; path = src/Viewport.h; sourceTree = SOURCE_ROOT; };
+		5B04C5CA14BFCFE100EB0071 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
+		5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformiOS.mm; path = src/PlatformiOS.mm; sourceTree = SOURCE_ROOT; };
+		5B04C5F514BFE50100EB0071 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
+		5B04C5F914BFE51000EB0071 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
+		5B04C5FB14BFE51600EB0071 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		5B43D17914C3497B008A5D9D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
+		5B5ADCE214C22DF900AC6109 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.7.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+		5B5ADCE414C22E1F00AC6109 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+		5B5ADD2E14C2439700AC6109 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5B5DB92D14C25B7B007755DB /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/ios/i386/libbullet.a"; sourceTree = "<group>"; };
+		5B5DB92F14C25B94007755DB /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/ios/armv7/libpng.a"; sourceTree = "<group>"; };
+		5B5DB93114C25BA5007755DB /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libogg.a"; sourceTree = "<group>"; };
+		5B5DB93214C25BA5007755DB /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libvorbis.a"; sourceTree = "<group>"; };
+		5B5DB93314C25BA5007755DB /* libvorbisenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisenc.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libvorbisenc.a"; sourceTree = "<group>"; };
+		5B5DB93414C25BA5007755DB /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libvorbisfile.a"; sourceTree = "<group>"; };
+		5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gameplay-main-android.cpp"; path = "src/gameplay-main-android.cpp"; sourceTree = SOURCE_ROOT; };
+		5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformAndroid.cpp; path = src/PlatformAndroid.cpp; sourceTree = SOURCE_ROOT; };
+		5BB0823C14C6FEC40019975F /* Mouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mouse.h; path = src/Mouse.h; sourceTree = SOURCE_ROOT; };
+		5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -340,13 +508,13 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				5B5ADCE314C22DF900AC6109 /* libz.dylib in Frameworks */,
 				42CD0DAB147D8EA80000361E /* libbullet.a in Frameworks */,
 				42CD0DAC147D8EA80000361E /* libogg.a in Frameworks */,
 				42CD0DAD147D8EA80000361E /* libvorbis.a in Frameworks */,
 				42CD0DAE147D8EA80000361E /* libvorbisenc.a in Frameworks */,
 				42CD0DAF147D8EA80000361E /* libvorbisfile.a in Frameworks */,
 				42CCD556146EC1EB00353661 /* libpng.a in Frameworks */,
-				42CCD554146EC1DD00353661 /* libz.dylib in Frameworks */,
 				4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */,
 				4220A6E8146B122B00CAEB3A /* QuartzCore.framework in Frameworks */,
 				4299EFA9146AC94300FF4A73 /* OpenGL.framework in Frameworks */,
@@ -354,6 +522,26 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B04C57414BFCFE100EB0071 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5BD776FD14C77E1F001CADA0 /* CoreMotion.framework in Frameworks */,
+				5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */,
+				5B5ADCE514C22E1F00AC6109 /* libz.dylib in Frameworks */,
+				5B04C5FC14BFE51600EB0071 /* OpenAL.framework in Frameworks */,
+				5B04C5FA14BFE51100EB0071 /* OpenGLES.framework in Frameworks */,
+				5B04C5F814BFE50B00EB0071 /* QuartzCore.framework in Frameworks */,
+				5B04C5F614BFE50100EB0071 /* UIKit.framework in Frameworks */,
+				5B04C57514BFCFE100EB0071 /* libbullet.a in Frameworks */,
+				5B04C57614BFCFE100EB0071 /* libogg.a in Frameworks */,
+				5B04C57714BFCFE100EB0071 /* libvorbis.a in Frameworks */,
+				5B04C57814BFCFE100EB0071 /* libvorbisenc.a in Frameworks */,
+				5B04C57914BFCFE100EB0071 /* libvorbisfile.a in Frameworks */,
+				5B04C57A14BFCFE100EB0071 /* libpng.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
@@ -371,6 +559,7 @@
 			isa = PBXGroup;
 			children = (
 				4234D99A14686C52003031B3 /* libgameplay.a */,
+				5B04C5CA14BFCFE100EB0071 /* libgameplay.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -378,6 +567,84 @@
 		4234D9A314686C52003031B3 /* src */ = {
 			isa = PBXGroup;
 			children = (
+				5B43D19714C35347008A5D9D /* gameplay */,
+				5B43D19614C35344008A5D9D /* platform */,
+			);
+			name = src;
+			path = gameplay;
+			sourceTree = "<group>";
+		};
+		427D4F42147DC8DE0076760E /* Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				42CD0DA6147D8EA80000361E /* libbullet.a */,
+				42CD0DA7147D8EA80000361E /* libogg.a */,
+				42CD0DA8147D8EA80000361E /* libvorbis.a */,
+				42CD0DA9147D8EA80000361E /* libvorbisenc.a */,
+				42CD0DAA147D8EA80000361E /* libvorbisfile.a */,
+				42CCD555146EC1EB00353661 /* libpng.a */,
+				5B5ADCE114C22DC700AC6109 /* Mac OS X */,
+				5B5ADCE014C22DBE00AC6109 /* iOS */,
+			);
+			name = Libraries;
+			sourceTree = "<group>";
+		};
+		42CCD4AF146D811D00353661 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				5B04C5FE14BFE52F00EB0071 /* Mac OS X */,
+				5B04C5FD14BFE52300EB0071 /* iOS */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		5B04C5FD14BFE52300EB0071 /* iOS */ = {
+			isa = PBXGroup;
+			children = (
+				5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */,
+				5B43D17914C3497B008A5D9D /* CoreGraphics.framework */,
+				5B5ADD2E14C2439700AC6109 /* Foundation.framework */,
+				5B04C5FB14BFE51600EB0071 /* OpenAL.framework */,
+				5B04C5F914BFE51000EB0071 /* OpenGLES.framework */,
+				5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */,
+				5B04C5F514BFE50100EB0071 /* UIKit.framework */,
+			);
+			name = iOS;
+			sourceTree = "<group>";
+		};
+		5B04C5FE14BFE52F00EB0071 /* Mac OS X */ = {
+			isa = PBXGroup;
+			children = (
+				4234D99D14686C52003031B3 /* Cocoa.framework */,
+				4220A6E7146B122B00CAEB3A /* QuartzCore.framework */,
+				4299EFA8146AC94300FF4A73 /* OpenGL.framework */,
+				4299EFAA146AC94B00FF4A73 /* OpenAL.framework */,
+			);
+			name = "Mac OS X";
+			sourceTree = "<group>";
+		};
+		5B43D19614C35344008A5D9D /* platform */ = {
+			isa = PBXGroup;
+			children = (
+				5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */,
+				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
+				42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */,
+				5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */,
+				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
+				42CD0E19147D8FF50000361E /* Platform.h */,
+				5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */,
+				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
+				42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */,
+				5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */,
+				42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */,
+			);
+			name = platform;
+			sourceTree = "<group>";
+		};
+		5B43D19714C35347008A5D9D /* gameplay */ = {
+			isa = PBXGroup;
+			children = (
+				5BB0823C14C6FEC40019975F /* Mouse.h */,
 				42CD0DB1147D8FF50000361E /* Animation.cpp */,
 				42CD0DB2147D8FF50000361E /* Animation.h */,
 				42CD0DB3147D8FF50000361E /* AnimationClip.cpp */,
@@ -425,9 +692,6 @@
 				42CD0DDC147D8FF50000361E /* Game.cpp */,
 				42CD0DDD147D8FF50000361E /* Game.h */,
 				42C932AF14919FD10098216A /* Game.inl */,
-				42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */,
-				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
-				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
 				42CD0DE1147D8FF50000361E /* gameplay.h */,
 				4208DEE614A4079F00D3C511 /* Image.cpp */,
 				4208DEE714A4079F00D3C511 /* Image.h */,
@@ -489,10 +753,6 @@
 				42CD0E16147D8FF50000361E /* Plane.cpp */,
 				42CD0E17147D8FF50000361E /* Plane.h */,
 				42CD0E18147D8FF50000361E /* Plane.inl */,
-				42CD0E19147D8FF50000361E /* Platform.h */,
-				42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */,
-				42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */,
-				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
 				42CD0E1D147D8FF50000361E /* Properties.cpp */,
 				42CD0E1E147D8FF50000361E /* Properties.h */,
 				42CD0E1F147D8FF50000361E /* Quaternion.cpp */,
@@ -538,33 +798,29 @@
 				42CD0E44147D8FF50000361E /* Viewport.cpp */,
 				42CD0E45147D8FF50000361E /* Viewport.h */,
 			);
-			name = src;
-			path = gameplay;
+			name = gameplay;
 			sourceTree = "<group>";
 		};
-		427D4F42147DC8DE0076760E /* Libraries */ = {
+		5B5ADCE014C22DBE00AC6109 /* iOS */ = {
 			isa = PBXGroup;
 			children = (
-				42CD0DA6147D8EA80000361E /* libbullet.a */,
-				42CD0DA7147D8EA80000361E /* libogg.a */,
-				42CD0DA8147D8EA80000361E /* libvorbis.a */,
-				42CD0DA9147D8EA80000361E /* libvorbisenc.a */,
-				42CD0DAA147D8EA80000361E /* libvorbisfile.a */,
-				42CCD555146EC1EB00353661 /* libpng.a */,
-				42CCD553146EC1DD00353661 /* libz.dylib */,
+				5B5DB93114C25BA5007755DB /* libogg.a */,
+				5B5DB93214C25BA5007755DB /* libvorbis.a */,
+				5B5DB93314C25BA5007755DB /* libvorbisenc.a */,
+				5B5DB93414C25BA5007755DB /* libvorbisfile.a */,
+				5B5DB92F14C25B94007755DB /* libpng.a */,
+				5B5DB92D14C25B7B007755DB /* libbullet.a */,
+				5B5ADCE414C22E1F00AC6109 /* libz.dylib */,
 			);
-			name = Libraries;
+			name = iOS;
 			sourceTree = "<group>";
 		};
-		42CCD4AF146D811D00353661 /* Frameworks */ = {
+		5B5ADCE114C22DC700AC6109 /* Mac OS X */ = {
 			isa = PBXGroup;
 			children = (
-				4234D99D14686C52003031B3 /* Cocoa.framework */,
-				4220A6E7146B122B00CAEB3A /* QuartzCore.framework */,
-				4299EFA8146AC94300FF4A73 /* OpenGL.framework */,
-				4299EFAA146AC94B00FF4A73 /* OpenAL.framework */,
+				5B5ADCE214C22DF900AC6109 /* libz.dylib */,
 			);
-			name = Frameworks;
+			name = "Mac OS X";
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -644,15 +900,94 @@
 				4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */,
 				4208DEEE14A407D500D3C511 /* Touch.h in Headers */,
 				4201819114A41B18008C3F56 /* MeshBatch.h in Headers */,
+				5BB0823D14C6FEC40019975F /* Mouse.h in Headers */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		5B04C58014BFCFE100EB0071 /* Headers */ = {
+			isa = PBXHeadersBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B04C58114BFCFE100EB0071 /* Animation.h in Headers */,
+				5B04C58214BFCFE100EB0071 /* AnimationClip.h in Headers */,
+				5B04C58314BFCFE100EB0071 /* AnimationController.h in Headers */,
+				5B04C58414BFCFE100EB0071 /* AnimationTarget.h in Headers */,
+				5B04C58514BFCFE100EB0071 /* AnimationValue.h in Headers */,
+				5B04C58614BFCFE100EB0071 /* AudioBuffer.h in Headers */,
+				5B04C58714BFCFE100EB0071 /* AudioController.h in Headers */,
+				5B04C58814BFCFE100EB0071 /* AudioListener.h in Headers */,
+				5B04C58914BFCFE100EB0071 /* AudioSource.h in Headers */,
+				5B04C58A14BFCFE100EB0071 /* Base.h in Headers */,
+				5B04C58B14BFCFE100EB0071 /* BoundingBox.h in Headers */,
+				5B04C58C14BFCFE100EB0071 /* BoundingSphere.h in Headers */,
+				5B04C58D14BFCFE100EB0071 /* Camera.h in Headers */,
+				5B04C58E14BFCFE100EB0071 /* Curve.h in Headers */,
+				5B04C58F14BFCFE100EB0071 /* DebugNew.h in Headers */,
+				5B04C59014BFCFE100EB0071 /* DepthStencilTarget.h in Headers */,
+				5B04C59114BFCFE100EB0071 /* Effect.h in Headers */,
+				5B04C59214BFCFE100EB0071 /* FileSystem.h in Headers */,
+				5B04C59314BFCFE100EB0071 /* Font.h in Headers */,
+				5B04C59414BFCFE100EB0071 /* FrameBuffer.h in Headers */,
+				5B04C59514BFCFE100EB0071 /* Frustum.h in Headers */,
+				5B04C59614BFCFE100EB0071 /* Game.h in Headers */,
+				5B04C59714BFCFE100EB0071 /* gameplay.h in Headers */,
+				5B04C59814BFCFE100EB0071 /* Joint.h in Headers */,
+				5B04C59914BFCFE100EB0071 /* Light.h in Headers */,
+				5B04C59A14BFCFE100EB0071 /* Material.h in Headers */,
+				5B04C59B14BFCFE100EB0071 /* MaterialParameter.h in Headers */,
+				5B04C59C14BFCFE100EB0071 /* Matrix.h in Headers */,
+				5B04C59D14BFCFE100EB0071 /* Mesh.h in Headers */,
+				5B04C59E14BFCFE100EB0071 /* MeshPart.h in Headers */,
+				5B04C59F14BFCFE100EB0071 /* MeshSkin.h in Headers */,
+				5B04C5A014BFCFE100EB0071 /* Model.h in Headers */,
+				5B04C5A114BFCFE100EB0071 /* Node.h in Headers */,
+				5B04C5A214BFCFE100EB0071 /* Package.h in Headers */,
+				5B04C5A314BFCFE100EB0071 /* ParticleEmitter.h in Headers */,
+				5B04C5A414BFCFE100EB0071 /* Pass.h in Headers */,
+				5B04C5A514BFCFE100EB0071 /* PhysicsConstraint.h in Headers */,
+				5B04C5A614BFCFE100EB0071 /* PhysicsController.h in Headers */,
+				5B04C5A714BFCFE100EB0071 /* PhysicsFixedConstraint.h in Headers */,
+				5B04C5A814BFCFE100EB0071 /* PhysicsGenericConstraint.h in Headers */,
+				5B04C5A914BFCFE100EB0071 /* PhysicsHingeConstraint.h in Headers */,
+				5B04C5AA14BFCFE100EB0071 /* PhysicsMotionState.h in Headers */,
+				5B04C5AB14BFCFE100EB0071 /* PhysicsRigidBody.h in Headers */,
+				5B04C5AC14BFCFE100EB0071 /* PhysicsSocketConstraint.h in Headers */,
+				5B04C5AD14BFCFE100EB0071 /* PhysicsSpringConstraint.h in Headers */,
+				5B04C5AE14BFCFE100EB0071 /* Plane.h in Headers */,
+				5B04C5AF14BFCFE100EB0071 /* Platform.h in Headers */,
+				5B04C5B014BFCFE100EB0071 /* Properties.h in Headers */,
+				5B04C5B114BFCFE100EB0071 /* Quaternion.h in Headers */,
+				5B04C5B214BFCFE100EB0071 /* Ray.h in Headers */,
+				5B04C5B314BFCFE100EB0071 /* Rectangle.h in Headers */,
+				5B04C5B414BFCFE100EB0071 /* Ref.h in Headers */,
+				5B04C5B514BFCFE100EB0071 /* RenderState.h in Headers */,
+				5B04C5B614BFCFE100EB0071 /* RenderTarget.h in Headers */,
+				5B04C5B714BFCFE100EB0071 /* Scene.h in Headers */,
+				5B04C5B814BFCFE100EB0071 /* SpriteBatch.h in Headers */,
+				5B04C5B914BFCFE100EB0071 /* Technique.h in Headers */,
+				5B04C5BA14BFCFE100EB0071 /* Texture.h in Headers */,
+				5B04C5BB14BFCFE100EB0071 /* Transform.h in Headers */,
+				5B04C5BC14BFCFE100EB0071 /* Vector2.h in Headers */,
+				5B04C5BD14BFCFE100EB0071 /* Vector3.h in Headers */,
+				5B04C5BE14BFCFE100EB0071 /* Vector4.h in Headers */,
+				5B04C5BF14BFCFE100EB0071 /* VertexAttributeBinding.h in Headers */,
+				5B04C5C014BFCFE100EB0071 /* VertexFormat.h in Headers */,
+				5B04C5C114BFCFE100EB0071 /* Viewport.h in Headers */,
+				5B04C5C214BFCFE100EB0071 /* SceneLoader.h in Headers */,
+				5B04C5C314BFCFE100EB0071 /* Image.h in Headers */,
+				5B04C5C414BFCFE100EB0071 /* Keyboard.h in Headers */,
+				5B04C5C514BFCFE100EB0071 /* Touch.h in Headers */,
+				5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */,
+				5BB0823E14C6FEC40019975F /* Mouse.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
-		4234D99914686C52003031B3 /* gameplay */ = {
+		4234D99914686C52003031B3 /* gameplay-macos */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay" */;
+			buildConfigurationList = 4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay-macos" */;
 			buildPhases = (
 				4234D99614686C52003031B3 /* Sources */,
 				4234D99714686C52003031B3 /* Frameworks */,
@@ -662,11 +997,28 @@
 			);
 			dependencies = (
 			);
-			name = gameplay;
+			name = "gameplay-macos";
 			productName = gameplay;
 			productReference = 4234D99A14686C52003031B3 /* libgameplay.a */;
 			productType = "com.apple.product-type.library.static";
 		};
+		5B04C52B14BFCFE100EB0071 /* gameplay-ios */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 5B04C5C714BFCFE100EB0071 /* Build configuration list for PBXNativeTarget "gameplay-ios" */;
+			buildPhases = (
+				5B04C52C14BFCFE100EB0071 /* Sources */,
+				5B04C57414BFCFE100EB0071 /* Frameworks */,
+				5B04C58014BFCFE100EB0071 /* Headers */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "gameplay-ios";
+			productName = gameplay;
+			productReference = 5B04C5CA14BFCFE100EB0071 /* libgameplay.a */;
+			productType = "com.apple.product-type.library.static";
+		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
@@ -687,7 +1039,8 @@
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				4234D99914686C52003031B3 /* gameplay */,
+				4234D99914686C52003031B3 /* gameplay-macos */,
+				5B04C52B14BFCFE100EB0071 /* gameplay-ios */,
 			);
 		};
 /* End PBXProject section */
@@ -719,8 +1072,6 @@
 				42CD0E6D147D8FF60000361E /* Frustum.cpp in Sources */,
 				42CD0E6F147D8FF60000361E /* Game.cpp in Sources */,
 				42CD0E71147D8FF60000361E /* gameplay-main-macos.mm in Sources */,
-				42CD0E72147D8FF60000361E /* gameplay-main-qnx.cpp in Sources */,
-				42CD0E73147D8FF60000361E /* gameplay-main-win32.cpp in Sources */,
 				42CD0E77147D8FF60000361E /* Joint.cpp in Sources */,
 				42CD0E79147D8FF60000361E /* Light.cpp in Sources */,
 				42CD0E7B147D8FF60000361E /* Material.cpp in Sources */,
@@ -745,8 +1096,6 @@
 				42CD0EA1147D8FF60000361E /* PhysicsSpringConstraint.cpp in Sources */,
 				42CD0EA3147D8FF60000361E /* Plane.cpp in Sources */,
 				42CD0EA6147D8FF60000361E /* PlatformMacOS.mm in Sources */,
-				42CD0EA7147D8FF60000361E /* PlatformQNX.cpp in Sources */,
-				42CD0EA8147D8FF60000361E /* PlatformWin32.cpp in Sources */,
 				42CD0EA9147D8FF60000361E /* Properties.cpp in Sources */,
 				42CD0EAB147D8FF60000361E /* Quaternion.cpp in Sources */,
 				42CD0EAD147D8FF60000361E /* Ray.cpp in Sources */,
@@ -771,18 +1120,96 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B04C52C14BFCFE100EB0071 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B04C52D14BFCFE100EB0071 /* Animation.cpp in Sources */,
+				5B04C52E14BFCFE100EB0071 /* AnimationClip.cpp in Sources */,
+				5B04C52F14BFCFE100EB0071 /* AnimationController.cpp in Sources */,
+				5B04C53014BFCFE100EB0071 /* AnimationTarget.cpp in Sources */,
+				5B04C53114BFCFE100EB0071 /* AnimationValue.cpp in Sources */,
+				5B04C53214BFCFE100EB0071 /* AudioBuffer.cpp in Sources */,
+				5B04C53314BFCFE100EB0071 /* AudioController.cpp in Sources */,
+				5B04C53414BFCFE100EB0071 /* AudioListener.cpp in Sources */,
+				5B04C53514BFCFE100EB0071 /* AudioSource.cpp in Sources */,
+				5B04C53614BFCFE100EB0071 /* BoundingBox.cpp in Sources */,
+				5B04C53714BFCFE100EB0071 /* BoundingSphere.cpp in Sources */,
+				5B04C53814BFCFE100EB0071 /* Camera.cpp in Sources */,
+				5B04C53914BFCFE100EB0071 /* Curve.cpp in Sources */,
+				5B04C53A14BFCFE100EB0071 /* DebugNew.cpp in Sources */,
+				5B04C53B14BFCFE100EB0071 /* DepthStencilTarget.cpp in Sources */,
+				5B04C53C14BFCFE100EB0071 /* Effect.cpp in Sources */,
+				5B04C53D14BFCFE100EB0071 /* FileSystem.cpp in Sources */,
+				5B04C53E14BFCFE100EB0071 /* Font.cpp in Sources */,
+				5B04C53F14BFCFE100EB0071 /* FrameBuffer.cpp in Sources */,
+				5B04C54014BFCFE100EB0071 /* Frustum.cpp in Sources */,
+				5B04C54114BFCFE100EB0071 /* Game.cpp in Sources */,
+				5B04C54514BFCFE100EB0071 /* Joint.cpp in Sources */,
+				5B04C54614BFCFE100EB0071 /* Light.cpp in Sources */,
+				5B04C54714BFCFE100EB0071 /* Material.cpp in Sources */,
+				5B04C54814BFCFE100EB0071 /* MaterialParameter.cpp in Sources */,
+				5B04C54914BFCFE100EB0071 /* Matrix.cpp in Sources */,
+				5B04C54A14BFCFE100EB0071 /* Mesh.cpp in Sources */,
+				5B04C54B14BFCFE100EB0071 /* MeshPart.cpp in Sources */,
+				5B04C54C14BFCFE100EB0071 /* MeshSkin.cpp in Sources */,
+				5B04C54D14BFCFE100EB0071 /* Model.cpp in Sources */,
+				5B04C54E14BFCFE100EB0071 /* Node.cpp in Sources */,
+				5B04C54F14BFCFE100EB0071 /* Package.cpp in Sources */,
+				5B04C55014BFCFE100EB0071 /* ParticleEmitter.cpp in Sources */,
+				5B04C55114BFCFE100EB0071 /* Pass.cpp in Sources */,
+				5B04C55214BFCFE100EB0071 /* PhysicsConstraint.cpp in Sources */,
+				5B04C55314BFCFE100EB0071 /* PhysicsController.cpp in Sources */,
+				5B04C55414BFCFE100EB0071 /* PhysicsFixedConstraint.cpp in Sources */,
+				5B04C55514BFCFE100EB0071 /* PhysicsGenericConstraint.cpp in Sources */,
+				5B04C55614BFCFE100EB0071 /* PhysicsHingeConstraint.cpp in Sources */,
+				5B04C55714BFCFE100EB0071 /* PhysicsMotionState.cpp in Sources */,
+				5B04C55814BFCFE100EB0071 /* PhysicsRigidBody.cpp in Sources */,
+				5B04C55914BFCFE100EB0071 /* PhysicsSocketConstraint.cpp in Sources */,
+				5B04C55A14BFCFE100EB0071 /* PhysicsSpringConstraint.cpp in Sources */,
+				5B04C55B14BFCFE100EB0071 /* Plane.cpp in Sources */,
+				5B04C55F14BFCFE100EB0071 /* Properties.cpp in Sources */,
+				5B04C56014BFCFE100EB0071 /* Quaternion.cpp in Sources */,
+				5B04C56114BFCFE100EB0071 /* Ray.cpp in Sources */,
+				5B04C56214BFCFE100EB0071 /* Rectangle.cpp in Sources */,
+				5B04C56314BFCFE100EB0071 /* Ref.cpp in Sources */,
+				5B04C56414BFCFE100EB0071 /* RenderState.cpp in Sources */,
+				5B04C56514BFCFE100EB0071 /* RenderTarget.cpp in Sources */,
+				5B04C56614BFCFE100EB0071 /* Scene.cpp in Sources */,
+				5B04C56714BFCFE100EB0071 /* SpriteBatch.cpp in Sources */,
+				5B04C56814BFCFE100EB0071 /* Technique.cpp in Sources */,
+				5B04C56914BFCFE100EB0071 /* Texture.cpp in Sources */,
+				5B04C56A14BFCFE100EB0071 /* Transform.cpp in Sources */,
+				5B04C56B14BFCFE100EB0071 /* Vector2.cpp in Sources */,
+				5B04C56C14BFCFE100EB0071 /* Vector3.cpp in Sources */,
+				5B04C56D14BFCFE100EB0071 /* Vector4.cpp in Sources */,
+				5B04C56E14BFCFE100EB0071 /* VertexAttributeBinding.cpp in Sources */,
+				5B04C56F14BFCFE100EB0071 /* VertexFormat.cpp in Sources */,
+				5B04C57014BFCFE100EB0071 /* Viewport.cpp in Sources */,
+				5B04C57114BFCFE100EB0071 /* SceneLoader.cpp in Sources */,
+				5B04C57214BFCFE100EB0071 /* Image.cpp in Sources */,
+				5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */,
+				5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */,
+				5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
 		4234D99114686BB6003031B3 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
+				VALID_ARCHS = "armv7 armv6 i386 x86_64";
 			};
 			name = Debug;
 		};
 		4234D99214686BB6003031B3 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
+				VALID_ARCHS = "armv7 armv6 i386 x86_64";
 			};
 			name = Release;
 		};
@@ -790,7 +1217,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				COPY_PHASE_STRIP = NO;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -823,12 +1250,14 @@
 					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/macos\"",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
-				ONLY_ACTIVE_ARCH = YES;
+				ONLY_ACTIVE_ARCH = NO;
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
-				PRODUCT_NAME = "$(TARGET_NAME)";
+				PRODUCT_NAME = gameplay;
 				SDKROOT = macosx;
 				SHARED_PRECOMPS_DIR = "";
+				SUPPORTED_PLATFORMS = macosx;
 				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "i386 x86_64";
 			};
 			name = Debug;
 		};
@@ -836,7 +1265,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				COPY_PHASE_STRIP = YES;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@@ -864,10 +1293,105 @@
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
-				PRODUCT_NAME = "$(TARGET_NAME)";
+				PRODUCT_NAME = gameplay;
 				SDKROOT = macosx;
 				SHARED_PRECOMPS_DIR = "";
+				SUPPORTED_PLATFORMS = macosx;
+				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "i386 x86_64";
+			};
+			name = Release;
+		};
+		5B04C5C814BFCFE100EB0071 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PRECOMPILE_PREFIX_HEADER = NO;
+				GCC_PREFIX_HEADER = "";
+				GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
+				GCC_WARN_MISSING_PARENTHESES = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					"../external-deps/libpng/include",
+					"../external-deps/bullet/include",
+					"../external-deps/oggvorbis/include",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)/../external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
+					"\"$(SRCROOT)/../external-deps/bullet/lib/ios/$(CURRENT_ARCH)\"",
+					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/ios/$(CURRENT_ARCH)\"",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				ONLY_ACTIVE_ARCH = YES;
+				OTHER_LDFLAGS = "-ObjC";
+				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
+				PRODUCT_NAME = gameplay;
+				PROVISIONING_PROFILE = "";
+				SDKROOT = iphoneos;
+				SHARED_PRECOMPS_DIR = "";
+				SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "armv7 armv6";
+			};
+			name = Debug;
+		};
+		5B04C5C914BFCFE100EB0071 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_PRECOMPILE_PREFIX_HEADER = NO;
+				GCC_PREFIX_HEADER = "";
+				GCC_PREPROCESSOR_DEFINITIONS = "";
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
+				GCC_WARN_MISSING_PARENTHESES = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					"../external-deps/libpng/include",
+					"../external-deps/bullet/include",
+					"../external-deps/oggvorbis/include",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"$(SRCROOT)/../external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
+					"\"$(SRCROOT)/../external-deps/bullet/lib/ios/$(CURRENT_ARCH)\"",
+					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/ios/$(CURRENT_ARCH)\"",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				OTHER_LDFLAGS = "-ObjC";
+				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
+				PRODUCT_NAME = gameplay;
+				PROVISIONING_PROFILE = "";
+				SDKROOT = iphoneos;
+				SHARED_PRECOMPS_DIR = "";
+				SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
 				USER_HEADER_SEARCH_PATHS = "";
+				VALID_ARCHS = "armv7 armv6";
 			};
 			name = Release;
 		};
@@ -883,7 +1407,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay" */ = {
+		4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay-macos" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				4234D9A914686C52003031B3 /* Debug */,
@@ -892,6 +1416,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		5B04C5C714BFCFE100EB0071 /* Build configuration list for PBXNativeTarget "gameplay-ios" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				5B04C5C814BFCFE100EB0071 /* Debug */,
+				5B04C5C914BFCFE100EB0071 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
 	};
 	rootObject = 4234D98C14686BB6003031B3 /* Project object */;

+ 57 - 0
gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-MacOSX.xcscheme

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "4234D99914686C52003031B3"
+               BuildableName = "libgameplay.a"
+               BlueprintName = "gameplay-macos"
+               ReferencedContainer = "container:gameplay.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 57 - 0
gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-iOS.xcscheme

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5B04C52B14BFCFE100EB0071"
+               BuildableName = "libgameplay.a"
+               BlueprintName = "gameplay-ios"
+               ReferencedContainer = "container:gameplay.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 4 - 2
gameplay/src/Animation.cpp

@@ -31,7 +31,8 @@ Animation::~Animation()
 {
     if (_defaultClip)
     {
-        _defaultClip->stop();
+        if (_defaultClip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+            _controller->unschedule(_defaultClip);
         SAFE_RELEASE(_defaultClip);
     }
 
@@ -42,7 +43,8 @@ Animation::~Animation()
         while (clipIter != _clips->end())
         {   
             AnimationClip* clip = *clipIter;
-            clip->stop();
+            if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+                _controller->unschedule(clip);
             SAFE_RELEASE(clip);
             clipIter++;
         }

+ 225 - 227
gameplay/src/AnimationClip.cpp

@@ -9,10 +9,10 @@ namespace gameplay
 {
 
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
-    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), _repeatCount(1.0f), 
-      _activeDuration(_duration * _repeatCount), _speed(1.0f), _isPlaying(false), _timeStarted(0), _elapsedTime(0), _runningTime(0), 
-      _crossFadeToClip(NULL), _crossFadeStart(0), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
-      _isFadingOutStarted(false), _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL)
+    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), 
+      _stateBits(0x00), _repeatCount(1.0f), _activeDuration(_duration * _repeatCount), _speed(1.0f), _timeStarted(0), 
+      _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL)
 {
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     
@@ -36,6 +36,29 @@ AnimationClip::~AnimationClip()
     SAFE_RELEASE(_crossFadeToClip);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
+
+    if (_listeners)
+    {
+        *_listenerItr = _listeners->begin();
+        while (*_listenerItr != _listeners->end())
+        {
+            ListenerEvent* lEvt = **_listenerItr;
+            SAFE_DELETE(lEvt);
+            ++*_listenerItr;
+        }
+        SAFE_DELETE(_listeners);
+    }
+    SAFE_DELETE(_listenerItr);
+}
+
+AnimationClip::ListenerEvent::ListenerEvent(Listener* listener, unsigned long eventTime)
+{
+    _listener = listener;
+    _eventTime = eventTime;
+}
+
+AnimationClip::ListenerEvent::~ListenerEvent()
+{
 }
 
 const char* AnimationClip::getID() const
@@ -106,6 +129,11 @@ unsigned long AnimationClip::getActiveDuration() const
     return _activeDuration;
 }
 
+unsigned long AnimationClip::getDuration() const
+{
+    return _duration;
+}
+
 void AnimationClip::setSpeed(float speed)
 {
     _speed = speed;
@@ -128,22 +156,39 @@ float AnimationClip::getBlendWeight() const
 
 bool AnimationClip::isPlaying() const
 {
-    return _isPlaying;
+    return isClipStateBitSet(CLIP_IS_PLAYING_BIT);
 }
 
 void AnimationClip::play()
 {
-    _animation->_controller->schedule(this);
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+    {
+        // If the clip is set to be removed, reset the flag.
+        if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+            resetClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
+
+        // Set the state bit to restart.
+        setClipStateBit(CLIP_IS_RESTARTED_BIT);
+    }
+    else
+    {
+        setClipStateBit(CLIP_IS_PLAYING_BIT);
+        _animation->_controller->schedule(this);
+    }
+    
     _timeStarted = Game::getGameTime();
 }
 
 void AnimationClip::stop()
 {
-    _animation->_controller->unschedule(this);
-    if (_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
     {
-        _isPlaying = false;
-        onEnd();
+        // If the clip was slated to be restarted, reset this flag.
+        if (isClipStateBitSet(CLIP_IS_RESTARTED_BIT))
+            resetClipStateBit(CLIP_IS_RESTARTED_BIT);
+
+        // Mark the clip to removed from the AnimationController.
+        setClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
     }
 }
 
@@ -151,37 +196,83 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 {
     assert(clip);
 
-    if (clip->_isPlaying && clip->_isFadingOut)
+    // Check if the given clip is fading into this clip.
+    // We should reset the clip from fading out, and this one from fading in 
+    // in order to start the crossfade back the other way.
+    if (clip->isClipStateBitSet(CLIP_IS_FADING_OUT_BIT) && clip->_crossFadeToClip == this)
     {
-        clip->_isFadingOut = false;
-        clip->_crossFadeToClip->_isFadingIn = false;
+        clip->resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+        clip->_crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
         SAFE_RELEASE(clip->_crossFadeToClip);
     }
 
-    // If I already have a clip I'm fading too.. release it.
+    // If I already have a clip I'm fading to and it's not the same as the given clip release it.
+    // Assign the new clip and increase it's ref count.
     if (_crossFadeToClip)
+    {
         SAFE_RELEASE(_crossFadeToClip);
+    }
 
-    // Assign the clip we're fading to, and increase its ref count.
+    // Set and initialize the crossfade clip
     _crossFadeToClip = clip;
     _crossFadeToClip->addRef();
-        
-    // Set the fade in clip to fading in, and set the duration of the fade in.
-    _crossFadeToClip->_isFadingIn = true;
+    _crossFadeToClip->setClipStateBit(CLIP_IS_FADING_IN_BIT);
+    _crossFadeToClip->_blendWeight = 0.0f;
     
-    // Set this clip to fade out, and reset the elapsed time for the fade out.
-    _isFadingOut = true;
-    _crossFadeOutElapsed = 0;
+    // Set and intiliaze this clip to fade out
+    setClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
+    setClipStateBit(CLIP_IS_FADING_OUT_BIT);
+    _crossFadeOutElapsed = 0L;
     _crossFadeOutDuration = duration;
-    _crossFadeStart = (Game::getGameTime() - _timeStarted);
-    _isFadingOutStarted = true;
     
-    if (!_isPlaying)
+    // If this clip is currently not playing, we should start playing it.
+    if (!isClipStateBitSet(CLIP_IS_PLAYING_BIT))
         play();
 
+    // Start playing the cross fade clip.
     _crossFadeToClip->play(); 
 }
 
+void AnimationClip::addListener(AnimationClip::Listener* listener, unsigned long eventTime)
+{
+    assert(listener);
+    assert(eventTime < _activeDuration);
+
+    ListenerEvent* listenerEvent = new ListenerEvent(listener, eventTime);
+
+    if (!_listeners)
+    {
+        _listeners = new std::list<ListenerEvent*>;
+        _listeners->push_front(listenerEvent);
+
+        _listenerItr = new std::list<ListenerEvent*>::iterator;
+        if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+            *_listenerItr = _listeners->begin();
+    }
+    else
+    {
+        for (std::list<ListenerEvent*>::iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
+        {
+            if (eventTime < (*itr)->_eventTime)
+            {
+                itr = _listeners->insert(itr, listenerEvent);
+
+                // If playing, update the iterator if we need to.
+                // otherwise, it will just be set the next time the clip gets played.
+                if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+                {
+                    unsigned long currentTime = _elapsedTime % _duration;
+                    if ((_speed >= 0.0f && currentTime < eventTime && (*_listenerItr == _listeners->end() || eventTime < (**_listenerItr)->_eventTime)) || 
+                        (_speed <= 0 && currentTime > eventTime && (*_listenerItr == _listeners->begin() || eventTime > (**_listenerItr)->_eventTime)))
+                        *_listenerItr = itr;
+                }
+                return;
+            }
+        }
+        _listeners->push_back(listenerEvent);
+    }
+}
+
 void AnimationClip::addBeginListener(AnimationClip::Listener* listener)
 {
     if (!_beginListeners)
@@ -198,89 +289,123 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
     _endListeners->push_back(listener);
 }
 
-bool AnimationClip::update(unsigned long elapsedTime)
+bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
 {
-    float speed = _speed;
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+    {   // If the marked for removal bit is set, it means stop() was called on the AnimationClip at some point
+        // after the last update call. Reset the flag, and return true so the AnimationClip is removed from the 
+        // running clips on the AnimationController.
+        onEnd();
+        return true;
+    }
+    else if (!isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
         onBegin();
-        _elapsedTime = Game::getGameTime() - _timeStarted;
-        _runningTime = _elapsedTime * speed;
     }
     else
     {
-        // Update elapsed time.
-        _elapsedTime += elapsedTime;
-        _runningTime += elapsedTime * speed;
-    }
+        _elapsedTime += elapsedTime * _speed;
 
-    float percentComplete = 0.0f;
+        if (_repeatCount == REPEAT_INDEFINITE && _elapsedTime <= 0)
+            _elapsedTime = _activeDuration + _elapsedTime;
+    }
 
+    unsigned long currentTime = 0L;
     // Check to see if clip is complete.
-    if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0 && _runningTime >= (long) _activeDuration) || (_speed < 0 && _runningTime <= 0)))
+    if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0.0f && _elapsedTime >= (long) _activeDuration) || (_speed <= 0.0f && _elapsedTime <= 0L)))
     {
-        _isPlaying = false;
-        if (_speed >= 0)
+        resetClipStateBit(CLIP_IS_STARTED_BIT);
+        if (_speed >= 0.0f)
         {
-            percentComplete = _activeDuration % _duration; // Get's the fractional part of the final repeat.
-            if (percentComplete == 0.0f)
-                percentComplete = _duration;
+            // If _duration == 0, we have a "pose". Just set currentTime to 0.
+            if (_duration == 0)
+            {
+                currentTime = 0L;
+            }
+            else
+            {
+                currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
+                if (currentTime == 0L)
+                    currentTime = _duration;
+            }
         }
         else
         {
-            percentComplete = 0.0f; // If we are negative speed, the end value should be 0.
+            currentTime = 0L; // If we are negative speed, the end value should be 0.
         }
     }
     else
     {
-        // Gets portion/fraction of the repeat.
-        percentComplete = (float) (_runningTime % _duration);
+        // If _duration == 0, we have a "pose". Just set currentTime to 0.
+        if (_duration == 0)
+            currentTime = 0L;
+        else // Gets portion/fraction of the repeat.
+            currentTime = _elapsedTime % _duration;
+    }
+
+    // Notify any listeners of Animation events.
+    if (_listeners)
+    {
+        if (_speed >= 0.0f)
+        {
+            while (*_listenerItr != _listeners->end() && _elapsedTime >= (long) (**_listenerItr)->_eventTime)
+            {
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
+                ++*_listenerItr;
+            }
+        }
+        else
+        {
+            while (*_listenerItr != _listeners->begin() && _elapsedTime <= (long) (**_listenerItr)->_eventTime)
+            {
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
+                --*_listenerItr;
+            }
+        }
     }
 
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
-    percentComplete = (float)(_startTime + percentComplete) / (float) _animation->_duration;
+    float percentComplete = (float)(_startTime + currentTime) / (float) _animation->_duration;
     
-    if (_isFadingOut)
+    if (isClipStateBitSet(CLIP_IS_FADING_OUT_BIT))
     {
-        if (_isFadingOutStarted) // Calculate elapsed time since the fade out begin.
+        if (isClipStateBitSet(CLIP_IS_FADING_OUT_STARTED_BIT)) // Calculate elapsed time since the fade out begin.
         {
-            _crossFadeOutElapsed = (_elapsedTime - _crossFadeStart) * speed;
-            _isFadingOutStarted = false;
+            _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * abs(_speed); 
+            resetClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
         }
         else
         {
             // continue tracking elapsed time.
-            _crossFadeOutElapsed += elapsedTime * speed;
+            _crossFadeOutElapsed += elapsedTime * abs(_speed);
         }
 
         if (_crossFadeOutElapsed < _crossFadeOutDuration)
         {
+            // Calculate this clip's blend weight.
             float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
-            _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight);
             
-            // adjust the clip your blending to's weight to be a percentage of your current blend weight
-            if (_isFadingIn)
+            // If this clip is fading in, adjust the crossfade clip's weight to be a percentage of your current blend weight
+            if (isClipStateBitSet(CLIP_IS_FADING_IN_BIT))
             {
-                _crossFadeToClip->_blendWeight *= _blendWeight;
+                _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
                 _blendWeight -= _crossFadeToClip->_blendWeight;
             }
             else
             {
+                // Just set the blend weight.
+                _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight);
                 _blendWeight = tempBlendWeight;
             }
         }
         else
-        {   // Fade done.
+        {   // Fade is done.
             _crossFadeToClip->_blendWeight = 1.0f;
-                
-            if (_isFadingIn)
-                _crossFadeToClip->_blendWeight *= _blendWeight;
-
-            _crossFadeToClip->_isFadingIn = false;
+            _blendWeight = 0.0f;
+            resetClipStateBit(CLIP_IS_STARTED_BIT);            
+            resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+            _crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
             SAFE_RELEASE(_crossFadeToClip);
-            _blendWeight = 0.0f; 
-            _isFadingOut = false;
-            _isPlaying = false;
         }
     }
     
@@ -295,172 +420,47 @@ bool AnimationClip::update(unsigned long elapsedTime)
         target = channel->_target;
         value = _values[i];
 
-        // Get the current value.
-        target->getAnimationPropertyValue(channel->_propertyId, value);
-
-        bool isHighest = false;
-        // My channel priority has changed if my priority is greater than the active animation count.
-        if (!target->_highestPriority)
-        {
-            target->_highestPriority = channel;
-            value->_isFirstActing = true;
-        }
-
-        if (_blendWeight != 0.0f)
-        {
-            // Evaluate point on Curve.
-            channel->_curve->evaluate(percentComplete, value->_interpolatedValue);
-
-            if (!channel->_curve->_quaternionOffset)
-            {
-                if (value->_isFirstActing)
-                {
-                    unsigned int componentCount = value->_componentCount;
-                    for (unsigned int j = 0; j < componentCount; j++)
-                    {
-                        if (_blendWeight != 1.0f)
-                            value->_interpolatedValue[j] *= _blendWeight;
-
-                        value->_currentValue[j] = value->_interpolatedValue[j];
-                    }
-                }
-                else
-                {
-                    unsigned int componentCount = value->_componentCount;
-                    for (unsigned int j = 0; j < componentCount; j++)
-                    {
-                        if (_blendWeight != 1.0f)
-                            value->_interpolatedValue[j] *= _blendWeight;
-
-                        value->_currentValue[j] += value->_interpolatedValue[j];
-                    }
-                }
-            }
-            else
-            {   //We have Quaternions!!!
-                unsigned int quaternionOffset = *(channel->_curve->_quaternionOffset);
-                
-                if (value->_isFirstActing)
-                {
-                    unsigned int j = 0;
-                    for (; j < quaternionOffset; j++)
-                    {
-                        if (_blendWeight != 1.0f)
-                            value->_interpolatedValue[j] *= _blendWeight;
-
-                        value->_currentValue[j] = value->_interpolatedValue[j];
-                    }
-
-                    // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
-                    Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
-                    Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
-
-                    // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
-                    if (_blendWeight != 1.0f)
-                        Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
-                    
-                    // Add in contribution.
-                    currentQuaternion->set(*interpolatedQuaternion);
-                    
-                    unsigned int componentCount = value->_componentCount;
-                    for (j += 4; j < componentCount; j++)
-                    {
-                        if (_blendWeight != 1.0f)
-                            value->_interpolatedValue[j] *= _blendWeight;
-
-                        value->_currentValue[j] = value->_interpolatedValue[j];
-                    }
-                }
-                else
-                {
-                    unsigned int j = 0;
-                    for (; j < quaternionOffset; j++)
-                    {
-                        if (_blendWeight != 1.0f)
-                            value->_interpolatedValue[j] *= _blendWeight;
-
-                        value->_currentValue[j] += value->_interpolatedValue[j];
-                    }
-                    // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
-
-                    Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
-                    Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
-
-                    // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
-                    if (_blendWeight != 1.0f)
-                        Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
-                    
-                    // Add in contribution.
-                    currentQuaternion->multiply(*interpolatedQuaternion);
-                    
-                    unsigned int componentCount = value->_componentCount;
-                    for (j += 4; j < componentCount; j++)
-                    {
-                        if (_blendWeight != 1.0f)
-                            value->_interpolatedValue[j] *= _blendWeight;
-
-                        value->_currentValue[j] += value->_interpolatedValue[j];
-                    }
-                }
-            }
-        }
-        else if (value->_isFirstActing)
-        {
-            if (!channel->_curve->_quaternionOffset)
-            {
-                memset(value->_currentValue, 0.0f, value->_componentCount);
-            }
-            else
-            {
-                unsigned int quaternionOffset = *(channel->_curve->_quaternionOffset);
-                unsigned int j = 0;
-                for (; j < quaternionOffset; j++)
-                {
-                    value->_currentValue[j] = 0.0f;
-                }
-
-                // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
-                Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+        // If the target's _animationPropertyBitFlag is clear, we can assume that this is the first
+        // animation channel to act on the target and we can add the target to the list of
+        // active targets stored by the AnimationController.
+        if (target->_animationPropertyBitFlag == 0x00)
+            activeTargets->push_front(target);
 
-                // Set it to identity.
-                currentQuaternion->setIdentity();
-                
-                unsigned int componentCount = value->_componentCount;
-                for (j += 4; j < componentCount; j++)
-                {
-                    value->_currentValue[j] = 0.0f;
-                }
-            }
-        }
-        
+        // Evaluate the point on Curve
+        channel->_curve->evaluate(percentComplete, value->_value);
         // Set the animation value on the target property.
-        target->setAnimationPropertyValue(channel->_propertyId, value);
+        target->setAnimationPropertyValue(channel->_propertyId, value, _blendWeight);
     }
 
     // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT) || !isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
         onEnd();
+        return true;
     }
 
-    return !_isPlaying;
+    return false;
 }
 
 void AnimationClip::onBegin()
 {
     // Initialize animation to play.
-    _isPlaying = true;
-    _elapsedTime = 0;
-
-    if (_speed > 0)
+    setClipStateBit(CLIP_IS_STARTED_BIT);
+    if (_speed >= 0)
     {
-        _runningTime = 0;
+        _elapsedTime = (Game::getGameTime() - _timeStarted) * _speed;
+
+        if (_listeners)
+            *_listenerItr = _listeners->begin(); 
     }
     else
     {
-        _runningTime = _activeDuration;
-    }
+        _elapsedTime = _activeDuration + (Game::getGameTime() - _timeStarted) * _speed;
 
+        if (_listeners)
+            *_listenerItr = _listeners->end();
+    }
+    
     // Notify begin listeners.. if any.
     if (_beginListeners)
     {
@@ -475,25 +475,8 @@ void AnimationClip::onBegin()
 
 void AnimationClip::onEnd()
 {
-    AnimationValue* value;
-    Animation::Channel* channel = NULL;
-    AnimationTarget* target = NULL;
-    unsigned int channelCount = _animation->_channels.size();
-    for (unsigned int i = 0; i < channelCount; i++)
-    {
-        value = _values[i];
-
-        if (value->_isFirstActing)
-        {
-            channel = _animation->_channels[i];
-            target = channel->_target;
-            target->_highestPriority = NULL;
-            value->_isFirstActing = false;
-        }
-    }
-
     _blendWeight = 1.0f;
-    _timeStarted = 0;
+    resetClipStateBit(CLIP_ALL_BITS);
 
     // Notify end listeners if any.
     if (_endListeners)
@@ -507,4 +490,19 @@ void AnimationClip::onEnd()
     }
 }
 
+bool AnimationClip::isClipStateBitSet(char bit) const
+{
+    return (_stateBits & bit) == bit;
+}
+
+void AnimationClip::setClipStateBit(char bit)
+{
+    _stateBits |= bit;
+}
+
+void AnimationClip::resetClipStateBit(char bit)
+{
+    _stateBits &= ~bit;
+}
+
 }

+ 100 - 29
gameplay/src/AnimationClip.h

@@ -32,13 +32,24 @@ public:
      */
     class Listener
     {
+        friend class AnimationClip;
+
     public:
 
+        Listener() 
+        {
+        }
+
         /**
          * The type of animation event.
          */
         enum EventType 
         {
+            /**
+             * Default event type.
+             */
+            DEFAULT,
+
             /**
              * Event fired when the clip begins.
              */
@@ -123,6 +134,13 @@ public:
      */
     unsigned long getActiveDuration() const;
 
+    /**
+     * Gets the AnimationClip's duration.
+     *
+     * @return the AnimationClip's duration.
+     */
+    unsigned long getDuration() const;
+
     /**
      * Set the AnimationClip's running speed. 
      *
@@ -177,20 +195,63 @@ public:
     void crossFade(AnimationClip* clip, unsigned long duration);
 
     /**
-     * Adds a animation begin listener.
+     * Adds an animation begin listener.
      *
-     * @param listener The listener to be called when an animation clip begins.
+     * @param listener The listener to be called when an AnimationClip begins.
      */
     void addBeginListener(AnimationClip::Listener* listener);
 
     /**
-     * Adds a animation end listener.
+     * Adds an animation end listener.
      *
-     * @param listener The listener to be called when an animation clip ends.
+     * @param listener The listener to be called when an AnimationClip ends.
      */
     void addEndListener(AnimationClip::Listener* listener);
 
+    /**
+     * Adds an animation listener to be called back at the specified eventTime during the playback 
+     * of the AnimationClip.
+     *
+     * @param listener The listener to be called when the AnimationClip reaches the 
+     *      specified time in its playback.
+     * @param eventTime The time the listener will be called during the playback of the AnimationClip. 
+     *      Must be between 0 and the duration of the AnimationClip.
+     */
+    void addListener(AnimationClip::Listener* listener, unsigned long eventTime);
+
 private:
+    /**
+     * State bits.
+     */
+    static const char CLIP_IS_PLAYING_BIT = 0x01;             // Bit representing whether AnimationClip is a running clip in AnimationController
+    static const char CLIP_IS_STARTED_BIT = 0x02;             // Bit representing whether the AnimationClip has actually been started (ie: received first call to update())
+    static const char CLIP_IS_FADING_OUT_STARTED_BIT = 0x04;  // Bit representing that a cross fade has started.
+    static const char CLIP_IS_FADING_OUT_BIT = 0x08;          // Bit representing whether the clip is fading out.
+    static const char CLIP_IS_FADING_IN_BIT = 0x10;           // Bit representing whether the clip is fading out.
+    static const char CLIP_IS_MARKED_FOR_REMOVAL_BIT = 0x20;  // Bit representing whether the clip has ended and should be removed from the AnimationController.
+    static const char CLIP_IS_RESTARTED_BIT = 0x40;           // Bit representing if the clip should be restarted by the AnimationController.
+    static const char CLIP_ALL_BITS = 0x7F;                   // Bit mask for all the state bits.
+
+    /**
+     * ListenerEvent.
+     *
+     * Internal structure used for storing the event time at which an AnimationClip::Listener should be called back.
+     */
+    struct ListenerEvent
+    {
+        /** 
+         * Constructor.
+         */
+        ListenerEvent(Listener* listener, unsigned long eventTime);
+
+        /**
+         * Destructor.
+         */
+        ~ListenerEvent();
+
+        Listener* _listener;        // This listener to call back when this event is triggered.
+        unsigned long _eventTime;   // The time at which the listener will be called back at during the playback of the AnimationClip.
+    };
 
     /**
      * Constructor.
@@ -215,7 +276,7 @@ private:
     /**
      * Updates the animation with the elapsed time.
      */
-    bool update(unsigned long elapsedTime);
+    bool update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets);
 
     /**
      * Handles when the AnimationClip begins.
@@ -227,32 +288,42 @@ private:
      */
     void onEnd();
 
-    std::string _id;                          // AnimationClip ID.
-    Animation* _animation;                    // The Animation this clip is created from.
-    unsigned long _startTime;                 // Start time of the clip.
-    unsigned long _endTime;                   // End time of the clip.
-    unsigned long _duration;                  // The total duration.
-    float _repeatCount;                       // The clip's repeat count.
-    unsigned long _activeDuration;            // The active duration of the clip.
-    float _speed;                             // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
-    bool _isPlaying;                          // A flag to indicate whether the clip is playing.
-    unsigned long _timeStarted;               // The game time when this clip was actually started.
-    unsigned long _elapsedTime;               // Time elapsed while the clip is running.
-    long _runningTime;                        // Keeps track of the Animation's relative time in respect to the active duration.
-    AnimationClip* _crossFadeToClip;          // The clip to cross fade to
-    unsigned long _crossFadeStart;            // The time at which the cross fade started.
-    unsigned long _crossFadeOutElapsed;       // The amount of time that has elapsed for the crossfade.
-    unsigned long _crossFadeOutDuration;      // The duration of the cross fade.
-    float _blendWeight;                       // The clip's blendweight
-    bool _isFadingOutStarted;                 // Flag to indicate if the cross fade started
-    bool _isFadingOut;                        // Flag to indicate if the clip is fading out
-    bool _isFadingIn;                         // Flag to indicate if the clip is fading in.
-    std::vector<AnimationValue*> _values;     // AnimationValue holder.
-    std::vector<Listener*>* _beginListeners;  // Collection of begin listeners on the clip
-    std::vector<Listener*>* _endListeners;    // Collection of end listeners on the clip
+    /**
+     * Determines whether the given bit is set in the AnimationClip's state.
+     */
+    bool isClipStateBitSet(char bit) const;
+
+    /**
+     * Sets the given bit in the AnimationClip's state.
+     */
+    void setClipStateBit(char bit);
 
+    /**
+     * Resets the given bit in the AnimationClip's state.
+     */
+    void resetClipStateBit(char bit);
+
+    std::string _id;                                    // AnimationClip ID.
+    Animation* _animation;                              // The Animation this clip is created from.
+    unsigned long _startTime;                           // Start time of the clip.
+    unsigned long _endTime;                             // End time of the clip.
+    unsigned long _duration;                            // The total duration.
+    char _stateBits;                                    // Bit flag used to keep track of the clip's current state.
+    float _repeatCount;                                 // The clip's repeat count.
+    unsigned long _activeDuration;                      // The active duration of the clip.
+    float _speed;                                       // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
+    unsigned long _timeStarted;                         // The game time when this clip was actually started.
+    long _elapsedTime;                                  // Time elapsed while the clip is running.
+    AnimationClip* _crossFadeToClip;                    // The clip to cross fade to.
+    unsigned long _crossFadeOutElapsed;                 // The amount of time that has elapsed for the crossfade.
+    unsigned long _crossFadeOutDuration;                // The duration of the cross fade.
+    float _blendWeight;                                 // The clip's blendweight.
+    std::vector<AnimationValue*> _values;               // AnimationValue holder.
+    std::vector<Listener*>* _beginListeners;            // Collection of begin listeners on the clip.
+    std::vector<Listener*>* _endListeners;              // Collection of end listeners on the clip.
+    std::list<ListenerEvent*>* _listeners;              // Ordered collection of listeners on the clip.
+    std::list<ListenerEvent*>::iterator* _listenerItr;  // Iterator that points to the next listener event to be triggered.
 };
 
 }
-
 #endif

+ 31 - 21
gameplay/src/AnimationController.cpp

@@ -7,7 +7,7 @@ namespace gameplay
 {
 
 AnimationController::AnimationController()
-    : _state(IDLE), _animations(NULL)
+    : _state(STOPPED), _animations(NULL)
 {
 }
 
@@ -66,6 +66,7 @@ Animation* AnimationController::createAnimationFromTo(const char* id, AnimationT
 
     Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
 
+    SAFE_DELETE_ARRAY(keyValues);
     SAFE_DELETE_ARRAY(keyTimes);
     
     return animation;
@@ -85,6 +86,7 @@ Animation* AnimationController::createAnimationFromBy(const char* id, AnimationT
 
     Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
 
+    SAFE_DELETE_ARRAY(keyValues);
     SAFE_DELETE_ARRAY(keyTimes);
 
     return animation;
@@ -109,9 +111,8 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = *clipIter;
-        clip->_isPlaying = false;
-        clip->onEnd();
-        SAFE_RELEASE(clip);
+        clipIter++;
+        clip->stop();
     }
     _runningClips.clear();
 
@@ -144,7 +145,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     
     char delimeter = ' ';
     unsigned int startOffset = 0;
-    unsigned int endOffset = std::string::npos;
+    unsigned int endOffset = (unsigned int)std::string::npos;
     
     unsigned long* keyTimes = new unsigned long[keyCount];
     for (unsigned int i = 0; i < keyCount; i++)
@@ -162,7 +163,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     }
 
     startOffset = 0;
-    endOffset = std::string::npos;
+    endOffset = (unsigned int)std::string::npos;
     
     int componentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(componentCount > 0);
@@ -190,7 +191,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     {
         keyIn = new float[components];
         startOffset = 0;
-        endOffset = std::string::npos;
+        endOffset = (unsigned int)std::string::npos;
         for (unsigned int i = 0; i < components; i++)
         {
             endOffset = static_cast<std::string>(keyInStr).find_first_of(delimeter, startOffset);
@@ -212,7 +213,7 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
     {   
         keyOut = new float[components];
         startOffset = 0;
-        endOffset = std::string::npos;
+        endOffset = (unsigned int)std::string::npos;
         for (unsigned int i = 0; i < components; i++)
         {
             endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
@@ -269,7 +270,7 @@ void AnimationController::initialize()
 void AnimationController::finalize()
 {
     stopAllAnimations();
-    _state = PAUSED;
+    _state = STOPPED;
 }
 
 void AnimationController::resume()
@@ -291,18 +292,8 @@ void AnimationController::schedule(AnimationClip* clip)
     {
         _state = RUNNING;
     }
-    
-    if (clip->_isPlaying)
-    {
-        _runningClips.remove(clip);
-        clip->_isPlaying = false;
-        clip->onEnd();
-    }
-    else
-    {
-        clip->addRef();
-    }
 
+    clip->addRef();
     _runningClips.push_back(clip);
 }
 
@@ -330,11 +321,20 @@ void AnimationController::update(long elapsedTime)
     if (_state != RUNNING)
         return;
 
+    // Loop through running clips and call update() on them.
     std::list<AnimationClip*>::iterator clipIter = _runningClips.begin();
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = (*clipIter);
-        if (clip->update(elapsedTime))
+        if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_RESTARTED_BIT))
+        {   // If the CLIP_IS_RESTARTED_BIT is set, we should end the clip and 
+            // move it from where it is in the running clips list to the back.
+            clip->onEnd();
+            clip->setClipStateBit(AnimationClip::CLIP_IS_PLAYING_BIT);
+            _runningClips.push_back(clip);
+            clipIter = _runningClips.erase(clipIter);
+        }
+        else if (clip->update(elapsedTime, &_activeTargets))
         {
             SAFE_RELEASE(clip);
             clipIter = _runningClips.erase(clipIter);
@@ -344,6 +344,16 @@ void AnimationController::update(long elapsedTime)
             clipIter++;
         }
     }
+
+    // Loop through active AnimationTarget's and reset their _animationPropertyBitFlag for the next frame.
+    std::list<AnimationTarget*>::iterator targetItr = _activeTargets.begin();
+    while (targetItr != _activeTargets.end())
+    {
+        AnimationTarget* target = (*targetItr);
+        target->_animationPropertyBitFlag = 0x00;
+        targetItr++;
+    }
+    _activeTargets.clear();
     
     if (_runningClips.empty())
         _state = IDLE;

+ 4 - 2
gameplay/src/AnimationController.h

@@ -117,7 +117,8 @@ private:
     {
         RUNNING,
         IDLE,
-        PAUSED
+        PAUSED,
+        STOPPED
     };
 
     /**
@@ -204,7 +205,8 @@ private:
     void destroyAllAnimations();
     
     State _state;                               // The current state of the AnimationController.
-    std::list<AnimationClip*> _runningClips;    // A list of currently running AnimationClips.
+    std::list<AnimationClip*> _runningClips;    // A list of running AnimationClips.
+    std::list<AnimationTarget*> _activeTargets;   // A list of animating AnimationTargets.
     std::vector<Animation*> _animations;        // A list of animations registered with the AnimationController
 };
 

+ 1 - 2
gameplay/src/AnimationTarget.cpp

@@ -2,13 +2,12 @@
 #include "AnimationTarget.h"
 #include "Animation.h"
 #include "Game.h"
-#include "Transform.h"
 
 namespace gameplay
 {
 
 AnimationTarget::AnimationTarget()
-    : _targetType(SCALAR), _highestPriority(NULL), _animationChannels(NULL)
+    : _targetType(SCALAR), _animationPropertyBitFlag(0x00), _animationChannels(NULL)
 {
 }
 

+ 4 - 3
gameplay/src/AnimationTarget.h

@@ -45,7 +45,7 @@ public:
      * @param propertyId The ID of the property on the AnimationTarget to set the animation property value on.
      * @param value The container to set the animation property value in.
      */
-    virtual void setAnimationPropertyValue(int propertyId, AnimationValue* value) = 0;
+    virtual void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f) = 0;
 
 protected:
     
@@ -69,6 +69,8 @@ protected:
 
     TargetType _targetType;             // The type of target this is.
 
+    char _animationPropertyBitFlag;     // Bit flag used to indicate which properties on the AnimationTarget are currently animating.
+
 private:
 
     /**
@@ -86,9 +88,8 @@ private:
      */
     static int getPropertyId(TargetType type, const char* propertyIdStr);
 
-    Animation::Channel* _highestPriority;
     std::vector<Animation::Channel*>* _animationChannels;   // Collection of all animation channels that target the AnimationTarget
-
+    
 };
 }
 

+ 7 - 9
gameplay/src/AnimationValue.cpp

@@ -5,44 +5,42 @@ namespace gameplay
 {
 
 AnimationValue::AnimationValue(unsigned int componentCount)
-  : _isFirstActing(false), _componentCount(componentCount), _componentSize(componentCount * sizeof(float))
+  : _componentCount(componentCount), _componentSize(componentCount * sizeof(float))
 {
-    _currentValue = new float[_componentCount];
-    _interpolatedValue = new float[_componentCount];
+    _value = new float[_componentCount];
 }
 
 AnimationValue::~AnimationValue()
 {
-    SAFE_DELETE_ARRAY(_currentValue);
-    SAFE_DELETE_ARRAY(_interpolatedValue);
+    SAFE_DELETE_ARRAY(_value);
 }
 
 float AnimationValue::getFloat(unsigned int index) const
 {
     assert(index < _componentCount);
 
-    return _currentValue[index];
+    return _value[index];
 }
 
 void AnimationValue::setFloat(unsigned int index, float value)
 {
     assert(index < _componentCount);
 
-    _currentValue[index] = value;
+    _value[index] = value;
 }
 
 void AnimationValue::getFloat(float* value, unsigned int offset, unsigned int length) const
 {
     assert(value && offset < _componentCount && (offset + length) <= _componentCount);
 
-    memcpy(value + offset, _currentValue, length * sizeof(float));
+    memcpy(value + offset, _value, length * sizeof(float));
 }
 
 void AnimationValue::setFloat(float* value, unsigned int offset, unsigned int length)
 {
     assert(value && offset < _componentCount && (offset + length) <= _componentCount);
 
-    memcpy(_currentValue, value + offset, length * sizeof(float));
+    memcpy(_value, value + offset, length * sizeof(float));
 }
 
 }

+ 2 - 3
gameplay/src/AnimationValue.h

@@ -72,11 +72,10 @@ private:
      */
     ~AnimationValue();
 
-    bool _isFirstActing;            // Flag indicating if this value's channel is the first to act on the target.
     unsigned int _componentCount;   // The number of float values for the property.
     unsigned int _componentSize;    // The number of bytes of memory the property is.
-    float* _currentValue;           // The current value of the property.
-    float* _interpolatedValue;      // The last interpolated value of the property.
+    float* _value;                  // The current value of the property.
+
 };
 
 }

+ 108 - 7
gameplay/src/AudioBuffer.cpp

@@ -2,24 +2,36 @@
 #include "AudioBuffer.h"
 #include "FileSystem.h"
 
+#ifdef __ANDROID__
+extern AAssetManager* __assetManager;
+#endif
+
 namespace gameplay
 {
 
 // Audio buffer cache
 static std::vector<AudioBuffer*> __buffers;
 
+#ifndef __ANDROID__
 AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
     : _filePath(path), _alBuffer(buffer)
 {
 }
+#else
+AudioBuffer::AudioBuffer(const char* path) : _filePath(path)
+{
+}
+#endif
 
 AudioBuffer::~AudioBuffer()
 {
+#ifndef __ANDROID__
     if (_alBuffer)
     {
         alDeleteBuffers(1, &_alBuffer);
         _alBuffer = 0;
     }
+#endif
 }
 
 AudioBuffer* AudioBuffer::create(const char* path)
@@ -39,6 +51,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
         }
     }
 
+#ifndef __ANDROID__
     ALuint alBuffer;
     ALCenum al_error;
 
@@ -106,8 +119,58 @@ cleanup:
     if (alBuffer)
         alDeleteBuffers(1, &alBuffer);
     return NULL;
+#else
+    // Get the file header in order to determine the type.
+    AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
+    char header[12];
+    if (AAsset_read(asset, header, 12) != 12)
+    {
+        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
+        return NULL;
+    }
+
+    // Get the file descriptor for the audio file.
+    off_t start, length;
+    int fd = AAsset_openFileDescriptor(asset, &start, &length);
+    if (fd < 0)
+    {
+        LOG_ERROR_VARG("Failed to open file descriptor for asset: %s", path);
+        return NULL;
+    }
+    AAsset_close(asset);
+    SLDataLocator_AndroidFD data = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
+
+    // Set the appropriate mime type information.
+    SLDataFormat_MIME mime;
+    mime.formatType = SL_DATAFORMAT_MIME;
+    std::string pathStr = path;
+    if (memcmp(header, "RIFF", 4) == 0)
+    {
+        mime.mimeType = (SLchar*)"audio/x-wav";
+        mime.containerType = SL_CONTAINERTYPE_WAV;
+    }
+    else if (memcmp(header, "OggS", 4) == 0)
+    {
+        mime.mimeType = (SLchar*)"application/ogg";
+        mime.containerType = SL_CONTAINERTYPE_OGG;
+    }
+    else
+    {
+        LOG_ERROR_VARG("Unsupported audio file: %s", path);
+    }
+
+    buffer = new AudioBuffer(path);
+    buffer->_data = data;
+    buffer->_mime = mime;
+
+    // Add the buffer to the cache.
+    __buffers.push_back(buffer);
+
+    return buffer;
+#endif
 }
-    
+
+#ifndef __ANDROID__
 bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
 {
     unsigned char stream[12];
@@ -116,6 +179,12 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
         return false;
     
+    unsigned int section_size;
+    section_size  = stream[7]<<24;
+    section_size |= stream[6]<<16;
+    section_size |= stream[5]<<8;
+    section_size |= stream[4];
+
     // Check for a valid pcm format.
     if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
     {
@@ -153,7 +222,6 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     bits  = stream[1]<<8;
     bits |= stream[0];
     
-
     // Now convert the given channel count and bit depth into an OpenAL format. 
     ALuint format = 0;
     if (bits == 8)
@@ -176,13 +244,45 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         return false;
     }
     
-    // Read the data chunk, which will hold the decoded sample data 
-    if (fread(stream, 1, 4, file) != 4 || memcmp(stream, "data", 4) != 0)
+    // Check against the size of the format header as there may be more data that we need to read
+    if (section_size > 16)
     {
-        LOG_ERROR("WAV file has no data.");
-        return false;
+    	unsigned int length = section_size - 16;
+
+    	// extension size is 2 bytes
+    	if (fread(stream, 1, length, file) != length)
+    		return false;
     }
-    
+
+    if (fread(stream, 1, 4, file) != 4)
+    	return false;
+
+    // read the next chunk, could be fact section or the data section
+    if (memcmp(stream, "fact", 4) == 0)
+    {
+    	if (fread(stream, 1, 4, file) != 4)
+    		return false;
+
+    	section_size  = stream[3]<<24;
+    	section_size |= stream[2]<<16;
+    	section_size |= stream[1]<<8;
+    	section_size |= stream[0];
+
+    	// read in the rest of the fact section
+    	if (fread(stream, 1, section_size, file) != section_size)
+    		return false;
+
+    	if (fread(stream, 1, 4, file) != 4)
+    		return false;
+    }
+
+    // should now be the data section which holds the decoded sample data
+    if (memcmp(stream, "data", 4) != 0)
+    {
+    	LOG_ERROR("WAV file has no data.");
+    	return false;
+    }
+
     // Read how much data is remaining and buffer it up.
     unsigned int dataSize;
     fread(&dataSize, sizeof(int), 1, file);
@@ -265,5 +365,6 @@ bool AudioBuffer::loadOgg(FILE* file, ALuint buffer)
 
     return true;
 }
+#endif
 
 }

+ 14 - 1
gameplay/src/AudioBuffer.h

@@ -18,11 +18,17 @@ class AudioBuffer : public Ref
     friend class AudioSource;
 
 private:
-
+#ifndef __ANDROID__
     /**
      * Constructor.
      */
     AudioBuffer(const char* path, ALuint buffer);
+#else
+    /**
+     * Constructor.
+     */
+    AudioBuffer(const char* path);
+#endif
 
     /**
      * Destructor.
@@ -38,12 +44,19 @@ private:
      */
     static AudioBuffer* create(const char* path);
     
+#ifndef __ANDROID__
     static bool loadWav(FILE* file, ALuint buffer);
     
     static bool loadOgg(FILE* file, ALuint buffer);
+#endif
 
     std::string _filePath;
+#ifndef __ANDROID__
     ALuint _alBuffer;
+#else
+    SLDataLocator_AndroidFD _data;
+    SLDataFormat_MIME _mime;
+#endif
 };
 
 }

+ 141 - 1
gameplay/src/AudioController.cpp

@@ -10,17 +10,27 @@ namespace gameplay
 
 std::list<AudioSource*> AudioController::_playingSources;
 
+
+#ifndef __ANDROID__
 AudioController::AudioController() 
     : _alcDevice(NULL), _alcContext(NULL)
 {
 }
+#else
+AudioController::AudioController() 
+    : _engineObject(NULL), _engineEngine(NULL), _outputMixObject(NULL), _listenerObject(NULL),
+    _listenerDoppler(NULL), _listenerLocation(NULL)
+{
+}
+#endif
 
 AudioController::~AudioController()
 {
 }
 
 void AudioController::initialize()
-{    
+{
+#ifndef __ANDROID__
     _alcDevice = alcOpenDevice (NULL);
     if (!_alcDevice)
     {
@@ -43,10 +53,52 @@ void AudioController::initialize()
     {
         LOG_ERROR_VARG("AudioController::initialize() error. Unable to make OpenAL context current. Error: %d\n", alcErr);
     }
+#else
+    // Create the engine.
+    SLresult result = slCreateEngine(&_engineObject, 0, NULL, 0, NULL, NULL);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to create OpenSL engine.");
+        return;
+    }
+
+    // Realize the engine.
+    result = (*_engineObject)->Realize(_engineObject, SL_BOOLEAN_FALSE);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to realize OpenSL engine.");
+        return;
+    }
+
+    // Get the engine interface in order to create other objects later on.
+    result = (*_engineObject)->GetInterface(_engineObject, SL_IID_ENGINE, &_engineEngine);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to retrieve OpenSL engine interface.");
+        return;
+    }
+
+    // Create the output mix.
+    result = (*_engineEngine)->CreateOutputMix(_engineEngine, &_outputMixObject, 0, NULL, NULL);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to create OpenSL output mix.");
+        return;
+    }
+
+    // Realize the output mix.
+    result = (*_outputMixObject)->Realize(_outputMixObject, SL_BOOLEAN_FALSE);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to realize OpenSL output mix.");
+        return;
+    }
+#endif
 }
 
 void AudioController::finalize()
 {
+#ifndef __ANDROID__
     alcMakeContextCurrent(NULL);
     if (_alcContext)
     {
@@ -58,6 +110,20 @@ void AudioController::finalize()
         alcCloseDevice(_alcDevice);
         _alcDevice = NULL;
     }
+#else
+    if (_outputMixObject != NULL)
+    {
+        (*_outputMixObject)->Destroy(_outputMixObject);
+        _outputMixObject = NULL;
+    }
+
+    if (_engineObject != NULL)
+    {
+        (*_engineObject)->Destroy(_engineObject);
+        _engineObject = NULL;
+        _engineEngine = NULL;
+    }
+#endif
 }
 
 void AudioController::pause()
@@ -79,6 +145,9 @@ void AudioController::pause()
 
 void AudioController::resume()
 {
+#ifndef __ANDROID__    
+    alcMakeContextCurrent(_alcContext);
+#endif
     std::list<AudioSource*>::iterator itr = _playingSources.begin();
 
     // For each source that is playing, resume it.
@@ -99,10 +168,81 @@ void AudioController::update(long elapsedTime)
     AudioListener* listener = AudioListener::getInstance();
     if (listener)
     {
+#ifndef __ANDROID__
         alListenerf(AL_GAIN, listener->getGain());
         alListenerfv(AL_ORIENTATION, (ALfloat*)&listener->getOrientationForward());
         alListenerfv(AL_VELOCITY, (ALfloat*)&listener->getVelocity());
         alListenerfv(AL_POSITION, (ALfloat*)&listener->getPosition());
+#else
+        if (!_listenerObject)
+        {
+            const SLInterfaceID interfaces[3] = {SL_IID_3DDOPPLER, SL_IID_3DLOCATION};
+            const SLboolean required[3] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};
+            SLresult result = (*_engineEngine)->CreateListener(_engineEngine, &_listenerObject, 2, interfaces, required);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: failed to create listener.");
+                return;
+            }
+
+            result = (*_listenerObject)->Realize(_listenerObject, SL_BOOLEAN_FALSE);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: failed to realize listener.");
+                return;
+            }
+
+            // Get the doppler interface in order to set the listener's velocity.
+            result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DDOPPLER, &_listenerDoppler);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: Unable to retrieve listener doppler interface.");
+                return;
+            }
+
+            // Get the location interface in order to set the listener's position and orientation.
+            result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DLOCATION, &_listenerLocation);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: Unable to retrieve listener location interface.");
+                return;
+            }
+        }
+        
+        SLVec3D f;
+        f.x = listener->getOrientationForward().x;
+        f.y = listener->getOrientationForward().y;
+        f.z = listener->getOrientationForward().z;
+        SLVec3D a;
+        a.x = listener->getOrientationUp().x;
+        a.y = listener->getOrientationUp().y;
+        a.z = listener->getOrientationUp().z;
+        SLresult result = (*_listenerLocation)->SetOrientationVectors(_listenerLocation, &f, &a);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to set listener orientation.");
+        }
+
+        SLVec3D p;
+        p.x = listener->getPosition().x;
+        p.y = listener->getPosition().y;
+        p.z = listener->getPosition().z;
+        result = (*_listenerLocation)->SetLocationCartesian(_listenerLocation, &p);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to set listener location.");
+        }
+
+        SLVec3D v;
+        v.x = listener->getVelocity().x;
+        v.y = listener->getVelocity().y;
+        v.z = listener->getVelocity().z;
+        result = (*_listenerDoppler)->SetVelocityCartesian(_listenerDoppler, &v);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to set listener velocity.");
+        }
+#endif
     }
 }
 

+ 9 - 0
gameplay/src/AudioController.h

@@ -54,8 +54,17 @@ private:
      */
     void update(long elapsedTime);
 
+#ifndef __ANDROID__
     ALCdevice* _alcDevice;
     ALCcontext* _alcContext;
+#else
+    SLObjectItf _engineObject;
+    SLEngineItf _engineEngine;
+    SLObjectItf _outputMixObject;
+    SLObjectItf _listenerObject;
+    SL3DDopplerItf _listenerDoppler;
+    SL3DLocationItf _listenerLocation;
+#endif
     static std::list<AudioSource*> _playingSources;     // List of currently running sources.
 };
 

+ 238 - 3
gameplay/src/AudioSource.cpp

@@ -1,11 +1,15 @@
 #include "Base.h"
 #include "Node.h"
 #include "AudioBuffer.h"
+#include "AudioController.h"
 #include "AudioSource.h"
+#include "Game.h"
 
 namespace gameplay
 {
 
+
+#ifndef __ANDROID__
 AudioSource::AudioSource(AudioBuffer* buffer, ALuint source) 
     : _alSource(source), _buffer(buffer), _looped(true), _gain(1.0f), _pitch(1.0f), _node(NULL)
 {
@@ -15,14 +19,86 @@ AudioSource::AudioSource(AudioBuffer* buffer, ALuint source)
     alSourcef(_alSource, AL_GAIN, _gain);
     alSourcefv(_alSource, AL_VELOCITY, (const ALfloat*)&_velocity);
 }
+#else
+AudioSource::AudioSource(AudioBuffer* buffer, const SLObjectItf& player)
+    : _playerObject(player), _playerDoppler(NULL), _playerLocation(NULL), _playerPlay(NULL), _playerPitch(NULL),
+    _playerSeek(NULL), _playerVolume(NULL), _buffer(buffer), _looped(true), _gain(1.0f), _pitch(1.0f), _node(NULL)
+{
+    // Get the different interfaces for the OpenSL audio player that we need.
+    SLresult result = (*_playerObject)->GetInterface(_playerObject, SL_IID_3DDOPPLER, &_playerDoppler);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::AudioSource() - Failed to get 3D doppler interface for OpenSL audio player.");
+    }
+    
+    result = (*_playerObject)->GetInterface(_playerObject, SL_IID_3DLOCATION, &_playerLocation);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::AudioSource() - Failed to get 3D location interface for OpenSL audio player.");
+    }
+
+    result = (*_playerObject)->GetInterface(_playerObject, SL_IID_PLAY, &_playerPlay);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::AudioSource() - Failed to get play interface for OpenSL audio player.");
+    }
+
+    result = (*_playerObject)->GetInterface(_playerObject, SL_IID_PITCH, &_playerPitch);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::AudioSource() - Failed to get rate pitch interface for OpenSL audio player.");
+    }
+
+    result = (*_playerObject)->GetInterface(_playerObject, SL_IID_SEEK, &_playerSeek);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::AudioSource() - Failed to get seek interface for OpenSL audio player.");
+    }
+
+    result = (*_playerObject)->GetInterface(_playerObject, SL_IID_VOLUME, &_playerVolume);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::AudioSource() - Failed to get volume interface for OpenSL audio player.");
+    }
+
+    // Get the max volume level (used to convert from our API's parameter to OpenSL's expected units).
+    if (_playerVolume)
+    {
+        result = (*_playerVolume)->GetMaxVolumeLevel(_playerVolume, &_maxVolume);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::AudioSource() - Failed to get the max volume level for OpenSL audio player (needed for parameter conversion).");
+        }
+    }
+
+    setLooped(_looped);
+    setPitch(_pitch);
+    setGain(_gain);
+    setVelocity(_velocity);
+}
+#endif
 
 AudioSource::~AudioSource()
 {
+#ifndef __ANDROID__
     if (_alSource)
     {
         alDeleteSources(1, &_alSource);
         _alSource = 0;
     }
+#else
+    if (_playerObject)
+    {
+        (*_playerObject)->Destroy(_playerObject);
+        _playerObject = NULL;
+        _playerDoppler = NULL;
+        _playerLocation = NULL;
+        _playerPlay = NULL;
+        _playerPitch = NULL;
+        _playerSeek = NULL;
+        _playerVolume = NULL;
+    }
+#endif
 
     SAFE_RELEASE(_buffer);
 }
@@ -52,17 +128,44 @@ AudioSource* AudioSource::create(const char* path)
     if (buffer == NULL)
         return NULL;
 
+#ifndef __ANDROID__
     // Load the audio source.
-    ALuint alSource;
+    ALuint alSource = 0;
+
     alGenSources(1, &alSource);
     if (alGetError() != AL_NO_ERROR)
     {
         SAFE_RELEASE(buffer);
-        LOG_ERROR("AudioSource::createAudioSource Error generating audio source.");
+        LOG_ERROR("AudioSource::createAudioSource - Error generating audio source.");
         return NULL;
     }
-
+    
     return new AudioSource(buffer, alSource);
+#else
+    AudioController* audioController = Game::getInstance()->getAudioController();
+    SLDataLocator_OutputMix locator = {SL_DATALOCATOR_OUTPUTMIX, audioController->_outputMixObject};
+
+    SLDataSource dataSource = {&buffer->_data, &buffer->_mime};
+    SLDataSink dataSink = {&locator, NULL};
+
+    SLObjectItf player;
+    const SLInterfaceID interfaces[] = {SL_IID_3DDOPPLER, SL_IID_3DLOCATION, SL_IID_PLAY, SL_IID_PITCH, SL_IID_SEEK, SL_IID_VOLUME};
+    const SLboolean required[] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};
+    SLresult result = (*audioController->_engineEngine)->CreateAudioPlayer(audioController->_engineEngine, &player, &dataSource, &dataSink, 6, interfaces, required);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::create - Failed to create OpenSL audio player.");
+        return NULL;
+    }
+
+    result = (*player)->Realize(player, SL_BOOLEAN_FALSE);
+    if(result != SL_RESULT_SUCCESS)
+    {
+        WARN("AudioSource::create - Failed to realize OpenSL audio player.");
+    }
+
+    return new AudioSource(buffer, player);
+#endif
 }
 
 AudioSource* AudioSource::create(Properties* properties)
@@ -114,6 +217,7 @@ AudioSource* AudioSource::create(Properties* properties)
 
 AudioSource::State AudioSource::getState() const
 {
+#ifndef __ANDROID__
     ALint state;
     alGetSourcei(_alSource, AL_SOURCE_STATE, &state);
 
@@ -128,18 +232,63 @@ AudioSource::State AudioSource::getState() const
         default:         
             return INITIAL;
     }
+#else
+    if (_playerPlay != NULL)
+    {
+        SLuint32 state;
+        SLresult result = (*_playerPlay)->GetPlayState(_playerPlay, &state);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::getState() failed to get player state.");
+        }
+
+        switch (state)
+        {
+            case SL_PLAYSTATE_PLAYING:
+                return PLAYING;
+            case SL_PLAYSTATE_PAUSED:
+                return PAUSED;
+            case SL_PLAYSTATE_STOPPED:
+                return STOPPED;
+            default:
+                return INITIAL;
+        }
+    }
+#endif
 
     return INITIAL;
 }
 
 void AudioSource::play()
 {
+#ifndef __ANDROID__
     alSourcePlay(_alSource);
+#else
+    if (_playerPlay != NULL)
+    {
+        SLresult result = (*_playerPlay)->SetPlayState(_playerPlay, SL_PLAYSTATE_PLAYING);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::play() failed to set player state.");
+        }
+    }
+#endif
 }
 
 void AudioSource::pause()
 {
+#ifndef __ANDROID__
     alSourcePause(_alSource);
+#else
+    if (_playerPlay != NULL)
+    {
+        SLresult result = (*_playerPlay)->SetPlayState(_playerPlay, SL_PLAYSTATE_PAUSED);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::pause() failed to set player state.");
+        }
+    }
+#endif
 }
 
 void AudioSource::resume()
@@ -152,12 +301,34 @@ void AudioSource::resume()
 
 void AudioSource::stop()
 {
+#ifndef __ANDROID__
     alSourceStop(_alSource);
+#else
+    if (_playerPlay != NULL)
+    {
+        SLresult result = (*_playerPlay)->SetPlayState(_playerPlay, SL_PLAYSTATE_STOPPED);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::stop() failed to set player state.");
+        }
+    }
+#endif 
 }
 
 void AudioSource::rewind()
 {
+#ifndef __ANDROID__
     alSourceRewind(_alSource);
+#else
+    if (_playerPlay != NULL)
+    {
+        SLresult result = (*_playerPlay)->SetMarkerPosition(_playerPlay, 0);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::rewind() failed to set player marker position.");
+        }
+    }
+#endif
 }
 
 bool AudioSource::isLooped() const
@@ -167,6 +338,7 @@ bool AudioSource::isLooped() const
 
 void AudioSource::setLooped(bool looped)
 {
+#ifndef __ANDROID__
      // Clear error state.
     alGetError();
     alSourcei(_alSource, AL_LOOPING, (looped) ? AL_TRUE : AL_FALSE);
@@ -176,6 +348,16 @@ void AudioSource::setLooped(bool looped)
     {
         LOG_ERROR_VARG("AudioSource::setLooped Error: %d", error);
     }
+#else
+    if (_playerSeek)
+    {
+        SLresult result = (*_playerSeek)->SetLoop(_playerSeek, looped, 0, SL_TIME_UNKNOWN);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::setLooped() failed.");
+        }
+    }
+#endif
 
     _looped = looped;
 }
@@ -187,7 +369,19 @@ float AudioSource::getGain() const
 
 void AudioSource::setGain(float gain)
 {
+#ifndef __ANDROID__
     alSourcef(_alSource, AL_GAIN, gain);
+#else
+    if (_playerVolume)
+    {
+        SLmillibel volume = (gain < MATH_EPSILON) ? SL_MILLIBEL_MIN : (10.0f * log10(gain)) * 100;
+        SLresult result = (*_playerVolume)->SetVolumeLevel(_playerVolume, volume);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::setGain() failed to set player gain.");
+        }
+    }
+#endif
     _gain = gain;
 }
 
@@ -198,7 +392,18 @@ float AudioSource::getPitch() const
 
 void AudioSource::setPitch(float pitch)
 {
+#ifndef __ANDROID__
     alSourcef(_alSource, AL_PITCH, pitch);
+#else
+    if (_playerPitch)
+    {
+        SLresult result = (*_playerPitch)->SetPitch(_playerPitch, (SLpermille)(pitch * 1000));
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::setPitch() failed to set player pitch.");
+        }
+    }
+#endif
     _pitch = pitch;
 }
 
@@ -209,7 +414,22 @@ const Vector3& AudioSource::getVelocity() const
 
 void AudioSource::setVelocity(const Vector3& velocity)
 {
+#ifndef __ANDROID__
     alSourcefv(_alSource, AL_VELOCITY, (ALfloat*)&velocity);
+#else
+    if (_playerDoppler)
+    {
+        SLVec3D v;
+        v.x = velocity.x;
+        v.y = velocity.y;
+        v.z = velocity.z;
+        SLresult result = (*_playerDoppler)->SetVelocityCartesian(_playerDoppler, &v);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::setVelocity - failed to set velocity.");
+        }
+    }
+#endif
     _velocity = velocity;
 }
 
@@ -240,7 +460,22 @@ void AudioSource::setNode(Node* node)
 
 void AudioSource::transformChanged(Transform* transform, long cookie)
 {
+#ifndef __ANDROID__
     alSourcefv(_alSource, AL_POSITION, (const ALfloat*)&transform->getTranslation());
+#else
+    if (_playerLocation)
+    {
+        SLVec3D position;
+        position.x = transform->getTranslationX();
+        position.y = transform->getTranslationY();
+        position.z = transform->getTranslationZ();
+        SLresult result = (*_playerLocation)->SetLocationCartesian(_playerLocation, &position);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioSource::transformChanged - failed to update location.");
+        }
+    }
+#endif
 }
 
 }

+ 21 - 0
gameplay/src/AudioSource.h

@@ -146,11 +146,21 @@ public:
 
 private:
 
+#ifndef __ANDROID__
     /**
      * Constructor that takes an AudioBuffer.
      */
     AudioSource(AudioBuffer* buffer, ALuint source);
 
+#else
+
+    /**
+     * Constructor that takes an AudioBuffer.
+     */
+    AudioSource(AudioBuffer* buffer, const SLObjectItf& player);
+#endif
+
+
     /**
      * Destructor.
      */
@@ -166,7 +176,18 @@ private:
      */
     void transformChanged(Transform* transform, long cookie);
 
+#ifndef __ANDROID__
     ALuint _alSource;
+#else
+    SLObjectItf _playerObject;
+    SL3DDopplerItf _playerDoppler;
+    SL3DLocationItf _playerLocation;
+    SLPlayItf _playerPlay;
+    SLPitchItf _playerPitch;
+    SLSeekItf _playerSeek;
+    SLVolumeItf _playerVolume;
+    SLmillibel _maxVolume;
+#endif
     AudioBuffer* _buffer;
     bool _looped;
     float _gain;

+ 74 - 17
gameplay/src/Base.h

@@ -17,6 +17,7 @@
 #include <string>
 #include <vector>
 #include <list>
+#include <set>
 #include <stack>
 #include <map>
 #include <algorithm>
@@ -39,6 +40,10 @@ using std::min;
 using std::max;
 using std::modf;
 
+#ifdef __ANDROID__
+#include <android/asset_manager.h>
+#endif
+
 // Common
 #ifndef NULL
 #define NULL     0
@@ -50,6 +55,31 @@ namespace gameplay
 extern void printError(const char* format, ...);
 }
 
+#ifdef __ANDROID__
+#include <android/log.h>
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
+
+// System Errors
+#define LOG_ERROR(x) \
+    { \
+        LOGI(x); \
+        assert(#x == 0); \
+    }
+#define LOG_ERROR_VARG(x, ...) \
+    { \
+        LOGI(x, __VA_ARGS__); \
+        assert(#x == 0); \
+    }
+
+// Warning macro
+#ifdef WARN
+#undef WARN
+#endif
+#define WARN(x) LOGI(x)
+#define WARN_VARG(x, ...) LOGI(x, __VA_ARGS__)
+
+#else
+
 // System Errors
 #define LOG_ERROR(x) \
     { \
@@ -69,15 +99,18 @@ extern void printError(const char* format, ...);
 #define WARN(x) printError(x)
 #define WARN_VARG(x, ...) printError(x, __VA_ARGS__)
 
+#endif
+
 // Bullet Physics
 #include <btBulletDynamicsCommon.h>
+#define BV(v) (btVector3((v).x, (v).y, (v).z))
+#define BQ(q) (btQuaternion((q).x, (q).y, (q).z, (q).w))
 
 // Debug new for memory leak detection
 #include "DebugNew.h"
 
 // Object deletion macro
 #define SAFE_DELETE(x) \
-    if (x) \
     { \
         delete x; \
         x = NULL; \
@@ -85,7 +118,6 @@ extern void printError(const char* format, ...);
 
 // Array deletion macro
 #define SAFE_DELETE_ARRAY(x) \
-    if (x) \
     { \
         delete[] x; \
         x = NULL; \
@@ -114,6 +146,7 @@ extern void printError(const char* format, ...);
 #define MATH_PIOVER4                M_PI_4
 #define MATH_PIX2                   6.28318530717958647693f
 #define MATH_EPSILON                0.000001f
+#define MATH_CLAMP(x, lo, hi)       ((x < lo) ? lo : ((x > hi) ? hi : x))
 #ifndef M_1_PI
 #define M_1_PI                      0.31830988618379067154
 #endif
@@ -128,7 +161,12 @@ inline float round(float r)
     #define NOMINMAX
 #endif
 
-// Audio (OpenAL)
+// Audio (OpenAL, OpenSL, OggVorbis)
+#ifdef __ANDROID__
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+#else
+
 #ifdef __QNX__
 #include <AL/al.h>
 #include <AL/alc.h>
@@ -139,19 +177,18 @@ inline float round(float r)
 #include <OpenAL/al.h>
 #include <OpenAL/alc.h>
 #endif
-#include <vorbis/vorbisfile.h>
 
-// Screen/Window
-#define WINDOW_WIDTH        1024
-#define WINDOW_HEIGHT       600
-#define WINDOW_VSYNC        1
-#define WINDOW_FULLSCREEN   0
+#include <vorbis/vorbisfile.h>
+#endif
 
 // Image
 #include <png.h>
 
+#define WINDOW_VSYNC        1
+#define WINDOW_FULLSCREEN   0
+
 // Graphics (OpenGL)
-#ifdef __QNX__
+#if defined (__QNX__) || defined(__ANDROID__)
     #include <EGL/egl.h>
     #include <GLES2/gl2.h>
     #include <GLES2/gl2ext.h>
@@ -160,19 +197,35 @@ inline float round(float r)
     extern PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays;
     extern PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
     #define glClearDepth glClearDepthf
-   #define OPENGL_ES
+    #define OPENGL_ES
 #elif WIN32
     #define WIN32_LEAN_AND_MEAN
     #include <GL/glew.h>
 #elif __APPLE__
-#include <OpenGL/gl.h>
-#include <OpenGL/glext.h>
-#define glBindVertexArray glBindVertexArrayAPPLE
-#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
-#define glGenVertexArrays glGenVertexArraysAPPLE
-#define glIsVertexArray glIsVertexArrayAPPLE
+    #include "TargetConditionals.h"
+    #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+        #include <OpenGLES/ES2/gl.h>
+        #include <OpenGLES/ES2/glext.h>
+        #define glBindVertexArray glBindVertexArrayOES
+        #define glDeleteVertexArrays glDeleteVertexArraysOES
+        #define glGenVertexArrays glGenVertexArraysOES
+        #define glIsVertexArray glIsVertexArrayOES
+        #define glClearDepth glClearDepthf
+        #define OPENGL_ES
+    #elif TARGET_OS_MAC
+        #include <OpenGL/gl.h>
+        #include <OpenGL/glext.h>
+        #define glBindVertexArray glBindVertexArrayAPPLE
+        #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
+        #define glGenVertexArrays glGenVertexArraysAPPLE
+        #define glIsVertexArray glIsVertexArrayAPPLE
+    #else
+        #error "Unsupported Apple Device"
+    #endif
 #endif
 
+
+
 // Graphics (GLSL)
 #define VERTEX_ATTRIBUTE_POSITION_NAME              "a_position"
 #define VERTEX_ATTRIBUTE_NORMAL_NAME                "a_normal"
@@ -255,5 +308,9 @@ extern GLenum __gl_error_code;
     #pragma warning( disable : 4996 )
 #endif
 
+#ifdef __ANDROID__
+#include <android_native_app_glue.h>
+extern void amain(struct android_app* state);
+#endif
 
 #endif

+ 3 - 3
gameplay/src/BoundingBox.cpp

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

+ 1 - 1
gameplay/src/BoundingBox.h

@@ -191,7 +191,7 @@ public:
  * @param box The bounding box to transform.
  * @return The resulting transformed bounding box.
  */
-inline BoundingBox operator*(const Matrix& matrix, const BoundingBox& box);
+inline const BoundingBox operator*(const Matrix& matrix, const BoundingBox& box);
 
 }
 

+ 1 - 1
gameplay/src/BoundingBox.inl

@@ -9,7 +9,7 @@ inline BoundingBox& BoundingBox::operator*=(const Matrix& matrix)
     return *this;
 }
 
-inline BoundingBox operator*(const Matrix& matrix, const BoundingBox& box)
+inline const BoundingBox operator*(const Matrix& matrix, const BoundingBox& box)
 {
     BoundingBox b(box);
     b.transform(matrix);

+ 1 - 1
gameplay/src/BoundingSphere.h

@@ -183,7 +183,7 @@ private:
  * @param sphere The bounding sphere to transform.
  * @return The resulting transformed bounding sphere.
  */
-inline BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere);
+inline const BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere);
 
 }
 

+ 1 - 1
gameplay/src/BoundingSphere.inl

@@ -9,7 +9,7 @@ inline BoundingSphere& BoundingSphere::operator*=(const Matrix& matrix)
     return *this;
 }
 
-inline BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere)
+inline const BoundingSphere operator*(const Matrix& matrix, const BoundingSphere& sphere)
 {
     BoundingSphere s(sphere);
     s.transform(matrix);

+ 14 - 12
gameplay/src/Curve.cpp

@@ -703,6 +703,11 @@ void Curve::evaluate(float time, float* dst) const
     interpolateLinear(t, from, to, dst);
 }
 
+float Curve::lerp(float t, float from, float to)
+{
+    return lerpInl(t, from, to);
+}
+
 void Curve::setQuaternionOffset(unsigned int offset)
 {
     assert(offset <= (_componentCount - 4));
@@ -1078,7 +1083,7 @@ void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
             if (fromValue[i] == toValue[i])
                 dst[i] = fromValue[i];
             else
-                dst[i] = lerp(s, fromValue[i], toValue[i]);
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
         }
     }
     else
@@ -1091,7 +1096,7 @@ void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
             if (fromValue[i] == toValue[i])
                 dst[i] = fromValue[i];
             else
-                dst[i] = lerp(s, fromValue[i], toValue[i]);
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
         }
 
         // Handle quaternion component.
@@ -1103,25 +1108,22 @@ void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
             if (fromValue[i] == toValue[i])
                 dst[i] = fromValue[i];
             else
-                dst[i] = lerp(s, fromValue[i], toValue[i]);
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
         }
     }
 }
 
 void Curve::interpolateQuaternion(float s, float* from, float* to, float* dst) const
 {
-    Quaternion quatFrom(from);
-    Quaternion quatTo(to);
-
-    // Normalize the quaternions.
-    quatFrom.normalize();
-    quatTo.normalize();
-        
     // Evaluate.
     if (s >= 0)
-        Quaternion::slerp(quatFrom, quatTo, s, (Quaternion*)dst);
+    {
+        Quaternion::slerp(from[0], from[1], from[2], from[3], to[0], to[1], to[2], to[3], s, dst, dst + 1, dst + 2, dst + 3);
+    }
     else
-        Quaternion::slerp(quatTo, quatFrom, -s, (Quaternion*)dst);
+        Quaternion::slerp(to[0], to[1], to[2], to[3], from[0], from[1], from[2], from[3], s, dst, dst + 1, dst + 2, dst + 3);
+
+    //((Quaternion*) dst)->normalize();
 }
 
 int Curve::determineIndex(float time) const

+ 11 - 6
gameplay/src/Curve.h

@@ -354,6 +354,11 @@ public:
      */
     void evaluate(float time, float* dst) const;
 
+    /**
+     * Linear interpolation function.
+     */
+    static float lerp(float t, float from, float to);
+
 private:
 
     /**
@@ -460,17 +465,17 @@ private:
     Point* _points;                     // The points on the curve.
 };
 
-inline float bezier(float eq0, float eq1, float eq2, float eq3, float from, float out, float to, float in);
+inline static float bezier(float eq0, float eq1, float eq2, float eq3, float from, float out, float to, float in);
 
-inline float bspline(float eq0, float eq1, float eq2, float eq3, float c0, float c1, float c2, float c3);
+inline static float bspline(float eq0, float eq1, float eq2, float eq3, float c0, float c1, float c2, float c3);
 
-inline float hermite(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
+inline static float hermite(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
 
-inline float hermiteFlat(float h00, float h01, float from, float to);
+inline static float hermiteFlat(float h00, float h01, float from, float to);
 
-inline float hermiteSmooth(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
+inline static float hermiteSmooth(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
 
-inline float lerp(float s, float from, float to);
+inline static float lerpInl(float s, float from, float to);
 
 }
 

+ 1 - 1
gameplay/src/Curve.inl

@@ -28,7 +28,7 @@ inline float hermiteSmooth(float h00, float h01, float h10, float h11, float fro
     return h00 * from + h01 * to + h10 * out + h11 * in;
 }
 
-inline float lerp(float s, float from, float to)
+inline float lerpInl(float s, float from, float to)
 {
     return from + (to - from) * s;
 }

+ 2 - 1
gameplay/src/DebugNew.cpp

@@ -109,7 +109,8 @@ void* debugAlloc(std::size_t size, const char* file, int line)
 
 void debugFree(void* p)
 {
-    assert(p);
+    if (p == 0)
+        return;
 
     // Backup passed in pointer to access memory allocation record
     void* mem = ((unsigned char*)p) - sizeof(MemoryAllocationRecord);

+ 146 - 3
gameplay/src/FileSystem.cpp

@@ -1,9 +1,64 @@
 #include "Base.h"
 #include "FileSystem.h"
 
+#ifdef WIN32
+    #include <windows.h>
+    #include <tchar.h>
+    #include <stdio.h>
+#else
+    #include <dirent.h>
+    #include <sys/stat.h>
+#endif
+
+#ifdef __ANDROID__
+extern AAssetManager* __assetManager;
+#endif
+
 namespace gameplay
 {
 
+#ifdef __ANDROID__
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+void makepath(std::string path, int mode)
+{
+    std::vector<std::string> dirs;
+    while (path.length() > 0)
+    {
+        int index = path.find('/');
+        std::string dir = (index == -1 ) ? path : path.substr(0, index);
+        if (dir.length() > 0)
+            dirs.push_back(dir);
+        
+        if (index + 1 >= path.length() || index == -1)
+            break;
+            
+        path = path.substr(index + 1);
+    }
+    
+    struct stat s;
+    std::string dirPath;
+    for (unsigned int i = 0; i < dirs.size(); i++)
+    {
+        dirPath += "/";
+        dirPath += dirs[i];
+        if (stat(dirPath.c_str(), &s) != 0)
+        {
+            // Directory does not exist.
+            if (mkdir(dirPath.c_str(), 0777) != 0)
+            {
+                WARN_VARG("Failed to create directory: '%s'", dirPath.c_str());
+                return;
+            }
+        }
+    }
+    
+    return;
+}
+#endif
+
 static std::string __resourcePath("./");
 
 FileSystem::FileSystem()
@@ -24,14 +79,102 @@ const char* FileSystem::getResourcePath()
     return __resourcePath.c_str();
 }
 
+bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
+{
+    // TODO make this method work with absolute and relative paths.
+#ifdef WIN32
+    std::string path(FileSystem::getResourcePath());
+    if (dirPath && strlen(dirPath) > 0)
+    {
+        path.append(dirPath);
+    }
+    path.append("/*");
+    // Convert char to wchar
+    std::basic_string<TCHAR> wPath;
+    wPath.assign(path.begin(), path.end());
+
+    WIN32_FIND_DATA FindFileData;
+    HANDLE hFind = FindFirstFile(wPath.c_str(), &FindFileData);
+    if (hFind == INVALID_HANDLE_VALUE) 
+    {
+        return false;
+    }
+    do
+    {
+        // Add to the list if this is not a directory
+        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+        {
+            // Convert wchar to char
+            std::basic_string<TCHAR> wfilename(FindFileData.cFileName);
+            std::string filename;
+            filename.assign(wfilename.begin(), wfilename.end());
+            files.push_back(filename);
+        }
+    } while(FindNextFile(hFind, &FindFileData) != 0);
+
+    FindClose(hFind);
+    return true;
+#else
+    std::string path(FileSystem::getResourcePath());
+    if (dirPath && strlen(dirPath) > 0)
+	{
+		path.append(dirPath);
+	}
+    path.append("/.");
+    struct dirent* dp;
+    DIR* dir = opendir(path.c_str());
+    if (!dir)
+    {
+        return false;
+    }
+	while ((dp = readdir(dir)) != NULL)
+	{
+		std::string filepath(path);
+		filepath.append("/");
+		filepath.append(dp->d_name);
+
+		struct stat buf;
+		if (!stat(filepath.c_str(), &buf))
+		{
+            // Add to the list if this is not a directory
+			if (!S_ISDIR(buf.st_mode))
+			{
+				files.push_back(dp->d_name);
+			}
+		}
+	}
+	closedir(dir);
+    return true;
+#endif
+}
+
 FILE* FileSystem::openFile(const char* path, const char* mode)
 {
     std::string fullPath(__resourcePath);
     fullPath += path;
-
+    
+#ifdef __ANDROID__
+    std::string directoryPath = fullPath.substr(0, fullPath.rfind('/'));
+    struct stat s;
+    if (stat(directoryPath.c_str(), &s) != 0)
+        makepath(directoryPath.c_str(), 0777);
+
+    if (stat(fullPath.c_str(), &s) != 0)
+    {
+        AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
+        const void* data = AAsset_getBuffer(asset);
+        int length = AAsset_getLength(asset);
+        FILE* file = fopen(fullPath.c_str(), "wb");
+        
+        int ret = fwrite(data, sizeof(unsigned char), length, file);
+        assert(ret == length);
+        fclose(file);
+    }
+#endif
+    
     FILE* fp = fopen(fullPath.c_str(), mode);
-
-// Win32 doesnt support a asset or bundle definitions.
+    
+// Win32 doesn't support an asset or bundle definitions.
 #ifdef WIN32
     if (fp == NULL)
     {

+ 10 - 0
gameplay/src/FileSystem.h

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

+ 1 - 1
gameplay/src/Font.cpp

@@ -53,7 +53,7 @@ Font::Font(const Font& copy)
 Font::~Font()
 {
     // Remove this Font from the font cache.
-    std::vector<Font*>::iterator itr = find(__fontCache.begin(), __fontCache.end(), this);
+    std::vector<Font*>::iterator itr = std::find(__fontCache.begin(), __fontCache.end(), this);
     if (itr != __fontCache.end())
     {
         __fontCache.erase(itr);

+ 15 - 2
gameplay/src/Game.cpp

@@ -68,8 +68,15 @@ int Game::run(int width, int height)
     if (_state != UNINITIALIZED)
         return -1;
 
-    _width = width;
-    _height = height;
+    if (width == -1)
+        _width = Platform::getDisplayWidth();
+    else
+        _width = width;
+    
+    if (height == -1)
+        _height = Platform::getDisplayHeight();
+    else
+        _height = height;
 
     // Start up game systems.
     if (!startup())
@@ -175,6 +182,7 @@ void Game::frame()
 
     // Update the scheduled and running animations.
     _animationController->update(elapsedTime);
+    
     // Update the physics.
     _physicsController->update(elapsedTime);
     // Application Update.
@@ -250,4 +258,9 @@ void Game::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactI
 {
 }
 
+bool Game::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+{
+    return false;
+}
+
 }

+ 32 - 4
gameplay/src/Game.h

@@ -3,6 +3,7 @@
 
 #include "Keyboard.h"
 #include "Touch.h"
+#include "Mouse.h"
 #include "AudioController.h"
 #include "AnimationController.h"
 #include "PhysicsController.h"
@@ -95,8 +96,8 @@ public:
     /**
      * Call this method to initialize the game, and begin running the game.
      *
-     * @param width The width of the game window to run at.
-     * @param height The height of the game window to run at.
+     * @param width The width of the game window to run at. Default is -1 meaning native resolution width.
+     * @param height The height of the game window to run at. Default is -1 meaning native resolution height.
      * 
      * @return Zero for normal termination, or non-zero if an error occurred.
      */
@@ -184,13 +185,22 @@ public:
      * Menu callback on menu events.
      */
     virtual void menu();
-
+    
+    /**
+     * Shows or hides the virtual keyboard (if supported).
+     *
+     * @param display true when virtual keyboard needs to be displayed; false otherwise.
+     */
+     inline void displayKeyboard(bool display);
+     
     /**
      * Keyboard callback on keyPress events.
      *
      * @param evt The key event that occured.
-     * @param key The key code that was pressed, released or repeated.
+     * @param key If evt is KEY_PRESS or KEY_RELEASE then key is the key code from Keyboard::Key.
+     *            If evt is KEY_CHAR then key is the unicode value of the character.
      * 
+     * @see Keyboard::KeyEvent
      * @see Keyboard::Key
      */
     virtual void keyEvent(Keyboard::KeyEvent evt, int key);
@@ -199,11 +209,29 @@ public:
      * Touch callback on touch events.
      *
      * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
      *
      * @see Touch::TouchEvent
      */
     virtual void touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Mouse callback on mouse events. If the game does not consume the mouse move event or left mouse click event
+     * then it is interpreted as a touch event instead.
+     *
+     * @param evt The mouse event that occurred.
+     * @param x The x position of the mouse in pixels. Left edge is zero.
+     * @param y The y position of the mouse in pixels. Top edge is zero.
+     * @param wheelDelta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
+     *
+     * @return True if the mouse event is consumed or false if it is not consumed.
+     *
+     * @see Mouse::MouseEvent
+     */
+    virtual bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
+
     /**
      * Sets muli-touch is to be enabled/disabled. Default is disabled.
      *

+ 5 - 0
gameplay/src/Game.inl

@@ -61,4 +61,9 @@ inline void Game::getAccelerometerValues(float* pitch, float* roll)
     Platform::getAccelerometerValues(pitch, roll);
 }
 
+inline void Game::displayKeyboard(bool display)
+{
+    Platform::displayKeyboard(display);
+}
+
 }

+ 158 - 156
gameplay/src/Keyboard.h

@@ -20,7 +20,8 @@ public:
     enum KeyEvent
     {
         KEY_PRESS,
-        KEY_RELEASE
+        KEY_RELEASE,
+        KEY_CHAR
     };
 
     /**
@@ -28,161 +29,162 @@ public:
      */
     enum Key
     {
-        KEY_NONE,
-        KEY_PAUSE,
-        KEY_SCROLL_LOCK,
-        KEY_PRINT,
-        KEY_SYSREQ,
-        KEY_BREAK,
-        KEY_ESCAPE,
-        KEY_BACKSPACE,
-        KEY_TAB,
-        KEY_BACK_TAB,
-        KEY_RETURN,
-        KEY_CAPS_LOCK,
-        KEY_LEFT_SHIFT,
-        KEY_RIGHT_SHIFT,
-        KEY_LEFT_CTRL,
-        KEY_RIGHT_CTRL,
-        KEY_LEFT_ALT,
-        KEY_RIGHT_ALT,
-        KEY_MENU,
-        KEY_LEFT_HYPER,
-        KEY_RIGHT_HYPER,
-        KEY_INSERT,
-        KEY_HOME,
-        KEY_PG_UP,
-        KEY_DELETE,
-        KEY_END,
-        KEY_PG_DOWN,
-        KEY_LEFT_ARROW,
-        KEY_RIGHT_ARROW,
-        KEY_UP_ARROW,
-        KEY_DOWN_ARROW,
-        KEY_NUM_LOCK,
-        KEY_KP_PLUS,
-        KEY_KP_MINUS,
-        KEY_KP_MULTIPLY,
-        KEY_KP_DIVIDE,
-        KEY_KP_ENTER,
-        KEY_KP_HOME,
-        KEY_KP_UP,
-        KEY_KP_PG_UP,
-        KEY_KP_LEFT,
-        KEY_KP_FIVE,
-        KEY_KP_RIGHT,
-        KEY_KP_END,
-        KEY_KP_DOWN,
-        KEY_KP_PG_DOWN,
-        KEY_KP_INSERT,
-        KEY_KP_DELETE,
-        KEY_F1,
-        KEY_F2,
-        KEY_F3,
-        KEY_F4,
-        KEY_F5,
-        KEY_F6,
-        KEY_F7,
-        KEY_F8,
-        KEY_F9,
-        KEY_F10,
-        KEY_F11,
-        KEY_F12,
-        KEY_SPACE,
-        KEY_EXCLAM,
-        KEY_QUOTE,
-        KEY_NUMBER,
-        KEY_DOLLAR,
-        KEY_PERCENT,
-        KEY_AMPERSAND,
-        KEY_APOSTROPHE,
-        KEY_LEFT_PARENTHESIS,
-        KEY_RIGHT_PARENTHESIS,
-        KEY_ASTERISK,
-        KEY_PLUS,
-        KEY_COMMA,
-        KEY_MINUS,
-        KEY_PERIOD,
-        KEY_SLASH,
-        KEY_ZERO,
-        KEY_ONE,
-        KEY_TWO,
-        KEY_THREE,
-        KEY_FOUR,
-        KEY_FIVE,
-        KEY_SIX,
-        KEY_SEVEN,
-        KEY_EIGHT,
-        KEY_NINE,
-        KEY_COLON,
-        KEY_SEMICOLON,
-        KEY_LESS_THAN,
-        KEY_EQUAL,
-        KEY_GREATER_THAN,
-        KEY_QUESTION,
-        KEY_AT,
-        KEY_CAPITAL_A,
-        KEY_CAPITAL_B,
-        KEY_CAPITAL_C,
-        KEY_CAPITAL_D,
-        KEY_CAPITAL_E,
-        KEY_CAPITAL_F,
-        KEY_CAPITAL_G,
-        KEY_CAPITAL_H,
-        KEY_CAPITAL_I,
-        KEY_CAPITAL_J,
-        KEY_CAPITAL_K,
-        KEY_CAPITAL_L,
-        KEY_CAPITAL_M,
-        KEY_CAPITAL_N,
-        KEY_CAPITAL_O,
-        KEY_CAPITAL_P,
-        KEY_CAPITAL_Q,
-        KEY_CAPITAL_R,
-        KEY_CAPITAL_S,
-        KEY_CAPITAL_T,
-        KEY_CAPITAL_U,
-        KEY_CAPITAL_V,
-        KEY_CAPITAL_W,
-        KEY_CAPITAL_X,
-        KEY_CAPITAL_Y,
-        KEY_CAPITAL_Z,
-        KEY_LEFT_BRACKET,
-        KEY_BACK_SLASH,
-        KEY_RIGHT_BRACKET,
-        KEY_CIRCUMFLEX,
-        KEY_UNDERSCORE,
-        KEY_GRAVE,
-        KEY_A,
-        KEY_B,
-        KEY_C,
-        KEY_D,
-        KEY_E,
-        KEY_F,
-        KEY_G,
-        KEY_H,
-        KEY_I,
-        KEY_J,
-        KEY_K,
-        KEY_L,
-        KEY_M,
-        KEY_N,
-        KEY_O,
-        KEY_P,
-        KEY_Q,
-        KEY_R,
-        KEY_S,
-        KEY_T,
-        KEY_U,
-        KEY_V,
-        KEY_W,
-        KEY_X,
-        KEY_Y,
-        KEY_Z,
-        KEY_LEFT_BRACE,
-        KEY_BAR,
-        KEY_RIGHT_BRACE,
-        KEY_TILDE
+        KEY_NONE              = 0,
+        KEY_PAUSE             = 0x0013,
+        KEY_SCROLL_LOCK       = 0x1014,
+        KEY_PRINT             = 0x1061,
+        KEY_SYSREQ            = 0x106A,
+        KEY_BREAK             = 0x106B,
+        KEY_ESCAPE            = 0x001B,
+        KEY_BACKSPACE         = 0x0008,
+        KEY_TAB               = 0x0009,
+        KEY_BACK_TAB          = 0x0089,
+        KEY_RETURN            = 0x000D,
+        KEY_CAPS_LOCK         = 0x00E5,
+        KEY_SHIFT             = 0x00E1,
+        KEY_CTRL              = 0x00E3,
+        KEY_ALT               = 0x00E9,
+        KEY_MENU              = 0x1067,
+        KEY_HYPER             = 0x10ED,
+        KEY_INSERT            = 0x1063,
+        KEY_HOME              = 0x1050,
+        KEY_PG_UP             = 0x1055,
+        KEY_DELETE            = 0x10FF,
+        KEY_END               = 0x1057,
+        KEY_PG_DOWN           = 0x1056,
+        KEY_LEFT_ARROW        = 0x1051,
+        KEY_RIGHT_ARROW       = 0x1053,
+        KEY_UP_ARROW          = 0x1052,
+        KEY_DOWN_ARROW        = 0x1054,
+        KEY_NUM_LOCK          = 0x107F,
+        KEY_KP_PLUS           = 0x10AB,
+        KEY_KP_MINUS          = 0x10AD,
+        KEY_KP_MULTIPLY       = 0x10AA,
+        KEY_KP_DIVIDE         = 0x10AF,
+        KEY_KP_ENTER          = 0x108D,
+        KEY_KP_HOME           = 0x10B7,
+        KEY_KP_UP             = 0x10B8,
+        KEY_KP_PG_UP          = 0x10B9,
+        KEY_KP_LEFT           = 0x10B4,
+        KEY_KP_FIVE           = 0x10B5,
+        KEY_KP_RIGHT          = 0x10B6,
+        KEY_KP_END            = 0x10B1,
+        KEY_KP_DOWN           = 0x10B2,
+        KEY_KP_PG_DOWN        = 0x10B3,
+        KEY_KP_INSERT         = 0x10B0,
+        KEY_KP_DELETE         = 0x10AE,
+        KEY_F1                = 0x00BE,
+        KEY_F2                = 0x00BF,
+        KEY_F3                = 0x00C0,
+        KEY_F4                = 0x00C1,
+        KEY_F5                = 0x00C2,
+        KEY_F6                = 0x00C3,
+        KEY_F7                = 0x00C4,
+        KEY_F8                = 0x00C5,
+        KEY_F9                = 0x00C6,
+        KEY_F10               = 0x00C7,
+        KEY_F11               = 0x00C8,
+        KEY_F12               = 0x00C9,
+        KEY_SPACE             = ' ',
+        KEY_EXCLAM            = '!',
+        KEY_QUOTE             = '"',
+        KEY_NUMBER            = '#',
+        KEY_DOLLAR            = '$',
+        KEY_PERCENT           = '%',
+        KEY_CIRCUMFLEX        = '^',
+        KEY_AMPERSAND         = '&',
+        KEY_APOSTROPHE        = '\'',
+        KEY_LEFT_PARENTHESIS  = '(',
+        KEY_RIGHT_PARENTHESIS = ')',
+        KEY_ASTERISK          = '*',
+        KEY_PLUS              = '+',
+        KEY_COMMA             = ',',
+        KEY_MINUS             = '-',
+        KEY_PERIOD            = '.',
+        KEY_SLASH             = '/',
+        KEY_ZERO              = '0',
+        KEY_ONE               = '1',
+        KEY_TWO               = '2',
+        KEY_THREE             = '3',
+        KEY_FOUR              = '4',
+        KEY_FIVE              = '5',
+        KEY_SIX               = '6',
+        KEY_SEVEN             = '7',
+        KEY_EIGHT             = '8',
+        KEY_NINE              = '9',
+        KEY_COLON             = ':',
+        KEY_SEMICOLON         = ';',
+        KEY_LESS_THAN         = '<',
+        KEY_EQUAL             = '=',
+        KEY_GREATER_THAN      = '>',
+        KEY_QUESTION          = '?',
+        KEY_AT                = '@',
+        KEY_CAPITAL_A         = 'A',
+        KEY_CAPITAL_B         = 'B',
+        KEY_CAPITAL_C         = 'C',
+        KEY_CAPITAL_D         = 'D',
+        KEY_CAPITAL_E         = 'E',
+        KEY_CAPITAL_F         = 'F',
+        KEY_CAPITAL_G         = 'G',
+        KEY_CAPITAL_H         = 'H',
+        KEY_CAPITAL_I         = 'I',
+        KEY_CAPITAL_J         = 'J',
+        KEY_CAPITAL_K         = 'K',
+        KEY_CAPITAL_L         = 'L',
+        KEY_CAPITAL_M         = 'M',
+        KEY_CAPITAL_N         = 'N',
+        KEY_CAPITAL_O         = 'O',
+        KEY_CAPITAL_P         = 'P',
+        KEY_CAPITAL_Q         = 'Q',
+        KEY_CAPITAL_R         = 'R',
+        KEY_CAPITAL_S         = 'S',
+        KEY_CAPITAL_T         = 'T',
+        KEY_CAPITAL_U         = 'U',
+        KEY_CAPITAL_V         = 'V',
+        KEY_CAPITAL_W         = 'W',
+        KEY_CAPITAL_X         = 'X',
+        KEY_CAPITAL_Y         = 'Y',
+        KEY_CAPITAL_Z         = 'Z',
+        KEY_LEFT_BRACKET      = '[',
+        KEY_BACK_SLASH        = '\\',
+        KEY_RIGHT_BRACKET     = ']',
+        KEY_UNDERSCORE        = '_',
+        KEY_GRAVE             = '`',
+        KEY_A                 = 'a',
+        KEY_B                 = 'b',
+        KEY_C                 = 'c',
+        KEY_D                 = 'd',
+        KEY_E                 = 'e',
+        KEY_F                 = 'f',
+        KEY_G                 = 'g',
+        KEY_H                 = 'h',
+        KEY_I                 = 'i',
+        KEY_J                 = 'j',
+        KEY_K                 = 'k',
+        KEY_L                 = 'l',
+        KEY_M                 = 'm',
+        KEY_N                 = 'n',
+        KEY_O                 = 'o',
+        KEY_P                 = 'p',
+        KEY_Q                 = 'q',
+        KEY_R                 = 'r',
+        KEY_S                 = 's',
+        KEY_T                 = 't',
+        KEY_U                 = 'u',
+        KEY_V                 = 'v',
+        KEY_W                 = 'w',
+        KEY_X                 = 'x',
+        KEY_Y                 = 'y',
+        KEY_Z                 = 'z',
+        KEY_LEFT_BRACE        = '{',
+        KEY_BAR               = '|',
+        KEY_RIGHT_BRACE       = '}',
+        KEY_TILDE             = '~',
+        KEY_EURO              = 0x20AC,
+        KEY_POUND             = 0x00A3,
+        KEY_YEN               = 0x00A5,
+        KEY_MIDDLE_DOT        = 0x0095,
+        KEY_SEARCH            = 0xFFAA
     };
 
 private:

+ 98 - 18
gameplay/src/MaterialParameter.cpp

@@ -304,7 +304,7 @@ unsigned int MaterialParameter::getAnimationPropertyComponentCount(int propertyI
                     return 0;
                 case FLOAT:
                 case INT:
-                    return 1;
+                    return _count;
                 case VECTOR2:
                     return 2 * _count;
                 case VECTOR3:
@@ -329,10 +329,30 @@ void MaterialParameter::getAnimationPropertyValue(int propertyId, AnimationValue
             switch (_type)
             {
                 case FLOAT:
-                    value->setFloat(0, _value.floatValue);
+                    if (_count == 1)
+                    {
+                        value->setFloat(0, _value.floatValue);
+                    }
+                    else
+                    {
+                        for (unsigned int i = 0; i < _count; i++)
+                        {
+                            value->setFloat(i, _value.floatPtrValue[i]);
+                        }
+                    }
                     break;
                 case INT:
-                    value->setFloat(0, _value.intValue);
+                    if (_count == 1)
+                    {
+                        value->setFloat(0, _value.intValue);
+                    }
+                    else
+                    {
+                        for (unsigned int i = 0; i < _count; i++)
+                        {
+                            value->setFloat(i, _value.intPtrValue[i]);
+                        }
+                    }
                     break;
                 case VECTOR2:
                     for (unsigned int i = 0; i < _count; i++)
@@ -359,8 +379,10 @@ void MaterialParameter::getAnimationPropertyValue(int propertyId, AnimationValue
     }
 }
 
-void MaterialParameter::setAnimationPropertyValue(int propertyId, AnimationValue* value)
+void MaterialParameter::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
 {
+    assert(blendWeight >= 0.0f && blendWeight <= 1.0f);
+
     switch (propertyId)
     {
         case ANIMATE_UNIFORM:
@@ -368,29 +390,70 @@ void MaterialParameter::setAnimationPropertyValue(int propertyId, AnimationValue
             switch (_type)
             {
                 case FLOAT:
-                    _value.floatValue = value->getFloat(0);
+                {
+                    if (_count == 1)
+                    {
+                        if ((_animationPropertyBitFlag & ANIMATION_UNIFORM_BIT) != ANIMATION_UNIFORM_BIT)
+                        {
+                            _animationPropertyBitFlag |= ANIMATION_UNIFORM_BIT;
+                            _value.floatValue = value->getFloat(0);
+                        }
+                        else
+                        {
+                            _value.floatValue = Curve::lerp(blendWeight, _value.floatValue, value->getFloat(0));
+                        }
+                    }
+                    else
+                    {
+                        applyAnimationValue(value, blendWeight, 1);
+                    }                    
                     break;
+                }
                 case INT:
-                    _value.intValue = value->getFloat(0);
-                    break;
-                case VECTOR2:
-                    for (unsigned int i = 0; i < _count; i++)
+                {
+                    if (_count == 1)
                     {
-                        value->getFloat(_value.floatPtrValue, i * 2, 2);
+                        if ((_animationPropertyBitFlag & ANIMATION_UNIFORM_BIT) != ANIMATION_UNIFORM_BIT)
+                        {
+                            _animationPropertyBitFlag |= ANIMATION_UNIFORM_BIT;
+                            _value.intValue = value->getFloat(0);
+                        }
+                        else
+                        {
+                            _value.intValue = Curve::lerp(blendWeight, _value.intValue, value->getFloat(0));
+                        }
                     }
-                    break;
-                case VECTOR3:
-                    for (unsigned int i = 0; i < _count; i++)
+                    else
                     {
-                        value->getFloat(_value.floatPtrValue, i * 3, 3);
+                        if ((_animationPropertyBitFlag & ANIMATION_UNIFORM_BIT) != ANIMATION_UNIFORM_BIT)
+                        {
+                            _animationPropertyBitFlag |= ANIMATION_UNIFORM_BIT;
+                            for (unsigned int i = 0; i < _count; i++)
+                                _value.intPtrValue[i] = value->getFloat(i);
+                        }
+                        else
+                        {
+                            for (unsigned int i = 0; i < _count; i++)
+                                _value.intPtrValue[i] = Curve::lerp(blendWeight, _value.intPtrValue[i], value->getFloat(i));
+                        }
                     }
                     break;
+                }
+                case VECTOR2:
+                {
+                    applyAnimationValue(value, blendWeight, 2);
+                    break;
+                }
+                case VECTOR3:
+                {
+                    applyAnimationValue(value, blendWeight, 3);
+                    break;
+                }
                 case VECTOR4:
-                    for (unsigned int i = 0; i < _count; i++)
-                    {
-                        value->getFloat(_value.floatPtrValue, i * 4, 4);
-                    }
+                {
+                    applyAnimationValue(value, blendWeight, 4);
                     break;
+                }
 
                 // UNSUPPORTED: NONE, MATRIX, METHOD, SAMPLER 
             }
@@ -398,4 +461,21 @@ void MaterialParameter::setAnimationPropertyValue(int propertyId, AnimationValue
     }
 }
 
+void MaterialParameter::applyAnimationValue(AnimationValue* value, float blendWeight, int components)
+{
+    unsigned int count = _count * components;
+    if ((_animationPropertyBitFlag & ANIMATION_UNIFORM_BIT) != ANIMATION_UNIFORM_BIT)
+    {
+        _animationPropertyBitFlag |= ANIMATION_UNIFORM_BIT;
+
+        for (unsigned int i = 0; i < count; i++)
+            _value.floatPtrValue[i] = value->getFloat(i);
+    }
+    else
+    {
+        for (unsigned int i = 0; i < count; i++)
+            _value.floatPtrValue[i] = Curve::lerp(blendWeight, _value.floatPtrValue[i], value->getFloat(i));
+    }
+}
+
 }

+ 5 - 1
gameplay/src/MaterialParameter.h

@@ -164,7 +164,7 @@ public:
     /**
      * @see AnimationTarget#setAnimationProperty
      */
-    void setAnimationPropertyValue(int propertyId, AnimationValue* value);
+    void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
 
 private:
 
@@ -253,6 +253,10 @@ private:
         METHOD
     } _type;
 
+    static const char ANIMATION_UNIFORM_BIT = 0x01;
+
+    void applyAnimationValue(AnimationValue* value, float blendWeight, int components);
+
     unsigned int _count;
     bool _dynamic;
     std::string _name;

+ 1 - 3
gameplay/src/Matrix.cpp

@@ -460,7 +460,7 @@ bool Matrix::decompose(Vector3* scale, Quaternion* rotation, Vector3* translatio
     // Now calculate the rotation from the resulting matrix (axes).
     float trace = xaxis.x + yaxis.y + zaxis.z + 1.0f;
 
-    if (trace > MATH_TOLERANCE)
+    if (trace > MATH_EPSILON)
     {
         float s = 0.5f / sqrt(trace);
         rotation->w = 0.25f / s;
@@ -635,8 +635,6 @@ bool Matrix::invert(Matrix* dst) const
     inverse.m[14] = -m[12] * a3 + m[13] * a1 - m[14] * a0;
     inverse.m[15] = m[8] * a3 - m[9] * a1 + m[10] * a0;
 
-    memcpy(dst->m, inverse.m, MATRIX_SIZE);
-
     multiply(inverse, 1.0f / det, dst);
 
     return true;

+ 9 - 9
gameplay/src/Matrix.h

@@ -831,7 +831,7 @@ public:
      * @param m The matrix to add.
      * @return The matrix sum.
      */
-    inline Matrix operator+(const Matrix& m) const;
+    inline const Matrix operator+(const Matrix& m) const;
     
     /**
      * Adds the given matrix to this matrix.
@@ -842,14 +842,14 @@ public:
     inline Matrix& operator+=(const Matrix& m);
 
     /**
-     * Calculates the sum of this matrix with the given matrix.
+     * Calculates the difference of this matrix with the given matrix.
      * 
      * Note: this does not modify this matrix.
      * 
-     * @param m The matrix to add.
-     * @return The matrix sum.
+     * @param m The matrix to subtract.
+     * @return The matrix difference.
      */
-    inline Matrix operator-(const Matrix& m) const;
+    inline const Matrix operator-(const Matrix& m) const;
 
     /**
      * Subtracts the given matrix from this matrix.
@@ -866,7 +866,7 @@ public:
      * 
      * @return The negation of this matrix.
      */
-    inline Matrix operator-() const;
+    inline const Matrix operator-() const;
 
     /**
      * Calculates the matrix product of this matrix with the given matrix.
@@ -876,7 +876,7 @@ public:
      * @param m The matrix to multiply by.
      * @return The matrix product.
      */
-    inline Matrix operator*(const Matrix& m) const;
+    inline const Matrix operator*(const Matrix& m) const;
 
     /**
      * Right-multiplies this matrix by the given matrix.
@@ -907,7 +907,7 @@ inline Vector3& operator*=(Vector3& v, const Matrix& m);
  * @param v The vector to transform.
  * @return The resulting transformed vector.
  */
-inline Vector3 operator*(const Matrix& m, const Vector3& v);
+inline const Vector3 operator*(const Matrix& m, const Vector3& v);
 
 /**
  * Transforms the given vector by the given matrix.
@@ -929,7 +929,7 @@ inline Vector4& operator*=(Vector4& v, const Matrix& m);
  * @param v The vector to transform.
  * @return The resulting transformed vector.
  */
-inline Vector4 operator*(const Matrix& m, const Vector4& v);
+inline const Vector4 operator*(const Matrix& m, const Vector4& v);
 
 }
 

+ 6 - 6
gameplay/src/Matrix.inl

@@ -3,7 +3,7 @@
 namespace gameplay
 {
 
-inline Matrix Matrix::operator+(const Matrix& m) const
+inline const Matrix Matrix::operator+(const Matrix& m) const
 {
     Matrix result(*this);
     result.add(m);
@@ -16,7 +16,7 @@ inline Matrix& Matrix::operator+=(const Matrix& m)
     return *this;
 }
 
-inline Matrix Matrix::operator-(const Matrix& m) const
+inline const Matrix Matrix::operator-(const Matrix& m) const
 {
     Matrix result(*this);
     result.subtract(m);
@@ -29,14 +29,14 @@ inline Matrix& Matrix::operator-=(const Matrix& m)
     return *this;
 }
 
-inline Matrix Matrix::operator-() const
+inline const Matrix Matrix::operator-() const
 {
     Matrix m(*this);
     m.negate();
     return m;
 }
 
-inline Matrix Matrix::operator*(const Matrix& m) const
+inline const Matrix Matrix::operator*(const Matrix& m) const
 {
     Matrix result(*this);
     result.multiply(m);
@@ -55,7 +55,7 @@ inline Vector3& operator*=(Vector3& v, const Matrix& m)
     return v;
 }
 
-inline Vector3 operator*(const Matrix& m, const Vector3& v)
+inline const Vector3 operator*(const Matrix& m, const Vector3& v)
 {
     Vector3 x;
     m.transformVector(v, &x);
@@ -68,7 +68,7 @@ inline Vector4& operator*=(Vector4& v, const Matrix& m)
     return v;
 }
 
-inline Vector4 operator*(const Matrix& m, const Vector4& v)
+inline const Vector4 operator*(const Matrix& m, const Vector4& v)
 {
     Vector4 x;
     m.transformVector(v, &x);

+ 40 - 0
gameplay/src/Mouse.h

@@ -0,0 +1,40 @@
+#ifndef MOUSE_H_
+#define MOUSE_H_
+
+namespace gameplay
+{
+
+/**
+ * Mouse event
+ */
+class Mouse
+{
+public:
+
+    /**
+     * The mouse event type.
+     */
+    enum MouseEvent
+    {
+        MOUSE_PRESS_LEFT_BUTTON,
+        MOUSE_RELEASE_LEFT_BUTTON,
+        MOUSE_PRESS_MIDDLE_BUTTON,
+        MOUSE_RELEASE_MIDDLE_BUTTON,
+        MOUSE_PRESS_RIGHT_BUTTON,
+        MOUSE_RELEASE_RIGHT_BUTTON,
+        MOUSE_MOVE,
+        MOUSE_WHEEL
+    };
+
+
+private:
+
+    /**
+     * Constructor. Used internally.
+     */
+    Mouse();
+};
+
+}
+
+#endif

+ 60 - 46
gameplay/src/Package.cpp

@@ -66,12 +66,50 @@ bool Package::readArray(unsigned int* length, T** ptr)
     }
     if (*length > 0)
     {
-       *ptr = new T[*length];
-       if (fread(*ptr, sizeof(T), *length, _file) != *length)
-       {
-           SAFE_DELETE_ARRAY(*ptr);
-           return false;
-       }
+        *ptr = new T[*length];
+        if (fread(*ptr, sizeof(T), *length, _file) != *length)
+        {
+            SAFE_DELETE_ARRAY(*ptr);
+            return false;
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool Package::readArray(unsigned int* length, std::vector<T>* values)
+{
+    if (!read(length))
+    {
+        return false;
+    }
+    if (*length > 0 && values)
+    {
+        values->resize(*length);
+        if (fread(&(*values)[0], sizeof(T), *length, _file) != *length)
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool Package::readArray(unsigned int* length, std::vector<T>* values, unsigned int readSize)
+{
+    assert(sizeof(T) >= readSize);
+
+    if (!read(length))
+    {
+        return false;
+    }
+    if (*length > 0 && values)
+    {
+        values->resize(*length);
+        if (fread(&(*values)[0], readSize, *length, _file) != *length)
+        {
+            return false;
+        }
     }
     return true;
 }
@@ -87,20 +125,16 @@ std::string readString(FILE* fp)
     // Sanity check to detect if string length is far too big
     assert(length < PACKAGE_MAX_STRING_LENGTH);
 
-    char* str = new char[length + 1];
+    std::string str;
     if (length > 0)
     {
-        if (fread(str, 1, length, fp) != length)
+        str.resize(length);
+        if (fread(&str[0], 1, length, fp) != length)
         {
-            SAFE_DELETE_ARRAY(str);
             return std::string();
         }
     }
-
-    str[length] = '\0';
-    std::string result(str);
-    SAFE_DELETE_ARRAY(str);
-    return result;
+    return str;
 }
 
 Package* Package::create(const char* path)
@@ -907,11 +941,11 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
         }
     }
 
-    unsigned long* keyTimes = NULL;
-    float* values = NULL;
-    float* tangentsIn = NULL;
-    float* tangentsOut = NULL;
-    unsigned int* interpolation = NULL;
+    std::vector<unsigned long> keyTimes;
+    std::vector<float> values;
+    std::vector<float> tangentsIn;
+    std::vector<float> tangentsOut;
+    std::vector<unsigned long> interpolation;
 
     // length of the arrays
     unsigned int keyTimesCount;
@@ -921,10 +955,9 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     unsigned int interpolationCount;
 
     // read key times
-    if (!readArray(&keyTimesCount, &keyTimes))
+    if (!readArray(&keyTimesCount, &keyTimes, sizeof(unsigned int)))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "keyTimes", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
         return NULL;
     }
     
@@ -932,8 +965,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&valuesCount, &values))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "values", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
         return NULL;
     }
     
@@ -941,9 +972,6 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&tangentsInCount, &tangentsIn))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "tangentsIn", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
-        SAFE_DELETE_ARRAY(tangentsIn);
         return NULL;
     }
     
@@ -951,22 +979,13 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     if (!readArray(&tangentsOutCount, &tangentsOut))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "tangentsOut", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
-        SAFE_DELETE_ARRAY(tangentsIn);
-        SAFE_DELETE_ARRAY(tangentsOut);
         return NULL;
     }
     
     // read interpolations
-    if (!readArray(&interpolationCount, &interpolation))
+    if (!readArray(&interpolationCount, &interpolation, sizeof(unsigned int)))
     {
         LOG_ERROR_VARG("Failed to read %s for %s: %s", "interpolation", "animation", id);
-        SAFE_DELETE_ARRAY(keyTimes);
-        SAFE_DELETE_ARRAY(values);
-        SAFE_DELETE_ARRAY(tangentsIn);
-        SAFE_DELETE_ARRAY(tangentsOut);
-        SAFE_DELETE_ARRAY(interpolation);
         return NULL;
     }
 
@@ -976,23 +995,18 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
     // TODO: Handle other target attributes later.
     if (targetAttribute > 0)
     {
+        assert(keyTimes.size() > 0 && values.size() > 0);
         if (animation == NULL)
         {
             // TODO: This code currently assumes LINEAR only
-            animation = controller->createAnimation(animationId, target, targetAttribute, keyTimesCount, keyTimes, values, Curve::LINEAR);
+            animation = controller->createAnimation(animationId, target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
         }
         else
         {
-            animation->createChannel(target, targetAttribute, keyTimesCount, keyTimes, values, Curve::LINEAR);
+            animation->createChannel(target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
         }
     }
 
-    SAFE_DELETE_ARRAY(keyTimes);
-    SAFE_DELETE_ARRAY(values);
-    SAFE_DELETE_ARRAY(tangentsIn);
-    SAFE_DELETE_ARRAY(tangentsOut);
-    SAFE_DELETE_ARRAY(interpolation);
-
     return animation;
 }
 
@@ -1075,7 +1089,7 @@ Mesh* Package::loadMesh(const char* id, bool loadWithMeshRBSupport, const char*
     }
     mesh->setVertexData(vertexData, 0, vertexCount);
     if (loadWithMeshRBSupport)
-        SceneLoader::addMeshRigidBodyData(nodeId, mesh, vertexData, vertexByteCount);
+        SceneLoader::addMeshRigidBodyData(_path, nodeId, mesh, vertexData, vertexByteCount);
     SAFE_DELETE_ARRAY(vertexData);
 
     // Set mesh bounding volumes
@@ -1136,7 +1150,7 @@ Mesh* Package::loadMesh(const char* id, bool loadWithMeshRBSupport, const char*
         }
         part->setIndexData(indexData, 0, indexCount);
         if (loadWithMeshRBSupport)
-            SceneLoader::addMeshRigidBodyData(nodeId, indexData, iByteCount);
+            SceneLoader::addMeshRigidBodyData(_path, nodeId, indexData, iByteCount);
         SAFE_DELETE_ARRAY(indexData);
     }
 

+ 23 - 0
gameplay/src/Package.h

@@ -252,6 +252,29 @@ private:
     template <class T>
     bool readArray(unsigned int* length, T** ptr);
 
+    /**
+     * Reads an array of values and the array length from the current file position.
+     * 
+     * @param length A pointer to where the length of the array will be copied to.
+     * @param values A pointer to the vector to copy the values to. The vector will be resized if it is smaller than length.
+     * 
+     * @return True if successful, false if an error occurred.
+     */
+    template <class T>
+    bool readArray(unsigned int* length, std::vector<T>* values);
+
+    /**
+     * Reads an array of values and the array length from the current file position.
+     * 
+     * @param length A pointer to where the length of the array will be copied to.
+     * @param values A pointer to the vector to copy the values to. The vector will be resized if it is smaller than length.
+     * @param readSize The size that reads will be preformed at, size must be the same as or smaller then the sizeof(T)
+     * 
+     * @return True if successful, false if an error occurred.
+     */
+    template <class T>
+    bool readArray(unsigned int* length, std::vector<T>* values, unsigned int readSize);
+    
     /**
      * Reads 16 floats from the current file position.
      *

+ 1 - 1
gameplay/src/PhysicsConstraint.cpp

@@ -118,7 +118,7 @@ btTransform PhysicsConstraint::getTransformOffset(const Node* node, const Vector
     
     t = offsetByCenterOfMass(node, t);
 
-    return btTransform(btQuaternion(r.x, r.y, r.z, r.w), btVector3(t.x, t.y, t.z));
+    return btTransform(BQ(r), BV(t));
 }
 
 Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)

+ 289 - 139
gameplay/src/PhysicsController.cpp

@@ -11,6 +11,10 @@
 namespace gameplay
 {
 
+const int PhysicsController::DIRTY         = 0x01;
+const int PhysicsController::COLLISION     = 0x02;
+const int PhysicsController::REGISTERED    = 0x04;
+
 PhysicsController::PhysicsController()
   : _collisionConfiguration(NULL), _dispatcher(NULL),
     _overlappingPairCache(NULL), _solver(NULL), _world(NULL), _debugDrawer(NULL), 
@@ -114,7 +118,7 @@ void PhysicsController::setGravity(const Vector3& gravity)
     _gravity = gravity;
 
     if (_world)
-        _world->setGravity(btVector3(_gravity.x, _gravity.y, _gravity.z));
+        _world->setGravity(BV(_gravity));
 }
 
 void PhysicsController::drawDebug(const Matrix& viewProjection)
@@ -124,6 +128,83 @@ void PhysicsController::drawDebug(const Matrix& viewProjection)
     _debugDrawer->end();
 }
 
+PhysicsRigidBody* PhysicsController::rayTest(const Ray& ray)
+{
+    btCollisionWorld::ClosestRayResultCallback callback(BV(ray.getOrigin()), BV(ray.getDirection()));
+    _world->rayTest(BV(ray.getOrigin()), BV(ray.getDirection()), callback);
+    if (callback.hasHit())
+        return getRigidBody(callback.m_collisionObject);
+
+    return NULL;
+}
+
+btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, 
+    const btCollisionObject* b, int partIdB, int indexB)
+{
+    // Get pointers to the PhysicsRigidBody objects.
+    PhysicsRigidBody* rbA = Game::getInstance()->getPhysicsController()->getRigidBody(a);
+    PhysicsRigidBody* rbB = Game::getInstance()->getPhysicsController()->getRigidBody(b);
+    
+    // If the given rigid body pair has collided in the past, then
+    // we notify the listeners only if the pair was not colliding
+    // during the previous frame. Otherwise, it's a new pair, so add a
+    // new entry to the cache with the appropriate listeners and notify them.
+    PhysicsRigidBody::CollisionPair pair(rbA, rbB);
+    if (_collisionStatus.count(pair) > 0)
+    {
+        const CollisionInfo& collisionInfo = _collisionStatus[pair];
+        if ((collisionInfo._status & COLLISION) == 0)
+        {
+            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = collisionInfo._listeners.begin();
+            for (; iter != collisionInfo._listeners.end(); iter++)
+            {
+                (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                    Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+            }
+        }
+    }
+    else
+    {
+        CollisionInfo& collisionInfo = _collisionStatus[pair];
+
+        // Add the appropriate listeners.
+        PhysicsRigidBody::CollisionPair p1(pair._rbA, NULL);
+        if (_collisionStatus.count(p1) > 0)
+        {
+            const CollisionInfo& ci = _collisionStatus[p1];
+            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = ci._listeners.begin();
+            for (; iter != ci._listeners.end(); iter++)
+            {
+                collisionInfo._listeners.push_back(*iter);
+            }
+        }
+        PhysicsRigidBody::CollisionPair p2(pair._rbB, NULL);
+        if (_collisionStatus.count(p2) > 0)
+        {
+            const CollisionInfo& ci = _collisionStatus[p2];
+            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = ci._listeners.begin();
+            for (; iter != ci._listeners.end(); iter++)
+            {
+                collisionInfo._listeners.push_back(*iter);
+            }
+        }
+
+        std::vector<PhysicsRigidBody::Listener*>::iterator iter = collisionInfo._listeners.begin();
+        for (; iter != collisionInfo._listeners.end(); iter++)
+        {
+            (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+        }
+    }
+
+    // Update the collision status cache (we remove the dirty bit
+    // set in the controller's update so that this particular collision pair's
+    // status is not reset to 'no collision' when the controller's update completes).
+    _collisionStatus[pair]._status &= ~DIRTY;
+    _collisionStatus[pair]._status |= COLLISION;
+    return 0.0f;
+}
+
 void PhysicsController::initialize()
 {
     _collisionConfiguration = new btDefaultCollisionConfiguration();
@@ -133,7 +214,7 @@ void PhysicsController::initialize()
 
     // Create the world.
     _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
-    _world->setGravity(btVector3(_gravity.x, _gravity.y, _gravity.z));
+    _world->setGravity(BV(_gravity));
 
     // Set up debug drawing.
     _debugDrawer = new DebugDrawer();
@@ -217,67 +298,57 @@ void PhysicsController::update(long elapsedTime)
     // set to COLLISION and the DIRTY bit is cleared. Then, after collision processing 
     // is finished, if a given status is still dirty, the COLLISION bit is cleared.
 
-    // Dirty all the collision listeners' collision status caches.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Dirty the collision status cache entries.
+    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end(); iter++)
     {
-        if (_bodies[i]->_listeners)
-        {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
-            {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
-                {
-                    iter->second |= PhysicsRigidBody::Listener::DIRTY;
-                }
-            }
-        }
+        iter->second._status |= DIRTY;
     }
 
-    // Go through the physics rigid bodies and update the collision listeners.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Go through the collision status cache and perform all registered collision tests.
+    iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end(); iter++)
     {
-        if (_bodies[i]->_listeners)
+        // If this collision pair was one that was registered for listening, then perform the collision test.
+        // (In the case where we register for all collisions with a rigid body, there will be a lot
+        // of collision pairs in the status cache that we did not explicitly register for.)
+        if ((iter->second._status & REGISTERED) != 0)
         {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
-            {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
-                {
-                    // If this collision pair was one that was registered for listening, then perform the collision test.
-                    // (In the case where we register for all collisions with a rigid body, there will be a lot
-                    // of collision pairs in the status cache that we did not explicitly register for.)
-                    if ((iter->second & PhysicsRigidBody::Listener::REGISTERED) != 0)
-                    {
-                        if (iter->first._rbB)
-                            Game::getInstance()->getPhysicsController()->_world->contactPairTest(iter->first._rbA->_body, iter->first._rbB->_body, *(*_bodies[i]->_listeners)[k]);
-                        else
-                            Game::getInstance()->getPhysicsController()->_world->contactTest(iter->first._rbA->_body, *(*_bodies[i]->_listeners)[k]);
-                    }
-                }   
-            }
+            if (iter->first._rbB)
+                _world->contactPairTest(iter->first._rbA->_body, iter->first._rbB->_body, *this);
+            else
+                _world->contactTest(iter->first._rbA->_body, *this);
         }
     }
 
-    // Go through all the collision listeners and update their collision status caches.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Update all the collision status cache entries.
+    iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end(); iter++)
     {
-        if (_bodies[i]->_listeners)
+        if ((iter->second._status & DIRTY) != 0)
         {
-            for (unsigned int k = 0; k < _bodies[i]->_listeners->size(); k++)
+            if ((iter->second._status & COLLISION) != 0 && iter->first._rbB)
             {
-                std::map<PhysicsRigidBody::CollisionPair, int>::iterator iter = (*_bodies[i]->_listeners)[k]->_collisionStatus.begin();
-                for (; iter != (*_bodies[i]->_listeners)[k]->_collisionStatus.end(); iter++)
+                unsigned int size = iter->second._listeners.size();
+                for (unsigned int i = 0; i < size; i++)
                 {
-                    if ((iter->second & PhysicsRigidBody::Listener::DIRTY) != 0)
-                    {
-                        iter->second &= ~PhysicsRigidBody::Listener::COLLISION;
-                    }
+                    iter->second._listeners[i]->collisionEvent(PhysicsRigidBody::Listener::NOT_COLLIDING, iter->first);
                 }
             }
+
+            iter->second._status &= ~COLLISION;
         }
     }
 }
-    
+
+void PhysicsController::addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
+{
+    // Add the listener and ensure the status includes that this collision pair is registered.
+    PhysicsRigidBody::CollisionPair pair(rbA, rbB);
+    _collisionStatus[pair]._listeners.push_back(listener);
+    if ((_collisionStatus[pair]._status & PhysicsController::REGISTERED) == 0)
+        _collisionStatus[pair]._status |= PhysicsController::REGISTERED;
+}
 
 void PhysicsController::addRigidBody(PhysicsRigidBody* body)
 {
@@ -297,6 +368,47 @@ void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
             break;
         }
     }
+
+    // Find the rigid body's collision shape and release the rigid body's reference to it.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape == rigidBody->_shape)
+        {
+            if (_shapes[i]->getRefCount() == 1)
+            {
+                _shapes[i]->release();
+                _shapes.erase(_shapes.begin() + i);
+            }
+            else
+                _shapes[i]->release();
+
+            break;
+        }
+    }
+
+    // Remove the rigid body from the controller's list.
+    for (unsigned int i = 0; i < _bodies.size(); i++)
+    {
+        if (_bodies[i] == rigidBody)
+        {
+            _bodies.erase(_bodies.begin() + i);
+            break;
+        }
+    }
+
+    // Find all references to the rigid body in the collision status cache and remove them.
+    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
+    for (; iter != _collisionStatus.end();)
+    {
+        if (iter->first._rbA == rigidBody || iter->first._rbB == rigidBody)
+        {
+            std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator eraseIter = iter;
+            iter++;
+            _collisionStatus.erase(eraseIter);
+        }
+        else
+            iter++;
+    }
 }
 
 PhysicsRigidBody* PhysicsController::getRigidBody(const btCollisionObject* collisionObject)
@@ -311,39 +423,93 @@ PhysicsRigidBody* PhysicsController::getRigidBody(const btCollisionObject* colli
     return NULL;
 }
 
-btCollisionShape* PhysicsController::createBox(const Vector3& min, const Vector3& max, const btVector3& scale)
+btCollisionShape* PhysicsController::createBox(const Vector3& min, const Vector3& max, const Vector3& scale)
 {
-    btVector3 halfExtents(scale.x() * 0.5 * abs(max.x - min.x), scale.y() * 0.5 * abs(max.y - min.y), scale.z() * 0.5 * abs(max.z - min.z));
+    btVector3 halfExtents(scale.x * 0.5 * abs(max.x - min.x), scale.y * 0.5 * abs(max.y - min.y), scale.z * 0.5 * abs(max.z - min.z));
+
+    // Return the box shape from the cache if it already exists.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape->getShapeType() == BOX_SHAPE_PROXYTYPE)
+        {
+            btBoxShape* box = static_cast<btBoxShape*>(_shapes[i]->_shape);
+            if (box->getHalfExtentsWithMargin() == halfExtents)
+            {
+                _shapes[i]->addRef();
+                return box;
+            }
+        }
+    }
+    
+    // Create the box shape and add it to the cache.
     btBoxShape* box = bullet_new<btBoxShape>(halfExtents);
-    _shapes.push_back(box);
+    _shapes.push_back(new PhysicsCollisionShape(box));
 
     return box;
 }
 
-btCollisionShape* PhysicsController::createSphere(float radius, const btVector3& scale)
+btCollisionShape* PhysicsController::createCapsule(float radius, float height)
+{
+    // Return the capsule shape from the cache if it already exists.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)
+        {
+            btCapsuleShape* capsule = static_cast<btCapsuleShape*>(_shapes[i]->_shape);
+            if (capsule->getRadius() == radius && capsule->getHalfHeight() == 0.5f * height)
+            {
+                _shapes[i]->addRef();
+                return capsule;
+            }
+        }
+    }
+    
+    // Create the capsule shape and add it to the cache.
+    btCapsuleShape* capsule = bullet_new<btCapsuleShape>(radius, height);
+    _shapes.push_back(new PhysicsCollisionShape(capsule));
+
+    return capsule;
+}
+
+btCollisionShape* PhysicsController::createSphere(float radius, const Vector3& scale)
 {
     // Since sphere shapes depend only on the radius, the best we can do is take
     // the largest dimension and apply that as the uniform scale to the rigid body.
-    float uniformScale = scale.x();
-    if (uniformScale < scale.y())
-        uniformScale = scale.y();
-    if (uniformScale < scale.z())
-        uniformScale = scale.z();
+    float uniformScale = scale.x;
+    if (uniformScale < scale.y)
+        uniformScale = scale.y;
+    if (uniformScale < scale.z)
+        uniformScale = scale.z;
     
+    // Return the sphere shape from the cache if it already exists.
+    for (unsigned int i = 0; i < _shapes.size(); i++)
+    {
+        if (_shapes[i]->_shape->getShapeType() == SPHERE_SHAPE_PROXYTYPE)
+        {
+            btSphereShape* sphere = static_cast<btSphereShape*>(_shapes[i]->_shape);
+            if (sphere->getRadius() == uniformScale * radius)
+            {
+                _shapes[i]->addRef();
+                return sphere;
+            }
+        }
+    }
+
+    // Create the sphere shape and add it to the cache.
     btSphereShape* sphere = bullet_new<btSphereShape>(uniformScale * radius);
-    _shapes.push_back(sphere);
+    _shapes.push_back(new PhysicsCollisionShape(sphere));
     
     return sphere;
 }
 
-btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
+btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body, const Vector3& scale)
 {
     // Retrieve the mesh rigid body data from the loaded scene.
     const SceneLoader::MeshRigidBodyData* data = SceneLoader::getMeshRigidBodyData(body->_node->getId());
 
     // Copy the scaled vertex position data to the rigid body's local buffer.
     Matrix m;
-    Matrix::createScale(body->_node->getScaleX(), body->_node->getScaleY(), body->_node->getScaleZ(), &m);
+    Matrix::createScale(scale, &m);
     unsigned int vertexCount = data->mesh->getVertexCount();
     body->_vertexData = new float[vertexCount * 3];
     Vector3 v;
@@ -396,7 +562,7 @@ btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
             indexedMesh.m_numTriangles = meshPart->getIndexCount() / 3;
             indexedMesh.m_numVertices = meshPart->getIndexCount();
             indexedMesh.m_triangleIndexBase = (const unsigned char*)body->_indexData[i];
-            indexedMesh.m_triangleIndexStride = indexStride;
+            indexedMesh.m_triangleIndexStride = indexStride*3;
             indexedMesh.m_vertexBase = (const unsigned char*)body->_vertexData;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexType = PHY_FLOAT;
@@ -431,7 +597,7 @@ btCollisionShape* PhysicsController::createMesh(PhysicsRigidBody* body)
     }
 
     btBvhTriangleMeshShape* shape = bullet_new<btBvhTriangleMeshShape>(meshInterface, true);
-    _shapes.push_back(shape);
+    _shapes.push_back(new PhysicsCollisionShape(shape));
 
     return shape;
 }
@@ -480,103 +646,87 @@ void PhysicsController::removeConstraint(PhysicsConstraint* constraint)
     
 PhysicsController::DebugDrawer::DebugDrawer()
     : _mode(btIDebugDraw::DBG_DrawAabb | btIDebugDraw::DBG_DrawConstraintLimits | btIDebugDraw::DBG_DrawConstraints | 
-       btIDebugDraw::DBG_DrawContactPoints | btIDebugDraw::DBG_DrawWireframe), _effect(NULL), _positionAttrib(0), _colorAttrib(0),
-       _viewProjectionMatrixUniform(NULL), _viewProjection(NULL), _vertexData(NULL), _vertexCount(0), _vertexDataSize(0)
+       btIDebugDraw::DBG_DrawContactPoints | btIDebugDraw::DBG_DrawWireframe), _viewProjection(NULL), _meshBatch(NULL)
 {
-    // Unused
+    // Vertex shader for drawing colored lines.
+    const char* vs_str = 
+    {
+        "uniform mat4 u_viewProjectionMatrix;\n"
+        "attribute vec4 a_position;\n"
+        "attribute vec4 a_color;\n"
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "    v_color = a_color;\n"
+        "    gl_Position = u_viewProjectionMatrix * a_position;\n"
+        "}"
+    };
+        
+    // Fragment shader for drawing colored lines.
+    const char* fs_str = 
+    {
+    #ifdef OPENGL_ES
+        "precision highp float;\n"
+    #endif
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "   gl_FragColor = v_color;\n"
+        "}"
+    };
+        
+    Effect* effect = Effect::createFromSource(vs_str, fs_str);
+    Material* material = Material::create(effect);
+
+    VertexFormat::Element elements[] =
+    {
+        VertexFormat::Element(VertexFormat::POSITION, 3),
+        VertexFormat::Element(VertexFormat::COLOR, 4),
+    };
+    _meshBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
+    
+    SAFE_RELEASE(material);
+    SAFE_RELEASE(effect);
 }
 
 PhysicsController::DebugDrawer::~DebugDrawer()
 {
-    SAFE_RELEASE(_effect);
-    SAFE_DELETE_ARRAY(_vertexData);
+    SAFE_DELETE(_meshBatch);
 }
 
 void PhysicsController::DebugDrawer::begin(const Matrix& viewProjection)
 {
     _viewProjection = &viewProjection;
-    _vertexCount = 0;
+    _meshBatch->begin();
 }
 
 void PhysicsController::DebugDrawer::end()
 {
-    // Lazy load the effect for drawing.
-    if (!_effect)
-    {
-        // Vertex shader for drawing colored lines.
-        const char* vs_str = 
-        {
-            "uniform mat4 u_viewProjectionMatrix;\n"
-            "attribute vec4 a_position;\n"
-            "attribute vec4 a_color;\n"
-            "varying vec4 v_color;\n"
-            "void main(void) {\n"
-            "    v_color = a_color;\n"
-            "    gl_Position = u_viewProjectionMatrix * a_position;\n"
-            "}"
-        };
-        
-        // Fragment shader for drawing colored lines.
-        const char* fs_str = 
-        {
-        #ifdef OPENGL_ES
-            "precision highp float;\n"
-        #endif
-            "varying vec4 v_color;\n"
-            "void main(void) {\n"
-            "   gl_FragColor = v_color;\n"
-            "}"
-        };
-        
-        _effect = Effect::createFromSource(vs_str, fs_str);
-        _positionAttrib = _effect->getVertexAttribute("a_position");
-        _colorAttrib = _effect->getVertexAttribute("a_color");
-        _viewProjectionMatrixUniform = _effect->getUniform("u_viewProjectionMatrix");
-    }
-    
-    // Bind the effect and set the vertex attributes.
-    _effect->bind();
-    GL_ASSERT( glEnableVertexAttribArray(_positionAttrib) );
-    GL_ASSERT( glEnableVertexAttribArray(_colorAttrib) );
-    GL_ASSERT( glVertexAttribPointer(_positionAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, _vertexData) );
-    GL_ASSERT( glVertexAttribPointer(_colorAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 7, &_vertexData[3]) );
-    
-    // Set the camera's view projection matrix and draw.
-    _effect->setValue( _viewProjectionMatrixUniform, _viewProjection);
-    GL_ASSERT( glDrawArrays(GL_LINES, 0, _vertexCount / 7) );
+    _meshBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_viewProjection);
+    _meshBatch->draw();
+    _meshBatch->end();
 }
 
 void PhysicsController::DebugDrawer::drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor)
 {
-    // Allocate extra space in the vertex data batch if it is needed.
-    if (_vertexDataSize - _vertexCount < 14)
-    {
-        if (_vertexDataSize > 0)
-        {
-            unsigned int newVertexDataSize = _vertexDataSize * 2;
-            float* newVertexData = new float[newVertexDataSize];
-            memcpy(newVertexData, _vertexData, _vertexDataSize * sizeof(float));
-            SAFE_DELETE_ARRAY(_vertexData);
-            _vertexData = newVertexData;
-            _vertexDataSize = newVertexDataSize;
-        }
-        else
-        {
-            _vertexDataSize = INITIAL_CAPACITY;
-            _vertexData = new float[_vertexDataSize];
-        }
-    }
+    static DebugDrawer::DebugVertex fromVertex, toVertex;
     
-    // Create the vertex data for the line and copy it into the batch.
-    float vertexData[] = 
-    {
-        from.getX(), from.getY(), from.getZ(), 
-        fromColor.getX(), fromColor.getY(), fromColor.getZ(), 1.0f,
-        to.getX(), to.getY(), to.getZ(),
-        toColor.getX(), toColor.getY(), toColor.getZ(), 1.0f
-    };
-    memcpy(&_vertexData[_vertexCount], vertexData, sizeof(float) * 14);
-    _vertexCount += 14;
+    fromVertex.x = from.getX();
+    fromVertex.y = from.getY();
+    fromVertex.z = from.getZ();
+    fromVertex.r = fromColor.getX();
+    fromVertex.g = fromColor.getY();
+    fromVertex.b = fromColor.getZ();
+    fromVertex.a = 1.0f;
+
+    toVertex.x = to.getX();
+    toVertex.y = to.getY();
+    toVertex.z = to.getZ();
+    toVertex.r = toColor.getX();
+    toVertex.g = toColor.getY();
+    toVertex.b = toColor.getZ();
+    toVertex.a = 1.0f;
+
+    _meshBatch->add(&fromVertex, 1);
+    _meshBatch->add(&toVertex, 1);
 }
 
 void PhysicsController::DebugDrawer::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
@@ -609,4 +759,4 @@ int	PhysicsController::DebugDrawer::getDebugMode() const
     return _mode;
 }
 
-}
+}

+ 57 - 14
gameplay/src/PhysicsController.h

@@ -15,7 +15,7 @@ namespace gameplay
 /**
  * Defines a class for controlling game physics.
  */
-class PhysicsController
+class PhysicsController : public btCollisionWorld::ContactResultCallback
 {
     friend class Game;
     friend class PhysicsConstraint;
@@ -189,8 +189,44 @@ public:
      */
     void drawDebug(const Matrix& viewProjection);
 
+    /**
+     * Gets the first rigid body that the given ray intersects.
+     * 
+     * @param ray The ray to test intersection with.
+     * @return The first rigid body that the ray intersects.
+     */
+    PhysicsRigidBody* rayTest(const Ray& ray);
+
+protected:
+
+    /**
+     * Internal function used for Bullet integration (do not use or override).
+     */
+    btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, const btCollisionObject* b, int partIdB, int indexB);    
+
 private:
 
+    // Internal constants for the collision status cache.
+    static const int DIRTY;
+    static const int COLLISION;
+    static const int REGISTERED;
+
+    // Represents the collision listeners and status for a given collision pair (used by the collision status cache).
+    struct CollisionInfo
+    {
+        std::vector<PhysicsRigidBody::Listener*> _listeners;
+        int _status;
+    };
+
+    // Wraps Bullet collision shapes (used for implementing shape caching).
+    struct PhysicsCollisionShape : public Ref
+    {
+        PhysicsCollisionShape(btCollisionShape* shape) : _shape(shape) {}
+        ~PhysicsCollisionShape() { SAFE_DELETE(_shape); }
+
+        btCollisionShape* _shape;
+    };
+
     /**
      * Constructor.
      */
@@ -226,6 +262,9 @@ private:
      */
     void update(long elapsedTime);
 
+    // Adds the given collision listener for the two given rigid bodies.
+    void addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB);
+
     // Adds the given rigid body to the world.
     void addRigidBody(PhysicsRigidBody* body);
     
@@ -236,13 +275,16 @@ private:
     PhysicsRigidBody* getRigidBody(const btCollisionObject* collisionObject);
     
     // Creates a box collision shape to be used in the creation of a rigid body.
-    btCollisionShape* createBox(const Vector3& min, const Vector3& max, const btVector3& scale);
+    btCollisionShape* createBox(const Vector3& min, const Vector3& max, const Vector3& scale);
+
+    // Creates a capsule collision shape to be used in the creation of a rigid body.
+    btCollisionShape* createCapsule(float radius, float height);
 
     // Creates a sphere collision shape to be used in the creation of a rigid body.
-    btCollisionShape* createSphere(float radius, const btVector3& scale);
+    btCollisionShape* createSphere(float radius, const Vector3& scale);
 
     // Creates a triangle mesh collision shape to be used in the creation of a rigid body.
-    btCollisionShape* createMesh(PhysicsRigidBody* body);
+    btCollisionShape* createMesh(PhysicsRigidBody* body, const Vector3& scale);
 
     // Sets up the given constraint for the given two rigid bodies.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -258,6 +300,12 @@ private:
     {
     public:
 
+        struct DebugVertex
+        {
+            float x, y, z;
+            float r, g, b, a;
+        };
+
         DebugDrawer();        
         ~DebugDrawer();
         
@@ -268,7 +316,7 @@ private:
         void drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor);        
         void drawLine(const btVector3& from, const btVector3& to, const btVector3& color);        
         void drawContactPoint(const btVector3& pointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color);        
-        void reportErrorWarning(const char* warningString);        
+        void reportErrorWarning(const char* warningString);
         void draw3dText(const btVector3& location, const char* textString);        
         void setDebugMode(int mode);        
         int	getDebugMode() const;
@@ -276,14 +324,8 @@ private:
     private:
         
         int _mode;
-        Effect* _effect;
-        VertexAttribute _positionAttrib;
-        VertexAttribute _colorAttrib;
-        Uniform* _viewProjectionMatrixUniform;
         const Matrix* _viewProjection;
-        float* _vertexData;
-        unsigned int _vertexCount;
-        unsigned int _vertexDataSize;
+        MeshBatch* _meshBatch;
     };
     
     btDefaultCollisionConfiguration* _collisionConfiguration;
@@ -291,14 +333,15 @@ private:
     btBroadphaseInterface* _overlappingPairCache;
     btSequentialImpulseConstraintSolver* _solver;
     btDynamicsWorld* _world;
-    btAlignedObjectArray<btCollisionShape*> _shapes;
+    std::vector<PhysicsCollisionShape*> _shapes;
     DebugDrawer* _debugDrawer;
     Listener::EventType _status;
     std::vector<Listener*>* _listeners;
     std::vector<PhysicsRigidBody*> _bodies;
     Vector3 _gravity;
+    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo> _collisionStatus;  
 };
 
 }
 
-#endif
+#endif

+ 3 - 3
gameplay/src/PhysicsGenericConstraint.cpp

@@ -45,13 +45,13 @@ PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, const Qu
         b->getNode()->getWorldMatrix().getScale(&sB);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
 
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
-        btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), btVector3(tB.x, tB.y, tB.z));
+        btTransform frameInA(BQ(rotationOffsetA), BV(tA));
+        btTransform frameInB(BQ(rotationOffsetB), BV(tB));
         _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
     }
     else
     {
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
+        btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         _constraint = new btGeneric6DofConstraint(*a->_body, frameInA, true);
     }
 }

+ 8 - 8
gameplay/src/PhysicsGenericConstraint.inl

@@ -45,42 +45,42 @@ inline const Vector3& PhysicsGenericConstraint::getTranslationOffsetB() const
 
 inline void PhysicsGenericConstraint::setAngularLowerLimit(const Vector3& limits)
 {
-    ((btGeneric6DofConstraint*)_constraint)->setAngularLowerLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setAngularLowerLimit(BV(limits));
 }
 
 inline void PhysicsGenericConstraint::setAngularUpperLimit(const Vector3& limits)
 {
-    ((btGeneric6DofConstraint*)_constraint)->setAngularUpperLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setAngularUpperLimit(BV(limits));
 }
 
 inline void PhysicsGenericConstraint::setLinearLowerLimit(const Vector3& limits)
 {
-    ((btGeneric6DofConstraint*)_constraint)->setLinearLowerLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setLinearLowerLimit(BV(limits));
 }
     
 inline void PhysicsGenericConstraint::setLinearUpperLimit(const Vector3& limits)
 {
-    ((btGeneric6DofConstraint*)_constraint)->setLinearUpperLimit(btVector3(limits.x, limits.y, limits.z));
+    ((btGeneric6DofConstraint*)_constraint)->setLinearUpperLimit(BV(limits));
 }
 
 inline void PhysicsGenericConstraint::setRotationOffsetA(const Quaternion& rotationOffset)
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setRotation(btQuaternion(rotationOffset.x, rotationOffset.y, rotationOffset.z, rotationOffset.w));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setRotation(BQ(rotationOffset));
 }
 
 inline void PhysicsGenericConstraint::setRotationOffsetB(const Quaternion& rotationOffset)
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setRotation(btQuaternion(rotationOffset.x, rotationOffset.y, rotationOffset.z, rotationOffset.w));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setRotation(BQ(rotationOffset));
 }
 
 inline void PhysicsGenericConstraint::setTranslationOffsetA(const Vector3& translationOffset)
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setOrigin(btVector3(translationOffset.x, translationOffset.y, translationOffset.z));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetA().setOrigin(BV(translationOffset));
 }
 
 inline void PhysicsGenericConstraint::setTranslationOffsetB(const Vector3& translationOffset)
 {
-    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setOrigin(btVector3(translationOffset.x, translationOffset.y, translationOffset.z));
+    static_cast<btGeneric6DofConstraint*>(_constraint)->getFrameOffsetB().setOrigin(BV(translationOffset));
 }
 
 }

+ 3 - 3
gameplay/src/PhysicsHingeConstraint.cpp

@@ -27,13 +27,13 @@ PhysicsHingeConstraint::PhysicsHingeConstraint(PhysicsRigidBody* a, const Quater
         b->getNode()->getWorldMatrix().getScale(&sB);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
 
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
-        btTransform frameInB(btQuaternion(rotationOffsetB.x, rotationOffsetB.y, rotationOffsetB.z, rotationOffsetB.w), btVector3(tB.x, tB.y, tB.z));
+        btTransform frameInA(BQ(rotationOffsetA), BV(tA));
+        btTransform frameInB(BQ(rotationOffsetB), BV(tB));
         _constraint = new btHingeConstraint(*a->_body, *b->_body, frameInA, frameInB);
     }
     else
     {
-        btTransform frameInA(btQuaternion(rotationOffsetA.x, rotationOffsetA.y, rotationOffsetA.z, rotationOffsetA.w), btVector3(tA.x, tA.y, tA.z));
+        btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         _constraint = new btHingeConstraint(*a->_body, frameInA);
     }
 }

+ 4 - 5
gameplay/src/PhysicsMotionState.cpp

@@ -9,7 +9,7 @@ PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOf
     if (centerOfMassOffset)
     {
         // Store the center of mass offset.
-        _centerOfMassOffset.setOrigin(btVector3(centerOfMassOffset->x, centerOfMassOffset->y, centerOfMassOffset->z));
+        _centerOfMassOffset.setOrigin(BV(*centerOfMassOffset));
     }
 
     updateTransformFromNode();
@@ -49,17 +49,16 @@ void PhysicsMotionState::updateTransformFromNode() const
     {
         // When there is a center of mass offset, we modify the initial world transformation
         // so that when physics is initially applied, the object is in the correct location.
-        btQuaternion orientation(rotation.x, rotation.y, rotation.z, rotation.w);
-        btTransform offset = btTransform(orientation, btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
+        btTransform offset = btTransform(BQ(rotation), btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
 
         btVector3 origin(m.m[12] + _centerOfMassOffset.getOrigin().getX() + offset.getOrigin().getX(), 
                          m.m[13] + _centerOfMassOffset.getOrigin().getY() + offset.getOrigin().getY(), 
                          m.m[14] + _centerOfMassOffset.getOrigin().getZ() + offset.getOrigin().getZ());
-        _worldTransform = btTransform(orientation, origin);
+        _worldTransform = btTransform(BQ(rotation), origin);
     }
     else
     {
-        _worldTransform = btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w), btVector3(m.m[12], m.m[13], m.m[14]));
+        _worldTransform = btTransform(BQ(rotation), btVector3(m.m[12], m.m[13], m.m[14]));
     }
 }
 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.