/* * 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. */ #ifndef _SIMPLE_MESH_H_ #define _SIMPLE_MESH_H_ #include <rsContext.h> #include <rsMesh.h> #include <string> using namespace android; using namespace android::renderscript; class SimpleMesh { public: struct Channel { std::vector<float> mData; std::string mName; uint32_t mStride; }; // Vertex channels (position, normal) // This assumes all the data array are the same size std::vector<Channel> mChannels; // Triangle list index data std::vector<std::vector<uint32_t> > mTriangleLists; // Names of all the triangle lists std::vector<std::string> mTriangleListNames; // Name of the entire object std::string mName; // Adds another index set to the mesh void appendFaceList(std::string name) { mTriangleListNames.push_back(name); mTriangleLists.push_back(std::vector<uint32_t>()); } // Adds another data channel (position, normal, etc.) void appendChannel(std::string name, uint32_t stride) { mChannels.push_back(Channel()); static const uint32_t reserveVtx = 128; mChannels.back().mData.reserve(reserveVtx*stride); mChannels.back().mName = name; mChannels.back().mStride = stride; } SimpleMesh() { // reserve some data in the vectors // simply letting it grow by itself tends to waste a lot of time on // rallocations / copies when dealing with geometry data static const uint32_t reserveFaces = 8; static const uint32_t reserveChannels = 8; mTriangleLists.reserve(reserveFaces); mTriangleListNames.reserve(reserveFaces); mChannels.reserve(reserveChannels); } // Generates a renderscript mesh that could be used for a3d serialization Mesh *getRsMesh(Context *rsc) { if (mChannels.size() == 0) { return NULL; } // Generate the element that describes our channel layout Element::Builder vtxBuilder; for (uint32_t c = 0; c < mChannels.size(); c ++) { // Skip empty channels if (mChannels[c].mData.size() == 0) { continue; } ObjectBaseRef<const Element> subElem = Element::createRef(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, mChannels[c].mStride); vtxBuilder.add(subElem.get(), mChannels[c].mName.c_str(), 1); } ObjectBaseRef<const Element> vertexDataElem = vtxBuilder.create(rsc); uint32_t numVerts = mChannels[0].mData.size()/mChannels[0].mStride; ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(rsc, vertexDataElem.get(), numVerts, 0, 0, false, false); vertexDataType->compute(); Allocation *vertexAlloc = Allocation::createAllocation(rsc, vertexDataType.get(), RS_ALLOCATION_USAGE_SCRIPT); uint32_t vertexSize = vertexDataElem->getSizeBytes()/sizeof(float); // Fill this allocation with some data float *dataPtr = (float*)vertexAlloc->getPtr(); for (uint32_t i = 0; i < numVerts; i ++) { // Find the pointer to the current vertex's data uint32_t vertexPos = i*vertexSize; float *vertexPtr = dataPtr + vertexPos; for (uint32_t c = 0; c < mChannels.size(); c ++) { // Skip empty channels if (mChannels[c].mData.size() == 0) { continue; } for (uint32_t cStride = 0; cStride < mChannels[c].mStride; cStride ++) { *(vertexPtr++) = mChannels[c].mData[i * mChannels[c].mStride + cStride]; } } } // Now lets write index data ObjectBaseRef<const Element> indexElem = Element::createRef(rsc, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1); Mesh *mesh = new Mesh(rsc, 1, mTriangleLists.size()); mesh->setName(mName.c_str()); mesh->setVertexBuffer(vertexAlloc, 0); // load all primitives for (uint32_t pCount = 0; pCount < mTriangleLists.size(); pCount ++) { uint32_t numIndicies = mTriangleLists[pCount].size(); ObjectBaseRef<Type> indexType = Type::getTypeRef(rsc, indexElem.get(), numIndicies, 0, 0, false, false ); indexType->compute(); Allocation *indexAlloc = Allocation::createAllocation(rsc, indexType.get(), RS_ALLOCATION_USAGE_SCRIPT); uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr(); const std::vector<uint32_t> &indexList = mTriangleLists[pCount]; uint32_t numTries = numIndicies / 3; for (uint32_t i = 0; i < numTries; i ++) { indexPtr[i * 3 + 0] = (uint16_t)indexList[i * 3 + 0]; indexPtr[i * 3 + 1] = (uint16_t)indexList[i * 3 + 1]; indexPtr[i * 3 + 2] = (uint16_t)indexList[i * 3 + 2]; } indexAlloc->setName(mTriangleListNames[pCount].c_str()); mesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, pCount); } return mesh; } }; #endif