/** * @file llworld.cpp * @brief Initial test structure to organize viewer regions * * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. * $License$ */ #include "llviewerprecompiledheaders.h" #include "llworld.h" #include "indra_constants.h" #include "llagent.h" #include "llviewercontrol.h" #include "lldrawpool.h" #include "llglheaders.h" #include "llregionhandle.h" #include "llsurface.h" #include "llviewercamera.h" #include "llviewerimage.h" #include "llviewerimagelist.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" #include "llviewerparceloverlay.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llvlcomposition.h" #include "llvoavatar.h" #include "llvowater.h" #include "message.h" #include "pipeline.h" #include "viewer.h" // for do_disconnect() // // Globals // LLWorld* gWorldp = NULL; U32 gAgentPauseSerialNum = 0; // // Constants // const S32 MAX_NUMBER_OF_CLOUDS = 750; const F32 MIN_IDLE_UPDATE_TIME = 0.025f; const S32 WORLD_PATCH_SIZE = 16; extern LLColor4U MAX_WATER_COLOR; // // Functions // // allocate the stack LLWorld::LLWorld(const U32 grids_per_region, const F32 meters_per_grid) : mWidth(grids_per_region), mScale(meters_per_grid), mWidthInMeters( grids_per_region * meters_per_grid ) { mSpaceTimeUSec = 0; mLastPacketsIn = 0; mLastPacketsOut = 0; mLastPacketsLost = 0; mLandFarClip = DEFAULT_FAR_PLANE; mIdleUpdateTime = MIN_IDLE_UPDATE_TIME; if (gNoRender) { return; } for (S32 i = 0; i < 8; i++) { mEdgeWaterObjects[i] = NULL; } LLPointer raw = new LLImageRaw(1,1,4); U8 *default_texture = raw->getData(); *(default_texture++) = MAX_WATER_COLOR.mV[0]; *(default_texture++) = MAX_WATER_COLOR.mV[1]; *(default_texture++) = MAX_WATER_COLOR.mV[2]; *(default_texture++) = MAX_WATER_COLOR.mV[3]; mDefaultWaterTexturep = new LLViewerImage(raw, FALSE); mDefaultWaterTexturep->bind(); mDefaultWaterTexturep->setClamp(TRUE, TRUE); } LLWorld::~LLWorld() { gObjectList.killAllObjects(); mRegionList.deleteAllData(); } LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host) { LLMemType mt(LLMemType::MTYPE_REGIONS); LLViewerRegion *regionp = getRegionFromHandle(region_handle); if (regionp) { LLHost old_host = regionp->getHost(); // region already exists! if (host == old_host && regionp->mAlive) { // 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->mAlive) { 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(®ionp->mWind); mRegionList.addData(regionp); mActiveRegionList.addData(regionp); mCulledRegionList.addData(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, ®ion_x, ®ion_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; } void LLWorld::removeRegion(const LLHost &host) { F32 x, y; LLViewerRegion *regionp = getRegion(host); if (!regionp) { llwarns << "Trying to remove region that doesn't exist!" << llendl; return; } if (regionp == gAgent.getRegion()) { LLViewerRegion *reg; for (reg = mRegionList.getFirstData(); reg; reg = mRegionList.getNextData()) { llwarns << "RegionDump: " << reg->getName() << " " << reg->getHost() << " " << reg->getOriginGlobal() << llendl; } llwarns << "Agent position global " << gAgent.getPositionGlobal() << " agent " << gAgent.getPositionAgent() << llendl; llwarns << "Regions visited " << gAgent.getRegionsVisited() << llendl; llwarns << "gFrameTimeSeconds " << gFrameTimeSeconds << llendl; llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl; do_disconnect("You have been disconnected from the region you were in."); return; } from_region_handle(regionp->getHandle(), &x, &y); llinfos << "Removing region " << x << ":" << y << llendl; // This code can probably be blitzed now... if (!mRegionList.removeData(regionp)) { for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { llwarns << "RegionDump: " << regionp->getName() << " " << regionp->getHost() << " " << regionp->getOriginGlobal() << llendl; } llerrs << "Region list is broken" << llendl; } if (!mActiveRegionList.removeData(regionp)) { llwarns << "LLWorld.mActiveRegionList is broken." << llendl; } if (!mCulledRegionList.removeData(regionp)) { if (!mVisibleRegionList.removeData(regionp)) { llwarns << "LLWorld.mCulled/mVisibleRegionList are broken" << llendl;; } } delete regionp; updateWaterObjects(); } LLViewerRegion *LLWorld::getRegion(const LLHost &host) { LLViewerRegion *regionp; for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { if (regionp->getHost() == host) { return regionp; } } return NULL; } LLViewerRegion *LLWorld::getRegionFromPosAgent(const LLVector3 &pos) { return getRegionFromPosGlobal(gAgent.getPosGlobalFromAgent(pos)); } LLViewerRegion *LLWorld::getRegionFromPosGlobal(const LLVector3d &pos) { LLViewerRegion *regionp; for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { if (regionp->pointInRegionGlobal(pos)) { return regionp; } } return NULL; } LLVector3d LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos) { if (positionRegionValidGlobal(end_pos)) { return end_pos; } LLViewerRegion* regionp = getRegionFromPosGlobal(start_pos); if (!regionp) { return start_pos; } LLVector3d delta_pos = end_pos - start_pos; LLVector3d delta_pos_abs; delta_pos_abs.setVec(delta_pos); delta_pos_abs.abs(); LLVector3 region_coord = regionp->getPosRegionFromGlobal(end_pos); F64 clip_factor = 1.0; F32 region_width = regionp->getWidth(); if (region_coord.mV[VX] < 0.f) { if (region_coord.mV[VY] < region_coord.mV[VX]) { // clip along y - clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]); } else { // clip along x - clip_factor = -(region_coord.mV[VX] / delta_pos_abs.mdV[VX]); } } else if (region_coord.mV[VX] > region_width) { if (region_coord.mV[VY] > region_coord.mV[VX]) { // clip along y + clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY]; } else { //clip along x + clip_factor = (region_coord.mV[VX] - region_width) / delta_pos_abs.mdV[VX]; } } else if (region_coord.mV[VY] < 0.f) { // clip along y - clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]); } else if (region_coord.mV[VY] > region_width) { // clip along y + clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY]; } // clamp to < 256 to stay in sim LLVector3d final_region_pos = LLVector3d(region_coord) - (delta_pos * clip_factor); final_region_pos.clamp(0.0, 255.999); return regionp->getPosGlobalFromRegion(LLVector3(final_region_pos)); } LLViewerRegion *LLWorld::getRegionFromHandle(const U64 &handle) { LLViewerRegion *regionp; for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { if (regionp->getHandle() == handle) { return regionp; } } return NULL; } void LLWorld::updateAgentOffset(const LLVector3d &offset_global) { #if 0 LLViewerRegion *regionp; for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { regionp->setAgentOffset(offset_global); } #endif } BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global) { LLViewerRegion *regionp; for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { if (regionp->pointInRegionGlobal(pos_global)) { return TRUE; } } return FALSE; } // Allow objects to go up to their radius underground. F32 LLWorld::getMinAllowedZ(LLViewerObject* object) { F32 land_height = resolveLandHeightGlobal(object->getPositionGlobal()); F32 radius = 0.5f * object->getScale().magVec(); return land_height - radius; } LLViewerRegion* LLWorld::resolveRegionGlobal(LLVector3 &pos_region, const LLVector3d &pos_global) { LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); if (regionp) { pos_region = regionp->getPosRegionFromGlobal(pos_global); return regionp; } return NULL; } LLViewerRegion* LLWorld::resolveRegionAgent(LLVector3 &pos_region, const LLVector3 &pos_agent) { LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); if (regionp) { pos_region = regionp->getPosRegionFromGlobal(pos_global); return regionp; } return NULL; } F32 LLWorld::resolveLandHeightAgent(const LLVector3 &pos_agent) { LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); return resolveLandHeightGlobal(pos_global); } F32 LLWorld::resolveLandHeightGlobal(const LLVector3d &pos_global) { LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); if (regionp) { return regionp->getLand().resolveHeightGlobal(pos_global); } return 0.0f; } // Takes a line defined by "point_a" and "point_b" and determines the closest (to point_a) // point where the the line intersects an object or the land surface. Stores the results // in "intersection" and "intersection_normal" and returns a scalar value that represents // the normalized distance along the line from "point_a" to "intersection". // // Currently assumes point_a and point_b only differ in z-direction, // but it may eventually become more general. F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d &point_a, const LLVector3d &point_b, LLVector3d &intersection, LLVector3 &intersection_normal, LLViewerObject **viewerObjectPtr) { // initialize return value to null if (viewerObjectPtr) { *viewerObjectPtr = NULL; } LLViewerRegion *regionp = getRegionFromPosGlobal(point_a); if (!regionp) { // We're outside the world intersection = 0.5f * (point_a + point_b); intersection_normal.setVec(0.0f, 0.0f, 1.0f); return 0.5f; } // calculate the length of the segment F32 segment_length = (F32)((point_a - point_b).magVec()); if (0.0f == segment_length) { intersection = point_a; intersection_normal.setVec(0.0f, 0.0f, 1.0f); return segment_length; } // get land height // Note: we assume that the line is parallel to z-axis here LLVector3d land_intersection = point_a; F32 normalized_land_distance; land_intersection.mdV[VZ] = regionp->getLand().resolveHeightGlobal(point_a); normalized_land_distance = (F32)(point_a.mdV[VZ] - land_intersection.mdV[VZ]) / segment_length; if (avatarp && !avatarp->mFootPlane.isExactlyClear()) { LLVector3 foot_plane_normal(avatarp->mFootPlane.mV); LLVector3 start_pt = avatarp->getRegion()->getPosRegionFromGlobal(point_a); // added 0.05 meters to compensate for error in foot plane reported by Havok F32 norm_dist_from_plane = ((start_pt * foot_plane_normal) - avatarp->mFootPlane.mV[VW]) + 0.05f; norm_dist_from_plane = llclamp(norm_dist_from_plane / segment_length, 0.f, 1.f); if (norm_dist_from_plane < normalized_land_distance) { normalized_land_distance = norm_dist_from_plane; intersection = point_a; intersection.mdV[VZ] -= norm_dist_from_plane * segment_length; intersection_normal = foot_plane_normal; } } else { intersection = land_intersection; intersection_normal = resolveLandNormalGlobal(land_intersection); } return normalized_land_distance; } LLSurfacePatch * LLWorld::resolveLandPatchGlobal(const LLVector3d &pos_global) { // returns a pointer to the patch at this location LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); if (!regionp) { return NULL; } return regionp->getLand().resolvePatchGlobal(pos_global); } LLVector3 LLWorld::resolveLandNormalGlobal(const LLVector3d &pos_global) { LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global); if (!regionp) { return LLVector3::z_axis; } return regionp->getLand().resolveNormalGlobal(pos_global); } void LLWorld::updateVisibilities() { F32 cur_far_clip = gCamera->getFar(); gCamera->setFar(mLandFarClip); LLViewerRegion *regionp; F32 diagonal_squared = F_SQRT2 * F_SQRT2 * mWidth * mWidth; // Go through the culled list and check for visible regions for (regionp = mCulledRegionList.getFirstData(); regionp; regionp = mCulledRegionList.getNextData()) { F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ(); F32 radius = 0.5f*fsqrtf(height * height + diagonal_squared); if (!regionp->getLand().hasZData() || gCamera->sphereInFrustum(regionp->getCenterAgent(), radius)) { mCulledRegionList.removeCurrentData(); mVisibleRegionList.addDataAtEnd(regionp); } } F32 last_dist_squared = 0.0f; F32 dist_squared; // Update all of the visible regions and make single bubble-sort pass for (regionp = mVisibleRegionList.getFirstData(); regionp; regionp = mVisibleRegionList.getNextData()) { if (!regionp->getLand().hasZData()) { continue; } F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ(); F32 radius = 0.5f*fsqrtf(height * height + diagonal_squared); if (gCamera->sphereInFrustum(regionp->getCenterAgent(), radius)) { if (!gNoRender) { regionp->getLand().updatePatchVisibilities(gAgent); } // sort by distance... closer regions to the front // Note: regions use absolute frame so we use the agent's center dist_squared = (F32)(gAgent.getCameraPositionGlobal() - regionp->getCenterGlobal()).magVecSquared(); if (dist_squared < last_dist_squared) { mVisibleRegionList.swapCurrentWithPrevious(); } else { last_dist_squared = dist_squared; } } else { mVisibleRegionList.removeCurrentData(); mCulledRegionList.addData(regionp); } } gCamera->setFar(cur_far_clip); } void LLWorld::updateRegions() { LLViewerRegion *regionp; LLTimer update_timer; // Perform idle time updates for the regions (and associated surfaces) for (regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { update_timer.reset(); if (!regionp->idleUpdate(update_timer, mIdleUpdateTime)) { // Didn't finish all the updates. Slightly increase the idle update time. mIdleUpdateTime *= 1.05f; } else { mIdleUpdateTime *= 0.9f; if (mIdleUpdateTime < MIN_IDLE_UPDATE_TIME) { mIdleUpdateTime = MIN_IDLE_UPDATE_TIME; } } } } void LLWorld::updateParticles() { mPartSim.updateSimulation(); } void LLWorld::updateClouds(const F32 dt) { if (gSavedSettings.getBOOL("FreezeTime")) { // don't move clouds in snapshot mode return; } LLViewerRegion *regionp; if (mActiveRegionList.getLength()) { // Update all the cloud puff positions, and timer based stuff // such as death decay for (regionp = mActiveRegionList.getFirstData(); regionp; regionp = mActiveRegionList.getNextData()) { regionp->mCloudLayer.updatePuffs(dt); } // Reshuffle who owns which puffs for (regionp = mActiveRegionList.getFirstData(); regionp; regionp = mActiveRegionList.getNextData()) { regionp->mCloudLayer.updatePuffOwnership(); } // Add new puffs for (regionp = mActiveRegionList.getFirstData(); regionp; regionp = mActiveRegionList.getNextData()) { regionp->mCloudLayer.updatePuffCount(); } } } LLCloudGroup *LLWorld::findCloudGroup(const LLCloudPuff &puff) { LLViewerRegion *regionp; if (mActiveRegionList.getLength()) { // Update all the cloud puff positions, and timer based stuff // such as death decay for (regionp = mActiveRegionList.getFirstData(); regionp; regionp = mActiveRegionList.getNextData()) { LLCloudGroup *groupp = regionp->mCloudLayer.findCloudGroup(puff); if (groupp) { return groupp; } } } return NULL; } void LLWorld::renderPropertyLines() { S32 region_count = 0; S32 vertex_count = 0; LLViewerRegion* region; for (region = mVisibleRegionList.getFirstData(); region; region = mVisibleRegionList.getNextData() ) { region_count++; vertex_count += region->renderPropertyLines(); } } void LLWorld::updateNetStats() { F32 bits = 0.f; U32 packets = 0; LLViewerRegion *regionp; for (regionp = mActiveRegionList.getFirstData(); regionp; regionp = mActiveRegionList.getNextData()) { regionp->updateNetStats(); bits += regionp->mBitStat.getCurrent(); packets += llfloor( regionp->mPacketsStat.getCurrent() ); } S32 packets_in = gMessageSystem->mPacketsIn - mLastPacketsIn; S32 packets_out = gMessageSystem->mPacketsOut - mLastPacketsOut; S32 packets_lost = gMessageSystem->mDroppedPackets - mLastPacketsLost; S32 actual_in_bits = gMessageSystem->mPacketRing.getAndResetActualInBits(); S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits(); gViewerStats->mActualInKBitStat.addValue(actual_in_bits/1024.f); gViewerStats->mActualOutKBitStat.addValue(actual_out_bits/1024.f); gViewerStats->mKBitStat.addValue(bits/1024.f); gViewerStats->mPacketsInStat.addValue(packets_in); gViewerStats->mPacketsOutStat.addValue(packets_out); gViewerStats->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets); if (packets_in) { gViewerStats->mPacketsLostPercentStat.addValue(100.f*((F32)packets_lost/(F32)packets_in)); } else { gViewerStats->mPacketsLostPercentStat.addValue(0.f); } mLastPacketsIn = gMessageSystem->mPacketsIn; mLastPacketsOut = gMessageSystem->mPacketsOut; mLastPacketsLost = gMessageSystem->mDroppedPackets; } void LLWorld::printPacketsLost() { LLViewerRegion *regionp; llinfos << "Simulators:" << llendl; llinfos << "----------" << llendl; LLCircuitData *cdp = NULL; for (regionp = mActiveRegionList.getFirstData(); regionp; regionp = mActiveRegionList.getNextData()) { cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost()); if (cdp) { LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal(); llinfos << regionp->getHost() << ", range: " << range.magVec() << " packets lost: " << cdp->getPacketsLost() << llendl; } } llinfos << "UserServer:" << llendl; llinfos << "-----------" << llendl; cdp = gMessageSystem->mCircuitInfo.findCircuit(gUserServer); if (cdp) { llinfos << gUserServer << " packets lost: " << cdp->getPacketsLost() << llendl; } } void LLWorld::processCoarseUpdate(LLMessageSystem* msg, void** user_data) { LLViewerRegion* region = NULL; region = gWorldp->getRegion(msg->getSender()); if( region ) region->updateCoarseLocations(msg); } F32 LLWorld::getLandFarClip() const { return mLandFarClip; } void LLWorld::setLandFarClip(const F32 far_clip) { mLandFarClip = far_clip; } void LLWorld::updateWaterObjects() { //llinfos << "Start water update" << llendl; if (!gAgent.getRegion()) { return; } S32 min_x, min_y, max_x, max_y; U32 region_x, region_y; S32 rwidth = llfloor(getRegionWidthInMeters()); // First, determine the min and max "box" of water objects LLViewerRegion *regionp; regionp = mRegionList.getFirstData(); if (!regionp) { llwarns << "No regions!" << llendl; return; } from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); min_x = max_x = region_x; min_y = max_y = region_y; LLVOWater *waterp; for (; regionp; regionp = mRegionList.getNextData()) { from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); min_x = llmin(min_x, (S32)region_x); min_y = llmin(min_y, (S32)region_y); max_x = llmax(max_x, (S32)region_x); max_y = llmax(max_y, (S32)region_y); waterp = regionp->getLand().getWaterObj(); if (waterp) { gObjectList.updateActive(waterp); } } for (waterp = mHoleWaterObjects.getFirstData(); waterp; waterp = mHoleWaterObjects.getNextData()) { gObjectList.killObject(waterp); } mHoleWaterObjects.removeAllNodes(); // We only want to fill in holes for stuff that's near us, say, within 512m regionp = gAgent.getRegion(); from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); min_x = llmax((S32)region_x - 512, min_x); min_y = llmax((S32)region_y - 512, min_y); max_x = llmin((S32)region_x + 512, max_x); max_y = llmin((S32)region_y + 512, max_y); // Now, get a list of the holes S32 x, y; for (x = min_x; x <= max_x; x += rwidth) { for (y = min_y; y <= max_y; y += rwidth) { U64 region_handle = to_region_handle(x, y); if (!getRegionFromHandle(region_handle)) { waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion()); waterp->setUseTexture(FALSE); gPipeline.addObject(waterp); waterp->setPositionGlobal(LLVector3d(x + rwidth/2, y + rwidth/2, DEFAULT_WATER_HEIGHT)); waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 0.f)); mHoleWaterObjects.addData(waterp); } } } // Update edge water objects S32 wx, wy; S32 center_x, center_y; wx = (max_x - min_x) + rwidth; wy = (max_y - min_y) + rwidth; center_x = min_x + (wx >> 1); center_y = min_y + (wy >> 1); S32 add_boundary[4] = { 512 - (max_x - region_x), 512 - (max_y - region_y), 512 - (region_x - min_x), 512 - (region_y - min_y) }; S32 dir; for (dir = 0; dir < 8; dir++) { S32 dim[2] = { 0 }; switch (gDirAxes[dir][0]) { case -1: dim[0] = add_boundary[2]; break; case 0: dim[0] = wx; break; default: dim[0] = add_boundary[0]; break; } switch (gDirAxes[dir][1]) { case -1: dim[1] = add_boundary[3]; break; case 0: dim[1] = wy; break; default: dim[1] = add_boundary[1]; break; } if (dim[0] == 0 || dim[1] == 0) { continue; } // Resize and reshape the water objects const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]); const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]); 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_WATER, gAgent.getRegion()); waterp = mEdgeWaterObjects[dir]; waterp->setUseTexture(FALSE); gPipeline.addObject(waterp); } waterp->setRegion(gAgent.getRegion()); LLVector3d water_pos(water_center_x, water_center_y, DEFAULT_WATER_HEIGHT); waterp->setPositionGlobal(water_pos); waterp->setScale(LLVector3((F32)dim[0], (F32)dim[1], 0.f)); gObjectList.updateActive(waterp); /*if (!gNoRender) { gPipeline.markMoved(waterp->mDrawable); }*/ } //llinfos << "End water update" << llendl; } LLViewerImage *LLWorld::getDefaultWaterTexture() { return mDefaultWaterTexturep; } void LLWorld::setSpaceTimeUSec(const U64 space_time_usec) { mSpaceTimeUSec = space_time_usec; } U64 LLWorld::getSpaceTimeUSec() const { return mSpaceTimeUSec; } void LLWorld::requestCacheMisses() { for(LLViewerRegion* regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { regionp->requestCacheMisses(); } } LLString LLWorld::getInfoString() { LLString info_string("World Info:\n"); for (LLViewerRegion* regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { info_string += regionp->getInfoString(); } return info_string; } void LLWorld::disconnectRegions() { LLMessageSystem* msg = gMessageSystem; for(LLViewerRegion* regionp = mRegionList.getFirstData(); regionp; regionp = mRegionList.getNextData()) { if (regionp == gAgent.getRegion()) { // Skip the main agent continue; } llinfos << "Sending AgentQuitCopy to: " << regionp->getHost() << llendl; msg->newMessageFast(_PREHASH_AgentQuitCopy); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_FuseBlock); msg->addU32Fast(_PREHASH_ViewerCircuitCode, gMessageSystem->mOurCircuitCode); msg->sendMessage(regionp->getHost()); } } void process_enable_simulator(LLMessageSystem *msg, void **user_data) { // enable the appropriate circuit for this simulator and // add its values into the gSimulator structure U64 handle; U32 ip_u32; U16 port; msg->getU64Fast(_PREHASH_SimulatorInfo, _PREHASH_Handle, handle); msg->getIPAddrFast(_PREHASH_SimulatorInfo, _PREHASH_IP, ip_u32); msg->getIPPortFast(_PREHASH_SimulatorInfo, _PREHASH_Port, port); // which simulator should we modify? LLHost sim(ip_u32, port); // Viewer trusts the simulator. msg->enableCircuit(sim, TRUE); gWorldp->addRegion(handle, sim); // give the simulator a message it can use to get ip and port llinfos << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << llendl; msg->newMessageFast(_PREHASH_UseCircuitCode); msg->nextBlockFast(_PREHASH_CircuitCode); msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); msg->sendReliable(sim); } // disable the circuit to this simulator // Called in response to "DisableSimulator" message. void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data) { LLHost host = mesgsys->getSender(); //llinfos << "Disabling simulator with message from " << host << llendl; gWorldp->removeRegion(host); mesgsys->disableCircuit(host); } void process_region_handshake(LLMessageSystem* msg, void** user_data) { LLHost host = msg->getSender(); LLViewerRegion* regionp = gWorldp->getRegion(host); if (!regionp) { llwarns << "Got region handshake for unknown region " << host << llendl; return; } regionp->unpackRegionHandshake(); } void send_agent_pause() { // world not initialized yet if (!gWorldp) return; gMessageSystem->newMessageFast(_PREHASH_AgentPause); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); gAgentPauseSerialNum++; gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum); LLViewerRegion *regionp; for (regionp = gWorldp->mActiveRegionList.getFirstData(); regionp; regionp = gWorldp->mActiveRegionList.getNextData()) { gMessageSystem->sendReliable(regionp->getHost()); } gMessageSystem->sendReliable(gUserServer); gObjectList.mWasPaused = TRUE; } void send_agent_resume() { // world not initialized yet if (!gWorldp) return; gMessageSystem->newMessageFast(_PREHASH_AgentResume); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); gAgentPauseSerialNum++; gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum); LLViewerRegion *regionp; for (regionp = gWorldp->mActiveRegionList.getFirstData(); regionp; regionp = gWorldp->mActiveRegionList.getNextData()) { gMessageSystem->sendReliable(regionp->getHost()); } gMessageSystem->sendReliable(gUserServer); // Reset the FPS counter to avoid an invalid fps gViewerStats->mFPSStat.start(); }