/* * Draw vertical lines from each vertex straight up in world space * with lengths indicating the current "strength" slider. * Decorate the tops and bottoms of the lines like this: * * Raise Revert * /|\ ___ * | | * | | * * Rough Smooth * /|\ ___ * | | * | | * \|/..........._|_ * * Lower Flatten * | | * | | * \|/..........._|_ */ void LLToolBrushLand::renderOverlay(LLSurface& land, const LLVector3& pos_region, const LLVector3& pos_world) { glMatrixMode(GL_MODELVIEW); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLDepthTest mDepthTest(GL_TRUE); glPushMatrix(); gGL.color4fv(OVERLAY_COLOR.mV); glTranslatef(0.0f, 0.0f, 1.0f); S32 i = (S32) pos_region.mV[VX]; S32 j = (S32) pos_region.mV[VY]; S32 half_edge = llfloor(mBrushSize); S32 radioAction = gSavedSettings.getS32("RadioLandBrushAction"); F32 force = gSavedSettings.getF32("LandBrushForce"); // .1 to 100? gGL.begin(LLRender::LINES); for(S32 di = -half_edge; di <= half_edge; di++) { if((i+di) < 0 || (i+di) >= (S32)land.mGridsPerEdge) continue; for(S32 dj = -half_edge; dj <= half_edge; dj++) { if( (j+dj) < 0 || (j+dj) >= (S32)land.mGridsPerEdge ) continue; const F32 wx = pos_world.mV[VX] + di, wy = pos_world.mV[VY] + dj, wz = land.getZ((i+di)+(j+dj)*land.mGridsPerEdge), norm_dist = sqrt((float)di*di + dj*dj) / half_edge, force_scale = sqrt(2.f) - norm_dist, // 1 at center, 0 at corner wz2 = wz + .2 + (.2 + force/100) * force_scale, // top vertex tic = .075f; // arrowhead size // vertical line gGL.vertex3f(wx, wy, wz); gGL.vertex3f(wx, wy, wz2); if(radioAction == E_LAND_RAISE || radioAction == E_LAND_NOISE) // up arrow { gGL.vertex3f(wx, wy, wz2); gGL.vertex3f(wx+tic, wy, wz2-tic); gGL.vertex3f(wx, wy, wz2); gGL.vertex3f(wx-tic, wy, wz2-tic); } if(radioAction == E_LAND_LOWER || radioAction == E_LAND_NOISE) // down arrow { gGL.vertex3f(wx, wy, wz); gGL.vertex3f(wx+tic, wy, wz+tic); gGL.vertex3f(wx, wy, wz); gGL.vertex3f(wx-tic, wy, wz+tic); } if(radioAction == E_LAND_REVERT || radioAction == E_LAND_SMOOTH) // flat top { gGL.vertex3f(wx-tic, wy, wz2); gGL.vertex3f(wx+tic, wy, wz2); } if(radioAction == E_LAND_LEVEL || radioAction == E_LAND_SMOOTH) // flat bottom { gGL.vertex3f(wx-tic, wy, wz); gGL.vertex3f(wx+tic, wy, wz); } } } gGL.end(); glPopMatrix(); }
S32 LLViewerParcelOverlay::renderPropertyLines () { if (!gSavedSettings.getBOOL("ShowPropertyLines")) { return 0; } if (!mVertexArray || !mColorArray) { return 0; } LLSurface& land = mRegion->getLand(); LLGLSUIDefault gls_ui; // called from pipeline gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLDepthTest mDepthTest(GL_TRUE, GL_FALSE); // Find camera height off the ground (not from zero) F32 ground_height_at_camera = land.resolveHeightGlobal( gAgentCamera.getCameraPositionGlobal() ); F32 camera_z = LLViewerCamera::getInstance()->getOrigin().mV[VZ]; F32 camera_height = camera_z - ground_height_at_camera; camera_height = llclamp(camera_height, 0.f, 100.f); // Pull lines toward camera by 1 cm per meter off the ground. const LLVector3& CAMERA_AT = LLViewerCamera::getInstance()->getAtAxis(); F32 pull_toward_camera_scale = 0.01f * camera_height; LLVector3 pull_toward_camera = CAMERA_AT; pull_toward_camera *= -pull_toward_camera_scale; // Always fudge a little vertically. pull_toward_camera.mV[VZ] += 0.01f; gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); // Move to appropriate region coords LLVector3 origin = mRegion->getOriginAgent(); gGL.translatef( origin.mV[VX], origin.mV[VY], origin.mV[VZ] ); gGL.translatef(pull_toward_camera.mV[VX], pull_toward_camera.mV[VY], pull_toward_camera.mV[VZ]); // Include +1 because vertices are fenceposts. // *2 because it's a quad strip const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS ); const S32 vertex_per_edge = 3 + 2 * (GRID_STEP-1) + 3; // Stomp the camera into two dimensions LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() ); // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind // the camera. The cull plane normal is the camera's at axis. LLVector3 cull_plane_point = LLViewerCamera::getInstance()->getAtAxis(); cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS; cull_plane_point += camera_region; LLVector3 vertex; const S32 BYTES_PER_COLOR = 4; const S32 FLOATS_PER_VERTEX = 3; //const S32 FLOATS_PER_TEX_COORD = 2; S32 i, j; S32 drawn = 0; F32* vertexp; U8* colorp; const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; for (i = 0; i < mVertexCount; i += vertex_per_edge) { colorp = mColorArray + BYTES_PER_COLOR * i; vertexp = mVertexArray + FLOATS_PER_VERTEX * i; vertex.mV[VX] = *(vertexp); vertex.mV[VY] = *(vertexp+1); vertex.mV[VZ] = *(vertexp+2); if (dist_vec_squared2D(vertex, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED) { continue; } // Destroy vertex, transform to plane-local. vertex -= cull_plane_point; // negative dot product means it is in back of the plane if ( vertex * CAMERA_AT < 0.f ) { continue; } gGL.begin(LLRender::TRIANGLE_STRIP); for (j = 0; j < vertex_per_edge; j++) { gGL.color4ubv(colorp); gGL.vertex3fv(vertexp); colorp += BYTES_PER_COLOR; vertexp += FLOATS_PER_VERTEX; } drawn += vertex_per_edge; gGL.end(); if (LLSelectMgr::sRenderHiddenSelections && gFloaterTools && gFloaterTools->getVisible()) { LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); colorp = mColorArray + BYTES_PER_COLOR * i; vertexp = mVertexArray + FLOATS_PER_VERTEX * i; gGL.begin(LLRender::TRIANGLE_STRIP); for (j = 0; j < vertex_per_edge; j++) { U8 color[4]; color[0] = colorp[0]; color[1] = colorp[1]; color[2] = colorp[2]; color[3] = colorp[3]/4; gGL.color4ubv(color); gGL.vertex3fv(vertexp); colorp += BYTES_PER_COLOR; vertexp += FLOATS_PER_VERTEX; } drawn += vertex_per_edge; gGL.end(); } } gGL.popMatrix(); return drawn; }