int GeoPatchContext::getIndices(std::vector<unsigned short> &pl, const unsigned int edge_hi_flags) { // calculate how many tri's there are int tri_count = (VBO_COUNT_MID_IDX() / 3); for( int i=0; i<4; ++i ) { if( edge_hi_flags & (1 << i) ) { tri_count += (VBO_COUNT_HI_EDGE() / 3); } else { tri_count += (VBO_COUNT_LO_EDGE() / 3); } } // pre-allocate enough space pl.reserve(tri_count); // add all of the middle indices for(int i=0; i<VBO_COUNT_MID_IDX(); ++i) { pl.push_back(midIndices[i]); } // selectively add the HI or LO detail indices for (int i=0; i<4; i++) { if( edge_hi_flags & (1 << i) ) { for(int j=0; j<VBO_COUNT_HI_EDGE(); ++j) { pl.push_back(hiEdgeIndices[i][j]); } } else { for(int j=0; j<VBO_COUNT_LO_EDGE(); ++j) { pl.push_back(loEdgeIndices[i][j]); } } } return tri_count; }
//static void GeoPatchContext::GenerateIndices() { if (prevEdgeLen == edgeLen) return; // Uint32 *idx; std::vector<Uint32> pl_short; int tri_count = 0; { // calculate how many tri's there are tri_count = (VBO_COUNT_MID_IDX() / 3); for (int i = 0; i<4; ++i) { tri_count += (VBO_COUNT_HI_EDGE() / 3); } // pre-allocate enough space pl_short.reserve(tri_count); // add all of the middle indices for (int i = 0; i<VBO_COUNT_MID_IDX(); ++i) { pl_short.push_back(0); } // add the HI detail indices for (int i = 0; i<4; i++) { for (int j = 0; j<VBO_COUNT_HI_EDGE(); ++j) { pl_short.push_back(0); } } } // want vtx indices for tris idx = &pl_short[0]; for (int x = 0; x<edgeLen - 1; x++) { for (int y = 0; y<edgeLen - 1; y++) { // 1st tri idx[0] = x + edgeLen*y; idx[1] = x + 1 + edgeLen*y; idx[2] = x + edgeLen*(y + 1); idx += 3; // 2nd tri idx[0] = x + 1 + edgeLen*y; idx[1] = x + 1 + edgeLen*(y + 1); idx[2] = x + edgeLen*(y + 1); idx += 3; } } // populate the N indices lists from the arrays built during InitTerrainIndices() // iterate over each index list and optimize it { VertexCacheOptimizerUInt vco; VertexCacheOptimizerUInt::Result res = vco.Optimize(&pl_short[0], tri_count); assert(0 == res); //create buffer & copy indices.Reset(Pi::renderer->CreateIndexBuffer(pl_short.size(), Graphics::BUFFER_USAGE_STATIC)); Uint32* idxPtr = indices->Map(Graphics::BUFFER_MAP_WRITE); for (Uint32 j = 0; j < pl_short.size(); j++) { idxPtr[j] = pl_short[j]; } indices->Unmap(); } prevEdgeLen = edgeLen; }
void GeoPatchContext::Init() { frac = 1.0 / double(edgeLen-1); vbotemp = new VBOVertex[NUMVERTICES()]; unsigned short *idx; midIndices.reset(new unsigned short[VBO_COUNT_MID_IDX()]); for (int i=0; i<4; i++) { loEdgeIndices[i].reset(new unsigned short[VBO_COUNT_LO_EDGE()]); hiEdgeIndices[i].reset(new unsigned short[VBO_COUNT_HI_EDGE()]); } /* also want vtx indices for tris not touching edge of patch */ idx = midIndices.get(); for (int x=1; x<edgeLen-2; x++) { for (int y=1; y<edgeLen-2; y++) { idx[0] = x + edgeLen*y; idx[1] = x+1 + edgeLen*y; idx[2] = x + edgeLen*(y+1); idx+=3; idx[0] = x+1 + edgeLen*y; idx[1] = x+1 + edgeLen*(y+1); idx[2] = x + edgeLen*(y+1); idx+=3; } } { for (int x=1; x<edgeLen-3; x+=2) { // razor teeth near edge 0 idx[0] = x + edgeLen; idx[1] = x+1; idx[2] = x+1 + edgeLen; idx+=3; idx[0] = x+1; idx[1] = x+2 + edgeLen; idx[2] = x+1 + edgeLen; idx+=3; } for (int x=1; x<edgeLen-3; x+=2) { // near edge 2 idx[0] = x + edgeLen*(edgeLen-2); idx[1] = x+1 + edgeLen*(edgeLen-2); idx[2] = x+1 + edgeLen*(edgeLen-1); idx+=3; idx[0] = x+1 + edgeLen*(edgeLen-2); idx[1] = x+2 + edgeLen*(edgeLen-2); idx[2] = x+1 + edgeLen*(edgeLen-1); idx+=3; } for (int y=1; y<edgeLen-3; y+=2) { // near edge 1 idx[0] = edgeLen-2 + y*edgeLen; idx[1] = edgeLen-1 + (y+1)*edgeLen; idx[2] = edgeLen-2 + (y+1)*edgeLen; idx+=3; idx[0] = edgeLen-2 + (y+1)*edgeLen; idx[1] = edgeLen-1 + (y+1)*edgeLen; idx[2] = edgeLen-2 + (y+2)*edgeLen; idx+=3; } for (int y=1; y<edgeLen-3; y+=2) { // near edge 3 idx[0] = 1 + y*edgeLen; idx[1] = 1 + (y+1)*edgeLen; idx[2] = (y+1)*edgeLen; idx+=3; idx[0] = 1 + (y+1)*edgeLen; idx[1] = 1 + (y+2)*edgeLen; idx[2] = (y+1)*edgeLen; idx+=3; } } // full detail edge triangles { idx = hiEdgeIndices[0].get(); for (int x=0; x<edgeLen-1; x+=2) { idx[0] = x; idx[1] = x+1; idx[2] = x+1 + edgeLen; idx+=3; idx[0] = x+1; idx[1] = x+2; idx[2] = x+1 + edgeLen; idx+=3; } idx = hiEdgeIndices[1].get(); for (int y=0; y<edgeLen-1; y+=2) { idx[0] = edgeLen-1 + y*edgeLen; idx[1] = edgeLen-1 + (y+1)*edgeLen; idx[2] = edgeLen-2 + (y+1)*edgeLen; idx+=3; idx[0] = edgeLen-1 + (y+1)*edgeLen; idx[1] = edgeLen-1 + (y+2)*edgeLen; idx[2] = edgeLen-2 + (y+1)*edgeLen; idx+=3; } idx = hiEdgeIndices[2].get(); for (int x=0; x<edgeLen-1; x+=2) { idx[0] = x + (edgeLen-1)*edgeLen; idx[1] = x+1 + (edgeLen-2)*edgeLen; idx[2] = x+1 + (edgeLen-1)*edgeLen; idx+=3; idx[0] = x+1 + (edgeLen-2)*edgeLen; idx[1] = x+2 + (edgeLen-1)*edgeLen; idx[2] = x+1 + (edgeLen-1)*edgeLen; idx+=3; } idx = hiEdgeIndices[3].get(); for (int y=0; y<edgeLen-1; y+=2) { idx[0] = y*edgeLen; idx[1] = 1 + (y+1)*edgeLen; idx[2] = (y+1)*edgeLen; idx+=3; idx[0] = (y+1)*edgeLen; idx[1] = 1 + (y+1)*edgeLen; idx[2] = (y+2)*edgeLen; idx+=3; } } // these edge indices are for patches with no // neighbour of equal or greater detail -- they reduce // their edge complexity by 1 division { idx = loEdgeIndices[0].get(); for (int x=0; x<edgeLen-2; x+=2) { idx[0] = x; idx[1] = x+2; idx[2] = x+1+edgeLen; idx += 3; } idx = loEdgeIndices[1].get(); for (int y=0; y<edgeLen-2; y+=2) { idx[0] = (edgeLen-1) + y*edgeLen; idx[1] = (edgeLen-1) + (y+2)*edgeLen; idx[2] = (edgeLen-2) + (y+1)*edgeLen; idx += 3; } idx = loEdgeIndices[2].get(); for (int x=0; x<edgeLen-2; x+=2) { idx[0] = x+edgeLen*(edgeLen-1); idx[2] = x+2+edgeLen*(edgeLen-1); idx[1] = x+1+edgeLen*(edgeLen-2); idx += 3; } idx = loEdgeIndices[3].get(); for (int y=0; y<edgeLen-2; y+=2) { idx[0] = y*edgeLen; idx[2] = (y+2)*edgeLen; idx[1] = 1 + (y+1)*edgeLen; idx += 3; } } // these will hold the optimised indices std::vector<unsigned short> pl_short[NUM_INDEX_LISTS]; // populate the N indices lists from the arrays built during InitTerrainIndices() for( int i=0; i<NUM_INDEX_LISTS; ++i ) { const unsigned int edge_hi_flags = i; indices_tri_counts[i] = getIndices(pl_short[i], edge_hi_flags); } // iterate over each index list and optimize it for( int i=0; i<NUM_INDEX_LISTS; ++i ) { int tri_count = indices_tri_counts[i]; VertexCacheOptimizerUShort vco; VertexCacheOptimizerUShort::Result res = vco.Optimize(&pl_short[i][0], tri_count); assert(0 == res); } // everything should be hunky-dory for setting up as OpenGL index buffers now. for( int i=0; i<NUM_INDEX_LISTS; ++i ) { glGenBuffersARB(1, &indices_list[i]); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, indices_list[i]); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*indices_tri_counts[i]*3, &(pl_short[i][0]), GL_STATIC_DRAW); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); } // default it to the last entry which uses the hi-res borders indices_vbo = indices_list[NUM_INDEX_LISTS-1]; indices_tri_count = indices_tri_counts[NUM_INDEX_LISTS-1]; if (midIndices) { midIndices.reset(); for (int i=0; i<4; i++) { loEdgeIndices[i].reset(); hiEdgeIndices[i].reset(); } } }