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;
	}
}
Exemple #2
0
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;
	}
}
Exemple #3
0
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;
	}
}