浏览代码

Canvas2D Alignment and Creation

First version done.
nockawa 9 年之前
父节点
当前提交
1028398775

+ 132 - 70
src/Canvas2d/babylon.canvas2d.ts

@@ -48,22 +48,21 @@
         public static CACHESTRATEGY_DONTCACHE = 4;
         public static CACHESTRATEGY_DONTCACHE = 4;
 
 
         constructor(scene: Scene, settings?: {
         constructor(scene: Scene, settings?: {
-            id               ?: string,
-            size             ?: Size,
-            renderScaleFactor?: number,
-            isScreenSpace    ?: boolean,
-            cachingStrategy  ?: number,
-            enableInteraction?: boolean,
-            origin           ?: Vector2,
-            isVisible        ?: boolean,
-            marginTop        ?: number | string,
-            marginLeft       ?: number | string,
-            marginRight      ?: number | string,
-            marginBottom     ?: number | string,
-            hAlign           ?: number,
-            vAlign           ?: number,
+            id                        ?: string,
+            children                  ?: Array<Prim2DBase>,
+            size                      ?: Size,
+            renderScaleFactor         ?: number,
+            isScreenSpace             ?: boolean,
+            cachingStrategy           ?: number,
+            enableInteraction         ?: boolean,
+            origin                    ?: Vector2,
+            isVisible                 ?: boolean,
+            backgroundRoundRadius     ?: number,
+            backgroundFill            ?: IBrush2D,
+            backgroundBorder          ?: IBrush2D,
+            backgroundBorderThickNess ?: number,
         }) {
         }) {
-            super(null, settings);
+            super(settings);
 
 
             Prim2DBase._isCanvasInit = false;
             Prim2DBase._isCanvasInit = false;
 
 
@@ -71,10 +70,51 @@
                 settings = {};
                 settings = {};
             }
             }
 
 
-            let renderScaleFactor = (settings.renderScaleFactor == null) ? 1    : settings.renderScaleFactor;
-            let enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
+            let renderScaleFactor = (settings.renderScaleFactor == null) ? 1 : settings.renderScaleFactor;
+            if (this._cachingStrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
+                this._background              = new Rectangle2D({ parent: this, id: "###CANVAS BACKGROUND###", size: settings.size }); //TODO CHECK when size is null
+                this._background.zOrder       = 1.0;
+                this._background.isPickable   = false;
+                this._background.origin       = Vector2.Zero();
+                this._background.levelVisible = false;
+
+                if (settings.backgroundRoundRadius != null) {
+                    this.backgroundRoundRadius = settings.backgroundRoundRadius;
+                }
+
+                if (settings.backgroundBorder != null) {
+                    this.backgroundBorder = settings.backgroundBorder;
+                }
+
+                if (settings.backgroundBorderThickNess != null) {
+                    this.backgroundBorderThickness = settings.backgroundBorderThickNess;
+                }
+
+                if (settings.backgroundFill != null) {
+                    this.backgroundFill = settings.backgroundFill;
+                }
+
+                this._background._patchHierarchy(this);
+            }
 
 
             let engine = scene.getEngine();
             let engine = scene.getEngine();
+
+            this.__engineData                   = engine.getOrAddExternalDataWithFactory("__BJSCANVAS2D__", k => new Canvas2DEngineBoundData());
+            this._renderScaleFactor             = renderScaleFactor;
+            this._primPointerInfo               = new PrimitivePointerInfo();
+            this._capturedPointers              = new StringDictionary<Prim2DBase>();
+            this._pickStartingPosition          = Vector2.Zero();
+            this._hierarchyLevelMaxSiblingCount = 10;
+            this._hierarchyDepthOffset          = 0;
+            this._siblingDepthOffset            = 1 / this._hierarchyLevelMaxSiblingCount;
+            this._scene                         = scene;
+            this._engine                        = engine;
+            this._renderingSize                 = new Size(0, 0);
+
+            this._patchHierarchy(this);
+
+            let enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
+
             this._fitRenderingDevice = !settings.size;
             this._fitRenderingDevice = !settings.size;
             if (!settings.size) {
             if (!settings.size) {
                 settings.size = new Size(engine.getRenderWidth(), engine.getRenderHeight());
                 settings.size = new Size(engine.getRenderWidth(), engine.getRenderHeight());
@@ -82,33 +122,12 @@
                 settings.size.height *= renderScaleFactor;
                 settings.size.height *= renderScaleFactor;
                 settings.size.width *= renderScaleFactor;
                 settings.size.width *= renderScaleFactor;
             }
             }
-            this.__engineData = engine.getOrAddExternalDataWithFactory("__BJSCANVAS2D__", k => new Canvas2DEngineBoundData());
-            this._renderScaleFactor = renderScaleFactor;
-            this._primPointerInfo = new PrimitivePointerInfo();
-            this._capturedPointers = new StringDictionary<Prim2DBase>();
-            this._pickStartingPosition = Vector2.Zero();
-
-            //this.setupGroup2D(this, null, name, Vector2.Zero(), origin, size, isVisible, this._cachingStrategy===Canvas2D.CACHESTRATEGY_ALLGROUPS ? Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign);
-
-            this._hierarchyLevelMaxSiblingCount = 10;
-            this._hierarchyDepthOffset = 0;
-            this._siblingDepthOffset = 1 / this._hierarchyLevelMaxSiblingCount;
-            this._scene = scene;
-            this._engine = engine;
-            this._renderingSize = new Size(0, 0);
 
 
             // Register scene dispose to also dispose the canvas when it'll happens
             // Register scene dispose to also dispose the canvas when it'll happens
             scene.onDisposeObservable.add((d, s) => {
             scene.onDisposeObservable.add((d, s) => {
                 this.dispose();
                 this.dispose();
             });
             });
 
 
-            if (this._cachingStrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
-                this._background = new Rectangle2D(this, { id: "###CANVAS BACKGROUND###", size: settings.size}); //TODO CHECK when size is null
-                this._background.isPickable = false;
-                this._background.origin = Vector2.Zero();
-                this._background.levelVisible = false;
-            }
-
             if (this._isScreeSpace) {
             if (this._isScreeSpace) {
                 this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
                 this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
                     this._engine.clear(null, false, true);
                     this._engine.clear(null, false, true);
@@ -132,9 +151,7 @@
             this._isScreeSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
             this._isScreeSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
         }
         }
 
 
-        public get hierarchyLevelMaxSiblingCount(): number {
-            return this._hierarchyLevelMaxSiblingCount;
-        }
+        public static hierarchyLevelMaxSiblingCount: number = 10;
 
 
         private _setupInteraction(enable: boolean) {
         private _setupInteraction(enable: boolean) {
             // No change detection
             // No change detection
@@ -744,6 +761,27 @@
         }
         }
 
 
         /**
         /**
+         * Property that defines the thickness of the border object used to draw the background of the Canvas.
+         * @returns If the background is not set, null will be returned, otherwise a valid number matching the thickness is returned.
+         */
+        public get backgroundBorderThickness(): number {
+            if (!this._background || !this._background.isVisible) {
+                return null;
+            }
+            return this._background.borderThickness;
+        }
+
+        public set backgroundBorderThickness(value: number) {
+            this.checkBackgroundAvailability();
+
+            if (value === this._background.borderThickness) {
+                return;
+            }
+
+            this._background.borderThickness = value;
+        }
+
+        /**
          * You can set the roundRadius of the background
          * You can set the roundRadius of the background
          * @returns The current roundRadius
          * @returns The current roundRadius
          */
          */
@@ -944,14 +982,14 @@
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
                 // Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
                 if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
                 if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
                     this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
                     this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
-                    let sprite = new Sprite2D(this._cachedCanvasGroup, map, {id: "__cachedCanvasSprite__", spriteSize:node.contentSize, spriteLocation:node.pos});
+                    let sprite = new Sprite2D(map, { parent: this._cachedCanvasGroup, id: "__cachedCanvasSprite__", spriteSize:node.contentSize, spriteLocation:node.pos});
                     sprite.zOrder = 1;
                     sprite.zOrder = 1;
                     sprite.origin = Vector2.Zero();
                     sprite.origin = Vector2.Zero();
                 }
                 }
 
 
                 // Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
                 // Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
                 else {
                 else {
-                    let sprite = new Sprite2D(parent, map, {id:`__cachedSpriteOfGroup__${group.id}`, x: group.position.x, y: group.position.y, spriteSize:node.contentSize, spriteLocation:node.pos});
+                    let sprite = new Sprite2D(map, { parent: parent, id:`__cachedSpriteOfGroup__${group.id}`, x: group.position.x, y: group.position.y, spriteSize:node.contentSize, spriteLocation:node.pos});
                     sprite.origin = group.origin.clone();
                     sprite.origin = group.origin.clone();
                     res.sprite = sprite;
                     res.sprite = sprite;
                 }
                 }
@@ -1010,16 +1048,31 @@
          * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
          * - customWorldSpaceNode: if specified the Canvas will be rendered in this given Node. But it's the responsibility of the caller to set the "worldSpaceToNodeLocal" property to compute the hit of the mouse ray into the node (in world coordinate system) as well as rendering the cached bitmap in the node itself. The properties cachedRect and cachedTexture of Group2D will give you what you need to do that.
          * - customWorldSpaceNode: if specified the Canvas will be rendered in this given Node. But it's the responsibility of the caller to set the "worldSpaceToNodeLocal" property to compute the hit of the mouse ray into the node (in world coordinate system) as well as rendering the cached bitmap in the node itself. The properties cachedRect and cachedTexture of Group2D will give you what you need to do that.
          */
          */
-        constructor(scene: Scene, size: Size, settings: {
-            id                  ?: string,
-            position            ?: Vector3,
-            rotation            ?: Quaternion,
-            renderScaleFactor   ?: number,
-            sideOrientation     ?: number,
-            cachingStrategy     ?: number,
-            enableInteraction   ?: boolean,
-            isVisible           ?: boolean,
-            customWorldSpaceNode?: Node,
+        constructor(scene: Scene, size: Size, settings?: {
+
+            children                 ?: Array<Prim2DBase>,
+            id                       ?: string,
+            position                 ?: Vector3,
+            rotation                 ?: Quaternion,
+            renderScaleFactor        ?: number,
+            sideOrientation          ?: number,
+            cachingStrategy          ?: number,
+            enableInteraction        ?: boolean,
+            isVisible                ?: boolean,
+            backgroundRoundRadius    ?: number,
+            backgroundFill           ?: IBrush2D,
+            backgroundBorder         ?: IBrush2D,
+            backgroundBorderThickNess?: number,
+            customWorldSpaceNode     ?: Node,
+            marginTop                ?: number | string,
+            marginLeft               ?: number | string,
+            marginRight              ?: number | string,
+            marginBottom             ?: number | string,
+            margin                   ?: string,
+            marginHAlignment         ?: number,
+            marginVAlignment         ?: number,
+            marginAlignment          ?: string,
+
         }) {
         }) {
             Prim2DBase._isCanvasInit = true;
             Prim2DBase._isCanvasInit = true;
             let s = <any>settings;
             let s = <any>settings;
@@ -1094,23 +1147,32 @@
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
         constructor(scene: Scene, settings?: {
         constructor(scene: Scene, settings?: {
-            id               ?: string,
-            x                ?: number,
-            y                ?: number,
-            position         ?: Vector2,
-            origin           ?: Vector2,
-            width            ?: number,
-            height           ?: number,
-            size             ?: Size,
-            cachingStrategy  ?: number,
-            enableInteraction?: boolean,
-            isVisible        ?: boolean,
-            marginTop        ?: number | string,
-            marginLeft       ?: number | string,
-            marginRight      ?: number | string,
-            marginBottom     ?: number | string,
-            hAlignment       ?: number,
-            vAlignment       ?: number,
+
+            children                  ?: Array<Prim2DBase>,
+            id                        ?: string,
+            x                         ?: number,
+            y                         ?: number,
+            position                  ?: Vector2,
+            origin                    ?: Vector2,
+            width                     ?: number,
+            height                    ?: number,
+            size                      ?: Size,
+            cachingStrategy           ?: number,
+            enableInteraction         ?: boolean,
+            isVisible                 ?: boolean,
+            backgroundRoundRadius     ?: number,
+            backgroundFill            ?: IBrush2D,
+            backgroundBorder          ?: IBrush2D,
+            backgroundBorderThickNess ?: number,
+            marginTop                 ?: number | string,
+            marginLeft                ?: number | string,
+            marginRight               ?: number | string,
+            marginBottom              ?: number | string,
+            margin                    ?: string,
+            marginHAlignment          ?: number,
+            marginVAlignment          ?: number,
+            marginAlignment           ?: string,
+
         }) {
         }) {
             Prim2DBase._isCanvasInit = true;
             Prim2DBase._isCanvasInit = true;
             super(scene, settings);
             super(scene, settings);

+ 39 - 55
src/Canvas2d/babylon.ellipse2d.ts

@@ -225,42 +225,49 @@
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
-        constructor(parent: Prim2DBase, settings?: {
-            id             ?: string,
-            position       ?: Vector2,
-            x              ?: number,
-            y              ?: number,
-            origin         ?: Vector2,
-            size           ?: Size,
-            width          ?: number,
-            height         ?: number,
-            subdivisions   ?: number,
-            fill           ?: IBrush2D,
-            border         ?: IBrush2D,
-            borderThickness?: number,
-            isVisible      ?: boolean,
-            marginTop      ?: number | string,
-            marginLeft     ?: number | string,
-            marginRight    ?: number | string,
-            marginBottom   ?: number | string,
-            vAlignment     ?: number,
-            hAlignment     ?: number,
+        constructor(settings?: {
+
+            parent            ?: Prim2DBase, 
+            children          ?: Array<Prim2DBase>,
+            id                ?: string,
+            position          ?: Vector2,
+            x                 ?: number,
+            y                 ?: number,
+            origin            ?: Vector2,
+            size              ?: Size,
+            width             ?: number,
+            height            ?: number,
+            subdivisions      ?: number,
+            fill              ?: IBrush2D,
+            border            ?: IBrush2D,
+            borderThickness   ?: number,
+            isVisible         ?: boolean,
+            marginTop         ?: number | string,
+            marginLeft        ?: number | string,
+            marginRight       ?: number | string,
+            marginBottom      ?: number | string,
+            margin            ?: string,
+            marginHAlignment  ?: number,
+            marginVAlignment  ?: number,
+            marginAlignment   ?: string,
+            paddingTop        ?: number | string,
+            paddingLeft       ?: number | string,
+            paddingRight      ?: number | string,
+            paddingBottom     ?: number | string,
+            padding           ?: string,
+            paddingHAlignment ?: number,
+            paddingVAlignment ?: number,
+            paddingAlignment  ?: string,
+
         }) {
         }) {
 
 
-            super(parent.owner, parent, settings);
-            Prim2DBase.CheckParent(parent);
+            // Avoid checking every time if the object exists
+            if (settings == null) {
+                settings = {};
+            }
 
 
-            //let ellipse = new Ellipse2D();
+            super(settings);
 
 
-            //if (!settings) {
-            //    ellipse.setupEllipse2D(parent.owner, parent, null, Vector2.Zero(), null, new Size(10, 10), 64, Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, true, null, null, null, null, null, null);
-            //} else {
-            let fill: IBrush2D;
-            if (settings.fill === undefined) {
-                fill = Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
-            } else {
-                fill = settings.fill;
-            }
             let pos  = settings.position || new Vector2(settings.x || 0, settings.y || 0);
             let pos  = settings.position || new Vector2(settings.x || 0, settings.y || 0);
             let size = settings.size || (new Size(settings.width || 10, settings.height || 10));
             let size = settings.size || (new Size(settings.width || 10, settings.height || 10));
             let sub  = (settings.subdivisions == null) ? 64 : settings.subdivisions;
             let sub  = (settings.subdivisions == null) ? 64 : settings.subdivisions;
@@ -268,29 +275,6 @@
             this.position     = pos;
             this.position     = pos;
             this.size         = size;
             this.size         = size;
             this.subdivisions = sub;
             this.subdivisions = sub;
-
-            //    ellipse.setupEllipse2D
-            //    (
-            //        parent.owner,
-            //        parent,
-            //        settings.id || null,
-            //        pos,
-            //        settings.origin || null,
-            //        size,
-            //        (settings.subdivisions == null) ? 64 : settings.subdivisions,
-            //        fill,
-            //        settings.border || null,
-            //        (settings.borderThickness == null) ? 1 : settings.borderThickness,
-            //        (settings.isVisible == null) ? true : settings.isVisible,
-            //        settings.marginTop,
-            //        settings.marginLeft,
-            //        settings.marginRight,
-            //        settings.marginBottom,
-            //        settings.vAlignment,
-            //        settings.hAlignment);
-            //}
-
-            //return ellipse;
         }
         }
 
 
         protected createModelRenderCache(modelKey: string): ModelRenderCache {
         protected createModelRenderCache(modelKey: string): ModelRenderCache {

+ 44 - 26
src/Canvas2d/babylon.group2d.ts

@@ -36,35 +36,43 @@
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
-        constructor(parent: Prim2DBase, settings?: {
-            id           ?: string,
-            position     ?: Vector2,
-            x            ?: number,
-            y            ?: number,
-            origin       ?: Vector2,
-            size         ?: Size,
-            width        ?: number,
-            height       ?: number,
-            cacheBehavior?: number,
-            isVisible    ?: boolean,
-            marginTop    ?: number | string,
-            marginLeft   ?: number | string,
-            marginRight  ?: number | string,
-            marginBottom ?: number | string,
-            vAlignment   ?: number,
-            hAlignment   ?: number,
-        }) {
-            Prim2DBase.CheckParent(parent);
+        constructor(settings?: {
+
+            parent            ?: Prim2DBase, 
+            children          ?: Array<Prim2DBase>,
+            id                ?: string,
+            position          ?: Vector2,
+            x                 ?: number,
+            y                 ?: number,
+            origin            ?: Vector2,
+            size              ?: Size,
+            width             ?: number,
+            height            ?: number,
+            cacheBehavior     ?: number,
+            isVisible         ?: boolean,
+            marginTop         ?: number | string,
+            marginLeft        ?: number | string,
+            marginRight       ?: number | string,
+            marginBottom      ?: number | string,
+            margin            ?: string,
+            marginHAlignment  ?: number,
+            marginVAlignment  ?: number,
+            marginAlignment   ?: string,
+            paddingTop        ?: number | string,
+            paddingLeft       ?: number | string,
+            paddingRight      ?: number | string,
+            paddingBottom     ?: number | string,
+            padding           ?: string,
+            paddingHAlignment ?: number,
+            paddingVAlignment ?: number,
+            paddingAlignment  ?: string,
 
 
+        }) {
             if (settings == null) {
             if (settings == null) {
                 settings = {};
                 settings = {};
             }
             }
 
 
-            if (Prim2DBase._isCanvasInit) {
-                super(null, null, settings);
-            } else {
-                super(parent.owner, parent, settings);
-            }
+            super(settings);
  
  
             let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
             let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
 
 
@@ -74,7 +82,7 @@
         }
         }
 
 
         static _createCachedCanvasGroup(owner: Canvas2D): Group2D {
         static _createCachedCanvasGroup(owner: Canvas2D): Group2D {
-            var g = new Group2D(owner, { id: "__cachedCanvasGroup__", position: Vector2.Zero(), origin: Vector2.Zero(), size:null, isVisible:true});
+            var g = new Group2D({ parent: owner, id: "__cachedCanvasGroup__", position: Vector2.Zero(), origin: Vector2.Zero(), size:null, isVisible:true});
             //g.setupGroup2D(owner, null, "__cachedCanvasGroup__", Vector2.Zero(), Vector2.Zero(), null, true, Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, null, null, null, null, null, null);
             //g.setupGroup2D(owner, null, "__cachedCanvasGroup__", Vector2.Zero(), Vector2.Zero(), null, true, Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, null, null, null, null, null, null);
             //g.origin = Vector2.Zero();
             //g.origin = Vector2.Zero();
             return g;
             return g;
@@ -344,6 +352,9 @@
                     var curVP = engine.setDirectViewport(this._viewportPosition.x, this._viewportPosition.y, this._viewportSize.width, this._viewportSize.height);
                     var curVP = engine.setDirectViewport(this._viewportPosition.x, this._viewportPosition.y, this._viewportSize.width, this._viewportSize.height);
                 }
                 }
 
 
+                let curAlphaTest = engine.getAlphaTesting() === true;
+                let curDepthWrite = engine.getDepthWrite() === true;
+
                 // ===================================================================
                 // ===================================================================
                 // First pass, update the InstancedArray and render Opaque primitives
                 // First pass, update the InstancedArray and render Opaque primitives
 
 
@@ -431,6 +442,10 @@
                         engine.setViewport(curVP);
                         engine.setViewport(curVP);
                     }
                     }
                 }
                 }
+
+                // Restore saved states
+                engine.setAlphaTesting(curAlphaTest);
+                engine.setDepthWrite(curDepthWrite);
             }
             }
         }
         }
 
 
@@ -740,7 +755,10 @@
 
 
 
 
             if (this._isRenderableGroup) {
             if (this._isRenderableGroup) {
-                this._renderableData = new RenderableGroupData();
+                // Yes, we do need that check, trust me, unfortunately we can call _detectGroupStates many time on the same object...
+                if (!this._renderableData) {
+                    this._renderableData = new RenderableGroupData();
+                }
             }
             }
 
 
             // If the group is tagged as renderable we add it to the renderable tree
             // If the group is tagged as renderable we add it to the renderable tree

+ 37 - 61
src/Canvas2d/babylon.lines2d.ts

@@ -359,44 +359,47 @@
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
-        constructor(parent: Prim2DBase, points: Vector2[], settings?: {
-            id             ?: string,
-            position       ?: Vector2,
-            x              ?: number,
-            y              ?: number,
-            origin         ?: Vector2,
-            fillThickness  ?: number,
-            closed         ?: boolean,
-            startCap       ?: number,
-            endCap         ?: number,
-            fill           ?: IBrush2D,
-            border         ?: IBrush2D,
-            borderThickness?: number,
-            isVisible      ?: boolean,
-            marginTop      ?: number | string,
-            marginLeft     ?: number | string,
-            marginRight    ?: number | string,
-            marginBottom   ?: number | string,
-            vAlignment     ?: number,
-            hAlignment     ?: number,
+        constructor(points: Vector2[], settings?: {
+
+            parent           ?: Prim2DBase, 
+            children         ?: Array<Prim2DBase>,
+            id               ?: string,
+            position         ?: Vector2,
+            x                ?: number,
+            y                ?: number,
+            origin           ?: Vector2,
+            fillThickness    ?: number,
+            closed           ?: boolean,
+            startCap         ?: number,
+            endCap           ?: number,
+            fill             ?: IBrush2D,
+            border           ?: IBrush2D,
+            borderThickness  ?: number,
+            isVisible        ?: boolean,
+            marginTop        ?: number | string,
+            marginLeft       ?: number | string,
+            marginRight      ?: number | string,
+            marginBottom     ?: number | string,
+            margin           ?: string,
+            marginHAlignment ?: number,
+            marginVAlignment ?: number,
+            marginAlignment  ?: string,
+            paddingTop       ?: number | string,
+            paddingLeft      ?: number | string,
+            paddingRight     ?: number | string,
+            paddingBottom    ?: number | string,
+            padding          ?: string,
+            paddingHAlignment?: number,
+            paddingVAlignment?: number,
+            paddingAlignment ?: string,
         }) {
         }) {
 
 
-            super(parent.owner, parent, settings);
-
-            Prim2DBase.CheckParent(parent);
-
-            //let lines = new Lines2D();
-
-            //if (!settings) {
-            //    lines.setupLines2D(parent.owner, parent, null, Vector2.Zero(), null, points, 1, 0, 0, Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, false, true, null, null, null, null, null, null);
-            //} else {
-            let fill: IBrush2D;
-            if (settings.fill === undefined) {
-                fill = Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF");
-            } else {
-                fill = settings.fill;
+            if (!settings) {
+                settings = {};
             }
             }
 
 
+            super(settings);
+
             this._fillVB   = null;
             this._fillVB   = null;
             this._fillIB   = null;
             this._fillIB   = null;
             this._borderVB = null;
             this._borderVB = null;
@@ -405,7 +408,6 @@
             this._boundingMin = null;
             this._boundingMin = null;
             this._boundingMax = null;
             this._boundingMax = null;
 
 
-
             let fillThickness = (settings.fillThickness == null) ? 1     : settings.fillThickness;
             let fillThickness = (settings.fillThickness == null) ? 1     : settings.fillThickness;
             let startCap      = (settings.startCap == null)      ? 0     : settings.startCap;
             let startCap      = (settings.startCap == null)      ? 0     : settings.startCap;
             let endCap        = (settings.endCap == null)        ? 0     : settings.endCap;
             let endCap        = (settings.endCap == null)        ? 0     : settings.endCap;
@@ -416,32 +418,6 @@
             this.startCap      = startCap;
             this.startCap      = startCap;
             this.endCap        = endCap;
             this.endCap        = endCap;
             this.closed        = closed;
             this.closed        = closed;
-
-            //    lines.setupLines2D
-            //        (
-            //        parent.owner,
-            //        parent,
-            //        settings.id || null,
-            //        pos,
-            //        settings.origin || null,
-            //points,
-            //(settings.fillThickness == null) ? 1 : settings.fillThickness,
-            //(settings.startCap == null) ? 0 : settings.startCap,
-            //(settings.endCap == null) ? 0 : settings.endCap,
-            //fill,
-            //settings.border || null,
-            //(settings.borderThickness == null) ? 1 : settings.borderThickness,
-            //(settings.closed == null) ? false : settings.closed,
-            //(settings.isVisible == null) ? true : settings.isVisible,
-            //        settings.marginTop,
-            //        settings.marginLeft,
-            //        settings.marginRight,
-            //        settings.marginBottom,
-            //        settings.vAlignment,
-            //        settings.hAlignment);
-            //}
-
-            //return lines;
         }
         }
 
 
         protected createModelRenderCache(modelKey: string): ModelRenderCache {
         protected createModelRenderCache(modelKey: string): ModelRenderCache {

+ 235 - 73
src/Canvas2d/babylon.prim2dBase.ts

@@ -377,6 +377,37 @@
                     return;
                     return;
             }
             }
         }
         }
+
+        fromString(value: string) {
+            let m = value.trim().split(",");
+            for (let v of m) {
+                v = v.toLocaleLowerCase().trim();
+
+                // Horizontal
+                let i = v.indexOf("h:");
+                if (i === -1) {
+                    i = v.indexOf("horizontal:");
+                }
+
+                if (i !== -1) {
+                    v = v.substr(v.indexOf(":") + 1);
+                    this.setHorizontal(v);
+                    continue;
+                }
+
+                // Vertical
+                i = v.indexOf("v:");
+                if (i === -1) {
+                    i = v.indexOf("vertical:");
+                }
+
+                if (i !== -1) {
+                    v = v.substr(v.indexOf(":") + 1);
+                    this.setVertical(v);
+                    continue;
+                }
+            }
+        }
     }
     }
 
 
     /**
     /**
@@ -1055,77 +1086,116 @@
     export class Prim2DBase extends SmartPropertyPrim {
     export class Prim2DBase extends SmartPropertyPrim {
         static PRIM2DBASE_PROPCOUNT: number = 15;
         static PRIM2DBASE_PROPCOUNT: number = 15;
 
 
-        constructor(owner: Canvas2D, parent: Prim2DBase, settings: {
-            id?: string,
-            position?: Vector2,
-            x?: number,
-            y?: number,
-            origin?: Vector2,
-            isVisible?: boolean,
-            marginTop?: number | string,
-            marginLeft?: number | string,
-            marginRight?: number | string,
-            marginBottom?: number | string,
-            vAlignment?: number,
-            hAlignment?: number,
-        }
-        ) {
-
+        constructor(settings: {
+            parent              ?: Prim2DBase, 
+            id                  ?: string,
+            children            ?: Array<Prim2DBase>,
+            position            ?: Vector2,
+            x                   ?: number,
+            y                   ?: number,
+            origin              ?: Vector2,
+            isVisible           ?: boolean,
+            marginTop           ?: number | string,
+            marginLeft          ?: number | string,
+            marginRight         ?: number | string,
+            marginBottom        ?: number | string,
+            margin              ?: string,
+            marginHAlignment    ?: number,
+            marginVAlignment    ?: number,
+            marginAlignment     ?: string,
+            paddingTop          ?: number | string,
+            paddingLeft         ?: number | string,
+            paddingRight        ?: number | string,
+            paddingBottom       ?: number | string,
+            padding             ?: string,
+            paddingHAlignment   ?: number,
+            paddingVAlignment   ?: number,
+            paddingAlignment    ?: string,
+        }) {
+
+            // Avoid checking every time if the object exists
             if (settings == null) {
             if (settings == null) {
                 settings = {};
                 settings = {};
             }
             }
 
 
+            // BASE CLASS CALL
             super();
             super();
 
 
+            // Fetch the owner, parent. There're many ways to do it and we can end up with nothing for both
+            let owner: Canvas2D;
+            let parent: Prim2DBase;
             if (Prim2DBase._isCanvasInit) {
             if (Prim2DBase._isCanvasInit) {
                 owner = <Canvas2D><any>this;
                 owner = <Canvas2D><any>this;
                 parent = null;
                 parent = null;
-
                 this._canvasPreInit(settings);
                 this._canvasPreInit(settings);
+            } else {
+                if (settings.parent != null) {
+                    parent = settings.parent;
+                    owner = settings.parent.owner;
+                    if (!owner) {
+                        throw new Error(`Parent ${parent.id} of ${settings.id} doesn't have a valid owner!`);
+                    }
+
+                    if (!(this instanceof Group2D) && !(this instanceof Sprite2D && settings.id !== null && settings.id.indexOf("__cachedSpriteOfGroup__") === 0) && (owner.cachingStrategy === Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) && (parent === owner)) {
+                        throw new Error("Can't create a primitive with the canvas as direct parent when the caching strategy is TOPLEVELGROUPS. You need to create a Group below the canvas and use it as the parent for the primitive");
+                    }
+                }
             }
             }
 
 
-            if (!(this instanceof Group2D) && !(this instanceof Sprite2D && settings.id !== null && settings.id.indexOf("__cachedSpriteOfGroup__") === 0) && (owner.cachingStrategy === Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) && (parent === owner)) {
-                throw new Error("Can't create a primitive with the canvas as direct parent when the caching strategy is TOPLEVELGROUPS. You need to create a Group below the canvas and use it as the parent for the primitive");
-            }
-
-            this._layoutEngine = CanvasLayoutEngine.Singleton;
-            this._size = Size.Zero();
-            this._layoutArea = Size.Zero();
-            this._paddingOffset = Vector2.Zero();
-            this._paddingArea = Size.Zero();
-            this._margingOffset = Vector2.Zero();
-            this._parentMargingOffset = Vector2.Zero();
-            this._parentContentArea = Size.Zero();
-            this._contentArea = new Size(null, null);
-            this._pointerEventObservable = new Observable<PrimitivePointerInfo>();
-            this._setFlags(SmartPropertyPrim.flagIsPickable);
-            this._siblingDepthOffset = this._hierarchyDepthOffset = 0;
-            this._setFlags(SmartPropertyPrim.flagBoundingInfoDirty);
-            this._boundingInfo = new BoundingInfo2D();
-            this._owner = owner;
-            this._parent = parent;
-            this._margin = null;
-            this._padding = null;
-            this._id = settings.id;
+            // Fields initialization
+            this._layoutEngine               = CanvasLayoutEngine.Singleton;
+            this._size                       = Size.Zero();
+            this._layoutArea                 = Size.Zero();
+            this._paddingOffset              = Vector2.Zero();
+            this._paddingArea                = Size.Zero();
+            this._margingOffset              = Vector2.Zero();
+            this._parentMargingOffset        = Vector2.Zero();
+            this._parentContentArea          = Size.Zero();
+            this._contentArea                = new Size(null, null);
+            this._pointerEventObservable     = new Observable<PrimitivePointerInfo>();
+            this._siblingDepthOffset         = this._hierarchyDepthOffset = 0;
+            this._boundingInfo               = new BoundingInfo2D();
+            this._owner                      = owner;
+            this._parent                     = null;
+            this._margin                     = null;
+            this._padding                    = null;
+            this._marginAlignment            = null;
+            this._paddingAlignment           = null;
+            this._id                         = settings.id;
+            this.propertyChanged             = new Observable<PropertyChangedInfo>();
+            this._children                   = new Array<Prim2DBase>();
+            this._globalTransform            = null;
+            this._invGlobalTransform         = null;
+            this._localTransform             = null;
+            this._globalTransformProcessStep = 0;
+            this._globalTransformStep        = 0;
+            this._hierarchyDepth             = 0;
+            this._renderGroup                = null;
+            this._setFlags(SmartPropertyPrim.flagIsPickable | SmartPropertyPrim.flagBoundingInfoDirty);
+
+            // If the parent is given, initialize the hierarchy/owner related data
             if (parent != null) {
             if (parent != null) {
-                this._hierarchyDepth = parent._hierarchyDepth + 1;
-                this._renderGroup = <Group2D>this.parent.traverseUp(p => p instanceof Group2D && p.isRenderableGroup);
                 parent.addChild(this);
                 parent.addChild(this);
-            } else {
-                this._hierarchyDepth = 0;
-                this._renderGroup = null;
+                this._patchHierarchy(parent.owner);
             }
             }
 
 
-            this.propertyChanged = new Observable<PropertyChangedInfo>();
-            this._children = new Array<Prim2DBase>();
-            this._globalTransformProcessStep = 0;
-            this._globalTransformStep = 0;
-
-            if (this instanceof Group2D) {
+            // If it's a group, detect its own states
+            if (this.owner && this instanceof Group2D) {
                 var group: any = this;
                 var group: any = this;
                 group.detectGroupStates();
                 group.detectGroupStates();
             }
             }
 
 
+            // Time to insert children if some are specified
+            if (settings.children != null) {
+                for (let child of settings.children) {
+                    this.addChild(child);
+
+                    // Good time to patch the hierarchy, it won't go very far if there's no need to
+                    child._patchHierarchy(this.owner);
+                } 
+            }
+
+            // Set the model related properties
             let pos = settings.position || new Vector2(settings.x || 0, settings.y || 0);
             let pos = settings.position || new Vector2(settings.x || 0, settings.y || 0);
             this.position = pos;
             this.position = pos;
             this.rotation = 0;
             this.rotation = 0;
@@ -1133,6 +1203,7 @@
             this.levelVisible = (settings.isVisible==null) ? true : settings.isVisible;
             this.levelVisible = (settings.isVisible==null) ? true : settings.isVisible;
             this.origin = settings.origin || new Vector2(0.5, 0.5);
             this.origin = settings.origin || new Vector2(0.5, 0.5);
 
 
+            // Set the layout/margin stuffs
             if (settings.marginTop) {
             if (settings.marginTop) {
                 this.margin.setTop(settings.marginTop);
                 this.margin.setTop(settings.marginTop);
             }
             }
@@ -1146,6 +1217,52 @@
                 this.margin.setBottom(settings.marginBottom);
                 this.margin.setBottom(settings.marginBottom);
             }
             }
 
 
+            if (settings.margin) {
+                this.margin.fromString(settings.margin);
+            }
+
+            if (settings.marginHAlignment) {
+                this.marginAlignment.horizontal = settings.marginHAlignment;
+            }
+
+            if (settings.marginVAlignment) {
+                this.marginAlignment.vertical = settings.marginVAlignment;
+            }
+
+            if (settings.marginAlignment) {
+                this.marginAlignment.fromString(settings.marginAlignment);
+            }
+
+            if (settings.paddingTop) {
+                this.padding.setTop(settings.paddingTop);
+            }
+            if (settings.paddingLeft) {
+                this.padding.setLeft(settings.paddingLeft);
+            }
+            if (settings.paddingRight) {
+                this.padding.setRight(settings.paddingRight);
+            }
+            if (settings.paddingBottom) {
+                this.padding.setBottom(settings.paddingBottom);
+            }
+
+            if (settings.padding) {
+                this.padding.fromString(settings.padding);
+            }
+
+            if (settings.paddingHAlignment) {
+                this.paddingAlignment.horizontal = settings.paddingHAlignment;
+            }
+
+            if (settings.paddingVAlignment) {
+                this.paddingAlignment.vertical = settings.paddingVAlignment;
+            }
+
+            if (settings.paddingAlignment) {
+                this.paddingAlignment.fromString(settings.paddingAlignment);
+            }
+
+            // Dirty layout and positioning
             this._parentLayoutDirty();
             this._parentLayoutDirty();
             this._positioningDirty();
             this._positioningDirty();
         }
         }
@@ -1557,8 +1674,8 @@
             return this._margin;
             return this._margin;
         }
         }
 
 
-        public get hasMargin(): boolean {
-            return this._margin !== null;
+        private get _hasMargin(): boolean {
+            return (this._margin !== null) || (this._marginAlignment !== null);
         }
         }
 
 
         @dynamicLevelProperty(10, pi => Prim2DBase.paddingProperty = pi)
         @dynamicLevelProperty(10, pi => Prim2DBase.paddingProperty = pi)
@@ -1578,8 +1695,8 @@
             return this._padding;
             return this._padding;
         }
         }
 
 
-        public get hasPadding(): boolean {
-            return this._padding !== null;
+        private get _hasPadding(): boolean {
+            return (this._padding !== null) || (this._paddingAlignment !== null);
         }
         }
 
 
         @dynamicLevelProperty(11, pi => Prim2DBase.marginAlignmentProperty = pi)
         @dynamicLevelProperty(11, pi => Prim2DBase.marginAlignmentProperty = pi)
@@ -1834,9 +1951,8 @@
         }
         }
 
 
         private addChild(child: Prim2DBase) {
         private addChild(child: Prim2DBase) {
-            child._hierarchyDepthOffset = this._hierarchyDepthOffset + ((this._children.length + 1) * this._siblingDepthOffset);
-//            console.log(`Node: ${child.id} has depth: ${child._hierarchyDepthOffset}`);
-            child._siblingDepthOffset = this._siblingDepthOffset / this.owner.hierarchyLevelMaxSiblingCount;
+            child._parent = this;
+            this._patchHierarchyDepth(child);
             this._children.push(child);
             this._children.push(child);
         }
         }
 
 
@@ -1921,10 +2037,10 @@
         }
         }
 
 
         protected static _isCanvasInit: boolean = false;
         protected static _isCanvasInit: boolean = false;
-        protected static CheckParent(parent: Prim2DBase) {
-            if (!Prim2DBase._isCanvasInit && !parent) {
-                throw new Error("A Primitive needs a valid Parent, it can be any kind of Primitives based types, even the Canvas (with the exception that only Group2D can be direct child of a Canvas if the cache strategy used is TOPLEVELGROUPS)");
-            }
+        protected static CheckParent(parent: Prim2DBase) {  // TODO remove
+            //if (!Prim2DBase._isCanvasInit && !parent) {
+            //    throw new Error("A Primitive needs a valid Parent, it can be any kind of Primitives based types, even the Canvas (with the exception that only Group2D can be direct child of a Canvas if the cache strategy used is TOPLEVELGROUPS)");
+            //}
         }
         }
 
 
         protected updateCachedStatesOf(list: Prim2DBase[], recurse: boolean) {
         protected updateCachedStatesOf(list: Prim2DBase[], recurse: boolean) {
@@ -2039,8 +2155,9 @@
                     let globalTransform = this._parent ? this._parent._globalTransform : null;
                     let globalTransform = this._parent ? this._parent._globalTransform : null;
                     if (parentMarginOffset && (parentMarginOffset.x !== 0 || parentMarginOffset.y !== 0)) {
                     if (parentMarginOffset && (parentMarginOffset.x !== 0 || parentMarginOffset.y !== 0)) {
                         globalTransform = globalTransform.clone();
                         globalTransform = globalTransform.clone();
-                        globalTransform.m[12] += parentMarginOffset.x;
-                        globalTransform.m[13] += parentMarginOffset.y;
+                        // parentMarginOffset is expressed in bottom/left, so to apply origin on it (which we have to), we offset the by -0.5 to put it in the same frame of reference
+                        globalTransform.m[12] += parentMarginOffset.x * (this._origin.x - 0.5); 
+                        globalTransform.m[13] += parentMarginOffset.y * (this._origin.y - 0.5);
                     }
                     }
 
 
                     this._globalTransform = this._parent ? this._localTransform.multiply(globalTransform) : this._localTransform;
                     this._globalTransform = this._parent ? this._localTransform.multiply(globalTransform) : this._localTransform;
@@ -2075,22 +2192,28 @@
             //  2. Determine the contentArea based on the primitive's initialContentArea and the margin property.
             //  2. Determine the contentArea based on the primitive's initialContentArea and the margin property.
 
 
             // Auto Create PaddingArea if there's no actualSize on width&|height to allocate the whole content available to the paddingArea where the actualSize is null
             // Auto Create PaddingArea if there's no actualSize on width&|height to allocate the whole content available to the paddingArea where the actualSize is null
-            if (!this.hasPadding && (this.actualSize.width == null || this.actualSize.height == null)) {
+            if (!this._hasPadding && (this.actualSize.width == null || this.actualSize.height == null)) {
                 if (this.actualSize.width == null) {
                 if (this.actualSize.width == null) {
                     this.paddingAlignment.horizontal = PrimitiveAlignment.AlignStretch;
                     this.paddingAlignment.horizontal = PrimitiveAlignment.AlignStretch;
-                    this.padding.leftPixels = 0;    // Ugly, but we need to fetch the padding object for the PaddingArea computing to trigger below
                 }
                 }
 
 
                 if (this.actualSize.height == null) {
                 if (this.actualSize.height == null) {
                     this.paddingAlignment.vertical = PrimitiveAlignment.AlignStretch;
                     this.paddingAlignment.vertical = PrimitiveAlignment.AlignStretch;
-                    this.padding.topPixels = 0;     // Same ugly thing as above
                 }
                 }
             }
             }
 
 
             // Compute the PaddingArea
             // Compute the PaddingArea
-            if (this.hasPadding) {
+            if (this._hasPadding) {
                 this.padding.compute(this._layoutArea, this.size, this.paddingAlignment, this._paddingOffset, this._paddingArea);
                 this.padding.compute(this._layoutArea, this.size, this.paddingAlignment, this._paddingOffset, this._paddingArea);
+
                 this.position = this._paddingOffset.clone();
                 this.position = this._paddingOffset.clone();
+
+                // Origin correction
+                if (this.origin.x !== 0 || this.origin.y !== 0) {
+                    this.position.x += this._paddingArea.width  * this.origin.x;
+                    this.position.y += this._paddingArea.height * this.origin.y;
+                }
+
                 if (this.size.width != null) {
                 if (this.size.width != null) {
                     this.size.width = this._paddingArea.width;
                     this.size.width = this._paddingArea.width;
                 }
                 }
@@ -2107,7 +2230,7 @@
                 this._paddingArea.copyFrom(this.actualSize);
                 this._paddingArea.copyFrom(this.actualSize);
             }
             }
 
 
-            if (this.hasMargin) {
+            if (this._hasMargin) {
                 this._getInitialContentAreaToRef(this._paddingArea, Prim2DBase._icPos, Prim2DBase._icArea);
                 this._getInitialContentAreaToRef(this._paddingArea, Prim2DBase._icPos, Prim2DBase._icArea);
                 this.margin.compute(Prim2DBase._icArea, this._contentArea, this.marginAlignment, this._margingOffset, Prim2DBase._newContent);
                 this.margin.compute(Prim2DBase._icArea, this._contentArea, this.marginAlignment, this._margingOffset, Prim2DBase._newContent);
                 this._margingOffset.x += Prim2DBase._icPos.x;
                 this._margingOffset.x += Prim2DBase._icPos.x;
@@ -2130,17 +2253,56 @@
             return this._contentArea;
             return this._contentArea;
         }
         }
 
 
+        public _patchHierarchy(owner: Canvas2D) {
+            this._owner = owner;
+
+            // The only place we initialize the _renderGroup is this method, if it's set, we already been there, no need to execute more
+            if (this._renderGroup!=null) {
+                return;
+            }
+
+            if (this instanceof Group2D) {
+                var group: any = this;
+                group.detectGroupStates();
+            }
+
+            if (this._parent) {
+                this._renderGroup = <Group2D>this.parent.traverseUp(p => p instanceof Group2D && p.isRenderableGroup);
+            }
+
+            // Make sure the prim is in the dirtyList if it should be
+            if (this._renderGroup && this.isDirty) {
+                let list = this._renderGroup._renderableData._primDirtyList;
+                let i = list.indexOf(this);
+                if (i === -1) {
+                    list.push(this);
+                }
+            }
+
+            // Recurse
+            for (let child of this._children) {
+                this._patchHierarchyDepth(child);
+                child._patchHierarchy(owner);
+            }
+        }
+
+        private _patchHierarchyDepth(child: Prim2DBase) {
+            child._hierarchyDepth = this._hierarchyDepth + 1;
+            child._hierarchyDepthOffset = this._hierarchyDepthOffset + ((this._children.length + 1) * this._siblingDepthOffset);
+            child._siblingDepthOffset = this._siblingDepthOffset / Canvas2D.hierarchyLevelMaxSiblingCount;           
+        }
+
         /**
         /**
          * This method is used to alter the contentArea of the Primitive before margin is applied.
          * This method is used to alter the contentArea of the Primitive before margin is applied.
          * In most of the case you won't need to override this method, but it can prove some usefulness, check the Rectangle2D class for a concrete application.
          * In most of the case you won't need to override this method, but it can prove some usefulness, check the Rectangle2D class for a concrete application.
          * @param primSize the current size of the primitive
          * @param primSize the current size of the primitive
-         * @param initialContentPosition the position of the initial content area to compute, a valid object is passed, you have to set its properties
-         * @param initialContentArea the size of the initial content area to compute, a valid object is passed, you have to set its properties
+         * @param initialContentPosition the position of the initial content area to compute, a valid object is passed, you have to set its properties. PLEASE ROUND the values, we're talking about pixels and fraction of them is not a good thing!
+         * @param initialContentArea the size of the initial content area to compute, a valid object is passed, you have to set its properties. PLEASE ROUND the values, we're talking about pixels and fraction of them is not a good thing!
          */
          */
         protected _getInitialContentAreaToRef(primSize: Size, initialContentPosition: Vector2, initialContentArea: Size) {
         protected _getInitialContentAreaToRef(primSize: Size, initialContentPosition: Vector2, initialContentArea: Size) {
-            initialContentArea.width = primSize.width;
-            initialContentPosition.x = initialContentPosition.y = 0;
+            initialContentArea.width  = primSize.width;
             initialContentArea.height = primSize.height;
             initialContentArea.height = primSize.height;
+            initialContentPosition.x  = initialContentPosition.y = 0;
         }
         }
 
 
         private   _owner                 : Canvas2D;
         private   _owner                 : Canvas2D;

+ 38 - 50
src/Canvas2d/babylon.rectangle2d.ts

@@ -317,37 +317,47 @@
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
-        constructor(parent: Prim2DBase, settings?: {
-            id             ?: string,
-            position       ?: Vector2,
-            x              ?: number,
-            y              ?: number,
-            origin         ?: Vector2,
-            size           ?: Size,
-            width          ?: number,
-            height         ?: number,
-            roundRadius    ?: number,
-            fill           ?: IBrush2D,
-            border         ?: IBrush2D,
-            borderThickness?: number,
-            isVisible      ?: boolean,
-            marginTop      ?: number | string,
-            marginLeft     ?: number | string,
-            marginRight    ?: number | string,
-            marginBottom   ?: number | string,
-            vAlignment     ?: number,
-            hAlignment     ?: number,
+        constructor(settings ?: {
+            parent           ?: Prim2DBase, 
+            children         ?: Array<Prim2DBase>,
+            id               ?: string,
+            position         ?: Vector2,
+            x                ?: number,
+            y                ?: number,
+            origin           ?: Vector2,
+            size             ?: Size,
+            width            ?: number,
+            height           ?: number,
+            roundRadius      ?: number,
+            fill             ?: IBrush2D,
+            border           ?: IBrush2D,
+            borderThickness  ?: number,
+            isVisible        ?: boolean,
+            marginTop        ?: number | string,
+            marginLeft       ?: number | string,
+            marginRight      ?: number | string,
+            marginBottom     ?: number | string,
+            margin           ?: string,
+            marginHAlignment ?: number,
+            marginVAlignment ?: number,
+            marginAlignment  ?: string,
+            paddingTop       ?: number | string,
+            paddingLeft      ?: number | string,
+            paddingRight     ?: number | string,
+            paddingBottom    ?: number | string,
+            padding          ?: string,
+            paddingHAlignment?: number,
+            paddingVAlignment?: number,
+            paddingAlignment ?: string,
         }) {
         }) {
 
 
-            super(parent.owner, parent, settings);
-
-            Prim2DBase.CheckParent(parent);
+            // Avoid checking every time if the object exists
+            if (settings == null) {
+                settings = {};
+            }
 
 
-            //let rect = new Rectangle2D();
+            super(settings);
 
 
-            //if (!settings) {
-            //    rect.setupRectangle2D(parent.owner, parent, null, Vector2.Zero(), null, new Size(10, 10), 0, Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF"), null, 1, true, null, null, null, null, null, null);
-            //} else {
             let pos             = settings.position || new Vector2(settings.x || 0, settings.y || 0);
             let pos             = settings.position || new Vector2(settings.x || 0, settings.y || 0);
             let size            = settings.size || (new Size((settings.width === null) ? null : (settings.width || 10), (settings.height === null) ? null : (settings.height || 10)));
             let size            = settings.size || (new Size((settings.width === null) ? null : (settings.width || 10), (settings.height === null) ? null : (settings.height || 10)));
             let fill            = settings.fill === undefined ? Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF") : settings.fill;
             let fill            = settings.fill === undefined ? Canvas2D.GetSolidColorBrushFromHex("#FFFFFFFF") : settings.fill;
@@ -359,28 +369,6 @@
             this.fill            = fill;
             this.fill            = fill;
             this.roundRadius     = roundRadius;
             this.roundRadius     = roundRadius;
             this.borderThickness = borderThickness;
             this.borderThickness = borderThickness;
-
-            //rect.setupRectangle2D
-            //(
-            //    parent.owner,
-            //    parent,
-            //    settings.id || null,
-            //    pos,
-            //    settings.origin || null,
-            //    size,
-            //    (settings.roundRadius == null) ? 0 : settings.roundRadius,
-            //    fill,
-            //    settings.border || null,
-            //    (settings.borderThickness==null) ? 1 : settings.borderThickness,
-            //    settings.isVisible || true,
-            //    settings.marginTop,
-            //    settings.marginLeft,
-            //    settings.marginRight,
-            //    settings.marginBottom,
-            //    settings.vAlignment,
-            //    settings.hAlignment);
-            //}
-            //return rect;
         }
         }
 
 
         public static roundSubdivisions = 16;
         public static roundSubdivisions = 16;
@@ -474,7 +462,7 @@
             if (this._notRounded) {
             if (this._notRounded) {
                 super._getInitialContentAreaToRef(primSize, initialContentPosition, initialContentArea);
                 super._getInitialContentAreaToRef(primSize, initialContentPosition, initialContentArea);
             } else {
             } else {
-                let rr = (this.roundRadius - (this.roundRadius/Math.sqrt(2))) * 1.3;
+                let rr = Math.round((this.roundRadius - (this.roundRadius/Math.sqrt(2))) * 1.3);
                 initialContentPosition.x = initialContentPosition.y = rr;
                 initialContentPosition.x = initialContentPosition.y = rr;
                 initialContentArea.width = primSize.width - (rr * 2);
                 initialContentArea.width = primSize.width - (rr * 2);
                 initialContentArea.height = primSize.height - (rr * 2);
                 initialContentArea.height = primSize.height - (rr * 2);

+ 16 - 11
src/Canvas2d/babylon.renderablePrim2d.ts

@@ -353,22 +353,16 @@
             this._isTransparent = value;
             this._isTransparent = value;
         }
         }
 
 
-        constructor(owner: Canvas2D, parent: Prim2DBase, settings?: {
+        constructor(settings?: {
+            parent       ?: Prim2DBase, 
             id           ?: string,
             id           ?: string,
             position     ?: Vector2,
             position     ?: Vector2,
             origin       ?: Vector2,
             origin       ?: Vector2,
             isVisible    ?: boolean,
             isVisible    ?: boolean,
-            marginTop    ?: number | string,
-            marginLeft   ?: number | string,
-            marginRight  ?: number | string,
-            marginBottom ?: number | string,
-            hAlign       ?: number,
-            vAlign       ?: number,
         }) {
         }) {
-            super(owner, parent, settings);
-//            this.setupPrim2DBase(owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign);
-            this._isTransparent = false;
-            this._isAlphaTest = false;
+            super(settings);
+            this._isTransparent            = false;
+            this._isAlphaTest              = false;
             this._transparentPrimitiveInfo = null;
             this._transparentPrimitiveInfo = null;
         }
         }
 
 
@@ -377,6 +371,11 @@
                 return false;
                 return false;
             }
             }
 
 
+            if (this._transparentPrimitiveInfo) {
+                this.renderGroup._renderableData.removeTransparentPrimitiveInfo(this._transparentPrimitiveInfo);
+                this._transparentPrimitiveInfo = null;
+            }
+
             if (this._modelRenderInstanceID) {
             if (this._modelRenderInstanceID) {
                 this._modelRenderCache.removeInstanceData(this._modelRenderInstanceID);
                 this._modelRenderCache.removeInstanceData(this._modelRenderInstanceID);
                 this._modelRenderInstanceID = null;
                 this._modelRenderInstanceID = null;
@@ -431,6 +430,11 @@
 
 
             // The last thing to do is check if the instanced related data must be updated because a InstanceLevel property had changed or the primitive visibility changed.
             // The last thing to do is check if the instanced related data must be updated because a InstanceLevel property had changed or the primitive visibility changed.
             if (this._isFlagSet(SmartPropertyPrim.flagVisibilityChanged) || context.forceRefreshPrimitive || newInstance || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep)) {
             if (this._isFlagSet(SmartPropertyPrim.flagVisibilityChanged) || context.forceRefreshPrimitive || newInstance || (this._instanceDirtyFlags !== 0) || (this._globalTransformProcessStep !== this._globalTransformStep)) {
+
+                if (this.isTransparent) {
+                    //this.renderGroup._renderableData._transparentListChanged = true;
+                }
+
                 this._updateInstanceDataParts(gii);
                 this._updateInstanceDataParts(gii);
             }
             }
         }
         }
@@ -576,6 +580,7 @@
                     } else {
                     } else {
                         if (this._transparentPrimitiveInfo) {
                         if (this._transparentPrimitiveInfo) {
                             this.renderGroup._renderableData.removeTransparentPrimitiveInfo(this._transparentPrimitiveInfo);
                             this.renderGroup._renderableData.removeTransparentPrimitiveInfo(this._transparentPrimitiveInfo);
+                            this._transparentPrimitiveInfo = null;
                         }
                         }
                     }
                     }
                     gii.transparentOrderDirty = true;
                     gii.transparentOrderDirty = true;

+ 2 - 13
src/Canvas2d/babylon.shape2d.ts

@@ -44,24 +44,13 @@
             this._borderThickness = value;
             this._borderThickness = value;
         }
         }
 
 
-        constructor(owner: Canvas2D, parent: Prim2DBase, settings?: {
-            id             ?: string,
-            position       ?: Vector2,
-            origin         ?: Vector2,
-            isVisible      ?: boolean,
+        constructor(settings?: {
             fill           ?: IBrush2D,
             fill           ?: IBrush2D,
             border         ?: IBrush2D,
             border         ?: IBrush2D,
             borderThickness?: number,
             borderThickness?: number,
-            marginTop      ?: number | string,
-            marginLeft     ?: number | string,
-            marginRight    ?: number | string,
-            marginBottom   ?: number | string,
-            vAlignment     ?: number,
-            hAlignment     ?: number,
         }) {
         }) {
 
 
-            super(owner, parent, settings);
-            //this.setupRenderablePrim2D(owner, parent, id, position, origin, isVisible, marginTop, marginLeft, marginRight, marginBottom, hAlignment || PrimitiveAlignment.AlignLeft, vAlignment || PrimitiveAlignment.AlignTop);
+            super(settings);
 
 
             if (!settings) {
             if (!settings) {
                 settings = {};
                 settings = {};

+ 47 - 66
src/Canvas2d/babylon.sprite2d.ts

@@ -236,82 +236,63 @@
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
-        constructor(parent: Prim2DBase, texture: Texture, settings?: {
-            id            ?: string,
-            position      ?: Vector2,
-            x             ?: number,
-            y             ?: number,
-            origin        ?: Vector2,
-            spriteSize    ?: Size,
-            spriteLocation?: Vector2,
-            invertY       ?: boolean,
-            alignToPixel  ?: boolean,
-            isVisible     ?: boolean,
-            marginTop     ?: number | string,
-            marginLeft    ?: number | string,
-            marginRight   ?: number | string,
-            marginBottom  ?: number | string,
-            vAlignment    ?: number,
-            hAlignment    ?: number,
+        constructor(texture: Texture, settings?: {
+
+            parent           ?: Prim2DBase, 
+            children         ?: Array<Prim2DBase>,
+            id               ?: string,
+            position         ?: Vector2,
+            x                ?: number,
+            y                ?: number,
+            origin           ?: Vector2,
+            spriteSize       ?: Size,
+            spriteLocation   ?: Vector2,
+            invertY          ?: boolean,
+            alignToPixel     ?: boolean,
+            isVisible        ?: boolean,
+            marginTop        ?: number | string,
+            marginLeft       ?: number | string,
+            marginRight      ?: number | string,
+            marginBottom     ?: number | string,
+            margin           ?: string,
+            marginHAlignment ?: number,
+            marginVAlignment ?: number,
+            marginAlignment  ?: string,
+            paddingTop       ?: number | string,
+            paddingLeft      ?: number | string,
+            paddingRight     ?: number | string,
+            paddingBottom    ?: number | string,
+            padding          ?: string,
+            paddingHAlignment?: number,
+            paddingVAlignment?: number,
+            paddingAlignment ?: string,
         }) {
         }) {
 
 
-            super(parent.owner, parent, settings);
-
-            Prim2DBase.CheckParent(parent);
-
             if (!settings) {
             if (!settings) {
                 settings = {};
                 settings = {};
             }
             }
 
 
-//            let sprite = new Sprite2D();
-            //if (!settings) {
-            //    sprite.setupSprite2D(parent.owner, parent, null, Vector2.Zero(), null, texture, null, null, false, true, true, null, null, null, null, null, null);
-            //} else {
-                //let pos = settings.position || new Vector2(settings.x || 0, settings.y || 0);
-                //sprite.setupSprite2D
-                //(
-                //    parent.owner,
-                //    parent,
-                //    settings.id || null,
-                //    pos,
-                //    settings.origin || null,
-                //    texture, settings.spriteSize || null,
-                //    settings.spriteLocation || null,
-                //    (settings.invertY == null) ? false : settings.invertY,
-                //    (settings.alignToPixel == null) ? true : settings.alignToPixel,
-                //    (settings.isVisible == null) ? true : settings.isVisible,
-                //    settings.marginTop,
-                //    settings.marginLeft,
-                //    settings.marginRight,
-                //    settings.marginBottom,
-                //    settings.vAlignment,
-                //    settings.hAlignment
-                //);
-            //}
-
-                this.texture        = texture;
-                this.texture.wrapU  = Texture.CLAMP_ADDRESSMODE;
-                this.texture.wrapV  = Texture.CLAMP_ADDRESSMODE;
-                this.size           = settings.spriteSize || null;
-                this.spriteLocation = settings.spriteLocation || new Vector2(0, 0);
-                this.spriteFrame    = 0;
-                this.invertY        = (settings.invertY==null) ? false : settings.invertY;
-                this.alignToPixel   = (settings.alignToPixel==null) ? true : settings.alignToPixel;
-                this._isTransparent = true;
-
-                if (!this.size) {
-                    var s = texture.getSize();
-                    this.size = new Size(s.width, s.height);
-                }
-
-            //return sprite;
+            super(settings);
+
+            this.texture = texture;
+            this.texture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this.texture.wrapV = Texture.CLAMP_ADDRESSMODE;
+            this.size = settings.spriteSize || null;
+            this.spriteLocation = settings.spriteLocation || new Vector2(0, 0);
+            this.spriteFrame = 0;
+            this.invertY = (settings.invertY == null) ? false : settings.invertY;
+            this.alignToPixel = (settings.alignToPixel == null) ? true : settings.alignToPixel;
+            this._isTransparent = true;
+
+            if (!this.size) {
+                var s = texture.getSize();
+                this.size = new Size(s.width, s.height);
+            }
         }
         }
 
 
         static _createCachedCanvasSprite(owner: Canvas2D, texture: MapTexture, size: Size, pos: Vector2): Sprite2D {
         static _createCachedCanvasSprite(owner: Canvas2D, texture: MapTexture, size: Size, pos: Vector2): Sprite2D {
 
 
-            let sprite = new Sprite2D(owner, texture, { id:"__cachedCanvasSprite__", position: Vector2.Zero(), origin: Vector2.Zero(), spriteSize: size, spriteLocation:pos, alignToPixel: true});
-            //sprite.setupSprite2D(owner, null, "__cachedCanvasSprite__", new Vector2(0, 0), null, texture, size, pos, false, true, true, null, null, null, null, null, null);
-
+            let sprite = new Sprite2D(texture, { parent: owner, id:"__cachedCanvasSprite__", position: Vector2.Zero(), origin: Vector2.Zero(), spriteSize: size, spriteLocation:pos, alignToPixel: true});
             return sprite;
             return sprite;
         }
         }
 
 

+ 49 - 61
src/Canvas2d/babylon.text2d.ts

@@ -150,31 +150,35 @@
 
 
         public set text(value: string) {
         public set text(value: string) {
             this._text = value;
             this._text = value;
-            this._actualSize = null;    // A change of text will reset the Actual Area Size which will be recomputed next time it's used
+            this._textSize = null;    // A change of text will reset the TextSize which will be recomputed next time it's used
             this._updateCharCount();
             this._updateCharCount();
         }
         }
 
 
         @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 4, pi => Text2D.sizeProperty = pi)
         @instanceLevelProperty(RenderablePrim2D.RENDERABLEPRIM2D_PROPCOUNT + 4, pi => Text2D.sizeProperty = pi)
         public get size(): Size {
         public get size(): Size {
-            return this._areaSize;
+            if (this._size != null) {
+                return this._size;
+            }
+            return this.textSize;
         }
         }
 
 
         public set size(value: Size) {
         public set size(value: Size) {
-            this._areaSize = value;
+            this._size = value;
         }
         }
 
 
         public get actualSize(): Size {
         public get actualSize(): Size {
-            if (this.size) {
-                return this.size;
-            }
-
             if (this._actualSize) {
             if (this._actualSize) {
                 return this._actualSize;
                 return this._actualSize;
             }
             }
 
 
-            this._actualSize = this.fontTexture.measureText(this._text, this._tabulationSize);
+            return this.size;
+        }
 
 
-            return this._actualSize;
+        public get textSize(): Size {
+            if (!this._textSize) {
+                this._textSize = this.fontTexture.measureText(this._text, this._tabulationSize);
+            }
+            return this._textSize;
         }
         }
 
 
         protected get fontTexture(): FontTexture {
         protected get fontTexture(): FontTexture {
@@ -231,66 +235,51 @@
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          *  - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
          */
          */
-        constructor(parent: Prim2DBase, text: string, settings?: {
-            id              ?: string,
-            position        ?: Vector2,
-            x               ?: number,
-            y               ?: number,
-            origin          ?: Vector2,
-            fontName        ?: string,
-            defaultFontColor?: Color4,
-            size            ?: Size,
-            tabulationSize  ?: number,
-            isVisible       ?: boolean,
-            marginTop       ?: number | string,
-            marginLeft      ?: number | string,
-            marginRight     ?: number | string,
-            marginBottom    ?: number | string,
-            hAlignment      ?: number,
-            vAlignment      ?: number,
+        constructor(text: string, settings?: {
+
+            parent           ?: Prim2DBase, 
+            children         ?: Array<Prim2DBase>,
+            id               ?: string,
+            position         ?: Vector2,
+            x                ?: number,
+            y                ?: number,
+            origin           ?: Vector2,
+            fontName         ?: string,
+            defaultFontColor ?: Color4,
+            size             ?: Size,
+            tabulationSize   ?: number,
+            isVisible        ?: boolean,
+            marginTop        ?: number | string,
+            marginLeft       ?: number | string,
+            marginRight      ?: number | string,
+            marginBottom     ?: number | string,
+            margin           ?: string,
+            marginHAlignment ?: number,
+            marginVAlignment ?: number,
+            marginAlignment  ?: string,
+            paddingTop       ?: number | string,
+            paddingLeft      ?: number | string,
+            paddingRight     ?: number | string,
+            paddingBottom    ?: number | string,
+            padding          ?: string,
+            paddingHAlignment?: number,
+            paddingVAlignment?: number,
+            paddingAlignment ?: string,
         }) {
         }) {
 
 
-            super(parent.owner, parent, settings);
-
-            Prim2DBase.CheckParent(parent);
-
             if (!settings) {
             if (!settings) {
                 settings = {};
                 settings = {};
             }
             }
 
 
+            super(settings);
+
             this.fontName         = (settings.fontName==null)         ? "12pt Arial"        : settings.fontName;
             this.fontName         = (settings.fontName==null)         ? "12pt Arial"        : settings.fontName;
             this.defaultFontColor = (settings.defaultFontColor==null) ? new Color4(1,1,1,1) : settings.defaultFontColor;
             this.defaultFontColor = (settings.defaultFontColor==null) ? new Color4(1,1,1,1) : settings.defaultFontColor;
-            this._tabulationSize  = (settings.tabulationSize == null) ? 4                   : settings.tabulationSize;
+            this._tabulationSize  = (settings.tabulationSize == null) ? 4 : settings.tabulationSize;
+            this._textSize        = null;
             this.text             = text;
             this.text             = text;
-            this.size             = settings.size;
+            this.size             = (settings.size==null) ? null : settings.size;
             this.isAlphaTest      = true;
             this.isAlphaTest      = true;
-
-            //let text2d = new Text2D();
-            //if (!settings) {
-            //    text2d.setupText2D(parent.owner, parent, null, Vector2.Zero(), null, "12pt Arial", text, null, new Color4(1,1,1,1), 4, true, null, null, null, null, null, null);
-            //} else {
-                //let pos = settings.position || new Vector2(settings.x || 0, settings.y || 0);
-                //text2d.setupText2D
-                //(
-                //    parent.owner,
-                //    parent,
-                //    settings.id || null,
-                //    pos,
-                //    settings.origin || null,
-                //    settings.fontName || "12pt Arial",
-                //    text,
-                //    settings.size,
-                //    settings.defaultFontColor || new Color4(1, 1, 1, 1),
-                //    (settings.tabulationSize==null) ? 4 : settings.tabulationSize,
-                //    (settings.isVisible==null) ? true : settings.isVisible,
-                //    settings.marginTop,
-                //    settings.marginLeft,
-                //    settings.marginRight,
-                //    settings.marginBottom,
-                //    settings.vAlignment,
-                //    settings.hAlignment);
-            //}
-            //return text2d;
         }
         }
 
 
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean {
         protected levelIntersect(intersectInfo: IntersectInfo2D): boolean {
@@ -429,8 +418,7 @@
         private _fontName: string;
         private _fontName: string;
         private _defaultFontColor: Color4;
         private _defaultFontColor: Color4;
         private _text: string;
         private _text: string;
-        private _areaSize: Size;
-
+        private _textSize: Size;
     }
     }