1/*
2 * Copyright (C) 2011 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#include "rsContext.h"
18#include "rsMesh.h"
19#include "rs.h"
20
21using namespace android;
22using namespace android::renderscript;
23
24Mesh::Mesh(Context *rsc) : ObjectBase(rsc) {
25    mHal.drv = NULL;
26    mHal.state.primitives = NULL;
27    mHal.state.primitivesCount = 0;
28    mHal.state.indexBuffers = NULL;
29    mHal.state.indexBuffersCount = 0;
30    mHal.state.vertexBuffers = NULL;
31    mHal.state.vertexBuffersCount = 0;
32    mInitialized = false;
33
34    mVertexBuffers = NULL;
35    mIndexBuffers = NULL;
36}
37
38Mesh::Mesh(Context *rsc,
39           uint32_t vertexBuffersCount,
40           uint32_t primitivesCount) : ObjectBase(rsc) {
41    mHal.drv = NULL;
42    mHal.state.primitivesCount = primitivesCount;
43    mHal.state.indexBuffersCount = primitivesCount;
44    mHal.state.primitives = new RsPrimitive[mHal.state.primitivesCount];
45    mHal.state.indexBuffers = new Allocation *[mHal.state.indexBuffersCount];
46    for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
47        mHal.state.primitives[i] = RS_PRIMITIVE_POINT;
48    }
49    for (uint32_t i = 0; i < mHal.state.indexBuffersCount; i ++) {
50        mHal.state.indexBuffers[i] = NULL;
51    }
52    mHal.state.vertexBuffersCount = vertexBuffersCount;
53    mHal.state.vertexBuffers = new Allocation *[mHal.state.vertexBuffersCount];
54    for (uint32_t i = 0; i < mHal.state.vertexBuffersCount; i ++) {
55        mHal.state.vertexBuffers[i] = NULL;
56    }
57
58    mVertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount];
59    mIndexBuffers = new ObjectBaseRef<Allocation>[mHal.state.primitivesCount];
60}
61
62Mesh::~Mesh() {
63#ifndef ANDROID_RS_SERIALIZE
64    mRSC->mHal.funcs.mesh.destroy(mRSC, this);
65#endif
66
67    delete[] mHal.state.vertexBuffers;
68    delete[] mHal.state.primitives;
69    delete[] mHal.state.indexBuffers;
70
71    delete[] mVertexBuffers;
72    delete[] mIndexBuffers;
73}
74
75void Mesh::init() {
76#ifndef ANDROID_RS_SERIALIZE
77    mRSC->mHal.funcs.mesh.init(mRSC, this);
78#endif
79}
80
81void Mesh::serialize(Context *rsc, OStream *stream) const {
82    // Need to identify ourselves
83    stream->addU32((uint32_t)getClassId());
84
85    String8 name(getName());
86    stream->addString(&name);
87
88    // Store number of vertex streams
89    stream->addU32(mHal.state.vertexBuffersCount);
90    for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) {
91        mHal.state.vertexBuffers[vCount]->serialize(rsc, stream);
92    }
93
94    stream->addU32(mHal.state.primitivesCount);
95    // Store the primitives
96    for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) {
97        stream->addU8((uint8_t)mHal.state.primitives[pCount]);
98
99        if (mHal.state.indexBuffers[pCount]) {
100            stream->addU32(1);
101            mHal.state.indexBuffers[pCount]->serialize(rsc, stream);
102        } else {
103            stream->addU32(0);
104        }
105    }
106}
107
108Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) {
109    // First make sure we are reading the correct object
110    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
111    if (classID != RS_A3D_CLASS_ID_MESH) {
112        ALOGE("mesh loading skipped due to invalid class id");
113        return NULL;
114    }
115
116    String8 name;
117    stream->loadString(&name);
118
119    uint32_t vertexBuffersCount = stream->loadU32();
120    ObjectBaseRef<Allocation> *vertexBuffers = NULL;
121    if (vertexBuffersCount) {
122        vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount];
123
124        for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
125            Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
126            vertexBuffers[vCount].set(vertexAlloc);
127        }
128    }
129
130    uint32_t primitivesCount = stream->loadU32();
131    ObjectBaseRef<Allocation> *indexBuffers = NULL;
132    RsPrimitive *primitives = NULL;
133    if (primitivesCount) {
134        indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount];
135        primitives = new RsPrimitive[primitivesCount];
136
137        // load all primitives
138        for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
139            primitives[pCount] = (RsPrimitive)stream->loadU8();
140
141            // Check to see if the index buffer was stored
142            uint32_t isIndexPresent = stream->loadU32();
143            if (isIndexPresent) {
144                Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
145                indexBuffers[pCount].set(indexAlloc);
146            }
147        }
148    }
149
150    Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount);
151    mesh->setName(name.string(), name.size());
152    for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
153        mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount);
154    }
155    for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
156        mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount);
157    }
158
159    // Cleanup
160    if (vertexBuffersCount) {
161        delete[] vertexBuffers;
162    }
163    if (primitivesCount) {
164        delete[] indexBuffers;
165        delete[] primitives;
166    }
167
168#ifndef ANDROID_RS_SERIALIZE
169    mesh->init();
170    mesh->uploadAll(rsc);
171#endif
172    return mesh;
173}
174
175void Mesh::render(Context *rsc) const {
176    for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
177        renderPrimitive(rsc, ct);
178    }
179}
180
181void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
182    if (primIndex >= mHal.state.primitivesCount) {
183        ALOGE("Invalid primitive index");
184        return;
185    }
186
187    if (mHal.state.indexBuffers[primIndex]) {
188        renderPrimitiveRange(rsc, primIndex, 0, mHal.state.indexBuffers[primIndex]->getType()->getDimX());
189        return;
190    }
191
192    renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX());
193}
194
195void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
196    if (len < 1 || primIndex >= mHal.state.primitivesCount) {
197        ALOGE("Invalid mesh or parameters");
198        return;
199    }
200
201    mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len);
202}
203
204void Mesh::uploadAll(Context *rsc) {
205    for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) {
206        if (mHal.state.vertexBuffers[ct]) {
207            rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.vertexBuffers[ct]);
208        }
209    }
210
211    for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
212        if (mHal.state.indexBuffers[ct]) {
213            rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.indexBuffers[ct]);
214        }
215    }
216}
217
218void Mesh::computeBBox(Context *rsc) {
219    float *posPtr = NULL;
220    uint32_t vectorSize = 0;
221    uint32_t stride = 0;
222    uint32_t numVerts = 0;
223    Allocation *posAlloc = NULL;
224    // First we need to find the position ptr and stride
225    for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
226        const Type *bufferType = mHal.state.vertexBuffers[ct]->getType();
227        const Element *bufferElem = bufferType->getElement();
228
229        for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) {
230            if (strcmp(bufferElem->getFieldName(ct), "position") == 0) {
231                vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize();
232                stride = bufferElem->getSizeBytes() / sizeof(float);
233                uint32_t offset = bufferElem->getFieldOffsetBytes(ct);
234                posAlloc = mHal.state.vertexBuffers[ct];
235                const uint8_t *bp = (const uint8_t *)rsc->mHal.funcs.allocation.lock1D(
236                        rsc, posAlloc);
237                posPtr = (float*)(bp + offset);
238                numVerts = bufferType->getDimX();
239                break;
240            }
241        }
242        if (posPtr) {
243            break;
244        }
245    }
246
247    mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 1e6;
248    mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = -1e6;
249    if (!posPtr) {
250        ALOGE("Unable to compute bounding box");
251        mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 0.0f;
252        mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = 0.0f;
253        return;
254    }
255
256    for (uint32_t i = 0; i < numVerts; i ++) {
257        for (uint32_t v = 0; v < vectorSize; v ++) {
258            mBBoxMin[v] = rsMin(mBBoxMin[v], posPtr[v]);
259            mBBoxMax[v] = rsMax(mBBoxMax[v], posPtr[v]);
260        }
261        posPtr += stride;
262    }
263
264    if (posAlloc) {
265        rsc->mHal.funcs.allocation.unlock1D(rsc, posAlloc);
266    }
267}
268
269namespace android {
270namespace renderscript {
271
272RsMesh rsi_MeshCreate(Context *rsc,
273                      RsAllocation * vtx, size_t vtxCount,
274                      RsAllocation * idx, size_t idxCount,
275                      uint32_t * primType, size_t primTypeCount) {
276    rsAssert(idxCount == primTypeCount);
277    Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
278    sm->incUserRef();
279
280    for (uint32_t i = 0; i < vtxCount; i ++) {
281        sm->setVertexBuffer((Allocation*)vtx[i], i);
282    }
283
284    for (uint32_t i = 0; i < idxCount; i ++) {
285        sm->setPrimitive((Allocation*)idx[i], (RsPrimitive)primType[i], i);
286    }
287
288    sm->init();
289
290    return sm;
291}
292
293}}
294
295void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) {
296    Mesh *sm = static_cast<Mesh *>(mv);
297    *numVtx = sm->mHal.state.vertexBuffersCount;
298}
299
300void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) {
301    Mesh *sm = static_cast<Mesh *>(mv);
302    *numIdx = sm->mHal.state.primitivesCount;
303}
304
305void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) {
306    Mesh *sm = static_cast<Mesh *>(mv);
307    rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount);
308
309    for (uint32_t ct = 0; ct < vtxDataCount; ct ++) {
310        vtxData[ct] = sm->mHal.state.vertexBuffers[ct];
311        sm->mHal.state.vertexBuffers[ct]->incUserRef();
312    }
313}
314
315void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) {
316    Mesh *sm = static_cast<Mesh *>(mv);
317    rsAssert(idxDataCount == sm->mHal.state.primitivesCount);
318
319    for (uint32_t ct = 0; ct < idxDataCount; ct ++) {
320        va[ct] = sm->mHal.state.indexBuffers[ct];
321        primType[ct] = sm->mHal.state.primitives[ct];
322        if (sm->mHal.state.indexBuffers[ct]) {
323            sm->mHal.state.indexBuffers[ct]->incUserRef();
324        }
325    }
326}
327