You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
9.4 KiB
288 lines
9.4 KiB
/* |
|
* 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" |
|
#include "rsMesh.h" |
|
#include "rs.h" |
|
|
|
namespace android { |
|
namespace renderscript { |
|
|
|
Mesh::Mesh(Context *rsc) : ObjectBase(rsc) { |
|
mHal.drv = nullptr; |
|
mHal.state.primitives = nullptr; |
|
mHal.state.primitivesCount = 0; |
|
mHal.state.indexBuffers = nullptr; |
|
mHal.state.indexBuffersCount = 0; |
|
mHal.state.vertexBuffers = nullptr; |
|
mHal.state.vertexBuffersCount = 0; |
|
mInitialized = false; |
|
|
|
mVertexBuffers = nullptr; |
|
mIndexBuffers = nullptr; |
|
} |
|
|
|
Mesh::Mesh(Context *rsc, |
|
uint32_t vertexBuffersCount, |
|
uint32_t primitivesCount) : ObjectBase(rsc) { |
|
mHal.drv = nullptr; |
|
mHal.state.primitivesCount = primitivesCount; |
|
mHal.state.indexBuffersCount = primitivesCount; |
|
mHal.state.primitives = new RsPrimitive[mHal.state.primitivesCount]; |
|
mHal.state.indexBuffers = new Allocation *[mHal.state.indexBuffersCount]; |
|
for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) { |
|
mHal.state.primitives[i] = RS_PRIMITIVE_POINT; |
|
} |
|
for (uint32_t i = 0; i < mHal.state.indexBuffersCount; i ++) { |
|
mHal.state.indexBuffers[i] = nullptr; |
|
} |
|
mHal.state.vertexBuffersCount = vertexBuffersCount; |
|
mHal.state.vertexBuffers = new Allocation *[mHal.state.vertexBuffersCount]; |
|
for (uint32_t i = 0; i < mHal.state.vertexBuffersCount; i ++) { |
|
mHal.state.vertexBuffers[i] = nullptr; |
|
} |
|
|
|
mVertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount]; |
|
mIndexBuffers = new ObjectBaseRef<Allocation>[mHal.state.primitivesCount]; |
|
} |
|
|
|
Mesh::~Mesh() { |
|
#ifndef ANDROID_RS_SERIALIZE |
|
mRSC->mHal.funcs.mesh.destroy(mRSC, this); |
|
#endif |
|
|
|
delete[] mHal.state.vertexBuffers; |
|
delete[] mHal.state.primitives; |
|
delete[] mHal.state.indexBuffers; |
|
|
|
delete[] mVertexBuffers; |
|
delete[] mIndexBuffers; |
|
} |
|
|
|
void Mesh::init() { |
|
#ifndef ANDROID_RS_SERIALIZE |
|
mRSC->mHal.funcs.mesh.init(mRSC, this); |
|
#endif |
|
} |
|
|
|
void Mesh::serialize(Context *rsc, OStream *stream) const { |
|
// Need to identify ourselves |
|
stream->addU32((uint32_t)getClassId()); |
|
stream->addString(getName()); |
|
|
|
// 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(rsc, stream); |
|
} |
|
|
|
stream->addU32(mHal.state.primitivesCount); |
|
// Store the primitives |
|
for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) { |
|
stream->addU8((uint8_t)mHal.state.primitives[pCount]); |
|
|
|
if (mHal.state.indexBuffers[pCount]) { |
|
stream->addU32(1); |
|
mHal.state.indexBuffers[pCount]->serialize(rsc, 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) { |
|
ALOGE("mesh loading skipped due to invalid class id"); |
|
return nullptr; |
|
} |
|
|
|
const char *name = stream->loadString(); |
|
|
|
uint32_t vertexBuffersCount = stream->loadU32(); |
|
ObjectBaseRef<Allocation> *vertexBuffers = nullptr; |
|
if (vertexBuffersCount) { |
|
vertexBuffers = new ObjectBaseRef<Allocation>[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<Allocation> *indexBuffers = nullptr; |
|
RsPrimitive *primitives = nullptr; |
|
if (primitivesCount) { |
|
indexBuffers = new ObjectBaseRef<Allocation>[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->assignName(name); |
|
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) { |
|
ALOGE("Invalid primitive index"); |
|
return; |
|
} |
|
|
|
if (mHal.state.indexBuffers[primIndex]) { |
|
renderPrimitiveRange(rsc, primIndex, 0, mHal.state.indexBuffers[primIndex]->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) { |
|
ALOGE("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]) { |
|
rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.vertexBuffers[ct]); |
|
} |
|
} |
|
|
|
for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) { |
|
if (mHal.state.indexBuffers[ct]) { |
|
rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.indexBuffers[ct]); |
|
} |
|
} |
|
} |
|
|
|
void Mesh::computeBBox(Context *rsc) { |
|
float *posPtr = nullptr; |
|
uint32_t vectorSize = 0; |
|
uint32_t stride = 0; |
|
uint32_t numVerts = 0; |
|
Allocation *posAlloc = nullptr; |
|
// 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); |
|
posAlloc = mHal.state.vertexBuffers[ct]; |
|
const uint8_t *bp = (const uint8_t *)rsc->mHal.funcs.allocation.lock1D( |
|
rsc, posAlloc); |
|
posPtr = (float*)(bp + offset); |
|
numVerts = bufferType->getDimX(); |
|
break; |
|
} |
|
} |
|
if (posPtr) { |
|
break; |
|
} |
|
} |
|
|
|
mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 1e6; |
|
mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = -1e6; |
|
if (!posPtr) { |
|
ALOGE("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; |
|
} |
|
|
|
if (posAlloc) { |
|
rsc->mHal.funcs.allocation.unlock1D(rsc, posAlloc); |
|
} |
|
} |
|
|
|
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; |
|
} |
|
|
|
} // namespace renderscript |
|
} // namespace android
|
|
|