Home | History | Annotate | Download | only in renderscript
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.renderscript;
     18 
     19 import java.util.Vector;
     20 
     21 import android.util.Log;
     22 
     23 /**
     24  * <p>This class is a container for geometric data displayed with
     25  * Renderscript. Internally, a mesh is a collection of allocations that
     26  * represent vertex data (positions, normals, texture
     27  * coordinates) and index data such as triangles and lines. </p>
     28  * <p>
     29  * Vertex data could either be interleaved within one
     30  * allocation that is provided separately, as multiple allocation
     31  * objects, or done as a combination of both. When a
     32  * vertex channel name matches an input in the vertex program,
     33  * Renderscript automatically connects the two together.
     34  * </p>
     35  * <p>
     36  *  Parts of the mesh can be rendered with either explicit
     37  *  index sets or primitive types.
     38  * </p>
     39  **/
     40 public class Mesh extends BaseObj {
     41 
     42     /**
     43     * Describes the way mesh vertex data is interpreted when rendering
     44     *
     45     **/
     46     public enum Primitive {
     47         /**
     48         * Vertex data will be rendered as a series of points
     49         */
     50         POINT (0),
     51         /**
     52         * Vertex pairs will be rendered as lines
     53         */
     54         LINE (1),
     55         /**
     56         * Vertex data will be rendered as a connected line strip
     57         */
     58         LINE_STRIP (2),
     59         /**
     60         * Vertices will be rendered as individual triangles
     61         */
     62         TRIANGLE (3),
     63         /**
     64         * Vertices will be rendered as a connected triangle strip
     65         * defined by the first three vertices with each additional
     66         * triangle defined by a new vertex
     67         */
     68         TRIANGLE_STRIP (4),
     69         /**
     70         * Vertices will be rendered as a sequence of triangles that all
     71         * share first vertex as the origin
     72         */
     73         TRIANGLE_FAN (5);
     74 
     75         int mID;
     76         Primitive(int id) {
     77             mID = id;
     78         }
     79     }
     80 
     81     Allocation[] mVertexBuffers;
     82     Allocation[] mIndexBuffers;
     83     Primitive[] mPrimitives;
     84 
     85     Mesh(int id, RenderScript rs) {
     86         super(id, rs);
     87     }
     88 
     89     /**
     90     * @return number of allocations containing vertex data
     91     *
     92     **/
     93     public int getVertexAllocationCount() {
     94         if(mVertexBuffers == null) {
     95             return 0;
     96         }
     97         return mVertexBuffers.length;
     98     }
     99     /**
    100     * @param slot index in the list of allocations to return
    101     * @return vertex data allocation at the given index
    102     *
    103     **/
    104     public Allocation getVertexAllocation(int slot) {
    105         return mVertexBuffers[slot];
    106     }
    107 
    108     /**
    109     * @return number of primitives or index sets in the mesh
    110     *
    111     **/
    112     public int getPrimitiveCount() {
    113         if(mIndexBuffers == null) {
    114             return 0;
    115         }
    116         return mIndexBuffers.length;
    117     }
    118 
    119     /**
    120     * @param slot locaton within the list of index set allocation
    121     * @return allocation containing primtive index data or null if
    122     *         the index data is not specified explicitly
    123     *
    124     **/
    125     public Allocation getIndexSetAllocation(int slot) {
    126         return mIndexBuffers[slot];
    127     }
    128     /**
    129     * @param slot locaiton within the list of index set primitives
    130     * @return index set primitive type
    131     *
    132     **/
    133     public Primitive getPrimitive(int slot) {
    134         return mPrimitives[slot];
    135     }
    136 
    137     @Override
    138     void updateFromNative() {
    139         super.updateFromNative();
    140         int vtxCount = mRS.nMeshGetVertexBufferCount(getID());
    141         int idxCount = mRS.nMeshGetIndexCount(getID());
    142 
    143         int[] vtxIDs = new int[vtxCount];
    144         int[] idxIDs = new int[idxCount];
    145         int[] primitives = new int[idxCount];
    146 
    147         mRS.nMeshGetVertices(getID(), vtxIDs, vtxCount);
    148         mRS.nMeshGetIndices(getID(), idxIDs, primitives, idxCount);
    149 
    150         mVertexBuffers = new Allocation[vtxCount];
    151         mIndexBuffers = new Allocation[idxCount];
    152         mPrimitives = new Primitive[idxCount];
    153 
    154         for(int i = 0; i < vtxCount; i ++) {
    155             if(vtxIDs[i] != 0) {
    156                 mVertexBuffers[i] = new Allocation(vtxIDs[i], mRS, null, Allocation.USAGE_SCRIPT);
    157                 mVertexBuffers[i].updateFromNative();
    158             }
    159         }
    160 
    161         for(int i = 0; i < idxCount; i ++) {
    162             if(idxIDs[i] != 0) {
    163                 mIndexBuffers[i] = new Allocation(idxIDs[i], mRS, null, Allocation.USAGE_SCRIPT);
    164                 mIndexBuffers[i].updateFromNative();
    165             }
    166             mPrimitives[i] = Primitive.values()[primitives[i]];
    167         }
    168     }
    169 
    170     /**
    171     * Mesh builder object. It starts empty and requires you to
    172     * add the types necessary to create vertex and index
    173     * allocations.
    174     *
    175     */
    176     public static class Builder {
    177         RenderScript mRS;
    178         int mUsage;
    179 
    180         class Entry {
    181             Type t;
    182             Element e;
    183             int size;
    184             Primitive prim;
    185             int usage;
    186         }
    187 
    188         int mVertexTypeCount;
    189         Entry[] mVertexTypes;
    190         Vector mIndexTypes;
    191 
    192         /**
    193         * Creates builder object
    194         * @param rs Context to which the mesh will belong.
    195         * @param usage specifies how the mesh allocations are to be
    196         *              handled, whether they need to be uploaded to a
    197         *              buffer on the gpu, maintain a cpu copy, etc
    198         */
    199         public Builder(RenderScript rs, int usage) {
    200             mRS = rs;
    201             mUsage = usage;
    202             mVertexTypeCount = 0;
    203             mVertexTypes = new Entry[16];
    204             mIndexTypes = new Vector();
    205         }
    206 
    207         /**
    208         * @return internal index of the last vertex buffer type added to
    209         *         builder
    210         **/
    211         public int getCurrentVertexTypeIndex() {
    212             return mVertexTypeCount - 1;
    213         }
    214 
    215         /**
    216         * @return internal index of the last index set added to the
    217         *         builder
    218         **/
    219         public int getCurrentIndexSetIndex() {
    220             return mIndexTypes.size() - 1;
    221         }
    222 
    223         /**
    224         * Adds a vertex data type to the builder object
    225         *
    226         * @param t type of the vertex data allocation to be created
    227         *
    228         * @return this
    229         **/
    230         public Builder addVertexType(Type t) throws IllegalStateException {
    231             if (mVertexTypeCount >= mVertexTypes.length) {
    232                 throw new IllegalStateException("Max vertex types exceeded.");
    233             }
    234 
    235             mVertexTypes[mVertexTypeCount] = new Entry();
    236             mVertexTypes[mVertexTypeCount].t = t;
    237             mVertexTypes[mVertexTypeCount].e = null;
    238             mVertexTypeCount++;
    239             return this;
    240         }
    241 
    242         /**
    243         * Adds a vertex data type to the builder object
    244         *
    245         * @param e element describing the vertex data layout
    246         * @param size number of elements in the buffer
    247         *
    248         * @return this
    249         **/
    250         public Builder addVertexType(Element e, int size) throws IllegalStateException {
    251             if (mVertexTypeCount >= mVertexTypes.length) {
    252                 throw new IllegalStateException("Max vertex types exceeded.");
    253             }
    254 
    255             mVertexTypes[mVertexTypeCount] = new Entry();
    256             mVertexTypes[mVertexTypeCount].t = null;
    257             mVertexTypes[mVertexTypeCount].e = e;
    258             mVertexTypes[mVertexTypeCount].size = size;
    259             mVertexTypeCount++;
    260             return this;
    261         }
    262 
    263         /**
    264         * Adds an index set data type to the builder object
    265         *
    266         * @param t type of the index set data, could be null
    267         * @param p primitive type
    268         *
    269         * @return this
    270         **/
    271         public Builder addIndexSetType(Type t, Primitive p) {
    272             Entry indexType = new Entry();
    273             indexType.t = t;
    274             indexType.e = null;
    275             indexType.size = 0;
    276             indexType.prim = p;
    277             mIndexTypes.addElement(indexType);
    278             return this;
    279         }
    280 
    281         /**
    282         * Adds an index set primitive type to the builder object
    283         *
    284         * @param p primitive type
    285         *
    286         * @return this
    287         **/
    288         public Builder addIndexSetType(Primitive p) {
    289             Entry indexType = new Entry();
    290             indexType.t = null;
    291             indexType.e = null;
    292             indexType.size = 0;
    293             indexType.prim = p;
    294             mIndexTypes.addElement(indexType);
    295             return this;
    296         }
    297 
    298         /**
    299         * Adds an index set data type to the builder object
    300         *
    301         * @param e element describing the index set data layout
    302         * @param size number of elements in the buffer
    303         * @param p primitive type
    304         *
    305         * @return this
    306         **/
    307         public Builder addIndexSetType(Element e, int size, Primitive p) {
    308             Entry indexType = new Entry();
    309             indexType.t = null;
    310             indexType.e = e;
    311             indexType.size = size;
    312             indexType.prim = p;
    313             mIndexTypes.addElement(indexType);
    314             return this;
    315         }
    316 
    317         Type newType(Element e, int size) {
    318             Type.Builder tb = new Type.Builder(mRS, e);
    319             tb.setX(size);
    320             return tb.create();
    321         }
    322 
    323         /**
    324         * Create a Mesh object from the current state of the builder
    325         *
    326         **/
    327         public Mesh create() {
    328             mRS.validate();
    329             int[] vtx = new int[mVertexTypeCount];
    330             int[] idx = new int[mIndexTypes.size()];
    331             int[] prim = new int[mIndexTypes.size()];
    332 
    333             Allocation[] vertexBuffers = new Allocation[mVertexTypeCount];
    334             Allocation[] indexBuffers = new Allocation[mIndexTypes.size()];
    335             Primitive[] primitives = new Primitive[mIndexTypes.size()];
    336 
    337             for(int ct = 0; ct < mVertexTypeCount; ct ++) {
    338                 Allocation alloc = null;
    339                 Entry entry = mVertexTypes[ct];
    340                 if (entry.t != null) {
    341                     alloc = Allocation.createTyped(mRS, entry.t, mUsage);
    342                 } else if(entry.e != null) {
    343                     alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
    344                 }
    345                 vertexBuffers[ct] = alloc;
    346                 vtx[ct] = alloc.getID();
    347             }
    348 
    349             for(int ct = 0; ct < mIndexTypes.size(); ct ++) {
    350                 Allocation alloc = null;
    351                 Entry entry = (Entry)mIndexTypes.elementAt(ct);
    352                 if (entry.t != null) {
    353                     alloc = Allocation.createTyped(mRS, entry.t, mUsage);
    354                 } else if(entry.e != null) {
    355                     alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
    356                 }
    357                 int allocID = (alloc == null) ? 0 : alloc.getID();
    358                 indexBuffers[ct] = alloc;
    359                 primitives[ct] = entry.prim;
    360 
    361                 idx[ct] = allocID;
    362                 prim[ct] = entry.prim.mID;
    363             }
    364 
    365             int id = mRS.nMeshCreate(vtx, idx, prim);
    366             Mesh newMesh = new Mesh(id, mRS);
    367             newMesh.mVertexBuffers = vertexBuffers;
    368             newMesh.mIndexBuffers = indexBuffers;
    369             newMesh.mPrimitives = primitives;
    370 
    371             return newMesh;
    372         }
    373     }
    374 
    375     /**
    376     * Mesh builder object. It starts empty and requires the user to
    377     * add all the vertex and index allocations that comprise the
    378     * mesh
    379     *
    380     */
    381     public static class AllocationBuilder {
    382         RenderScript mRS;
    383 
    384         class Entry {
    385             Allocation a;
    386             Primitive prim;
    387         }
    388 
    389         int mVertexTypeCount;
    390         Entry[] mVertexTypes;
    391 
    392         Vector mIndexTypes;
    393 
    394         public AllocationBuilder(RenderScript rs) {
    395             mRS = rs;
    396             mVertexTypeCount = 0;
    397             mVertexTypes = new Entry[16];
    398             mIndexTypes = new Vector();
    399         }
    400 
    401         /**
    402         * @return internal index of the last vertex buffer type added to
    403         *         builder
    404         **/
    405         public int getCurrentVertexTypeIndex() {
    406             return mVertexTypeCount - 1;
    407         }
    408 
    409         /**
    410         * @return internal index of the last index set added to the
    411         *         builder
    412         **/
    413         public int getCurrentIndexSetIndex() {
    414             return mIndexTypes.size() - 1;
    415         }
    416 
    417         /**
    418         * Adds an allocation containing vertex buffer data to the
    419         * builder
    420         *
    421         * @param a vertex data allocation
    422         *
    423         * @return this
    424         **/
    425         public AllocationBuilder addVertexAllocation(Allocation a) throws IllegalStateException {
    426             if (mVertexTypeCount >= mVertexTypes.length) {
    427                 throw new IllegalStateException("Max vertex types exceeded.");
    428             }
    429 
    430             mVertexTypes[mVertexTypeCount] = new Entry();
    431             mVertexTypes[mVertexTypeCount].a = a;
    432             mVertexTypeCount++;
    433             return this;
    434         }
    435 
    436         /**
    437         * Adds an allocation containing index buffer data and index type
    438         * to the builder
    439         *
    440         * @param a index set data allocation, could be null
    441         * @param p index set primitive type
    442         *
    443         * @return this
    444         **/
    445         public AllocationBuilder addIndexSetAllocation(Allocation a, Primitive p) {
    446             Entry indexType = new Entry();
    447             indexType.a = a;
    448             indexType.prim = p;
    449             mIndexTypes.addElement(indexType);
    450             return this;
    451         }
    452 
    453         /**
    454         * Adds an index set type to the builder
    455         *
    456         * @param p index set primitive type
    457         *
    458         * @return this
    459         **/
    460         public AllocationBuilder addIndexSetType(Primitive p) {
    461             Entry indexType = new Entry();
    462             indexType.a = null;
    463             indexType.prim = p;
    464             mIndexTypes.addElement(indexType);
    465             return this;
    466         }
    467 
    468         /**
    469         * Create a Mesh object from the current state of the builder
    470         *
    471         **/
    472         public Mesh create() {
    473             mRS.validate();
    474 
    475             int[] vtx = new int[mVertexTypeCount];
    476             int[] idx = new int[mIndexTypes.size()];
    477             int[] prim = new int[mIndexTypes.size()];
    478 
    479             Allocation[] indexBuffers = new Allocation[mIndexTypes.size()];
    480             Primitive[] primitives = new Primitive[mIndexTypes.size()];
    481             Allocation[] vertexBuffers = new Allocation[mVertexTypeCount];
    482 
    483             for(int ct = 0; ct < mVertexTypeCount; ct ++) {
    484                 Entry entry = mVertexTypes[ct];
    485                 vertexBuffers[ct] = entry.a;
    486                 vtx[ct] = entry.a.getID();
    487             }
    488 
    489             for(int ct = 0; ct < mIndexTypes.size(); ct ++) {
    490                 Entry entry = (Entry)mIndexTypes.elementAt(ct);
    491                 int allocID = (entry.a == null) ? 0 : entry.a.getID();
    492                 indexBuffers[ct] = entry.a;
    493                 primitives[ct] = entry.prim;
    494 
    495                 idx[ct] = allocID;
    496                 prim[ct] = entry.prim.mID;
    497             }
    498 
    499             int id = mRS.nMeshCreate(vtx, idx, prim);
    500             Mesh newMesh = new Mesh(id, mRS);
    501             newMesh.mVertexBuffers = vertexBuffers;
    502             newMesh.mIndexBuffers = indexBuffers;
    503             newMesh.mPrimitives = primitives;
    504 
    505             return newMesh;
    506         }
    507     }
    508 
    509     /**
    510     * Builder that allows creation of a mesh object point by point
    511     * and triangle by triangle
    512     *
    513     **/
    514     public static class TriangleMeshBuilder {
    515         float mVtxData[];
    516         int mVtxCount;
    517         short mIndexData[];
    518         int mIndexCount;
    519         RenderScript mRS;
    520         Element mElement;
    521 
    522         float mNX = 0;
    523         float mNY = 0;
    524         float mNZ = -1;
    525         float mS0 = 0;
    526         float mT0 = 0;
    527         float mR = 1;
    528         float mG = 1;
    529         float mB = 1;
    530         float mA = 1;
    531 
    532         int mVtxSize;
    533         int mFlags;
    534 
    535         public static final int COLOR = 0x0001;
    536         public static final int NORMAL = 0x0002;
    537         public static final int TEXTURE_0 = 0x0100;
    538 
    539         /**
    540         * @param rs Context to which the mesh will belong.
    541         * @param vtxSize specifies whether the vertex is a float2 or
    542         *                float3
    543         * @param flags bitfield that is a combination of COLOR, NORMAL,
    544         *              and TEXTURE_0 that specifies what vertex data
    545         *              channels are present in the mesh
    546         *
    547         **/
    548         public TriangleMeshBuilder(RenderScript rs, int vtxSize, int flags) {
    549             mRS = rs;
    550             mVtxCount = 0;
    551             mIndexCount = 0;
    552             mVtxData = new float[128];
    553             mIndexData = new short[128];
    554             mVtxSize = vtxSize;
    555             mFlags = flags;
    556 
    557             if (vtxSize < 2 || vtxSize > 3) {
    558                 throw new IllegalArgumentException("Vertex size out of range.");
    559             }
    560         }
    561 
    562         private void makeSpace(int count) {
    563             if ((mVtxCount + count) >= mVtxData.length) {
    564                 float t[] = new float[mVtxData.length * 2];
    565                 System.arraycopy(mVtxData, 0, t, 0, mVtxData.length);
    566                 mVtxData = t;
    567             }
    568         }
    569 
    570         private void latch() {
    571             if ((mFlags & COLOR) != 0) {
    572                 makeSpace(4);
    573                 mVtxData[mVtxCount++] = mR;
    574                 mVtxData[mVtxCount++] = mG;
    575                 mVtxData[mVtxCount++] = mB;
    576                 mVtxData[mVtxCount++] = mA;
    577             }
    578             if ((mFlags & TEXTURE_0) != 0) {
    579                 makeSpace(2);
    580                 mVtxData[mVtxCount++] = mS0;
    581                 mVtxData[mVtxCount++] = mT0;
    582             }
    583             if ((mFlags & NORMAL) != 0) {
    584                 makeSpace(3);
    585                 mVtxData[mVtxCount++] = mNX;
    586                 mVtxData[mVtxCount++] = mNY;
    587                 mVtxData[mVtxCount++] = mNZ;
    588             }
    589         }
    590 
    591         /**
    592         * Adds a float2 vertex to the mesh
    593         *
    594         * @param x position x
    595         * @param y position y
    596         *
    597         * @return this
    598         *
    599         **/
    600         public TriangleMeshBuilder addVertex(float x, float y) {
    601             if (mVtxSize != 2) {
    602                 throw new IllegalStateException("add mistmatch with declared components.");
    603             }
    604             makeSpace(2);
    605             mVtxData[mVtxCount++] = x;
    606             mVtxData[mVtxCount++] = y;
    607             latch();
    608             return this;
    609         }
    610 
    611         /**
    612         * Adds a float3 vertex to the mesh
    613         *
    614         * @param x position x
    615         * @param y position y
    616         * @param z position z
    617         *
    618         * @return this
    619         *
    620         **/
    621         public TriangleMeshBuilder addVertex(float x, float y, float z) {
    622             if (mVtxSize != 3) {
    623                 throw new IllegalStateException("add mistmatch with declared components.");
    624             }
    625             makeSpace(3);
    626             mVtxData[mVtxCount++] = x;
    627             mVtxData[mVtxCount++] = y;
    628             mVtxData[mVtxCount++] = z;
    629             latch();
    630             return this;
    631         }
    632 
    633         /**
    634         * Sets the texture coordinate for the last added vertex
    635         *
    636         * @param s texture coordinate s
    637         * @param t texture coordinate t
    638         *
    639         * @return this
    640         **/
    641         public TriangleMeshBuilder setTexture(float s, float t) {
    642             if ((mFlags & TEXTURE_0) == 0) {
    643                 throw new IllegalStateException("add mistmatch with declared components.");
    644             }
    645             mS0 = s;
    646             mT0 = t;
    647             return this;
    648         }
    649 
    650         /**
    651         * Sets the normal vector for the last added vertex
    652         *
    653         * @param x normal vector x
    654         * @param y normal vector y
    655         * @param z normal vector z
    656         *
    657         * @return this
    658         **/
    659         public TriangleMeshBuilder setNormal(float x, float y, float z) {
    660             if ((mFlags & NORMAL) == 0) {
    661                 throw new IllegalStateException("add mistmatch with declared components.");
    662             }
    663             mNX = x;
    664             mNY = y;
    665             mNZ = z;
    666             return this;
    667         }
    668 
    669         /**
    670         * Sets the color for the last added vertex
    671         *
    672         * @param r red component
    673         * @param g green component
    674         * @param b blue component
    675         * @param a alpha component
    676         *
    677         * @return this
    678         **/
    679         public TriangleMeshBuilder setColor(float r, float g, float b, float a) {
    680             if ((mFlags & COLOR) == 0) {
    681                 throw new IllegalStateException("add mistmatch with declared components.");
    682             }
    683             mR = r;
    684             mG = g;
    685             mB = b;
    686             mA = a;
    687             return this;
    688         }
    689 
    690         /**
    691         * Adds a new triangle to the mesh builder
    692         *
    693         * @param idx1 index of the first vertex in the triangle
    694         * @param idx2 index of the second vertex in the triangle
    695         * @param idx3 index of the third vertex in the triangle
    696         *
    697         * @return this
    698         **/
    699         public TriangleMeshBuilder addTriangle(int idx1, int idx2, int idx3) {
    700             if((idx1 >= mVtxCount) || (idx1 < 0) ||
    701                (idx2 >= mVtxCount) || (idx2 < 0) ||
    702                (idx3 >= mVtxCount) || (idx3 < 0)) {
    703                throw new IllegalStateException("Index provided greater than vertex count.");
    704             }
    705             if ((mIndexCount + 3) >= mIndexData.length) {
    706                 short t[] = new short[mIndexData.length * 2];
    707                 System.arraycopy(mIndexData, 0, t, 0, mIndexData.length);
    708                 mIndexData = t;
    709             }
    710             mIndexData[mIndexCount++] = (short)idx1;
    711             mIndexData[mIndexCount++] = (short)idx2;
    712             mIndexData[mIndexCount++] = (short)idx3;
    713             return this;
    714         }
    715 
    716         /**
    717         * Creates the mesh object from the current state of the builder
    718         *
    719         * @param uploadToBufferObject specifies whether the vertex data
    720         *                             is to be uploaded into the buffer
    721         *                             object indicating that it's likely
    722         *                             not going to be modified and
    723         *                             rendered many times.
    724         *                             Alternatively, it indicates the
    725         *                             mesh data will be updated
    726         *                             frequently and remain in script
    727         *                             accessible memory
    728         *
    729         **/
    730         public Mesh create(boolean uploadToBufferObject) {
    731             Element.Builder b = new Element.Builder(mRS);
    732             int floatCount = mVtxSize;
    733             b.add(Element.createVector(mRS,
    734                                        Element.DataType.FLOAT_32,
    735                                        mVtxSize), "position");
    736             if ((mFlags & COLOR) != 0) {
    737                 floatCount += 4;
    738                 b.add(Element.F32_4(mRS), "color");
    739             }
    740             if ((mFlags & TEXTURE_0) != 0) {
    741                 floatCount += 2;
    742                 b.add(Element.F32_2(mRS), "texture0");
    743             }
    744             if ((mFlags & NORMAL) != 0) {
    745                 floatCount += 3;
    746                 b.add(Element.F32_3(mRS), "normal");
    747             }
    748             mElement = b.create();
    749 
    750             int usage = Allocation.USAGE_SCRIPT;
    751             if (uploadToBufferObject) {
    752                 usage |= Allocation.USAGE_GRAPHICS_VERTEX;
    753             }
    754 
    755             Builder smb = new Builder(mRS, usage);
    756             smb.addVertexType(mElement, mVtxCount / floatCount);
    757             smb.addIndexSetType(Element.U16(mRS), mIndexCount, Primitive.TRIANGLE);
    758 
    759             Mesh sm = smb.create();
    760 
    761             sm.getVertexAllocation(0).copy1DRangeFromUnchecked(0, mVtxCount / floatCount, mVtxData);
    762             if(uploadToBufferObject) {
    763                 if (uploadToBufferObject) {
    764                     sm.getVertexAllocation(0).syncAll(Allocation.USAGE_SCRIPT);
    765                 }
    766             }
    767 
    768             sm.getIndexSetAllocation(0).copy1DRangeFromUnchecked(0, mIndexCount, mIndexData);
    769             if (uploadToBufferObject) {
    770                 sm.getIndexSetAllocation(0).syncAll(Allocation.USAGE_SCRIPT);
    771             }
    772 
    773             return sm;
    774         }
    775     }
    776 }
    777 
    778