Пример #1
0
void LLWorld::setLandFarClip(const F32 far_clip)
{
	static S32 const rwidth = (S32)getRegionWidthInMeters();
	S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
	S32 const n2 = (llceil(far_clip) - 1) / rwidth;
	bool need_water_objects_update = n1 != n2;

	mLandFarClip = far_clip;

	if (need_water_objects_update)
	{
		updateWaterObjects();
	}
}
Пример #2
0
void LLWorld::setLandFarClip(const F32 far_clip)
{
// <FS:CR> Aurora Sim
	//static S32 const rwidth = (S32)REGION_WIDTH_U32;
	S32 const rwidth = (S32)getRegionWidthInMeters();
// </FS:CR> Aurora Sim
	S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
	S32 const n2 = (llceil(far_clip) - 1) / rwidth;
	bool need_water_objects_update = n1 != n2;

	mLandFarClip = far_clip;

	if (need_water_objects_update)
	{
		updateWaterObjects();
	}
}
Пример #3
0
LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
{
	llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl;
	LLViewerRegion *regionp = getRegionFromHandle(region_handle);
	if (regionp)
	{
		llinfos << "Region exists, removing it " << llendl;
		LLHost old_host = regionp->getHost();
		// region already exists!
		if (host == old_host && regionp->isAlive())
		{
			// This is a duplicate for the same host and it's alive, don't bother.
			return regionp;
		}

		if (host != old_host)
		{
			llwarns << "LLWorld::addRegion exists, but old host " << old_host
					<< " does not match new host " << host << llendl;
		}
		if (!regionp->isAlive())
		{
			llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl;
		}

		// Kill the old host, and then we can continue on and add the new host.  We have to kill even if the host
		// matches, because all the agent state for the new camera is completely different.
		removeRegion(old_host);
	}

	U32 iindex = 0;
	U32 jindex = 0;
	from_region_handle(region_handle, &iindex, &jindex);
// <FS:CR> Aurora Sim
	//S32 x = (S32)(iindex/mWidth);
	//S32 y = (S32)(jindex/mWidth);
	S32 x = (S32)(iindex/256); //MegaRegion
	S32 y = (S32)(jindex/256); //MegaRegion
// </FS:CR> Aurora Sim
	llinfos << "Adding new region (" << x << ":" << y << ")" << llendl;
	llinfos << "Host: " << host << llendl;

	LLVector3d origin_global;

	origin_global = from_region_handle(region_handle);

	regionp = new LLViewerRegion(region_handle,
								    host,
									mWidth,
									WORLD_PATCH_SIZE,
									getRegionWidthInMeters() );
	if (!regionp)
	{
		llerrs << "Unable to create new region!" << llendl;
	}

	//Classic clouds
#if ENABLE_CLASSIC_CLOUDS
	regionp->mCloudLayer.create(regionp);
	regionp->mCloudLayer.setWidth((F32)mWidth);
	regionp->mCloudLayer.setWindPointer(&regionp->mWind);
#endif

	mRegionList.push_back(regionp);
	mActiveRegionList.push_back(regionp);
	mCulledRegionList.push_back(regionp);


	// Find all the adjacent regions, and attach them.
	// Generate handles for all of the adjacent regions, and attach them in the correct way.
	// connect the edges
	F32 adj_x = 0.f;
	F32 adj_y = 0.f;
	F32 region_x = 0.f;
	F32 region_y = 0.f;
	U64 adj_handle = 0;

	F32 width = getRegionWidthInMeters();

	LLViewerRegion *neighborp;
	from_region_handle(region_handle, &region_x, &region_y);

	// Iterate through all directions, and connect neighbors if there.
	S32 dir;
	for (dir = 0; dir < 8; dir++)
	{
		adj_x = region_x + width * gDirAxes[dir][0];
		adj_y = region_y + width * gDirAxes[dir][1];

		if (mWidth == 256 && mLength == 256)
		{
			to_region_handle(adj_x, adj_y, &adj_handle);
			neighborp = getRegionFromHandle(adj_handle);
			if (neighborp)
			{
				//llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl;
				regionp->connectNeighbor(neighborp, dir);
			}
		}
		else // Unconventional region size
		{
			LLViewerRegion* last_neighborp = NULL;
			if(gDirAxes[dir][0] < 0) adj_x = region_x - WORLD_PATCH_SIZE;
			if(gDirAxes[dir][1] < 0) adj_y = region_y - WORLD_PATCH_SIZE;

			for (S32 offset = 0; offset < width; offset += WORLD_PATCH_SIZE)
			{
				to_region_handle(adj_x, adj_y, &adj_handle);
				neighborp = getRegionFromHandle(adj_handle);

				if (neighborp && last_neighborp != neighborp)
				{
					//llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl;
					regionp->connectNeighbor(neighborp, dir);
					last_neighborp = neighborp;
				}

				if (dir == NORTH || dir == SOUTH)
					adj_x += WORLD_PATCH_SIZE;
				else if (dir == EAST || dir == WEST)
					adj_y += WORLD_PATCH_SIZE;
				else if (dir == NORTHEAST || dir == NORTHWEST || dir == SOUTHWEST || dir == SOUTHEAST)
					break;

			}
		}
	}

	updateWaterObjects();

	return regionp;
}
Пример #4
0
LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
{
	LLMemType mt(LLMemType::MTYPE_REGIONS);
	llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl;
	LLViewerRegion *regionp = getRegionFromHandle(region_handle);
	if (regionp)
	{
		llinfos << "Region exists, removing it " << llendl;
		LLHost old_host = regionp->getHost();
		// region already exists!
		if (host == old_host && regionp->isAlive())
		{
			// This is a duplicate for the same host and it's alive, don't bother.
			return regionp;
		}

		if (host != old_host)
		{
			llwarns << "LLWorld::addRegion exists, but old host " << old_host
					<< " does not match new host " << host << llendl;
		}
		if (!regionp->isAlive())
		{
			llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl;
		}

		// Kill the old host, and then we can continue on and add the new host.  We have to kill even if the host
		// matches, because all the agent state for the new camera is completely different.
		removeRegion(old_host);
	}

	U32 iindex = 0;
	U32 jindex = 0;
	from_region_handle(region_handle, &iindex, &jindex);
	S32 x = (S32)(iindex/mWidth);
	S32 y = (S32)(jindex/mWidth);
	llinfos << "Adding new region (" << x << ":" << y << ")" << llendl;
	llinfos << "Host: " << host << llendl;

	LLVector3d origin_global;

	origin_global = from_region_handle(region_handle);

	regionp = new LLViewerRegion(region_handle,
								    host,
									mWidth,
									WORLD_PATCH_SIZE,
									getRegionWidthInMeters() );
	if (!regionp)
	{
		llerrs << "Unable to create new region!" << llendl;
	}

	regionp->mCloudLayer.create(regionp);
	regionp->mCloudLayer.setWidth((F32)mWidth);
	regionp->mCloudLayer.setWindPointer(&regionp->mWind);

	mRegionList.push_back(regionp);
	mActiveRegionList.push_back(regionp);
	mCulledRegionList.push_back(regionp);


	// Find all the adjacent regions, and attach them.
	// Generate handles for all of the adjacent regions, and attach them in the correct way.
	// connect the edges
	F32 adj_x = 0.f;
	F32 adj_y = 0.f;
	F32 region_x = 0.f;
	F32 region_y = 0.f;
	U64 adj_handle = 0;

	F32 width = getRegionWidthInMeters();

	LLViewerRegion *neighborp;
	from_region_handle(region_handle, &region_x, &region_y);

	// Iterate through all directions, and connect neighbors if there.
	S32 dir;
	for (dir = 0; dir < 8; dir++)
	{
		adj_x = region_x + width * gDirAxes[dir][0];
		adj_y = region_y + width * gDirAxes[dir][1];
		to_region_handle(adj_x, adj_y, &adj_handle);

		neighborp = getRegionFromHandle(adj_handle);
		if (neighborp)
		{
			//llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl;
			regionp->connectNeighbor(neighborp, dir);
		}
	}

	updateWaterObjects();

	return regionp;
}
Пример #5
0
// There are three types of water objects:
// Region water objects: the water in a region.
// Hole water objects: water in the void but within current draw distance.
// Edge water objects: the water outside the draw distance, up till the horizon.
//
// For example:
//
// -----------------------horizon-------------------------
// |                 |                 |                 |
// |  Edge Water     |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |      rwidth     |                 |
// |                 |     <----->     |                 |
// -------------------------------------------------------
// |                 |Hole |other|     |                 |
// |                 |Water|reg. |     |                 |
// |                 |-----------------|                 |
// |                 |other|cur. |<--> |                 |
// |                 |reg. | reg.|  \__|_ draw distance  |
// |                 |-----------------|                 |
// |                 |     |     |<--->|                 |
// |                 |     |     |  \__|_ range          |
// -------------------------------------------------------
// |                 |<----width------>|<--horizon ext.->|
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// |                 |                 |                 |
// -------------------------------------------------------
//
void LLWorld::updateWaterObjects()
{
	if (!gAgent.getRegion())
	{
		return;
	}
	if (mRegionList.empty())
	{
		llwarns << "No regions!" << llendl;
		return;
	}

	// Region width in meters.
	//S32 const rwidth = (S32)REGION_WIDTH_U32;//non var
	S32 const rwidth = (S32)getRegionWidthInMeters();//REGION_WIDTH_U32;

	// The distance we might see into the void
	// when standing on the edge of a region, in meters.
	S32 const draw_distance = llceil(mLandFarClip);

	// We can only have "holes" in the water (where there no region) if we
	// can have existing regions around it. Taking into account that this
	// code is only executed when we enter a region, and not when we walk
	// around in it, we (only) need to take into account regions that fall
	// within the draw_distance.
	//
	// Set 'range' to draw_distance, rounded up to the nearest multiple of rwidth.
	S32 const nsims = (draw_distance + rwidth - 1) / rwidth;
	S32 const range = nsims * rwidth;

	// Get South-West corner of current region.
	LLViewerRegion const* regionp = gAgent.getRegion();
	U32 region_x, region_y;
	from_region_handle(regionp->getHandle(), &region_x, &region_y);

	// The min. and max. coordinates of the South-West corners of the Hole water objects.
	S32 const min_x = (S32)region_x - range;
	S32 const min_y = (S32)region_y - range;
	S32 const max_x = (S32)region_x + range;
	S32 const max_y = (S32)region_y + range;

	// Attempt to determine a sensible water height for all the
	// Hole Water objects.
	//
	// It make little sense to try to guess what the best water
	// height should be when that isn't completely obvious: if it's
	// impossible to satisfy every region's water height without
	// getting a jump in the water height.
	//
	// In order to keep the reasoning simple, we assume something
	// logical as a group of connected regions, where the coastline
	// is at the outer edge. Anything more complex that would "break"
	// under such an assumption would probably break anyway (would
	// depend on terrain editing and existing mega prims, say, if
	// anything would make sense at all).
	//
	// So, what we do is find all connected regions within the
	// draw distance that border void, and then pick the lowest
	// water height of those (coast) regions.
	S32 const n = 2 * nsims + 1;
	S32 const origin = nsims + nsims * n;
	std::vector<F32> water_heights(n * n);
	std::vector<U8> checked(n * n, 0);		// index = nx + ny * n + origin;
	U8 const region_bit = 1;
	U8 const hole_bit = 2;
	U8 const bordering_hole_bit = 4;
	U8 const bordering_edge_bit = 8;
	// Use the legacy waterheight for the Edge water in the case
	// that we don't find any Hole water at all.
	F32 water_height = DEFAULT_WATER_HEIGHT;
	int max_count = 0;
	LL_DEBUGS("WaterHeight") << "Current region: " << regionp->getName() << "; water height: " << regionp->getWaterHeight() << " m." << LL_ENDL;
	std::map<S32, int> water_height_counts;
	typedef std::queue<std::pair<S32, S32>, std::deque<std::pair<S32, S32> > > nxny_pairs_type;
	nxny_pairs_type nxny_pairs;
	nxny_pairs.push(nxny_pairs_type::value_type(0, 0));
	water_heights[origin] = regionp->getWaterHeight();
	checked[origin] = region_bit;
	// For debugging purposes.
	int number_of_connected_regions = 1;
	int uninitialized_regions = 0;
	int bordering_hole = 0;
	int bordering_edge = 0;
	while(!nxny_pairs.empty())
	{
		S32 const nx = nxny_pairs.front().first;
		S32 const ny = nxny_pairs.front().second;
		LL_DEBUGS("WaterHeight") << "nx,ny = " << nx << "," << ny << LL_ENDL;
		S32 const index = nx + ny * n + origin;
		nxny_pairs.pop();
		for (S32 dir = 0; dir < 4; ++dir)
		{
			S32 const cnx = nx + gDirAxes[dir][0];
			S32 const cny = ny + gDirAxes[dir][1];
			LL_DEBUGS("WaterHeight") << "dir = " << dir << "; cnx,cny = " << cnx << "," << cny << LL_ENDL;
			S32 const cindex = cnx + cny * n + origin;
			bool is_hole = false;
			bool is_edge = false;
			LLViewerRegion* new_region_found = NULL;
			if (cnx < -nsims || cnx > nsims ||
			    cny < -nsims || cny > nsims)
			{
				LL_DEBUGS("WaterHeight") << "  Edge Water!" << LL_ENDL;
				// Bumped into Edge water object.
				is_edge = true;
			}
			else if (checked[cindex])
			{
				LL_DEBUGS("WaterHeight") << "  Already checked before!" << LL_ENDL;
				// Already checked.
				is_hole = (checked[cindex] & hole_bit);
			}
			else
			{
				S32 x = (S32)region_x + cnx * rwidth;
				S32 y = (S32)region_y + cny * rwidth;
				U64 region_handle = to_region_handle(x, y);
				new_region_found = getRegionFromHandle(region_handle);
				is_hole = !new_region_found;
				checked[cindex] = is_hole ? hole_bit : region_bit;
			}
			if (is_hole)
			{
				// This was a region that borders at least one 'hole'.
				// Count the found coastline.
				F32 new_water_height = water_heights[index];
				LL_DEBUGS("WaterHeight") << "  This is void; counting coastline with water height of " << new_water_height << LL_ENDL;
				S32 new_water_height_cm = llround(new_water_height * 100);
				int count = (water_height_counts[new_water_height_cm] += 1);
				// Just use the lowest water height: this is mainly about the horizon water,
				// and whatever we do, we don't want it to be possible to look under the water
				// when looking in the distance: it is better to make a step downwards in water
				// height when going away from the avie than a step upwards. However, since
				// everyone is used to DEFAULT_WATER_HEIGHT, don't allow a single region
				// to drag the water level below DEFAULT_WATER_HEIGHT on it's own.
				if (bordering_hole == 0 ||			// First time we get here.
				    (new_water_height >= DEFAULT_WATER_HEIGHT &&
					 new_water_height < water_height) ||
				    (new_water_height < DEFAULT_WATER_HEIGHT &&
					 count > max_count)
				   )
				{
					water_height = new_water_height;
				}
				if (count > max_count)
				{
					max_count = count;
				}
				if (!(checked[index] & bordering_hole_bit))
				{
					checked[index] |= bordering_hole_bit;
					++bordering_hole;
				}
			}
			else if (is_edge && !(checked[index] & bordering_edge_bit))
			{
				checked[index] |= bordering_edge_bit;
				++bordering_edge;
			}
			if (!new_region_found)
			{
				// Dead end, there is no region here.
				continue;
			}
			// Found a new connected region.
			++number_of_connected_regions;
			if (new_region_found->getName().empty())
			{
				// Uninitialized LLViewerRegion, don't use it's water height.
				LL_DEBUGS("WaterHeight") << "  Uninitialized region." << LL_ENDL;
				++uninitialized_regions;
				continue;
			}
			nxny_pairs.push(nxny_pairs_type::value_type(cnx, cny));
			water_heights[cindex] = new_region_found->getWaterHeight();
			LL_DEBUGS("WaterHeight") << "  Found a new region (name: " << new_region_found->getName() << "; water height: " << water_heights[cindex] << " m)!" << LL_ENDL;
		}
	}
	llinfos << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions <<
		" uninitialized); number of regions bordering Hole water: " << bordering_hole <<
		"; number of regions bordering Edge water: " << bordering_edge << llendl;
	llinfos << "Coastline count (height, count): ";
	bool first = true;
	for (std::map<S32, int>::iterator iter = water_height_counts.begin(); iter != water_height_counts.end(); ++iter)
	{
		if (!first) llcont << ", ";
		llcont << "(" << (iter->first / 100.f) << ", " << iter->second << ")";
		first = false;
	}
	llcont << llendl;
	llinfos << "Water height used for Hole and Edge water objects: " << water_height << llendl;

	// Update all Region water objects.
	for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
	{
		LLViewerRegion* regionp = *iter;
		LLVOWater* waterp = regionp->getLand().getWaterObj();
		if (waterp)
		{
			gObjectList.updateActive(waterp);
		}
	}

	// Clean up all existing Hole water objects.
	for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin();
		 iter != mHoleWaterObjects.end(); ++iter)
	{
		LLVOWater* waterp = *iter;
		gObjectList.killObject(waterp);
	}
	mHoleWaterObjects.clear();

	// Let the Edge and Hole water boxes be 1024 meter high so that they
	// are never too small to be drawn (A LL_VO_*_WATER box has water
	// rendered on it's bottom surface only), and put their bottom at
	// the current regions water height.
	F32 const box_height = 1024;
	F32 const water_center_z = water_height + box_height / 2;

	// Create new Hole water objects within 'range' where there is no region.
	for (S32 x = min_x; x <= max_x; x += rwidth)
	{
		for (S32 y = min_y; y <= max_y; y += rwidth)
		{
			U64 region_handle = to_region_handle(x, y);
			if (!getRegionFromHandle(region_handle))
			{
				LLVOWater* waterp = (LLVOWater*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion());
				waterp->setUseTexture(FALSE);
				waterp->setPositionGlobal(LLVector3d(x + rwidth / 2, y + rwidth / 2, water_center_z));
				waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, box_height));
				gPipeline.createObject(waterp);
				mHoleWaterObjects.push_back(waterp);
			}
		}
	}

	// Center of the region.
	S32 const center_x = region_x + rwidth / 2;
	S32 const center_y = region_y + rwidth / 2;
	// Width of the area with Hole water objects.
	S32 const width = rwidth + 2 * range;
	S32 const horizon_extend = 2048 + 512 - range;	// Legacy value.
	// The overlap is needed to get rid of sky pixels being visible between the
	// Edge and Hole water object at greater distances (due to floating point
	// round off errors).
	S32 const edge_hole_overlap = 1;		// Twice the actual overlap.
		
	for (S32 dir = 0; dir < 8; ++dir)
	{
		// Size of the Edge water objects.
		S32 const dim_x = (gDirAxes[dir][0] == 0) ? width : (horizon_extend + edge_hole_overlap);
		S32 const dim_y = (gDirAxes[dir][1] == 0) ? width : (horizon_extend + edge_hole_overlap);
		// And their position.
		S32 const water_center_x = center_x + (width + horizon_extend) / 2 * gDirAxes[dir][0];
		S32 const water_center_y = center_y + (width + horizon_extend) / 2 * gDirAxes[dir][1];

		LLVOWater* waterp = mEdgeWaterObjects[dir];
		if (!waterp || waterp->isDead())
		{
			// The edge water objects can be dead because they're attached to the region that the
			// agent was in when they were originally created.
			mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion());
			waterp = mEdgeWaterObjects[dir];
			waterp->setUseTexture(FALSE);
			waterp->setIsEdgePatch(TRUE);		// Mark that this is edge water and not hole water.
			gPipeline.createObject(waterp);
		}

		waterp->setRegion(gAgent.getRegion());
		LLVector3d water_pos(water_center_x, water_center_y, water_center_z);
		LLVector3 water_scale((F32) dim_x, (F32) dim_y, box_height);

		waterp->setPositionGlobal(water_pos);
		waterp->setScale(water_scale);

		gObjectList.updateActive(waterp);
	}
}