/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "rsContext.h" using namespace android; using namespace android::renderscript; Mesh::Mesh(Context *rsc) : ObjectBase(rsc) { mHal.drv = NULL; mHal.state.primitives = NULL; mHal.state.primitivesCount = 0; mHal.state.vertexBuffers = NULL; mHal.state.vertexBuffersCount = 0; mInitialized = false; } Mesh::Mesh(Context *rsc, uint32_t vertexBuffersCount, uint32_t primitivesCount) : ObjectBase(rsc) { mHal.drv = NULL; mHal.state.primitivesCount = primitivesCount; mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount]; for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { mHal.state.primitives[i] = new Primitive_t; } mHal.state.vertexBuffersCount = vertexBuffersCount; mHal.state.vertexBuffers = new ObjectBaseRef[mHal.state.vertexBuffersCount]; } Mesh::~Mesh() { #ifndef ANDROID_RS_SERIALIZE mRSC->mHal.funcs.mesh.destroy(mRSC, this); #endif if (mHal.state.vertexBuffers) { delete[] mHal.state.vertexBuffers; } if (mHal.state.primitives) { for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { mHal.state.primitives[i]->mIndexBuffer.clear(); delete mHal.state.primitives[i]; } delete[] mHal.state.primitives; } } void Mesh::init() { #ifndef ANDROID_RS_SERIALIZE mRSC->mHal.funcs.mesh.init(mRSC, this); #endif } void Mesh::serialize(OStream *stream) const { // Need to identify ourselves stream->addU32((uint32_t)getClassId()); String8 name(getName()); stream->addString(&name); // Store number of vertex streams stream->addU32(mHal.state.vertexBuffersCount); for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) { mHal.state.vertexBuffers[vCount]->serialize(stream); } stream->addU32(mHal.state.primitivesCount); // Store the primitives for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) { Primitive_t * prim = mHal.state.primitives[pCount]; stream->addU8((uint8_t)prim->mPrimitive); if (prim->mIndexBuffer.get()) { stream->addU32(1); prim->mIndexBuffer->serialize(stream); } else { stream->addU32(0); } } } Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) { // First make sure we are reading the correct object RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); if (classID != RS_A3D_CLASS_ID_MESH) { LOGE("mesh loading skipped due to invalid class id"); return NULL; } String8 name; stream->loadString(&name); uint32_t vertexBuffersCount = stream->loadU32(); ObjectBaseRef *vertexBuffers = NULL; if (vertexBuffersCount) { vertexBuffers = new ObjectBaseRef[vertexBuffersCount]; for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) { Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); vertexBuffers[vCount].set(vertexAlloc); } } uint32_t primitivesCount = stream->loadU32(); ObjectBaseRef *indexBuffers = NULL; RsPrimitive *primitives = NULL; if (primitivesCount) { indexBuffers = new ObjectBaseRef[primitivesCount]; primitives = new RsPrimitive[primitivesCount]; // load all primitives for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { primitives[pCount] = (RsPrimitive)stream->loadU8(); // Check to see if the index buffer was stored uint32_t isIndexPresent = stream->loadU32(); if (isIndexPresent) { Allocation *indexAlloc = Allocation::createFromStream(rsc, stream); indexBuffers[pCount].set(indexAlloc); } } } Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount); mesh->setName(name.string(), name.size()); for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) { mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount); } for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) { mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount); } // Cleanup if (vertexBuffersCount) { delete[] vertexBuffers; } if (primitivesCount) { delete[] indexBuffers; delete[] primitives; } #ifndef ANDROID_RS_SERIALIZE mesh->init(); mesh->uploadAll(rsc); #endif return mesh; } void Mesh::render(Context *rsc) const { for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { renderPrimitive(rsc, ct); } } void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const { if (primIndex >= mHal.state.primitivesCount) { LOGE("Invalid primitive index"); return; } Primitive_t *prim = mHal.state.primitives[primIndex]; if (prim->mIndexBuffer.get()) { renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX()); return; } renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX()); } void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { if (len < 1 || primIndex >= mHal.state.primitivesCount) { LOGE("Invalid mesh or parameters"); return; } mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len); } void Mesh::uploadAll(Context *rsc) { for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) { if (mHal.state.vertexBuffers[ct].get()) { rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.vertexBuffers[ct].get()); } } for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { if (mHal.state.primitives[ct]->mIndexBuffer.get()) { rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.primitives[ct]->mIndexBuffer.get()); } } } void Mesh::computeBBox() { float *posPtr = NULL; uint32_t vectorSize = 0; uint32_t stride = 0; uint32_t numVerts = 0; // First we need to find the position ptr and stride for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) { const Type *bufferType = mHal.state.vertexBuffers[ct]->getType(); const Element *bufferElem = bufferType->getElement(); for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) { if (strcmp(bufferElem->getFieldName(ct), "position") == 0) { vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize(); stride = bufferElem->getSizeBytes() / sizeof(float); uint32_t offset = bufferElem->getFieldOffsetBytes(ct); posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset); numVerts = bufferType->getDimX(); break; } } if (posPtr) { break; } } mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 1e6; mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = -1e6; if (!posPtr) { LOGE("Unable to compute bounding box"); mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 0.0f; mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = 0.0f; return; } for (uint32_t i = 0; i < numVerts; i ++) { for (uint32_t v = 0; v < vectorSize; v ++) { mBBoxMin[v] = rsMin(mBBoxMin[v], posPtr[v]); mBBoxMax[v] = rsMax(mBBoxMax[v], posPtr[v]); } posPtr += stride; } } namespace android { namespace renderscript { RsMesh rsi_MeshCreate(Context *rsc, RsAllocation * vtx, size_t vtxCount, RsAllocation * idx, size_t idxCount, uint32_t * primType, size_t primTypeCount) { rsAssert(idxCount == primTypeCount); Mesh *sm = new Mesh(rsc, vtxCount, idxCount); sm->incUserRef(); for (uint32_t i = 0; i < vtxCount; i ++) { sm->setVertexBuffer((Allocation*)vtx[i], i); } for (uint32_t i = 0; i < idxCount; i ++) { sm->setPrimitive((Allocation*)idx[i], (RsPrimitive)primType[i], i); } sm->init(); return sm; } }} void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) { Mesh *sm = static_cast(mv); *numVtx = sm->mHal.state.vertexBuffersCount; } void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) { Mesh *sm = static_cast(mv); *numIdx = sm->mHal.state.primitivesCount; } void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) { Mesh *sm = static_cast(mv); rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount); for (uint32_t ct = 0; ct < vtxDataCount; ct ++) { vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get(); sm->mHal.state.vertexBuffers[ct]->incUserRef(); } } void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) { Mesh *sm = static_cast(mv); rsAssert(idxDataCount == sm->mHal.state.primitivesCount); for (uint32_t ct = 0; ct < idxDataCount; ct ++) { va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get(); primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive; if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) { sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef(); } } }