Advertisement
Guest User

VertexData Domain Memory

a guest
Jun 17th, 2018
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // =================================================================================================
  2. //
  3. //  Starling Framework
  4. //  Copyright Gamua GmbH. All Rights Reserved.
  5. //
  6. //  This program is free software. You can redistribute and/or modify it
  7. //  in accordance with the terms of the accompanying license agreement.
  8. //
  9. // =================================================================================================
  10.  
  11. package starling.rendering
  12. {
  13.     import flash.display3D.Context3D;
  14.     import flash.display3D.VertexBuffer3D;
  15.     import flash.errors.IllegalOperationError;
  16.     import flash.geom.Matrix;
  17.     import flash.geom.Matrix3D;
  18.     import flash.geom.Point;
  19.     import flash.geom.Rectangle;
  20.     import flash.geom.Vector3D;
  21.    
  22.     import avm2.intrinsics.memory.lf32;
  23.     import avm2.intrinsics.memory.li32;
  24.     import avm2.intrinsics.memory.li8;
  25.     import avm2.intrinsics.memory.sf32;
  26.     import avm2.intrinsics.memory.si32;
  27.     import avm2.intrinsics.memory.si8;
  28.    
  29.     import starling.core.Starling;
  30.     import starling.errors.MissingContextError;
  31.     import starling.memory.FastByteArray;
  32.     import starling.memory.IHeapOwner;
  33.     import starling.styles.MeshStyle;
  34.     import starling.utils.MathUtil;
  35.     import starling.utils.MatrixUtil;
  36.     import starling.utils.StringUtil;
  37.    
  38.     /** The VertexData class manages a raw list of vertex information, allowing direct upload
  39.      *  to Stage3D vertex buffers. <em>You only have to work with this class if you're writing
  40.      *  your own rendering code (e.g. if you create custom display objects).</em>
  41.      *
  42.      *  <p>To render objects with Stage3D, you have to organize vertices and indices in so-called
  43.      *  vertex- and index-buffers. Vertex buffers store the coordinates of the vertices that make
  44.      *  up an object; index buffers reference those vertices to determine which vertices spawn
  45.      *  up triangles. Those buffers reside in graphics memory and can be accessed very
  46.      *  efficiently by the GPU.</p>
  47.      *
  48.      *  <p>Before you can move data into the buffers, you have to set it up in conventional
  49.      *  memory — that is, in a Vector or a ByteArray. Since it's quite cumbersome to manually
  50.      *  create and manipulate those data structures, the IndexData and VertexData classes provide
  51.      *  a simple way to do just that. The data is stored sequentially (one vertex or index after
  52.      *  the other) so that it can easily be uploaded to a buffer.</p>
  53.      *
  54.      *  <strong>Vertex Format</strong>
  55.      *
  56.      *  <p>The VertexData class requires a custom format string on initialization, or an instance
  57.      *  of the VertexDataFormat class. Here is an example:</p>
  58.      *
  59.      *  <listing>
  60.      *  vertexData = new VertexData("position:float2, color:bytes4");
  61.      *  vertexData.setPoint(0, "position", 320, 480);
  62.      *  vertexData.setColor(0, "color", 0xff00ff);</listing>
  63.      *
  64.      *  <p>This instance is set up with two attributes: "position" and "color". The keywords
  65.      *  after the colons depict the format and size of the data that each property uses; in this
  66.      *  case, we store two floats for the position (for the x- and y-coordinates) and four
  67.      *  bytes for the color. Please refer to the VertexDataFormat documentation for details.</p>
  68.      *
  69.      *  <p>The attribute names are then used to read and write data to the respective positions
  70.      *  inside a vertex. Furthermore, they come in handy when copying data from one VertexData
  71.      *  instance to another: attributes with equal name and data format may be transferred between
  72.      *  different VertexData objects, even when they contain different sets of attributes or have
  73.      *  a different layout.</p>
  74.      *
  75.      *  <strong>Colors</strong>
  76.      *
  77.      *  <p>Always use the format <code>bytes4</code> for color data. The color access methods
  78.      *  expect that format, since it's the most efficient way to store color data. Furthermore,
  79.      *  you should always include the string "color" (or "Color") in the name of color data;
  80.      *  that way, it will be recognized as such and will always have its value pre-filled with
  81.      *  pure white at full opacity.</p>
  82.      *
  83.      *  <strong>Premultiplied Alpha</strong>
  84.      *
  85.      *  <p>Per default, color values are stored with premultiplied alpha values, which
  86.      *  means that the <code>rgb</code> values were multiplied with the <code>alpha</code> values
  87.      *  before saving them. You can change this behavior with the <code>premultipliedAlpha</code>
  88.      *  property.</p>
  89.      *
  90.      *  <p>Beware: with premultiplied alpha, the alpha value always affects the resolution of
  91.      *  the RGB channels. A small alpha value results in a lower accuracy of the other channels,
  92.      *  and if the alpha value reaches zero, the color information is lost altogether.</p>
  93.      *
  94.      *  <strong>Tinting</strong>
  95.      *
  96.      *  <p>Some low-end hardware is very sensitive when it comes to fragment shader complexity.
  97.      *  Thus, Starling optimizes shaders for non-tinted meshes. The VertexData class keeps track
  98.      *  of its <code>tinted</code>-state, at least at a basic level: whenever you change color
  99.      *  or alpha value of a vertex to something different than white (<code>0xffffff</code>) with
  100.      *  full alpha (<code>1.0</code>), the <code>tinted</code> property is enabled.</p>
  101.      *
  102.      *  <p>However, that value is not entirely accurate: when you restore the color of just a
  103.      *  range of vertices, or copy just a subset of vertices to another instance, the property
  104.      *  might wrongfully indicate a tinted mesh. If that's the case, you can either call
  105.      *  <code>updateTinted()</code> or assign a custom value to the <code>tinted</code>-property.
  106.      *  </p>
  107.      *
  108.      *  @see VertexDataFormat
  109.      *  @see IndexData
  110.      */
  111.     public class VertexData implements IHeapOwner {
  112.         private var _rawData:FastByteArray;
  113.         private var _heapOffset:uint;
  114.        
  115.         private var _numVertices:int;
  116.         private var _format:VertexDataFormat;
  117.         private var _attributes:Vector.<VertexDataAttribute>;
  118.         private var _numAttributes:int;
  119.         private var _premultipliedAlpha:Boolean;
  120.         private var _tinted:Boolean;
  121.        
  122.         private var _posOffset:int;  // in bytes
  123.         private var _colOffset:int;  // in bytes
  124.         private var _vertexSize:int; // in bytes
  125.        
  126.         // helper objects
  127.         private static var sHelperPoint:Point = new Point();
  128.         private static var sHelperPoint3D:Vector3D = new Vector3D();
  129.         private static var sBytes:FastByteArray = FastByteArray.create(4);
  130.        
  131.         /** Creates an empty VertexData object with the given format and initial capacity.
  132.          *
  133.          *  @param format
  134.          *
  135.          *  Either a VertexDataFormat instance or a String that describes the data format.
  136.          *  Refer to the VertexDataFormat class for more information. If you don't pass a format,
  137.          *  the default <code>MeshStyle.VERTEX_FORMAT</code> will be used.
  138.          *
  139.          *  @param initialCapacity
  140.          *
  141.          *  The initial capacity affects just the way the internal ByteArray is allocated, not the
  142.          *  <code>numIndices</code> value, which will always be zero when the constructor returns.
  143.          *  The reason for this behavior is the peculiar way in which ByteArrays organize their
  144.          *  memory:
  145.          *
  146.          *  <p>The first time you set the length of a ByteArray, it will adhere to that:
  147.          *  a ByteArray with length 20 will take up 20 bytes (plus some overhead). When you change
  148.          *  it to a smaller length, it will stick to the original value, e.g. with a length of 10
  149.          *  it will still take up 20 bytes. However, now comes the weird part: change it to
  150.          *  anything above the original length, and it will allocate 4096 bytes!</p>
  151.          *
  152.          *  <p>Thus, be sure to always make a generous educated guess, depending on the planned
  153.          *  usage of your VertexData instances.</p>
  154.          */
  155.         public function VertexData(format:*=null, initialCapacity:int=32)
  156.         {
  157.             if (format == null) _format = MeshStyle.VERTEX_FORMAT;
  158.             else if (format is VertexDataFormat) _format = format;
  159.             else if (format is String) _format = VertexDataFormat.fromString(format as String);
  160.             else throw new ArgumentError("'format' must be String or VertexDataFormat");
  161.            
  162.             _attributes = _format.attributes;
  163.             _numAttributes = _attributes.length;
  164.             _posOffset = _format.hasAttribute("position") ? _format.getOffset("position") : 0;
  165.             _colOffset = _format.hasAttribute("color")    ? _format.getOffset("color")    : 0;
  166.             _vertexSize = _format.vertexSize;
  167.             _numVertices = 0;
  168.             _premultipliedAlpha = true;
  169.            
  170.             _rawData = FastByteArray.create(initialCapacity * _vertexSize,this);
  171.             _rawData.length = 0; // changes length, but not memory!
  172.            
  173.         }
  174.        
  175.         public function updateHeapOffset(newOffset:uint ):void {
  176.             _heapOffset = newOffset;
  177.         }
  178.        
  179.         /** Explicitly frees up the memory used by the ByteArray. */
  180.         public function clear():void
  181.         {
  182.             if (_rawData) {
  183.                 _rawData.dispose();
  184.                 _rawData = null;
  185.             }
  186.             _numVertices = 0;
  187.             _tinted = false;
  188.         }
  189.        
  190.         /** Creates a duplicate of the vertex data object. */
  191.         public function clone():VertexData
  192.         {
  193.             var clone:VertexData = new VertexData(_format, _numVertices);
  194.             writeBytes(clone._rawData, 0, _rawData, 0, _rawData.length);
  195.             clone._heapOffset = clone._rawData.offset;
  196.             clone._numVertices = _numVertices;
  197.             clone._premultipliedAlpha = _premultipliedAlpha;
  198.             clone._tinted = _tinted;
  199.             return clone;
  200.         }
  201.        
  202.         public function writeBytes(targetBytes:FastByteArray, targetPos:uint, sourceBytes:FastByteArray, sourcePos:uint = 0, length:uint = 0):void {
  203.             length = length == 0 ? sourceBytes.length : length;
  204.             var destinationEndPosition:int = targetPos + length;
  205.             if (targetBytes.length < destinationEndPosition) {
  206.                 targetBytes.length = destinationEndPosition;
  207.             }
  208.            
  209.             var heapAddress:uint = targetBytes.getHeapAddress(targetPos);
  210.             var sourceHeapAddress:uint = sourceBytes.getHeapAddress(sourcePos);
  211.            
  212.             var byteCount:int = length % 4;
  213.             var sourceEndPosition:uint = sourceBytes.getHeapAddress(sourcePos + byteCount);
  214.             while (sourceHeapAddress < sourceEndPosition) {
  215.                 si8(li8(sourceHeapAddress++), heapAddress++);
  216.             }
  217.             sourceEndPosition = sourceBytes.getHeapAddress(sourcePos + length);
  218.             while (sourceHeapAddress < sourceEndPosition) {
  219.                 si32(li32(sourceHeapAddress), heapAddress);
  220.                 heapAddress += 4;
  221.                 sourceHeapAddress += 4;
  222.             }
  223.         }
  224.         /** Copies the vertex data (or a range of it, defined by 'vertexID' and 'numVertices')
  225.          *  of this instance to another vertex data object, starting at a certain target index.
  226.          *  If the target is not big enough, it will be resized to fit all the new vertices.
  227.          *
  228.          *  <p>If you pass a non-null matrix, the 2D position of each vertex will be transformed
  229.          *  by that matrix before storing it in the target object. (The position being either an
  230.          *  attribute with the name "position" or, if such an attribute is not found, the first
  231.          *  attribute of each vertex. It must consist of two float values containing the x- and
  232.          *  y-coordinates of the vertex.)</p>
  233.          *
  234.          *  <p>Source and target do not need to have the exact same format. Only properties that
  235.          *  exist in the target will be copied; others will be ignored. If a property with the
  236.          *  same name but a different format exists in the target, an exception will be raised.
  237.          *  Beware, though, that the copy-operation becomes much more expensive when the formats
  238.          *  differ.</p>
  239.          */
  240.         public function copyTo(target:VertexData, targetVertexID:int=0, matrix:Matrix=null,
  241.                                vertexID:int=0, numVertices:int=-1):void
  242.         {
  243.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  244.                 numVertices = _numVertices - vertexID;
  245.            
  246.             if (_format === target._format)
  247.             {
  248.                 if (target._numVertices < targetVertexID + numVertices)
  249.                     target._numVertices = targetVertexID + numVertices;
  250.                
  251.                 target._tinted ||= _tinted;
  252.                
  253.                 // In this case, it's fastest to copy the complete range in one call
  254.                 // and then overwrite only the transformed positions.
  255.                
  256.                 var targetRawData:FastByteArray = target._rawData;
  257.                
  258.                 writeBytes(targetRawData, targetVertexID * _vertexSize, _rawData, ( vertexID * _vertexSize), numVertices * _vertexSize);
  259.                 target._heapOffset = targetRawData.offset;
  260.                 if (matrix)    {
  261.                     var x:Number, y:Number;
  262.                     var heapAddress:uint = targetRawData.offset + targetVertexID * _vertexSize + _posOffset;
  263.                     var endAddress:uint = heapAddress + (numVertices * _vertexSize);
  264.                    
  265.                     while (heapAddress < endAddress) {
  266.                         x = lf32(heapAddress);
  267.                         y = lf32(heapAddress + 4);
  268.                        
  269.                         sf32(matrix.a * x + matrix.c * y + matrix.tx, heapAddress);
  270.                         sf32(matrix.d * y + matrix.b * x + matrix.ty, heapAddress + 4);
  271.                         heapAddress += _vertexSize;
  272.                     }
  273.                 }
  274.             }
  275.             else
  276.             {
  277.                 if (target._numVertices < targetVertexID + numVertices)
  278.                     target.numVertices  = targetVertexID + numVertices; // ensure correct alphas!
  279.                
  280.                 for (var i:int=0; i<_numAttributes; ++i)
  281.                 {
  282.                     var srcAttr:VertexDataAttribute = _attributes[i];
  283.                     var tgtAttr:VertexDataAttribute = target.getAttribute(srcAttr.name);
  284.                    
  285.                     if (tgtAttr) // only copy attributes that exist in the target, as well
  286.                     {
  287.                         if (srcAttr.offset == _posOffset)
  288.                             copyAttributeTo_internal(target, targetVertexID, matrix,
  289.                                 srcAttr, tgtAttr, vertexID, numVertices);
  290.                         else
  291.                             copyAttributeTo_internal(target, targetVertexID, null,
  292.                                 srcAttr, tgtAttr, vertexID, numVertices);
  293.                     }
  294.                 }
  295.             }
  296.         }
  297.        
  298.         /** Copies a specific attribute of all contained vertices (or a range of them, defined by
  299.          *  'vertexID' and 'numVertices') to another VertexData instance. Beware that both name
  300.          *  and format of the attribute must be identical in source and target.
  301.          *  If the target is not big enough, it will be resized to fit all the new vertices.
  302.          *
  303.          *  <p>If you pass a non-null matrix, the specified attribute will be transformed by
  304.          *  that matrix before storing it in the target object. It must consist of two float
  305.          *  values.</p>
  306.          */
  307.         public function copyAttributeTo(target:VertexData, targetVertexID:int, attrName:String,
  308.                                         matrix:Matrix=null, vertexID:int=0, numVertices:int=-1):void
  309.         {
  310.             var sourceAttribute:VertexDataAttribute = getAttribute(attrName);
  311.             var targetAttribute:VertexDataAttribute = target.getAttribute(attrName);
  312.            
  313.             if (sourceAttribute == null)
  314.                 throw new ArgumentError("Attribute '" + attrName + "' not found in source data");
  315.            
  316.             if (targetAttribute == null)
  317.                 throw new ArgumentError("Attribute '" + attrName + "' not found in target data");
  318.            
  319.             if (sourceAttribute.isColor)
  320.                 target._tinted ||= _tinted;
  321.            
  322.             copyAttributeTo_internal(target, targetVertexID, matrix,
  323.                 sourceAttribute, targetAttribute, vertexID, numVertices);
  324.         }
  325.        
  326.         private function copyAttributeTo_internal(
  327.             target:VertexData, targetVertexID:int, matrix:Matrix,
  328.             sourceAttribute:VertexDataAttribute, targetAttribute:VertexDataAttribute,
  329.             vertexID:int, numVertices:int):void
  330.         {
  331.             if (sourceAttribute.format != targetAttribute.format)
  332.                 throw new IllegalOperationError("Attribute formats differ between source and target");
  333.            
  334.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  335.                 numVertices = _numVertices - vertexID;
  336.            
  337.             if (target._numVertices < targetVertexID + numVertices)
  338.                 target._numVertices = targetVertexID + numVertices;
  339.            
  340.             var i:int, j:int, x:Number, y:Number;
  341.             var sourceData:FastByteArray = _rawData;
  342.             var sourceDataHeapOffset:uint = sourceData.offset;
  343.             var sourceDelta:int = _vertexSize - sourceAttribute.size;
  344.             var targetDelta:int = target._vertexSize - targetAttribute.size;
  345.             var attributeSizeIn32Bits:int = sourceAttribute.size / 4;
  346.            
  347.             var sourceHeapAddress:uint = sourceDataHeapOffset + vertexID * _vertexSize + sourceAttribute.offset;
  348.             var targetHeapAddress:uint = sourceDataHeapOffset + targetVertexID * target._vertexSize + targetAttribute.offset;
  349.            
  350.             if (matrix)
  351.             {
  352.                 for (i=0; i<numVertices; ++i)
  353.                 {
  354.                     x = lf32(sourceHeapAddress);
  355.                     y = lf32(sourceHeapAddress += 4);
  356.                     sf32(matrix.a * x + matrix.c * y + matrix.tx, sourceHeapAddress += 4);
  357.                     sf32(matrix.d * y + matrix.b * x + matrix.ty, sourceHeapAddress += 4);
  358.                    
  359.                     sourceHeapAddress += sourceDelta;
  360.                     targetHeapAddress += targetDelta;
  361.                 }
  362.             }
  363.             else
  364.             {
  365.                 for (i=0; i<numVertices; ++i)
  366.                 {
  367.                     for (j=0; j<attributeSizeIn32Bits; ++j){
  368.                         si32(li32(sourceHeapAddress), targetHeapAddress);
  369.                         sourceHeapAddress += 4;
  370.                         targetHeapAddress += 4;
  371.                     }
  372.                     sourceHeapAddress += sourceDelta;
  373.                     targetHeapAddress += targetDelta;
  374.                 }
  375.             }
  376.         }
  377.        
  378.         /** Optimizes the ByteArray so that it has exactly the required capacity, without
  379.          *  wasting any memory. If your VertexData object grows larger than the initial capacity
  380.          *  you passed to the constructor, call this method to avoid the 4k memory problem. */
  381.         public function trim():void
  382.         {
  383.             var numBytes:int = _numVertices * _vertexSize;
  384.            
  385.             sBytes.length = numBytes;
  386.             writeBytes(sBytes, 0, _rawData, 0, numBytes);
  387.            
  388.             FastByteArray.switchMemory(_rawData, sBytes);
  389.            
  390.             sBytes.length = 0;
  391.         }
  392.        
  393.         /** Returns a string representation of the VertexData object,
  394.          *  describing both its format and size. */
  395.         public function toString():String
  396.         {
  397.             return StringUtil.format("[VertexData format=\"{0}\" numVertices={1}]",
  398.                 _format.formatString, _numVertices);
  399.         }
  400.        
  401.         // read / write attributes
  402.        
  403.         /** Reads an unsigned integer value from the specified vertex and attribute. */
  404.         public function getUnsignedInt(vertexID:int, attrName:String):uint
  405.         {
  406.             return li32(_heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset);
  407.         }
  408.        
  409.         /** Writes an unsigned integer value to the specified vertex and attribute. */
  410.         public function setUnsignedInt(vertexID:int, attrName:String, value:uint):void
  411.         {
  412.             if (_numVertices < vertexID + 1)
  413.                 numVertices = vertexID + 1;
  414.             si32(value, _heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset);
  415.         }
  416.        
  417.         /** Reads a float value from the specified vertex and attribute. */
  418.         public function getFloat(vertexID:int, attrName:String):Number
  419.         {
  420.             return lf32(_heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset);
  421.         }
  422.        
  423.         /** Writes a float value to the specified vertex and attribute. */
  424.         public function setFloat(vertexID:int, attrName:String, value:Number):void
  425.         {
  426.             if (_numVertices < vertexID + 1)
  427.                 numVertices = vertexID + 1;
  428.             sf32(value, _heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset);
  429.         }
  430.        
  431.         /** Reads a Point from the specified vertex and attribute. */
  432.         public function getPoint(vertexID:int, attrName:String, out:Point=null):Point
  433.         {
  434.             if (out == null) out = new Point();
  435.            
  436.             var offset:int = attrName == "position" ? _posOffset : getAttribute(attrName).offset;
  437.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  438.             out.x = lf32(heapAddress);
  439.             out.y = lf32(heapAddress + 4);
  440.            
  441.             return out;
  442.         }
  443.        
  444.         /** Writes the given coordinates to the specified vertex and attribute. */
  445.         public function setPoint(vertexID:int, attrName:String, x:Number, y:Number):void
  446.         {
  447.             if (_numVertices < vertexID + 1)
  448.                 numVertices = vertexID + 1;
  449.            
  450.             var offset:int = attrName == "position" ? _posOffset : getAttribute(attrName).offset;
  451.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  452.             sf32(x, heapAddress);
  453.             sf32(y, heapAddress + 4);
  454.         }
  455.        
  456.         /** Reads a Vector3D from the specified vertex and attribute.
  457.          *  The 'w' property of the Vector3D is ignored. */
  458.         public function getPoint3D(vertexID:int, attrName:String, out:Vector3D=null):Vector3D
  459.         {
  460.             if (out == null) out = new Vector3D();
  461.            
  462.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset;
  463.             out.x = lf32(heapAddress);
  464.             out.y = lf32(heapAddress + 4);
  465.             out.z = lf32(heapAddress + 8);
  466.            
  467.             return out;
  468.         }
  469.        
  470.         /** Writes the given coordinates to the specified vertex and attribute. */
  471.         public function setPoint3D(vertexID:int, attrName:String, x:Number, y:Number, z:Number):void
  472.         {
  473.             if (_numVertices < vertexID + 1)
  474.                 numVertices = vertexID + 1;
  475.            
  476.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset;
  477.             sf32(x, heapAddress);
  478.             sf32(y, heapAddress + 4);
  479.             sf32(z, heapAddress + 8);
  480.         }
  481.        
  482.         /** Reads a Vector3D from the specified vertex and attribute, including the fourth
  483.          *  coordinate ('w'). */
  484.         public function getPoint4D(vertexID:int, attrName:String, out:Vector3D=null):Vector3D
  485.         {
  486.             if (out == null) out = new Vector3D();
  487.            
  488.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset;
  489.             out.x = lf32(heapAddress);
  490.             out.y = lf32(heapAddress + 4);
  491.             out.z = lf32(heapAddress + 8);
  492.             out.w = lf32(heapAddress + 12);
  493.            
  494.             return out;
  495.         }
  496.        
  497.         /** Writes the given coordinates to the specified vertex and attribute. */
  498.         public function setPoint4D(vertexID:int, attrName:String,
  499.                                    x:Number, y:Number, z:Number, w:Number=1.0):void
  500.         {
  501.             if (_numVertices < vertexID + 1)
  502.                 numVertices = vertexID + 1;
  503.            
  504.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + getAttribute(attrName).offset;
  505.             sf32(x, heapAddress);
  506.             sf32(y, heapAddress + 4);
  507.             sf32(z, heapAddress + 8);
  508.             sf32(w, heapAddress + 12);
  509.         }
  510.        
  511.         private static var li32Color:int = 0;
  512.         private static var heapAddress:int = 0;
  513.         private static var rgba:uint = 0;
  514.        
  515.         /** Reads an RGB color from the specified vertex and attribute (no alpha). */
  516.         public function getColor(vertexID:int, attrName:String="color"):uint
  517.         {
  518.             var offset:int = attrName == "color" ? _colOffset : getAttribute(attrName).offset;
  519.            
  520.             heapAddress = _heapOffset + vertexID * _vertexSize + offset;
  521.             li32Color = li32(heapAddress);
  522.            
  523.             rgba = switchEndian(li32Color);
  524.            
  525.             if(_premultipliedAlpha)
  526.             {
  527.                 rgba = unmultiplyAlpha(rgba);    
  528.             }
  529.            
  530.             return (rgba >> 8) & 0xffffff;
  531.         }
  532.        
  533.         /** Writes the RGB color to the specified vertex and attribute (alpha is not changed). */
  534.         public function setColor(vertexID:int, attrName:String, color:uint):void
  535.         {
  536.             if (_numVertices < vertexID + 1)
  537.                 numVertices = vertexID + 1;
  538.            
  539.             var alpha:Number = getAlpha(vertexID, attrName);
  540.             colorize(attrName, color, alpha, vertexID, 1);
  541.         }
  542.        
  543.         /** Reads the alpha value from the specified vertex and attribute. */
  544.         public function getAlpha(vertexID:int, attrName:String="color"):Number
  545.         {
  546.             var offset:int = attrName == "color" ? _colOffset : getAttribute(attrName).offset;
  547.            
  548.             heapAddress = _heapOffset + vertexID * _vertexSize + offset;
  549.             li32Color = li32(heapAddress);
  550.            
  551.             rgba = switchEndian(li32Color);
  552.            
  553.             return (rgba & 0xff) / 255.0;
  554.         }
  555.        
  556.         /** Writes the given alpha value to the specified vertex and attribute (range 0-1). */
  557.         public function setAlpha(vertexID:int, attrName:String, alpha:Number):void
  558.         {
  559.             if (_numVertices < vertexID + 1)
  560.                 numVertices = vertexID + 1;
  561.            
  562.             var color:uint = getColor(vertexID, attrName);
  563.             colorize(attrName, color, alpha, vertexID, 1);
  564.         }
  565.        
  566.         // bounds helpers
  567.        
  568.         /** Calculates the bounds of the 2D vertex positions identified by the given name.
  569.          *  The positions may optionally be transformed by a matrix before calculating the bounds.
  570.          *  If you pass an 'out' Rectangle, the result will be stored in this rectangle
  571.          *  instead of creating a new object. To use all vertices for the calculation, set
  572.          *  'numVertices' to '-1'. */
  573.         public function getBounds(attrName:String="position", matrix:Matrix=null,
  574.                                   vertexID:int=0, numVertices:int=-1, out:Rectangle=null):Rectangle
  575.         {
  576.             if (out == null) out = new Rectangle();
  577.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  578.                 numVertices = _numVertices - vertexID;
  579.            
  580.             if (numVertices == 0)
  581.             {
  582.                 if (matrix == null)
  583.                     out.setEmpty();
  584.                 else
  585.                 {
  586.                     MatrixUtil.transformCoords(matrix, 0, 0, sHelperPoint);
  587.                     out.setTo(sHelperPoint.x, sHelperPoint.y, 0, 0);
  588.                 }
  589.             }
  590.             else
  591.             {
  592.                 var minX:Number = Number.MAX_VALUE, maxX:Number = -Number.MAX_VALUE;
  593.                 var minY:Number = Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE;
  594.                 var offset:int = attrName == "position" ? _posOffset : getAttribute(attrName).offset;
  595.                 var x:Number, y:Number, i:int;
  596.                 var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  597.                
  598.                 if (matrix == null)
  599.                 {
  600.                     for (i=0; i<numVertices; ++i)
  601.                     {
  602.                         x = lf32(heapAddress);
  603.                         y = lf32(heapAddress + 4);
  604.                         heapAddress += _vertexSize;
  605.                        
  606.                         if (minX > x) minX = x;
  607.                         if (maxX < x) maxX = x;
  608.                         if (minY > y) minY = y;
  609.                         if (maxY < y) maxY = y;
  610.                     }
  611.                 }
  612.                 else
  613.                 {
  614.                     for (i=0; i<numVertices; ++i)
  615.                     {
  616.                         x = lf32(heapAddress);
  617.                         y = lf32(heapAddress + 4);
  618.                         heapAddress += _vertexSize;
  619.                        
  620.                         MatrixUtil.transformCoords(matrix, x, y, sHelperPoint);
  621.                        
  622.                         if (minX > sHelperPoint.x) minX = sHelperPoint.x;
  623.                         if (maxX < sHelperPoint.x) maxX = sHelperPoint.x;
  624.                         if (minY > sHelperPoint.y) minY = sHelperPoint.y;
  625.                         if (maxY < sHelperPoint.y) maxY = sHelperPoint.y;
  626.                     }
  627.                 }
  628.                
  629.                 out.setTo(minX, minY, maxX - minX, maxY - minY);
  630.             }
  631.            
  632.             return out;
  633.         }
  634.        
  635.         /** Calculates the bounds of the 2D vertex positions identified by the given name,
  636.          *  projected into the XY-plane of a certain 3D space as they appear from the given
  637.          *  camera position. Note that 'camPos' is expected in the target coordinate system
  638.          *  (the same that the XY-plane lies in).
  639.          *
  640.          *  <p>If you pass an 'out' Rectangle, the result will be stored in this rectangle
  641.          *  instead of creating a new object. To use all vertices for the calculation, set
  642.          *  'numVertices' to '-1'.</p> */
  643.         public function getBoundsProjected(attrName:String, matrix:Matrix3D,
  644.                                            camPos:Vector3D, vertexID:int=0, numVertices:int=-1,
  645.                                            out:Rectangle=null):Rectangle
  646.         {
  647.             if (out == null) out = new Rectangle();
  648.             if (camPos == null) throw new ArgumentError("camPos must not be null");
  649.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  650.                 numVertices = _numVertices - vertexID;
  651.            
  652.             if (numVertices == 0)
  653.             {
  654.                 if (matrix)
  655.                     MatrixUtil.transformCoords3D(matrix, 0, 0, 0, sHelperPoint3D);
  656.                 else
  657.                     sHelperPoint3D.setTo(0, 0, 0);
  658.                
  659.                 MathUtil.intersectLineWithXYPlane(camPos, sHelperPoint3D, sHelperPoint);
  660.                 out.setTo(sHelperPoint.x, sHelperPoint.y, 0, 0);
  661.             }
  662.             else
  663.             {
  664.                 var minX:Number = Number.MAX_VALUE, maxX:Number = -Number.MAX_VALUE;
  665.                 var minY:Number = Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE;
  666.                 var offset:int = attrName == "position" ? _posOffset : getAttribute(attrName).offset;
  667.                 var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  668.                 var x:Number, y:Number, i:int;
  669.                
  670.                 for (i=0; i<numVertices; ++i)
  671.                 {
  672.                     x = lf32(heapAddress);
  673.                     y = lf32(heapAddress + 4);
  674.                     heapAddress += _vertexSize;
  675.                    
  676.                     if (matrix)
  677.                         MatrixUtil.transformCoords3D(matrix, x, y, 0, sHelperPoint3D);
  678.                     else
  679.                         sHelperPoint3D.setTo(x, y, 0);
  680.                    
  681.                     MathUtil.intersectLineWithXYPlane(camPos, sHelperPoint3D, sHelperPoint);
  682.                    
  683.                     if (minX > sHelperPoint.x) minX = sHelperPoint.x;
  684.                     if (maxX < sHelperPoint.x) maxX = sHelperPoint.x;
  685.                     if (minY > sHelperPoint.y) minY = sHelperPoint.y;
  686.                     if (maxY < sHelperPoint.y) maxY = sHelperPoint.y;
  687.                 }
  688.                
  689.                 out.setTo(minX, minY, maxX - minX, maxY - minY);
  690.             }
  691.            
  692.             return out;
  693.         }
  694.        
  695.         /** Indicates if color attributes should be stored premultiplied with the alpha value.
  696.          *  Changing this value does <strong>not</strong> modify any existing color data.
  697.          *  If you want that, use the <code>setPremultipliedAlpha</code> method instead.
  698.          *  @default true */
  699.         public function get premultipliedAlpha():Boolean { return _premultipliedAlpha; }
  700.         public function set premultipliedAlpha(value:Boolean):void
  701.         {
  702.             setPremultipliedAlpha(value, false);
  703.         }
  704.        
  705.         /** Changes the way alpha and color values are stored. Optionally updates all existing
  706.          *  vertices. */
  707.         public function setPremultipliedAlpha(value:Boolean, updateData:Boolean):void
  708.         {
  709.             if (updateData && value != _premultipliedAlpha)
  710.             {
  711.                 for (var i:int=0; i<_numAttributes; ++i)
  712.                 {
  713.                     var attribute:VertexDataAttribute = _attributes[i];
  714.                     if (attribute.isColor)
  715.                     {
  716.                         var heapAddress:uint = _heapOffset + attribute.offset;
  717.                         var oldColor:uint;
  718.                         var newColor:uint;
  719.                        
  720.                         for (var j:int=0; j<_numVertices; ++j)
  721.                         {
  722.                             li32Color = li32(heapAddress);
  723.                            
  724.                             oldColor = switchEndian(li32Color);
  725.                            
  726.                             if(value)
  727.                             {
  728.                                 oldColor = premultiplyAlpha(oldColor);
  729.                                 newColor = switchEndian(oldColor);
  730.                             }
  731.                             else
  732.                             {
  733.                                 oldColor = unmultiplyAlpha(oldColor);
  734.                                 newColor = switchEndian(oldColor);
  735.                             }
  736.                            
  737.                             si32(newColor, heapAddress);
  738.                             heapAddress += _vertexSize;
  739.                         }
  740.                     }
  741.                 }
  742.             }
  743.            
  744.             _premultipliedAlpha = value;
  745.         }
  746.        
  747.         /** Updates the <code>tinted</code> property from the actual color data. This might make
  748.          *  sense after copying part of a tinted VertexData instance to another, since not each
  749.          *  color value is checked in the process. An instance is tinted if any vertices have a
  750.          *  non-white color or are not fully opaque. */
  751.         public function updateTinted(attrName:String="color"):Boolean
  752.         {
  753.             var heapAddress:uint = attrName == "color" ? _heapOffset + _colOffset : _heapOffset + getAttribute(attrName).offset;
  754.             _tinted = false;
  755.            
  756.             for (var i:int=0; i<_numVertices; ++i)
  757.             {
  758.                 if (li32(heapAddress) != 0xffffffff) {
  759.                     _tinted = true;
  760.                     break;
  761.                 }
  762.                 heapAddress += _vertexSize;
  763.             }
  764.            
  765.             return _tinted;
  766.         }
  767.        
  768.         // modify multiple attributes
  769.        
  770.         /** Transforms the 2D positions of subsequent vertices by multiplication with a
  771.          *  transformation matrix. */
  772.         public function transformPoints(attrName:String, matrix:Matrix,
  773.                                         vertexID:int=0, numVertices:int=-1):void
  774.         {
  775.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  776.                 numVertices = _numVertices - vertexID;
  777.            
  778.             var x:Number, y:Number;
  779.             var offset:int = attrName == "position" ? _posOffset : getAttribute(attrName).offset;
  780.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  781.             var endAddress:uint = heapAddress + numVertices * _vertexSize;
  782.            
  783.             while (heapAddress < endAddress) {
  784.                 x = lf32(heapAddress);
  785.                 y = lf32(heapAddress + 4);
  786.                 sf32(matrix.a * x + matrix.c * y + matrix.tx, heapAddress);
  787.                 sf32(matrix.d * y + matrix.b * x + matrix.ty, heapAddress + 4);
  788.                 heapAddress += _vertexSize;
  789.             }
  790.         }
  791.        
  792.         /** Translates the 2D positions of subsequent vertices by a certain offset. */
  793.         public function translatePoints(attrName:String, deltaX:Number, deltaY:Number,
  794.                                         vertexID:int=0, numVertices:int=-1):void
  795.         {
  796.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  797.                 numVertices = _numVertices - vertexID;
  798.            
  799.             var x:Number, y:Number;
  800.             var offset:int = attrName == "position" ? _posOffset : getAttribute(attrName).offset;
  801.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  802.             var endAddress:uint = heapAddress + numVertices * _vertexSize;
  803.            
  804.             while (heapAddress < endAddress) {
  805.                 x = lf32(heapAddress);
  806.                 y = lf32(heapAddress + 4);
  807.                
  808.                 sf32(x + deltaX, heapAddress);
  809.                 sf32(y + deltaY, heapAddress + 4);
  810.                 heapAddress += _vertexSize;
  811.             }
  812.         }
  813.        
  814.         /** Multiplies the alpha values of subsequent vertices by a certain factor. */
  815.         public function scaleAlphas(attrName:String, factor:Number,
  816.                                     vertexID:int=0, numVertices:int=-1):void
  817.         {
  818.             if (factor == 1.0) return;
  819.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  820.                 numVertices = _numVertices - vertexID;
  821.            
  822.             _tinted = true; // factor must be != 1, so there's definitely tinting.
  823.            
  824.             var i:int;
  825.             var offset:int = attrName == "color" ? _colOffset : getAttribute(attrName).offset;
  826.             var colorAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  827.            
  828.             for (i=0; i<numVertices; ++i)
  829.             {
  830.                 var alphaAddress:uint = colorAddress + 3;
  831.                 var alpha:Number = li8(alphaAddress) / 255.0 * factor;
  832.                
  833.                 if (alpha > 1.0)      alpha = 1.0;
  834.                 else if (alpha < 0.0) alpha = 0.0;
  835.                
  836.                 if (alpha == 1.0 || !_premultipliedAlpha)
  837.                 {
  838.                     var value:int = int(alpha * 255.0);
  839.                     si8(value, alphaAddress);
  840.                 }
  841.                 else
  842.                 {
  843.                    
  844.                    
  845.                     li32Color = li32(colorAddress);
  846.                    
  847.                     rgba = switchEndian(li32Color);
  848.                     rgba = unmultiplyAlpha(rgba);
  849.                    
  850.                     rgba = (rgba & 0xffffff00) | (int(alpha * 255.0) & 0xff);
  851.                    
  852.                     rgba = premultiplyAlpha(rgba);
  853.                     rgba = switchEndian(rgba);
  854.                    
  855.                     si32(rgba, colorAddress);
  856.                 }
  857.                
  858.                 colorAddress += _vertexSize;
  859.             }
  860.         }
  861.        
  862.         /** Writes the given RGB and alpha values to the specified vertices. */
  863.         public function colorize(attrName:String="color", color:uint=0xffffff, alpha:Number=1.0,
  864.                                  vertexID:int=0, numVertices:int=-1):void
  865.         {
  866.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  867.                 numVertices = _numVertices - vertexID;
  868.            
  869.             var offset:int = attrName == "color" ? _colOffset : getAttribute(attrName).offset;
  870.             var heapAddress:uint = _heapOffset + vertexID * _vertexSize + offset;
  871.             var endAddress:uint = heapAddress + numVertices * _vertexSize;
  872.            
  873.             if (alpha > 1.0)      alpha = 1.0;
  874.             else if (alpha < 0.0) alpha = 0.0;
  875.            
  876.             rgba = ((color << 8) & 0xffffff00) | (int(alpha * 255.0) & 0xff);
  877.            
  878.             if (rgba == 0xffffffff && numVertices == _numVertices) _tinted = false;
  879.             else if (rgba != 0xffffffff) _tinted = true;
  880.            
  881.             if(_premultipliedAlpha && alpha != 1.0)
  882.             {
  883.                 rgba = premultiplyAlpha(rgba);
  884.                 rgba = switchEndian(rgba);
  885.             }
  886.             else
  887.             {
  888.                 rgba = switchEndian(rgba);
  889.             }
  890.            
  891.             si32(rgba, heapAddress);
  892.            
  893.             while (heapAddress < endAddress)
  894.             {
  895.                 si32(rgba, heapAddress);
  896.                 heapAddress += _vertexSize;
  897.             }
  898.         }
  899.        
  900.         // format helpers
  901.        
  902.         /** Returns the format of a certain vertex attribute, identified by its name.
  903.          * Typical values: <code>float1, float2, float3, float4, bytes4</code>. */
  904.         public function getFormat(attrName:String):String
  905.         {
  906.             return getAttribute(attrName).format;
  907.         }
  908.        
  909.         /** Returns the size of a certain vertex attribute in bytes. */
  910.         public function getSize(attrName:String):int
  911.         {
  912.             return getAttribute(attrName).size;
  913.         }
  914.        
  915.         /** Returns the size of a certain vertex attribute in 32 bit units. */
  916.         public function getSizeIn32Bits(attrName:String):int
  917.         {
  918.             return getAttribute(attrName).size / 4;
  919.         }
  920.        
  921.         /** Returns the offset (in bytes) of an attribute within a vertex. */
  922.         public function getOffset(attrName:String):int
  923.         {
  924.             return getAttribute(attrName).offset;
  925.         }
  926.        
  927.         /** Returns the offset (in 32 bit units) of an attribute within a vertex. */
  928.         public function getOffsetIn32Bits(attrName:String):int
  929.         {
  930.             return getAttribute(attrName).offset / 4;
  931.         }
  932.        
  933.         /** Indicates if the VertexData instances contains an attribute with the specified name. */
  934.         public function hasAttribute(attrName:String):Boolean
  935.         {
  936.             return getAttribute(attrName) != null;
  937.         }
  938.        
  939.         // VertexBuffer helpers
  940.        
  941.         /** Creates a vertex buffer object with the right size to fit the complete data.
  942.          *  Optionally, the current data is uploaded right away. */
  943.         public function createVertexBuffer(upload:Boolean=false,
  944.                                            bufferUsage:String="staticDraw"):VertexBuffer3D
  945.         {
  946.             var context:Context3D = Starling.context;
  947.             if (context == null) throw new MissingContextError();
  948.             if (_numVertices == 0) return null;
  949.            
  950.             var buffer:VertexBuffer3D = context.createVertexBuffer(
  951.                 _numVertices, _vertexSize / 4, bufferUsage);
  952.            
  953.             if (upload) uploadToVertexBuffer(buffer);
  954.             return buffer;
  955.         }
  956.        
  957.         /** Uploads the complete data (or a section of it) to the given vertex buffer. */
  958.         public function uploadToVertexBuffer(buffer:VertexBuffer3D, vertexID:int=0, numVertices:int=-1):void
  959.         {
  960.             if (numVertices < 0 || vertexID + numVertices > _numVertices)
  961.                 numVertices = _numVertices - vertexID;
  962.            
  963.             if (numVertices > 0)
  964.                 buffer.uploadFromByteArray(_rawData.heap, _rawData.offset, vertexID, numVertices);
  965.         }
  966.        
  967.         [Inline]
  968.         private final function getAttribute(attrName:String):VertexDataAttribute
  969.         {
  970.             var i:int, attribute:VertexDataAttribute;
  971.            
  972.             for (i=0; i<_numAttributes; ++i)
  973.             {
  974.                 attribute = _attributes[i];
  975.                 if (attribute.name == attrName) return attribute;
  976.             }
  977.            
  978.             return null;
  979.         }
  980.        
  981.         private static var alpha:Number;
  982.         private static var factor:Number;
  983.         private static var rc:uint;
  984.         private static var gc:uint;
  985.         private static var bc:uint;
  986.        
  987.         [Inline]
  988.         private static function premultiplyAlpha(rgba:uint):uint
  989.         {
  990.             alpha = rgba & 0xff;
  991.            
  992.             if (alpha == 0xff) return rgba;
  993.             else
  994.             {
  995.                 factor = alpha / 255.0;
  996.                 rc = ((rgba >> 24) & 0xff) * factor;
  997.                 gc = ((rgba >> 16) & 0xff) * factor;
  998.                 bc = ((rgba >>  8) & 0xff) * factor;
  999.                
  1000.                 return (rc & 0xff) << 24 |
  1001.                     (gc & 0xff) << 16 |
  1002.                     (bc & 0xff) <<  8 | alpha;
  1003.             }
  1004.         }
  1005.        
  1006.         [Inline]
  1007.         private static function unmultiplyAlpha(rgba:uint):uint
  1008.         {
  1009.             alpha = rgba & 0xff;
  1010.            
  1011.             if (alpha == 0xff || alpha == 0x0) return rgba;
  1012.             else
  1013.             {
  1014.                 factor = alpha / 255.0;
  1015.                 rc = ((rgba >> 24) & 0xff) / factor;
  1016.                 gc = ((rgba >> 16) & 0xff) / factor;
  1017.                 bc = ((rgba >>  8) & 0xff) / factor;
  1018.                
  1019.                 return (rc & 0xff) << 24 |
  1020.                     (gc & 0xff) << 16 |
  1021.                     (bc & 0xff) <<  8 | alpha;
  1022.             }
  1023.         }
  1024.        
  1025.         [Inline]
  1026.         private static function switchEndian(value:uint):uint
  1027.         {
  1028.             return ( value & 0xff) << 24 |
  1029.                 ((value >>  8) & 0xff) << 16 |
  1030.                 ((value >> 16) & 0xff) <<  8 |
  1031.                 ((value >> 24) & 0xff);
  1032.         }
  1033.        
  1034.         // properties
  1035.        
  1036.         /** The total number of vertices. If you make the object bigger, it will be filled up with
  1037.          *  <code>1.0</code> for all alpha values and zero for everything else. */
  1038.         public function get numVertices():int { return _numVertices; }
  1039.         public function set numVertices(value:int):void
  1040.         {
  1041.             if (value > _numVertices)
  1042.             {
  1043.                 var oldLength:int = _numVertices * vertexSize;
  1044.                 var newLength:int = value * _vertexSize;
  1045.                 var heapAddress:uint;
  1046.                
  1047.                 if (_rawData.length > oldLength)
  1048.                 {
  1049.                     heapAddress = _heapOffset + oldLength;
  1050.                     var rawDataLength:uint = _rawData.length;
  1051.                     while (heapAddress < rawDataLength) {
  1052.                         si32(0, heapAddress);
  1053.                         heapAddress += 4;
  1054.                     }
  1055.                 }
  1056.                
  1057.                 if (_rawData.length < newLength){
  1058.                     _rawData.length = newLength;
  1059.                 }
  1060.                
  1061.                 for (var i:int=0; i<_numAttributes; ++i)
  1062.                 {
  1063.                     var attribute:VertexDataAttribute = _attributes[i];
  1064.                     if (attribute.isColor) // initialize color values with "white" and full alpha
  1065.                     {
  1066.                         heapAddress = _heapOffset + _numVertices * _vertexSize + attribute.offset;
  1067.                         for (var j:int=_numVertices; j<value; ++j)
  1068.                         {
  1069.                             si32(0xffffffff, heapAddress);
  1070.                             heapAddress += _vertexSize;
  1071.                         }
  1072.                     }
  1073.                 }
  1074.             }
  1075.            
  1076.             if (value == 0) _tinted = false;
  1077.             _numVertices = value;
  1078.         }
  1079.        
  1080.         /** The format that describes the attributes of each vertex.
  1081.          *  When you assign a different format, the raw data will be converted accordingly,
  1082.          *  i.e. attributes with the same name will still point to the same data.
  1083.          *  New properties will be filled up with zeros (except for colors, which will be
  1084.          *  initialized with an alpha value of 1.0). As a side-effect, the instance will also
  1085.          *  be trimmed. */
  1086.         public function get format():VertexDataFormat
  1087.         {
  1088.             return _format;
  1089.         }
  1090.        
  1091.         public function set format(value:VertexDataFormat):void
  1092.         {
  1093.             if (_format == value) return;
  1094.            
  1095.             var a:int, i:int;
  1096.             var srcVertexSize:int = _format.vertexSize;
  1097.             var tgtVertexSize:int = value.vertexSize;
  1098.             var numAttributes:int = value.numAttributes;
  1099.            
  1100.             sBytes.length = value.vertexSize * _numVertices;
  1101.             var heapOffset:uint = sBytes.offset;
  1102.            
  1103.             for (a=0; a<numAttributes; ++a)
  1104.             {
  1105.                 var tgtAttr:VertexDataAttribute = value.attributes[a];
  1106.                 var srcAttr:VertexDataAttribute = getAttribute(tgtAttr.name);
  1107.                
  1108.                 if (srcAttr) // copy attributes that exist in both targets
  1109.                 {
  1110.                     var sBytesPos:uint = tgtAttr.offset;
  1111.                    
  1112.                     for (i=0; i<_numVertices; ++i)
  1113.                     {
  1114.                         writeBytes(sBytes, sBytesPos, _rawData, (srcVertexSize * i + srcAttr.offset), srcAttr.size);
  1115.                         sBytesPos += tgtVertexSize;
  1116.                     }
  1117.                 }
  1118.                 else if (tgtAttr.isColor) // initialize color values with "white" and full alpha
  1119.                 {
  1120.                     var heapAddress:uint = heapOffset + tgtAttr.offset;
  1121.                    
  1122.                     for (i=0; i<_numVertices; ++i)
  1123.                     {
  1124.                         si32(0xffffffff, heapAddress);
  1125.                         heapAddress += tgtVertexSize;
  1126.                     }
  1127.                 }
  1128.             }
  1129.             if (value.vertexSize > _format.vertexSize)
  1130.                 _rawData.length = 0;
  1131.            
  1132.             FastByteArray.switchMemory(_rawData, sBytes);
  1133.             sBytes.length = 0;
  1134.            
  1135.             _format = value;
  1136.             _attributes = _format.attributes;
  1137.             _numAttributes = _attributes.length;
  1138.             _vertexSize = _format.vertexSize;
  1139.             _posOffset = _format.hasAttribute("position") ? _format.getOffset("position") : 0;
  1140.             _colOffset = _format.hasAttribute("color")    ? _format.getOffset("color")    : 0;
  1141.         }
  1142.        
  1143.         /** Indicates if the mesh contains any vertices that are not white or not fully opaque.
  1144.          *  If <code>false</code> (and the value wasn't modified manually), the result is 100%
  1145.          *  accurate; <code>true</code> represents just an educated guess. To be entirely sure,
  1146.          *  you may call <code>updateTinted()</code>.
  1147.          */
  1148.         public function get tinted():Boolean { return _tinted; }
  1149.         public function set tinted(value:Boolean):void { _tinted = value; }
  1150.        
  1151.         /** The format string that describes the attributes of each vertex. */
  1152.         public function get formatString():String
  1153.         {
  1154.             return _format.formatString;
  1155.         }
  1156.        
  1157.         /** The size (in bytes) of each vertex. */
  1158.         public function get vertexSize():int
  1159.         {
  1160.             return _vertexSize;
  1161.         }
  1162.        
  1163.         /** The size (in 32 bit units) of each vertex. */
  1164.         public function get vertexSizeIn32Bits():int
  1165.         {
  1166.             return _vertexSize / 4;
  1167.         }
  1168.        
  1169.         /** The size (in bytes) of the raw vertex data. */
  1170.         public function get size():int
  1171.         {
  1172.             return _numVertices * _vertexSize;
  1173.         }
  1174.        
  1175.         /** The size (in 32 bit units) of the raw vertex data. */
  1176.         public function get sizeIn32Bits():int
  1177.         {
  1178.             return _numVertices * _vertexSize / 4;
  1179.         }
  1180.     }
  1181. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement