BOOL LLSurfacePatch::updateTexture() { if (mSTexUpdate) // Update texture as needed { F32 meters_per_grid = getSurface()->getMetersPerGrid(); F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge(); if ((!getNeighborPatch(EAST) || getNeighborPatch(EAST)->getHasReceivedData()) && (!getNeighborPatch(WEST) || getNeighborPatch(WEST)->getHasReceivedData()) && (!getNeighborPatch(SOUTH) || getNeighborPatch(SOUTH)->getHasReceivedData()) && (!getNeighborPatch(NORTH) || getNeighborPatch(NORTH)->getHasReceivedData())) { LLViewerRegion *regionp = getSurface()->getRegion(); LLVector3d origin_region = getOriginGlobal() - getSurface()->getOriginGlobal(); // Have to figure out a better way to deal with these edge conditions... LLVLComposition* comp = regionp->getComposition(); if (!mHeightsGenerated) { F32 patch_size = meters_per_grid*(grids_per_patch_edge+1); if (comp->generateHeights((F32)origin_region[VX], (F32)origin_region[VY], patch_size, patch_size)) { mHeightsGenerated = TRUE; } else { return FALSE; } } if (comp->generateComposition()) { if (mVObjp) { mVObjp->dirtyGeom(); gPipeline.markGLRebuild(mVObjp); return TRUE; } } } return FALSE; } else { return TRUE; } }
void LLSurfacePatch::updateVisibility() { if (mVObjp.isNull()) { return; } const F32 DEFAULT_DELTA_ANGLE = (0.15f); U32 old_render_stride, max_render_stride; U32 new_render_level; F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid(); U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); LLVector3 center = mCenterRegion + mSurfacep->getOriginAgent(); LLVector3 radius = LLVector3(mRadius, mRadius, mRadius); // sphere in frustum on global coordinates if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, radius)) { // We now need to calculate the render stride based on patchp's distance // from LLCamera render_stride is governed by a relation something like this... // // delta_angle * patch.distance // render_stride <= ---------------------------------------- // mMetersPerGrid // // where 'delta_angle' is the desired solid angle of the average polgon on a patch. // // Any render_stride smaller than the RHS would be 'satisfactory'. Smaller // strides give more resolution, but efficiency suggests that we use the largest // of the render_strides that obey the relation. Flexibility is achieved by // modulating 'delta_angle' until we have an acceptable number of triangles. old_render_stride = mVisInfo.mRenderStride; // Calculate the render_stride using information in agent max_render_stride = lltrunc(mVisInfo.mDistance * stride_per_distance); max_render_stride = llmin(max_render_stride , 2*grids_per_patch_edge); // We only use render_strides that are powers of two, so we use look-up tables to figure out // the render_level and corresponding render_stride new_render_level = mVisInfo.mRenderLevel = mSurfacep->getRenderLevel(max_render_stride); mVisInfo.mRenderStride = mSurfacep->getRenderStride(new_render_level); if ((mVisInfo.mRenderStride != old_render_stride)) // The reason we check !mbIsVisible is because non-visible patches normals // are not updated when their data is changed. When this changes we can get // rid of mbIsVisible altogether. { if (mVObjp) { mVObjp->dirtyGeom(); if (getNeighborPatch(WEST)) { getNeighborPatch(WEST)->mVObjp->dirtyGeom(); } if (getNeighborPatch(SOUTH)) { getNeighborPatch(SOUTH)->mVObjp->dirtyGeom(); } } } mVisInfo.mbIsVisible = TRUE; } else { mVisInfo.mbIsVisible = FALSE; } }
void LLSurfacePatch::updateNormals() { if (mSurfacep->mType == 'w') { return; } U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); U32 grids_per_edge = mSurfacep->getGridsPerEdge(); BOOL dirty_patch = FALSE; U32 i, j; // update the east edge if (mNormalsInvalid[EAST] || mNormalsInvalid[NORTHEAST] || mNormalsInvalid[SOUTHEAST]) { for (j = 0; j <= grids_per_patch_edge; j++) { calcNormal(grids_per_patch_edge, j, 2); calcNormal(grids_per_patch_edge - 1, j, 2); calcNormal(grids_per_patch_edge - 2, j, 2); } dirty_patch = TRUE; } // update the north edge if (mNormalsInvalid[NORTHEAST] || mNormalsInvalid[NORTH] || mNormalsInvalid[NORTHWEST]) { for (i = 0; i <= grids_per_patch_edge; i++) { calcNormal(i, grids_per_patch_edge, 2); calcNormal(i, grids_per_patch_edge - 1, 2); calcNormal(i, grids_per_patch_edge - 2, 2); } dirty_patch = TRUE; } // update the west edge if (mNormalsInvalid[NORTHWEST] || mNormalsInvalid[WEST] || mNormalsInvalid[SOUTHWEST]) { for (j = 0; j < grids_per_patch_edge; j++) { calcNormal(0, j, 2); calcNormal(1, j, 2); } dirty_patch = TRUE; } // update the south edge if (mNormalsInvalid[SOUTHWEST] || mNormalsInvalid[SOUTH] || mNormalsInvalid[SOUTHEAST]) { for (i = 0; i < grids_per_patch_edge; i++) { calcNormal(i, 0, 2); calcNormal(i, 1, 2); } dirty_patch = TRUE; } // Invalidating the northeast corner is different, because depending on what the adjacent neighbors are, // we'll want to do different things. if (mNormalsInvalid[NORTHEAST]) { if (!getNeighborPatch(NORTHEAST)) { if (!getNeighborPatch(NORTH)) { if (!getNeighborPatch(EAST)) { // No north or east neighbors. Pull from the diagonal in your own patch. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); } else { if (getNeighborPatch(EAST)->getHasReceivedData()) { // East, but not north. Pull from your east neighbor's northwest point. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(getNeighborPatch(EAST)->mDataZ + (grids_per_patch_edge - 1)*grids_per_edge); } else { *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); } } } else { // We have a north. if (getNeighborPatch(EAST)) { // North and east neighbors, but not northeast. // Pull from diagonal in your own patch. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); } else { if (getNeighborPatch(NORTH)->getHasReceivedData()) { // North, but not east. Pull from your north neighbor's southeast corner. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(getNeighborPatch(NORTH)->mDataZ + (grids_per_patch_edge - 1)); } else { *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); } } } } else if (getNeighborPatch(NORTHEAST)->mSurfacep != mSurfacep) { if ( (!getNeighborPatch(NORTH) || (getNeighborPatch(NORTH)->mSurfacep != mSurfacep)) && (!getNeighborPatch(EAST) || (getNeighborPatch(EAST)->mSurfacep != mSurfacep))) { *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = *(getNeighborPatch(NORTHEAST)->mDataZ); } } else { // We've got a northeast patch in the same surface. // The z and normals will be handled by that patch. } calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2); calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2); calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2); calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2); dirty_patch = TRUE; } // update the middle normals if (mNormalsInvalid[MIDDLE]) { for (j=2; j < grids_per_patch_edge - 2; j++) { for (i=2; i < grids_per_patch_edge - 2; i++) { calcNormal(i, j, 2); } } dirty_patch = TRUE; } if (dirty_patch) { mSurfacep->dirtySurfacePatch(this); } for (i = 0; i < 9; i++) { mNormalsInvalid[i] = FALSE; } }