| /* |
| * Copyright (C) 2009 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 ANDROID_RS_BUILD_FOR_HOST |
| #include "rsContext.h" |
| |
| #include <GLES/gl.h> |
| #include <GLES2/gl2.h> |
| #include <GLES/glext.h> |
| #else |
| #include "rsContextHostStub.h" |
| |
| #include <OpenGL/gl.h> |
| #include <OpenGl/glext.h> |
| #endif |
| |
| using namespace android; |
| using namespace android::renderscript; |
| |
| |
| |
| |
| SimpleMesh::SimpleMesh(Context *rsc) : ObjectBase(rsc) |
| { |
| mAllocFile = __FILE__; |
| mAllocLine = __LINE__; |
| } |
| |
| SimpleMesh::~SimpleMesh() |
| { |
| delete[] mVertexTypes; |
| delete[] mVertexBuffers; |
| } |
| |
| void SimpleMesh::render(Context *rsc) const |
| { |
| if (mPrimitiveType.get()) { |
| renderRange(rsc, 0, mPrimitiveType->getDimX()); |
| return; |
| } |
| |
| if (mIndexType.get()) { |
| renderRange(rsc, 0, mIndexType->getDimX()); |
| return; |
| } |
| |
| renderRange(rsc, 0, mVertexTypes[0]->getDimX()); |
| } |
| |
| void SimpleMesh::renderRange(Context *rsc, uint32_t start, uint32_t len) const |
| { |
| if (len < 1) { |
| return; |
| } |
| |
| rsc->checkError("SimpleMesh::renderRange 1"); |
| VertexArray va; |
| if (rsc->checkVersion2_0()) { |
| for (uint32_t ct=0; ct < mVertexTypeCount; ct++) { |
| mVertexBuffers[ct]->uploadCheck(rsc); |
| va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID()); |
| mVertexTypes[ct]->enableGLVertexBuffer2(&va); |
| } |
| va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache); |
| } else { |
| for (uint32_t ct=0; ct < mVertexTypeCount; ct++) { |
| mVertexBuffers[ct]->uploadCheck(rsc); |
| va.setActiveBuffer(mVertexBuffers[ct]->getBufferObjectID()); |
| mVertexTypes[ct]->enableGLVertexBuffer(&va); |
| } |
| va.setupGL(rsc, 0); |
| } |
| |
| rsc->checkError("SimpleMesh::renderRange 2"); |
| if (mIndexType.get()) { |
| mIndexBuffer->uploadCheck(rsc); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID()); |
| glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2)); |
| } else { |
| glDrawArrays(mGLPrimitive, start, len); |
| } |
| |
| rsc->checkError("SimpleMesh::renderRange"); |
| } |
| |
| void SimpleMesh::uploadAll(Context *rsc) |
| { |
| for (uint32_t ct=0; ct < mVertexTypeCount; ct++) { |
| if (mVertexBuffers[ct].get()) { |
| mVertexBuffers[ct]->deferedUploadToBufferObject(rsc); |
| } |
| } |
| if (mIndexBuffer.get()) { |
| mIndexBuffer->deferedUploadToBufferObject(rsc); |
| } |
| if (mPrimitiveBuffer.get()) { |
| mPrimitiveBuffer->deferedUploadToBufferObject(rsc); |
| } |
| rsc->checkError("SimpleMesh::uploadAll"); |
| } |
| |
| void SimpleMesh::updateGLPrimitive() |
| { |
| switch(mPrimitive) { |
| case RS_PRIMITIVE_POINT: mGLPrimitive = GL_POINTS; break; |
| case RS_PRIMITIVE_LINE: mGLPrimitive = GL_LINES; break; |
| case RS_PRIMITIVE_LINE_STRIP: mGLPrimitive = GL_LINE_STRIP; break; |
| case RS_PRIMITIVE_TRIANGLE: mGLPrimitive = GL_TRIANGLES; break; |
| case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitive = GL_TRIANGLE_STRIP; break; |
| case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitive = GL_TRIANGLE_FAN; break; |
| } |
| } |
| |
| void SimpleMesh::serialize(OStream *stream) const |
| { |
| // Need to identify ourselves |
| stream->addU32((uint32_t)getClassId()); |
| |
| String8 name(getName()); |
| stream->addString(&name); |
| |
| // Add primitive type |
| stream->addU8((uint8_t)mPrimitive); |
| |
| // And now serialize the allocations |
| mIndexBuffer->serialize(stream); |
| |
| // We need to indicate if the primitive buffer is present |
| if(mPrimitiveBuffer.get() != NULL) { |
| // Write if the primitive buffer is present |
| stream->addU32(1); |
| mPrimitiveBuffer->serialize(stream); |
| } |
| else { |
| // No buffer present, will need this when we read |
| stream->addU32(0); |
| } |
| |
| // Store number of vertex streams |
| stream->addU32(mVertexTypeCount); |
| for(uint32_t vCount = 0; vCount < mVertexTypeCount; vCount ++) { |
| mVertexBuffers[vCount]->serialize(stream); |
| } |
| } |
| |
| SimpleMesh *SimpleMesh::createFromStream(Context *rsc, IStream *stream) |
| { |
| // First make sure we are reading the correct object |
| A3DClassID classID = (A3DClassID)stream->loadU32(); |
| if(classID != A3D_CLASS_ID_SIMPLE_MESH) { |
| LOGE("simple mesh loading skipped due to invalid class id"); |
| return NULL; |
| } |
| |
| SimpleMesh * mesh = new SimpleMesh(rsc); |
| |
| String8 name; |
| stream->loadString(&name); |
| mesh->setName(name.string(), name.size()); |
| |
| mesh->mPrimitive = (RsPrimitive)stream->loadU8(); |
| mesh->updateGLPrimitive(); |
| |
| Allocation *indexAlloc = Allocation::createFromStream(rsc, stream); |
| const Type *indexType = indexAlloc->getType(); |
| mesh->mIndexBuffer.set(indexAlloc); |
| mesh->mIndexType.set(indexType); |
| |
| bool isPrimitivePresent = stream->loadU32() != 0; |
| if(isPrimitivePresent) { |
| mesh->mPrimitiveBuffer.set(Allocation::createFromStream(rsc, stream)); |
| mesh->mPrimitiveType.set(mesh->mPrimitiveBuffer->getType()); |
| } |
| |
| mesh->mVertexTypeCount = stream->loadU32(); |
| if(mesh->mVertexTypeCount) { |
| mesh->mVertexTypes = new ObjectBaseRef<const Type>[mesh->mVertexTypeCount]; |
| mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexTypeCount]; |
| |
| for(uint32_t vCount = 0; vCount < mesh->mVertexTypeCount; vCount ++) { |
| Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream); |
| const Type *vertexType = vertexAlloc->getType(); |
| mesh->mVertexBuffers[vCount].set(vertexAlloc); |
| mesh->mVertexTypes[vCount].set(vertexType); |
| } |
| } |
| |
| return mesh; |
| } |
| |
| |
| SimpleMeshContext::SimpleMeshContext() |
| { |
| } |
| |
| SimpleMeshContext::~SimpleMeshContext() |
| { |
| } |
| |
| |
| namespace android { |
| namespace renderscript { |
| |
| |
| RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType) |
| { |
| SimpleMesh *sm = new SimpleMesh(rsc); |
| sm->incUserRef(); |
| |
| sm->mIndexType.set((const Type *)idx); |
| sm->mPrimitiveType.set((const Type *)prim); |
| |
| sm->mVertexTypeCount = vtxCount; |
| sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount]; |
| sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount]; |
| for (uint32_t ct=0; ct < vtxCount; ct++) { |
| sm->mVertexTypes[ct].set((const Type *)vtx[ct]); |
| } |
| |
| sm->mPrimitive = (RsPrimitive)primType; |
| sm->updateGLPrimitive(); |
| return sm; |
| } |
| |
| void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot) |
| { |
| SimpleMesh *sm = static_cast<SimpleMesh *>(mv); |
| rsAssert(slot < sm->mVertexTypeCount); |
| |
| sm->mVertexBuffers[slot].set((Allocation *)va); |
| } |
| |
| void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va) |
| { |
| SimpleMesh *sm = static_cast<SimpleMesh *>(mv); |
| sm->mIndexBuffer.set((Allocation *)va); |
| } |
| |
| void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va) |
| { |
| SimpleMesh *sm = static_cast<SimpleMesh *>(mv); |
| sm->mPrimitiveBuffer.set((Allocation *)va); |
| } |
| |
| |
| |
| |
| }} |
| |