Mesh.java revision 80a4c2cd34aedb4f1a2e5e7d1ac26a9aeebe41ae
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
17package android.renderscript;
18
19import java.util.Vector;
20
21import android.util.Config;
22import android.util.Log;
23
24/**
25 * @hide
26 *
27 **/
28public class Mesh extends BaseObj {
29
30    Allocation[] mVertexBuffers;
31    Allocation[] mIndexBuffers;
32    Primitive[] mPrimitives;
33
34    Mesh(int id, RenderScript rs) {
35        super(rs);
36        mID = id;
37    }
38
39    public int getVertexAllocationCount() {
40        if(mVertexBuffers == null) {
41            return 0;
42        }
43        return mVertexBuffers.length;
44    }
45    public Allocation getVertexAllocation(int slot) {
46        return mVertexBuffers[slot];
47    }
48
49    public int getPrimitiveCount() {
50        if(mIndexBuffers == null) {
51            return 0;
52        }
53        return mIndexBuffers.length;
54    }
55    public Allocation getIndexAllocation(int slot) {
56        return mIndexBuffers[slot];
57    }
58    public Primitive getPrimitive(int slot) {
59        return mPrimitives[slot];
60    }
61
62    @Override
63    void updateFromNative() {
64        int vtxCount = mRS.nMeshGetVertexBufferCount(mID);
65        int idxCount = mRS.nMeshGetIndexCount(mID);
66
67        int[] vtxIDs = new int[vtxCount];
68        int[] idxIDs = new int[idxCount];
69        int[] primitives = new int[idxCount];
70
71        mRS.nMeshGetVertices(mID, vtxIDs, vtxCount);
72        mRS.nMeshGetIndices(mID, idxIDs, primitives, vtxCount);
73
74        mVertexBuffers = new Allocation[vtxCount];
75        mIndexBuffers = new Allocation[idxCount];
76        mPrimitives = new Primitive[idxCount];
77
78        for(int i = 0; i < vtxCount; i ++) {
79            if(vtxIDs[i] != 0) {
80                mVertexBuffers[i] = new Allocation(vtxIDs[i], mRS);
81                mVertexBuffers[i].updateFromNative();
82            }
83        }
84
85        for(int i = 0; i < idxCount; i ++) {
86            if(idxIDs[i] != 0) {
87                mIndexBuffers[i] = new Allocation(idxIDs[i], mRS);
88                mIndexBuffers[i].updateFromNative();
89            }
90            mPrimitives[i] = Primitive.values()[primitives[i]];
91        }
92    }
93
94    public static class Builder {
95        RenderScript mRS;
96
97        class Entry {
98            Type t;
99            Element e;
100            int size;
101            Primitive prim;
102        }
103
104        int mVertexTypeCount;
105        Entry[] mVertexTypes;
106        Vector mIndexTypes;
107
108        public Builder(RenderScript rs) {
109            mRS = rs;
110            mVertexTypeCount = 0;
111            mVertexTypes = new Entry[16];
112            mIndexTypes = new Vector();
113        }
114
115        public int addVertexType(Type t) throws IllegalStateException {
116            if (mVertexTypeCount >= mVertexTypes.length) {
117                throw new IllegalStateException("Max vertex types exceeded.");
118            }
119
120            int addedIndex = mVertexTypeCount;
121            mVertexTypes[mVertexTypeCount] = new Entry();
122            mVertexTypes[mVertexTypeCount].t = t;
123            mVertexTypes[mVertexTypeCount].e = null;
124            mVertexTypeCount++;
125            return addedIndex;
126        }
127
128        public int addVertexType(Element e, int size) throws IllegalStateException {
129            if (mVertexTypeCount >= mVertexTypes.length) {
130                throw new IllegalStateException("Max vertex types exceeded.");
131            }
132
133            int addedIndex = mVertexTypeCount;
134            mVertexTypes[mVertexTypeCount] = new Entry();
135            mVertexTypes[mVertexTypeCount].t = null;
136            mVertexTypes[mVertexTypeCount].e = e;
137            mVertexTypes[mVertexTypeCount].size = size;
138            mVertexTypeCount++;
139            return addedIndex;
140        }
141
142        public int addIndexType(Type t, Primitive p) {
143            int addedIndex  = mIndexTypes.size();
144            Entry indexType = new Entry();
145            indexType.t = t;
146            indexType.e = null;
147            indexType.size = 0;
148            indexType.prim = p;
149            mIndexTypes.addElement(indexType);
150            return addedIndex;
151        }
152
153        public int addIndexType(Primitive p) {
154            int addedIndex  = mIndexTypes.size();
155            Entry indexType = new Entry();
156            indexType.t = null;
157            indexType.e = null;
158            indexType.size = 0;
159            indexType.prim = p;
160            mIndexTypes.addElement(indexType);
161            return addedIndex;
162        }
163
164        public int addIndexType(Element e, int size, Primitive p) {
165            int addedIndex  = mIndexTypes.size();
166            Entry indexType = new Entry();
167            indexType.t = null;
168            indexType.e = e;
169            indexType.size = size;
170            indexType.prim = p;
171            mIndexTypes.addElement(indexType);
172            return addedIndex;
173        }
174
175        Type newType(Element e, int size) {
176            Type.Builder tb = new Type.Builder(mRS, e);
177            tb.add(Dimension.X, size);
178            return tb.create();
179        }
180
181        static synchronized Mesh internalCreate(RenderScript rs, Builder b) {
182
183            int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size());
184            Mesh newMesh = new Mesh(id, rs);
185            newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()];
186            newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()];
187            newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount];
188
189            for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) {
190                Allocation alloc = null;
191                Entry entry = (Entry)b.mIndexTypes.elementAt(ct);
192                if (entry.t != null) {
193                    alloc = Allocation.createTyped(rs, entry.t);
194                }
195                else if(entry.e != null) {
196                    alloc = Allocation.createSized(rs, entry.e, entry.size);
197                }
198                int allocID = (alloc == null) ? 0 : alloc.getID();
199                rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct);
200                newMesh.mIndexBuffers[ct] = alloc;
201                newMesh.mPrimitives[ct] = entry.prim;
202            }
203
204            for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
205                Allocation alloc = null;
206                Entry entry = b.mVertexTypes[ct];
207                if (entry.t != null) {
208                    alloc = Allocation.createTyped(rs, entry.t);
209                } else if(entry.e != null) {
210                    alloc = Allocation.createSized(rs, entry.e, entry.size);
211                }
212                rs.nMeshBindVertex(id, alloc.getID(), ct);
213                newMesh.mVertexBuffers[ct] = alloc;
214            }
215
216            return newMesh;
217        }
218
219        public Mesh create() {
220            mRS.validate();
221            Mesh sm = internalCreate(mRS, this);
222            return sm;
223        }
224    }
225
226    public static class AllocationBuilder {
227        RenderScript mRS;
228
229        class Entry {
230            Allocation a;
231            Primitive prim;
232        }
233
234        int mVertexTypeCount;
235        Entry[] mVertexTypes;
236
237        Vector mIndexTypes;
238
239        public AllocationBuilder(RenderScript rs) {
240            mRS = rs;
241            mVertexTypeCount = 0;
242            mVertexTypes = new Entry[16];
243            mIndexTypes = new Vector();
244        }
245
246        public int addVertexAllocation(Allocation a) throws IllegalStateException {
247            if (mVertexTypeCount >= mVertexTypes.length) {
248                throw new IllegalStateException("Max vertex types exceeded.");
249            }
250
251            int addedIndex = mVertexTypeCount;
252            mVertexTypes[mVertexTypeCount] = new Entry();
253            mVertexTypes[mVertexTypeCount].a = a;
254            mVertexTypeCount++;
255            return addedIndex;
256        }
257
258        public int addIndexAllocation(Allocation a, Primitive p) {
259            int addedIndex  = mIndexTypes.size();
260            Entry indexType = new Entry();
261            indexType.a = a;
262            indexType.prim = p;
263            mIndexTypes.addElement(indexType);
264            return addedIndex;
265        }
266
267        public int addIndexType(Primitive p) {
268            int addedIndex  = mIndexTypes.size();
269            Entry indexType = new Entry();
270            indexType.a = null;
271            indexType.prim = p;
272            mIndexTypes.addElement(indexType);
273            return addedIndex;
274        }
275
276        static synchronized Mesh internalCreate(RenderScript rs, AllocationBuilder b) {
277
278            int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size());
279            Mesh newMesh = new Mesh(id, rs);
280            newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()];
281            newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()];
282            newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount];
283
284            for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) {
285                Entry entry = (Entry)b.mIndexTypes.elementAt(ct);
286                int allocID = (entry.a == null) ? 0 : entry.a.getID();
287                rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct);
288                newMesh.mIndexBuffers[ct] = entry.a;
289                newMesh.mPrimitives[ct] = entry.prim;
290            }
291
292            for(int ct = 0; ct < b.mVertexTypeCount; ct ++) {
293                Entry entry = b.mVertexTypes[ct];
294                rs.nMeshBindVertex(id, entry.a.mID, ct);
295                newMesh.mVertexBuffers[ct] = entry.a;
296            }
297
298            return newMesh;
299        }
300
301        public Mesh create() {
302            mRS.validate();
303            Mesh sm = internalCreate(mRS, this);
304            return sm;
305        }
306    }
307
308
309    public static class TriangleMeshBuilder {
310        float mVtxData[];
311        int mVtxCount;
312        short mIndexData[];
313        int mIndexCount;
314        RenderScript mRS;
315        Element mElement;
316
317        float mNX = 0;
318        float mNY = 0;
319        float mNZ = -1;
320        float mS0 = 0;
321        float mT0 = 0;
322        float mR = 1;
323        float mG = 1;
324        float mB = 1;
325        float mA = 1;
326
327        int mVtxSize;
328        int mFlags;
329
330        public static final int COLOR = 0x0001;
331        public static final int NORMAL = 0x0002;
332        public static final int TEXTURE_0 = 0x0100;
333
334        public TriangleMeshBuilder(RenderScript rs, int vtxSize, int flags) {
335            mRS = rs;
336            mVtxCount = 0;
337            mIndexCount = 0;
338            mVtxData = new float[128];
339            mIndexData = new short[128];
340            mVtxSize = vtxSize;
341            mFlags = flags;
342
343            if (vtxSize < 2 || vtxSize > 3) {
344                throw new IllegalArgumentException("Vertex size out of range.");
345            }
346        }
347
348        private void makeSpace(int count) {
349            if ((mVtxCount + count) >= mVtxData.length) {
350                float t[] = new float[mVtxData.length * 2];
351                System.arraycopy(mVtxData, 0, t, 0, mVtxData.length);
352                mVtxData = t;
353            }
354        }
355
356        private void latch() {
357            if ((mFlags & COLOR) != 0) {
358                makeSpace(4);
359                mVtxData[mVtxCount++] = mR;
360                mVtxData[mVtxCount++] = mG;
361                mVtxData[mVtxCount++] = mB;
362                mVtxData[mVtxCount++] = mA;
363            }
364            if ((mFlags & TEXTURE_0) != 0) {
365                makeSpace(2);
366                mVtxData[mVtxCount++] = mS0;
367                mVtxData[mVtxCount++] = mT0;
368            }
369            if ((mFlags & NORMAL) != 0) {
370                makeSpace(3);
371                mVtxData[mVtxCount++] = mNX;
372                mVtxData[mVtxCount++] = mNY;
373                mVtxData[mVtxCount++] = mNZ;
374            }
375        }
376
377        public void addVertex(float x, float y) {
378            if (mVtxSize != 2) {
379                throw new IllegalStateException("add mistmatch with declared components.");
380            }
381            makeSpace(2);
382            mVtxData[mVtxCount++] = x;
383            mVtxData[mVtxCount++] = y;
384            latch();
385        }
386
387        public void addVertex(float x, float y, float z) {
388            if (mVtxSize != 3) {
389                throw new IllegalStateException("add mistmatch with declared components.");
390            }
391            makeSpace(3);
392            mVtxData[mVtxCount++] = x;
393            mVtxData[mVtxCount++] = y;
394            mVtxData[mVtxCount++] = z;
395            latch();
396        }
397
398        public void setTexture(float s, float t) {
399            if ((mFlags & TEXTURE_0) == 0) {
400                throw new IllegalStateException("add mistmatch with declared components.");
401            }
402            mS0 = s;
403            mT0 = t;
404        }
405
406        public void setNormal(float x, float y, float z) {
407            if ((mFlags & NORMAL) == 0) {
408                throw new IllegalStateException("add mistmatch with declared components.");
409            }
410            mNX = x;
411            mNY = y;
412            mNZ = z;
413        }
414
415        public void setColor(float r, float g, float b, float a) {
416            if ((mFlags & COLOR) == 0) {
417                throw new IllegalStateException("add mistmatch with declared components.");
418            }
419            mR = r;
420            mG = g;
421            mB = b;
422            mA = a;
423        }
424
425        public void addTriangle(int idx1, int idx2, int idx3) {
426            if((idx1 >= mVtxCount) || (idx1 < 0) ||
427               (idx2 >= mVtxCount) || (idx2 < 0) ||
428               (idx3 >= mVtxCount) || (idx3 < 0)) {
429               throw new IllegalStateException("Index provided greater than vertex count.");
430            }
431            if ((mIndexCount + 3) >= mIndexData.length) {
432                short t[] = new short[mIndexData.length * 2];
433                System.arraycopy(mIndexData, 0, t, 0, mIndexData.length);
434                mIndexData = t;
435            }
436            mIndexData[mIndexCount++] = (short)idx1;
437            mIndexData[mIndexCount++] = (short)idx2;
438            mIndexData[mIndexCount++] = (short)idx3;
439        }
440
441        public Mesh create(boolean uploadToBufferObject) {
442            Element.Builder b = new Element.Builder(mRS);
443            int floatCount = mVtxSize;
444            b.add(Element.createVector(mRS,
445                                       Element.DataType.FLOAT_32,
446                                       mVtxSize), "position");
447            if ((mFlags & COLOR) != 0) {
448                floatCount += 4;
449                b.add(Element.F32_4(mRS), "color");
450            }
451            if ((mFlags & TEXTURE_0) != 0) {
452                floatCount += 2;
453                b.add(Element.F32_2(mRS), "texture0");
454            }
455            if ((mFlags & NORMAL) != 0) {
456                floatCount += 3;
457                b.add(Element.F32_3(mRS), "normal");
458            }
459            mElement = b.create();
460
461            Builder smb = new Builder(mRS);
462            smb.addVertexType(mElement, mVtxCount / floatCount);
463            smb.addIndexType(Element.U16(mRS), mIndexCount, Primitive.TRIANGLE);
464
465            Mesh sm = smb.create();
466
467            sm.getVertexAllocation(0).data(mVtxData);
468            if(uploadToBufferObject) {
469                sm.getVertexAllocation(0).uploadToBufferObject();
470            }
471
472            sm.getIndexAllocation(0).data(mIndexData);
473            sm.getIndexAllocation(0).uploadToBufferObject();
474
475            return sm;
476        }
477    }
478}
479
480