123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- /**
- * @file llviewerjointmesh.cpp
- * @brief Implementation of LLViewerJointMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llviewerjointmesh.h"
- #include "imageids.h"
- #include "llfasttimer.h"
- #include "llgl.h"
- #include "llrender.h"
- #include "lldrawable.h"
- #include "lldrawpoolavatar.h"
- #include "lldrawpoolbump.h"
- #include "lldynamictexture.h"
- #include "llface.h"
- #include "llpipeline.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewershadermgr.h"
- #include "llviewertexlayer.h"
- #include "llviewertexturelist.h"
- #include "llvoavatar.h"
- constexpr U32 JOINT_MESH_RENDER_MASK = LLVertexBuffer::MAP_VERTEX |
- LLVertexBuffer::MAP_NORMAL |
- LLVertexBuffer::MAP_TEXCOORD0;
- LLViewerJointMesh::LLViewerJointMesh()
- : LLAvatarJointMesh()
- {
- }
- constexpr S32 NUM_AXES = 3;
- // Register layout
- // rotation X 0-n
- // rotation Y 0-n
- // rotation Z 0-n
- // pivot parent 0-n -- child = n+1
- static LLMatrix4 gJointMatUnaligned[32];
- static LLMatrix4a gJointMatAligned[32];
- static LLMatrix3 gJointRotUnaligned[32];
- static LLVector4 gJointPivot[32];
- void LLViewerJointMesh::uploadJointMatrices()
- {
- LLPolyMesh* reference_mesh = mMesh->getReferenceMesh();
- if (!reference_mesh) // Paranoia
- {
- llwarns << "NULL mMesh !" << llendl;
- return;
- }
- S32 joint_count = reference_mesh->mJointRenderData.size();
- LLDrawPool* poolp = mFace ? mFace->getPool() : NULL;
- bool hardware_skinning = poolp && poolp->getShaderLevel() > 0;
- // Calculate joint matrices
- for (S32 joint_num = 0; joint_num < joint_count; ++joint_num)
- {
- LLMatrix4 joint_mat =
- *reference_mesh->mJointRenderData[joint_num]->mWorldMatrix;
- if (hardware_skinning)
- {
- joint_mat *= LLDrawPoolAvatar::getModelView();
- }
- gJointMatUnaligned[joint_num] = joint_mat;
- gJointRotUnaligned[joint_num] = joint_mat.getMat3();
- }
- // Upload joint pivots
- bool last_pivot_uploaded = false;
- S32 j = 0;
- for (S32 joint_num = 0; joint_num < joint_count; ++joint_num)
- {
- LLSkinJoint* sj =
- reference_mesh->mJointRenderData[joint_num]->mSkinJoint;
- if (sj)
- {
- if (!last_pivot_uploaded)
- {
- LLVector4 parent_pivot(sj->mRootToParentJointSkinOffset);
- parent_pivot.mV[VW] = 0.f;
- gJointPivot[j++] = parent_pivot;
- }
- LLVector4 child_pivot(sj->mRootToJointSkinOffset);
- child_pivot.mV[VW] = 0.f;
- gJointPivot[j++] = child_pivot;
- last_pivot_uploaded = true;
- }
- else
- {
- last_pivot_uploaded = false;
- }
- }
- // Add pivot point into transform
- for (S32 i = 0; i < j; ++i)
- {
- LLVector3 pivot;
- pivot = LLVector3(gJointPivot[i]);
- pivot = pivot * gJointRotUnaligned[i];
- gJointMatUnaligned[i].translate(pivot);
- }
- // Upload matrices
- if (hardware_skinning)
- {
- F32 mat[45 * 4];
- memset(mat, 0, sizeof(F32) * 45 * 4);
- for (S32 joint_num = 0; joint_num < joint_count; ++joint_num)
- {
- gJointMatUnaligned[joint_num].transpose();
- for (S32 axis = 0; axis < NUM_AXES; ++axis)
- {
- F32* vector = gJointMatUnaligned[joint_num].mMatrix[axis];
- U32 offset = LL_CHARACTER_MAX_JOINTS_PER_MESH * axis +
- joint_num;
- memcpy(mat + offset * 4, vector, sizeof(F32) * 4);
- }
- }
- if (LLGLSLShader::sCurBoundShaderPtr)
- {
- LLGLSLShader::sCurBoundShaderPtr->uniform4fv(LLShaderMgr::AVATAR_MATRIX,
- 45, mat);
- }
- stop_glerror();
- }
- else
- {
- // Load gJointMatUnaligned into gJointMatAligned
- for (S32 joint_num = 0; joint_num < joint_count; ++joint_num)
- {
- gJointMatAligned[joint_num].loadu(gJointMatUnaligned[joint_num]);
- }
- }
- }
- // Used by the qsort function to sort the index array
- int compare_int(const void* a, const void* b)
- {
- if (*(U32*)a < *(U32*)b)
- {
- return -1;
- }
- else if (*(U32*)a > *(U32*)b)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- //virtual
- U32 LLViewerJointMesh::drawShape(bool first_pass, bool is_dummy)
- {
- if (!mValid || !mMesh || !mFace || !mVisible ||
- !mFace->getVertexBuffer() || mMesh->getNumFaces() == 0 ||
- !LLGLSLShader::sCurBoundShaderPtr)
- {
- return 0;
- }
- LLTexUnit* unit;
- if (LLDrawPoolAvatar::sDiffuseChannel > -1)
- {
- unit = gGL.getTexUnit(LLDrawPoolAvatar::sDiffuseChannel);
- }
- else
- {
- unit = NULL;
- }
- //----------------------------------------------------------------
- // Setup current color
- //----------------------------------------------------------------
- if (is_dummy)
- {
- gGL.diffuseColor4fv(LLVOAvatar::getDummyColor().mV);
- }
- else
- {
- gGL.diffuseColor4fv(mColor.mV);
- }
- LLGLSSpecular specular(LLColor4(1.f, 1.f, 1.f, 1.f), 0.f);
- //----------------------------------------------------------------
- // Setup current texture
- //----------------------------------------------------------------
- llassert(!(mTexture.notNull() && mLayerSet)); // mutually exclusive
- LLViewerTexLayerSet* layerset = NULL;
- if (mLayerSet)
- {
- layerset = mLayerSet->asViewerTexLayerSet();
- }
- if (mTestImageName)
- {
- if (unit)
- {
- unit->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
- }
- if (mIsTransparent)
- {
- gGL.diffuseColor4f(1.f, 1.f, 1.f, 1.f);
- }
- else
- {
- gGL.diffuseColor4f(0.7f, 0.6f, 0.3f, 1.f);
- }
- }
- else if (!is_dummy && layerset)
- {
- if (layerset->hasComposite())
- {
- if (unit)
- {
- unit->bind(layerset->getViewerComposite());
- }
- }
- else
- {
- // This warning will always trigger if you have hacked the avatar
- // to show as incomplete. Ignore the warning if this is the case.
- static LLCachedControl<bool> render_unloaded_avatar(gSavedSettings,
- "RenderUnloadedAvatar");
- if (!render_unloaded_avatar)
- {
- static std::set<S32> mesh_ids;
- if (mesh_ids.count(mMeshID) == 0)
- {
- mesh_ids.emplace(mMeshID);
- llwarns << "Layerset without composite for MeshID = "
- << mMeshID << llendl;
- }
- }
- if (LLViewerFetchedTexture::sDefaultImagep && unit)
- {
- unit->bind(LLViewerFetchedTexture::sDefaultImagep);
- }
- }
- }
- else if (!is_dummy && mTexture.notNull())
- {
- if (unit)
- {
- unit->bind(mTexture);
- }
- }
- else if (LLViewerFetchedTexture::sDefaultImagep && unit)
- {
- unit->bind(LLViewerFetchedTexture::sDefaultImagep);
- }
- U32 mask = JOINT_MESH_RENDER_MASK;
- U32 start = mMesh->mFaceVertexOffset;
- U32 end = start + mMesh->mFaceVertexCount - 1;
- U32 count = mMesh->mFaceIndexCount;
- U32 offset = mMesh->mFaceIndexOffset;
- LLVertexBuffer* buff = mFace->getVertexBuffer();
- if (mMesh->hasWeights())
- {
- if (mFace->getPool()->getShaderLevel() > 0)
- {
- if (first_pass)
- {
- uploadJointMatrices();
- }
- mask |= LLVertexBuffer::MAP_WEIGHT;
- if (mFace->getPool()->getShaderLevel() > 1)
- {
- mask |= LLVertexBuffer::MAP_CLOTHWEIGHT;
- }
- }
- buff->setBuffer(mask);
- buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
- }
- else
- {
- gGL.pushMatrix();
- LLMatrix4 joint_to_world = getWorldMatrix();
- gGL.multMatrix(joint_to_world.getF32ptr());
- buff->setBuffer(mask);
- buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
- gGL.popMatrix();
- }
- gPipeline.addTrianglesDrawn(count);
- stop_glerror();
- return count;
- }
- void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices,
- F32 pixel_area)
- {
- // Bump num_vertices to next multiple of 4
- num_vertices = (num_vertices + 0x3) & ~0x3;
- // Do a pre-alloc pass to determine sizes of data.
- if (mMesh && mValid)
- {
- mMesh->mFaceVertexOffset = num_vertices;
- mMesh->mFaceVertexCount = mMesh->getNumVertices();
- mMesh->mFaceIndexOffset = num_indices;
- mMesh->mFaceIndexCount = mMesh->getSharedData()->mNumTriangleIndices;
- mMesh->getReferenceMesh()->mCurVertexCount = mMesh->mFaceVertexCount;
- num_vertices += mMesh->getNumVertices();
- num_indices += mMesh->mFaceIndexCount;
- }
- }
- // IF THIS FUNCTION BREAKS, SEE LLPOLYMESH CONSTRUCTOR AND CHECK ALIGNMENT OF
- // INPUT ARRAYS
- void LLViewerJointMesh::updateFaceData(LLFace* face, F32 pixel_area,
- bool damp_wind, bool terse_update)
- {
- mFace = face;
- if (!mFace->getVertexBuffer())
- {
- return;
- }
- LLDrawPool* poolp = mFace->getPool();
- bool hardware_skinning = poolp && poolp->getShaderLevel() > 0;
- if (!hardware_skinning && terse_update)
- {
- // No need to do terse updates if we're doing software vertex skinning
- // since mMesh is being copied into mVertexBuffer every frame
- return;
- }
- LL_FAST_TIMER(FTM_AVATAR_FACE);
- LLStrider<LLVector3> verticesp;
- LLStrider<LLVector3> normalsp;
- LLStrider<LLVector2> tex_coordsp;
- LLStrider<F32> vertex_weightsp;
- LLStrider<LLVector4a> clothing_weightsp;
- LLStrider<U16> indicesp;
- // Copy data into the faces from the polymesh data.
- if (mMesh && mValid)
- {
- const U32 num_verts = mMesh->getNumVertices();
- if (num_verts)
- {
- face->getGeometryAvatar(verticesp, normalsp, tex_coordsp,
- vertex_weightsp, clothing_weightsp);
- if (!face->getVertexBuffer()->getIndexStrider(indicesp))
- {
- return;
- }
- verticesp += mMesh->mFaceVertexOffset;
- normalsp += mMesh->mFaceVertexOffset;
- F32* v = (F32*)verticesp.get();
- F32* n = (F32*)normalsp.get();
- U32 words = num_verts * 4;
- LLVector4a::memcpyNonAliased16(v, (F32*)mMesh->getCoords(),
- words * sizeof(F32));
- LLVector4a::memcpyNonAliased16(n, (F32*)mMesh->getNormals(),
- words * sizeof(F32));
- if (!terse_update)
- {
- vertex_weightsp += mMesh->mFaceVertexOffset;
- clothing_weightsp += mMesh->mFaceVertexOffset;
- tex_coordsp += mMesh->mFaceVertexOffset;
- F32* tc = (F32*)tex_coordsp.get();
- F32* vw = (F32*)vertex_weightsp.get();
- F32* cw = (F32*)clothing_weightsp.get();
- S32 tc_size = (num_verts * 2 * sizeof(F32) + 0xF) & ~0xF;
- LLVector4a::memcpyNonAliased16(tc, (F32*)mMesh->getTexCoords(),
- tc_size);
- S32 vw_size = (num_verts * sizeof(F32) + 0xF) & ~0xF;
- LLVector4a::memcpyNonAliased16(vw, (F32*)mMesh->getWeights(),
- vw_size);
- LLVector4a::memcpyNonAliased16(cw,
- (F32*)mMesh->getClothingWeights(),
- num_verts * 4 * sizeof(F32));
- }
- const U32 idx_count = mMesh->getNumFaces() * 3;
- indicesp += mMesh->mFaceIndexOffset;
- U16* __restrict idx = indicesp.get();
- S32* __restrict src_idx = (S32*)mMesh->getFaces();
- const S32 offset = (S32)mMesh->mFaceVertexOffset;
- for (U32 i = 0; i < idx_count; ++i)
- {
- *(idx++) = *(src_idx++) + offset;
- }
- }
- }
- }
- bool LLViewerJointMesh::updateLOD(F32 pixel_area, bool activate)
- {
- bool valid = mValid;
- setValid(activate, true);
- return valid != activate;
- }
- //static
- void LLViewerJointMesh::updateGeometry(LLFace* mFace, LLPolyMesh* mMesh)
- {
- LLStrider<LLVector3> o_vertices;
- LLStrider<LLVector3> o_normals;
- // Get vertex and normal striders
- LLVertexBuffer* buffer = mFace->getVertexBuffer();
- if (!buffer->getVertexStrider(o_vertices, 0) ||
- !buffer->getNormalStrider(o_normals, 0))
- {
- return;
- }
- F32* __restrict vert = o_vertices[0].mV;
- F32* __restrict norm = o_normals[0].mV;
- const F32* __restrict weights = mMesh->getWeights();
- const LLVector4a* __restrict coords = (LLVector4a*)mMesh->getCoords();
- const LLVector4a* __restrict normals = (LLVector4a*)mMesh->getNormals();
- U32 offset = mMesh->mFaceVertexOffset * 4;
- vert += offset;
- norm += offset;
- for (U32 index = 0, count = mMesh->getNumVertices(); index < count;
- ++index)
- {
- // Equivalent to joint = floorf(weights[index]);
- S32 joint = _mm_cvtt_ss2si(_mm_load_ss(weights+index));
- F32 w = weights[index] - joint;
- LLMatrix4a gBlendMat;
- if (w != 0.f)
- {
- // Blend between matrices and apply
- gBlendMat.setLerp(gJointMatAligned[joint + 0],
- gJointMatAligned[joint + 1], w);
- LLVector4a res;
- gBlendMat.affineTransform(coords[index], res);
- res.store4a(vert + index * 4);
- gBlendMat.rotate(normals[index], res);
- res.store4a(norm + index * 4);
- }
- else
- { // No lerp required in this case.
- LLVector4a res;
- gJointMatAligned[joint].affineTransform(coords[index], res);
- res.store4a(vert + index * 4);
- gJointMatAligned[joint].rotate(normals[index], res);
- res.store4a(norm + index * 4);
- }
- }
- buffer->unmapBuffer();
- }
- void LLViewerJointMesh::updateJointGeometry()
- {
- if (!(mValid && mMesh && mFace &&
- mMesh->hasWeights() && mFace->getVertexBuffer() &&
- gViewerShaderMgrp->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) == 0))
- {
- return;
- }
- uploadJointMatrices();
- updateGeometry(mFace, mMesh);
- }
- void LLViewerJointMesh::dump()
- {
- if (mValid)
- {
- llinfos << "Usable LOD: " << getName() << llendl;
- }
- }
|