| /* |
| * 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. |
| */ |
| |
| #include "rsContext.h" |
| |
| using namespace android; |
| using namespace android::renderscript; |
| |
| #include <GLES/gl.h> |
| #include <GLES/glext.h> |
| |
| TriangleMesh::TriangleMesh() |
| { |
| mVertexElement = NULL; |
| mIndexElement = NULL; |
| mVertexData = NULL; |
| mIndexData = NULL; |
| mTriangleCount = 0; |
| mVertexDataSize = 0; |
| mIndexDataSize = 0; |
| |
| mBufferObjects[0] = 0; |
| mBufferObjects[1] = 0; |
| |
| mOffsetCoord = 0; |
| mOffsetTex = 0; |
| mOffsetNorm = 0; |
| |
| mSizeCoord = 0; |
| mSizeTex = 0; |
| mSizeNorm = 0; |
| |
| } |
| |
| TriangleMesh::~TriangleMesh() |
| { |
| free(mVertexData); |
| free(mIndexData); |
| } |
| |
| |
| |
| TriangleMeshContext::TriangleMeshContext() |
| { |
| clear(); |
| } |
| |
| TriangleMeshContext::~TriangleMeshContext() |
| { |
| } |
| |
| void TriangleMeshContext::clear() |
| { |
| mVertexElement = NULL; |
| mVertexSizeBits = 0; |
| mIndexElement = NULL; |
| mIndexSizeBits = 0; |
| mTriangleCount = 0; |
| mVertexData.clear(); |
| mIndexData.clear(); |
| } |
| |
| void TriangleMesh::analyzeElement() |
| { |
| for (uint32_t ct=0; ct < mVertexElement->getComponentCount(); ct++) { |
| const Component *c = mVertexElement->getComponent(ct); |
| |
| if (c->getKind() == Component::X) { |
| rsAssert(mSizeCoord == 0); |
| mSizeCoord = 1; |
| mOffsetCoord = ct; |
| } |
| if (c->getKind() == Component::Y) { |
| rsAssert(mSizeCoord == 1); |
| mSizeCoord = 2; |
| } |
| if (c->getKind() == Component::Z) { |
| rsAssert(mSizeCoord == 2); |
| mSizeCoord = 3; |
| } |
| if (c->getKind() == Component::W) { |
| rsAssert(mSizeCoord == 4); |
| mSizeCoord = 4; |
| } |
| |
| if (c->getKind() == Component::NX) { |
| rsAssert(mSizeNorm == 0); |
| mSizeNorm = 1; |
| mOffsetNorm = ct; |
| } |
| if (c->getKind() == Component::NY) { |
| rsAssert(mSizeNorm == 1); |
| mSizeNorm = 2; |
| } |
| if (c->getKind() == Component::NZ) { |
| rsAssert(mSizeNorm == 2); |
| mSizeNorm = 3; |
| } |
| |
| if (c->getKind() == Component::S) { |
| rsAssert(mSizeTex == 0); |
| mSizeTex = 1; |
| mOffsetTex = ct; |
| } |
| if (c->getKind() == Component::T) { |
| rsAssert(mSizeTex == 1); |
| mSizeTex = 2; |
| } |
| } |
| LOGV("TriangleMesh %i,%i %i,%i %i,%i", mSizeCoord, mOffsetCoord, mSizeNorm, mOffsetNorm, mSizeTex, mOffsetTex); |
| |
| } |
| |
| |
| namespace android { |
| namespace renderscript { |
| |
| void rsi_TriangleMeshBegin(Context *rsc, RsElement vertex, RsElement index) |
| { |
| TriangleMeshContext *tmc = &rsc->mStateTriangleMesh; |
| |
| tmc->clear(); |
| tmc->mVertexElement = static_cast<Element *>(vertex); |
| tmc->mVertexSizeBits = tmc->mVertexElement->getSizeBits(); |
| tmc->mIndexElement = static_cast<Element *>(index); |
| tmc->mIndexSizeBits = tmc->mIndexElement->getSizeBits(); |
| |
| assert(!(tmc->mVertexSizeBits & 0x7)); |
| assert(!(tmc->mIndexSizeBits & 0x7)); |
| } |
| |
| void rsi_TriangleMeshAddVertex(Context *rsc, const void *data) |
| { |
| TriangleMeshContext *tmc = &rsc->mStateTriangleMesh; |
| |
| // todo: Make this efficient. |
| for (uint32_t ct = 0; (ct * 8) < tmc->mVertexSizeBits; ct++) { |
| tmc->mVertexData.add(static_cast<const uint8_t *>(data) [ct]); |
| } |
| } |
| |
| void rsi_TriangleMeshAddTriangle(Context *rsc, uint32_t idx1, uint32_t idx2, uint32_t idx3) |
| { |
| TriangleMeshContext *tmc = &rsc->mStateTriangleMesh; |
| |
| // todo: Make this efficient. |
| switch(tmc->mIndexSizeBits) { |
| case 16: |
| tmc->mIndexData.add(idx1); |
| tmc->mIndexData.add(idx2); |
| tmc->mIndexData.add(idx3); |
| break; |
| default: |
| assert(0); |
| } |
| |
| tmc->mTriangleCount++; |
| } |
| |
| RsTriangleMesh rsi_TriangleMeshCreate(Context *rsc) |
| { |
| TriangleMeshContext *tmc = &rsc->mStateTriangleMesh; |
| |
| TriangleMesh * tm = new TriangleMesh(); |
| if (!tm) { |
| LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY"); |
| // error |
| return 0; |
| } |
| |
| tm->mTriangleCount = tmc->mTriangleCount; |
| tm->mIndexDataSize = tmc->mIndexData.size() * tmc->mIndexSizeBits >> 3; |
| tm->mVertexDataSize = tmc->mVertexData.size(); |
| tm->mIndexElement = tmc->mIndexElement; |
| tm->mVertexElement = tmc->mVertexElement; |
| |
| tm->mIndexData = malloc(tm->mIndexDataSize); |
| tm->mVertexData = malloc(tm->mVertexDataSize); |
| if (!tm->mIndexData || !tm->mVertexData) { |
| LOGE("rsTriangleMeshCreate: Error OUT OF MEMORY"); |
| delete tm; |
| return 0; |
| } |
| |
| memcpy(tm->mVertexData, tmc->mVertexData.array(), tm->mVertexDataSize); |
| memcpy(tm->mIndexData, tmc->mIndexData.array(), tm->mIndexDataSize); |
| tm->analyzeElement(); |
| |
| tm->incRef(); |
| return tm; |
| } |
| |
| void rsi_TriangleMeshDestroy(Context *rsc, RsTriangleMesh vtm) |
| { |
| TriangleMeshContext *tmc = &rsc->mStateTriangleMesh; |
| TriangleMesh * tm = static_cast<TriangleMesh *>(vtm); |
| |
| free(tm->mIndexData); |
| free(tm->mVertexData); |
| delete tm; |
| } |
| |
| |
| |
| void rsi_TriangleMeshRenderRange(Context *rsc, RsTriangleMesh vtm, uint32_t first, uint32_t count) |
| { |
| TriangleMesh * tm = static_cast<TriangleMesh *>(vtm); |
| |
| rsc->setupCheck(); |
| |
| if (!tm->mBufferObjects[0]) { |
| glGenBuffers(2, &tm->mBufferObjects[0]); |
| |
| glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]); |
| glBufferData(GL_ARRAY_BUFFER, tm->mVertexDataSize, tm->mVertexData, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]); |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, tm->mIndexDataSize, tm->mIndexData, GL_STATIC_DRAW); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
| } |
| |
| if (first >= tm->mTriangleCount) { |
| return; |
| } |
| if (count >= (tm->mTriangleCount - first)) { |
| count = tm->mTriangleCount - first; |
| } |
| if (!count) { |
| return; |
| } |
| |
| const float *f = (const float *)tm->mVertexData; |
| |
| glBindBuffer(GL_ARRAY_BUFFER, tm->mBufferObjects[0]); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]); |
| |
| glEnableClientState(GL_VERTEX_ARRAY); |
| glVertexPointer(tm->mSizeCoord, |
| GL_FLOAT, |
| tm->mVertexElement->getSizeBytes(), |
| (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetCoord)); |
| |
| if (tm->mSizeTex) { |
| glEnableClientState(GL_TEXTURE_COORD_ARRAY); |
| glTexCoordPointer(tm->mSizeTex, |
| GL_FLOAT, |
| tm->mVertexElement->getSizeBytes(), |
| (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetTex)); |
| } else { |
| glDisableClientState(GL_TEXTURE_COORD_ARRAY); |
| } |
| |
| if (tm->mSizeNorm) { |
| glEnableClientState(GL_NORMAL_ARRAY); |
| glNormalPointer(GL_FLOAT, |
| tm->mVertexElement->getSizeBytes(), |
| (void *)tm->mVertexElement->getComponentOffsetBytes(tm->mOffsetNorm)); |
| } else { |
| glDisableClientState(GL_NORMAL_ARRAY); |
| } |
| |
| glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, (GLvoid *)(first * 3 * 2)); |
| |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
| } |
| |
| void rsi_TriangleMeshRender(Context *rsc, RsTriangleMesh vtm) |
| { |
| rsi_TriangleMeshRenderRange(rsc, vtm, 0, 0xffffff); |
| } |
| |
| }} |