diff options
Diffstat (limited to 'indra/newview/llmeshreduction.cpp')
-rw-r--r-- | indra/newview/llmeshreduction.cpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/indra/newview/llmeshreduction.cpp b/indra/newview/llmeshreduction.cpp new file mode 100644 index 0000000000..b50b4cf063 --- /dev/null +++ b/indra/newview/llmeshreduction.cpp @@ -0,0 +1,283 @@ +/** + * @file llmeshreduction.cpp + * @brief LLMeshReduction class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llmeshreduction.h" +#include "llgl.h" +#include "llvertexbuffer.h" + +#include "glod/glod.h" + +static BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + + +void create_vertex_buffers_from_model(LLModel* model, std::vector<LLPointer <LLVertexBuffer> >& vertex_buffers) +{ +#if 0 //VECTORIZE THIS ? + vertex_buffers.clear(); + + for (S32 i = 0; i < model->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = model->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = + new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider<LLVector3> vertex_strider; + LLStrider<LLVector3> normal_strider; + LLStrider<LLVector2> tc_strider; + LLStrider<U16> index_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + + vb->getIndexStrider(index_strider); + + // build vertices and normals + for (U32 i = 0; (S32)i < num_vertices; i++) + { + *(vertex_strider++) = vf.mVertices[i].mPosition; + *(tc_strider++) = vf.mVertices[i].mTexCoord; + LLVector3 normal = vf.mVertices[i].mNormal; + normal.normalize(); + *(normal_strider++) = normal; + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + + vertex_buffers.push_back(vb); + } +#endif +} + +void create_glod_object_from_vertex_buffers(S32 object, S32 group, std::vector<LLPointer <LLVertexBuffer> >& vertex_buffers) +{ + glodNewGroup(group); + stop_gloderror(); + glodNewObject(object, group, GLOD_DISCRETE); + stop_gloderror(); + + for (U32 i = 0; i < vertex_buffers.size(); ++i) + { + vertex_buffers[i]->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + U32 num_indices = vertex_buffers[i]->getNumIndices(); + + if (num_indices > 2) + { + glodInsertElements(object, i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, + vertex_buffers[i]->getIndicesPointer(), 0, 0.f); + } + stop_gloderror(); + } + + glodBuildObject(object); + stop_gloderror(); +} + +// extract the GLOD data into vertex buffers +void create_vertex_buffers_from_glod_object(S32 object, S32 group, std::vector<LLPointer <LLVertexBuffer> >& vertex_buffers) +{ + vertex_buffers.clear(); + + GLint patch_count = 0; + glodGetObjectParameteriv(object, GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(object, GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(object, GLOD_PATCH_NAMES, names); + stop_gloderror(); + + for (S32 i = 0; i < patch_count; i++) + { + LLPointer<LLVertexBuffer> buff = + new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glodFillElements(object, names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { + // this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + } + + vertex_buffers.push_back(buff); + } + + glodDeleteObject(object); + stop_gloderror(); + glodDeleteGroup(group); + stop_gloderror(); + + delete [] sizes; + delete [] names; +} + + +LLPointer<LLModel> create_model_from_vertex_buffers(std::vector<LLPointer <LLVertexBuffer> >& vertex_buffers) +{ + // extract the newly reduced mesh + + // create our output model + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + LLPointer<LLModel> out_model = new LLModel(volume_params, 0.f); + + out_model->setNumVolumeFaces(vertex_buffers.size()); + + // build new faces from each vertex buffer + for (GLint i = 0; i < vertex_buffers.size(); ++i) + { + LLStrider<LLVector3> pos; + LLStrider<LLVector3> norm; + LLStrider<LLVector2> tc; + LLStrider<U16> index; + + vertex_buffers[i]->getVertexStrider(pos); + vertex_buffers[i]->getNormalStrider(norm); + vertex_buffers[i]->getTexCoord0Strider(tc); + vertex_buffers[i]->getIndexStrider(index); + + out_model->setVolumeFaceData(i, pos, norm, tc, index, + vertex_buffers[i]->getNumVerts(), vertex_buffers[i]->getNumIndices()); + } + + return out_model; +} + + + +LLMeshReduction::LLMeshReduction() +{ + mCounter = 1; + + glodInit(); +} + +LLMeshReduction::~LLMeshReduction() +{ + glodShutdown(); +} + + +LLPointer<LLModel> LLMeshReduction::reduce(LLModel* in_model, F32 limit, S32 mode) +{ + LLVertexBuffer::unbind(); + + // create vertex buffers from model + std::vector<LLPointer<LLVertexBuffer> > in_vertex_buffers; + create_vertex_buffers_from_model(in_model, in_vertex_buffers); + + // create glod object from vertex buffers + stop_gloderror(); + S32 glod_group = mCounter++; + S32 glod_object = mCounter++; + create_glod_object_from_vertex_buffers(glod_object, glod_group, in_vertex_buffers); + + + // set reduction parameters + stop_gloderror(); + + if (mode == TRIANGLE_BUDGET) + { + // triangle budget mode + glodGroupParameteri(glod_group, GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + glodGroupParameteri(glod_group, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + S32 triangle_count = (S32)limit; + glodGroupParameteri(glod_group, GLOD_MAX_TRIANGLES, triangle_count); + stop_gloderror(); + } + else if (mode == ERROR_THRESHOLD) + { + // error threshold mode + glodGroupParameteri(glod_group, GLOD_ADAPT_MODE, GLOD_ERROR_THRESHOLD); + glodGroupParameteri(glod_group, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + F32 error_threshold = limit; + glodGroupParameterf(glod_group, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, error_threshold); + stop_gloderror(); + } + + else + { + // not a legal mode + return NULL; + } + + + // do the reduction + glodAdaptGroup(glod_group); + stop_gloderror(); + + // convert glod object into vertex buffers + std::vector<LLPointer<LLVertexBuffer> > out_vertex_buffers; + create_vertex_buffers_from_glod_object(glod_object, glod_group, out_vertex_buffers); + + // convert vertex buffers into a model + LLPointer<LLModel> out_model = create_model_from_vertex_buffers(out_vertex_buffers); + + + return out_model; +} + + |