LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b) { // Operate "to the left" on row-vector a return LLVector4(a.mV[VX] * b.mMatrix[VX][VX] + a.mV[VY] * b.mMatrix[VY][VX] + a.mV[VZ] * b.mMatrix[VZ][VX] + a.mV[VW] * b.mMatrix[VW][VX], a.mV[VX] * b.mMatrix[VX][VY] + a.mV[VY] * b.mMatrix[VY][VY] + a.mV[VZ] * b.mMatrix[VZ][VY] + a.mV[VW] * b.mMatrix[VW][VY], a.mV[VX] * b.mMatrix[VX][VZ] + a.mV[VY] * b.mMatrix[VY][VZ] + a.mV[VZ] * b.mMatrix[VZ][VZ] + a.mV[VW] * b.mMatrix[VW][VZ], a.mV[VX] * b.mMatrix[VX][VW] + a.mV[VY] * b.mMatrix[VY][VW] + a.mV[VZ] * b.mMatrix[VZ][VW] + a.mV[VW] * b.mMatrix[VW][VW]); }
void LLWLParamManager::propagateParameters(void) { LLFastTimer ftm(FTM_UPDATE_WLPARAM); LLVector4 sunDir; LLVector4 moonDir; // set the sun direction from SunAngle and EastAngle F32 sinTheta = sin(mCurParams.getEastAngle()); F32 cosTheta = cos(mCurParams.getEastAngle()); F32 sinPhi = sin(mCurParams.getSunAngle()); F32 cosPhi = cos(mCurParams.getSunAngle()); sunDir.mV[0] = -sinTheta * cosPhi; sunDir.mV[1] = sinPhi; sunDir.mV[2] = cosTheta * cosPhi; sunDir.mV[3] = 0; moonDir = -sunDir; // is the normal from the sun or the moon if(sunDir.mV[1] >= 0) { mLightDir = sunDir; } else if(sunDir.mV[1] < 0 && sunDir.mV[1] > LLSky::NIGHTTIME_ELEVATION_COS) { // clamp v1 to 0 so sun never points up and causes weirdness on some machines LLVector3 vec(sunDir.mV[0], sunDir.mV[1], sunDir.mV[2]); vec.mV[1] = 0; vec.normVec(); mLightDir = LLVector4(vec, 0.f); } else { mLightDir = moonDir; } // calculate the clamp lightnorm for sky (to prevent ugly banding in sky // when haze goes below the horizon mClampedLightDir = sunDir; if (mClampedLightDir.mV[1] < -0.1f) { mClampedLightDir.mV[1] = -0.1f; } mCurParams.set("lightnorm", mLightDir); // bind the variables for all shaders only if we're using WindLight std::vector<LLGLSLShader*>::iterator shaders_iter=mShaderList.begin(); for(; shaders_iter != mShaderList.end(); ++shaders_iter) { (*shaders_iter)->mUniformsDirty = TRUE; } // get the cfr version of the sun's direction LLVector3 cfrSunDir(sunDir.mV[2], sunDir.mV[0], sunDir.mV[1]); // set direction and don't allow overriding gSky.setSunDirection(cfrSunDir, LLVector3(0,0,0)); gSky.setOverrideSun(TRUE); }
//----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) { return; } mLastSex = avatar_sex; // Check for NaN condition (NaN is detected if a variable doesn't equal itself. if (mCurWeight != mCurWeight) { mCurWeight = 0.0; } if (mLastWeight != mLastWeight) { mLastWeight = mCurWeight+.001; } // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight mLastWeight += delta_weight; if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); LLVector4 *coords = mMesh->getWritableCoords(); LLVector3 *scaled_normals = mMesh->getScaledNormals(); LLVector4 *normals = mMesh->getWritableNormals(); LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); LLVector3 *binormals = mMesh->getWritableBinormals(); LLVector4 *clothing_weights = mMesh->getWritableClothingWeights(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++) { S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph]; F32 maskWeight = 1.f; if (maskWeightArray) { maskWeight = maskWeightArray[vert_index_morph]; } coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight); if (getInfo()->mIsClothingMorph && clothing_weights) { LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight; LLVector4* clothing_weight = &clothing_weights[vert_index_mesh]; clothing_weight->mV[VX] += clothing_offset.mV[VX]; clothing_weight->mV[VY] += clothing_offset.mV[VY]; clothing_weight->mV[VZ] += clothing_offset.mV[VZ]; clothing_weight->mV[VW] = maskWeight; } // calculate new normals based on half angles scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; LLVector3 normalized_normal = scaled_normals[vert_index_mesh]; normalized_normal.normVec(); normals[vert_index_mesh] = LLVector4(normalized_normal); // calculate new binormals scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; LLVector3 tangent = scaled_binormals[vert_index_mesh] % normalized_normal; LLVector3 normalized_binormal = normalized_normal % tangent; normalized_binormal.normVec(); binormals[vert_index_mesh] = normalized_binormal; tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; } // now apply volume changes for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) { LLPolyVolumeMorph* volume_morph = &(*iter); LLVector3 scale_delta = volume_morph->mScale * delta_weight; LLVector3 pos_delta = volume_morph->mPos * delta_weight; volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); } } if (mNext) { mNext->apply(avatar_sex); } }
void LLWLParamManager::propagateParameters(void) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); LLVector4 sunDir; LLVector4 moonDir; // set the sun direction from SunAngle and EastAngle F32 sinTheta = sin(mCurParams.getEastAngle()); F32 cosTheta = cos(mCurParams.getEastAngle()); F32 sinPhi = sin(mCurParams.getSunAngle()); F32 cosPhi = cos(mCurParams.getSunAngle()); sunDir.mV[0] = -sinTheta * cosPhi; sunDir.mV[1] = sinPhi; sunDir.mV[2] = cosTheta * cosPhi; sunDir.mV[3] = 0; moonDir = -sunDir; // is the normal from the sun or the moon if(sunDir.mV[1] >= 0) { mLightDir = sunDir; } else if(sunDir.mV[1] < 0 && sunDir.mV[1] > NIGHTTIME_ELEVATION_COS) { // clamp v1 to 0 so sun never points up and causes weirdness on some machines LLVector3 vec(sunDir.mV[0], sunDir.mV[1], sunDir.mV[2]); vec.mV[1] = 0; vec.normVec(); mLightDir = LLVector4(vec, 0.f); } else { mLightDir = moonDir; } // calculate the clamp lightnorm for sky (to prevent ugly banding in sky // when haze goes below the horizon mClampedLightDir = sunDir; if (mClampedLightDir.mV[1] < -0.1f) { mClampedLightDir.mV[1] = -0.1f; } mCurParams.set("lightnorm", mLightDir); // bind the variables for all shaders only if we're using WindLight LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; end_shaders = LLViewerShaderMgr::instance()->endShaders(); for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) { if (shaders_iter->mProgramObject != 0 && (gPipeline.canUseWindLightShaders() || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) { shaders_iter->mUniformsDirty = TRUE; } } // get the cfr version of the sun's direction LLVector3 cfrSunDir(sunDir.mV[2], sunDir.mV[0], sunDir.mV[1]); // set direction and don't allow overriding gSky.setSunDirection(cfrSunDir, LLVector3(0,0,0)); gSky.setOverrideSun(TRUE); }
BOOL QToolAlign::findSelectedManipulator(S32 x, S32 y) { mHighlightedAxis = -1; mHighlightedDirection = 0; LLMatrix4 transform; if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD) { LLVector4 translation(mBBox.getCenterAgent()); transform.initRotTrans(mBBox.getRotation(), translation); LLMatrix4 cfr(OGL_TO_CFR_ROTATION); transform *= cfr; LLMatrix4 window_scale; F32 zoom_level = 2.f * gAgentCamera.mHUDCurZoom; window_scale.initAll(LLVector3(zoom_level / LLViewerCamera::getInstance()->getAspect(), zoom_level, 0.f), LLQuaternion::DEFAULT, LLVector3::zero); transform *= window_scale; } else { transform.initAll(LLVector3(1.f, 1.f, 1.f), mBBox.getRotation(), mBBox.getCenterAgent()); LLMatrix4 projection_matrix = LLViewerCamera::getInstance()->getProjection(); LLMatrix4 model_matrix = LLViewerCamera::getInstance()->getModelview(); transform *= model_matrix; transform *= projection_matrix; } LLRect world_view_rect = gViewerWindow->getWorldViewRectScaled(); F32 half_width = (F32)world_view_rect.getWidth() / 2.f; F32 half_height = (F32)world_view_rect.getHeight() / 2.f; LLVector2 manip2d; LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); LLVector2 delta; LLVector3 bbox_scale = mBBox.getMaxLocal() - mBBox.getMinLocal(); for (S32 axis = VX; axis <= VZ; axis++) { for (F32 direction = -1.0; direction <= 1.0; direction += 2.0) { LLVector3 axis_vector = LLVector3(0,0,0); axis_vector.mV[axis] = direction * bbox_scale.mV[axis] / 2.0; LLVector4 manipulator_center = LLVector4(axis_vector); LLVector4 screen_center = manipulator_center * transform; screen_center /= screen_center.mV[VW]; manip2d.setVec(screen_center.mV[VX] * half_width, screen_center.mV[VY] * half_height); delta = manip2d - mousePos; if (delta.magVecSquared() < MANIPULATOR_SELECT_SIZE * MANIPULATOR_SELECT_SIZE) { mHighlightedAxis = axis; mHighlightedDirection = direction; return TRUE; } } } return FALSE; }
//static void LLDrawPoolBump::beginShiny(bool invisible) { LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) { return; } mShiny = TRUE; sVertexMask = VERTEX_MASK_SHINY; // Second pass: environment map if (!invisible && mVertexShaderLevel > 1) { sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; } if (LLPipeline::sUnderWaterRender) { shader = &gObjectShinyWaterProgram; } else { shader = &gObjectShinyProgram; } LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { if (!invisible && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0 ) { LLMatrix4 mat; mat.initRows(LLVector4(gGLModelView+0), LLVector4(gGLModelView+4), LLVector4(gGLModelView+8), LLVector4(gGLModelView+12)); shader->bind(); LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); if (mVertexShaderLevel > 1) { cube_map->setMatrix(1); // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for // the cube map in the one pass shiny shaders cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); cube_map->enableTexture(cube_channel); cube_map->enableTextureCoords(1); diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } else { cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); diffuse_channel = -1; cube_map->setMatrix(0); cube_map->enable(cube_channel); } gGL.getTexUnit(cube_channel)->bind(cube_map); gGL.getTexUnit(0)->activate(); } else { cube_channel = 0; diffuse_channel = -1; gGL.getTexUnit(0)->disable(); cube_map->enable(0); cube_map->setMatrix(0); gGL.getTexUnit(0)->bind(cube_map); gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_ALPHA); } } }
void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, LLStrider<LLVector3>& normals, LLStrider<LLVector2>& tex_coords, LLStrider<U16>& indices, U16& index_offset, LLMatrix4& matrix, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha) { // // Generates a tree mesh by recursing, generating branches and then a 'leaf' texture. static F32 constant_twist; static F32 width = 0; F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength); F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect); constant_twist = 360.f/branches; if (stop_level >= 0) { if (depth > stop_level) { { llassert(sLODIndexCount[trunk_LOD] > 0); width = scale * length * aspect; LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = width; scale_mat.mMatrix[1][1] = width; scale_mat.mMatrix[2][2] = scale*length; scale_mat *= matrix; glh::matrix4f norm((F32*) scale_mat.mMatrix); LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m); norm_mat.invert(); appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, sLODVertexOffset[trunk_LOD], sLODVertexCount[trunk_LOD], sLODIndexCount[trunk_LOD], sLODIndexOffset[trunk_LOD]); } // Recurse to create more branches for (S32 i=0; i < (S32)branches; i++) { LLMatrix4 trans_mat; trans_mat.setTranslation(0,0,scale*length); trans_mat *= matrix; LLQuaternion rot = LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) * LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) * LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)); LLMatrix4 rot_mat(rot); rot_mat *= trans_mat; genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); } // Recurse to continue trunk if (trunk_depth) { LLMatrix4 trans_mat; trans_mat.setTranslation(0,0,scale*length); trans_mat *= matrix; LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1)); rot_mat *= trans_mat; // rotate a bit around Z when ascending genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); } } else { // // Append leaves as two 90 deg crossed quads with leaf textures // { LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = scale_mat.mMatrix[1][1] = scale_mat.mMatrix[2][2] = scale*mLeafScale; scale_mat *= matrix; glh::matrix4f norm((F32*) scale_mat.mMatrix); LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m); appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0); } } } }
//----------------------------------------------------------------------------- // setMorphFromMesh() //----------------------------------------------------------------------------- BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) { if (!morph) return FALSE; LLVector4 *morph_coords = morph->getWritableCoords(); LLVector4 *morph_normals = morph->getWritableNormals(); LLVector3 *morph_binormals = morph->getWritableBinormals(); LLVector2 *morph_tex_coords = morph->getWritableTexCoords(); // We now have the morph loaded as a mesh. We have to subtract the // base mesh to get the delta morph. LLPolyMesh delta(mMesh, NULL); U32 nverts = delta.getNumVertices(); LLVector4 *delta_coords = delta.getWritableCoords(); LLVector4 *delta_normals = delta.getWritableNormals(); LLVector3 *delta_binormals = delta.getWritableBinormals(); LLVector2 *delta_tex_coords = delta.getWritableTexCoords(); U32 num_significant = 0; U32 vert_index; for( vert_index = 0; vert_index < nverts; vert_index++) { delta_coords[vert_index] = morph_coords[vert_index] - delta_coords[vert_index]; delta_normals[vert_index] = morph_normals[vert_index] - delta_normals[vert_index]; delta_binormals[vert_index] = morph_binormals[vert_index] - delta_binormals[vert_index]; delta_tex_coords[vert_index] = morph_tex_coords[vert_index] - delta_tex_coords[vert_index]; // For the normals and binormals, we really want the deltas // to be perpendicular to the mesh (bi)normals in the plane // that contains both the mesh and morph (bi)normals, such // that the morph (bi)normals form the hypotenuses of right // triangles. Right now, we just compute the difference vector. if (delta_coords[vert_index].length() > SIGNIFICANT_DELTA || delta_normals[vert_index].length() > SIGNIFICANT_DELTA || delta_binormals[vert_index].length() > SIGNIFICANT_DELTA || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA) { num_significant++; } } //------------------------------------------------------------------------- // compute new morph //------------------------------------------------------------------------- // If the morph matches the base mesh, we store one vertex to prevent // zero length vectors. U32 nindices = num_significant; if (num_significant == 0) nindices = 1; LLVector3* new_coords = new LLVector3[nindices]; LLVector3* new_normals = new LLVector3[nindices]; LLVector3* new_binormals = new LLVector3[nindices]; LLVector2* new_tex_coords = new LLVector2[nindices]; U32* new_vertex_indices = new U32[nindices]; // We'll set the distortion directly mTotalDistortion = 0.f; mMaxDistortion = 0.f; mAvgDistortion.zeroVec(); U32 morph_index = 0; for( vert_index = 0; vert_index < nverts; vert_index++) { if (delta_coords[vert_index].length() > SIGNIFICANT_DELTA || delta_normals[vert_index].length() > SIGNIFICANT_DELTA || delta_binormals[vert_index].length() > SIGNIFICANT_DELTA || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA || num_significant == 0) { new_vertex_indices[morph_index] = vert_index; new_coords[morph_index] = LLVector3(delta_coords[vert_index]); new_normals[morph_index] = LLVector3(delta_normals[vert_index]); new_binormals[morph_index] = delta_binormals[vert_index]; new_tex_coords[morph_index] = delta_tex_coords[vert_index]; F32 magnitude = new_coords[morph_index].magVec(); mTotalDistortion += magnitude; mAvgDistortion.mV[VX] += fabs(new_coords[morph_index].mV[VX]); mAvgDistortion.mV[VY] += fabs(new_coords[morph_index].mV[VY]); mAvgDistortion.mV[VZ] += fabs(new_coords[morph_index].mV[VZ]); if (magnitude > mMaxDistortion) { mMaxDistortion = magnitude; } morph_index++; num_significant = 1; } } mAvgDistortion = mAvgDistortion * (1.f/(F32)nindices); mAvgDistortion.normVec(); //------------------------------------------------------------------------- // compute the change in the morph //------------------------------------------------------------------------- // Because meshes are set by continually updating morph weights // there is no easy way to reapply the morphs, so we just compute // the change in this morph and apply that appropriately weighted. for( morph_index = 0; morph_index < mNumIndices; morph_index++) { vert_index = mVertexIndices[morph_index]; delta_coords[vert_index] -= LLVector4(mCoords[morph_index]); delta_normals[vert_index] -= LLVector4(mNormals[morph_index]); delta_binormals[vert_index] -= mBinormals[morph_index]; delta_tex_coords[vert_index] -= mTexCoords[morph_index]; } //------------------------------------------------------------------------- // Update all avatars //------------------------------------------------------------------------- std::vector< LLCharacter* >::iterator avatar_it; for(avatar_it = LLCharacter::sInstances.begin(); avatar_it != LLCharacter::sInstances.end(); ++avatar_it) { LLVOAvatar* avatarp = (LLVOAvatar*)*avatar_it; LLPolyMorphTarget* param = (LLPolyMorphTarget*) avatarp->getVisualParam(mName.c_str()); if (!param) { continue; } F32 weight = param->getLastWeight(); if (weight == 0.0f) { continue; } LLPolyMesh* mesh = avatarp->getMesh(mMesh); if (!mesh) { continue; } // If we have a vertex mask, just remove it. It will be recreated. /*if (param->undoMask(TRUE)) { continue; }*/ LLVector4 *mesh_coords = mesh->getWritableCoords(); LLVector4 *mesh_normals = mesh->getWritableNormals(); LLVector3 *mesh_binormals = mesh->getWritableBinormals(); LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); LLVector3 *mesh_scaled_normals = mesh->getScaledNormals(); LLVector3 *mesh_scaled_binormals = mesh->getScaledBinormals(); for( vert_index = 0; vert_index < nverts; vert_index++) { mesh_coords[vert_index] += delta_coords[vert_index] * weight; mesh_tex_coords[vert_index] += delta_tex_coords[vert_index] * weight; mesh_scaled_normals[vert_index] += LLVector3(delta_normals[vert_index] * weight * NORMAL_SOFTEN_FACTOR); LLVector3 normalized_normal = mesh_scaled_normals[vert_index]; normalized_normal.normVec(); mesh_normals[vert_index] = LLVector4(normalized_normal); mesh_scaled_binormals[vert_index] += delta_binormals[vert_index] * weight * NORMAL_SOFTEN_FACTOR; LLVector3 tangent = mesh_scaled_binormals[vert_index] % normalized_normal; LLVector3 normalized_binormal = normalized_normal % tangent; normalized_binormal.normVec(); mesh_binormals[vert_index] = normalized_binormal; } avatarp->dirtyMesh(); } //------------------------------------------------------------------------- // reallocate vertices //------------------------------------------------------------------------- delete [] mVertexIndices; delete [] mCoords; delete [] mNormals; delete [] mBinormals; delete [] mTexCoords; mVertexIndices = new_vertex_indices; mCoords = new_coords; mNormals = new_normals; mBinormals = new_binormals; mTexCoords = new_tex_coords; mNumIndices = nindices; return TRUE; }
U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha) { U32 ret = 0; // // Draws a tree by recursing, drawing branches and then a 'leaf' texture. // If stop_level = -1, simply draws the whole tree as a billboarded texture // static F32 constant_twist; static F32 width = 0; //F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength); //F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect); F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength); F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect); constant_twist = 360.f/branches; if (!LLPipeline::sReflectionRender && stop_level >= 0) { // // Draw the tree using recursion // if (depth > stop_level) { { llassert(sLODIndexCount[trunk_LOD] > 0); width = scale * length * aspect; LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = width; scale_mat.mMatrix[1][1] = width; scale_mat.mMatrix[2][2] = scale*length; scale_mat *= matrix; glLoadMatrixf((F32*) scale_mat.mMatrix); glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]); gPipeline.addTrianglesDrawn(LEAF_INDICES/3); stop_glerror(); ret += sLODIndexCount[trunk_LOD]; } // Recurse to create more branches for (S32 i=0; i < (S32)branches; i++) { LLMatrix4 trans_mat; trans_mat.setTranslation(0,0,scale*length); trans_mat *= matrix; LLQuaternion rot = LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) * LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) * LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)); LLMatrix4 rot_mat(rot); rot_mat *= trans_mat; ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); } // Recurse to continue trunk if (trunk_depth) { LLMatrix4 trans_mat; trans_mat.setTranslation(0,0,scale*length); trans_mat *= matrix; LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1)); rot_mat *= trans_mat; // rotate a bit around Z when ascending ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); } } else { // // Draw leaves as two 90 deg crossed quads with leaf textures // { LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = scale_mat.mMatrix[1][1] = scale_mat.mMatrix[2][2] = scale*mLeafScale; scale_mat *= matrix; glLoadMatrixf((F32*) scale_mat.mMatrix); glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp); gPipeline.addTrianglesDrawn(LEAF_INDICES/3); stop_glerror(); ret += LEAF_INDICES; } } } else { // // Draw the tree as a single billboard texture // LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = scale_mat.mMatrix[1][1] = scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio; scale_mat *= matrix; glMatrixMode(GL_TEXTURE); glTranslatef(0.0, -0.5, 0.0); glMatrixMode(GL_MODELVIEW); glLoadMatrixf((F32*) scale_mat.mMatrix); glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp); gPipeline.addTrianglesDrawn(LEAF_INDICES/3); stop_glerror(); ret += LEAF_INDICES; glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } return ret; }
void LLWaterParamManager::update(LLViewerCamera * cam) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); // update the shaders and the menu propagateParameters(); // sync menus if they exist if(LLFloaterWater::isOpen()) { LLFloaterWater::instance()->syncMenu(); } stop_glerror(); // only do this if we're dealing with shaders if(gPipeline.canUseVertexShaders()) { //transform water plane to eye space glh::vec3f norm(0.f, 0.f, 1.f); glh::vec3f p(0.f, 0.f, gAgent.getRegion()->getWaterHeight()+0.1f); F32 modelView[16]; for (U32 i = 0; i < 16; i++) { modelView[i] = (F32) gGLModelView[i]; } glh::matrix4f mat(modelView); glh::matrix4f invtrans = mat.inverse().transpose(); glh::vec3f enorm; glh::vec3f ep; invtrans.mult_matrix_vec(norm, enorm); enorm.normalize(); mat.mult_matrix_vec(p, ep); mWaterPlane = LLVector4(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); LLVector3 sunMoonDir; if (gSky.getSunDirection().mV[2] > NIGHTTIME_ELEVATION_COS) { sunMoonDir = gSky.getSunDirection(); } else { sunMoonDir = gSky.getMoonDirection(); } sunMoonDir.normVec(); mWaterFogKS = 1.f/llmax(sunMoonDir.mV[2], WATER_FOG_LIGHT_CLAMP); LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; end_shaders = LLViewerShaderMgr::instance()->endShaders(); for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) { if (shaders_iter->mProgramObject != 0 && shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER) { shaders_iter->mUniformsDirty = TRUE; } } } }
LLVector4 vec3to4(const LLVector3 &vec) { return LLVector4(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); }
LLVector4 LLMatrix4::getUpRow4() const { return LLVector4(mMatrix[VZ][VX], mMatrix[VZ][VY], mMatrix[VZ][VZ], mMatrix[VZ][VW]); }
void LLWaterParamManager::update(LLViewerCamera * cam) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); // update the shaders and the menu propagateParameters(); // sync menus if they exist if(LLFloaterWater::isOpen()) { LLFloaterWater::instance()->syncMenu(); } stop_glerror(); // only do this if we're dealing with shaders if(gPipeline.canUseVertexShaders()) { //transform water plane to eye space glh::vec3f norm(0.f, 0.f, 1.f); glh::vec3f p(0.f, 0.f, gAgent.getRegion()->getWaterHeight()+0.1f); F32 modelView[16]; for (U32 i = 0; i < 16; i++) { modelView[i] = (F32) gGLModelView[i]; } glh::matrix4f mat(modelView); glh::matrix4f invtrans = mat.inverse().transpose(); glh::vec3f enorm; glh::vec3f ep; invtrans.mult_matrix_vec(norm, enorm); enorm.normalize(); mat.mult_matrix_vec(p, ep); mWaterPlane = LLVector4(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); if((mWaterPlane.mV[3] >= 0.f) == LLViewerCamera::getInstance()->cameraUnderWater()) //Sign borkage.. { mWaterPlane.scaleVec(LLVector4(-1.f,-1.f,-1.f,-1.f)); } LLVector3 sunMoonDir; if (gSky.getSunDirection().mV[2] > LLSky::NIGHTTIME_ELEVATION_COS) { sunMoonDir = gSky.getSunDirection(); } else { sunMoonDir = gSky.getMoonDirection(); } sunMoonDir.normVec(); mWaterFogKS = 1.f/llmax(sunMoonDir.mV[2], WATER_FOG_LIGHT_CLAMP); std::vector<LLGLSLShader*>::iterator shaders_iter=mShaderList.begin(); for(; shaders_iter != mShaderList.end(); ++shaders_iter) { (*shaders_iter)->mUniformsDirty = TRUE; } } }
void LLDrawPoolBump::beginFullbrightShiny() { LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; } sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; // Second pass: environment map if (LLPipeline::sUnderWaterRender) { shader = &gObjectFullbrightShinyWaterProgram; } else { if (LLPipeline::sRenderDeferred) { shader = &gDeferredFullbrightShinyProgram; } else { shader = &gObjectFullbrightShinyProgram; } } LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { LLMatrix4 mat; mat.initRows(LLVector4(gGLModelView+0), LLVector4(gGLModelView+4), LLVector4(gGLModelView+8), LLVector4(gGLModelView+12)); shader->bind(); LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); cube_map->setMatrix(1); // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for // the cube map in the one pass shiny shaders gGL.getTexUnit(1)->disable(); cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); cube_map->enableTexture(cube_channel); cube_map->enableTextureCoords(1); diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gGL.getTexUnit(cube_channel)->bind(cube_map); gGL.getTexUnit(0)->activate(); } if (mVertexShaderLevel > 1) { //indexed texture rendering, channel 0 is always diffuse diffuse_channel = 0; } mShiny = TRUE; }
void LLVOTree::updateMesh() { LLMatrix4 matrix; // Translate to tree base HACK - adjustment in Z plants tree underground const LLVector3 &pos_agent = getPositionAgent(); //glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); LLMatrix4 trans_mat; trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); trans_mat *= matrix; // Rotate to tree position and bend for current trunk/wind // Note that trunk stiffness controls the amount of bend at the trunk as // opposed to the crown of the tree // const F32 TRUNK_STIFF = 22.f; LLQuaternion rot = LLQuaternion(mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(mTrunkBend.mV[VX], mTrunkBend.mV[VY], 0)) * LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) * getRotation(); LLMatrix4 rot_mat(rot); rot_mat *= trans_mat; F32 radius = getScale().magVec()*0.05f; LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = scale_mat.mMatrix[1][1] = scale_mat.mMatrix[2][2] = radius; scale_mat *= rot_mat; // const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f; // const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f; F32 droop = mDroop + 25.f*(1.f - mTrunkBend.magVec()); S32 stop_depth = 0; F32 alpha = 1.0; U32 vert_count = 0; U32 index_count = 0; calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches); LLFace* facep = mDrawable->getFace(0); facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); facep->mVertexBuffer->allocateBuffer(vert_count, index_count, TRUE); LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; LLStrider<U16> indices; U16 idx_offset = 0; facep->mVertexBuffer->getVertexStrider(vertices); facep->mVertexBuffer->getNormalStrider(normals); facep->mVertexBuffer->getTexCoord0Strider(tex_coords); facep->mVertexBuffer->getIndexStrider(indices); genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); mReferenceBuffer->setBuffer(0); facep->mVertexBuffer->setBuffer(0); }
void LLDrawPoolTree::renderTree(BOOL selecting) { LLGLState normalize(GL_NORMALIZE, TRUE); // Bind the texture for this tree. gGL.getTexUnit(sDiffTex)->bind(mTexturep.get(), TRUE); U32 indices_drawn = 0; glMatrixMode(GL_MODELVIEW); for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { LLFace *face = *iter; LLDrawable *drawablep = face->getDrawable(); if (drawablep->isDead() || !face->getVertexBuffer()) { continue; } face->getVertexBuffer()->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); U16* indicesp = (U16*) face->getVertexBuffer()->getIndicesPointer(); // Render each of the trees LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get(); LLColor4U color(255,255,255,255); if (!selecting || treep->mGLName != 0) { if (selecting) { S32 name = treep->mGLName; color = LLColor4U((U8)(name >> 16), (U8)(name >> 8), (U8)name, 255); } gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); //glPushMatrix(); F32 mat[16]; for (U32 i = 0; i < 16; i++) mat[i] = (F32) gGLModelView[i]; LLMatrix4 matrix(mat); // Translate to tree base HACK - adjustment in Z plants tree underground const LLVector3 &pos_agent = treep->getPositionAgent(); //glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); LLMatrix4 trans_mat; trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); trans_mat *= matrix; // Rotate to tree position and bend for current trunk/wind // Note that trunk stiffness controls the amount of bend at the trunk as // opposed to the crown of the tree // const F32 TRUNK_STIFF = 22.f; LLQuaternion rot = LLQuaternion(treep->mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(treep->mTrunkBend.mV[VX], treep->mTrunkBend.mV[VY], 0)) * LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) * treep->getRotation(); LLMatrix4 rot_mat(rot); rot_mat *= trans_mat; F32 radius = treep->getScale().magVec()*0.05f; LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = scale_mat.mMatrix[1][1] = scale_mat.mMatrix[2][2] = radius; scale_mat *= rot_mat; const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f; const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f; F32 droop = treep->mDroop + 25.f*(1.f - treep->mTrunkBend.magVec()); S32 stop_depth = 0; F32 app_angle = treep->getAppAngle()*LLVOTree::sTreeFactor; F32 alpha = 1.0; S32 trunk_LOD = LLVOTree::sMAX_NUM_TREE_LOD_LEVELS; for (S32 j = 0; j < 4; j++) { if (app_angle > LLVOTree::sLODAngles[j]) { trunk_LOD = j; break; } } if(trunk_LOD >= LLVOTree::sMAX_NUM_TREE_LOD_LEVELS) { continue ; //do not render. } if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD - BLEND_RANGE_FOR_BILLBOARD)) { // // Draw only the billboard // // Only the billboard, can use closer to normal alpha func. stop_depth = -1; LLFacePool::LLOverrideFaceColor clr(this, color); indices_drawn += treep->drawBranchPipeline(scale_mat, indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); } else // if (app_angle > (THRESH_ANGLE_FOR_BILLBOARD + BLEND_RANGE_FOR_BILLBOARD)) { // // Draw only the full geometry tree // //stop_depth = (app_angle < THRESH_ANGLE_FOR_RECURSION_REDUCTION); LLFacePool::LLOverrideFaceColor clr(this, color); indices_drawn += treep->drawBranchPipeline(scale_mat, indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); } //glPopMatrix(); } } }
void LLWLParamManager::update(LLViewerCamera * cam) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); // update clouds, sun, and general mCurParams.updateCloudScrolling(); // update only if running if(mAnimator.mIsRunning) { mAnimator.update(mCurParams); } // update the shaders and the menu propagateParameters(); // sync menus if they exist if(LLFloaterWindLight::isOpen()) { LLFloaterWindLight::instance()->syncMenu(); } if(LLFloaterDayCycle::isOpen()) { LLFloaterDayCycle::instance()->syncMenu(); } if(LLFloaterEnvSettings::isOpen()) { LLFloaterEnvSettings::instance()->syncMenu(); } F32 camYaw = cam->getYaw(); stop_glerror(); // *TODO: potential optimization - this block may only need to be // executed some of the time. For example for water shaders only. { F32 camYawDelta = mSunDeltaYaw * DEG_TO_RAD; LLVector3 lightNorm3(mLightDir); lightNorm3 *= LLQuaternion(-(camYaw + camYawDelta), LLVector3(0.f, 1.f, 0.f)); mRotatedLightDir = LLVector4(lightNorm3, 0.f); LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; end_shaders = LLViewerShaderMgr::instance()->endShaders(); for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) { if (shaders_iter->mProgramObject != 0 && (gPipeline.canUseWindLightShaders() || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) { shaders_iter->mUniformsDirty = TRUE; } } } //Mix windlight settings if needed if(sNeedsMix == TRUE) { if(sMixSet == NULL) { sNeedsMix = FALSE; return; } if (wlSmoothTransitionTimer.getElapsedTimeF32() >= (sMixTime / 100)) //100 steps inbetween { wlSmoothTransitionTimer.reset(); mCurParams.mix(mCurParams, *sMixSet, sMixCount / 100);//.01 to 1.0 } sMixCount++; if((sMixCount / 100) == 1) { //All done sNeedsMix = FALSE; std::string wlSkyPresetName = "(Region settings)"; mCurParams.mName = wlSkyPresetName; removeParamSet( wlSkyPresetName, true ); addParamSet( wlSkyPresetName, mCurParams ); savePreset( wlSkyPresetName ); mAnimator.mIsRunning = false; mAnimator.mUseLindenTime = false; loadPreset( wlSkyPresetName, true ); sMixSet = NULL; } } }