Przeglądaj źródła

Implement the transform property.

Markus Schöngart 11 lat temu
rodzic
commit
0ac598617e
58 zmienionych plików z 6007 dodań i 500 usunięć
  1. 1 1
      Build/CMakeLists.txt
  2. 348 330
      Build/cmake/FileList.cmake
  3. 66 60
      Build/cmake/SampleFileList.cmake
  4. 1 1
      Build/cmake/gen_samplelists.sh
  5. 14 0
      Include/Rocket/Core/Context.h
  6. 42 0
      Include/Rocket/Core/Element.h
  7. 18 0
      Include/Rocket/Core/ElementUtilities.h
  8. 7 0
      Include/Rocket/Core/Event.h
  9. 496 0
      Include/Rocket/Core/Matrix4.h
  10. 733 0
      Include/Rocket/Core/Matrix4.inl
  11. 14 10
      Include/Rocket/Core/Property.h
  12. 150 0
      Include/Rocket/Core/Reference.h
  13. 9 0
      Include/Rocket/Core/RenderInterface.h
  14. 20 0
      Include/Rocket/Core/StyleSheetKeywords.h
  15. 92 0
      Include/Rocket/Core/Transform.h
  16. 326 0
      Include/Rocket/Core/TransformPrimitive.h
  17. 135 0
      Include/Rocket/Core/TransformState.h
  18. 13 0
      Include/Rocket/Core/TypeConverter.inl
  19. 23 2
      Include/Rocket/Core/Types.h
  20. 12 0
      Include/Rocket/Core/Variant.h
  21. 12 0
      Include/Rocket/Core/Variant.inl
  22. 139 0
      Include/Rocket/Core/Vector3.h
  23. 195 0
      Include/Rocket/Core/Vector3.inl
  24. 143 0
      Include/Rocket/Core/Vector4.h
  25. 201 0
      Include/Rocket/Core/Vector4.inl
  26. 86 0
      Include/Rocket/Core/ViewState.h
  27. 2 0
      Samples/basic/drag/src/main.cpp
  28. 108 0
      Samples/basic/transform/data/transform.rml
  29. 193 0
      Samples/basic/transform/src/main.cpp
  30. 2 0
      Samples/invaders/src/main.cpp
  31. 11 0
      Samples/shell/include/ShellRenderInterfaceOpenGL.h
  32. 74 4
      Samples/shell/src/ShellRenderInterfaceOpenGL.cpp
  33. 1 0
      Samples/shell/src/x11/ShellX11.cpp
  34. 37 6
      Source/Core/Context.cpp
  35. 4 4
      Source/Core/DecoratorTiledInstancer.cpp
  36. 537 1
      Source/Core/Element.cpp
  37. 71 35
      Source/Core/ElementStyle.cpp
  38. 17 0
      Source/Core/ElementStyle.h
  39. 112 0
      Source/Core/ElementUtilities.cpp
  40. 39 1
      Source/Core/Event.cpp
  41. 1 1
      Source/Core/FontEffectOutlineInstancer.cpp
  42. 2 2
      Source/Core/FontEffectShadowInstancer.cpp
  43. 2 0
      Source/Core/PropertyDefinition.cpp
  44. 49 9
      Source/Core/PropertyParserNumber.cpp
  45. 24 1
      Source/Core/PropertyParserNumber.h
  46. 282 0
      Source/Core/PropertyParserTransform.cpp
  47. 76 0
      Source/Core/PropertyParserTransform.h
  48. 10 0
      Source/Core/RenderInterface.cpp
  49. 9 0
      Source/Core/StringCache.cpp
  50. 9 0
      Source/Core/StringCache.h
  51. 58 30
      Source/Core/StyleSheetSpecification.cpp
  52. 120 0
      Source/Core/Transform.cpp
  53. 217 0
      Source/Core/TransformPrimitive.cpp
  54. 346 0
      Source/Core/TransformState.cpp
  55. 42 2
      Source/Core/Variant.cpp
  56. 55 0
      Source/Core/Vector3.cpp
  57. 55 0
      Source/Core/Vector4.cpp
  58. 146 0
      Source/Core/ViewState.cpp

+ 1 - 1
Build/CMakeLists.txt

@@ -205,7 +205,7 @@ endmacro()
 if(BUILD_SAMPLES)
     include(SampleFileList)
 
-    set(samples treeview customlog drag loaddocument)
+    set(samples treeview customlog drag loaddocument transform)
     set(tutorials template datagrid datagrid_tree tutorial_drag)
     
     set(sample_LIBRARIES

+ 348 - 330
Build/cmake/FileList.cmake

@@ -1,396 +1,412 @@
 # This file was auto-generated with gen_filelists.sh
 
 set(Core_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstOfType.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.h
-	${PROJECT_SOURCE_DIR}/Source/Core/ElementStyleCache.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementHandle.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancerDefault.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyChild.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNoneInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontal.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImageInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorEmpty.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetParser.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerTemplate.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyShorthandDefinition.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthOfType.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementTextDefault.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelector.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadowInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastOfType.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRow.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementBackground.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserString.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.h
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNode.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Clock.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelector.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyOfType.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImage.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastChild.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontFamily.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DebugFont.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthOfType.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayout.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TemplateCache.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontalInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastChild.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementHandle.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/EventDispatcher.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserString.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerTemplate.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBox.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyleCache.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastOfType.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutEngine.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDecoration.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Pool.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TemplateCache.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Template.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/EventIterators.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerBody.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImage.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StringCache.h
     ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSlider.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBoxText.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceLayer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementImage.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFamily.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLParseTools.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSliderScroll.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceHandle.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastChild.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstChild.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutLineBox.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DebugFont.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNone.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNoneInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureDatabase.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRow.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVertical.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthChild.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRectangle.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBox.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutlineInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.h
     ${PROJECT_SOURCE_DIR}/Source/Core/FontFace.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayout.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancerDefault.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRectangle.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstChild.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstOfType.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceLayer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementBorder.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerHead.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDecoration.h
     ${PROJECT_SOURCE_DIR}/Source/Core/StreamFile.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutEngine.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNone.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastOfType.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerHead.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceHandle.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyShorthandDefinition.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementTextDefault.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Template.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutLineBox.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLParseTools.h
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetFactory.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastOfType.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerDefault.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyChild.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBoxText.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorEmpty.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSliderScroll.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontal.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutlineInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthChild.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementImage.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/EventIterators.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/EventDispatcher.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImageInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNone.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontalInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StringCache.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNoneInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyOfType.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserTransform.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerBody.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerDefault.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Clock.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureDatabase.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetParser.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadowInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNoneInstancer.h
 )
 
 set(Core_PUB_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FontEffect.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/GeometryUtilities.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/EventListenerInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Platform.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/TypeConverter.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementScroll.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/SystemInterface.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Colour.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Box.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Debug.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementUtilities.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Transform.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ConvolutionFilter.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/EventListenerInstancer.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementInstancerGeneric.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FileInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FontDatabase.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Element.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Colour.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/MathTypes.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Vertex.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertySpecification.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Property.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Plugin.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementReference.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StreamMemory.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/WString.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/XMLParser.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/EventListener.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyDefinition.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Decorator.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Texture.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Event.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Box.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Variant.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyDictionary.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Log.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/TransformState.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementReference.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Stream.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyParser.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Header.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ContextInstancer.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StyleSheet.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Math.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FontGlyph.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ReferenceCountable.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StringUtilities.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Vertex.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementUtilities.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Factory.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Stream.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/GeometryUtilities.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Vector2.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StyleSheetSpecification.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/RenderInterface.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StyleSheetKeywords.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Font.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Decorator.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Vector3.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Core.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FontDatabase.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Header.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Dictionary.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Types.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/XMLParser.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StringBase.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementDocument.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/BaseXMLParser.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Debug.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/EventInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/String.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/XMLNodeHandler.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/URL.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Input.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Event.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/RenderInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementInstancerGeneric.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ViewState.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FileInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Factory.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyDefinition.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Plugin.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Vector2.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementScroll.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Geometry.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Font.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Vector4.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ElementText.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/String.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Element.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ScriptInterface.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StringBase.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/EventInstancer.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/DecoratorInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StringUtilities.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Context.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Input.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FontEffect.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/BaseXMLParser.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ReferenceCountable.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/WString.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/SystemInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/TransformPrimitive.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Texture.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Types.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Matrix4.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StreamMemory.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/DecoratorInstancer.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ScriptInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Property.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Dictionary.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StyleSheetKeywords.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/StyleSheetSpecification.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Reference.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/FontEffectInstancer.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Variant.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Math.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Log.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Platform.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/XMLNodeHandler.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/PropertyParser.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/ContextInstancer.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core.h
 )
 
 set(Core_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Core/StreamMemory.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVertical.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancerDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementHandle.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerBody.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureDatabase.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetParser.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Core.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Template.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandler.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/String.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ReferenceCountable.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastOfType.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementBackground.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontal.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/EventDispatcher.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Texture.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/EventListenerInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/RenderInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Transform.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerBody.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Element.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StringCache.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementUtilities.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/TemplateCache.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Event.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Clock.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyChild.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Dictionary.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDecoration.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffect.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerTemplate.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ConvolutionFilter.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerHead.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Decorator.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserString.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureDatabase.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRectangle.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StringUtilities.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastOfType.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNone.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/BaseXMLParser.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Box.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDefinition.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelector.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Math.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementText.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetSpecification.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNone.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/RenderInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBoxText.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayout.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TransformState.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDictionary.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Context.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastChild.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutLineBox.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceLayer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNoneInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertySpecification.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementReference.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Box.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserTransform.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ViewState.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLParseTools.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/LayoutEngine.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSlider.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Property.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.cpp
-	${PROJECT_SOURCE_DIR}/Source/Core/ElementStyleCache.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNode.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Log.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNoneInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Element.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementBackground.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDecoration.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBox.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutlineInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontDatabase.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Texture.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TemplateCache.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementScroll.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceLayer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FileInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastChild.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetFactory.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastChild.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSlider.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Vector4.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceHandle.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandler.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Factory.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImage.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TransformPrimitive.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/String.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDefinition.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/WString.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNoneInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFace.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Vector2.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNode.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDocument.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorEmpty.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImageInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/FontFamily.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/WString.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/URL.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadowInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontalInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNone.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Plugin.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstChild.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectNone.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementHandle.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StreamFile.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Dictionary.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImage.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementUtilities.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRow.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertySpecification.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/FontFaceHandle.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/SystemInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementBorder.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Plugin.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutLineBox.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRectangle.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ReferenceCountable.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLParser.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerHead.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Geometry.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/URL.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancerDefault.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Context.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontDatabase.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Template.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Variant.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthOfType.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Core.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheet.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Stream.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/UnicodeRange.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontalInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Vector3.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetFactory.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Decorator.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ConvolutionFilter.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontFace.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StreamMemory.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImageInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerDefault.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastChild.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementImage.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelector.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/GeometryUtilities.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSliderScroll.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLParseTools.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Event.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/SystemInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayout.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerTemplate.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDocument.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetParser.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontal.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorInstancer.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstOfType.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadowInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementText.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Property.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyChild.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBoxText.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FontEffect.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Vector2.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/FileInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVertical.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyleCache.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Clock.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/WidgetSliderScroll.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetSpecification.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/ElementTextDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerDefault.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Stream.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/XMLParser.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheet.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstChild.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StringUtilities.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Log.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Variant.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/EventDispatcher.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorEmpty.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/ElementBorder.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthChild.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Geometry.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementReference.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserString.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Factory.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBox.cpp
 )
 
 set(Controls_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetDropDown.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRange.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeSubmit.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSliderInput.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputSingleLine.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInput.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeButton.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSlider.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputMultiLine.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTabSet.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTextArea.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeCheckbox.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeSubmit.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRadio.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSlider.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeText.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/ElementTextSelection.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRange.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/InputType.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInput.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRadio.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTabSet.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerDataGrid.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTextArea.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputMultiLine.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputSingleLinePassword.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeText.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetDropDown.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeButton.h
 )
 
 set(Controls_PUB_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataQuery.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlDataSelect.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlTextArea.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementTabSet.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/Controls.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlSelect.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementForm.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGridRow.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGridCell.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/SelectOption.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlInput.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControl.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGridExpandButton.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataFormatter.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlTextArea.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/Header.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementTabSet.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataSource.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataSourceListener.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGrid.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGridExpandButton.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGridRow.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControl.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlDataSelect.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/Clipboard.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataFormatter.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataSourceListener.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementForm.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementDataGridCell.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/Controls.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlSelect.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/ElementFormControlInput.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls/DataQuery.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Controls.h
 )
 
 set(Controls_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Controls/SelectOption.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputSingleLinePassword.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerDataGrid.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTextArea.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetDropDown.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementTabSet.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControlDataSelect.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGridRow.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSliderInput.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGridExpandButton.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRadio.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/DataSource.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputSingleLine.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTabSet.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGridCell.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSlider.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControlTextArea.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/DataFormatter.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/Clipboard.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputMultiLine.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/DataSourceListener.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSliderInput.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControlDataSelect.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeSubmit.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInput.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Controls.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRadio.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGridRow.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControlSelect.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetSlider.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGridExpandButton.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/DataQuery.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeButton.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeSubmit.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeText.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeCheckbox.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetDropDown.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Controls.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementForm.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementTabSet.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControl.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/InputType.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTextArea.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControlInput.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGrid.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/SelectOption.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerDataGrid.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/ElementTextSelection.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/XMLNodeHandlerTabSet.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/DataQuery.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementForm.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeButton.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/InputTypeRange.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGridCell.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControl.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/WidgetTextInputSingleLine.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/DataFormatter.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/DataSource.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementDataGrid.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/DataSourceListener.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/ElementFormControlSelect.cpp
 )
 
 set(Debugger_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementLog.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/SystemInterface.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementContextHook.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/BeaconSource.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/CommonSource.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/InfoSource.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/Plugin.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/LogSource.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/BeaconSource.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/Geometry.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/MenuSource.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementContextHook.h
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/CommonSource.h
     ${PROJECT_SOURCE_DIR}/Source/Debugger/FontSource.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/SystemInterface.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/MenuSource.h
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/LogSource.h
 )
 
 set(Debugger_PUB_HDR_FILES
@@ -400,77 +416,79 @@ set(Debugger_PUB_HDR_FILES
 )
 
 set(Debugger_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.cpp
     ${PROJECT_SOURCE_DIR}/Source/Debugger/Debugger.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementLog.cpp
     ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementContextHook.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Debugger/SystemInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementLog.cpp
     ${PROJECT_SOURCE_DIR}/Source/Debugger/Plugin.cpp
     ${PROJECT_SOURCE_DIR}/Source/Debugger/Geometry.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Debugger/SystemInterface.cpp
 )
 
 set(Pycore_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextDocumentProxy.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventListenerInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementInterface.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementDocumentWrapper.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextProxy.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventListener.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementAttributeProxy.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/Module.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventWrapper.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInterface.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementStyleProxy.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInterface.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextProxy.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/DataSourceWrapper.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInstancer.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/Converters.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementDocumentWrapper.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementInterface.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementStyleProxy.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/precompiled.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInterface.h
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementChildrenProxy.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInstancer.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementAttributeProxy.h
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInstancer.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventWrapper.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInterface.h
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextDocumentProxy.h
 )
 
 set(Pycore_PUB_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/VectorInterface.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/Wrapper.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/NameIndexInterface.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/ElementInstancer.h
-    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/PickleTypeConverter.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/ElementWrapper.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/Utilities.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/VectorInterface.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/Header.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/Wrapper.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/ElementInstancer.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/Python.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/WrapperIter.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/NameIndexInterface.h
+    ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/PickleTypeConverter.h
     ${PROJECT_SOURCE_DIR}/Include/Rocket/Core/Python/ConverterScriptObject.h
 )
 
 set(Pycore_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementChildrenProxy.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventListenerInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementAttributeProxy.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventListener.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Utilities.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Interfaces.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/DataSourceWrapper.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/precompiled.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementStyleProxy.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Interfaces.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextProxy.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementDocumentWrapper.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Converters.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Module.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventWrapper.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementAttributeProxy.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Utilities.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextDocumentProxy.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ContextInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Module.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementInterface.cpp
     ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/EventWrapper.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/Converters.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementDocumentWrapper.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementStyleProxy.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Core/Python/ElementChildrenProxy.cpp
 )
 
 set(Pycontrols_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataFormatterWrapper.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/SelectOptionProxy.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/Module.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataSourceWrapper.h
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataFormatterWrapper.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/ElementInterface.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/Module.h
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/SelectOptionProxy.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/precompiled.h
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataGridRowProxy.h
 )
@@ -479,12 +497,12 @@ set(Pycontrols_PUB_HDR_FILES
 )
 
 set(Pycontrols_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/precompiled.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataGridRowProxy.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataSourceWrapper.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/Module.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/precompiled.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/SelectOptionProxy.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataFormatterWrapper.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/Module.cpp
     ${PROJECT_SOURCE_DIR}/Source/Controls/Python/ElementInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataGridRowProxy.cpp
+    ${PROJECT_SOURCE_DIR}/Source/Controls/Python/DataFormatterWrapper.cpp
 )
 

+ 66 - 60
Build/cmake/SampleFileList.cmake

@@ -14,13 +14,13 @@ set(directx_HDR_FILES
 )
 
 set(directx_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/directx/src/main.cpp
     ${PROJECT_SOURCE_DIR}/Samples/basic/directx/src/RenderInterfaceDirectX.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/basic/directx/src/main.cpp
 )
 
 set(drag_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/DragListener.h
     ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/Inventory.h
+    ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/DragListener.h
 )
 
 set(drag_SRC_FILES
@@ -37,18 +37,18 @@ set(loaddocument_SRC_FILES
 )
 
 set(ogre3d_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RenderInterfaceOgre3D.h
     ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RocketApplication.h
+    ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RenderInterfaceOgre3D.h
     ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RocketFrameListener.h
     ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/SystemInterfaceOgre3D.h
 )
 
 set(ogre3d_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/main.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RenderInterfaceOgre3D.cpp
     ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RocketApplication.cpp
     ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RocketFrameListener.cpp
     ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/SystemInterfaceOgre3D.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/main.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/basic/ogre3d/src/RenderInterfaceOgre3D.cpp
 )
 
 set(treeview_HDR_FILES
@@ -62,107 +62,114 @@ set(treeview_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/src/main.cpp
 )
 
+set(transform_HDR_FILES
+)
+
+set(transform_SRC_FILES
+    ${PROJECT_SOURCE_DIR}/Samples/basic/transform/src/main.cpp
+)
+
 set(invaders_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorDefender.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerDefender.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerStarfield.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorStarfield.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Defender.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/ElementGame.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Event.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandler.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerHighScore.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventManager.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Shield.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerOptions.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerStartGame.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresNameFormatter.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerStarfield.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresShipFormatter.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventInstancer.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventManager.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerStartGame.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandler.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/ElementGame.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Defender.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorStarfield.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Game.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/GameDetails.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerDefender.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScores.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresNameFormatter.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresShipFormatter.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Invader.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Mothership.h
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Shield.h
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Sprite.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/GameDetails.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Mothership.h
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Invader.h
 )
 
 set(invaders_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorDefender.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerDefender.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerStarfield.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorStarfield.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Defender.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/ElementGame.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Event.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandler.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerHighScore.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerOptions.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerStartGame.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventInstancer.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventManager.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Game.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/GameDetails.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Game.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Mothership.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerOptions.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerHighScore.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerStarfield.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScores.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Sprite.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerStartGame.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresNameFormatter.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorStarfield.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventInstancer.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandler.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresShipFormatter.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Defender.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Shield.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Invader.cpp
     ${PROJECT_SOURCE_DIR}/Samples/invaders/src/main.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Mothership.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Shield.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Sprite.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorDefender.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Event.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/ElementGame.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventManager.cpp
 )
 
 set(pyinvaders_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorDefender.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorInstancerDefender.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/PythonInterface.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Shield.h
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorInstancerStarfield.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorStarfield.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Defender.h
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/ElementGame.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Defender.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorStarfield.h
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Game.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/GameDetails.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorInstancerDefender.h
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/HighScores.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Invader.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Mothership.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/PythonInterface.h
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Shield.h
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Sprite.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/GameDetails.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Mothership.h
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Invader.h
 )
 
 set(pyinvaders_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorDefender.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorInstancerDefender.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/GameDetails.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Game.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Mothership.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorInstancerStarfield.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/HighScores.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Sprite.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorStarfield.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Defender.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/ElementGame.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Game.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/GameDetails.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/HighScores.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Shield.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Invader.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/main.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Mothership.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/DecoratorDefender.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/ElementGame.cpp
     ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/PythonInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Shield.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/pyinvaders/src/Sprite.cpp
 )
 
 set(shell_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/Input.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/Shell.h
     ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellFileInterface.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellOpenGL.h
     ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellRenderInterfaceOpenGL.h
+    ${PROJECT_SOURCE_DIR}/Samples/shell/include/Shell.h
+    ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellOpenGL.h
     ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellSystemInterface.h
+    ${PROJECT_SOURCE_DIR}/Samples/shell/include/Input.h
 )
 
 set(shell_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Samples/shell/src/Input.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellSystemInterface.cpp
     ${PROJECT_SOURCE_DIR}/Samples/shell/src/Shell.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellFileInterface.cpp
     ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellRenderInterfaceOpenGL.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellSystemInterface.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellFileInterface.cpp
 )
 
 set(template_HDR_FILES
@@ -179,25 +186,25 @@ set(datagrid_HDR_FILES
 )
 
 set(datagrid_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorDefender.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorInstancerDefender.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/HighScores.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/main.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorDefender.cpp
 )
 
 set(datagrid_tree_HDR_FILES
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorDefender.h
+    ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScoresShipFormatter.h
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.h
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScores.h
-    ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScoresShipFormatter.h
 )
 
 set(datagrid_tree_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScores.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScoresShipFormatter.cpp
     ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/main.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp
 )
 
 set(tutorial_drag_HDR_FILES
@@ -235,4 +242,3 @@ else()
                ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/InputX11.h
        )
 endif()
-

+ 1 - 1
Build/cmake/gen_samplelists.sh

@@ -7,7 +7,7 @@ hdr='set(sample_HDR_FILES'
 srcdir='${PROJECT_SOURCE_DIR}'
 srcpath=Samples
 samples=('basic/customlog' 'basic/directx' 'basic/drag' 'basic/loaddocument'
-        'basic/ogre3d' 'basic/treeview' 'invaders' 'pyinvaders' 'shell'
+        'basic/ogre3d' 'basic/treeview' 'basic/transform' 'invaders' 'pyinvaders' 'shell'
 	'tutorial/template' 'tutorial/datagrid' 'tutorial/datagrid_tree' 'tutorial/tutorial_drag'
 )
 

+ 14 - 0
Include/Rocket/Core/Context.h

@@ -35,6 +35,7 @@
 #include <Rocket/Core/Input.h>
 #include <Rocket/Core/String.h>
 #include <Rocket/Core/ScriptInterface.h>
+#include <Rocket/Core/ViewState.h>
 
 namespace Rocket {
 namespace Core {
@@ -80,6 +81,9 @@ public:
 	/// @return The current dimensions of the context.
 	const Vector2i& GetDimensions() const;
 
+	/// Returns the current state of the view.
+	const ViewState& GetViewState() const throw();
+
 	/// Updates all elements in the context's documents.
 	bool Update();
 	/// Renders all visible elements in the context's documents.
@@ -209,6 +213,13 @@ public:
 	/// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
 	bool ProcessMouseWheel(int wheel_delta, int key_modifier_state);
 
+	/// Notifies Rocket of a change in the projection matrix.
+	/// @param[in] projection The new projection matrix.
+	void ProcessProjectionChange(const Matrix4f &projection);
+	/// Notifies Rocket of a change in the view matrix.
+	/// @param[in] projection The new view matrix.
+	void ProcessViewChange(const Matrix4f &view);
+
 	/// Gets the context's render interface.
 	/// @return The render interface the context renders through.
 	RenderInterface* GetRenderInterface() const;
@@ -292,6 +303,9 @@ private:
 	Vector2i clip_origin;
 	Vector2i clip_dimensions;
 
+	// The current view state
+	ViewState view_state;
+
 	// Internal callback for when an element is removed from the hierarchy.
 	void OnElementRemove(Element* element);
 	// Internal callback for when a new element gains focus.

+ 42 - 0
Include/Rocket/Core/Element.h

@@ -35,6 +35,10 @@
 #include <Rocket/Core/Event.h>
 #include <Rocket/Core/Property.h>
 #include <Rocket/Core/Types.h>
+#include <Rocket/Core/Transform.h>
+#include <Rocket/Core/TransformState.h>
+
+#include <memory>
 
 namespace Rocket {
 namespace Core {
@@ -216,12 +220,14 @@ public:
 	const Property* GetLocalProperty(const String& name);		
 	/// Resolves one of this element's properties. If the value is a number or px, this is returned. If it's a 
 	/// percentage then it is resolved based on the second argument (the base value).
+	/// If it's an angle it is returned as degrees.
 	/// @param[in] name The name of the property to resolve the value for.
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
 	/// @return The value of this property for this element.
 	float ResolveProperty(const String& name, float base_value);
 	/// Resolves one of this element's non-inherited properties. If the value is a number or px, this is returned. If it's a 
 	/// percentage then it is resolved based on the second argument (the base value).
+	/// If it's an angle it is returned as degrees.
 	/// @param[in] name The property to resolve the value for.
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
 	/// @return The value of this property for this element.
@@ -258,6 +264,33 @@ public:
 	/// Returns 'vertical-align' property value from element's style or local cache.
 	const Property *GetVerticalAlignProperty();
 
+	/// Returns 'perspective' property value from element's style or local cache.
+	const Property *GetPerspective();
+	/// Returns 'perspective-origin-x' property value from element's style or local cache.
+	const Property *GetPerspectiveOriginX();
+	/// Returns 'perspective-origin-y' property value from element's style or local cache.
+	const Property *GetPerspectiveOriginY();
+	/// Returns 'transform' property value from element's style or local cache.
+	const Property *GetTransform();
+	/// Returns 'transform-origin-x' property value from element's style or local cache.
+	const Property *GetTransformOriginX();
+	/// Returns 'transform-origin-y' property value from element's style or local cache.
+	const Property *GetTransformOriginY();
+	/// Returns 'transform-origin-z' property value from element's style or local cache.
+	const Property *GetTransformOriginZ();
+	/// Returns this element's TransformState
+	const TransformState *GetTransformState() const throw();
+	/// Returns the TransformStates that are effective for this element.
+	void GetEffectiveTransformState(
+		const TransformState **local_perspective,
+		const TransformState **perspective,
+		const TransformState **transform
+	) throw();
+	/// Project a 2D point in pixel coordinates onto the element's plane.
+	/// @param[in] point The point to project.
+	/// @return The projected coordinates.
+	const Vector2f Project(const Vector2f& point) throw();
+
 	/// Iterates over the properties defined on this element.
 	/// @param[inout] index Index of the property to fetch. This is incremented to the next valid index after the fetch. Indices are not necessarily incremental.
 	/// @param[out] pseudo_classes The pseudo-classes the property is defined by.
@@ -638,6 +671,9 @@ private:
 
 	void DirtyStructure();
 
+	void DirtyTransformState(bool perspective_changed, bool transform_changed, bool parent_pv_changed);
+	void UpdateTransformState();
+
 	// Original tag this element came from.
 	String tag;
 
@@ -715,6 +751,12 @@ private:
 	bool clipping_enabled;
 	bool clipping_state_dirty;
 
+	// Transform state
+	std::auto_ptr< TransformState > transform_state;
+	bool transform_state_perspective_dirty;
+	bool transform_state_transform_dirty;
+	bool transform_state_parent_transform_dirty;
+
 	friend class Context;
 	friend class ElementStyle;
 	friend class LayoutEngine;

+ 18 - 0
Include/Rocket/Core/ElementUtilities.h

@@ -139,6 +139,24 @@ public:
 	/// @param offset[in] The offset from the parent's borders.
 	/// @param anchor[in] Defines which corner or edge the border is to be positioned relative to.
 	static bool PositionElement(Element* element, const Vector2f& offset, PositionAnchor anchor);
+
+	/// Applies an element's `perspective' and `transform' properties.
+	/// @param[in] element		The element whose transform to apply.
+	/// @param[in] apply		Whether to apply (true) or unapply (false) the transform.
+	/// @return true if the element has a transform and it could be applied.
+	static bool ApplyTransform(Element &element, bool apply = true);
+	/// Unapplies an element's `perspective' and `transform' properties.
+	/// @param[in] element		The element whose transform to unapply.
+	/// @return true if the element has a transform and it could be unapplied.
+	static bool UnapplyTransform(Element &element);
+
+	/// Projects the mouse cursor coordinates into a transformed element's plane.
+	/// @param[in/out] dict		The dictionary with the projected mouse coordinates.
+	/// @param[in] old_dict		The dictionary with the original mouse coordinates.
+	/// @param[in] element		The element to project the mouse coordinates into.
+	/// @param[in] view		The current global projection and view matrices.
+	/// @return true, if the mouse coordinates could be updated.
+	static bool ProjectMouse(Dictionary &dict, const Dictionary &old_dict, Element &element, const ViewState *view = 0);
 };
 
 }

+ 7 - 0
Include/Rocket/Core/Event.h

@@ -108,6 +108,11 @@ public:
 	/// Release this event.
 	virtual void OnReferenceDeactivate();
 
+private:
+	/// Project the mouse coordinates to the current element to enable
+	/// interacting with transformed elements.
+	void ProjectMouse(Element* element);
+
 protected:
 	String type;
 	Dictionary parameters;
@@ -116,6 +121,8 @@ protected:
 	Element* current_element;
 
 private:
+	Dictionary parameters_backup;
+
 	bool interruptible;
 	bool interruped;
 

+ 496 - 0
Include/Rocket/Core/Matrix4.h

@@ -0,0 +1,496 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREMATRIX4_H
+#define ROCKETCOREMATRIX4_H
+
+#include <Rocket/Core/Debug.h>
+#include <Rocket/Core/Math.h>
+#include <Rocket/Core/Vector4.h>
+
+namespace Rocket {
+namespace Core {
+
+/**
+	Templated class that acts as base strategy for vectors access patterns of matrices.
+	@author Markus Schöngart
+ */
+template< typename Component >
+struct MatrixStorageBase
+{
+		typedef Component ComponentType;
+		typedef Vector4< ComponentType > VectorType;
+		typedef VectorType VectorsType[4];
+
+		class StrideVector
+		{
+				VectorsType& vectors;
+				int idx;
+
+			public:
+				inline StrideVector(VectorsType& vectors, int idx) throw()
+					: vectors(vectors), idx(idx) { }
+				inline ComponentType& operator[](int i) throw()
+					{ return vectors[i][idx]; }
+				inline StrideVector& operator=(const VectorType& vec) throw()
+					{
+						(*this)[0] = vec[0];
+						(*this)[1] = vec[1];
+						(*this)[2] = vec[2];
+						(*this)[3] = vec[3];
+						return *this;
+					}
+				operator const VectorType() const throw()
+					{
+						return VectorType(
+							(*this)[0],
+							(*this)[1],
+							(*this)[2],
+							(*this)[3]
+						);
+					}
+		};
+		class StrideAccess
+		{
+				VectorsType& vectors;
+			public:
+				inline StrideAccess(VectorsType& vectors) throw()
+					: vectors(vectors) { }
+				inline StrideVector operator[](int i) throw()
+					{ return StrideVector(vectors, i); }
+		};
+		class ConstStrideVector
+		{
+				const VectorsType& vectors;
+				int idx;
+			public:
+				inline ConstStrideVector(const VectorsType& vectors, int idx) throw()
+					: vectors(vectors), idx(idx) { }
+				inline const ComponentType& operator[](int i) const throw()
+					{ return vectors[i][idx]; }
+				inline operator const VectorType() const throw()
+					{
+						return VectorType(
+							(*this)[0],
+							(*this)[1],
+							(*this)[2],
+							(*this)[3]
+						);
+					}
+		};
+		class ConstStrideAccess
+		{
+				const VectorsType& vectors;
+			public:
+				inline ConstStrideAccess(const VectorsType& vectors) throw()
+					: vectors(vectors) { }
+				inline ConstStrideVector operator[](int i) throw()
+					{ return ConstStrideVector(vectors, i); }
+		};
+
+		class PackedVector
+		{
+				VectorType& vector;
+			public:
+				inline PackedVector(VectorType& vector) throw()
+					: vector(vector) { }
+				inline ComponentType& operator[](int i) throw()
+					{ return vector[i]; }
+				inline PackedVector& operator=(const VectorType& vec) throw()
+					{
+						vector = vec;
+						return *this;
+					}
+				inline PackedVector& operator=(StrideVector& vec) throw()
+					{
+						vector[0] = vec[0];
+						vector[1] = vec[1];
+						vector[2] = vec[2];
+						vector[3] = vec[3];
+						return *this;
+					}
+				inline PackedVector& operator=(ConstStrideVector& vec) throw()
+					{
+						vector[0] = vec[0];
+						vector[1] = vec[1];
+						vector[2] = vec[2];
+						vector[3] = vec[3];
+						return *this;
+					}
+				inline operator VectorType&() throw() { return vector; }
+		};
+		class PackedAccess
+		{
+				VectorsType& vectors;
+			public:
+				inline PackedAccess(VectorsType& vectors) throw()
+					: vectors(vectors) { }
+				inline PackedVector operator[](int i) throw()
+					{ return PackedVector(vectors[i]); }
+		};
+		#if 0
+		class ConstPackedVector
+		{
+				const VectorType& vectors;
+			public:
+				inline ConstPackedVector(const VectorType& vectors) throw()
+					: vectors(vectors) { }
+				inline const ComponentType& operator[](int i) const throw()
+					{ return vectors[i]; }
+				inline operator const VectorType&() throw() { return vectors; }
+		};
+		#endif
+		class ConstPackedAccess
+		{
+				const VectorsType& vectors;
+			public:
+				inline ConstPackedAccess(const VectorsType& vectors) throw()
+					: vectors(vectors) { }
+				inline const VectorType& operator[](int i) throw()
+					{ return vectors[i]; }
+		};
+};
+
+template< typename Component >
+struct RowMajorStorage;
+template< typename Component >
+struct ColumnMajorStorage;
+
+/**
+	Templated class that defines the vectors access pattern for row-major matrices.
+	@author Markus Schöngart
+ */
+template< typename Component >
+struct RowMajorStorage : public MatrixStorageBase< Component >
+{
+		typedef Component ComponentType;
+		typedef Vector4< ComponentType > VectorType;
+		typedef RowMajorStorage< ComponentType > ThisType;
+		typedef ColumnMajorStorage< ComponentType > TransposeType;
+
+		typedef typename MatrixStorageBase< Component >::PackedVector Row;
+		typedef typename MatrixStorageBase< Component >::PackedAccess Rows;
+		typedef const typename MatrixStorageBase< Component >::VectorType& ConstRow;
+		typedef typename MatrixStorageBase< Component >::ConstPackedAccess ConstRows;
+		typedef typename MatrixStorageBase< Component >::StrideVector Column;
+		typedef typename MatrixStorageBase< Component >::StrideAccess Columns;
+		typedef typename MatrixStorageBase< Component >::ConstStrideVector ConstColumn;
+		typedef typename MatrixStorageBase< Component >::ConstStrideAccess ConstColumns;
+};
+
+/**
+	Templated class that defines the vectors access pattern for column-major matrices.
+	@author Markus Schöngart
+ */
+template< typename Component >
+struct ColumnMajorStorage
+{
+		typedef Component ComponentType;
+		typedef Vector4< ComponentType > VectorType;
+		typedef ColumnMajorStorage< ComponentType > ThisType;
+		typedef RowMajorStorage< ComponentType > TransposeType;
+
+		typedef typename MatrixStorageBase< Component >::PackedVector Column;
+		typedef typename MatrixStorageBase< Component >::PackedAccess Columns;
+		typedef const typename MatrixStorageBase< Component >::VectorType& ConstColumn;
+		typedef typename MatrixStorageBase< Component >::ConstPackedAccess ConstColumns;
+		typedef typename MatrixStorageBase< Component >::StrideVector Row;
+		typedef typename MatrixStorageBase< Component >::StrideAccess Rows;
+		typedef typename MatrixStorageBase< Component >::ConstStrideVector ConstRow;
+		typedef typename MatrixStorageBase< Component >::ConstStrideAccess ConstRows;
+};
+
+/**
+	Templated class for a generic 4x4 matrix.
+	@author Markus Schöngart
+ */
+
+template< typename Component, class Storage = ColumnMajorStorage< Component > >
+class Matrix4
+{
+	public:
+		typedef Component ComponentType;
+		typedef Vector4< ComponentType > VectorType;
+		typedef Matrix4< ComponentType, Storage > ThisType;
+
+		typedef Storage StorageType;
+		typedef typename StorageType::Row Row;
+		typedef typename StorageType::Rows Rows;
+		typedef typename StorageType::ConstRow ConstRow;
+		typedef typename StorageType::ConstRows ConstRows;
+		typedef typename StorageType::Column Column;
+		typedef typename StorageType::Columns Columns;
+		typedef typename StorageType::ConstColumn ConstColumn;
+		typedef typename StorageType::ConstColumns ConstColumns;
+
+		typedef typename StorageType::TransposeType TransposeStorageType;
+		typedef Matrix4< ComponentType, TransposeStorageType > TransposeType;
+		friend class Matrix4< ComponentType, TransposeStorageType >;
+
+	private:
+		// The components of the matrix.
+		VectorType vectors[4];
+
+		/// Initialising constructor.
+		Matrix4(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw();
+
+		template< typename _Component, class _StorageA >
+		struct VectorMultiplier
+		{
+			typedef _Component ComponentType;
+			typedef _StorageA StorageAType;
+			typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+			typedef Vector4< ComponentType > VectorType;
+
+			static const VectorType Multiply(
+				const MatrixAType& lhs,
+				const VectorType& rhs
+			) throw();
+		};
+
+		template< typename _Component, class _StorageA, class _StorageB >
+		struct MatrixMultiplier
+		{
+			typedef _Component ComponentType;
+			typedef _StorageA StorageAType;
+			typedef _StorageB StorageBType;
+			typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+			typedef Matrix4< ComponentType, StorageBType > MatrixBType;
+
+			static const VectorType Multiply(
+				const MatrixAType& lhs,
+				const VectorType& rhs
+			);
+
+			static const MatrixAType Multiply(
+				const MatrixAType& lhs,
+				const MatrixBType& rhs
+			) throw();
+		};
+
+	public:
+		/// Lightweight, non-initialising constructor.
+		inline Matrix4() throw();
+
+		/// Initialising, copy constructor.
+		inline Matrix4(const ThisType& other) throw();
+		Matrix4(const TransposeType& other) throw();
+
+		/// Assignment operator
+		const ThisType& operator=(const ThisType& other) throw();
+		const ThisType& operator=(const TransposeType& other) throw();
+
+		/// Construct from row vectors.
+		static const ThisType FromRows(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw();
+
+		/// Construct from column vectors.
+		static const ThisType FromColumns(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw();
+
+		/// Construct from components.
+		static const ThisType FromRowMajor(const ComponentType* components) throw();
+		static const ThisType FromColumnMajor(const ComponentType* components) throw();
+
+		// Convert to raw values; keep the storage mode in mind.
+		inline operator Component*() throw()
+			{ return &vectors[0][0]; }
+		inline operator const Component*() const throw()
+			{ return &vectors[0][0]; }
+
+		/// Get the i-th row
+		inline Row GetRow(int i) throw()
+			{ Rows rows(vectors); return rows[i]; }
+		/// Get the i-th row
+		inline ConstRow GetRow(int i) const throw()
+			{ ConstRows rows(vectors); return rows[i]; }
+		/// Set the i-th row
+		inline void SetRow(int i, const VectorType& vec) throw()
+			{ Rows rows(vectors); rows[i] = vec; }
+		/// Set all rows
+		void SetRows(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw();
+
+		/// Get the i-th column
+		inline Column GetColumn(int i) throw()
+			{ Columns columns(vectors); return columns[i]; }
+		/// Get the i-th column
+		inline ConstColumn GetColumn(int i) const throw()
+			{ ConstColumns columns(vectors); return columns[i]; }
+		/// Set the i-th column
+		inline void SetColumn(int i, const VectorType& vec) throw()
+			{ Columns columns(vectors); columns[i] = vec; }
+		/// Set all columns
+		void SetColumns(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw();
+
+		/// Returns the transpose of this matrix.
+		/// @return The transpose matrix.
+		inline const TransposeType& Transpose() const throw()
+			{ return reinterpret_cast<const TransposeType&>(*this); }
+
+		/// Inverts this matrix in place, if possible.
+		/// @return true, if the inversion succeeded.
+		bool Invert() throw();
+
+		/// Returns the negation of this matrix.
+		/// @return The negation of this matrix.
+		ThisType operator-() const throw();
+
+		/// Adds another matrix to this in-place.
+		/// @param[in] other The matrix to add.
+		/// @return This matrix, post-operation.
+		const ThisType& operator+=(const ThisType& other) throw();
+		const ThisType& operator+=(const TransposeType& other) throw();
+		/// Subtracts another matrix from this in-place.
+		/// @param[in] other The matrix to subtract.
+		/// @return This matrix, post-operation.
+		const ThisType& operator-=(const ThisType& other) throw();
+		const ThisType& operator-=(const TransposeType& other) throw();
+		/// Scales this matrix in-place.
+		/// @param[in] other The value to scale this matrix's components by.
+		/// @return This matrix, post-operation.
+		const ThisType& operator*=(Component other) throw();
+		/// Scales this matrix in-place by the inverse of a value.
+		/// @param[in] other The value to divide this matrix's components by.
+		/// @return This matrix, post-operation.
+		const ThisType& operator/=(Component other) throw();
+
+		/// Returns the sum of this matrix and another.
+		/// @param[in] other The matrix to add this to.
+		/// @return The sum of the two matrices.
+		inline const ThisType operator+(const ThisType& other) const throw()
+			{ ThisType result(*this); result += other; return result; }
+		inline const ThisType operator+(const TransposeType& other) const throw()
+			{ ThisType result(*this); result += other; return result; }
+		/// Returns the result of subtracting another matrix from this matrix.
+		/// @param[in] other The matrix to subtract from this matrix.
+		/// @return The result of the subtraction.
+		inline const ThisType operator-(const ThisType& other) const throw()
+			{ ThisType result(*this); result -= other; return result; }
+		inline const ThisType operator-(const TransposeType& other) const throw()
+			{ ThisType result(*this); result -= other; return result; }
+		/// Returns the result of multiplying this matrix by a scalar.
+		/// @param[in] other The scalar value to multiply by.
+		/// @return The result of the scale.
+		inline const ThisType operator*(Component other) const throw()
+			{ ThisType result(*this); result *= other; return result; }
+		/// Returns the result of dividing this matrix by a scalar.
+		/// @param[in] other The scalar value to divide by.
+		/// @return The result of the scale.
+		inline const ThisType operator/(Component other) const throw()
+			{ ThisType result(*this); result *= other; return result; }
+
+		/// Returns the result of multiplying this matrix by a vector.
+		/// @param[in] other The scalar value to multiply by.
+		/// @return The result of the scale.
+		const VectorType operator*(const VectorType& other) const throw()
+			{ return VectorMultiplier< Component, Storage >::Multiply(*this, other); }
+
+		/// Returns the result of multiplying this matrix by another matrix.
+		/// @param[in] other The matrix value to multiply by.
+		/// @return The result of the multiplication.
+		template< class Storage2 >
+		const ThisType operator*(const Matrix4< Component, Storage2 >& other) const throw()
+			{ return MatrixMultiplier< Component, Storage, Storage2 >::Multiply(*this, other); }
+
+		/// Multiplies this matrix by another matrix in place.
+		/// @param[in] other The scalar value to multiply by.
+		/// @return The result of the scale.
+		inline const ThisType& operator*=(const ThisType& other) throw()
+			{ *this = *this * other; return *this; }
+		inline const ThisType& operator*=(const TransposeType& other) throw()
+			{ *this = *this * other; return *this; }
+
+		/// Equality operator.
+		/// @param[in] other The matrix to compare this against.
+		/// @return True if the two matrices are equal, false otherwise.
+		bool operator==(const ThisType& other) const throw();
+		bool operator==(const TransposeType& other) const throw();
+		/// Inequality operator.
+		/// @param[in] other The matrix to compare this against.
+		/// @return True if the two matrices are not equal, false otherwise.
+		bool operator!=(const ThisType& other) const throw();
+		bool operator!=(const TransposeType& other) const throw();
+
+		/// Return the identity matrix.
+		/// @return The identity matrix.
+		inline static const ThisType& Identity() throw();
+		/// Return a diagonal matrix.
+		/// @return A diagonal matrix.
+		static ThisType Diag(Component a, Component b, Component c, Component d = 1) throw();
+
+		/// Create an orthographic projection matrix
+		/// @param l The horizontal coordinate of the left clipping plane
+		/// @param r The horizontal coordinate of the right clipping plane
+		/// @param b The vertical coordinate of the bottom clipping plane
+		/// @param t The vertical coordinate of the top clipping plane
+		/// @param n The depth coordinate of the near clipping plane
+		/// @param f The depth coordinate of the far clipping plane
+		/// @return The specified orthographic projection matrix.
+		static ThisType ProjectOrtho(Component l, Component r, Component b, Component t, Component n, Component f) throw();
+		/// Create a perspective projection matrix
+		/// @param l The horizontal coordinate of the left clipping plane
+		/// @param r The horizontal coordinate of the right clipping plane
+		/// @param b The vertical coordinate of the bottom clipping plane
+		/// @param t The vertical coordinate of the top clipping plane
+		/// @param n The depth coordinate of the near clipping plane
+		/// @param f The depth coordinate of the far clipping plane
+		/// @return The specified perspective projection matrix.
+		static ThisType ProjectPerspective(Component l, Component r, Component b, Component t, Component n, Component f) throw();
+
+		/// Return a translation matrix.
+		/// @return A translation matrix.
+		static ThisType Translate (const Vector3< Component >& v) throw();
+		static ThisType Translate (Component x, Component y, Component z) throw();
+		static ThisType TranslateX (Component x) throw();
+		static ThisType TranslateY (Component y) throw();
+		static ThisType TranslateZ (Component z) throw();
+
+		/// Return a scaling matrix.
+		/// @return A scaling matrix.
+		static ThisType Scale (Component x, Component y, Component z) throw();
+		static ThisType ScaleX (Component x) throw();
+		static ThisType ScaleY (Component y) throw();
+		static ThisType ScaleZ (Component z) throw();
+
+		/// Return a rotation matrix.
+		/// @return A rotation matrix.
+		static ThisType Rotate (const Vector3< Component >& v, Component angle) throw();
+		static ThisType RotateX (Component angle) throw();
+		static ThisType RotateY (Component angle) throw();
+		static ThisType RotateZ (Component angle) throw();
+
+		/// Return a skew/shearing matrix.
+		/// @return A skew matrix.
+		static ThisType Skew (Component angle_x, Component angle_y) throw();
+		static ThisType SkewX (Component angle) throw();
+		static ThisType SkewY (Component angle) throw();
+};
+
+#include <Rocket/Core/Matrix4.inl>
+
+}
+}
+
+#endif

+ 733 - 0
Include/Rocket/Core/Matrix4.inl

@@ -0,0 +1,733 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+// Initialising constructor.
+template< typename Component, class Storage >
+Matrix4< Component, Storage >::Matrix4(
+	const typename Matrix4< Component, Storage >::VectorType& vec0,
+	const typename Matrix4< Component, Storage >::VectorType& vec1,
+	const typename Matrix4< Component, Storage >::VectorType& vec2,
+	const typename Matrix4< Component, Storage >::VectorType& vec3
+) throw()
+{
+	vectors[0] = vec0;
+	vectors[1] = vec1;
+	vectors[2] = vec2;
+	vectors[3] = vec3;
+}
+
+// Default constructor.
+template< typename Component, class Storage >
+Matrix4< Component, Storage >::Matrix4() throw()
+{
+}
+
+// Initialising, copy constructor.
+template< typename Component, class Storage >
+Matrix4< Component, Storage >::Matrix4(const typename Matrix4< Component, Storage >::ThisType& other) throw()
+	: vectors(other.vectors)
+{
+}
+
+template< typename Component, class Storage >
+Matrix4< Component, Storage >::Matrix4(const typename Matrix4< Component, Storage >::TransposeType& other) throw()
+{
+	Rows rows(vectors);
+	typename Matrix4< Component, Storage >::TransposeType::ConstRows other_rows(other.vectors);
+	for (int i = 0; i < 4; ++i)
+	{
+		rows[i] = other_rows[i];
+	}
+}
+
+// Assignment operator
+template< typename Component, class Storage >
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator=(const typename Matrix4< Component, Storage >::ThisType& other) throw()
+{
+	for (int i = 0; i < 4; ++i)
+	{
+		vectors[i] = other.vectors[i];
+	}
+}
+
+template< typename Component, class Storage >
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator=(const typename Matrix4< Component, Storage >::TransposeType& other) throw()
+{
+	Rows rows(vectors);
+	typename Matrix4< Component, Storage >::TransposeType::Rows other_rows(other.vectors);
+	for (int i = 0; i < 4; ++i)
+	{
+		rows[i] = other_rows[i];
+	}
+}
+
+// Construct from row vectors.
+template< typename Component, class Storage >
+const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromRows(
+	const typename Matrix4< Component, Storage >::VectorType& vec0,
+	const typename Matrix4< Component, Storage >::VectorType& vec1,
+	const typename Matrix4< Component, Storage >::VectorType& vec2,
+	const typename Matrix4< Component, Storage >::VectorType& vec3
+) throw()
+{
+	typename Matrix4< Component, Storage >::ThisType result;
+	result.SetRows(vec0, vec1, vec2, vec3);
+	return result;
+}
+
+// Construct from column vectors.
+template< typename Component, class Storage >
+const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromColumns(
+	const typename Matrix4< Component, Storage >::VectorType& vec0,
+	const typename Matrix4< Component, Storage >::VectorType& vec1,
+	const typename Matrix4< Component, Storage >::VectorType& vec2,
+	const typename Matrix4< Component, Storage >::VectorType& vec3
+) throw()
+{
+	typename Matrix4< Component, Storage >::ThisType result;
+	result.SetColumns(vec0, vec1, vec2, vec3);
+	return result;
+}
+
+// Construct from components
+template< typename Component, class Storage >
+const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromRowMajor(const Component* components) throw()
+{
+	Matrix4< Component, Storage >::ThisType result;
+	Matrix4< Component, Storage >::Rows rows(result.vectors);
+	for (int i = 0; i < 4; ++i)
+	{
+		for (int j = 0; j < 4; ++j)
+		{
+			rows[i][j] = components[i*4 + j];
+		}
+	}
+	return result;
+}
+template< typename Component, class Storage >
+const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromColumnMajor(const Component* components) throw()
+{
+	Matrix4< Component, Storage >::ThisType result;
+	Matrix4< Component, Storage >::Columns columns(result.vectors);
+	for (int i = 0; i < 4; ++i)
+	{
+		for (int j = 0; j < 4; ++j)
+		{
+			columns[i][j] = components[i*4 + j];
+		}
+	}
+	return result;
+}
+
+// Set all rows
+template< typename Component, class Storage >
+void Matrix4< Component, Storage >::SetRows(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw()
+{
+	Rows rows(vectors);
+	rows[0] = vec0;
+	rows[1] = vec1;
+	rows[2] = vec2;
+	rows[3] = vec3;
+}
+
+// Set all columns
+template< typename Component, class Storage >
+void Matrix4< Component, Storage >::SetColumns(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) throw()
+{
+	Columns columns(vectors);
+	columns[0] = vec0;
+	columns[1] = vec1;
+	columns[2] = vec2;
+	columns[3] = vec3;
+}
+
+// Inverts this matrix in place.
+// This is from the MESA implementation of the GLU library.
+template< typename Component, class Storage >
+bool Matrix4< Component, Storage >::Invert() throw()
+{
+	Matrix4< Component, Storage >::ThisType result;
+	Component *dst = result;
+	const Component *src = *this;
+
+	dst[0] = src[5]  * src[10] * src[15] -
+		src[5]  * src[11] * src[14] -
+		src[9]  * src[6]  * src[15] +
+		src[9]  * src[7]  * src[14] +
+		src[13] * src[6]  * src[11] -
+		src[13] * src[7]  * src[10];
+
+	dst[4] = -src[4]  * src[10] * src[15] +
+		src[4]  * src[11] * src[14] +
+		src[8]  * src[6]  * src[15] -
+		src[8]  * src[7]  * src[14] -
+		src[12] * src[6]  * src[11] +
+		src[12] * src[7]  * src[10];
+
+	dst[8] = src[4]  * src[9] * src[15] -
+		src[4]  * src[11] * src[13] -
+		src[8]  * src[5] * src[15] +
+		src[8]  * src[7] * src[13] +
+		src[12] * src[5] * src[11] -
+		src[12] * src[7] * src[9];
+
+	dst[12] = -src[4]  * src[9] * src[14] +
+		src[4]  * src[10] * src[13] +
+		src[8]  * src[5] * src[14] -
+		src[8]  * src[6] * src[13] -
+		src[12] * src[5] * src[10] +
+		src[12] * src[6] * src[9];
+
+	dst[1] = -src[1]  * src[10] * src[15] +
+		src[1]  * src[11] * src[14] +
+		src[9]  * src[2] * src[15] -
+		src[9]  * src[3] * src[14] -
+		src[13] * src[2] * src[11] +
+		src[13] * src[3] * src[10];
+
+	dst[5] = src[0]  * src[10] * src[15] -
+		src[0]  * src[11] * src[14] -
+		src[8]  * src[2] * src[15] +
+		src[8]  * src[3] * src[14] +
+		src[12] * src[2] * src[11] -
+		src[12] * src[3] * src[10];
+
+	dst[9] = -src[0]  * src[9] * src[15] +
+		src[0]  * src[11] * src[13] +
+		src[8]  * src[1] * src[15] -
+		src[8]  * src[3] * src[13] -
+		src[12] * src[1] * src[11] +
+		src[12] * src[3] * src[9];
+
+	dst[13] = src[0]  * src[9] * src[14] -
+		src[0]  * src[10] * src[13] -
+		src[8]  * src[1] * src[14] +
+		src[8]  * src[2] * src[13] +
+		src[12] * src[1] * src[10] -
+		src[12] * src[2] * src[9];
+
+	dst[2] = src[1]  * src[6] * src[15] -
+		src[1]  * src[7] * src[14] -
+		src[5]  * src[2] * src[15] +
+		src[5]  * src[3] * src[14] +
+		src[13] * src[2] * src[7] -
+		src[13] * src[3] * src[6];
+
+	dst[6] = -src[0]  * src[6] * src[15] +
+		src[0]  * src[7] * src[14] +
+		src[4]  * src[2] * src[15] -
+		src[4]  * src[3] * src[14] -
+		src[12] * src[2] * src[7] +
+		src[12] * src[3] * src[6];
+
+	dst[10] = src[0]  * src[5] * src[15] -
+		src[0]  * src[7] * src[13] -
+		src[4]  * src[1] * src[15] +
+		src[4]  * src[3] * src[13] +
+		src[12] * src[1] * src[7] -
+		src[12] * src[3] * src[5];
+
+	dst[14] = -src[0]  * src[5] * src[14] +
+		src[0]  * src[6] * src[13] +
+		src[4]  * src[1] * src[14] -
+		src[4]  * src[2] * src[13] -
+		src[12] * src[1] * src[6] +
+		src[12] * src[2] * src[5];
+
+	dst[3] = -src[1] * src[6] * src[11] +
+		src[1] * src[7] * src[10] +
+		src[5] * src[2] * src[11] -
+		src[5] * src[3] * src[10] -
+		src[9] * src[2] * src[7] +
+		src[9] * src[3] * src[6];
+
+	dst[7] = src[0] * src[6] * src[11] -
+		src[0] * src[7] * src[10] -
+		src[4] * src[2] * src[11] +
+		src[4] * src[3] * src[10] +
+		src[8] * src[2] * src[7] -
+		src[8] * src[3] * src[6];
+
+	dst[11] = -src[0] * src[5] * src[11] +
+		src[0] * src[7] * src[9] +
+		src[4] * src[1] * src[11] -
+		src[4] * src[3] * src[9] -
+		src[8] * src[1] * src[7] +
+		src[8] * src[3] * src[5];
+
+	dst[15] = src[0] * src[5] * src[10] -
+		src[0] * src[6] * src[9] -
+		src[4] * src[1] * src[10] +
+		src[4] * src[2] * src[9] +
+		src[8] * src[1] * src[6] -
+		src[8] * src[2] * src[5];
+
+	float det = src[0] * dst[0] + \
+		src[1] * dst[4] + \
+		src[2] * dst[8] + \
+		src[3] * dst[12];
+
+	if (det == 0)
+	{
+		return false;
+	}
+
+	*this = result * (1 / det);
+	return true;
+}
+
+// Returns the negation of this matrix.
+template< typename Component, class Storage >
+typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::operator-() const throw()
+{
+	return typename Matrix4< Component, Storage >::ThisType(
+		-vectors[0],
+		-vectors[1],
+		-vectors[2],
+		-vectors[3]
+	);
+}
+
+// Adds another matrix to this in-place.
+template< typename Component, class Storage>
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator+=(const typename Matrix4< Component, Storage >::ThisType& other) throw()
+{
+	for (int i = 0; i < 4; ++i)
+	{
+		vectors[i] += other.vectors[i];
+	}
+	return *this;
+}
+template< typename Component, class Storage>
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator+=(const typename Matrix4< Component, Storage >::TransposeType& other) throw()
+{
+	Rows rows(vectors);
+	typename Matrix4< Component, Storage >::TransposeType::ConstRows other_rows(other);
+	for (int i = 0; i < 4; ++i)
+	{
+		rows[i] += other_rows[i];
+	}
+	return *this;
+}
+
+// Subtracts another matrix from this in-place.
+template< typename Component, class Storage>
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator-=(const typename Matrix4< Component, Storage >::ThisType& other) throw()
+{
+	for (int i = 0; i < 4; ++i)
+	{
+		vectors[i] -= other.vectors[i];
+	}
+	return *this;
+}
+template< typename Component, class Storage>
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator-=(const typename Matrix4< Component, Storage >::TransposeType& other) throw()
+{
+	Rows rows(vectors);
+	typename Matrix4< Component, Storage >::TransposeType::ConstRows other_rows(other);
+	for (int i = 0; i < 4; ++i)
+	{
+		rows[i] -= other_rows[i];
+	}
+	return *this;
+}
+
+// Scales this matrix in-place.
+template< typename Component, class Storage>
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator*=(Component s) throw()
+{
+	for (int i = 0; i < 4; ++i)
+	{
+		vectors[i] *= s;
+	}
+	return *this;
+}
+
+// Scales this matrix in-place by the inverse of a value.
+template< typename Component, class Storage>
+const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator/=(Component s) throw()
+{
+	for (int i = 0; i < 4; ++i)
+	{
+		vectors[i] /= s;
+	}
+	return *this;
+}
+
+// Equality operator.
+template< typename Component, class Storage>
+bool Matrix4< Component, Storage >::operator==(const typename Matrix4< Component, Storage >::ThisType& other) const throw()
+{
+	typename Matrix4< Component, Storage >::ConstRows rows(vectors);
+	typename Matrix4< Component, Storage >::ConstRows other_rows(other.vectors);
+	return vectors[0] == other.vectors[0]
+	   and vectors[1] == other.vectors[1]
+	   and vectors[2] == other.vectors[2]
+	   and vectors[3] == other.vectors[3];
+}
+template< typename Component, class Storage>
+bool Matrix4< Component, Storage >::operator==(const typename Matrix4< Component, Storage >::TransposeType& other) const throw()
+{
+	typename Matrix4< Component, Storage >::ConstRows rows(vectors);
+	typename Matrix4< Component, Storage >::ConstRows other_rows(other.vectors);
+	return rows[0] == other_rows[0]
+	   and rows[1] == other_rows[1]
+	   and rows[2] == other_rows[2]
+	   and rows[3] == other_rows[3];
+}
+
+// Inequality operator.
+template< typename Component, class Storage>
+bool Matrix4< Component, Storage >::operator!=(const typename Matrix4< Component, Storage >::ThisType& other) const throw()
+{
+	return vectors[0] != other.vectors[0]
+	    or vectors[1] != other.vectors[1]
+	    or vectors[2] != other.vectors[2]
+	    or vectors[3] != other.vectors[3];
+}
+template< typename Component, class Storage>
+bool Matrix4< Component, Storage >::operator!=(const typename Matrix4< Component, Storage >::TransposeType& other) const throw()
+{
+	typename Matrix4< Component, Storage >::ConstRows rows(vectors);
+	typename Matrix4< Component, Storage >::ConstRows other_rows(other.vectors);
+	return rows[0] != other_rows[0]
+	    or rows[1] != other_rows[1]
+	    or rows[2] != other_rows[2]
+	    or rows[3] != other_rows[3];
+}
+
+// Return the identity matrix.
+template< typename Component, class Storage>
+const Matrix4< Component, Storage >& Matrix4< Component, Storage >::Identity() throw()
+{
+	static Matrix4< Component, Storage > identity(Diag(1, 1, 1, 1));
+	return identity;
+}
+
+// Return a diagonal matrix.
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::Diag(Component a, Component b, Component c, Component d) throw()
+{
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(a, 0, 0, 0),
+		Matrix4< Component, Storage >::VectorType(0, b, 0, 0),
+		Matrix4< Component, Storage >::VectorType(0, 0, c, 0),
+		Matrix4< Component, Storage >::VectorType(0, 0, 0, d)
+	);
+}
+
+// Create an orthographic projection matrix
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::ProjectOrtho(Component l, Component r, Component b, Component t, Component n, Component f) throw()
+{
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(2 / (r - l), 0, 0, -(r + l)/(r - l)),
+		Matrix4< Component, Storage >::VectorType(0, 2 / (t - b), 0, -(t + b)/(t - b)),
+		Matrix4< Component, Storage >::VectorType(0, 0, 2 / (f - n), -(f + n)/(f - n)),
+		Matrix4< Component, Storage >::VectorType(0, 0, 0, 1)
+	);
+}
+
+// Create a perspective projection matrix
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::ProjectPerspective(Component l, Component r, Component b, Component t, Component n, Component f) throw()
+{
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(2 * n / (r - l), 0, (r + l)/(r - l), 0),
+		Matrix4< Component, Storage >::VectorType(0, 2 * n / (t - b), (t + b)/(t - b), 0),
+		Matrix4< Component, Storage >::VectorType(0, 0, -(f + n)/(f - n), -(2 * f * n)/(f - n)),
+		Matrix4< Component, Storage >::VectorType(0, 0, -1, 0)
+	);
+}
+
+// Return a translation matrix.
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::Translate(const Vector3< Component >& v) throw()
+{
+	return Translate(v.x, v.y, v.z);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::Translate(Component x, Component y, Component z) throw()
+{
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(1, 0, 0, x),
+		Matrix4< Component, Storage >::VectorType(0, 1, 0, y),
+		Matrix4< Component, Storage >::VectorType(0, 0, 1, z),
+		Matrix4< Component, Storage >::VectorType(0, 0, 0, 1)
+	);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::TranslateX(Component x) throw()
+{
+	return Translate(Vector3< Component >(x, 0, 0));
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::TranslateY(Component y) throw()
+{
+	return Translate(Vector3< Component >(0, y, 0));
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::TranslateZ(Component z) throw()
+{
+	return Translate(Vector3< Component >(0, 0, z));
+}
+
+// Return a scaling matrix.
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::Scale(Component x, Component y, Component z) throw()
+{
+	return Matrix4::Diag(x, y, z, 1);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::ScaleX(Component x) throw()
+{
+	return Scale(x, 1, 1);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::ScaleY(Component y) throw()
+{
+	return Scale(1, y, 1);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::ScaleZ(Component z) throw()
+{
+	return Scale(1, 1, z);
+}
+
+// Return a rotation matrix.
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::Rotate(const Vector3< Component >& v, Component angle) throw()
+{
+	Vector3< Component > n = v.Normalise();
+	Component Sin = Math::Sin(Math::DegreesToRadians(angle));
+	Component Cos = Math::Cos(Math::DegreesToRadians(angle));
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(
+			n.x * n.x * (1 - Cos) +       Cos,
+			n.x * n.y * (1 - Cos) - n.z * Sin,
+			n.x * n.z * (1 - Cos) + n.y * Sin,
+			0
+		),
+		Matrix4< Component, Storage >::VectorType(
+			n.y * n.x * (1 - Cos) + n.z * Sin,
+			n.y * n.y * (1 - Cos) +       Cos,
+			n.y * n.z * (1 - Cos) - n.x * Sin,
+			0
+		),
+		Matrix4< Component, Storage >::VectorType(
+			n.z * n.x * (1 - Cos) - n.y * Sin,
+			n.z * n.y * (1 - Cos) + n.x * Sin,
+			n.z * n.z * (1 - Cos) +       Cos,
+			0
+		),
+		Matrix4< Component, Storage >::VectorType(0, 0, 0, 1)
+	);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::RotateX(Component angle) throw()
+{
+	Component Sin = Math::Sin(Math::DegreesToRadians(angle));
+	Component Cos = Math::Cos(Math::DegreesToRadians(angle));
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(1, 0,    0,   0),
+		Matrix4< Component, Storage >::VectorType(0, Cos, -Sin, 0),
+		Matrix4< Component, Storage >::VectorType(0, Sin,  Cos, 0),
+		Matrix4< Component, Storage >::VectorType(1, 0,    0,   1)
+	);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::RotateY(Component angle) throw()
+{
+	Component Sin = Math::Sin(Math::DegreesToRadians(angle));
+	Component Cos = Math::Cos(Math::DegreesToRadians(angle));
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType( Cos, 0, Sin, 0),
+		Matrix4< Component, Storage >::VectorType( 0,   1, 0,   0),
+		Matrix4< Component, Storage >::VectorType(-Sin, 0, Cos, 0),
+		Matrix4< Component, Storage >::VectorType( 0,   0, 0,   1)
+	);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::RotateZ(Component angle) throw()
+{
+	Component Sin = Math::Sin(Math::DegreesToRadians(angle));
+	Component Cos = Math::Cos(Math::DegreesToRadians(angle));
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(Cos, -Sin, 0, 0),
+		Matrix4< Component, Storage >::VectorType(Sin,  Cos, 0, 0),
+		Matrix4< Component, Storage >::VectorType( 0,   0,   1, 0),
+		Matrix4< Component, Storage >::VectorType( 0,   0,   0, 1)
+	);
+}
+// Return a skew/shearing matrix.
+// @return A skew matrix.
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::Skew(Component angle_x, Component angle_y) throw()
+{
+	Component SkewX = Math::Tan(Math::DegreesToRadians(angle_x));
+	Component SkewY = Math::Tan(Math::DegreesToRadians(angle_y));
+	return Matrix4< Component, Storage >::FromRows(
+		Matrix4< Component, Storage >::VectorType(0,     SkewY, 0, 0),
+		Matrix4< Component, Storage >::VectorType(SkewX, 0,     0, 0),
+		Matrix4< Component, Storage >::VectorType( 0,    0,     1, 0),
+		Matrix4< Component, Storage >::VectorType( 0,    0,     0, 1)
+	);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::SkewX(Component angle) throw()
+{
+	return Skew(angle, 0);
+}
+
+template< typename Component, class Storage>
+Matrix4< Component, Storage > Matrix4< Component, Storage >::SkewY(Component angle) throw()
+{
+	return Skew(0, angle);
+}
+
+template< typename Component, class Storage >
+template< typename _Component >
+struct Matrix4< Component, Storage >::VectorMultiplier< _Component, RowMajorStorage< _Component > >
+{
+	typedef _Component ComponentType;
+	typedef RowMajorStorage< ComponentType > StorageAType;
+	typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+	typedef Vector4< ComponentType > VectorType;
+
+	static const VectorType Multiply(const MatrixAType& lhs, const VectorType& rhs) throw()
+	{
+		typename MatrixAType::ConstRows rows(lhs.vectors);
+		return VectorType(
+			rhs.DotProduct(rows[0]),
+			rhs.DotProduct(rows[1]),
+			rhs.DotProduct(rows[2]),
+			rhs.DotProduct(rows[3])
+		);
+	}
+};
+
+template< typename Component, class Storage >
+template< typename _Component >
+struct Matrix4< Component, Storage >::VectorMultiplier< _Component, ColumnMajorStorage< _Component > >
+{
+	typedef _Component ComponentType;
+	typedef ColumnMajorStorage< ComponentType > StorageAType;
+	typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+	typedef Vector4< ComponentType > VectorType;
+
+	static const VectorType Multiply(const MatrixAType& lhs, const VectorType& rhs) throw()
+	{
+		typename MatrixAType::ConstRows rows(lhs.vectors);
+		return VectorType(
+			rhs.DotProduct(rows[0]),
+			rhs.DotProduct(rows[1]),
+			rhs.DotProduct(rows[2]),
+			rhs.DotProduct(rows[3])
+		);
+	}
+};
+
+template< typename Component, class Storage >
+template< typename _Component, class _StorageB >
+struct Matrix4< Component, Storage >::MatrixMultiplier< _Component, RowMajorStorage< _Component >, _StorageB >
+{
+	typedef _Component ComponentType;
+	typedef RowMajorStorage< ComponentType > StorageAType;
+	typedef _StorageB StorageBType;
+	typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+	typedef Matrix4< ComponentType, StorageBType > MatrixBType;
+
+	static const MatrixAType Multiply(const MatrixAType& lhs, const MatrixBType& rhs) throw()
+	{
+		typename MatrixAType::ThisType result;
+		typename MatrixAType::Rows result_rows(result.vectors);
+		typename MatrixAType::ConstRows lhs_rows(lhs.vectors);
+		typename MatrixBType::ConstColumns rhs_columns(rhs.vectors);
+		for (int i = 0; i < 4; ++i)
+		{
+			for (int j = 0; j < 4; ++j)
+			{
+				result_rows[i][j] = lhs_rows[i].DotProduct(rhs_columns[j]);
+			}
+		}
+		return result;
+	}
+};
+
+template< typename Component, class Storage >
+template< typename _Component >
+struct Matrix4< Component, Storage >::MatrixMultiplier< _Component, ColumnMajorStorage< _Component >, ColumnMajorStorage< _Component > >
+{
+	typedef _Component ComponentType;
+	typedef ColumnMajorStorage< ComponentType > StorageAType;
+	typedef ColumnMajorStorage< ComponentType > StorageBType;
+	typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+	typedef Matrix4< ComponentType, StorageBType > MatrixBType;
+
+	static const MatrixAType Multiply(const MatrixAType& lhs, const MatrixBType& rhs) throw()
+	{
+		typename MatrixAType::ThisType result;
+		typename MatrixAType::Rows result_rows(result.vectors);
+		typename MatrixAType::ConstRows lhs_rows(lhs.vectors);
+		typename MatrixBType::ConstColumns rhs_columns(rhs.vectors);
+		for (int i = 0; i < 4; ++i)
+		{
+			for (int j = 0; j < 4; ++j)
+			{
+				result_rows[i][j] = rhs_columns[j].DotProduct(lhs_rows[i]);
+			}
+		}
+		return result;
+	}
+};
+
+template< typename Component, class Storage >
+template< typename _Component >
+struct Matrix4< Component, Storage >::MatrixMultiplier< _Component, ColumnMajorStorage< _Component >, RowMajorStorage< _Component > >
+{
+	typedef _Component ComponentType;
+	typedef ColumnMajorStorage< ComponentType > StorageAType;
+	typedef RowMajorStorage< ComponentType > StorageBType;
+	typedef Matrix4< ComponentType, StorageAType > MatrixAType;
+	typedef Matrix4< ComponentType, StorageBType > MatrixBType;
+
+	static const MatrixAType Multiply(const MatrixAType& lhs, const MatrixBType& rhs) throw()
+	{
+		return lhs * MatrixAType(rhs);
+	}
+};

+ 14 - 10
Include/Rocket/Core/Property.h

@@ -54,21 +54,25 @@ public:
 		// Absolute values.
 		NUMBER = 1 << 3,			// number unsuffixed; fetch as < float >
 		PX = 1 << 4,				// number suffixed by 'px'; fetch as < float >
-		COLOUR = 1 << 5,			// colour; fetch as < Colourb >
-		ABSOLUTE_UNIT = NUMBER | PX | COLOUR,
+		DEG = 1 << 5,				// number suffixed by 'px'; fetch as < float >
+		RAD = 1 << 6,				// number suffixed by 'px'; fetch as < float >
+		COLOUR = 1 << 7,			// colour; fetch as < Colourb >
+		ABSOLUTE_UNIT = NUMBER | PX | DEG | RAD | COLOUR,
 
 		// Relative values.
-		EM = 1 << 6,				// number suffixed by 'em'; fetch as < float >
-		PERCENT = 1 << 7,			// number suffixed by '%'; fetch as < float >
+		EM = 1 << 8,				// number suffixed by 'em'; fetch as < float >
+		PERCENT = 1 << 9,			// number suffixed by '%'; fetch as < float >
 		RELATIVE_UNIT = EM | PERCENT,
 
 		// Values based on pixels-per-inch.
-		INCH = 1 << 8,				// number suffixed by 'in'; fetch as < float >
-		CM = 1 << 9,				// number suffixed by 'cm'; fetch as < float >
-		MM = 1 << 10,				// number suffixed by 'mm'; fetch as < float >
-		PT = 1 << 11,				// number suffixed by 'pt'; fetch as < float >
-		PC = 1 << 12,				// number suffixed by 'pc'; fetch as < float >
-		PPI_UNIT = INCH | CM | MM | PT | PC
+		INCH = 1 << 10,				// number suffixed by 'in'; fetch as < float >
+		CM = 1 << 11,				// number suffixed by 'cm'; fetch as < float >
+		MM = 1 << 12,				// number suffixed by 'mm'; fetch as < float >
+		PT = 1 << 13,				// number suffixed by 'pt'; fetch as < float >
+		PC = 1 << 14,				// number suffixed by 'pc'; fetch as < float >
+		PPI_UNIT = INCH | CM | MM | PT | PC,
+
+		TRANSFORM = 1 << 15			// transform; fetch as < TransformRef >
 	};
 
 	Property();

+ 150 - 0
Include/Rocket/Core/Reference.h

@@ -0,0 +1,150 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREREFERENCE_H
+#define ROCKETCOREREFERENCE_H
+
+#include <Rocket/Core/Header.h>
+#include <algorithm>
+
+namespace Rocket {
+namespace Core {
+
+template< class ReferenceCountable >
+class ROCKETCORE_API SharedReference;
+
+template< class ReferenceCountable >
+class ROCKETCORE_API SharedConstReference;
+
+/**
+	A smart pointer class template that manages ReferenceCountables.
+	SharedReference allows unrestricted access to the shared object via every reference.
+	@author Markus Schöngart
+	@see ReferenceCountable
+*/
+template< class ReferenceCountable >
+class ROCKETCORE_API SharedReference
+{
+public:
+	typedef ReferenceCountable ReferenceType;
+	typedef SharedReference< ReferenceCountable > ThisType;
+	typedef SharedConstReference< ReferenceCountable > ReadOnlyType;
+
+	/// Constructor. Does not increase the object's reference count.
+	/// @param[in] object The object to refer to.
+	SharedReference(ReferenceType* object = 0) : object(object)
+		{ /*if (object) object->AddReference();*/ }
+	/// Copy constructor. Increases the object's reference count.
+	/// @param[in] other The other Reference.
+	SharedReference(const ThisType& other) : object(other.object)
+		{ if (object) object->AddReference(); }
+	/// Destructor. Decrements the stored object's reference count.
+	~SharedReference()
+		{ if (object) object->RemoveReference(); }
+
+	/// Swaps the contents of two References.
+	void Swap(ThisType& other) throw()
+		{ std::swap(object, other.object); }
+
+	/// Assign another referenced object to this smart pointer
+	const ThisType& operator=(ReferenceType* ref)
+		{ ThisType tmp(ref); Swap(tmp); return *this; }
+	/// Assign another referenced object to this smart pointer
+	const ThisType& operator=(const ThisType& other)
+		{ ThisType tmp(other); Swap(tmp); return *this; }
+
+	const ReferenceType& operator*() const throw()
+		{ return *object; }
+	ReferenceType& operator*() throw()
+		{ return *object; }
+
+	const ReferenceType* operator->() const throw()
+		{ return object; }
+	ReferenceType* operator->() throw()
+		{ return object; }
+
+	friend ReadOnlyType;
+
+private:
+	mutable ReferenceType *object;
+};
+
+/**
+	A smart pointer class template that manages ReferenceCountables.
+	SharedConstReference allows read-only access to the shared object via every reference.
+	@author Markus Schöngart
+	@see ReferenceCountable
+*/
+template< class ReferenceCountable >
+class ROCKETCORE_API SharedConstReference
+{
+public:
+	typedef ReferenceCountable ReferenceType;
+	typedef SharedConstReference< ReferenceCountable > ThisType;
+	typedef SharedReference< ReferenceCountable > ReadWriteType;
+
+	/// Constructor. Does not increase the object's reference count.
+	/// @param[in] object The object to refer to.
+	SharedConstReference(ReferenceType* object = 0) : object(object)
+		{ /*if (object) object->AddReference();*/ }
+	/// Copy constructor. Increases the object's reference count.
+	/// @param[in] other The other Reference.
+	SharedConstReference(const ThisType& other) : object(other.object)
+		{ if (object) object->AddReference(); }
+	/// Constructor from read-write reference. Increases the object's reference count.
+	/// @param[in] other The other Reference.
+	SharedConstReference(const ReadWriteType& other) : object(other.object)
+		{ if (object) object->AddReference(); }
+	/// Destructor. Decrements the stored object's reference count.
+	~SharedConstReference()
+		{ if (object) object->RemoveReference(); }
+
+	/// Swaps the contents of two References.
+	void Swap(ThisType& other) throw()
+		{ std::swap(object, other.object); }
+
+	/// Assign another referenced object to this smart pointer
+	const ThisType& operator=(ReferenceType* ref)
+		{ ThisType tmp(ref); Swap(tmp); return *this; }
+	/// Assign another referenced object to this smart pointer
+	const ThisType& operator=(const ThisType& other)
+		{ ThisType tmp(other); Swap(tmp); return *this; }
+
+	const ReferenceType& operator*() const throw()
+		{ return *object; }
+
+	const ReferenceType* operator->() const throw()
+		{ return object; }
+
+private:
+	mutable ReferenceType *object;
+};
+
+}
+}
+
+#endif

+ 9 - 0
Include/Rocket/Core/RenderInterface.h

@@ -32,6 +32,7 @@
 #include <Rocket/Core/Header.h>
 #include <Rocket/Core/Texture.h>
 #include <Rocket/Core/Vertex.h>
+#include <Rocket/Core/Types.h>
 
 namespace Rocket {
 namespace Core {
@@ -116,6 +117,14 @@ public:
 	/// @returns The number of pixels per inch. The default implementation returns 100.
 	virtual float GetPixelsPerInch();
 
+	/// Called by Rocket when it wants to set the current transform matrix to a new matrix.
+	/// @param[in] transform The new transform to apply.
+	virtual void PushTransform(const Matrix4f& transform);
+	/// Called by Rocket when it wants to revert the latest transform change.
+	/// @param[in] transform This is the transform to unapply.
+	///            It always equals the argument of the latest call to PushTransform().
+	virtual void PopTransform(const Matrix4f& transform);
+
 	/// Called when this render interface is released.
 	virtual void Release();
 

+ 20 - 0
Include/Rocket/Core/StyleSheetKeywords.h

@@ -113,6 +113,26 @@ const int TAB_INDEX_AUTO = 1;
 const int FOCUS_NONE = 0;
 const int FOCUS_AUTO = 1;
 
+const int PERSPECTIVE_NONE = 0;
+
+const int PERSPECTIVE_ORIGIN_X_LEFT = 0;
+const int PERSPECTIVE_ORIGIN_X_CENTER = 1;
+const int PERSPECTIVE_ORIGIN_X_RIGHT = 2;
+
+const int PERSPECTIVE_ORIGIN_Y_TOP = 0;
+const int PERSPECTIVE_ORIGIN_Y_CENTER = 1;
+const int PERSPECTIVE_ORIGIN_Y_BOTTOM = 2;
+
+const int TRANSFORM_NONE = 0;
+
+const int TRANSFORM_ORIGIN_X_LEFT = 0;
+const int TRANSFORM_ORIGIN_X_CENTER = 1;
+const int TRANSFORM_ORIGIN_X_RIGHT = 2;
+
+const int TRANSFORM_ORIGIN_Y_TOP = 0;
+const int TRANSFORM_ORIGIN_Y_CENTER = 1;
+const int TRANSFORM_ORIGIN_Y_BOTTOM = 2;
+
 }
 }
 

+ 92 - 0
Include/Rocket/Core/Transform.h

@@ -0,0 +1,92 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCORETRANSFORM_H
+#define ROCKETCORETRANSFORM_H
+
+#include <Rocket/Core/Header.h>
+#include <Rocket/Core/ReferenceCountable.h>
+
+namespace Rocket {
+namespace Core {
+
+class ViewState;
+namespace Transforms { class Primitive; }
+
+/**
+	The Transform class holds the information parsed from an element's
+	`transform' property.  It is one of the primitive types that a Variant
+	can assume.  The method `ComputeFinalTransform()' computes the
+	transformation matrix that is to be applied to the current
+	projection/view matrix in order to render the associated element.
+
+	@author Markus Schöngart
+	@see Rocket::Core::Variant
+ */
+
+class ROCKETCORE_API Transform : public ReferenceCountable
+{
+public:
+	/// Default constructor, initializes an identity transform
+	Transform();
+
+	/// Copy constructor
+	Transform(const Transform& other);
+
+	/// Destructor
+	~Transform();
+
+	/// Swap the content of two Transform instances
+	void Swap(Transform& other);
+
+	/// Assignment operator
+	const Transform& operator=(const Transform& other);
+
+	/// Remove all Primitives from this Transform
+	void ClearPrimitives();
+	/// Add a Primitive to this Transform
+	void AddPrimitive(const Transforms::Primitive& p);
+	/// Return the number of Primitives in this Transform
+	int GetNumPrimitives() const throw()
+		{ return primitives.size(); }
+	/// Return the i-th Primitive in this Transform
+	const Transforms::Primitive& GetPrimitive(int i) const throw()
+		{ return *primitives[i]; }
+
+protected:
+	void OnReferenceDeactivate()
+		{ delete this; }
+
+private:
+	typedef std::vector< Transforms::Primitive * > Primitives;
+	Primitives primitives;
+};
+
+}
+}
+
+#endif

+ 326 - 0
Include/Rocket/Core/TransformPrimitive.h

@@ -0,0 +1,326 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCORETRANSFORMPRIMITIVE_H
+#define ROCKETCORETRANSFORMPRIMITIVE_H
+
+#include <Rocket/Core/Header.h>
+#include <Rocket/Core/Types.h>
+#include <Rocket/Core/Property.h>
+
+namespace Rocket {
+namespace Core {
+namespace Transforms {
+
+struct NumericValue
+{
+	/// Non-initializing constructor.
+	NumericValue() throw();
+	/// Construct from a float and a Unit.
+	NumericValue(float number, Property::Unit unit) throw();
+
+	/// Resolve a numeric property value for an element.
+	float Resolve(Element& e, float base) const throw();
+	/// Resolve a numeric property value with the element's width as relative base value.
+	float ResolveWidth(Element& e) const throw();
+	/// Resolve a numeric property value with the element's height as relative base value.
+	float ResolveHeight(Element& e) const throw();
+	/// Resolve a numeric property value with the element's depth as relative base value.
+	float ResolveDepth(Element& e) const throw();
+
+	float number;
+	Rocket::Core::Property::Unit unit;
+};
+
+/**
+	The Primitive class is the base class of geometric transforms such as rotations, scalings and translations.
+	Instances of this class are added to a Rocket::Core::Transform instance
+	by the Rocket::Core::PropertyParserTransform, which is responsible for
+	parsing the `transform' property.
+
+	@author Markus Schöngart
+	@see Rocket::Core::Transform
+	@see Rocket::Core::PropertyParserTransform
+ */
+class Primitive
+{
+	public:
+		virtual ~Primitive() { }
+
+		virtual Primitive* Clone() const = 0;
+
+		/// Resolve the transformation matrix encoded by the primitive.
+		/// @param m The transformation matrix to resolve the Primitive to.
+		/// @param e The Element which to resolve the Primitive for.
+		/// @return true if the Primitive encodes a transformation.
+		virtual bool ResolveTransform(Matrix4f& m, Element& e) const throw()
+			{ return false; }
+		/// Resolve the perspective value encoded by the primitive.
+		/// @param p The perspective value to resolve the Primitive to.
+		/// @param e The Element which to resolve the Primitive for.
+		/// @return true if the Primitive encodes a perspective value.
+		virtual bool ResolvePerspective(float &p, Element& e) const throw()
+			{ return false; }
+};
+
+template< size_t N >
+class ResolvedValuesPrimitive : public Primitive
+{
+	public:
+		ResolvedValuesPrimitive(const NumericValue* values) throw()
+			{ for (size_t i = 0; i < N; ++i) this->values[i] = values[i].number; }
+
+	protected:
+		float values[N];
+};
+
+template< size_t N >
+class UnresolvedValuesPrimitive : public Primitive
+{
+	public:
+		UnresolvedValuesPrimitive(const NumericValue* values) throw()
+			{ memcpy(this->values, values, sizeof(this->values)); }
+
+	protected:
+		NumericValue values[N];
+};
+
+class Matrix2D : public ResolvedValuesPrimitive< 6 >
+{
+	public:
+		Matrix2D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Matrix2D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Matrix3D : public ResolvedValuesPrimitive< 16 >
+{
+	public:
+		Matrix3D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Matrix3D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class TranslateX : public UnresolvedValuesPrimitive< 1 >
+{
+	public:
+		TranslateX(const NumericValue* values) throw()
+			: UnresolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new TranslateX(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class TranslateY : public UnresolvedValuesPrimitive< 1 >
+{
+	public:
+		TranslateY(const NumericValue* values) throw()
+			: UnresolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new TranslateY(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class TranslateZ : public UnresolvedValuesPrimitive< 1 >
+{
+	public:
+		TranslateZ(const NumericValue* values) throw()
+			: UnresolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new TranslateZ(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Translate2D : public UnresolvedValuesPrimitive< 2 >
+{
+	public:
+		Translate2D(const NumericValue* values) throw()
+			: UnresolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Translate2D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Translate3D : public UnresolvedValuesPrimitive< 3 >
+{
+	public:
+		Translate3D(const NumericValue* values) throw()
+			: UnresolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Translate3D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class ScaleX : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		ScaleX(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new ScaleX(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class ScaleY : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		ScaleY(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new ScaleY(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class ScaleZ : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		ScaleZ(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new ScaleZ(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Scale2D : public ResolvedValuesPrimitive< 2 >
+{
+	public:
+		Scale2D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Scale2D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Scale3D : public ResolvedValuesPrimitive< 3 >
+{
+	public:
+		Scale3D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Scale3D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class RotateX : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		RotateX(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new RotateX(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class RotateY : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		RotateY(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new RotateY(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class RotateZ : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		RotateZ(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new RotateZ(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Rotate2D : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		Rotate2D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Rotate2D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Rotate3D : public ResolvedValuesPrimitive< 4 >
+{
+	public:
+		Rotate3D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Rotate3D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class SkewX : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		SkewX(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new SkewX(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class SkewY : public ResolvedValuesPrimitive< 1 >
+{
+	public:
+		SkewY(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new SkewY(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Skew2D : public ResolvedValuesPrimitive< 2 >
+{
+	public:
+		Skew2D(const NumericValue* values) throw()
+			: ResolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Skew2D(*this); }
+		bool ResolveTransform(Matrix4f& m, Element& e) const throw();
+};
+
+class Perspective : public UnresolvedValuesPrimitive< 1 >
+{
+	public:
+		Perspective(const NumericValue* values) throw()
+			: UnresolvedValuesPrimitive(values) { }
+
+		inline Primitive* Clone() const { return new Perspective(*this); }
+		bool ResolvePerspective(float& p, Element& e) const throw();
+};
+
+}
+}
+}
+
+#endif

+ 135 - 0
Include/Rocket/Core/TransformState.h

@@ -0,0 +1,135 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCORETRANSFORMSTATE_H
+#define ROCKETCORETRANSFORMSTATE_H
+
+#include <Rocket/Core/Header.h>
+#include <Rocket/Core/Types.h>
+
+namespace Rocket {
+namespace Core {
+
+/**
+	A TransformState captures an element's current perspective and transform settings.
+
+	@author Markus Schöngart
+ */
+
+class ROCKETCORE_API TransformState
+{
+public:
+	struct Perspective
+	{
+		/// Calculates the projection matrix.
+		Matrix4f GetProjection() const throw();
+
+		/// Calculates the clip space coordinates ([-1; 1]³) of a 3D vertex in world space.
+		/// @param[in] point The point in world space coordinates.
+		/// @return The clip space coordinates of the point.
+		Vector3f Project(const Vector3f &point) const throw();
+		/// Calculates the world space coordinates of a 3D vertex in clip space ([-1; 1]³).
+		/// @param[in] point The point in clip space coordinates.
+		/// @return The world space coordinates of the point.
+		Vector3f Unproject(const Vector3f &point) const throw();
+	
+		float		distance;	// The CSS `perspective:' value
+		Vector2i	view_size;
+		Vector2f	vanish;		// The vanishing point, in [0; 1]²; Only relevant if distance > 0
+	};
+
+	struct LocalPerspective
+	{
+		/// Calculates the projection matrix.
+		Matrix4f GetProjection() const throw();
+
+		/// Calculates the clip space coordinates ([-1; 1]³) of a 3D vertex in world space.
+		/// @param[in] point The point in world space coordinates.
+		/// @return The clip space coordinates of the point.
+		Vector3f Project(const Vector3f &point) const throw();
+		/// Calculates the world space coordinates of a 3D vertex in clip space ([-1; 1]³).
+		/// @param[in] point The point in clip space coordinates.
+		/// @return The world space coordinates of the point.
+		Vector3f Unproject(const Vector3f &point) const throw();
+
+		float		distance;	// The CSS `perspective:' value
+		Vector2i	view_size;
+	};
+
+	TransformState();
+
+	/// Stores a new perspective value
+	void SetPerspective(const Perspective *perspective) throw();
+	/// Returns the perspective value
+	bool GetPerspective(Perspective *perspective) const throw();
+
+	/// Stores a new local perspective value
+	void SetLocalPerspective(const LocalPerspective *local_perspective) throw();
+	/// Returns the local perspective value
+	bool GetLocalPerspective(LocalPerspective *local_perspective) const throw();
+
+	/// Stores a new transform matrix
+	void SetTransform(const Matrix4f *transform) throw();
+	/// Returns the stored transform matrix
+	bool GetTransform(Matrix4f *transform) const throw();
+
+	/// Stores a new recursive parent transform.
+	void SetParentRecursiveTransform(const Matrix4f *parent_recursive_transform) throw();
+	/// Returns the stored recursive parent transform matrix
+	bool GetParentRecursiveTransform(Matrix4f *transform) const throw();
+
+	/// Transforms a 3D point by the `parent transform' and `transform' matrices stored in this TransformState.
+	/// @param[in] point The point in world space coordinates.
+	/// @return The transformed point in world space coordinates.
+	Vector3f Transform(const Vector3f &point) const throw();
+	/// Transforms a 3D point by the inverse `parent transform' and `transform' matrices stored in this TransformState.
+	/// @param[in] point The point in world space coordinates.
+	/// @return The transformed point in world space coordinates.
+	Vector3f Untransform(const Vector3f &point) const throw();
+
+	/// Returns the parent's recursive transform multiplied by this transform.
+	bool GetRecursiveTransform(Matrix4f *recursive_transform) const throw();
+
+private:
+	// Flags for stored values
+	bool have_perspective;
+	bool have_local_perspective;
+	bool have_parent_recursive_transform;
+	bool have_transform;
+
+	// Stored values
+	float perspective, local_perspective;
+	Vector2i view_size;
+	Vector2f vanish;
+	Matrix4f parent_recursive_transform;
+	Matrix4f transform;
+};
+
+}
+}
+
+#endif

+ 13 - 0
Include/Rocket/Core/TypeConverter.inl

@@ -104,9 +104,14 @@ PASS_THROUGH(char);
 PASS_THROUGH(word);
 PASS_THROUGH(Vector2i);
 PASS_THROUGH(Vector2f);
+PASS_THROUGH(Vector3i);
+PASS_THROUGH(Vector3f);
+PASS_THROUGH(Vector4i);
+PASS_THROUGH(Vector4f);
 PASS_THROUGH(Colourf);
 PASS_THROUGH(Colourb);
 PASS_THROUGH(String);
+PASS_THROUGH(TransformRef);
 
 // Pointer types need to be typedef'd
 class ScriptInterface;
@@ -256,6 +261,10 @@ public: \
 
 STRING_VECTOR_CONVERTER(Vector2i, int, 2);
 STRING_VECTOR_CONVERTER(Vector2f, float, 2);
+STRING_VECTOR_CONVERTER(Vector3i, int, 3);
+STRING_VECTOR_CONVERTER(Vector3f, float, 3);
+STRING_VECTOR_CONVERTER(Vector4i, int, 4);
+STRING_VECTOR_CONVERTER(Vector4f, float, 4);
 STRING_VECTOR_CONVERTER(Colourf, float, 4);
 STRING_VECTOR_CONVERTER(Colourb, byte, 4);
 
@@ -373,6 +382,10 @@ public: \
 
 VECTOR_STRING_CONVERTER(Vector2i, int, 2);
 VECTOR_STRING_CONVERTER(Vector2f, float, 2);
+VECTOR_STRING_CONVERTER(Vector3i, int, 3);
+VECTOR_STRING_CONVERTER(Vector3f, float, 3);
+VECTOR_STRING_CONVERTER(Vector4i, int, 4);
+VECTOR_STRING_CONVERTER(Vector4f, float, 4);
 VECTOR_STRING_CONVERTER(Colourf, float, 4);
 VECTOR_STRING_CONVERTER(Colourb, byte, 4);
 #undef PASS_THROUGH

+ 23 - 2
Include/Rocket/Core/Types.h

@@ -65,7 +65,11 @@ typedef unsigned __int64 uint64_t;
 
 #include <Rocket/Core/Colour.h>
 #include <Rocket/Core/Vector2.h>
+#include <Rocket/Core/Vector3.h>
+#include <Rocket/Core/Vector4.h>
+#include <Rocket/Core/Matrix4.h>
 #include <Rocket/Core/String.h>
+#include <Rocket/Core/Reference.h>
 
 namespace Rocket {
 namespace Core {
@@ -73,9 +77,16 @@ namespace Core {
 // Default colour types.
 typedef Colour< float, 1 > Colourf;
 typedef Colour< byte, 255 > Colourb;
-typedef Vector2< float > Vector2f;
 typedef Vector2< int > Vector2i;
-	
+typedef Vector2< float > Vector2f;
+typedef Vector3< int > Vector3i;
+typedef Vector3< float > Vector3f;
+typedef Vector4< int > Vector4i;
+typedef Vector4< float > Vector4f;
+
+typedef Matrix4< float, ColumnMajorStorage< float > > ColumnMajorMatrix4f;
+typedef Matrix4< float, RowMajorStorage< float > > RowMajorMatrix4f;
+typedef ColumnMajorMatrix4f Matrix4f;
 
 class Element;
 class Dictionary;
@@ -92,6 +103,16 @@ typedef std::set< String > PseudoClassList;
 typedef std::set< String > PropertyNameList;
 typedef std::set< String > AttributeNameList;
 typedef Dictionary ElementAttributes;
+}
+}
+
+#include <Rocket/Core/Transform.h>
+
+namespace Rocket {
+namespace Core {
+
+// Reference types
+typedef SharedConstReference< Transform > TransformRef;
 
 }
 }

+ 12 - 0
Include/Rocket/Core/Variant.h

@@ -70,9 +70,12 @@ public:
 		STRING = 's',
 		WORD = 'w',
 		VECTOR2 = '2',
+		VECTOR3 = '3',
+		VECTOR4 = '4',
 		COLOURF = 'g',
 		COLOURB = 'h',
 		SCRIPTINTERFACE = 'p',
+		TRANSFORMREF = 't',
 		VOIDPTR = '*',			
 	};
 
@@ -113,6 +116,15 @@ public:
 	/// Sets a Vector2f value on this variant.
 	/// @param[in] value New value to set.
 	void Set(const Vector2f& value);
+	/// Sets a Vector3f value on this variant.
+	/// @param[in] value New value to set.
+	void Set(const Vector3f& value);
+	/// Sets a Vector4f value on this variant.
+	/// @param[in] value New value to set.
+	void Set(const Vector4f& value);
+	/// Sets a TransformRef value on this variant.
+	/// @param[in] value New value to set.
+	void Set(const TransformRef& value);
 	/// Sets a Colourf value on this variant.
 	/// @param[in] value New value to set.
 	void Set(const Colourf& value);

+ 12 - 0
Include/Rocket/Core/Variant.inl

@@ -66,6 +66,18 @@ bool Variant::GetInto(T& value) const
 			return TypeConverter< Vector2f, T >::Convert(*(Vector2f*)data, value);
 		break;
 
+		case VECTOR3:
+			return TypeConverter< Vector3f, T >::Convert(*(Vector3f*)data, value);
+		break;
+
+		case VECTOR4:
+			return TypeConverter< Vector4f, T >::Convert(*(Vector4f*)data, value);
+		break;
+
+		case TRANSFORMREF:
+			return TypeConverter< TransformRef, T >::Convert(*(TransformRef*)data, value);
+		break;
+
 		case COLOURF:
 			return TypeConverter< Colourf, T >::Convert(*(Colourf*)data, value);
 		break;

+ 139 - 0
Include/Rocket/Core/Vector3.h

@@ -0,0 +1,139 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREVECTOR3_H
+#define ROCKETCOREVECTOR3_H
+
+#include <Rocket/Core/Debug.h>
+#include <Rocket/Core/Math.h>
+
+namespace Rocket {
+namespace Core {
+
+/**
+	Templated class for a generic three-component vector.
+	@author Markus Schöngart
+ */
+
+template < typename Type >
+class Vector3
+{
+	public:
+		/// Lightweight, non-initialising constructor.
+		inline Vector3();
+		/// Initialising constructor.
+		/// @param[in] x Initial x-value of the vector.
+		/// @param[in] y Initial y-value of the vector.
+		/// @param[in] z Initial z-value of the vector.
+		inline Vector3(Type x, Type y, Type z);
+
+		/// Returns the magnitude of the vector.
+		/// @return The computed magnitude.
+		inline float Magnitude() const;
+		/// Returns the squared magnitude of the vector.
+		/// @return The computed squared magnitude.
+		inline Type SquaredMagnitude() const;
+		/// Generates a normalised vector from this vector.
+		/// @return The normalised vector.
+		inline Vector3 Normalise() const;
+
+		/// Computes the dot-product between this vector and another.
+		/// @param[in] rhs The other vector to use in the dot-product.
+		/// @return The computed dot-product between the two vectors.
+		inline Type DotProduct(const Vector3& rhs) const;
+
+		/// Computes the cross-product between this vector and another.
+		/// @param[in] rhs The other vector to use in the dot-product.
+		/// @return The computed cross-product between the two vectors.
+		inline Vector3 CrossProduct(const Vector3& rhs) const;
+
+		/// Returns the negation of this vector.
+		/// @return The negation of this vector.
+		inline Vector3 operator-() const;
+
+		/// Returns the sum of this vector and another.
+		/// @param[in] rhs The vector to add this to.
+		/// @return The sum of the two vectors.
+		inline Vector3 operator+(const Vector3& rhs) const;
+		/// Returns the result of subtracting another vector from this vector.
+		/// @param[in] rhs The vector to subtract from this vector.
+		/// @return The result of the subtraction.
+		inline Vector3 operator-(const Vector3& rhs) const;
+		/// Returns the result of multiplying this vector by a scalar.
+		/// @param[in] rhs The scalar value to multiply by.
+		/// @return The result of the scale.
+		inline Vector3 operator*(Type rhs) const;
+		/// Returns the result of dividing this vector by a scalar.
+		/// @param[in] rhs The scalar value to divide by.
+		/// @return The result of the scale.
+		inline Vector3 operator/(Type rhs) const;
+
+		/// Adds another vector to this in-place.
+		/// @param[in] rhs The vector to add.
+		/// @return This vector, post-operation.
+		inline Vector3& operator+=(const Vector3& rhs);
+		/// Subtracts another vector from this in-place.
+		/// @param[in] rhs The vector to subtract.
+		/// @return This vector, post-operation.
+		inline Vector3& operator-=(const Vector3& rhs);
+		/// Scales this vector in-place.
+		/// @param[in] rhs The value to scale this vector's components by.
+		/// @return This vector, post-operation.
+		inline Vector3& operator*=(const Type& rhs);
+		/// Scales this vector in-place by the inverse of a value.
+		/// @param[in] rhs The value to divide this vector's components by.
+		/// @return This vector, post-operation.
+		inline Vector3& operator/=(const Type& rhs);
+
+		/// Equality operator.
+		/// @param[in] rhs The vector to compare this against.
+		/// @return True if the two vectors are equal, false otherwise.
+		inline bool operator==(const Vector3& rhs) const;
+		/// Inequality operator.
+		/// @param[in] rhs The vector to compare this against.
+		/// @return True if the two vectors are not equal, false otherwise.
+		inline bool operator!=(const Vector3& rhs) const;
+
+		/// Constant auto-cast operator.
+		/// @return A pointer to the first value.
+		inline operator const Type*() const;
+		/// Auto-cast operator.
+		/// @return A constant pointer to the first value.
+		inline operator Type*();
+
+		// The components of the vector.
+		Type x;
+		Type y;
+		Type z;
+};
+
+#include <Rocket/Core/Vector3.inl>
+
+}
+}
+
+#endif

+ 195 - 0
Include/Rocket/Core/Vector3.inl

@@ -0,0 +1,195 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+// Default constructor.
+template < typename Type >
+Vector3< Type >::Vector3()
+{
+}
+
+// Initialising constructor.
+template < typename Type >
+Vector3< Type >::Vector3(Type _x, Type _y, Type _z)
+{
+	x = _x;
+	y = _y;
+	z = _z;
+}
+
+// Returns the magnitude of the vector.
+template < typename Type >
+float Vector3< Type >::Magnitude() const
+{
+	float squared_magnitude = (float) SquaredMagnitude();
+	if (Math::IsZero(squared_magnitude))
+		return 0;
+
+	return Math::SquareRoot(squared_magnitude);
+}
+
+// Returns the squared magnitude of the vector.
+template < typename Type >
+Type Vector3< Type >::SquaredMagnitude() const
+{
+	return x * x + y * y + z * z;
+}
+
+// Generates a normalised vector from this vector.
+template < typename Type >
+Vector3< Type > Vector3< Type >::Normalise() const
+{
+	ROCKET_STATIC_ASSERT(false, Invalid_Operation);
+	return *this;
+}
+
+template <>
+ROCKETCORE_API Vector3< float > Vector3< float >::Normalise() const;
+
+// Computes the dot-product between this vector and another.
+template < typename Type >
+Type Vector3< Type >::DotProduct(const Vector3< Type >& rhs) const
+{
+	return x * rhs.x + y * rhs.y + z * rhs.z;
+}
+
+// Computes the cross-product between this vector and another.
+template < typename Type >
+Vector3< Type> Vector3< Type >::CrossProduct(const Vector3< Type >& rhs) const
+{
+	return Vector3< Type > (
+		y * rhs.z - z * rhs.y,
+		z * rhs.x - x * rhs.z,
+		x * rhs.y - y * rhs.x
+	);
+}
+
+// Returns the negation of this vector.
+template < typename Type >
+Vector3< Type > Vector3< Type >::operator-() const
+{
+	return Vector3(-x, -y, -z);
+}
+
+// Returns the sum of this vector and another.
+template < typename Type >
+Vector3< Type > Vector3< Type >::operator+(const Vector3< Type >& rhs) const
+{
+	return Vector3< Type >(x + rhs.x, y + rhs.y, z + rhs.z);
+}
+
+// Returns the result of subtracting another vector from this vector.
+template < typename Type >
+Vector3< Type > Vector3< Type >::operator-(const Vector3< Type >& rhs) const
+{
+	return Vector3(x - rhs.x, y - rhs.y, z - rhs.z);
+}
+
+// Returns the result of multiplying this vector by a scalar.
+template < typename Type >
+Vector3< Type > Vector3< Type >::operator*(Type rhs) const
+{
+	return Vector3(x * rhs, y * rhs, z * rhs);
+}
+
+// Returns the result of dividing this vector by a scalar.
+template < typename Type >
+Vector3< Type > Vector3< Type >::operator/(Type rhs) const
+{
+	return Vector3(x / rhs, y / rhs, z / rhs);
+}
+
+// Adds another vector to this in-place.
+template < typename Type >
+Vector3< Type >& Vector3< Type >::operator+=(const Vector3& rhs)
+{
+	x += rhs.x;
+	y += rhs.y;
+	z += rhs.z;
+
+	return *this;
+}
+
+// Subtracts another vector from this in-place.
+template < typename Type >
+Vector3< Type >& Vector3< Type >::operator-=(const Vector3& rhs)
+{
+	x -= rhs.x;
+	y -= rhs.y;
+	z -= rhs.z;
+
+	return *this;
+}
+
+// Scales this vector in-place.
+template < typename Type >
+Vector3< Type >& Vector3< Type >::operator*=(const Type& rhs)
+{
+	x *= rhs;
+	y *= rhs;
+	z *= rhs;
+
+	return *this;
+}
+
+// Scales this vector in-place by the inverse of a value.
+template < typename Type >
+Vector3< Type >& Vector3< Type >::operator/=(const Type& rhs)
+{
+	x /= rhs;
+	y /= rhs;
+	z /= rhs;
+
+	return *this;
+}
+
+// Equality operator.
+template < typename Type >
+bool Vector3< Type >::operator==(const Vector3& rhs) const
+{
+	return (x == rhs.x && y == rhs.y && z == rhs.z);
+}
+
+// Inequality operator.
+template < typename Type >
+bool Vector3< Type >::operator!=(const Vector3& rhs) const
+{
+	return (x != rhs.x || y != rhs.y || z != rhs.z);
+}
+
+// Constant auto-cast operator.
+template < typename Type >
+Vector3< Type >::operator const Type*() const
+{
+	return &x;
+}
+
+// Auto-cast operator.
+template < typename Type >
+Vector3< Type >::operator Type*()
+{
+	return &x;
+}

+ 143 - 0
Include/Rocket/Core/Vector4.h

@@ -0,0 +1,143 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREVECTOR4_H
+#define ROCKETCOREVECTOR4_H
+
+#include <Rocket/Core/Debug.h>
+#include <Rocket/Core/Math.h>
+#include <Rocket/Core/Vector3.h>
+
+namespace Rocket {
+namespace Core {
+
+/**
+	Templated class for a generic four-component vector.
+	@author Markus Schöngart
+ */
+
+template < typename Type >
+class Vector4
+{
+	public:
+		/// Lightweight, non-initialising constructor.
+		inline Vector4();
+		/// Initialising constructor.
+		/// @param[in] x Initial x-value of the vector.
+		/// @param[in] y Initial y-value of the vector.
+		/// @param[in] z Initial z-value of the vector.
+		/// @param[in] w Initial omega-value of the vector.
+		inline Vector4(Type x, Type y, Type z, Type w = 1);
+		/// Implicit conversion from a 3D Vector.
+		inline Vector4(Vector3< Type > const &v, Type w = 1);
+
+		/// Returns the magnitude of the vector.
+		/// @return The computed magnitude.
+		inline float Magnitude() const;
+		/// Returns the squared magnitude of the vector.
+		/// @return The computed squared magnitude.
+		inline Type SquaredMagnitude() const;
+		/// Generates a normalised vector from this vector.
+		/// @return The normalised vector.
+		inline Vector4 Normalise() const;
+
+		/// Computes the dot-product between this vector and another.
+		/// @param[in] rhs The other vector to use in the dot-product.
+		/// @return The computed dot-product between the two vectors.
+		inline Type DotProduct(const Vector4& rhs) const;
+
+		/// Returns the negation of this vector.
+		/// @return The negation of this vector.
+		inline Vector4 operator-() const;
+
+		/// Returns the sum of this vector and another.
+		/// @param[in] rhs The vector to add this to.
+		/// @return The sum of the two vectors.
+		inline Vector4 operator+(const Vector4& rhs) const;
+		/// Returns the result of subtracting another vector from this vector.
+		/// @param[in] rhs The vector to subtract from this vector.
+		/// @return The result of the subtraction.
+		inline Vector4 operator-(const Vector4& rhs) const;
+		/// Returns the result of multiplying this vector by a scalar.
+		/// @param[in] rhs The scalar value to multiply by.
+		/// @return The result of the scale.
+		inline Vector4 operator*(Type rhs) const;
+		/// Returns the result of dividing this vector by a scalar.
+		/// @param[in] rhs The scalar value to divide by.
+		/// @return The result of the scale.
+		inline Vector4 operator/(Type rhs) const;
+
+		/// Adds another vector to this in-place.
+		/// @param[in] rhs The vector to add.
+		/// @return This vector, post-operation.
+		inline Vector4& operator+=(const Vector4& rhs);
+		/// Subtracts another vector from this in-place.
+		/// @param[in] rhs The vector to subtract.
+		/// @return This vector, post-operation.
+		inline Vector4& operator-=(const Vector4& rhs);
+		/// Scales this vector in-place.
+		/// @param[in] rhs The value to scale this vector's components by.
+		/// @return This vector, post-operation.
+		inline Vector4& operator*=(const Type& rhs);
+		/// Scales this vector in-place by the inverse of a value.
+		/// @param[in] rhs The value to divide this vector's components by.
+		/// @return This vector, post-operation.
+		inline Vector4& operator/=(const Type& rhs);
+
+		/// Equality operator.
+		/// @param[in] rhs The vector to compare this against.
+		/// @return True if the two vectors are equal, false otherwise.
+		inline bool operator==(const Vector4& rhs) const;
+		/// Inequality operator.
+		/// @param[in] rhs The vector to compare this against.
+		/// @return True if the two vectors are not equal, false otherwise.
+		inline bool operator!=(const Vector4& rhs) const;
+
+		/// Auto-cast operator to array of components.
+		/// @return A pointer to the first value.
+		inline operator const Type*() const;
+		/// Constant auto-cast operator to array of components.
+		/// @return A constant pointer to the first value.
+		inline operator Type*();
+
+		/// Auto-cast operator to 3D vector.
+		/// @return Equivalent 3D vector.
+		inline operator Vector3< Type >() const;
+
+		// The components of the vector.
+		Type x;
+		Type y;
+		Type z;
+		Type w;
+};
+
+#include <Rocket/Core/Vector4.inl>
+
+}
+}
+
+#endif

+ 201 - 0
Include/Rocket/Core/Vector4.inl

@@ -0,0 +1,201 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+// Default constructor.
+template < typename Type >
+Vector4< Type >::Vector4()
+{
+}
+
+// Initialising constructor.
+template < typename Type >
+Vector4< Type >::Vector4(Type _x, Type _y, Type _z, Type _w)
+	: x (_x), y (_y), z (_z), w (_w)
+{
+}
+
+// Implicit conversion from a 3D Vector.
+template < typename Type >
+Vector4< Type >::Vector4(Vector3< Type > const &v, Type w)
+	: x (v.x), y (v.y), z (v.z), w (w)
+{
+}
+
+// Returns the magnitude of the vector.
+template < typename Type >
+float Vector4< Type >::Magnitude() const
+{
+	float squared_magnitude = (float) SquaredMagnitude();
+	if (Math::IsZero(squared_magnitude))
+		return 0;
+
+	return Math::SquareRoot(squared_magnitude);
+}
+
+// Returns the squared magnitude of the vector.
+template < typename Type >
+Type Vector4< Type >::SquaredMagnitude() const
+{
+	return x * x + y * y + z * z + w * w;
+}
+
+// Generates a normalised vector from this vector.
+template < typename Type >
+Vector4< Type > Vector4< Type >::Normalise() const
+{
+	ROCKET_STATIC_ASSERT(false, Invalid_Operation);
+	return *this;
+}
+
+template <>
+ROCKETCORE_API Vector4< float > Vector4< float >::Normalise() const;
+
+// Computes the dot-product between this vector and another.
+template < typename Type >
+Type Vector4< Type >::DotProduct(const Vector4< Type >& rhs) const
+{
+	return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w;
+}
+
+// Returns the negation of this vector.
+template < typename Type >
+Vector4< Type > Vector4< Type >::operator-() const
+{
+	return Vector4(-x, -y, -z, -w);
+}
+
+// Returns the sum of this vector and another.
+template < typename Type >
+Vector4< Type > Vector4< Type >::operator+(const Vector4< Type >& rhs) const
+{
+	return Vector4< Type >(x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w);
+}
+
+// Returns the result of subtracting another vector from this vector.
+template < typename Type >
+Vector4< Type > Vector4< Type >::operator-(const Vector4< Type >& rhs) const
+{
+	return Vector4(x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w);
+}
+
+// Returns the result of multiplying this vector by a scalar.
+template < typename Type >
+Vector4< Type > Vector4< Type >::operator*(Type rhs) const
+{
+	return Vector4(x * rhs, y * rhs, z * rhs, w * rhs);
+}
+
+// Returns the result of dividing this vector by a scalar.
+template < typename Type >
+Vector4< Type > Vector4< Type >::operator/(Type rhs) const
+{
+	return Vector4(x / rhs, y / rhs, z / rhs, w / rhs);
+}
+
+// Adds another vector to this in-place.
+template < typename Type >
+Vector4< Type >& Vector4< Type >::operator+=(const Vector4& rhs)
+{
+	x += rhs.x;
+	y += rhs.y;
+	z += rhs.z;
+	w += rhs.w;
+
+	return *this;
+}
+
+// Subtracts another vector from this in-place.
+template < typename Type >
+Vector4< Type >& Vector4< Type >::operator-=(const Vector4& rhs)
+{
+	x -= rhs.x;
+	y -= rhs.y;
+	z -= rhs.z;
+	w -= rhs.w;
+
+	return *this;
+}
+
+// Scales this vector in-place.
+template < typename Type >
+Vector4< Type >& Vector4< Type >::operator*=(const Type& rhs)
+{
+	x *= rhs;
+	y *= rhs;
+	z *= rhs;
+	w *= rhs;
+
+	return *this;
+}
+
+// Scales this vector in-place by the inverse of a value.
+template < typename Type >
+Vector4< Type >& Vector4< Type >::operator/=(const Type& rhs)
+{
+	x /= rhs;
+	y /= rhs;
+	z /= rhs;
+	w /= rhs;
+
+	return *this;
+}
+
+// Equality operator.
+template < typename Type >
+bool Vector4< Type >::operator==(const Vector4& rhs) const
+{
+	return (x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w);
+}
+
+// Inequality operator.
+template < typename Type >
+bool Vector4< Type >::operator!=(const Vector4& rhs) const
+{
+	return (x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w);
+}
+
+// Auto-cast operator.
+template < typename Type >
+Vector4< Type >::operator const Type*() const
+{
+	return &x;
+}
+
+// Constant auto-cast operator.
+template < typename Type >
+Vector4< Type >::operator Type*()
+{
+	return &x;
+}
+
+// Auto-cast operator to 3D vector.
+// @return Equivalent 3D vector.
+template < typename Type >
+Vector4< Type >::operator Vector3< Type >() const
+{
+	return Vector3< Type > (x/w, y/w, z/w);
+}

+ 86 - 0
Include/Rocket/Core/ViewState.h

@@ -0,0 +1,86 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREVIEWSTATE_H
+#define ROCKETCOREVIEWSTATE_H
+
+#include <Rocket/Core/Header.h>
+#include <Rocket/Core/Types.h>
+
+namespace Rocket {
+namespace Core {
+
+/**
+	A ViewState captures the current global projection and view matrices (`camera settings').
+
+	@author Markus Schöngart
+ */
+
+class ROCKETCORE_API ViewState
+{
+public:
+	ViewState();
+
+	/// Stores a new projection matrix
+	void SetProjection(const Matrix4f *projection) throw();
+
+	/// Stores a new view matrix
+	void SetView(const Matrix4f *view) throw();
+
+	/// Retrieves the cancellation matrix (projection * view)⁻¹
+	bool GetProjectionViewInv(Matrix4f& projection_view_inv) const throw();
+
+	/// Calculates the clip space coordinates ([-1; 1]³) of a 3D vertex in world space.
+	/// @param[in] point The point in world space coordinates.
+	/// @return The clip space coordinates of the point.
+	Vector3f Project(const Vector3f &point) const throw();
+	/// Calculates the world space coordinates of a 3D vertex in clip space ([-1; 1]³).
+	/// @param[in] point The point in clip space coordinates.
+	/// @return The world space coordinates of the point.
+	Vector3f Unproject(const Vector3f &point) const throw();
+
+private:
+	// Flags for stored values
+	bool have_projection;
+	bool have_view;
+
+	// Flags for cached values
+	mutable bool projection_view_inv_dirty;
+
+	// Stored values
+	Matrix4f projection;
+	Matrix4f view;
+
+	// Cached values
+	mutable Matrix4f projection_view_inv;
+	void UpdateProjectionViewInv() const throw();
+};
+
+}
+}
+
+#endif

+ 2 - 0
Samples/basic/drag/src/main.cpp

@@ -77,6 +77,8 @@ int main(int ROCKET_UNUSED(argc), char** ROCKET_UNUSED(argv))
 		return -1;
 	}
 
+	opengl_renderer.QueryProjectionView(*context);
+
 	Rocket::Debugger::Initialise(context);
 	Input::SetContext(context);
 

+ 108 - 0
Samples/basic/transform/data/transform.rml

@@ -0,0 +1,108 @@
+<rml>
+<head>
+	<link type="text/template" href="../../../assets/window.rml"/>
+	<title>Transform Sample</title>
+	<style>
+		body
+		{
+			width: 350px;
+			height: 300px;
+		}
+		
+		/* Hide the window icon. */
+		div#title_bar div#icon
+		{
+			display: none;
+		}
+
+		spacer
+		{
+			display: inline-block;
+			width: 25px;
+		}
+	</style>
+</head>
+<body template="window">
+<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
+tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
+vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
+gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum
+dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
+invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
+eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no
+sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit
+amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
+labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam
+et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
+sanctus est Lorem ipsum dolor sit amet.</p>
+
+<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
+molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et
+accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit
+augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
+laoreet dolore magna aliquam erat volutpat.</p>
+
+<p>Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
+lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
+dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore
+eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui
+blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla
+facilisi.</p>
+
+<p>Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming
+id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
+laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
+nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea
+commodo consequat.</p>
+
+<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
+molestie consequat, vel illum dolore eu feugiat nulla facilisis.</p>
+
+<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
+gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum
+dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
+invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
+eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no
+sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit
+amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores
+duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet
+clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero
+voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
+consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore
+et dolore magna aliquyam erat.</p>
+
+<p>Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
+labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam
+et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
+sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur
+sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore
+magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
+dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est
+Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing
+elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna
+aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores
+et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus.</p>
+
+<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
+eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
+voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita
+kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem
+ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
+tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
+vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
+gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum
+dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
+invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero
+eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no
+sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
+
+<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
+molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et
+accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit
+augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
+laoreet dolore magna aliquam erat volutpat.</p>
+</body>
+</rml>

+ 193 - 0
Samples/basic/transform/src/main.cpp

@@ -0,0 +1,193 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <Rocket/Core.h>
+#include <Rocket/Controls.h>
+#include <Rocket/Debugger.h>
+#include <Input.h>
+#include <Shell.h>
+
+#include <cmath>
+#include <sstream>
+
+class DemoWindow
+{
+public:
+	DemoWindow(const Rocket::Core::String &title, const Rocket::Core::Vector2f &position, Rocket::Core::Context *context)
+	{
+		document = context->LoadDocument("data/transform.rml");
+		if (document != NULL)
+		{
+			document->GetElementById("title")->SetInnerRML(title);
+			document->SetProperty("left", Rocket::Core::Property(position.x, Rocket::Core::Property::PX));
+			document->SetProperty("top", Rocket::Core::Property(position.y, Rocket::Core::Property::PX));
+			document->Show();
+		}
+	}
+
+	~DemoWindow()
+	{
+		if (document)
+		{
+			document->RemoveReference();
+			document->Close();
+		}
+	}
+
+	void SetPerspective(float distance)
+	{
+		if (document)
+		{
+			std::stringstream s;
+			s << distance;
+			document->SetProperty("perspective", s.str().c_str());
+		}
+	}
+
+	void SetPerspectiveOrigin(float x, float y)
+	{
+		if (document)
+		{
+			std::stringstream s;
+			s << x * 100 << "%" << " " << y * 100 << "%";
+			document->SetProperty("perspective-origin", s.str().c_str());
+		}
+	}
+
+	void SetRotation(float degrees)
+	{
+		if (document)
+		{
+			std::stringstream s;
+			s << "rotate3d(0.0, 1.0, 0.0, " << degrees << ")";
+			document->SetProperty("transform", s.str().c_str());
+		}
+	}
+
+private:
+	Rocket::Core::ElementDocument *document;
+};
+
+Rocket::Core::Context* context = NULL;
+DemoWindow* window_1 = NULL;
+DemoWindow* window_2 = NULL;
+
+void GameLoop()
+{
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	context->Update();
+	context->Render();
+
+	static float deg = 0;
+	Rocket::Core::SystemInterface* system_interface = Rocket::Core::GetSystemInterface();
+	deg = std::fmod(system_interface->GetElapsedTime() * 30.0f, 360.0f);
+	if (window_1)
+	{
+		window_1->SetRotation(deg);
+	}
+	if (window_2)
+	{
+		window_2->SetRotation(deg);
+	}
+
+	Shell::FlipBuffers();
+}
+
+#if defined ROCKET_PLATFORM_WIN32
+#include <windows.h>
+int APIENTRY WinMain(HINSTANCE ROCKET_UNUSED(instance_handle), HINSTANCE ROCKET_UNUSED(previous_instance_handle), char* ROCKET_UNUSED(command_line), int ROCKET_UNUSED(command_show))
+#else
+int main(int ROCKET_UNUSED(argc), char** ROCKET_UNUSED(argv))
+#endif
+{
+	// Generic OS initialisation, creates a window and attaches OpenGL.
+	if (!Shell::Initialise("../Samples/basic/transform/") ||
+		!Shell::OpenWindow("Transform Sample", true))
+	{
+		Shell::Shutdown();
+		return -1;
+	}
+
+	// Rocket initialisation.
+	ShellRenderInterfaceOpenGL opengl_renderer;
+	opengl_renderer.SetViewport(1024,768);
+
+	Rocket::Core::SetRenderInterface(&opengl_renderer);
+
+	ShellSystemInterface system_interface;
+	Rocket::Core::SetSystemInterface(&system_interface);
+
+	Rocket::Core::Initialise();
+
+	// Create the main Rocket context and set it on the shell's input layer.
+	context = Rocket::Core::CreateContext("main", Rocket::Core::Vector2i(1024, 768));
+	if (context == NULL)
+	{
+		Rocket::Core::Shutdown();
+		Shell::Shutdown();
+		return -1;
+	}
+
+	float M[16];
+	glGetFloatv(GL_PROJECTION_MATRIX, M);
+	context->ProcessProjectionChange(Rocket::Core::Matrix4f::FromColumnMajor(M));
+	glGetFloatv(GL_MODELVIEW_MATRIX, M);
+	context->ProcessViewChange(Rocket::Core::Matrix4f::FromColumnMajor(M));
+
+	Rocket::Controls::Initialise();
+	Rocket::Debugger::Initialise(context);
+	Input::SetContext(context);
+
+	Shell::LoadFonts("../../assets/");
+
+	window_1 = new DemoWindow("Orthographic transform", Rocket::Core::Vector2f(81, 200), context);
+	if (window_1)
+	{
+		window_1->SetPerspective(0);
+	}
+	window_2 = new DemoWindow("Perspective transform", Rocket::Core::Vector2f(593, 200), context);
+	if (window_2)
+	{
+		window_2->SetPerspective(800);
+		window_2->SetPerspectiveOrigin(0.5, 0.75);
+	}
+
+	Shell::EventLoop(GameLoop);
+
+	delete window_1;
+	delete window_2;
+
+	// Shutdown Rocket.
+	context->RemoveReference();
+	Rocket::Core::Shutdown();
+
+	Shell::CloseWindow();
+	Shell::Shutdown();
+
+	return 0;
+}

+ 2 - 0
Samples/invaders/src/main.cpp

@@ -89,6 +89,8 @@ int main(int, char**)
 		return -1;
 	}
 
+	opengl_renderer.QueryProjectionView(*context);
+
 	// Initialise the Rocket debugger.
 	Rocket::Debugger::Initialise(context);
 	Input::SetContext(context);

+ 11 - 0
Samples/shell/include/ShellRenderInterfaceOpenGL.h

@@ -47,6 +47,9 @@ public:
      */
     void SetViewport(int width, int height);
 
+	/// Query the current projection and view matrices and tell the context about them.
+	void QueryProjectionView(Rocket::Core::Context& context);
+
 	/// Called by Rocket when it wants to render geometry that it does not wish to optimise.
 	virtual void RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation);
 
@@ -70,9 +73,17 @@ public:
 	/// Called by Rocket when a loaded texture is no longer required.
 	virtual void ReleaseTexture(Rocket::Core::TextureHandle texture_handle);
 
+	/// Called by Rocket when it wants to set the current transform matrix to a new matrix.
+	virtual void PushTransform(const Rocket::Core::RowMajorMatrix4f& transform);
+	virtual void PushTransform(const Rocket::Core::ColumnMajorMatrix4f& transform);
+
+	/// Called by Rocket when it wants to revert the latest transform change.
+	virtual void PopTransform(const Rocket::Core::Matrix4f& transform);
+
 private:
 	int m_width;
 	int m_height;
+	int m_transforms;
 };
 
 #endif

+ 74 - 4
Samples/shell/src/ShellRenderInterfaceOpenGL.cpp

@@ -38,6 +38,18 @@ void ShellRenderInterfaceOpenGL::SetViewport(int width, int height)
 {
     m_width = width;
     m_height = height;
+    m_transforms = 0;
+}
+
+void ShellRenderInterfaceOpenGL::QueryProjectionView(Rocket::Core::Context& context)
+{
+	float values[16];
+
+	glGetFloatv(GL_PROJECTION_MATRIX, values);
+	context.ProcessProjectionChange(Rocket::Core::Matrix4f::FromColumnMajor(values));
+
+	glGetFloatv(GL_MODELVIEW_MATRIX, values);
+	context.ProcessViewChange(Rocket::Core::Matrix4f::FromColumnMajor(values));
 }
 
 
@@ -88,16 +100,54 @@ void ShellRenderInterfaceOpenGL::ReleaseCompiledGeometry(Rocket::Core::CompiledG
 // Called by Rocket when it wants to enable or disable scissoring to clip content.		
 void ShellRenderInterfaceOpenGL::EnableScissorRegion(bool enable)
 {
-	if (enable)
-		glEnable(GL_SCISSOR_TEST);
-	else
+	if (enable) {
+		if (m_transforms <= 0) {
+			glEnable(GL_SCISSOR_TEST);
+			glDisable(GL_STENCIL_TEST);
+		} else {
+			glDisable(GL_SCISSOR_TEST);
+			glEnable(GL_STENCIL_TEST);
+		}
+	} else {
 		glDisable(GL_SCISSOR_TEST);
+		glDisable(GL_STENCIL_TEST);
+	}
 }
 
 // Called by Rocket when it wants to change the scissor region.		
 void ShellRenderInterfaceOpenGL::SetScissorRegion(int x, int y, int width, int height)
 {
-	glScissor(x, m_height - (y + height), width, height);
+	if (m_transforms <= 0) {
+		glScissor(x, m_height - (y + height), width, height);
+	} else {
+		// clear the stencil buffer
+		glStencilMask(-1);
+		glClear(GL_STENCIL_BUFFER_BIT);
+
+		// fill the stencil buffer
+		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+		glDepthMask(GL_FALSE);
+		glStencilFunc(GL_NEVER, 1, -1);
+		glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
+		// draw transformed quad
+		GLfloat vertices[] = {
+			x, y, 0,
+			x, y + height, 0,
+			x + width, y + height, 0,
+			x + width, y, 0
+		};
+		glDisableClientState(GL_COLOR_ARRAY);
+		glVertexPointer(3, GL_FLOAT, 0, vertices);
+		GLushort indices[] = { 1, 2, 0, 3 };
+		glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices);
+		glEnableClientState(GL_COLOR_ARRAY);
+	
+		// prepare for drawing the real thing
+		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+		glDepthMask(GL_TRUE);
+		glStencilMask(0);
+		glStencilFunc(GL_EQUAL, 1, -1);
+	}
 }
 
 // Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
@@ -222,3 +272,23 @@ void ShellRenderInterfaceOpenGL::ReleaseTexture(Rocket::Core::TextureHandle text
 	glDeleteTextures(1, (GLuint*) &texture_handle);
 }
 
+// Called by Rocket when it wants to set the current transform matrix to a new matrix.
+void ShellRenderInterfaceOpenGL::PushTransform(const Rocket::Core::RowMajorMatrix4f& transform)
+{
+	glPushMatrix();
+	glLoadMatrixf(transform.Transpose());
+	++m_transforms;
+}
+void ShellRenderInterfaceOpenGL::PushTransform(const Rocket::Core::ColumnMajorMatrix4f& transform)
+{
+	glPushMatrix();
+	glLoadMatrixf(transform);
+	++m_transforms;
+}
+
+// Called by Rocket when it wants to revert the latest transform change.
+void ShellRenderInterfaceOpenGL::PopTransform(const Rocket::Core::Matrix4f& transform)
+{
+	glPopMatrix();
+	--m_transforms;
+}

+ 1 - 0
Samples/shell/src/x11/ShellX11.cpp

@@ -83,6 +83,7 @@ bool Shell::OpenWindow(const char* name, bool attach_opengl)
 							GLX_GREEN_SIZE, 8,
 							GLX_BLUE_SIZE, 8,
 							GLX_DEPTH_SIZE, 24,
+							GLX_STENCIL_SIZE, 8,
 							None};
 
 	visual_info = glXChooseVisual(display, screen, attribute_list);

+ 37 - 6
Source/Core/Context.cpp

@@ -40,7 +40,11 @@ namespace Core {
 
 const float DOUBLE_CLICK_TIME = 0.5f;
 
-Context::Context(const String& name) : name(name), mouse_position(0, 0), dimensions(0, 0), clip_origin(-1, -1), clip_dimensions(-1, -1)
+Context::Context(const String& name) :
+	name(name), dimensions(0, 0),
+	mouse_position(0, 0),
+	clip_origin(-1, -1), clip_dimensions(-1, -1),
+	view_state()
 {
 	instancer = NULL;
 
@@ -120,9 +124,16 @@ void Context::SetDimensions(const Vector2i& _dimensions)
 				document->DirtyLayout();
 				document->UpdatePosition();
 			}
+
+			// We need to rebuild our projection matrices when the
+			// dimensions change.
+			root->GetChild(i)->DirtyTransformState(true, false, false);
 		}
 		
 		clip_dimensions = dimensions;
+
+		// TODO: Ensure the user calls ProcessProjectionChange() before
+		// the next rendering phase.
 	}
 }
 
@@ -132,6 +143,12 @@ const Vector2i& Context::GetDimensions() const
 	return dimensions;
 }
 
+// Returns the current state of the view.
+const ViewState& Context::GetViewState() const throw()
+{
+	return view_state;
+}
+
 // Updates all elements in the element tree.
 bool Context::Update()
 {
@@ -800,6 +817,18 @@ bool Context::ProcessMouseWheel(int wheel_delta, int key_modifier_state)
 	return true;
 }
 
+// Notifies Rocket of a change in the projection matrix.
+void Context::ProcessProjectionChange(const Matrix4f &projection)
+{
+	view_state.SetProjection(&projection);
+}
+
+// Notifies Rocket of a change in the view matrix.
+void Context::ProcessViewChange(const Matrix4f &view)
+{
+	view_state.SetView(&view);
+}
+
 // Gets the context's render interface.
 RenderInterface* Context::GetRenderInterface() const
 {
@@ -1092,17 +1121,19 @@ Element* Context::GetElementAtPoint(const Vector2f& point, const Element* ignore
 		}
 	}
 
+	Vector2f projected_point = element->Project(point);
+
 	// Check if the point is actually within this element.
-	bool within_element = element->IsPointWithinElement(point);
+	bool within_element = element->IsPointWithinElement(projected_point);
 	if (within_element)
 	{
 		Vector2i clip_origin, clip_dimensions;
 		if (ElementUtilities::GetClippingRegion(clip_origin, clip_dimensions, element))
 		{
-			within_element = point.x >= clip_origin.x &&
-							 point.y >= clip_origin.y &&
-							 point.x <= (clip_origin.x + clip_dimensions.x) &&
-							 point.y <= (clip_origin.y + clip_dimensions.y);
+			within_element = projected_point.x >= clip_origin.x &&
+							 projected_point.y >= clip_origin.y &&
+							 projected_point.x <= (clip_origin.x + clip_dimensions.x) &&
+							 projected_point.y <= (clip_origin.y + clip_dimensions.y);
 		}
 	}
 

+ 4 - 4
Source/Core/DecoratorTiledInstancer.cpp

@@ -40,10 +40,10 @@ DecoratorTiledInstancer::~DecoratorTiledInstancer()
 void DecoratorTiledInstancer::RegisterTileProperty(const String& name, bool register_repeat_modes)
 {
 	RegisterProperty(String(32, "%s-src", name.CString()), "").AddParser("string");
-	RegisterProperty(String(32, "%s-s-begin", name.CString()), "0").AddParser("number");
-	RegisterProperty(String(32, "%s-s-end", name.CString()), "1").AddParser("number");
-	RegisterProperty(String(32, "%s-t-begin", name.CString()), "0").AddParser("number");
-	RegisterProperty(String(32, "%s-t-end", name.CString()), "1").AddParser("number");
+	RegisterProperty(String(32, "%s-s-begin", name.CString()), "0").AddParser("length");
+	RegisterProperty(String(32, "%s-s-end", name.CString()), "1").AddParser("length");
+	RegisterProperty(String(32, "%s-t-begin", name.CString()), "0").AddParser("length");
+	RegisterProperty(String(32, "%s-t-end", name.CString()), "1").AddParser("length");
 	RegisterShorthand(String(32, "%s-s", name.CString()), String(64, "%s-s-begin, %s-s-end", name.CString(), name.CString()));
 	RegisterShorthand(String(32, "%s-t", name.CString()), String(64, "%s-t-begin, %s-t-end", name.CString(), name.CString()));
 

+ 537 - 1
Source/Core/Element.cpp

@@ -28,7 +28,9 @@
 #include "precompiled.h"
 #include <Rocket/Core/Element.h>
 #include <Rocket/Core/Dictionary.h>
+#include <Rocket/Core/TransformPrimitive.h>
 #include <algorithm>
+#include <limits>
 #include "ElementBackground.h"
 #include "ElementBorder.h"
 #include "ElementDefinition.h"
@@ -73,7 +75,7 @@ public:
 };
 
 /// Constructs a new libRocket element.
-Element::Element(const String& _tag) : absolute_offset(0, 0), relative_offset_base(0, 0), relative_offset_position(0, 0), scroll_offset(0, 0), content_offset(0, 0), content_box(0, 0), boxes(1)
+Element::Element(const String& _tag) : absolute_offset(0, 0), relative_offset_base(0, 0), relative_offset_position(0, 0), scroll_offset(0, 0), content_offset(0, 0), content_box(0, 0), boxes(1), transform_state(), transform_state_perspective_dirty(true), transform_state_transform_dirty(true), transform_state_parent_transform_dirty(true)
 {
 	tag = _tag.ToLower();
 	parent = NULL;
@@ -159,6 +161,9 @@ void Element::Update()
 	// Force a definition reload, if necessary.
 	style->GetDefinition();
 
+	// Update the transform state, if necessary.
+	UpdateTransformState();
+
 	scroll->Update();
 	OnUpdate();
 }
@@ -169,6 +174,9 @@ void Element::Render()
 	if (stacking_context_dirty)
 		BuildLocalStackingContext();
 
+	// Apply our transform
+	ElementUtilities::ApplyTransform(*this);
+
 	// Render all elements in our local stacking context that have a z-index beneath our local index of 0.
 	size_t i = 0;
 	for (; i < stacking_context.size() && stacking_context[i]->z_index < 0; ++i)
@@ -187,6 +195,9 @@ void Element::Render()
 	// Render the rest of the elements in the stacking context.
 	for (; i < stacking_context.size(); ++i)
 		stacking_context[i]->Render();
+
+	// Unapply our transform
+	ElementUtilities::UnapplyTransform(*this);
 }
 
 // Clones this element, returning a new, unparented element.
@@ -605,6 +616,234 @@ const Property *Element::GetVerticalAlignProperty()
 	return style->GetVerticalAlignProperty();
 }
 
+// Returns 'perspective' property value from element's style or local cache.
+const Property *Element::GetPerspective()
+{
+	return style->GetPerspective();
+}
+
+// Returns 'perspective-origin-x' property value from element's style or local cache.
+const Property *Element::GetPerspectiveOriginX()
+{
+	return style->GetPerspectiveOriginX();
+}
+
+// Returns 'perspective-origin-y' property value from element's style or local cache.
+const Property *Element::GetPerspectiveOriginY()
+{
+	return style->GetPerspectiveOriginY();
+}
+
+// Returns 'transform' property value from element's style or local cache.
+const Property *Element::GetTransform()
+{
+	return style->GetTransform();
+}
+
+// Returns 'transform-origin-x' property value from element's style or local cache.
+const Property *Element::GetTransformOriginX()
+{
+	return style->GetTransformOriginX();
+}
+
+// Returns 'transform-origin-y' property value from element's style or local cache.
+const Property *Element::GetTransformOriginY()
+{
+	return style->GetTransformOriginY();
+}
+
+// Returns 'transform-origin-z' property value from element's style or local cache.
+const Property *Element::GetTransformOriginZ()
+{
+	return style->GetTransformOriginZ();
+}
+
+// Returns this element's TransformState
+const TransformState *Element::GetTransformState() const throw()
+{
+	return transform_state.get();
+}
+
+// Returns the TransformStates that are effective for this element.
+void Element::GetEffectiveTransformState(
+	const TransformState **local_perspective,
+	const TransformState **perspective,
+	const TransformState **transform
+) throw()
+{
+	UpdateTransformState();
+
+	if (local_perspective)
+	{
+		*local_perspective = 0;
+	}
+	if (perspective)
+	{
+		*perspective = 0;
+	}
+	if (transform)
+	{
+		*transform = 0;
+	}
+
+	// Find the TransformState to use for unprojecting.
+	if (transform_state.get() && transform_state->GetLocalPerspective(0))
+	{
+		if (local_perspective)
+		{
+			*local_perspective = transform_state.get();
+		}
+	}
+	else
+	{
+		Element *node = 0;
+		for (node = parent; node; node = node->parent)
+		{
+			if (node->transform_state.get() && node->transform_state->GetPerspective(0))
+			{
+				if (perspective)
+				{
+					*perspective = node->transform_state.get();
+				}
+				break;
+			}
+		}
+	}
+
+	// Find the TransformState to use for transforming.
+	Element *node = 0;
+	for (node = this; node; node = node->parent)
+	{
+		if (node->transform_state.get() && node->transform_state->GetRecursiveTransform(0))
+		{
+			if (transform)
+			{
+				*transform = node->transform_state.get();
+			}
+			break;
+		}
+	}
+}
+
+// Project a 2D point in pixel coordinates onto the element's plane.
+const Vector2f Element::Project(const Vector2f& point) throw()
+{
+	UpdateTransformState();
+
+	Context *context = GetContext();
+	if (!context)
+	{
+		return point;
+	}
+
+	const TransformState *local_perspective, *perspective, *transform;
+	GetEffectiveTransformState(&local_perspective, &perspective, &transform);
+
+	Vector2i view_pos(0, 0);
+	Vector2i view_size = context->GetDimensions();
+
+	// Compute the line segment for ray picking, one point on the near and one on the far plane.
+	// These need to be in clip space coordinates ([-1; 1]³) so that we an unproject them.
+	Vector3f line_segment[2] =
+	{
+		// When unprojected, the intersection point on the near plane
+		Vector3f(
+			(point.x - view_pos.x) / (0.5f * view_size.x) - 1.0f,
+			(view_size.y - point.y - view_pos.y) / (0.5f * view_size.y) - 1.0f,
+			-1
+		),
+		// When unprojected, the intersection point on the far plane
+		Vector3f(
+			(point.x - view_pos.x) / (0.5f * view_size.x) - 1.0f,
+			(view_size.y - point.y - view_pos.y) / (0.5f * view_size.y) - 1.0f,
+			1
+		)
+	};
+
+	// Find the TransformState to use for unprojecting.
+	if (local_perspective)
+	{
+		TransformState::LocalPerspective the_local_perspective;
+		local_perspective->GetLocalPerspective(&the_local_perspective);
+		line_segment[0] = the_local_perspective.Unproject(line_segment[0]);
+		line_segment[1] = the_local_perspective.Unproject(line_segment[1]);
+	}
+	else if (perspective)
+	{
+		TransformState::Perspective the_perspective;
+		perspective->GetPerspective(&the_perspective);
+		line_segment[0] = the_perspective.Unproject(line_segment[0]);
+		line_segment[1] = the_perspective.Unproject(line_segment[1]);
+	}
+	else
+	{
+		line_segment[0] = context->GetViewState().Unproject(line_segment[0]);
+		line_segment[1] = context->GetViewState().Unproject(line_segment[1]);
+	}
+
+	// Compute three points on the context's corners to define the element's plane.
+	// It may seem elegant to base this computation on the element's size, but
+	// there are elements with zero length or height.
+	Vector3f element_rect[3] =
+	{
+		// Top-left corner
+		Vector3f(0, 0, 0),
+		// Top-right corner
+		Vector3f(view_size.x, 0, 0),
+		// Bottom-left corner
+		Vector3f(0, view_size.y, 0)
+	};
+	// Transform by the correct matrix
+	if (transform)
+	{
+		element_rect[0] = transform->Transform(element_rect[0]);
+		element_rect[1] = transform->Transform(element_rect[1]);
+		element_rect[2] = transform->Transform(element_rect[2]);
+	}
+
+	Vector3f u = line_segment[0] - line_segment[1];
+	Vector3f v = element_rect[1] - element_rect[0];
+	Vector3f w = element_rect[2] - element_rect[0];
+
+	// Now compute the intersection point of the line segment and the element's rectangle.
+	// This is based on the algorithm discussed at Wikipedia
+	// (http://en.wikipedia.org/wiki/Line-plane_intersection).
+	Matrix4f A = Matrix4f::FromColumns(
+		Vector4f(u, 0),
+		Vector4f(v, 0),
+		Vector4f(w, 0),
+		Vector4f(0, 0, 0, 1)
+	);
+	if (A.Invert())
+	{
+		Vector3f factors = A * (line_segment[0] - element_rect[0]);
+		Vector3f intersection3d = element_rect[0] + v * factors[1] + w * factors[2];
+		Vector3f projected;
+		if (transform)
+		{
+			projected = transform->Untransform(intersection3d);
+			//ROCKET_ASSERT(fabs(projected.z) < 0.0001);
+		}
+		else
+		{
+			// FIXME: Is this correct?
+			projected = intersection3d;
+		}
+		return Vector2f(projected.x, projected.y);
+	}
+	else
+	{
+		// The line segment is parallel to the element's plane.
+		// Although, mathematically, it could also lie within the plane
+		// (yielding infinitely many intersection points), we still
+		// return a value that's pretty sure to not match anything,
+		// since this case has nothing to do with the user `picking'
+		// anything.
+		float inf = std::numeric_limits< float >::infinity();
+		return Vector2f(-inf, -inf);
+	}
+}
+
 // Iterates over the properties defined on this element.
 bool Element::IterateProperties(int& index, PseudoClassList& pseudo_classes, String& name, const Property*& property) const
 {
@@ -1620,6 +1859,25 @@ void Element::OnPropertyChange(const PropertyNameList& changed_properties)
 	{
 		clipping_state_dirty = true;
 	}
+
+	// Check for `perspective' and `perspective-origin' changes
+	if (all_dirty ||
+		changed_properties.find(PERSPECTIVE) != changed_properties.end() ||
+		changed_properties.find(PERSPECTIVE_ORIGIN_X) != changed_properties.end() ||
+		changed_properties.find(PERSPECTIVE_ORIGIN_Y) != changed_properties.end())
+	{
+		DirtyTransformState(true, false, false);
+	}
+
+	// Check for `transform' and `transform-origin' changes
+	if (all_dirty ||
+		changed_properties.find(TRANSFORM) != changed_properties.end() ||
+		changed_properties.find(TRANSFORM_ORIGIN_X) != changed_properties.end() ||
+		changed_properties.find(TRANSFORM_ORIGIN_Y) != changed_properties.end() ||
+		changed_properties.find(TRANSFORM_ORIGIN_Z) != changed_properties.end())
+	{
+		DirtyTransformState(false, true, false);
+	}
 }
 
 // Called when a child node has been added somewhere in the hierarchy
@@ -1967,5 +2225,283 @@ void Element::DirtyStructure()
 	}
 }
 
+void Element::DirtyTransformState(bool perspective_changed, bool transform_changed, bool parent_transform_changed)
+{
+	for (size_t i = 0; i < children.size(); ++i)
+	{
+		children[i]->DirtyTransformState(false, false, transform_changed || parent_transform_changed);
+	}
+
+	if (perspective_changed)
+	{
+		this->transform_state_perspective_dirty = true;
+	}
+	if (transform_changed)
+	{
+		this->transform_state_transform_dirty = true;
+	}
+	if (parent_transform_changed)
+	{
+		this->transform_state_parent_transform_dirty = true;
+	}
+}
+
+void Element::UpdateTransformState()
+{
+	Context *context = GetContext();
+
+	Vector2f pos = GetAbsoluteOffset(Box::BORDER);
+	Vector2f size = GetBox().GetSize(Box::BORDER);
+
+	if (transform_state_perspective_dirty || transform_state_transform_dirty || transform_state_parent_transform_dirty)
+	{
+		if (!transform_state.get())
+		{
+			transform_state.reset(new TransformState());
+		}
+	}
+
+	if (transform_state_perspective_dirty)
+	{
+		bool have_perspective = false;
+		TransformState::Perspective perspective_value;
+
+		perspective_value.vanish = Vector2f(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f);
+
+		const Property *perspective = GetPerspective();
+		if (perspective && (perspective->unit != Property::KEYWORD || perspective->value.Get< int >() != PERSPECTIVE_NONE))
+		{
+			have_perspective = true;
+
+			// Compute the perspective value
+			perspective_value.distance = ResolveProperty(perspective, Math::Max(size.x, size.y));
+
+			// Compute the perspective origin, if necessary
+			if (perspective_value.distance > 0)
+			{
+				const Property *perspective_origin_x = GetPerspectiveOriginX();
+				if (perspective_origin_x)
+				{
+					if (perspective_origin_x->unit == Property::KEYWORD)
+					{
+						switch (perspective_origin_x->value.Get< int >())
+						{
+							case PERSPECTIVE_ORIGIN_X_LEFT:
+								perspective_value.vanish.x = pos.x;
+								break;
+
+							case PERSPECTIVE_ORIGIN_X_CENTER:
+								perspective_value.vanish.x = pos.x + size.x * 0.5f;
+								break;
+
+							case PERSPECTIVE_ORIGIN_X_RIGHT:
+								perspective_value.vanish.x = pos.x + size.x;
+								break;
+						}
+					}
+					else
+					{
+						perspective_value.vanish.x = pos.x + ResolveProperty(perspective_origin_x, size.x);
+					}
+				}
+
+				const Property *perspective_origin_y = GetPerspectiveOriginY();
+				if (perspective_origin_y)
+				{
+					if (perspective_origin_y->unit == Property::KEYWORD)
+					{
+						switch (perspective_origin_y->value.Get< int >())
+						{
+							case PERSPECTIVE_ORIGIN_Y_TOP:
+								perspective_value.vanish.y = pos.y;
+								break;
+
+							case PERSPECTIVE_ORIGIN_Y_CENTER:
+								perspective_value.vanish.y = pos.y + size.y * 0.5f;
+								break;
+
+							case PERSPECTIVE_ORIGIN_Y_BOTTOM:
+								perspective_value.vanish.y = pos.y + size.y;
+								break;
+						}
+					}
+					else
+					{
+						perspective_value.vanish.y = pos.y + ResolveProperty(perspective_origin_y, size.y);
+					}
+				}
+			}
+		}
+
+		if (have_perspective && context)
+		{
+			perspective_value.view_size = context->GetDimensions();
+			transform_state->SetPerspective(&perspective_value);
+		}
+		else
+		{
+			transform_state->SetPerspective(0);
+		}
+
+		transform_state_perspective_dirty = false;
+	}
+
+	if (transform_state_transform_dirty)
+	{
+		bool have_local_perspective = false;
+		TransformState::LocalPerspective local_perspective;
+
+		bool have_transform = false;
+		Matrix4f transform_value = Matrix4f::Identity();
+		Vector3f transform_origin(pos.x + size.x * 0.5, pos.y + size.y * 0.5, 0);
+
+		const Property *transform = GetTransform();
+		if (transform && (transform->unit != Property::KEYWORD || transform->value.Get< int >() != TRANSFORM_NONE))
+		{
+			TransformRef transforms = transform->value.Get< TransformRef >();
+			int n = transforms->GetNumPrimitives();
+			for (int i = 0; i < n; ++i)
+			{
+				const Transforms::Primitive &primitive = transforms->GetPrimitive(i);
+
+				if (primitive.ResolvePerspective(local_perspective.distance, *this))
+				{
+					have_local_perspective = true;
+				}
+
+				Matrix4f matrix;
+				if (primitive.ResolveTransform(matrix, *this))
+				{
+					transform_value *= matrix;
+					have_transform = true;
+				}
+			}
+
+			// Compute the transform origin
+			const Property *transform_origin_x = GetTransformOriginX();
+			if (transform_origin_x)
+			{
+				if (transform_origin_x->unit == Property::KEYWORD)
+				{
+					switch (transform_origin_x->value.Get< int >())
+					{
+						case TRANSFORM_ORIGIN_X_LEFT:
+							transform_origin.x = pos.x;
+							break;
+
+						case TRANSFORM_ORIGIN_X_CENTER:
+							transform_origin.x = pos.x + size.x * 0.5f;
+							break;
+
+						case TRANSFORM_ORIGIN_X_RIGHT:
+							transform_origin.x = pos.x + size.x;
+							break;
+					}
+				}
+				else
+				{
+					transform_origin.x = pos.x + ResolveProperty(transform_origin_x, size.x);
+				}
+			}
+
+			const Property *transform_origin_y = GetTransformOriginY();
+			if (transform_origin_y)
+			{
+				if (transform_origin_y->unit == Property::KEYWORD)
+				{
+					switch (transform_origin_y->value.Get< int >())
+					{
+						case TRANSFORM_ORIGIN_Y_TOP:
+							transform_origin.y = pos.y;
+							break;
+
+						case TRANSFORM_ORIGIN_Y_CENTER:
+							transform_origin.y = pos.y + size.y * 0.5f;
+							break;
+
+						case TRANSFORM_ORIGIN_Y_BOTTOM:
+							transform_origin.y = pos.y + size.y;
+							break;
+					}
+				}
+				else
+				{
+					transform_origin.y = pos.y + ResolveProperty(transform_origin_y, size.y);
+				}
+			}
+
+			const Property *transform_origin_z = GetTransformOriginZ();
+			if (transform_origin_z)
+			{
+				transform_origin.z = ResolveProperty(transform_origin_z, Math::Max(size.x, size.y));
+			}
+		}
+
+		if (have_local_perspective && context)
+		{
+			local_perspective.view_size = context->GetDimensions();
+			transform_state->SetLocalPerspective(&local_perspective);
+		}
+		else
+		{
+			transform_state->SetLocalPerspective(0);
+		}
+
+		if (have_transform)
+		{
+			// TODO: If we're using the global projection matrix
+			// (perspective < 0), then scale the coordinates from
+			// pixel space to 3D unit space.
+
+			// Transform the Rocket context so that the computed `transform_origin'
+			// lies at the coordinate system origin.
+			transform_value =
+				  Matrix4f::Translate(transform_origin)
+				* transform_value
+				* Matrix4f::Translate(-transform_origin);
+		}
+
+		transform_state->SetTransform(have_transform ? &transform_value : 0);
+
+		transform_state_transform_dirty = false;
+	}
+
+	if (transform_state_parent_transform_dirty)
+	{
+		// We need to clean up from the top-most to the bottom-most dirt.
+		if (parent)
+		{
+			parent->UpdateTransformState();
+		}
+
+		// Store the parent's new full transform as our parent transform
+		Element *node = 0;
+		Matrix4f parent_transform;
+		for (Element *node = parent; node; node = node->parent)
+		{
+			if (node->GetTransformState() && node->GetTransformState()->GetRecursiveTransform(&parent_transform))
+			{
+				transform_state->SetParentRecursiveTransform(&parent_transform);
+				break;
+			}
+		}
+		if (!node)
+		{
+			transform_state->SetParentRecursiveTransform(0);
+		}
+
+		transform_state_parent_transform_dirty = false;
+	}
+
+	// If we neither have a local perspective, nor a perspective nor a
+	// transform, we don't need to keep the large TransformState object
+	// around. GetEffectiveTransformState() will then recursively visit
+	// parents in order to find a non-trivial TransformState.
+	if (transform_state.get() && !transform_state->GetLocalPerspective(0) && !transform_state->GetPerspective(0) && !transform_state->GetTransform(0))
+	{
+		transform_state.reset(0);
+	}
+}
+
 }
 }

+ 71 - 35
Source/Core/ElementStyle.cpp

@@ -32,10 +32,12 @@
 #include <Rocket/Core/ElementDocument.h>
 #include <Rocket/Core/ElementUtilities.h>
 #include <Rocket/Core/Log.h>
+#include <Rocket/Core/Math.h>
 #include <Rocket/Core/Property.h>
 #include <Rocket/Core/PropertyDefinition.h>
 #include <Rocket/Core/PropertyDictionary.h>
 #include <Rocket/Core/StyleSheetSpecification.h>
+#include <Rocket/Core/TransformPrimitive.h>
 #include "ElementBackground.h"
 #include "ElementBorder.h"
 #include "ElementDecoration.h"
@@ -350,17 +352,21 @@ float ElementStyle::ResolveProperty(const Property* property, float base_value)
 		return 0.0f;
 	}
 
-	if (property->unit & Property::RELATIVE_UNIT)
+	switch (property->unit)
 	{
-		if (property->unit & Property::PERCENT)
+		case Property::NUMBER:
+		case Property::PX:
+		case Property::DEG:
+			return property->value.Get< float >();
+
+		case Property::PERCENT:
 			return base_value * property->value.Get< float >() * 0.01f;
-		else if (property->unit & Property::EM)
+
+		case Property::EM:
 			return property->value.Get< float >() * ElementUtilities::GetFontSize(element);
-	}
 
-	if (property->unit & Property::NUMBER || property->unit & Property::PX)
-	{
-		return property->value.Get< float >();
+		case Property::RAD:
+			return Math::RadiansToDegrees(property->value.Get< float >());
 	}
 
 	// We're not a numeric property; return 0.
@@ -377,43 +383,31 @@ float ElementStyle::ResolveProperty(const String& name, float base_value)
 		return 0.0f;
 	}
 
-	if (property->unit & Property::RELATIVE_UNIT)
+	// The calculated value of the font-size property is inherited, so we need to check if this
+	// is an inherited property. If so, then we return our parent's font size instead.
+	if (name == FONT_SIZE && property->unit & Property::RELATIVE_UNIT)
 	{
-		// The calculated value of the font-size property is inherited, so we need to check if this
-		// is an inherited property. If so, then we return our parent's font size instead.
-		if (name == FONT_SIZE)
-		{
-			Rocket::Core::Element* parent = element->GetParentNode();
-			if (parent == NULL)
-				return 0;
+		Rocket::Core::Element* parent = element->GetParentNode();
+		if (parent == NULL)
+			return 0;
 
-			if (GetLocalProperty(FONT_SIZE) == NULL)
-				return parent->ResolveProperty(FONT_SIZE, 0);
+		if (GetLocalProperty(FONT_SIZE) == NULL)
+			return parent->ResolveProperty(FONT_SIZE, 0);
 
-			// The base value for font size is always the height of *this* element's parent's font.
-			base_value = parent->ResolveProperty(FONT_SIZE, 0);
-		}
+		// The base value for font size is always the height of *this* element's parent's font.
+		base_value = parent->ResolveProperty(FONT_SIZE, 0);
 
-		if (property->unit & Property::PERCENT)
-			return base_value * property->value.Get< float >() * 0.01f;
-		else if (property->unit & Property::EM)
+		switch (property->unit)
 		{
-			// If an em-relative font size is specified, it is expressed relative to the parent's
-			// font height.
-			if (name == FONT_SIZE)
+			case Property::PERCENT:
+				return base_value * property->value.Get< float >() * 0.01f;
+
+			case Property::EM:
 				return property->value.Get< float >() * base_value;
-			else
-				return property->value.Get< float >() * ElementUtilities::GetFontSize(element);
 		}
 	}
 
-	if (property->unit & Property::NUMBER || property->unit & Property::PX)
-	{
-		return property->value.Get< float >();
-	}
-
-	// We're not a numeric property; return 0.
-	return 0.0f;
+	return ResolveProperty(property, base_value);
 }
 
 // Iterates over the properties defined on the element.
@@ -719,5 +713,47 @@ const Property *ElementStyle::GetVerticalAlignProperty()
 	return cache->GetVerticalAlignProperty();
 }
 
+// Returns 'perspective' property value from element's style or local cache.
+const Property *ElementStyle::GetPerspective()
+{
+	return element->GetProperty(PERSPECTIVE);
+}
+
+// Returns 'perspective-origin-x' property value from element's style or local cache.
+const Property *ElementStyle::GetPerspectiveOriginX()
+{
+	return element->GetProperty(PERSPECTIVE_ORIGIN_X);
+}
+
+// Returns 'perspective-origin-y' property value from element's style or local cache.
+const Property *ElementStyle::GetPerspectiveOriginY()
+{
+	return element->GetProperty(PERSPECTIVE_ORIGIN_Y);
+}
+
+// Returns 'transform' property value from element's style or local cache.
+const Property *ElementStyle::GetTransform()
+{
+	return element->GetProperty(TRANSFORM);
+}
+
+// Returns 'transform-origin-x' property value from element's style or local cache.
+const Property *ElementStyle::GetTransformOriginX()
+{
+	return element->GetProperty(TRANSFORM_ORIGIN_X);
+}
+
+// Returns 'transform-origin-y' property value from element's style or local cache.
+const Property *ElementStyle::GetTransformOriginY()
+{
+	return element->GetProperty(TRANSFORM_ORIGIN_Y);
+}
+
+// Returns 'transform-origin-z' property value from element's style or local cache.
+const Property *ElementStyle::GetTransformOriginZ()
+{
+	return element->GetProperty(TRANSFORM_ORIGIN_Z);
+}
+
 }
 }

+ 17 - 0
Source/Core/ElementStyle.h

@@ -107,12 +107,14 @@ public:
 	const Property* GetLocalProperty(const String& name);
 	/// Resolves one of this element's properties. If the value is a number or px, this is returned. If it's a 
 	/// percentage then it is resolved based on the second argument (the base value).
+	/// If it's an angle, it is returned as degrees.
 	/// @param[in] property Property to resolve the value for.
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
 	/// @return The value of this property for this element.
 	float ResolveProperty(const Property *property, float base_value);
 	/// Resolves one of this element's properties. If the value is a number or px, this is returned. If it's a 
 	/// percentage then it is resolved based on the second argument (the base value).
+	/// If it's an angle, it is returned as degrees.
 	/// @param[in] name The name of the property to resolve the value for.
 	/// @param[in] base_value The value that is scaled by the percentage value, if it is a percentage.
 	/// @return The value of this property for this element.
@@ -172,6 +174,21 @@ public:
 	/// Returns 'vertical-align' property value from element's style or local cache.
 	const Property *GetVerticalAlignProperty();
 
+	/// Returns 'perspective' property value from element's style or local cache.
+	const Property *GetPerspective();
+	/// Returns 'perspective-origin-x' property value from element's style or local cache.
+	const Property *GetPerspectiveOriginX();
+	/// Returns 'perspective-origin-y' property value from element's style or local cache.
+	const Property *GetPerspectiveOriginY();
+	/// Returns 'transform' property value from element's style or local cache.
+	const Property *GetTransform();
+	/// Returns 'transform-origin-x' property value from element's style or local cache.
+	const Property *GetTransformOriginX();
+	/// Returns 'transform-origin-y' property value from element's style or local cache.
+	const Property *GetTransformOriginY();
+	/// Returns 'transform-origin-z' property value from element's style or local cache.
+	const Property *GetTransformOriginZ();
+
 	static PropCounter &GetPropCounter();
 
 private:

+ 112 - 0
Source/Core/ElementUtilities.cpp

@@ -28,9 +28,11 @@
 #include "precompiled.h"
 #include <Rocket/Core/ElementUtilities.h>
 #include <queue>
+#include <limits>
 #include "FontFaceHandle.h"
 #include "LayoutEngine.h"
 #include <Rocket/Core.h>
+#include <Rocket/Core/TransformPrimitive.h>
 
 namespace Rocket {
 namespace Core {
@@ -439,5 +441,115 @@ static void SetElementOffset(Element* element, const Vector2f& offset)
 	element->SetOffset(relative_offset, element->GetParentNode());
 }
 
+// Applies an element's `perspective' and `transform' properties.
+bool ElementUtilities::ApplyTransform(Element &element, bool apply)
+{
+	Context *context = element.GetContext();
+	if (!context)
+	{
+		return false;
+	}
+
+	RenderInterface *render_interface = element.GetRenderInterface();
+	if (!render_interface)
+	{
+		return false;
+	}
+
+	const TransformState *local_perspective, *perspective, *transform;
+	element.GetEffectiveTransformState(&local_perspective, &perspective, &transform);
+
+	bool have_perspective = false;
+	float perspective_distance;
+	Matrix4f the_projection;
+	if (local_perspective)
+	{
+		TransformState::LocalPerspective the_local_perspective;
+		local_perspective->GetLocalPerspective(&the_local_perspective);
+		have_perspective = true;
+		perspective_distance = the_local_perspective.distance;
+		the_projection = the_local_perspective.GetProjection();
+	}
+	else if (perspective)
+	{
+		TransformState::Perspective the_perspective;
+		perspective->GetPerspective(&the_perspective);
+		have_perspective = true;
+		perspective_distance = the_perspective.distance;
+		the_projection = the_perspective.GetProjection();
+	}
+
+	bool have_transform = false;
+	Matrix4f the_transform;
+	if (transform)
+	{
+		transform->GetRecursiveTransform(&the_transform);
+		have_transform = true;
+	}
+
+	if (have_perspective && perspective_distance >= 0)
+	{
+		// If we are to apply a custom projection, then we need to cancel the global one first.
+		Matrix4f global_pv_inv;
+		bool have_global_pv_inv = context->GetViewState().GetProjectionViewInv(global_pv_inv);
+
+		if (have_global_pv_inv && have_transform)
+		{
+			if (apply) {
+				render_interface->PushTransform(global_pv_inv * the_projection * the_transform);
+			} else {
+				render_interface->PopTransform(global_pv_inv * the_projection * the_transform);
+			}
+			return true;
+		}
+		else if (have_global_pv_inv)
+		{
+			if (apply) {
+				render_interface->PushTransform(global_pv_inv * the_projection);
+			} else {
+				render_interface->PopTransform(global_pv_inv * the_projection);
+			}
+			return true;
+		}
+		else if (have_transform)
+		{
+			// The context has not received Process(Projection|View)Change() calls.
+			// Assume we don't really need to cancel.
+			if (apply) {
+				render_interface->PushTransform(the_transform);
+			} else {
+				render_interface->PopTransform(the_transform);
+			}
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if (have_transform)
+		{
+			if (apply) {
+				render_interface->PushTransform(the_transform);
+			} else {
+				render_interface->PopTransform(the_transform);
+			}
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+}
+
+// Unapplies an element's `perspective' and `transform' properties.
+bool ElementUtilities::UnapplyTransform(Element &element)
+{
+	return ApplyTransform(element, false);
+}
+
 }
 }

+ 39 - 1
Source/Core/Event.cpp

@@ -41,7 +41,7 @@ Event::Event()
 	target_element = NULL;
 }
 
-Event::Event(Element* _target_element, const String& _type, const Dictionary& _parameters, bool _interruptible) : parameters(_parameters), target_element(_target_element), type(_type), interruptible(_interruptible)
+Event::Event(Element* _target_element, const String& _type, const Dictionary& _parameters, bool _interruptible) : parameters(_parameters), target_element(_target_element), type(_type), parameters_backup(_parameters), interruptible(_interruptible)
 {
 	phase = PHASE_UNKNOWN;
 	interruped = false;
@@ -54,6 +54,7 @@ Event::~Event()
 
 void Event::SetCurrentElement(Element* element)
 {
+	ProjectMouse(element);
 	current_element = element;
 }
 
@@ -111,5 +112,42 @@ void Event::OnReferenceDeactivate()
 	instancer->ReleaseEvent(this);
 }
 
+void Event::ProjectMouse(Element* element)
+{
+	if (element)
+	{
+		Variant *old_mouse_x = parameters_backup.Get("mouse_x");
+		Variant *old_mouse_y = parameters_backup.Get("mouse_y");
+		if (!old_mouse_x || !old_mouse_y)
+		{
+			// This is not a mouse event.
+			return;
+		}
+
+		Variant *mouse_x = parameters.Get("mouse_x");
+		Variant *mouse_y = parameters.Get("mouse_y");
+		if (!mouse_x || !mouse_y)
+		{
+			// This should not happen.
+			return;
+		}
+
+		Vector2f old_mouse(
+			old_mouse_x->Get< float >(),
+			old_mouse_y->Get< float >()
+		);
+		Vector2f mouse = element->Project(old_mouse);
+
+		//mouse_x->Set(int(mouse.x + 0.5f));
+		//mouse_y->Set(int(mouse.y + 0.5f));
+		mouse_x->Set(mouse.x);
+		mouse_y->Set(mouse.y);
+	}
+	else
+	{
+		parameters = parameters_backup;
+	}
+}
+
 }
 }

+ 1 - 1
Source/Core/FontEffectOutlineInstancer.cpp

@@ -35,7 +35,7 @@ namespace Core {
 FontEffectOutlineInstancer::FontEffectOutlineInstancer()
 {
 	RegisterProperty("width", "1", true)
-		.AddParser("number");
+		.AddParser("length");
 }
 
 FontEffectOutlineInstancer::~FontEffectOutlineInstancer()

+ 2 - 2
Source/Core/FontEffectShadowInstancer.cpp

@@ -35,9 +35,9 @@ namespace Core {
 FontEffectShadowInstancer::FontEffectShadowInstancer()
 {
 	RegisterProperty("offset-x", "0", true)
-		.AddParser("number");
+		.AddParser("length");
 	RegisterProperty("offset-y", "0", true)
-		.AddParser("number");
+		.AddParser("length");
 	RegisterShorthand("offset", "offset-x, offset-y");
 }
 

+ 2 - 0
Source/Core/PropertyDefinition.cpp

@@ -132,6 +132,8 @@ bool PropertyDefinition::GetValue(String& value, const Property& property) const
 		break;
 
 		case Property::PX:		value.Append("px"); break;
+		case Property::DEG:		value.Append("deg"); break;
+		case Property::RAD:		value.Append("rad"); break;
 		case Property::EM:		value.Append("em"); break;
 		case Property::PERCENT:	value.Append("%"); break;
 		case Property::INCH:	value.Append("in"); break;

+ 49 - 9
Source/Core/PropertyParserNumber.cpp

@@ -31,16 +31,49 @@
 namespace Rocket {
 namespace Core {
 
-PropertyParserNumber::PropertyParserNumber()
+PropertyParserNumber::PropertyParserNumber(int units)
+	: units(units)
 {
-	unit_suffixes.push_back(UnitSuffix(Property::PX, "px"));
-	unit_suffixes.push_back(UnitSuffix(Property::EM, "em"));
-	unit_suffixes.push_back(UnitSuffix(Property::INCH, "in"));
-	unit_suffixes.push_back(UnitSuffix(Property::CM, "cm"));
-	unit_suffixes.push_back(UnitSuffix(Property::MM, "mm"));
-	unit_suffixes.push_back(UnitSuffix(Property::PT, "pt"));
-	unit_suffixes.push_back(UnitSuffix(Property::PC, "pc"));
-	unit_suffixes.push_back(UnitSuffix(Property::PERCENT, "%"));
+	if (units & Property::PERCENT)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::PERCENT, "%"));
+	}
+	if (units & Property::PX)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::PX, "px"));
+	}
+	if (units & Property::EM)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::EM, "em"));
+	}
+	if (units & Property::INCH)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::INCH, "in"));
+	}
+	if (units & Property::CM)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::CM, "cm"));
+	}
+	if (units & Property::MM)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::MM, "mm"));
+	}
+	if (units & Property::PT)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::PT, "pt"));
+	}
+	if (units & Property::PC)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::PC, "pc"));
+	}
+	if (units & Property::DEG)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::DEG, "deg"));
+	}
+	if (units & Property::RAD)
+	{
+		unit_suffixes.push_back(UnitSuffix(Property::RAD, "rad"));
+	}
 }
 
 PropertyParserNumber::~PropertyParserNumber()
@@ -68,6 +101,13 @@ bool PropertyParserNumber::ParseValue(Property& property, const String& value, c
 		}
 	}
 
+	if ((units & property.unit) == 0)
+	{
+		// Detected unit not allowed (this can only apply to NUMBER,
+		// i.e., when no unit was found but one is required).
+		return false;
+	}
+
 	float float_value;
 	if (sscanf(value.CString(), "%f", &float_value) == 1)
 	{

+ 24 - 1
Source/Core/PropertyParserNumber.h

@@ -42,7 +42,27 @@ namespace Core {
 class PropertyParserNumber : public PropertyParser
 {
 public:
-	PropertyParserNumber();
+	enum
+	{
+		ABS_NUMBER =	Property::NUMBER,
+		NUMBER =	Property::NUMBER
+				| Property::PERCENT,
+		LENGTH =	Property::NUMBER
+				| Property::PERCENT
+				| Property::PX
+				| Property::EM
+				| Property::INCH
+				| Property::CM
+				| Property::MM
+				| Property::PT
+				| Property::PC,
+		ANGLE =		Property::NUMBER
+				| Property::PERCENT
+				| Property::DEG
+				| Property::RAD
+	};
+
+	PropertyParserNumber(int units);
 	virtual ~PropertyParserNumber();
 
 	/// Called to parse a RCSS number declaration.
@@ -56,6 +76,9 @@ public:
 	void Release();
 
 private:
+	// Stores a bit mask of allowed units.
+	int units;
+
 	// Stores a list of the numerical units and their suffixes.
 	typedef std::pair< Property::Unit, String > UnitSuffix;
 	std::vector< UnitSuffix > unit_suffixes;

+ 282 - 0
Source/Core/PropertyParserTransform.cpp

@@ -0,0 +1,282 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include "PropertyParserTransform.h"
+
+namespace Rocket {
+namespace Core {
+
+PropertyParserTransform::PropertyParserTransform()
+	: abs_number(PropertyParserNumber::ABS_NUMBER),
+	  number(PropertyParserNumber::NUMBER),
+	  length(PropertyParserNumber::LENGTH),
+	  angle(PropertyParserNumber::ANGLE)
+{
+}
+
+PropertyParserTransform::~PropertyParserTransform()
+{
+}
+
+// Called to parse a RCSS transform declaration.
+bool PropertyParserTransform::ParseValue(Property& property, const String& value, const ParameterMap& ROCKET_UNUSED(parameters)) const
+{
+	SharedReference< Transform > transform(new Transform);
+
+	char const* next = value.CString();
+
+	Transforms::NumericValue args[16];
+
+	const PropertyParser* angle1[] = { &angle };
+	const PropertyParser* angle2[] = { &angle, &angle };
+	const PropertyParser* length1[] = { &length };
+	const PropertyParser* length2[] = { &length, &length };
+	const PropertyParser* length3[] = { &length, &length, &length };
+	const PropertyParser* length3angle1[] = { &length, &length, &length, &angle };
+	const PropertyParser* number1[] = { &number };
+	const PropertyParser* number2[] = { &number, &number };
+	const PropertyParser* number3[] = { &number, &number, &number };
+	const PropertyParser* abs_numbers6[] = { &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number };
+	const PropertyParser* abs_numbers16[] = { &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number, &abs_number };
+
+	while (strlen(next))
+	{
+		int bytes_read = 0;
+
+		if ((bytes_read = Scan(next, "perspective", length1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::Perspective(args));
+		}
+		else if ((bytes_read = Scan(next, "matrix", abs_numbers6, args, 6)))
+		{
+			transform->AddPrimitive(Transforms::Matrix2D(args));
+		}
+		else if ((bytes_read = Scan(next, "matrix3d", abs_numbers16, args, 16)))
+		{
+			transform->AddPrimitive(Transforms::Matrix3D(args));
+		}
+		else if ((bytes_read = Scan(next, "translateX", length1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::TranslateX(args));
+		}
+		else if ((bytes_read = Scan(next, "translateY", length1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::TranslateY(args));
+		}
+		else if ((bytes_read = Scan(next, "translateZ", length1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::TranslateZ(args));
+		}
+		else if ((bytes_read = Scan(next, "translate", length2, args, 2)))
+		{
+			transform->AddPrimitive(Transforms::Translate2D(args));
+		}
+		else if ((bytes_read = Scan(next, "translate3d", length3, args, 3)))
+		{
+			transform->AddPrimitive(Transforms::Translate3D(args));
+		}
+		else if ((bytes_read = Scan(next, "scaleX", number1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::ScaleX(args));
+		}
+		else if ((bytes_read = Scan(next, "scaleY", number1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::ScaleY(args));
+		}
+		else if ((bytes_read = Scan(next, "scaleZ", number1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::ScaleZ(args));
+		}
+		else if ((bytes_read = Scan(next, "scale", number2, args, 2)))
+		{
+			transform->AddPrimitive(Transforms::Scale2D(args));
+		}
+		else if ((bytes_read = Scan(next, "scale3d", number3, args, 3)))
+		{
+			transform->AddPrimitive(Transforms::Scale3D(args));
+		}
+		else if ((bytes_read = Scan(next, "rotateX", angle1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::RotateX(args));
+		}
+		else if ((bytes_read = Scan(next, "rotateY", angle1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::RotateY(args));
+		}
+		else if ((bytes_read = Scan(next, "rotateZ", angle1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::RotateZ(args));
+		}
+		else if ((bytes_read = Scan(next, "rotate", angle1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::Rotate2D(args));
+		}
+		else if ((bytes_read = Scan(next, "rotate3d", length3angle1, args, 4)))
+		{
+			transform->AddPrimitive(Transforms::Rotate3D(args));
+		}
+		else if ((bytes_read = Scan(next, "skewX", angle1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::SkewX(args));
+		}
+		else if ((bytes_read = Scan(next, "skewY", angle1, args, 1)))
+		{
+			transform->AddPrimitive(Transforms::SkewY(args));
+		}
+		else if ((bytes_read = Scan(next, "skew", angle2, args, 2)))
+		{
+			transform->AddPrimitive(Transforms::Skew2D(args));
+		}
+
+		if (bytes_read > 0)
+		{
+			next += bytes_read;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	property.value = Variant(TransformRef(transform));
+	property.unit = Property::TRANSFORM;
+}
+
+// Destroys the parser.
+void PropertyParserTransform::Release()
+{
+	delete this;
+}
+
+// Scan a string for a parameterized keyword with a certain number of numeric arguments.
+int PropertyParserTransform::Scan(const char* str, const char* keyword, const PropertyParser** parsers, Transforms::NumericValue* args, int nargs) const
+{
+	int total_bytes_read = 0, bytes_read = 0;
+
+	/* use the quicker stack-based argument buffer, if possible */
+	char *arg = 0;
+	char arg_stack[1024];
+	std::string arg_heap;
+	if (strlen(str) < sizeof(arg_stack))
+	{
+		arg = arg_stack;
+	}
+	else
+	{
+		arg_heap = str;
+		arg = &arg_heap[0];
+	}
+
+	/* skip leading white space */
+	bytes_read = 0;
+	sscanf(str, " %n", &bytes_read);
+	str += bytes_read;
+	total_bytes_read += bytes_read;
+
+	/* find the keyword */
+	if (!memcmp(str, keyword, strlen(keyword)))
+	{
+		bytes_read = strlen(keyword);
+		str += bytes_read;
+		total_bytes_read += bytes_read;
+	}
+	else
+	{
+		return 0;
+	}
+
+	/* skip any white space */
+	bytes_read = 0;
+	sscanf(str, " %n", &bytes_read);
+	str += bytes_read;
+	total_bytes_read += bytes_read;
+
+	/* find the opening brace */
+	bytes_read = 0;
+	if (sscanf(str, " ( %n", &bytes_read), bytes_read)
+	{
+		str += bytes_read;
+		total_bytes_read += bytes_read;
+	}
+	else
+	{
+		return 0;
+	}
+
+	/* parse the arguments */
+	for (int i = 0; i < nargs; ++i)
+	{
+		Property prop;
+
+		bytes_read = 0;
+		if (sscanf(str, " %[^,)] %n", arg, &bytes_read), bytes_read
+			&& parsers[i]->ParseValue(prop, String(arg), ParameterMap()))
+		{
+			args[i].number = prop.value.Get<float>();
+			args[i].unit = prop.unit;
+			str += bytes_read;
+			total_bytes_read += bytes_read;
+		}
+		else
+		{
+			return 0;
+		}
+
+		/* find the comma */
+		if (i < nargs - 1)
+		{
+			bytes_read = 0;
+			if (sscanf(str, " , %n", &bytes_read), bytes_read)
+			{
+				str += bytes_read;
+				total_bytes_read += bytes_read;
+			}
+			else
+			{
+				return 0;
+			}
+		}
+	}
+
+	/* find the closing brace */
+	bytes_read = 0;
+	if (sscanf(str, " ) %n", &bytes_read), bytes_read)
+	{
+		str += bytes_read;
+		total_bytes_read += bytes_read;
+	}
+	else
+	{
+		return 0;
+	}
+
+	return total_bytes_read;
+}
+
+}
+}

+ 76 - 0
Source/Core/PropertyParserTransform.h

@@ -0,0 +1,76 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef ROCKETCOREPROPERTYPARSERTRANSFORM_H
+#define ROCKETCOREPROPERTYPARSERTRANSFORM_H
+
+#include <Rocket/Core/PropertyParser.h>
+#include <Rocket/Core/TransformPrimitive.h>
+#include "PropertyParserNumber.h"
+
+namespace Rocket {
+namespace Core {
+
+/**
+	A property parser that parses a RCSS transform property specification.
+
+	@author Markus Schöngart
+ */
+
+class PropertyParserTransform : public PropertyParser
+{
+public:
+	PropertyParserTransform();
+	virtual ~PropertyParserTransform();
+
+	/// Called to parse a RCSS transform declaration.
+	/// @param[out] property The property to set the parsed value on.
+	/// @param[in] value The raw value defined for this property.
+	/// @param[in] parameters The parameters defined for this property.
+	/// @return True if the value was validated successfully, false otherwise.
+	virtual bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const;
+
+	// Destroys the parser.
+	void Release();
+
+private:
+	/// Scan a string for a parameterized keyword with a certain number of numeric arguments.
+	/// @param[in] str The string to search for the parameterized keyword
+	/// @param[in] keyword The name of the keyword to search for
+	/// @param[in] parsers The numeric argument parsers
+	/// @param[out] args The numeric arguments encountered
+	/// @param[in] nargs The number of numeric arguments expected
+	/// @returns The number of bytes read, if the function call occurs at the beginning of str, 0 otherwise.
+	int Scan(const char* str, const char* keyword, const PropertyParser** parsers, Transforms::NumericValue* args, int nargs) const;
+
+	PropertyParserNumber abs_number, number, length, angle;
+};
+
+}
+}
+
+#endif

+ 10 - 0
Source/Core/RenderInterface.cpp

@@ -92,6 +92,16 @@ float RenderInterface::GetPixelsPerInch()
 	return 100;
 }
 
+// Called by Rocket when it wants to change the current transform matrix to a new matrix.
+void RenderInterface::PushTransform(const Matrix4f& transform)
+{
+}
+
+// Called by Rocket when it wants to revert the latest transform change.
+void RenderInterface::PopTransform(const Matrix4f& transform)
+{
+}
+
 // Called when this render interface is released.
 void RenderInterface::Release()
 {

+ 9 - 0
Source/Core/StringCache.cpp

@@ -92,6 +92,15 @@ const String CURSOR = "cursor";
 const String DRAG = "drag";
 const String TAB_INDEX = "tab-index";
 const String SCROLLBAR_MARGIN = "scrollbar-margin";
+const String PERSPECTIVE = "perspective";
+const String PERSPECTIVE_ORIGIN = "perspective-origin";
+const String PERSPECTIVE_ORIGIN_X = "perspective-origin-x";
+const String PERSPECTIVE_ORIGIN_Y = "perspective-origin-y";
+const String TRANSFORM = "transform";
+const String TRANSFORM_ORIGIN = "transform-origin";
+const String TRANSFORM_ORIGIN_X = "transform-origin-x";
+const String TRANSFORM_ORIGIN_Y = "transform-origin-y";
+const String TRANSFORM_ORIGIN_Z = "transform-origin-z";
 
 const String MOUSEDOWN = "mousedown";
 const String MOUSESCROLL = "mousescroll";

+ 9 - 0
Source/Core/StringCache.h

@@ -95,6 +95,15 @@ extern const String CURSOR;
 extern const String DRAG;
 extern const String TAB_INDEX;
 extern const String SCROLLBAR_MARGIN;
+extern const String PERSPECTIVE;
+extern const String PERSPECTIVE_ORIGIN;
+extern const String PERSPECTIVE_ORIGIN_X;
+extern const String PERSPECTIVE_ORIGIN_Y;
+extern const String TRANSFORM;
+extern const String TRANSFORM_ORIGIN;
+extern const String TRANSFORM_ORIGIN_X;
+extern const String TRANSFORM_ORIGIN_Y;
+extern const String TRANSFORM_ORIGIN_Z;
 
 extern const String MOUSEDOWN;
 extern const String MOUSESCROLL;

+ 58 - 30
Source/Core/StyleSheetSpecification.cpp

@@ -31,6 +31,7 @@
 #include "PropertyParserColour.h"
 #include "PropertyParserKeyword.h"
 #include "PropertyParserString.h"
+#include "PropertyParserTransform.h"
 
 namespace Rocket {
 namespace Core {
@@ -138,10 +139,13 @@ bool StyleSheetSpecification::ParsePropertyDeclaration(PropertyDictionary& dicti
 // Registers Rocket's default parsers.
 void StyleSheetSpecification::RegisterDefaultParsers()
 {
-	RegisterParser("number", new PropertyParserNumber());
+	RegisterParser("number", new PropertyParserNumber(PropertyParserNumber::NUMBER));
+	RegisterParser("length", new PropertyParserNumber(PropertyParserNumber::LENGTH));
+	RegisterParser("angle", new PropertyParserNumber(PropertyParserNumber::ANGLE));
 	RegisterParser("keyword", new PropertyParserKeyword());
 	RegisterParser("string", new PropertyParserString());
 	RegisterParser(COLOR, new PropertyParserColour());
+	RegisterParser(TRANSFORM, new PropertyParserTransform());
 }
 
 // Registers Rocket's default style properties.
@@ -151,28 +155,28 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 
 	RegisterProperty(MARGIN_TOP, "0px", false, true)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
+		.AddParser("length");
 	RegisterProperty(MARGIN_RIGHT, "0px", false, true)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
+		.AddParser("length");
 	RegisterProperty(MARGIN_BOTTOM, "0px", false, true)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
+		.AddParser("length");
 	RegisterProperty(MARGIN_LEFT, "0px", false, true)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
+		.AddParser("length");
 	RegisterShorthand(MARGIN, "margin-top, margin-right, margin-bottom, margin-left");
 
-	RegisterProperty(PADDING_TOP, "0px", false, true).AddParser("number");
-	RegisterProperty(PADDING_RIGHT, "0px", false, true).AddParser("number");
-	RegisterProperty(PADDING_BOTTOM, "0px", false, true).AddParser("number");
-	RegisterProperty(PADDING_LEFT, "0px", false, true).AddParser("number");
+	RegisterProperty(PADDING_TOP, "0px", false, true).AddParser("length");
+	RegisterProperty(PADDING_RIGHT, "0px", false, true).AddParser("length");
+	RegisterProperty(PADDING_BOTTOM, "0px", false, true).AddParser("length");
+	RegisterProperty(PADDING_LEFT, "0px", false, true).AddParser("length");
 	RegisterShorthand(PADDING, "padding-top, padding-right, padding-bottom, padding-left");
 
-	RegisterProperty(BORDER_TOP_WIDTH, "0px", false, true).AddParser("number");
-	RegisterProperty(BORDER_RIGHT_WIDTH, "0px", false, true).AddParser("number");
-	RegisterProperty(BORDER_BOTTOM_WIDTH, "0px", false, true).AddParser("number");
-	RegisterProperty(BORDER_LEFT_WIDTH, "0px", false, true).AddParser("number");
+	RegisterProperty(BORDER_TOP_WIDTH, "0px", false, true).AddParser("length");
+	RegisterProperty(BORDER_RIGHT_WIDTH, "0px", false, true).AddParser("length");
+	RegisterProperty(BORDER_BOTTOM_WIDTH, "0px", false, true).AddParser("length");
+	RegisterProperty(BORDER_LEFT_WIDTH, "0px", false, true).AddParser("length");
 	RegisterShorthand(BORDER_WIDTH, "border-top-width, border-right-width, border-bottom-width, border-left-width");
 
 	RegisterProperty(BORDER_TOP_COLOR, "black", false, false).AddParser(COLOR);
@@ -190,16 +194,16 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 	RegisterProperty(POSITION, "static", false, true).AddParser("keyword", "static, relative, absolute, fixed");
 	RegisterProperty(TOP, "0px", false, false)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
-	RegisterProperty(RIGHT, "0px", false, false).AddParser("number")
+		.AddParser("length");
+	RegisterProperty(RIGHT, "0px", false, false).AddParser("length")
 		.AddParser("keyword", "auto")
-		.AddParser("number");
-	RegisterProperty(BOTTOM, "0px", false, false).AddParser("number")
+		.AddParser("length");
+	RegisterProperty(BOTTOM, "0px", false, false).AddParser("length")
 		.AddParser("keyword", "auto")
-		.AddParser("number");
-	RegisterProperty(LEFT, "0px", false, false).AddParser("number")
+		.AddParser("length");
+	RegisterProperty(LEFT, "0px", false, false).AddParser("length")
 		.AddParser("keyword", "auto")
-		.AddParser("number");
+		.AddParser("length");
 
 	RegisterProperty(FLOAT, "none", false, true).AddParser("keyword", "none, left, right");
 	RegisterProperty(CLEAR, "none", false, true).AddParser("keyword", "none, left, right, both");
@@ -210,27 +214,27 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 
 	RegisterProperty(WIDTH, "auto", false, true)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
-	RegisterProperty(MIN_WIDTH, "0px", false, true).AddParser("number");
-	RegisterProperty(MAX_WIDTH, "-1", false, true).AddParser("number");
+		.AddParser("length");
+	RegisterProperty(MIN_WIDTH, "0px", false, true).AddParser("length");
+	RegisterProperty(MAX_WIDTH, "-1", false, true).AddParser("length");
 
 	RegisterProperty(HEIGHT, "auto", false, true)
 		.AddParser("keyword", "auto")
-		.AddParser("number");
-	RegisterProperty(MIN_HEIGHT, "0px", false, true).AddParser("number");
-	RegisterProperty(MAX_HEIGHT, "-1", false, true).AddParser("number");
+		.AddParser("length");
+	RegisterProperty(MIN_HEIGHT, "0px", false, true).AddParser("length");
+	RegisterProperty(MAX_HEIGHT, "-1", false, true).AddParser("length");
 
-	RegisterProperty(LINE_HEIGHT, "1.2", true, true).AddParser("number");
+	RegisterProperty(LINE_HEIGHT, "1.2", true, true).AddParser("length");
 	RegisterProperty(VERTICAL_ALIGN, "baseline", false, true)
 		.AddParser("keyword", "baseline, middle, sub, super, text-top, text-bottom, top, bottom")
-		.AddParser("number");
+		.AddParser("length");
 
 	RegisterProperty(OVERFLOW_X, "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");
 	RegisterProperty(OVERFLOW_Y, "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll");
 	RegisterShorthand("overflow", "overflow-x, overflow-y", PropertySpecification::REPLICATE);
 	RegisterProperty(CLIP, "auto", true, false)
 		.AddParser("keyword", "auto, none")
-		.AddParser("number");
+		.AddParser("length");
 	RegisterProperty(VISIBILITY, "visible", false, false).AddParser("keyword", "visible, hidden");
 
 	// Need some work on this if we are to include images.
@@ -260,7 +264,31 @@ void StyleSheetSpecification::RegisterDefaultProperties()
 	RegisterProperty(TAB_INDEX, "none", false, false).AddParser("keyword", "none, auto");
 	RegisterProperty(FOCUS, "auto", true, false).AddParser("keyword", "none, auto");
 
-	RegisterProperty(SCROLLBAR_MARGIN, "0", false, false).AddParser("number");
+	RegisterProperty(SCROLLBAR_MARGIN, "0", false, false).AddParser("length");
+
+	// Perspective and Transform specifications
+	RegisterProperty(PERSPECTIVE, "none", false, false)
+		.AddParser("keyword", "none")
+		.AddParser("length");
+	RegisterProperty(PERSPECTIVE_ORIGIN_X, "50%", false, false)
+		.AddParser("keyword", "left, center, right")
+		.AddParser("length");
+	RegisterProperty(PERSPECTIVE_ORIGIN_Y, "50%", false, false)
+		.AddParser("keyword", "top, center, bottom")
+		.AddParser("length");
+	RegisterShorthand(PERSPECTIVE_ORIGIN, "perspective-origin-x, perspective-origin-y");
+	RegisterProperty(TRANSFORM, "none", false, false)
+		.AddParser("keyword", "none")
+		.AddParser(TRANSFORM);
+	RegisterProperty(TRANSFORM_ORIGIN_X, "50%", false, false)
+		.AddParser("keyword", "left, center, right")
+		.AddParser("length");
+	RegisterProperty(TRANSFORM_ORIGIN_Y, "50%", false, false)
+		.AddParser("keyword", "top, center, bottom")
+		.AddParser("length");
+	RegisterProperty(TRANSFORM_ORIGIN_Z, "0", false, false)
+		.AddParser("length");
+	RegisterShorthand(TRANSFORM_ORIGIN, "transform-origin-x, transform-origin-y, transform-origin-z");
 }
 
 }

+ 120 - 0
Source/Core/Transform.cpp

@@ -0,0 +1,120 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include <Rocket/Core/Transform.h>
+#include <Rocket/Core/TransformPrimitive.h>
+#include <Rocket/Core/ViewState.h>
+
+namespace Rocket {
+namespace Core {
+
+// Default constructor, initializes an identity transform
+Transform::Transform()
+	: primitives()
+{
+}
+
+Transform::Transform(const Transform& other)
+	: primitives()
+{
+	primitives.reserve(other.primitives.size());
+	Primitives::const_iterator i = other.primitives.begin();
+	Primitives::const_iterator end = other.primitives.end();
+	for (; i != end; ++i)
+	{
+		try
+		{
+			AddPrimitive(**i);
+		}
+		catch(...)
+		{
+			ClearPrimitives();
+			throw;
+		}
+	}
+}
+
+Transform::~Transform()
+{
+	ClearPrimitives();
+}
+
+// Swap the content of two Transfrom instances
+void Transform::Swap(Transform& other)
+{
+	primitives.swap(other.primitives);
+}
+
+// Assignment operato
+const Transform& Transform::operator=(const Transform& other)
+{
+	Transform result(other);
+	Swap(result);
+	return *this;
+}
+
+// Remove all Primitives from this Transform
+void Transform::ClearPrimitives()
+{
+	Primitives::iterator i = primitives.begin();
+	Primitives::iterator end = primitives.end();
+	for (; i != end; ++i)
+	{
+		try
+		{
+			delete *i;
+			*i = 0;
+		}
+		catch(...)
+		{
+		}
+	}
+	primitives.clear();
+}
+
+// Add a Primitive to this Transform
+void Transform::AddPrimitive(const Transforms::Primitive& p)
+{
+	Transforms::Primitive* q = p.Clone();
+	if (!q)
+	{
+		throw std::bad_alloc();
+	}
+	try
+	{
+		primitives.push_back(q);
+	}
+	catch (...)
+	{
+		delete q;
+		throw;
+	}
+}
+
+}
+}

+ 217 - 0
Source/Core/TransformPrimitive.cpp

@@ -0,0 +1,217 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include <Rocket/Core/TransformPrimitive.h>
+#include <iostream>
+
+namespace Rocket {
+namespace Core {
+namespace Transforms {
+
+NumericValue::NumericValue() throw()
+	: number(), unit(Property::UNKNOWN)
+{
+}
+
+NumericValue::NumericValue(float number, Property::Unit unit) throw()
+	: number(number), unit(unit)
+{
+}
+
+float NumericValue::Resolve(Element& e, float base) const throw()
+{
+	Property prop;
+	prop.value = Variant(number);
+	prop.unit = unit;
+	return e.ResolveProperty(&prop, base);
+}
+
+float NumericValue::ResolveWidth(Element& e) const throw()
+{
+	return Resolve(e, e.GetBox().GetSize().x);
+}
+
+float NumericValue::ResolveHeight(Element& e) const throw()
+{
+	return Resolve(e, e.GetBox().GetSize().y);
+}
+
+float NumericValue::ResolveDepth(Element& e) const throw()
+{
+	Vector2f size = e.GetBox().GetSize();
+	return Resolve(e, Math::Max(size.x, size.y));
+}
+
+bool Matrix2D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::FromRows(
+		Vector4f(values[0], values[1], 0, values[2]),
+		Vector4f(values[3], values[4], 0, values[5]),
+		Vector4f(        0,         0, 1,         0),
+		Vector4f(        0,         0, 0,         1)
+	);
+	return true;
+}
+
+bool Matrix3D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::FromRows(
+		Vector4f(values[ 0], values[ 1], values[ 2], values[ 3]),
+		Vector4f(values[ 4], values[ 5], values[ 6], values[ 7]),
+		Vector4f(values[ 8], values[ 9], values[10], values[11]),
+		Vector4f(values[12], values[13], values[14], values[15])
+	);
+	return true;
+}
+
+bool TranslateX::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::TranslateX(values[0].ResolveWidth(e));
+	return true;
+}
+
+bool TranslateY::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::TranslateY(values[0].ResolveHeight(e));
+	return true;
+}
+
+bool TranslateZ::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::TranslateZ(values[0].ResolveDepth(e));
+	return true;
+}
+
+bool Translate2D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::Translate(
+		values[0].ResolveWidth(e),
+		values[1].ResolveHeight(e),
+		0
+	);
+	return true;
+}
+
+bool Translate3D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::Translate(
+		values[0].ResolveWidth(e),
+		values[1].ResolveHeight(e),
+		values[2].ResolveDepth(e)
+	);
+	return true;
+}
+
+bool ScaleX::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::ScaleX(values[0]);
+	return true;
+}
+
+bool ScaleY::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::ScaleY(values[0]);
+	return true;
+}
+
+bool ScaleZ::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::ScaleZ(values[0]);
+	return true;
+}
+
+bool Scale2D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::Scale(values[0], values[1], 1);
+	return true;
+}
+
+bool Scale3D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::Scale(values[0], values[1], values[2]);
+	return true;
+}
+
+bool RotateX::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::RotateX(values[0]);
+	return true;
+}
+
+bool RotateY::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::RotateY(values[0]);
+	return true;
+}
+
+bool RotateZ::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::RotateZ(values[0]);
+	return true;
+}
+
+bool Rotate2D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::RotateZ(values[0]);
+	return true;
+}
+
+bool Rotate3D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::Rotate(Vector3f(values[0], values[1], values[2]), values[3]);
+	return true;
+}
+
+bool SkewX::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	std::cout << "foo" << std::endl;
+	m = Matrix4f::SkewX(values[0]);
+	return true;
+}
+
+bool SkewY::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::SkewY(values[0]);
+	return true;
+}
+
+bool Skew2D::ResolveTransform(Matrix4f& m, Element& e) const throw()
+{
+	m = Matrix4f::Skew(values[0], values[1]);
+	return true;
+}
+
+bool Perspective::ResolvePerspective(float& p, Element& e) const throw()
+{
+	p = values[0].ResolveDepth(e);
+	return true;
+}
+
+}
+}
+}

+ 346 - 0
Source/Core/TransformState.cpp

@@ -0,0 +1,346 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include <Rocket/Core/TransformState.h>
+#include <cmath>
+
+namespace Rocket {
+namespace Core {
+
+Matrix4f TransformState::Perspective::GetProjection() const throw()
+{
+	float depth = Math::Max(view_size.x, view_size.y);
+
+	if (distance == 0)
+	{
+		return Matrix4f::ProjectOrtho(
+			-0.5 * view_size.x,
+			+0.5 * view_size.x,
+			+0.5 * view_size.y,
+			-0.5 * view_size.y,
+			-1.0 * depth,
+			+1.0 * depth
+		) * Matrix4f::Translate(
+			-0.5f * view_size.x,
+			-0.5f * view_size.y,
+			0
+		);
+	}
+	else if (distance > 0)
+	{
+		float far = distance + 1.0 * depth;
+		const float FAR_NEAR_RATIO = 256.0f;
+		float near = Math::Max(1.0f, far / FAR_NEAR_RATIO);
+		float scale = near / distance;
+		return Matrix4f::ProjectPerspective(
+			(-vanish.x) * scale,
+			(view_size.x - vanish.x) * scale,
+			(view_size.y - vanish.y) * scale,
+			(-vanish.y) * scale,
+			near,
+			far
+		) * Matrix4f::Translate(
+			-vanish.x,
+			-vanish.y,
+			-distance
+		);
+	}
+	else /* if (distance < 0) */
+	{
+		return Matrix4f::Identity();
+	}
+}
+
+Vector3f TransformState::Perspective::Project(const Vector3f &point) const throw()
+{
+	if (distance < 0)
+	{
+		return point;
+	}
+	else /* if (distance >= 0) */
+	{
+		return GetProjection() * point;
+	}
+}
+
+Vector3f TransformState::Perspective::Unproject(const Vector3f &point) const throw()
+{
+	if (distance < 0)
+	{
+		return point;
+	}
+	else /* if (distance >= 0) */
+	{
+		Matrix4f projection_inv = GetProjection();
+		projection_inv.Invert();
+		return projection_inv * point;
+	}
+}
+
+Matrix4f TransformState::LocalPerspective::GetProjection() const throw()
+{
+	float depth = Math::Max(view_size.x, view_size.y);
+
+	if (distance == 0)
+	{
+		return Matrix4f::ProjectOrtho(
+			-0.5 * view_size.x,
+			+0.5 * view_size.x,
+			+0.5 * view_size.y,
+			-0.5 * view_size.y,
+			-0.5 * depth,
+			+0.5 * depth
+		) * Matrix4f::Translate(
+			-0.5f * view_size.x,
+			-0.5f * view_size.y,
+			0
+		);
+	}
+	else if (distance > 0)
+	{
+		return Matrix4f::ProjectPerspective(
+			(0 - 0.5f) * view_size.x,
+			(1 - 0.5f) * view_size.x,
+			(1 - 0.5f) * view_size.y,
+			(0 - 0.5f) * view_size.y,
+			distance,
+			distance + depth
+		) * Matrix4f::Translate(
+			-0.5f * view_size.x,
+			-0.5f * view_size.y,
+			-distance - 0.5f * depth
+		);
+	}
+	else /* if (distance < 0) */
+	{
+		return Matrix4f::Identity();
+	}
+}
+
+Vector3f TransformState::LocalPerspective::Project(const Vector3f &point) const throw()
+{
+	if (distance < 0)
+	{
+		return point;
+	}
+	else /* if (distance >= 0) */
+	{
+		return GetProjection() * point;
+	}
+}
+
+Vector3f TransformState::LocalPerspective::Unproject(const Vector3f &point) const throw()
+{
+	if (distance < 0)
+	{
+		return point;
+	}
+	else /* if (distance >= 0) */
+	{
+		Matrix4f projection_inv = GetProjection();
+		projection_inv.Invert();
+		return projection_inv * point;
+	}
+}
+
+TransformState::TransformState()
+	: have_perspective(false), have_local_perspective(false),
+	  have_parent_recursive_transform(false), have_transform(false)
+{
+}
+
+void TransformState::SetPerspective(const Perspective *perspective) throw()
+{
+	if (perspective)
+	{
+		this->perspective = perspective->distance;
+		this->view_size = perspective->view_size;
+		this->vanish = perspective->vanish;
+	}
+
+	have_perspective = perspective != 0;
+}
+
+bool TransformState::GetPerspective(Perspective *perspective) const throw()
+{
+	if (have_perspective && perspective)
+	{
+		perspective->distance = this->perspective;
+		perspective->view_size = this->view_size;
+		perspective->vanish = this->vanish;
+	}
+
+	return have_perspective;
+}
+
+void TransformState::SetLocalPerspective(const LocalPerspective *local_perspective) throw()
+{
+	if (local_perspective)
+	{
+		this->local_perspective = local_perspective->distance;
+		this->view_size = local_perspective->view_size;
+	}
+
+	have_local_perspective = local_perspective != 0;
+}
+
+bool TransformState::GetLocalPerspective(LocalPerspective *local_perspective) const throw()
+{
+	if (have_local_perspective && local_perspective)
+	{
+		local_perspective->distance = this->local_perspective;
+		local_perspective->view_size = this->view_size;
+	}
+
+	return have_local_perspective;
+}
+
+void TransformState::SetTransform(const Matrix4f *transform) throw()
+{
+	if (transform)
+	{
+		this->transform = *transform;
+	}
+
+	have_transform = transform != 0;
+}
+
+bool TransformState::GetTransform(Matrix4f *transform) const throw()
+{
+	if (have_transform)
+	{
+		if (transform)
+		{
+			*transform = this->transform;
+		}
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+void TransformState::SetParentRecursiveTransform(const Matrix4f *parent_recursive_transform) throw()
+{
+	if (parent_recursive_transform)
+	{
+		this->parent_recursive_transform = *parent_recursive_transform;
+	}
+
+	have_parent_recursive_transform = parent_recursive_transform != 0;
+}
+
+bool TransformState::GetParentRecursiveTransform(Matrix4f *transform) const throw()
+{
+	if (have_parent_recursive_transform)
+	{
+		if (transform)
+		{
+			*transform = this->parent_recursive_transform;
+		}
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+Vector3f TransformState::Transform(const Vector3f &point) const throw()
+{
+	if (have_parent_recursive_transform && have_transform)
+	{
+		return parent_recursive_transform * (transform * point);
+	}
+	else if (have_parent_recursive_transform)
+	{
+		return parent_recursive_transform * point;
+	}
+	else if (have_transform)
+	{
+		return transform * point;
+	}
+	else
+	{
+		return point;
+	}
+}
+
+Vector3f TransformState::Untransform(const Vector3f &point) const throw()
+{
+	Matrix4f transform_inv;
+
+	if (have_parent_recursive_transform && have_transform)
+	{
+		transform_inv = parent_recursive_transform * transform;
+		transform_inv.Invert();
+	}
+	else if (have_parent_recursive_transform)
+	{
+		transform_inv = parent_recursive_transform;
+		transform_inv.Invert();
+	}
+	else if (have_transform)
+	{
+		transform_inv = transform;
+		transform_inv.Invert();
+	}
+	else
+	{
+		return point;
+	}
+
+	return transform_inv * point;
+}
+
+bool TransformState::GetRecursiveTransform(Matrix4f *recursive_transform) const throw()
+{
+	if (recursive_transform)
+	{
+		if (have_parent_recursive_transform && have_transform)
+		{
+			*recursive_transform = parent_recursive_transform * transform;
+		}
+		else if (have_parent_recursive_transform)
+		{
+			*recursive_transform = parent_recursive_transform;
+		}
+		else if (have_transform)
+		{
+			*recursive_transform = transform;
+		}
+	}
+
+	return have_parent_recursive_transform || have_transform;
+}
+
+}
+}

+ 42 - 2
Source/Core/Variant.cpp

@@ -61,7 +61,15 @@ void Variant::Clear()
 			string->~String();
 		}
 		break;
-			
+
+		case TRANSFORMREF:
+		{
+			// Clean up the transform.
+			TransformRef* transform = (TransformRef*)data;
+			transform->~TransformRef();
+		}
+		break;
+
 		default:
 		break;
 	}
@@ -89,7 +97,14 @@ void Variant::Set(const Variant& copy)
 			Set(*(String*)copy.data);
 		}
 		break;
-			
+
+		case TRANSFORMREF:
+		{
+			// Create the transform
+			Set(*(TransformRef*)copy.data);
+		}
+		break;
+
 		default:
 			Clear();
 			memcpy(data, copy.data, LOCAL_DATA_SIZE);
@@ -158,6 +173,31 @@ void Variant::Set(const Vector2f& value)
 	SET_VARIANT(Vector2f);
 }
 
+void Variant::Set(const Vector3f& value)
+{
+	type = VECTOR3;
+	SET_VARIANT(Vector3f);
+}
+
+void Variant::Set(const Vector4f& value)
+{
+	type = VECTOR4;
+	SET_VARIANT(Vector4f);
+}
+
+void Variant::Set(const TransformRef& value)
+{
+	if (type == TRANSFORMREF)
+	{
+		SET_VARIANT(TransformRef);
+	}
+	else
+	{
+		type = TRANSFORMREF;
+		new(data) TransformRef(value);
+	}
+}
+
 void Variant::Set(const Colourf& value)
 {
 	type = COLOURF;

+ 55 - 0
Source/Core/Vector3.cpp

@@ -0,0 +1,55 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include <Rocket/Core/Types.h>
+
+namespace Rocket {
+namespace Core {
+
+Vector3i operator*(int lhs, const Vector3i& rhs)
+{
+	return Vector3i(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
+}
+
+Vector3f operator*(float lhs, const Vector3f& rhs)
+{
+	return Vector3f(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
+}
+
+template <>
+Vector3< float > Vector3< float >::Normalise() const
+{
+	float magnitude = Magnitude();
+	if (Math::IsZero(magnitude))
+		return *this;
+
+	return *this / magnitude;
+}
+
+}
+}

+ 55 - 0
Source/Core/Vector4.cpp

@@ -0,0 +1,55 @@
+/*
+ * This source file is part of rocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include <Rocket/Core/Types.h>
+
+namespace Rocket {
+namespace Core {
+
+Vector4i operator*(int lhs, const Vector4i& rhs)
+{
+	return Vector4i(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
+}
+
+Vector4f operator*(float lhs, const Vector4f& rhs)
+{
+	return Vector4f(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w);
+}
+
+template <>
+Vector4< float > Vector4< float >::Normalise() const
+{
+	float magnitude = Magnitude();
+	if (Math::IsZero(magnitude))
+		return *this;
+
+	return *this / magnitude;
+}
+
+}
+}

+ 146 - 0
Source/Core/ViewState.cpp

@@ -0,0 +1,146 @@
+/*
+ * This source file is part of libRocket, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://www.librocket.com
+ *
+ * Copyright (c) 2014 Markus Schöngart
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "precompiled.h"
+#include <Rocket/Core/ViewState.h>
+#include <cmath>
+
+namespace Rocket {
+namespace Core {
+
+ViewState::ViewState()
+	: have_projection(false), have_view(false), projection_view_inv_dirty(true)
+{
+}
+
+void ViewState::SetProjection(const Matrix4f *projection) throw()
+{
+	if (projection)
+	{
+		this->projection = *projection;
+	}
+
+	have_projection = projection != 0;
+	projection_view_inv_dirty = true;
+}
+
+void ViewState::SetView(const Matrix4f *view) throw()
+{
+	if (view)
+	{
+		this->view = *view;
+	}
+
+	have_view = view != 0;
+	projection_view_inv_dirty = true;
+}
+
+bool ViewState::GetProjectionViewInv(Matrix4f& projection_view_inv) const throw()
+{
+	if (have_projection || have_view)
+	{
+		if (projection_view_inv_dirty)
+		{
+			UpdateProjectionViewInv();
+		}
+
+		projection_view_inv = this->projection_view_inv;
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+Vector3f ViewState::Project(const Vector3f &point) const throw()
+{
+	if (have_projection && have_view)
+	{
+		return projection * (view * point);
+	}
+	else if (have_projection)
+	{
+		return projection * point;
+	}
+	else if (have_view)
+	{
+		return view * point;
+	}
+	else
+	{
+		return point;
+	}
+}
+
+Vector3f ViewState::Unproject(const Vector3f &point) const throw()
+{
+	if (have_projection || have_view)
+	{
+		if (projection_view_inv_dirty)
+		{
+			UpdateProjectionViewInv();
+		}
+
+		return projection_view_inv * point;
+	}
+	else
+	{
+		return point;
+	}
+}
+
+void ViewState::UpdateProjectionViewInv() const throw()
+{
+	ROCKET_ASSERT(projection_view_inv_dirty);
+
+	if (have_projection && have_view)
+	{
+		projection_view_inv = projection * view;
+		projection_view_inv.Invert();
+	}
+	else if (have_projection)
+	{
+		projection_view_inv = projection;
+		projection_view_inv.Invert();
+	}
+	else if (have_view)
+	{
+		projection_view_inv = view;
+		projection_view_inv.Invert();
+	}
+	else
+	{
+		projection_view_inv = Matrix4f::Identity();
+	}
+
+	projection_view_inv_dirty = false;
+}
+
+}
+}