void EditTSCtrl::onRightMouseDown(const GuiEvent & event) { // always process the right mouse event first... mRightMouseDown = true; mLastBorderMoveTime = 0; make3DMouseEvent(mLastEvent, event); on3DRightMouseDown(mLastEvent); if(!mLeftMouseDown && mRightMousePassThru && mProfile->mCanKeyFocus) { GuiCanvas *pCanvas = getRoot(); if( !pCanvas ) return; PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow(); if( !pWindow ) return; PlatformCursorController *pController = pWindow->getCursorController(); if( !pController ) return; // ok, gotta disable the mouse // script functions are lockMouse(true); Canvas.cursorOff(); pWindow->setMouseLocked(true); pCanvas->setCursorON( false ); if(mDisplayType != DisplayTypePerspective) { mouseLock(); mLastMousePos = event.mousePoint; pCanvas->setForceMouseToGUI(true); mLastMouseClamping = pCanvas->getClampTorqueCursor(); pCanvas->setClampTorqueCursor(false); } if(mDisplayType == DisplayTypeIsometric) { // Store the screen center point on the terrain for a possible rotation TerrainBlock* activeTerrain = getActiveTerrain(); if( activeTerrain ) { F32 extx, exty; if(event.modifier & SI_SHIFT) { extx = F32(event.mousePoint.x); exty = F32(event.mousePoint.y); } else { extx = getExtent().x * 0.5; exty = getExtent().y * 0.5; } Point3F sp(extx, exty, 0.0f); // Near plane projection Point3F start; unproject(sp, &start); Point3F end = start + mLastEvent.vec * 4000.0f; Point3F tStartPnt, tEndPnt; activeTerrain->getTransform().mulP(start, &tStartPnt); activeTerrain->getTransform().mulP(end, &tEndPnt); RayInfo info; bool result = activeTerrain->castRay(tStartPnt, tEndPnt, &info); if(result) { info.point.interpolate(start, end, info.t); mIsoCamRotCenter = info.point; } else { mIsoCamRotCenter = start; } } else { F32 extx = getExtent().x * 0.5; F32 exty = getExtent().y * 0.5; Point3F sp(extx, exty, 0.0f); // Near plane projection unproject(sp, &mIsoCamRotCenter); } } setFirstResponder(); } }
void BrushAdjustHeightAction::process(Selection * sel, const Gui3DMouseEvent & event, bool, Type type) { if(type == Process) return; TerrainBlock *terrBlock = mTerrainEditor->getActiveTerrain(); if ( !terrBlock ) return; if(type == Begin) { mTerrainEditor->lockSelection(true); mTerrainEditor->getRoot()->mouseLock(mTerrainEditor); // the way this works is: // construct a plane that goes through the collision point // with one axis up the terrain Z, and horizontally parallel to the // plane of projection // the cross of the camera ffdv and the terrain up vector produces // the cross plane vector. // all subsequent mouse actions are collided against the plane and the deltaZ // from the previous position is used to delta the selection up and down. Point3F cameraDir; EditTSCtrl::smCamMatrix.getColumn(1, &cameraDir); terrBlock->getTransform().getColumn(2, &mTerrainUpVector); // ok, get the cross vector for the plane: Point3F planeCross; mCross(cameraDir, mTerrainUpVector, &planeCross); planeCross.normalize(); Point3F planeNormal; Point3F intersectPoint; mTerrainEditor->collide(event, intersectPoint); mCross(mTerrainUpVector, planeCross, &planeNormal); mIntersectionPlane.set(intersectPoint, planeNormal); // ok, we have the intersection point... // project the collision point onto the up vector of the terrain mPreviousZ = mDot(mTerrainUpVector, intersectPoint); // add to undo // and record the starting heights for(U32 i = 0; i < sel->size(); i++) { mTerrainEditor->getUndoSel()->add((*sel)[i]); (*sel)[i].mStartHeight = (*sel)[i].mHeight; } } else if(type == Update) { // ok, collide the ray from the event with the intersection plane: Point3F intersectPoint; Point3F start = event.pos; Point3F end = start + event.vec * 1000; F32 t = mIntersectionPlane.intersect(start, end); m_point3F_interpolate( start, end, t, intersectPoint); F32 currentZ = mDot(mTerrainUpVector, intersectPoint); F32 diff = currentZ - mPreviousZ; for(U32 i = 0; i < sel->size(); i++) { (*sel)[i].mHeight = (*sel)[i].mStartHeight + diff * (*sel)[i].mWeight; // clamp it if((*sel)[i].mHeight < 0.f) (*sel)[i].mHeight = 0.f; if((*sel)[i].mHeight > 2047.f) (*sel)[i].mHeight = 2047.f; mTerrainEditor->setGridInfoHeight((*sel)[i]); } mTerrainEditor->scheduleGridUpdate(); } else if(type == End) { mTerrainEditor->getRoot()->mouseUnlock(mTerrainEditor); } }
void blTerrainProxy::lightVector(LightInfo * light) { // Grab our terrain object TerrainBlock* terrain = getObject(); if (!terrain) return; // Get the direction to the light (the inverse of the direction // the light is pointing) Point3F lightDir = -light->getDirection(); lightDir.normalize(); // Get the ratio between the light map pixel and world space (used below) F32 lmTerrRatio = (F32)mTerrainBlockSize / (F32) mLightMapSize; lmTerrRatio *= terrain->getSquareSize(); // Get the terrain position Point3F terrPos( terrain->getTransform().getPosition() ); U32 i = 0; for (U32 y = 0; y < mLightMapSize; y++) { for (U32 x = 0; x < mLightMapSize; x++) { // Get the relative pixel position and scale it // by the ratio between lightmap and world space Point2F pixelPos(x, y); pixelPos *= lmTerrRatio; // Start with a default normal of straight up Point3F normal(0.0f, 0.0f, 1.0f); // Try to get the actual normal from the terrain. // Note: this won't change the default normal if // it can't find a normal. terrain->getNormal(pixelPos, &normal); // The terrain lightmap only contains shadows. F32 shadowed = 0.0f; // Get the height at the lightmap pixel's position F32 height = 0.0f; terrain->getHeight(pixelPos, &height); // Calculate the 3D position of the pixel Point3F pixelPos3F(pixelPos.x, pixelPos.y, height); // Translate that position by the terrain's transform terrain->getTransform().mulP(pixelPos3F); // Offset slighting along the normal so that we don't // raycast into ourself pixelPos3F += (normal * 0.1f); // Calculate the light's position. // If it is a vector light like the sun (no position // just direction) then translate along that direction // a reasonable distance to get a point sufficiently // far away Point3F lightPos = light->getPosition(); if(light->getType() == LightInfo::Vector) { lightPos = 1000.f * lightDir; lightPos = pixelPos3F + lightPos; } // Cast a ray from the world space position of the lightmap pixel to the light source. // If we hit something then we are in shadow. This allows us to be shadowed by anything // that supports a castRay operation. RayInfo info; if(terrain->getContainer()->castRay(pixelPos3F, lightPos, STATIC_COLLISION_TYPEMASK, &info)) { // Shadow the pixel. shadowed = 1.0f; } // Set the final lightmap color. mLightmap[i++] += ColorF::WHITE * mClampF( 1.0f - shadowed, 0.0f, 1.0f ); } } }