Game Development Community

dev|Pro Game Development Curriculum

fxGuiSnooper TGEA

by Shaderman · 11/12/2007 (1:44 pm) · 14 comments

Download Code File

I've ported Melvyn's work to TGEA (1.0.3). Here are the setup instructions / properties (copied from his resource):

Allows you to show the scene from any named objects' viewpoint. You can setup automatic sweeping (like a security camera) in all axis as well as put a bitmap/colour overlay for the finishing effect.

Before I get started I would just like to point out that this control will seriously affect your framerate as you are effectively rendering another view so you could see your framerate drop by half in some circumstances. Saying that, if you use it like a security camera / monitoring device then you can place it on a seperate GUI screen so that you maintain your FPS.

Add the file "fxGuiSnooper.cpp" to your engine code, compile and you should have a new control named "fxGuiSnooper" in the controls list within the GUI editor.

The "camera.png" can be used as an example for the bitmap overlay (not a very good one I might add) but is not needed otherwise.

The properties explained are:-
(All angles are in degrees)

"ViewRotation" - Sets an initial rotation to the view.

"ViewOffset" - Sets an initial translation to the view.

"FOV" - Sets the Field-of-view. (Hmmm!)

"SweepAmplitude" - Sets the magnitude to which the view will automatically sweep. You can individually select each axis XYZ. The sweep will be centered around the initial rotation e.g 60 = (-30)->(+30).

"SweepTime" - Sets the time constants for the sweep to complete. Again, you can individually select the time for each axis. The time is in mS e.g. 1000mS = 1 Sec. Sweeping will continue for an infinite period.

"AttachedObject" - Sets the object to which the view will be attached. Essentially, the view will use the objects' position as a bsae for snooping. If you move the object, then the view should move with it. Try naming a tree or building as a test.

"OverlayBitmap" - Sets the bitmap which will be overlayed ontop of the view. This allows you to blend/obscure the view for screen effects such as interlacing/moire fringing etc.

"OverlayTile" - Sets the bitmap tile mode. When on, the bitmap will be tessellated over the view.

"OverlayColour" - Sets the overlay colour mode. When on, the overlay colour/mask settings are used to colourise the view so you can do green-screens etc. (See my fxGuiFilter control).

"BitmapOverlay" - Selects the bitmap filename to use for the overlay. Using "fps/client/ui/" is a good idea.

"ColourOverlay" - Selects the RGB colours used for the colourisation effect.

"Red/Green/BlueMask" - Selects the masking effect used for the colourisation effect. A tick indicates that that colour channel can be written to using the ColourOverlay.

Thanks for sharing Melvyn!

Stefan

#1
11/21/2007 (6:17 am)
Thanks :D

Perhaps you could port GuiObjectView as well? ;)
#2
12/01/2007 (4:40 am)
James, that is already working @ a decent extent.
http://www.garagegames.com/mg/forums/result.thread.php?qt=58720
#3
12/01/2007 (5:08 am)
Yeh I found that after I ported it over myself :P
#4
07/15/2008 (8:46 pm)
I have been trying to update this to TGEA 1.7.1 and ran into a little problem.

When the gui renders it is producing an odd picture in picture effect.

#5
07/16/2008 (11:24 am)
Just realized it doesn't help much without code.

fxGuiSnooper.cpp
#include "sceneGraph/sceneGraph.h"
#include "T3D/gameConnection.h"
#include "console/consoleTypes.h"
#include "gui/3d/guiTSControl.h"

#include "gui/core/guiControl.h"

class GuiSnooper : public GuiTSCtrl
{
private:
	typedef GuiTSCtrl Parent;

	Point3F				mRotateView;					// View Rotation.
	Point3F				mOffsetView;					// Offset Distance.
	F32					mFov;							// Field of View.
	Point3F				mSweepAmplitude;				// Sweep Amplitude.
	Point3F				mSweepTime;						// Sweep Time.

	bool				mUseOverlayBitmap;				// Use Overlay Bitmap Flag.
	bool				mUseOverlayColour;				// Use Overlay Colour Flag.
	bool				mOverlayTile;					// Overlay Tile Flag.
	ColorF				mOverlayColor;					// Filter Colour Vector.
	bool				mOverlayRedMask;				// Overlay Red Mask Flag.
	bool				mOverlayGreenMask;				// Overlay Green Mask Flag.
	bool				mOverlayBlueMask;				// Overlay Blue Mask Flag.

	StringTableEntry	mObjectName;					// Attached Object Name.
	SceneObject*		mAttachedObject;				// Attached Object.

	U32					mLastTimeStamp;					// Last Time Stamp.
	Point3F				mCurrentSweepMagnitude;			// Current Sweep Phase.
	StringTableEntry	mOverlayBitmapName;				// Overlay Bitmap Name.
	GFXTexHandle		mOverlayTextureHandle;			// Overlay Texture Handle.

	void renderWorld(const RectI & updateRect);
	void onRender(Point2I offset, const RectI &updateRect);

public:
	GuiSnooper();

	static void initPersistFields();
	static void consoleInit();

	bool processCameraQuery(CameraQuery * query);

	void setViewObject(const char* ObjectName);
	void setViewRotation(Point3F Rotation);
	void setOverlayBitmap(const char *name);
	void setOverlayColor(ColorF OverlayColor);
	void setOverlayMask(bool RedMask, bool GreenMask, bool BlueMask);

	bool onWake(); 
	void onSleep();

	DECLARE_CONOBJECT(GuiSnooper);
};

IMPLEMENT_CONOBJECT(GuiSnooper);

//------------------------------------------------------------------------------


GuiSnooper::GuiSnooper() :
	mRotateView(0,0,0),
	mOffsetView(0,0,0),
	mFov(60.0),
	mSweepAmplitude(0,0,60),
	mSweepTime(5000,5000,5000),
	mCurrentSweepMagnitude(0,0,0),
	mAttachedObject(NULL),
	mOverlayRedMask(true),
	mOverlayGreenMask(true),
	mOverlayBlueMask(true),
	mOverlayTile(false),
	mUseOverlayBitmap(false),
	mUseOverlayColour(false),
	mLastTimeStamp(Platform::getRealMilliseconds())
{
	// Create Empty Attached Object Name.
	mObjectName = StringTable->insert("");

	// Create Empty Overlay Bitmap Name.
	mOverlayBitmapName = StringTable->insert("");

	// Set Default Overlay Colour.
	mOverlayColor.set(1, 1, 1, 0.5f);
};

//------------------------------------------------------------------------------

void GuiSnooper::initPersistFields()
{
	// Initialise parents' persistent fields.
	Parent::initPersistFields();

	// Add out own persistent fields.
	addField( "ViewRotation", TypePoint3F, Offset( mRotateView, GuiSnooper ) );
	addField( "ViewOffset", TypePoint3F, Offset( mOffsetView, GuiSnooper ) );
	addField( "FOV", TypeF32, Offset( mFov, GuiSnooper ) );
	addField( "SweepAmplitude", TypePoint3F, Offset( mSweepAmplitude, GuiSnooper ) );
	addField( "SweepTime", TypePoint3F, Offset( mSweepTime, GuiSnooper ) );
	addField( "AttachedObject", TypeString, Offset( mObjectName, GuiSnooper ) );
	addField( "OverlayBitmap", TypeBool, Offset( mUseOverlayBitmap, GuiSnooper ) );
	addField( "OverlayTile", TypeBool, Offset( mOverlayTile, GuiSnooper ) );
	addField( "OverlayColour", TypeBool, Offset( mUseOverlayColour, GuiSnooper ) );
	addField( "BitmapOverlay", TypeFilename, Offset(mOverlayBitmapName, GuiSnooper));
	addField( "ColorOverlay", TypeColorF, Offset( mOverlayColor, GuiSnooper ) );
	addField( "RedMask", TypeBool, Offset( mOverlayRedMask, GuiSnooper ) );
	addField( "GreenMask", TypeBool, Offset( mOverlayGreenMask, GuiSnooper ) );
	addField( "BlueMask", TypeBool, Offset( mOverlayBlueMask, GuiSnooper ) );
}

//------------------------------------------------------------------------------

bool GuiSnooper::onWake()
{
	// Wake-up Parent.
	if (!Parent::onWake()) return false;

	// Set Active.
	setActive(true);

	// Have we an Attached Object Name?
	if (mObjectName)
	{
		// Yes, so attach to it.
		setViewObject(mObjectName);
	}

	// Set Overlay Bitmap.
	setOverlayBitmap(mOverlayBitmapName);

	// Return OK.
	return true;
}

//------------------------------------------------------------------------------

void GuiSnooper::onSleep()
{
	// Reset Overlay Texture Handle.
	mOverlayTextureHandle = NULL;
	// Call Parent.
	Parent::onSleep();
}

//------------------------------------------------------------------------------

void GuiSnooper::setViewRotation(Point3F Rotation)
{
	// Set the Rotation internally.
	mRotateView = Rotation;
}

//------------------------------------------------------------------------------

void GuiSnooper::setViewObject(const char* ObjectName)
{
	// Get Root Group.
	SimGroup* SG = Sim::getRootGroup();

	// Interate Sim Group.
	for (SimSetIterator itr(SG); *itr; ++itr)
	{
		// Is this our Type?
		if ((*itr)->getType() & STATIC_COLLISION_MASK)
		{
			// Yes, so cast our Object.
			SceneObject* SceneObj = static_cast<SceneObject*>(*itr);
			// Check that it's a Server Object.
			if (SceneObj->isServerObject())
			{
				const char* getName;

				getName = SceneObj->getName();

				// Yes, so is this our Object?
				if (getName && dStrcmp(getName, ObjectName) == 0)
				{
					// Store Scene Object.
					mAttachedObject = SceneObj;

					// Return OK.
					return;
				}
			}
		}
	}

	// Reset Object.
	mAttachedObject = NULL;

}

//------------------------------------------------------------------------------

void GuiSnooper::setOverlayBitmap(const char *name)
{
	// Set Overlay Bitmap Name.
	mOverlayBitmapName = StringTable->insert(name);

	if (*mOverlayBitmapName)
		// Yes, so get Texture Handle.
	    mOverlayTextureHandle.set( mOverlayBitmapName, &GFXDefaultGUIProfile );
	else
		// No, so reset Texture Handle.
		mOverlayTextureHandle = NULL;

	// Update.
	setUpdate();
}   

//------------------------------------------------------------------------------

void GuiSnooper::setOverlayColor(ColorF OverlayColor)
{
	// Set the Overlay Colour internally.
	mOverlayColor = OverlayColor;
}

//------------------------------------------------------------------------------

void GuiSnooper::setOverlayMask(bool RedMask, bool GreenMask, bool BlueMask)
{
	// Set the Overlay Masks internally.
	mOverlayRedMask		= RedMask;
	mOverlayGreenMask	= GreenMask;
	mOverlayBlueMask	= BlueMask;
}

//------------------------------------------------------------------------------

ConsoleMethod(GuiSnooper,setViewRotation,void,5,5,"Sets View Rotation.")
{
	Point3F		Rotation;

	// Fetch the GuiSnooper object.
	GuiSnooper *Viewport = static_cast<GuiSnooper*>(object);

	// Fetch Rotation.
	Rotation.set(	mDegToRad(dAtof(argv[2])),
					mDegToRad(dAtof(argv[3])),
					mDegToRad(dAtof(argv[4])));

	// Set Rotation.
	Viewport->setViewRotation(Rotation);
}

//------------------------------------------------------------------------------

ConsoleMethod(GuiSnooper,setViewObject,void,3,3,"Sets View to Object.")
{
//	F32		Rotation;

	// Fetch the GuiSnooper object.
	GuiSnooper *Viewport = static_cast<GuiSnooper*>(object);

	// Set the GuiFilter Filter Colour.
	Viewport->setViewObject(argv[2]);
}

//------------------------------------------------------------------------------

ConsoleMethod(GuiSnooper,setOverlayBitmap,void,3,3,"Sets Overlay Bitmap.")
{
	// Fetch the GuiSnooper object.
	GuiSnooper *Viewport = static_cast<GuiSnooper*>(object);

	// Set Overlay Bitmap.
	Viewport->setOverlayBitmap(argv[2]);
}

//------------------------------------------------------------------------------

ConsoleMethod(GuiSnooper,setOverlayColor,void,5,6,"Sets Overlay Color.")
{
	F32		r,g,b,a;
	ColorF	TempColor;

	// Fetch the GuiSnooper object.
	GuiSnooper *Viewport = static_cast<GuiSnooper*>(object);

	// Convert RGB Ascii parms to float.
	r = dAtof(argv[2]);
	g = dAtof(argv[3]);
	b = dAtof(argv[4]);

	// Did we get an alpha param?
	if (argc == 6)
		// Yep, so convert it.
		a = dAtof(argv[5]);
	else
		// Nope, so default to 1.
		a = 1;

	// Setup our temporary colour vector.
	TempColor.set(r,g,b,a);

	// Set the GuiSnooper Overlay Colour.
	Viewport->setOverlayColor(TempColor);
}

//------------------------------------------------------------------------------

ConsoleMethod(GuiSnooper,setOverlayMask,void,5,5,"Sets Overlay Masks.")
{
	F32		r,g,b;

	// Fetch the GuiSnooper object.
	GuiSnooper *Viewport = static_cast<GuiSnooper*>(object);

	// Convert RGB Ascii parms to float.
	r = dAtof(argv[2]);
	g = dAtof(argv[3]);
	b = dAtof(argv[4]);

	// Set the GuiSnooper Masks.
	Viewport->setOverlayMask(r,g,b);
}

//------------------------------------------------------------------------------

static void cfxGuiBitmapSetOverlayBitmap(SimObject *obj, S32, const char **argv)
{
	// Fetch HUD Control.
	GuiSnooper *ctrl = static_cast<GuiSnooper*>(obj);

	// Set Overlay Bitmap.
	ctrl->setOverlayBitmap(argv[2]);
}

//------------------------------------------------------------------------------

void GuiSnooper::consoleInit()
{
   Con::addCommand("GuiSnooper", "setOverlayBitmap",  cfxGuiBitmapSetOverlayBitmap, "GuiSnooper.setOverlayBitmap(Bitmap)", 3, 3);
}

//------------------------------------------------------------------------------

void GuiSnooper::renderWorld(const RectI & updateRect)
{
	GFX->clear(GFXClearZBuffer, ColorI(0,0,0), 1.0f, 0);
	GFX->setZEnable(true);
	GFX->setZWriteEnable(true);
	GFX->setZFunc(GFXCmpLessEqual);
	GFX->setCullMode(GFXCullNone);


	// Render Client Scene Graph.
	gClientSceneGraph->renderScene();

	GFX->setZEnable(false);
}

//------------------------------------------------------------------------------

void GuiSnooper::onRender(Point2I offset, const RectI &updateRect)
{
	// Call Parent Render.
	Parent::onRender(offset, updateRect);

	// Set Clipping Rectangle to GUI Bounds.
	GFX->setClipRect(getBounds());

	// Do we have an attached Object?
	if (!mAttachedObject)
	{
		// No, so signal to user this problem ...
		ColorF ErrorColor(1,0,0);
		GFX->getDrawUtil()->drawRectFill(updateRect, ErrorColor);
		ErrorColor.set(1,1,1);
		char buf[256];
		dSprintf(buf, sizeof(buf), "*** Object not selected ***");
		GFX->getDrawUtil()->setBitmapModulation(ErrorColor);
		GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
		GFX->getDrawUtil()->clearBitmapModulation();

		// Return Error.
		return;
	}

	// Are we using the Overlay Bitmap?
	if (mUseOverlayBitmap)
	{
		// Yes, so do we have a texture Handle?
		if (mOverlayTextureHandle)
		{
			// Yes, so clear Bitmap Modulation.
			GFX->getDrawUtil()->clearBitmapModulation();

			// Are we tiling the Overlay Bitmap?
			if(mOverlayTile)
			{
				RectI SrcRegion;
				RectI DstRegion;

				// Yes, so fetch texture object.
				GFXTextureObject* TextureObj = mOverlayTextureHandle;

				// Calculate Tesselation Count.
				float XTess = ((float)mBounds.extent.x/(float)TextureObj->mBitmapSize.x)+1;
				float YTess = ((float)mBounds.extent.y/(float)TextureObj->mBitmapSize.y)+1;

				for(int y = 0; y < YTess; ++y)
				{
					for(int x = 0; x < XTess; ++x)
					{
						// Calculate Source Region.
						SrcRegion.set(0,0,TextureObj->mBitmapSize.x, TextureObj->mBitmapSize.y);

						// Calculate Destination Region.
						DstRegion.set(((TextureObj->mBitmapSize.x*x)+offset.x),
									  ((TextureObj->mBitmapSize.y*y)+offset.y),
									  TextureObj->mBitmapSize.x,	
									  TextureObj->mBitmapSize.y);

						// Draw Tiled Bitmap.
						GFX->getDrawUtil()->drawBitmapStretchSR(TextureObj, DstRegion, SrcRegion);
					}
				}
			}
			else
			{
				// No, so draw stretched Bitmap.
				GFX->getDrawUtil()->drawBitmapStretch(mOverlayTextureHandle, mBounds);
			}
		}
	}

	// Are we using the Overlay Colour?
	if (mUseOverlayColour)
	{
		// Set Colour Mask.
		GFX->enableColorWrites(mOverlayRedMask, mOverlayGreenMask, mOverlayBlueMask, true);

		// Draw our filled rectangle with the Filter Colour.
		GFX->getDrawUtil()->drawRectFill(updateRect, mOverlayColor);

		// Reset the Colour Mask.
		GFX->enableColorWrites(true, true, true, true);
	}
}

//------------------------------------------------------------------------------

bool GuiSnooper::processCameraQuery(CameraQuery * query)
{
	Point3F		CameraRotation;							// Rotated View.
	float		VisibleDistance = 1100.0f;				// Visible Distance.


	// Get Game Connection.
	GameConnection* pConnection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());

	// Did we get the connection?
	if (pConnection)
	{
		// Have we got an Attached Object?
		if (mAttachedObject)
		{
			// Current Sweep.
			EulerF mCurrentSweep;

			// Create Camera Matrix.
			MatrixF	Camera(true);

			// Craete Rotation Quaternion.
			QuatF	QRotation;

			// Get Time Elapsed.
			U32 CurrentTime = Platform::getRealMilliseconds();
			U32 TimeElapsed = CurrentTime - mLastTimeStamp;
			mLastTimeStamp = CurrentTime;

			// Calculate new Sweep.
			Point3F NewSweep(	(U32)(360.0f / mSweepTime[0] * TimeElapsed) % 360,
								(U32)(360.0f / mSweepTime[1] * TimeElapsed) % 360,
								(U32)(360.0f / mSweepTime[2] * TimeElapsed) % 360);

			// Add to Current Sweep.
			mCurrentSweepMagnitude += NewSweep;

			// Calculate Current Sweep Angle.
			mCurrentSweep.set(	mDegToRad((mSweepAmplitude[0] * mCos(mDegToRad(mCurrentSweepMagnitude[0])))/2 + mRotateView[0]),
								mDegToRad((mSweepAmplitude[1] * mCos(mDegToRad(mCurrentSweepMagnitude[1])))/2 + mRotateView[1]),
								mDegToRad((mSweepAmplitude[2] * mCos(mDegToRad(mCurrentSweepMagnitude[2])))/2 + mRotateView[2]));

			// Set-up Quaternion Rotation.
			QRotation.set(mCurrentSweep);

			// Set Camera Matrix to new Rotation.
			QRotation.setMatrix(&Camera);

			// Set Position @ Attached Object.
			Camera.setColumn(3, mAttachedObject->getBoxCenter() + mOffsetView);

			// Set Camera Matrix.
			query->cameraMatrix = Camera;

			// Set Near/Far Planes.
			query->nearPlane = 0.1f;
			query->farPlane = getMax(VisibleDistance, 50.f);

			// Set FOV.
			query->fov = mDegToRad(mFov);

			// Return OK.
			return(true);
		}
	}

	// Return Error.
	return(false);
}
#6
07/23/2008 (10:12 am)
I'm getting the same thing, picture-in-picture. With two GuiSnooper windows, the first is PIP and the second is 2PIP.

Also I needed to replace the three instances of "mBounds" with "getBounds()" before the code would even compile. Said mBounds is a private member.
#7
07/23/2008 (10:44 am)
I actually found the problem the same day and tried to post it but GG website kept eating my post so I went on to other things and forgot to come back and post the fix.

The problem as it turns out is a call in Parent::onRender .
So I duplicated it's code in GuiSnooper::onRender then commenting out the one line that was causing the error.

This is the line in Parent::render that is the problem.
//gClientSceneGraph->getLightManager()->hdrRender();

This is the code I used to fix it for the GuiSnooper.

void GuiSnooper::onRender(Point2I offset, const RectI &updateRect)
{
	// Call Parent Render.
	//Parent::onRender(offset, updateRect);
  if(!processCameraQuery(&mLastCameraQuery))
      return;

   // Clear the zBuffer so GUI doesn't hose object rendering accidentally
   GFX->clear( GFXClearZBuffer , ColorI(20,20,20), 1.0f, 0 );

   // set up the camera and viewport stuff:
   F32 wwidth;
   F32 wheight;
   if(!mLastCameraQuery.ortho)
   {
      wwidth = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2);
      wheight = F32(getHeight()) / F32(getWidth()) * wwidth;
   }
   else
   {
      wwidth = mLastCameraQuery.fov;
      wheight = F32(getHeight()) / F32(getWidth()) * wwidth;
   }

   F32 hscale = wwidth * 2 / F32(getWidth());
   F32 vscale = wheight * 2 / F32(getHeight());

   F32 left = (updateRect.point.x - offset.x) * hscale - wwidth;
   F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth;
   F32 top = wheight - vscale * (updateRect.point.y - offset.y);
   F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y);

   GFX->setViewport( updateRect );

   if(!mLastCameraQuery.ortho)
   {
      GFX->setFrustum( left, right, bottom, top,
                       mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane );
   }
   else
   {
      GFX->setOrtho(left, right, bottom, top, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, true);

      mOrthoWidth = right - left;
      mOrthoHeight = top - bottom;
   }

   // We're going to be displaying this render at size of this control in
   // pixels - let the scene know so that it can calculate e.g. reflections
   // correctly for that final display result.
   gClientSceneGraph->setDisplayTargetResolution(getExtent());

   gClientSceneGraph->setVisibleDistance( mLastCameraQuery.farPlane );

   gClientSceneGraph->getLightManager()->hdrPrepare(updateRect.point, updateRect.extent);

   // save the world matrix before attempting to draw anything
   //GFX->pushWorldMatrix();

   // Set the GFX world matrix to the world-to-camera transform, but don't 
   // change the cameraMatrix in mLastCameraQuery. This is because 
   // mLastCameraQuery.cameraMatrix is supposed to contain the camera-to-world
   // transform. In-place invert would save a copy but mess up any GUIs that
   // depend on that value.
   MatrixF worldToCamera = mLastCameraQuery.cameraMatrix;
   worldToCamera.inverse();
   GFX->setWorldMatrix( worldToCamera );

   mSaveProjection = GFX->getProjectionMatrix();
   mSaveModelview = GFX->getWorldMatrix();

   mSaveViewport = updateRect;

   renderWorld(updateRect);

//   if(gDebugDraw) gDebugDraw->render();

  // gClientSceneGraph->getLightManager()->hdrRender();//this is causing the picture in picture effect


   // restore the world matrix so the GUI will render correctly
   //GFX->popWorldMatrix();

  // renderChildControls(offset, updateRect);
   smFrameCount++;


	// Set Clipping Rectangle to GUI Bounds.
	GFX->setClipRect(getBounds());

	// Do we have an attached Object?
	if (!mAttachedObject)
	{
		// No, so signal to user this problem ...
		ColorF ErrorColor(1,0,0);
		GFX->getDrawUtil()->drawRectFill(updateRect, ErrorColor);
		ErrorColor.set(1,1,1);
		char buf[256];
		dSprintf(buf, sizeof(buf), "*** Object not selected ***");
		GFX->getDrawUtil()->setBitmapModulation(ErrorColor);
		GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
		GFX->getDrawUtil()->clearBitmapModulation();

		// Return Error.
		return;
	}

	// Are we using the Overlay Bitmap?

	if (mUseOverlayBitmap)
	{
		// Yes, so do we have a texture Handle?
		if (mOverlayTextureHandle)
		{
			// Yes, so clear Bitmap Modulation.
			GFX->getDrawUtil()->clearBitmapModulation();

			// Are we tiling the Overlay Bitmap?
			if(mOverlayTile)
			{
				RectI SrcRegion;
				RectI DstRegion;

				// Yes, so fetch texture object.
				GFXTextureObject* TextureObj = mOverlayTextureHandle;

				// Calculate Tesselation Count.
				float XTess = ((float)getBounds().extent.x/(float)TextureObj->mBitmapSize.x)+1;
				float YTess = ((float)getBounds().extent.y/(float)TextureObj->mBitmapSize.y)+1;

				for(int y = 0; y < YTess; ++y)
				{
					for(int x = 0; x < XTess; ++x)
					{
						// Calculate Source Region.
						SrcRegion.set(0,0,TextureObj->mBitmapSize.x, TextureObj->mBitmapSize.y);

						// Calculate Destination Region.
						DstRegion.set(((TextureObj->mBitmapSize.x*x)+offset.x),
									  ((TextureObj->mBitmapSize.y*y)+offset.y),
									  TextureObj->mBitmapSize.x,	
									  TextureObj->mBitmapSize.y);

						// Draw Tiled Bitmap.
						GFX->getDrawUtil()->drawBitmapStretchSR(TextureObj, DstRegion, SrcRegion);
					}
				}
			}
			else
			{
				// No, so draw stretched Bitmap.
				GFX->getDrawUtil()->drawBitmapStretch(mOverlayTextureHandle, getBounds());
			}
		}
	}

	// Are we using the Overlay Colour?
	if (mUseOverlayColour)
	{
		// Set Colour Mask.
		GFX->enableColorWrites(mOverlayRedMask, mOverlayGreenMask, mOverlayBlueMask, true);

		// Draw our filled rectangle with the Filter Colour.
		GFX->getDrawUtil()->drawRectFill(updateRect, mOverlayColor);

		// Reset the Colour Mask.
		GFX->enableColorWrites(true, true, true, true);
	}
}
#8
07/23/2008 (12:30 pm)
Thanks Bill,
I was just going to post that I found the same thing. GG should really look into this.
I like your solution, but I need to create some getters and setters for GuiTSCtrl.
#9
07/29/2008 (8:26 am)
I have been running into some water reflection problems.
I think the problem is some GFX calls are not in the right order or I am not calling something correctly.
The code is the same as I posted above.

I am using the advanced camera resource but I don't think that is contributing to the error.

Here are some pics of the error.

In god mode with a godViewOffset of "-100 0 100".
The reflect for both the main playGui and the fxgui are messed up.
www.dayofwar.net/images/errors/fx_gui_water_reflect_error_0.png
www.dayofwar.net/images/errors/fx_gui_water_reflect_error_2.png
In first person the reflect appears ok for both.
www.dayofwar.net/images/errors/fx_gui_water_reflect_error_1.png
www.dayofwar.net/images/errors/fx_gui_water_reflect_error_3.png

These 2 pics show the same area without the fxguisnooper.
Refection is OK in god mode.
www.dayofwar.net/images/errors/fx_gui_water_reflect_error_4.png
www.dayofwar.net/images/errors/fx_gui_water_reflect_error_5.png
#10
01/07/2009 (1:18 pm)
Finished a port to 1.8 its a little buggy but its there.
#include "sceneGraph/sceneGraph.h"
#include "T3D/gameConnection.h"
#include "console/consoleTypes.h"
#include "gui/3d/guiTSControl.h"
#include "gui/core/guiControl.h"
#include "renderInstance/renderPassManager.h"
#include "gfx/gfxDevice.h"

class fxGuiSnooper : public GuiTSCtrl
{
private:
	typedef GuiTSCtrl Parent;

	Point3F				mRotateView;					// View Rotation.
	Point3F				mOffsetView;					// Offset Distance.
	F32					mFov;							// Field of View.
	Point3F				mSweepAmplitude;				// Sweep Amplitude.
	Point3F				mSweepTime;						// Sweep Time.

	bool				mUseOverlayBitmap;				// Use Overlay Bitmap Flag.
	bool				mUseOverlayColour;				// Use Overlay Colour Flag.
	bool				mOverlayTile;					// Overlay Tile Flag.
	ColorF				mOverlayColor;					// Filter Colour Vector.
	bool				mOverlayRedMask;				// Overlay Red Mask Flag.
	bool				mOverlayGreenMask;				// Overlay Green Mask Flag.
	bool				mOverlayBlueMask;				// Overlay Blue Mask Flag.

	StringTableEntry	mObjectName;					// Attached Object Name.
	SceneObject*		mAttachedObject;				// Attached Object.

	U32					mLastTimeStamp;					// Last Time Stamp.
	Point3F				mCurrentSweepMagnitude;			// Current Sweep Phase.
	StringTableEntry	mOverlayBitmapName;				// Overlay Bitmap Name.
	GFXTexHandle		mOverlayTextureHandle;			// Overlay Texture Handle.

    GFXStateBlockRef mSnooperClearSB;
    GFXStateBlockRef mDzEnableSB;
	GFXStateBlockRef mEcwSB;
	GFXStateBlockRef mEcwResetSB;

	void renderWorld(const RectI & updateRect);
	void onRender(Point2I offset, const RectI &updateRect);

public:
	fxGuiSnooper();

	static void initPersistFields();
	static void consoleInit();

	bool processCameraQuery(CameraQuery * query);

	void setViewObject(const char* ObjectName);
	void setViewRotation(Point3F Rotation);
	void setOverlayBitmap(const char *name);
	void setOverlayColor(ColorF OverlayColor);
	void setOverlayMask(bool RedMask, bool GreenMask, bool BlueMask);

	bool onWake();
	void onSleep();

	DECLARE_CONOBJECT(fxGuiSnooper);
};

//------------------------------------------------------------------------------

IMPLEMENT_CONOBJECT(fxGuiSnooper);

//------------------------------------------------------------------------------


fxGuiSnooper::fxGuiSnooper() :
	mRotateView(0,0,0),
	mOffsetView(0,0,0),
	mFov(60.0),
	mSweepAmplitude(0,0,60),
	mSweepTime(5000,5000,5000),
	mCurrentSweepMagnitude(0,0,0),
	mAttachedObject(NULL),
	mOverlayRedMask(true),
	mOverlayGreenMask(true),
	mOverlayBlueMask(true),
	mOverlayTile(false),
	mUseOverlayBitmap(false),
	mUseOverlayColour(false),
	mLastTimeStamp(Platform::getRealMilliseconds())
{
	// Create Empty Attached Object Name.
	mObjectName = StringTable->insert("");

	// Create Empty Overlay Bitmap Name.
	mOverlayBitmapName = StringTable->insert("");

	// Set Default Overlay Colour.
	mOverlayColor.set(1, 1, 1, 0.5f);
};

//------------------------------------------------------------------------------

void fxGuiSnooper::initPersistFields()
{
	// Initialise parents' persistent fields.
	Parent::initPersistFields();

	// Add out own persistent fields.
	addField( "ViewRotation", TypePoint3F, Offset( mRotateView, fxGuiSnooper ) );
	addField( "ViewOffset", TypePoint3F, Offset( mOffsetView, fxGuiSnooper ) );
	addField( "FOV", TypeF32, Offset( mFov, fxGuiSnooper ) );
	addField( "SweepAmplitude", TypePoint3F, Offset( mSweepAmplitude, fxGuiSnooper ) );
	addField( "SweepTime", TypePoint3F, Offset( mSweepTime, fxGuiSnooper ) );
	addField( "AttachedObject", TypeString, Offset( mObjectName, fxGuiSnooper ) );
	addField( "OverlayBitmap", TypeBool, Offset( mUseOverlayBitmap, fxGuiSnooper ) );
	addField( "OverlayTile", TypeBool, Offset( mOverlayTile, fxGuiSnooper ) );
	addField( "OverlayColour", TypeBool, Offset( mUseOverlayColour, fxGuiSnooper ) );
	addField( "BitmapOverlay", TypeFilename, Offset(mOverlayBitmapName, fxGuiSnooper));
	addField( "ColorOverlay", TypeColorF, Offset( mOverlayColor, fxGuiSnooper ) );
	addField( "RedMask", TypeBool, Offset( mOverlayRedMask, fxGuiSnooper ) );
	addField( "GreenMask", TypeBool, Offset( mOverlayGreenMask, fxGuiSnooper ) );
	addField( "BlueMask", TypeBool, Offset( mOverlayBlueMask, fxGuiSnooper ) );
}

//------------------------------------------------------------------------------

bool fxGuiSnooper::onWake()
{
	// Wake-up Parent.
	if (!Parent::onWake()) return false;

	// Set Active.
	setActive(true);

	// Have we an Attached Object Name?
	if (mObjectName)
	{
		// Yes, so attach to it.
		setViewObject(mObjectName);
	}

	// Set Overlay Bitmap.
	setOverlayBitmap(mOverlayBitmapName);

	// Return OK.
	return true;
}

//------------------------------------------------------------------------------

void fxGuiSnooper::onSleep()
{
	// Reset Overlay Texture Handle.
	mOverlayTextureHandle = NULL;
	// Call Parent.
	Parent::onSleep();
}

//------------------------------------------------------------------------------

void fxGuiSnooper::setViewRotation(Point3F Rotation)
{
	// Set the Rotation internally.
	mRotateView = Rotation;
}

//------------------------------------------------------------------------------

void fxGuiSnooper::setViewObject(const char* ObjectName)
{
	// Get Root Group.
	SimGroup* SG = Sim::getRootGroup();

	// Interate Sim Group.
	for (SimSetIterator itr(SG); *itr; ++itr)
	{
		// Is this our Type?
		if ((*itr)->getType() & STATIC_COLLISION_MASK)
		{
			// Yes, so cast our Object.
			SceneObject* SceneObj = static_cast<SceneObject*>(*itr);
			// Check that it's a Server Object.
			if (SceneObj->isServerObject())
			{
				const char* getName;

				getName = SceneObj->getName();

				// Yes, so is this our Object?
				if (getName && dStrcmp(getName, ObjectName) == 0)
				{
					// Store Scene Object.
					mAttachedObject = SceneObj;

					// Return OK.
					return;
				}
			}
		}
	}

	// Reset Object.
	mAttachedObject = NULL;

}

//------------------------------------------------------------------------------

void fxGuiSnooper::setOverlayBitmap(const char *name)
{
	// Set Overlay Bitmap Name.
	mOverlayBitmapName = StringTable->insert(name);

	if (*mOverlayBitmapName)
		// Yes, so get Texture Handle.
	    mOverlayTextureHandle.set( mOverlayBitmapName, &GFXDefaultGUIProfile, "" );
	else
		// No, so reset Texture Handle.
		mOverlayTextureHandle = NULL;

	// Update.
	setUpdate();
}   

//------------------------------------------------------------------------------

void fxGuiSnooper::setOverlayColor(ColorF OverlayColor)
{
	// Set the Overlay Colour internally.
	mOverlayColor = OverlayColor;
}

//------------------------------------------------------------------------------

void fxGuiSnooper::setOverlayMask(bool RedMask, bool GreenMask, bool BlueMask)
{
	// Set the Overlay Masks internally.
	mOverlayRedMask		= RedMask;
	mOverlayGreenMask	= GreenMask;
	mOverlayBlueMask	= BlueMask;
}

//------------------------------------------------------------------------------

ConsoleMethod(fxGuiSnooper,setViewRotation,void,5,5,"Sets View Rotation.")
{
	Point3F		Rotation;

	// Fetch the fxGuiSnooper object.
	fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);

	// Fetch Rotation.
	Rotation.set(	mDegToRad(dAtof(argv[2])),
					mDegToRad(dAtof(argv[3])),
					mDegToRad(dAtof(argv[4])));

	// Set Rotation.
	Viewport->setViewRotation(Rotation);
}

//------------------------------------------------------------------------------

ConsoleMethod(fxGuiSnooper,setViewObject,void,3,3,"Sets View to Object.")
{
	F32		Rotation;

	// Fetch the fxGuiSnooper object.
	fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);

	// Set the GuiFilter Filter Colour.
	Viewport->setViewObject(argv[2]);
}

//------------------------------------------------------------------------------

ConsoleMethod(fxGuiSnooper,setOverlayBitmap,void,3,3,"Sets Overlay Bitmap.")
{
	// Fetch the fxGuiSnooper object.
	fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);

	// Set Overlay Bitmap.
	Viewport->setOverlayBitmap(argv[2]);
}

//------------------------------------------------------------------------------

ConsoleMethod(fxGuiSnooper,setOverlayColor,void,5,6,"Sets Overlay Color.")
{
	F32		r,g,b,a;
	ColorF	TempColor;

	// Fetch the fxGuiSnooper object.
	fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);

	// Convert RGB Ascii parms to float.
	r = dAtof(argv[2]);
	g = dAtof(argv[3]);
	b = dAtof(argv[4]);

	// Did we get an alpha param?
	if (argc == 6)
		// Yep, so convert it.
		a = dAtof(argv[5]);
	else
		// Nope, so default to 1.
		a = 1;

	// Setup our temporary colour vector.
	TempColor.set(r,g,b,a);

	// Set the fxGuiSnooper Overlay Colour.
	Viewport->setOverlayColor(TempColor);
}

//------------------------------------------------------------------------------

ConsoleMethod(fxGuiSnooper,setOverlayMask,void,5,5,"Sets Overlay Masks.")
{
	F32		r,g,b;

	// Fetch the fxGuiSnooper object.
	fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);

	// Convert RGB Ascii parms to float.
	r = dAtof(argv[2]);
	g = dAtof(argv[3]);
	b = dAtof(argv[4]);

	// Set the fxGuiSnooper Masks.
	Viewport->setOverlayMask(r,g,b);
}

//------------------------------------------------------------------------------

static void cfxGuiBitmapSetOverlayBitmap(SimObject *obj, S32, const char **argv)
{
	// Fetch HUD Control.
	fxGuiSnooper *ctrl = static_cast<fxGuiSnooper*>(obj);

	// Set Overlay Bitmap.
	ctrl->setOverlayBitmap(argv[2]);
}

//------------------------------------------------------------------------------

void fxGuiSnooper::consoleInit()
{
   Con::addCommand("fxGuiSnooper", "setOverlayBitmap",  cfxGuiBitmapSetOverlayBitmap, "fxGuiSnooper.setOverlayBitmap(Bitmap)", 3, 3);
}

//------------------------------------------------------------------------------

void fxGuiSnooper::renderWorld(const RectI & updateRect)
{
	/* proj = FGX->getProjectionMatrix();
	
	myShaderConstBuffer->set(mModelViewProjSC, &proj);
	myShaderConstBuffer->set(mOpacityMapSC, (S32) 0);
	myShaderConstBuffer->set(mLightMapSC, (S32) 1);

	GFX->setShaderConstBuffer(myShaderConstBuffer);
	*/

	GFX->clear(GFXClearZBuffer, ColorI(0,0,0), 1.0f, 0);
	/*
	GFX->setZEnable(true);
	GFX->setZWriteEnable(true);
	GFX->setZFunc(GFXCmpLessEqual);
	GFX->setCullMode(GFXCullNone);
    */

	GFXStateBlockDesc snooperClear;
	snooperClear.zEnable = true;
	snooperClear.zWriteEnable = true;
	snooperClear.zFunc = GFXCmpLessEqual;
	snooperClear.cullMode = GFXCullNone;
		
	mSnooperClearSB = GFX->createStateBlock(snooperClear);
	
	GFXStateBlockDesc dzEnable;
	dzEnable.zEnable = false;
	mDzEnableSB = GFX->createStateBlock(dzEnable);
	

	GFX->setStateBlock(mSnooperClearSB);
	// Render Client Scene Graph.
	gClientSceneGraph->renderScene();
	
	//GFX->setZEnable(false);

    GFX->setStateBlock(mDzEnableSB);
}

//------------------------------------------------------------------------------

void fxGuiSnooper::onRender(Point2I offset, const RectI &updateRect)
{

	// Declare StateBlocks


	// Call Parent Render.
	Parent::onRender(offset, updateRect);

	// Set Clipping Rectangle to GUI Bounds.
	GFX->setClipRect(getBounds());

	// Do we have an attached Object?
	if (!mAttachedObject)
	{
		// No, so signal to user this problem ...
		ColorF ErrorColor(1,0,0);
		GFX->getDrawUtil()->drawRectFill(updateRect, ErrorColor);
		ErrorColor.set(1,1,1);
		char buf[256];
		dSprintf(buf, sizeof(buf), "*** Object not selected ***");
		GFX->getDrawUtil()->setBitmapModulation(ErrorColor);
		GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
		GFX->getDrawUtil()->clearBitmapModulation();

		// Return Error.
		return;
	}

	// Are we using the Overlay Bitmap?
	if (mUseOverlayBitmap)
	{
		// Yes, so do we have a texture Handle?
		if (mOverlayTextureHandle)
		{
			// Yes, so clear Bitmap Modulation.
			GFX->getDrawUtil()->clearBitmapModulation();

			// Are we tiling the Overlay Bitmap?
			if(mOverlayTile)
			{
				RectI SrcRegion;
				RectI DstRegion;

				// Yes, so fetch texture object.
				GFXTextureObject* TextureObj = mOverlayTextureHandle;

				// Calculate Tesselation Count.
				float XTess = ((float)getWidth()/(float)TextureObj->mBitmapSize.x)+1;
				float YTess = ((float)getHeight()/(float)TextureObj->mBitmapSize.y)+1;

				for(int y = 0; y < YTess; ++y)
				{
					for(int x = 0; x < XTess; ++x)
					{
						// Calculate Source Region.
						SrcRegion.set(0,0,TextureObj->mBitmapSize.x, TextureObj->mBitmapSize.y);

						// Calculate Destination Region.
						DstRegion.set(((TextureObj->mBitmapSize.x*x)+offset.x),
									  ((TextureObj->mBitmapSize.y*y)+offset.y),
									  TextureObj->mBitmapSize.x,	
									  TextureObj->mBitmapSize.y);

						// Draw Tiled Bitmap.
						GFX->getDrawUtil()->drawBitmapStretchSR(TextureObj, DstRegion, SrcRegion);
					}
				}
			}
			else
			{
				// No, so draw stretched Bitmap.
				GFX->getDrawUtil()->drawBitmapStretch(mOverlayTextureHandle, getBounds());
			}
		}
	}

	// Are we using the Overlay Colour?
	if (mUseOverlayColour)
	{
		// Set Colour Mask.
				
		//GFX->enableColorWrites(mOverlayRedMask, mOverlayGreenMask, mOverlayBlueMask, true);
		
			// Declare StateBlocks
		GFXStateBlockDesc ecw;
		ecw.colorWriteRed   |= ( mOverlayRedMask ? GFXCOLORWRITEENABLE_RED		: 0 ); 
		ecw.colorWriteGreen |= ( mOverlayGreenMask ? GFXCOLORWRITEENABLE_GREEN	: 0 );
		ecw.colorWriteBlue  |= ( mOverlayBlueMask ? GFXCOLORWRITEENABLE_BLUE	: 0 );
		ecw.colorWriteAlpha = GFXCOLORWRITEENABLE_ALPHA;
		mEcwSB = GFX->createStateBlock(ecw);
		
		GFXStateBlockDesc ecwReset;
		ecwReset.colorWriteRed   = GFXCOLORWRITEENABLE_RED; 
		ecwReset.colorWriteGreen = GFXCOLORWRITEENABLE_GREEN;
		ecwReset.colorWriteBlue  = GFXCOLORWRITEENABLE_BLUE;
		ecwReset.colorWriteAlpha = GFXCOLORWRITEENABLE_ALPHA;
		mEcwResetSB = GFX->createStateBlock(ecwReset);

		GFX->setStateBlock(mEcwSB);

		// Draw our filled rectangle with the Filter Colour.
		GFX->getDrawUtil()->drawRectFill(updateRect, mOverlayColor);

		// Reset the Colour Mask.
		GFX->setStateBlock(mEcwResetSB);
		//GFX->enableColorWrites(true, true, true, true);
	}
}

//------------------------------------------------------------------------------

bool fxGuiSnooper::processCameraQuery(CameraQuery * query)
{
	Point3F		CameraRotation;							// Rotated View.
	float		VisibleDistance = 1100.0f;				// Visible Distance.


	// Get Game Connection.
	GameConnection* pConnection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());

	// Did we get the connection?
	if (pConnection)
	{
		// Have we got an Attached Object?
		if (mAttachedObject)
		{
			// Current Sweep.
			EulerF mCurrentSweep;

			// Create Camera Matrix.
			MatrixF	Camera(true);

			// Craete Rotation Quaternion.
			QuatF	QRotation;

			// Get Time Elapsed.
			U32 CurrentTime = Platform::getRealMilliseconds();
			U32 TimeElapsed = CurrentTime - mLastTimeStamp;
			mLastTimeStamp = CurrentTime;

			// Calculate new Sweep.
			Point3F NewSweep(	(U32)(360.0f / mSweepTime[0] * TimeElapsed) % 360,
								(U32)(360.0f / mSweepTime[1] * TimeElapsed) % 360,
								(U32)(360.0f / mSweepTime[2] * TimeElapsed) % 360);

			// Add to Current Sweep.
			mCurrentSweepMagnitude += NewSweep;

			// Calculate Current Sweep Angle.
			mCurrentSweep.set(	mDegToRad((mSweepAmplitude[0] * mCos(mDegToRad(mCurrentSweepMagnitude[0])))/2 + mRotateView[0]),
								mDegToRad((mSweepAmplitude[1] * mCos(mDegToRad(mCurrentSweepMagnitude[1])))/2 + mRotateView[1]),
								mDegToRad((mSweepAmplitude[2] * mCos(mDegToRad(mCurrentSweepMagnitude[2])))/2 + mRotateView[2]));

			// Set-up Quaternion Rotation.
			QRotation.set(mCurrentSweep);

			// Set Camera Matrix to new Rotation.
			QRotation.setMatrix(&Camera);

			// Set Position @ Attached Object.
			Camera.setColumn(3, mAttachedObject->getBoxCenter() + mOffsetView);

			// Set Camera Matrix.
			query->cameraMatrix = Camera;

			// Set Near/Far Planes.
			query->nearPlane = 0.1;
			query->farPlane = getMax(VisibleDistance, 50.f);

			// Set FOV.
			query->fov = mDegToRad(mFov);

			// Return OK.
			return(true);
		}
	}

	// Return Error.
	return(false);
}
#11
01/05/2010 (6:31 pm)
Has anyone successfully implemented this resource in T3D?
#12
01/09/2010 (12:54 pm)
I implemented this resource to T3D and modify it so that it can be attached any kind of shape in the world editor, not only static shapes. I want to attach it to different players and use it as a split screen. But when I attach it to the player I start having a problem. The problem is that the animation for when the player walks or runs is not playing smoothly. It the image of the player starts to shake and it looks like one frame is ahead of the current frame. The strange part is that this only happens to the shape that has the camera attached to it. Any one has an idea why this is happening?
#13
01/14/2010 (11:30 pm)
jaun

any chance of you sharing yor T3D modifications. I just saw this and would like to persue a solution with this resource in T3D

#14
09/02/2010 (3:58 pm)
To make this work with T3D 1.1 beta 2, just add this to the list of includes:
#include "gfx/gfxDrawUtil.h"