فهرست منبع

remove terrain dependency from mission area

Mission Area now captures the entire level bounds based on objects in the scene
Terrain is no longer required for mission area to be set
marauder2k7 2 ماه پیش
والد
کامیت
0a1e3f74ed

+ 2 - 2
Engine/source/T3D/missionArea.cpp

@@ -51,7 +51,7 @@ ConsoleDocClass( MissionArea,
    "@ingroup enviroMisc\n"
 );
 
-RectI MissionArea::smMissionArea(Point2I(768, 768), Point2I(512, 512));
+RectI MissionArea::smMissionArea(Point2I(-100, -100), Point2I(100, 100));
 
 MissionArea * MissionArea::smServerObject = NULL;
 
@@ -59,7 +59,7 @@ MissionArea * MissionArea::smServerObject = NULL;
 
 MissionArea::MissionArea()
 {
-   mArea.set(Point2I(768, 768), Point2I(512, 512));
+   mArea.set(Point2I(-100, -100), Point2I(100, 100));
    mNetFlags.set(Ghostable | ScopeAlways);
 
    mFlightCeiling      = 2000;

+ 113 - 93
Engine/source/gui/worldEditor/guiMissionArea.cpp

@@ -29,6 +29,13 @@
 #include "gui/3d/guiTSControl.h"
 #include "T3D/gameFunctions.h"
 #include "terrain/terrData.h"
+#include "gfx/gfxTransformSaver.h"
+#include "scene/sceneManager.h"
+#include "scene/sceneRenderState.h"
+#include "lighting/lightManager.h"
+#include "lighting/shadowMap/lightShadowMap.h"
+#include "math/mathUtils.h"
+#include "math/util/frustum.h"
 
 namespace {
    F32 round_local(F32 val)
@@ -65,7 +72,8 @@ GuiMissionAreaCtrl::GuiMissionAreaCtrl()
    mSquareBitmap = true;
 
    mMissionArea = 0;
-   mTerrainBlock = 0;
+   mLevelTexture = NULL;
+   mLevelBounds = Box3F::Zero;
 
    mMissionBoundsColor.set(255,0,0);
    mCameraColor.set(255,0,0);
@@ -75,6 +83,8 @@ GuiMissionAreaCtrl::GuiMissionAreaCtrl()
 
    mLastHitMode = Handle_None;
    mSavedDrag = false;
+
+   mBitmap.set(256, 256, GFXFormatR8G8B8, &GFXRenderTargetProfile, "MissionAreaRenderTarget");
 }
 
 GuiMissionAreaCtrl::~GuiMissionAreaCtrl()
@@ -131,18 +141,7 @@ bool GuiMissionAreaCtrl::onWake()
    if(!Parent::onWake())
       return(false);
 
-   //mMissionArea = const_cast<MissionArea*>(MissionArea::getServerObject());
-   //if(!bool(mMissionArea))
-   //   Con::warnf(ConsoleLogEntry::General, "GuiMissionAreaCtrl::onWake: no MissionArea object.");
-
-   //mTerrainBlock = getTerrainObj();
-   //if(!bool(mTerrainBlock))
-   //   Con::warnf(ConsoleLogEntry::General, "GuiMissionAreaCtrl::onWake: no TerrainBlock object.");
-
-   //if ( !bool(mMissionArea) || !bool(mTerrainBlock) )
-   //   return true;
-
-   updateTerrainBitmap();
+   updateLevelBitmap();
 
    // make sure mission area is clamped
    setArea(getArea());
@@ -157,7 +156,6 @@ void GuiMissionAreaCtrl::onSleep()
 {
    mBitmap = NULL;
    mMissionArea = 0;
-   mTerrainBlock = 0;
 
    Parent::onSleep();
 }
@@ -319,78 +317,97 @@ void GuiMissionAreaCtrl::submitUndo( const UTF8 *name )
 
 //------------------------------------------------------------------------------
 
-void GuiMissionAreaCtrl::updateTerrain()
-{
-   mTerrainBlock = getTerrainObj();
-   updateTerrainBitmap();
-}
-
-TerrainBlock * GuiMissionAreaCtrl::getTerrainObj()
+void GuiMissionAreaCtrl::setMissionArea( MissionArea* area )
 {
-   SimSet * scopeAlwaysSet = Sim::getGhostAlwaysSet();
-   for(SimSet::iterator itr = scopeAlwaysSet->begin(); itr != scopeAlwaysSet->end(); itr++)
+   mMissionArea = area;
+   if( mMissionArea )
    {
-      TerrainBlock * terrain = dynamic_cast<TerrainBlock*>(*itr);
-      if(terrain)
-         return(terrain);
+      setArea(getArea());
    }
-   return(0);
 }
 
-void GuiMissionAreaCtrl::updateTerrainBitmap()
+void GuiMissionAreaCtrl::updateLevelBitmap()
 {
-   GBitmap * bitmap = createTerrainBitmap();
-   if( bitmap )
-      setBitmapHandle( GFXTexHandle( bitmap, &GFXDefaultGUIProfile, true, String("Terrain Bitmap Update") ) );
-   else
-      setBitmap( "" );
-}
+   if (mLevelTexture.isNull())
+      mLevelTexture = GFX->allocRenderToTextureTarget();
 
-GBitmap * GuiMissionAreaCtrl::createTerrainBitmap()
-{
-   if(!mTerrainBlock)
-      return NULL;
+   mLevelTexture->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
+   mLevelTexture->attachTexture(GFXTextureTarget::Color0, mBitmap);
 
-   GBitmap * bitmap = new GBitmap(mTerrainBlock->getBlockSize(), mTerrainBlock->getBlockSize(), false, GFXFormatR8G8B8 );
+   mLevelBounds = Box3F::Zero;
 
-   // get the min/max
-   F32 min, max;
-   mTerrainBlock->getMinMaxHeight(&min, &max);
+   for (SimSetIterator iter(Sim::getRootGroup()); *iter; ++iter)
+   {
+      SceneObject* obj = dynamic_cast<SceneObject*>(*iter);
+      if (!obj)
+         continue;
 
-   F32 diff = max - min;
-   F32 colRange = 255.0f / diff;
+      // Skip if bounds are too large (e.g., GroundPlane or visual-only objects)
+      const Box3F& box = obj->getWorldBox();
+      const F32 maxSizeThreshold = 2048.0f; // or tweak for your game scale
 
-   // This method allocates it's bitmap above, and does all assignment
-   // in the following loop. It is not subject to 24-bit -> 32-bit conversion
-   // problems, because the texture handle creation is where the conversion would
-   // occur, if it occurs. Since the data in the texture is never read back, and
-   // the bitmap is deleted after texture-upload, this is not a problem.
-   for(S32 y = 0; y < mTerrainBlock->getBlockSize() ; y++)
-   {
-      for(S32 x = 0; x < mTerrainBlock->getBlockSize(); x++)
-      {
-         F32 height;
-         height = mTerrainBlock->getHeight(Point2I(x, y));
- 
-         U8 col = U8((height - min) * colRange);
-         ColorI color(col, col, col);
-         bitmap->setColor(x, y, color);
-    
-      }
+      VectorF extents = box.getExtents();
+      if (extents.x > maxSizeThreshold || extents.y > maxSizeThreshold)
+         continue;
+
+      // Merge bounds
+      mLevelBounds.intersect(box);
    }
 
-   return(bitmap);
-}
+   GFXTransformSaver saver;
 
-//------------------------------------------------------------------------------
+   // Calculate orthographic dimensions
+   Point3F minPt = mLevelBounds.minExtents;
+   Point3F maxPt = mLevelBounds.maxExtents;
 
-void GuiMissionAreaCtrl::setMissionArea( MissionArea* area )
-{
-   mMissionArea = area;
-   if( mMissionArea )
-   {
-      setArea(getArea());
-   }
+   F32 orthoWidth = maxPt.x - minPt.x;
+   F32 orthoHeight = maxPt.y - minPt.y;
+   F32 nearPlane = 0.01f;
+   F32 farPlane = 1000.0f;
+
+   // Set orthographic projection centered around level bounds
+   GFX->setOrtho(
+      -orthoWidth * 0.5f, orthoWidth * 0.5f,  // left/right
+      -orthoHeight * 0.5f, orthoHeight * 0.5f, // bottom/top
+      nearPlane, farPlane,
+      true // flip y
+   );
+
+   GFX->pushActiveRenderTarget();
+
+   // create camera matrix
+   MatrixF lightMatrix(true);
+   VectorF eye = mLevelBounds.getCenter();
+   eye.z += 500.0f;
+   lightMatrix.LookAt(eye, VectorF(0.0f, 0.0f, -1.0f), VectorF(0.0f, -1.0f, 0.0f));
+   lightMatrix.inverse();
+
+   GFX->setWorldMatrix(lightMatrix);
+   GFX->clearTextureStateImmediate(0);
+
+   GFX->setActiveRenderTarget(mLevelTexture);
+   GFX->clear(GFXClearStencil | GFXClearTarget | GFXClearZBuffer, ColorI::BLACK, 1.0f, 0);
+
+   SceneRenderState reflectRenderState
+   (
+      gClientSceneGraph,
+      SPT_Reflect,
+      SceneCameraState::fromGFX()
+   );
+
+   // We don't use a special clipping projection, but still need to initialize 
+   // this for objects like SkyBox which will use it during a reflect pass.
+   gClientSceneGraph->setNonClipProjection(GFX->getProjectionMatrix());
+
+   // render scene
+   LIGHTMGR->registerGlobalLights(&reflectRenderState.getCullingFrustum(), false);
+   gClientSceneGraph->renderSceneNoLights(&reflectRenderState);
+   LIGHTMGR->unregisterAllLights();
+
+   // Clean up.
+   mLevelTexture->resolve();
+
+   GFX->popActiveRenderTarget();
 }
 
 const RectI & GuiMissionAreaCtrl::getArea()
@@ -503,31 +520,33 @@ Point2I GuiMissionAreaCtrl::screenDeltaToWorldDelta(const Point2I &screenPoint)
    return(Point2I(S32(screenPoint.x / mScale.x), S32(screenPoint.y / mScale.y)));
 }
 
-void GuiMissionAreaCtrl::setupScreenTransform(const Point2I & offset)
+void GuiMissionAreaCtrl::setupScreenTransform(const Point2I& offset)
 {
-   const MatrixF & terrMat = mTerrainBlock->getTransform();
-   Point3F terrPos;
-   terrMat.getColumn(3, &terrPos);
-   terrPos.z = 0;
+   // Compute 2D size of the bounding box
+   Point2F boxSize(mLevelBounds.len_x(), mLevelBounds.len_y());
+   Point2F boxMin(mLevelBounds.minExtents.x, mLevelBounds.minExtents.y);
+   Point2F boxCenter = Point2F(mLevelBounds.getCenter().x, mLevelBounds.getCenter().y);
 
-   F32 terrDim = mTerrainBlock->getWorldBlockSize();
+   // GUI control size
+   const Point2I& extenti = getExtent();
+   Point2F extent((F32)extenti.x, (F32)extenti.y);
 
-   const Point2I& extenti = getExtent( );
-   Point2F extent( static_cast<F32>( extenti.x ), static_cast<F32>( extenti.y ) );
-
-   if(mSquareBitmap)
+   // Maintain square aspect ratio if requested
+   if (mSquareBitmap)
       extent.x > extent.y ? extent.x = extent.y : extent.y = extent.x;
 
-   // We need to negate the y-axis so we are correctly oriented with
-   // positive y increase up the screen.
-   mScale.set(extent.x / terrDim, -extent.y / terrDim, 0);
+   // Compute scale (how many pixels per world unit)
+   mScale.set(extent.x / boxSize.x, -extent.y / boxSize.y, 0); // Y flipped
+
+   // Instead of offsetting the center to (0,0), we want to place the box center at GUI center
+   // So we compute the world-to-screen offset for center
+   Point2F screenCenter((F32)offset.x + extent.x * 0.5f, (F32)offset.y + extent.y * 0.5f);
 
-   Point3F terrOffset = -terrPos;
-   terrOffset.convolve(mScale);
+   Point2F worldCenterOffset = boxCenter * Point2F(mScale.x, mScale.y);
 
-   // We need to add the y extent so we start from the bottom left of the control
-   // rather than the top left.
-   mCenterPos.set(terrOffset.x + F32(offset.x), terrOffset.y + F32(offset.y) + extent.y);
+   // Compute the final offset that maps world center to screen center
+   mCenterPos.set(screenCenter.x - worldCenterOffset.x,
+      screenCenter.y - worldCenterOffset.y);
 }
 
 void GuiMissionAreaCtrl::getScreenMissionArea(RectI & rect)
@@ -575,7 +594,7 @@ void GuiMissionAreaCtrl::onRender(Point2I offset, const RectI & updateRect)
    setUpdate();
 
    // draw an x
-   if(!bool(mMissionArea) || !bool(mTerrainBlock))
+   if(!bool(mMissionArea))
    {
       GFX->setStateBlock(mSolidStateBlock);
       PrimBuild::color3i( 0, 0, 0 );
@@ -683,12 +702,13 @@ DefineEngineMethod( GuiMissionAreaCtrl, setMissionArea, void, ( MissionArea* are
    object->setMissionArea( area );
 }
 
-DefineEngineMethod( GuiMissionAreaCtrl, updateTerrain, void, ( ),,
-   "@brief Update the terrain bitmap.\n\n")
+DefineEngineMethod(GuiMissionAreaCtrl, updateLevelBitmap, void, (), ,
+   "@brief Update the level bitmap and bounds.\n\n")
 {
-   object->updateTerrain();
+   object->updateLevelBitmap();
 }
 
+
 //------------------------------------------------------------------------------
 
 void GuiMissionAreaUndoAction::undo()

+ 3 - 6
Engine/source/gui/worldEditor/guiMissionArea.h

@@ -58,10 +58,11 @@ protected:
    };
 
    SimObjectPtr<MissionArea>  mMissionArea;
-   SimObjectPtr<TerrainBlock> mTerrainBlock;
 
    GFXStateBlockRef  mBlendStateBlock;
    GFXStateBlockRef  mSolidStateBlock;
+   GFXTextureTargetRef mLevelTexture;
+   Box3F mLevelBounds;
 
    DECLARE_IMAGEASSET(GuiMissionAreaCtrl, HandleBitmap, GFXDefaultGUIProfile)
 
@@ -82,10 +83,6 @@ protected:
 
    void submitUndo( const UTF8 *name = "Action" );
 
-   TerrainBlock * getTerrainObj();
-   GBitmap * createTerrainBitmap();
-   void updateTerrainBitmap();
-
    //void onUpdate();
 
    void setupScreenTransform(const Point2I & offset);
@@ -132,7 +129,7 @@ public:
    void onMouseLeave(const GuiEvent & event) override;
 
    void setMissionArea( MissionArea* area );
-   void updateTerrain();
+   void updateLevelBitmap();
 
    const RectI & getArea();
    void setArea(const RectI & area);

+ 2 - 2
Templates/BaseGame/game/tools/missionAreaEditor/main.tscript

@@ -137,7 +137,7 @@ function MissionAreaEditorPlugin::readSettings( %this )
 {
    EditorSettings.beginGroup( "MissionAreaEditor", true );
    
-   MissionAreaEditorTerrainEditor.missionBoundsColor     = EditorSettings.value("MissionBoundsColor");
+   MissionAreaEditorLevelEditor.missionBoundsColor     = EditorSettings.value("MissionBoundsColor");
    
    EditorSettings.endGroup();  
 }
@@ -146,7 +146,7 @@ function MissionAreaEditorPlugin::writeSettings( %this )
 {
    EditorSettings.beginGroup( "MissionAreaEditor", true );
    
-   EditorSettings.setValue( "MissionBoundsColor",     MissionAreaEditorTerrainEditor.missionBoundsColor );
+   EditorSettings.setValue( "MissionBoundsColor",     MissionAreaEditorLevelEditor.missionBoundsColor );
 
    EditorSettings.endGroup();
 }

+ 1 - 1
Templates/BaseGame/game/tools/missionAreaEditor/missionAreaEditorGui.ed.gui

@@ -79,7 +79,7 @@ $guiContent = new GuiMissionAreaEditorCtrl(MissionAreaEditorGui, EditorGuiGroup)
          VertSizing = "height";
          isContainer = "1";
          
-         new GuiMissionAreaCtrl(MissionAreaEditorTerrainEditor) {
+         new GuiMissionAreaCtrl(MissionAreaEditorLevelEditor) {
             canSaveDynamicFields = "0";
             isContainer = "0";
             Profile = "EditorDefaultProfile";

+ 4 - 4
Templates/BaseGame/game/tools/missionAreaEditor/missionAreaEditorGui.ed.tscript

@@ -290,7 +290,7 @@ function MissionAreaEditorGui::onEditorActivated( %this )
    {
       EWorldEditor.selectObject( %ma );
       EWorldEditor.syncGui();
-      MissionAreaEditorTerrainEditor.updateTerrain();
+      MissionAreaEditorLevelEditor.updateLevelBitmap();
       %this.setSelectedMissionArea( %ma );
       %this.onMissionAreaSelected( %this.getSelectedMissionArea() );   
    }
@@ -303,18 +303,18 @@ function MissionAreaEditorGui::onEditorDeactivated( %this )
 function MissionAreaEditorGui::onMissionAreaSelected( %this, %missionArea )
 {
    %this.missionArea = %missionArea;
-   MissionAreaEditorTerrainEditor.setMissionArea( %missionArea );
+   MissionAreaEditorLevelEditor.setMissionArea( %missionArea );
    MissionAreaInspector.inspect( %missionArea );  
 }
 
 //-----------------------------------------------------------------------------
 
-function MissionAreaEditorTerrainEditor::onMissionAreaModified( %this )
+function MissionAreaEditorLevelEditor::onMissionAreaModified( %this )
 {
    MissionAreaInspector.refresh();
 }
 
-function MissionAreaEditorTerrainEditor::onUndo( %this )
+function MissionAreaEditorLevelEditor::onUndo( %this )
 {
    MissionAreaInspector.refresh();
 }