Game Development Community

dev|Pro Game Development Curriculum

GUIs Rendered on an object: guiDynamicTexture for TSE

by Dave Young · 08/17/2006 (12:16 pm) · 60 comments

Download Code File

GUIDynamicTextures

This was originally written by Tom Spilman, I am only doing the work of porting his code into a resource that is compatible with TSE HEAD, and making minor improvements where I can.

www.sickheadgames.com

I am hoping to integrate this in to the MMO KIT soon, after I get TGE to work with it. It would be very handy for several uses!

This resource uses (not included!) mouse cursor based object selection to perform the interactions with the object. A good use of this is to map a gui onto a surface of an object, and then have that surface receive mouse clicks and thereby interact with the actual gui. I also chose to use Rigid Shapes (also not included) as Tom's original model was a RigidShape monitor.

First off, there are a variety of changes to canvas to accomodate for multiple global canvases. We will be using another canvas to store the gui. Then the material needs to be associated through a property map to be a GUi instead of a texture. Finally there are some extended raycasts used to get the material of the surface struck, and later on to pass any mouse clicks on to the gui itself.

This is a very intensive resource to add in, but it is well worth the effort.

This resource is working when added to TSE HEAD as of 7/14/2006.

Copy the files guiTextureCanvas.cpp and guiTextureCanvas.h into your engine\gui\core folder, and add them into your project.

In engine\editor\editTSCtrl.cpp:

On line 178, change:
Canvas->setCursorON(false);
to
getRoot()->setCursorON(false);

On line 203, change:
Canvas->setCursorON(true);
to
getRoot()->setCursorON(true);


In engine\gui\core\guiCanvas.cpp:

After:

#include "sim/sceneObject.h"

Add:
#include "gui/core/guiTextureCanvas.h"


Line 53, change:
Canvas->setContentControl(gui);
to
object->setContentControl(gui);

You will change all other instances of Canvas to object, these are found on lines:
53, 74, 92, 94, 105, 113, 121, 138, 143, 148, 153, 158, 163, 168, 173, 186


In GuiCanvas::renderFrame, near line 1219, add the following bold code:

GFX->setActiveDevice( 0 );
GFX->beginScene();

// Update the offscreen gui texture canvases.
GuiTextureCanvas::updateCanvases();


// do this at beginning of frame
updateReflections();


In engine\gui\core\guiControl.cpp, add the following console functions:

ConsoleMethod( GuiControl, getParent, S32, 2, 2, "()")
{
   GuiControl* parent = object->getParent();
   return parent ? parent->getId() : -1;
}

ConsoleMethod( GuiControl, getRoot, S32, 2, 2, "()")
{
   GuiCanvas* canvas = object->getRoot();
   return canvas ? canvas->getId() : -1;
}

In engine\gui\core\guiTSControl.cpp, add the following console function:

ConsoleMethod(GuiTSCtrl, unproject, const char*, 3, 5, "(Point3F screenPos)")
{
   Point3F pos(0,0,0);
   if(argc == 4)
      pos.set(dAtof(argv[2]), dAtof(argv[3]), dAtof(argv[4]));
   else
      dSscanf(argv[2], "%g %g %g", &pos.x, &pos.y, &pos.z);

   Point3F out;
   object->unproject( pos, &out );

   char* ret = Con::getReturnBuffer(128);
   dSprintf(ret, 32, "%g %g %g", out.x, out.y, out.z);
   return ret;
}

In engine\materials\materials.cpp:

Underneath:

#include "materialPropertyMap.h"

Add:
#include "gui/core/guiTextureCanvas.h"


Near line 76, above:
dMemset( animFlags, 0, sizeof( animFlags ) );
dMemset( scrollOffset, 0, sizeof( scrollOffset ) );

Add:
guiTextureCanvasName = NULL;
guiTextureCanvas = NULL;



Near line 150, after:
addField("mapTo", TypeString, Offset(mapTo, Material));

Add:
addField("guiTextureCanvas", TypeString, Offset(guiTextureCanvasName, Material));



In Material::onAdd, near line 156, add the following bold code:
if( cubemapName )
{
mCubemapData = static_cast( Sim::findObject( cubemapName ) );
}

if( guiTextureCanvasName )
{
guiTextureCanvas = dynamic_cast( Sim::findObject( guiTextureCanvasName ) );
}


SimSet *matSet = getMaterialSet();
if( matSet )
{
matSet->addObject( (SimObject*)this );
}

In Material::setStageData(), near line 200, change:
if( baseTexFilename[i] && baseTexFilename[i][0] )

to:
if( guiTextureCanvas && baseTexFilename[i] && !dStrcmp( baseTexFilename[i], "$gui" ) )
{
stages[i].tex[GFXShaderFeatureData::BaseTex] = guiTextureCanvas->getTextureHandle();
}
else if( baseTexFilename[i] && baseTexFilename[i][0] )




In engine\materials\materials.cpp:
Near line 18, after:

class GFXCubemap;

Add:
class GuiTextureCanvas;



Near line 143, after:
CubemapData * mCubemapData;
bool dynamicCubemap;

Add:
const char * guiTextureCanvasName;
GuiTextureCanvas* guiTextureCanvas;



In engine\materials\matInstance.cpp:
After:

#include "gfx/gfxCubemap.h"

Add:
#include "gui/core/guiTextureCanvas.h"

In MatInstance::setupPass, near line 545:
Before:

setTextureStages( sgData, mCurPass );

Add:
// if we have a gui texture canvas then let
   // it know we want an update on the next frame.
   if( mMaterial->guiTextureCanvas )
   {
      mMaterial->guiTextureCanvas->setDirty();
   }


In engine\math\mathUtils.cpp, after the end of the function getVectorFromAngles, add the following functions. There should still be a final } in the file after these functions and before the end of the file:

F32 getArea( const Point3F* verts, S32 count )
{
	// Vector whose length will be area^2.
	Point3F vec( 0, 0, 0 );
	for ( S32 i = 0; i < count; i++ ) {

      S32 j = i ? i - 1 : count - 1;

      // Add cross_product(pnts[j],pnts[i]).
		vec.x += verts[j].y * verts[i].z - verts[j].z * verts[i].y;
		vec.y += verts[j].z * verts[i].x - verts[j].x * verts[i].z;
		vec.z += verts[j].x * verts[i].y - verts[j].y * verts[i].x;
	}
   
	// Find length of vector, return it.
	return mSqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z ) / 2.0f;
}

Point3F getBarrycentricCoord( const Point3F& point, const Point3F* tri )
{
	// If the area of the triangle is zero... return 0.
	const F32 a = getArea( tri, 3 );

	if ( a <= 0.0f )
      return Point3F( 0, 0, 0 );

	Point3F b;
	{
      Point3F temp[3] =
      {
         tri[1],
         tri[2],
         point
      };
		b.x = getArea( temp, 3 ) / a;
	}
	{
      Point3F temp[3] =
      {
         tri[2],
         tri[0],
         point
      };
		b.y = getArea( temp, 3 ) / a;
	}
	{
      Point3F temp[3] =
      {
         tri[0],
         tri[1],
         point
      };
		b.z = getArea( temp, 3 ) / a;
	}

   return b;
}

bool rayTriangleIntersect( const Point3F& orig, const Point3F& dir,
   const Point3F& vert0, const Point3F& vert1, const Point3F& vert2,
   F32 *t, F32 *u, F32 *v )
{
   const F32 EPSILON = __EQUAL_CONST_F;

   /* find vectors for two edges sharing vert0 */
   Point3F edge1( vert1 -  vert0 );
   Point3F edge2( vert2 -  vert0 );

   /* begin calculating determinant - also used to calculate U parameter */
   Point3F pvec( mCross( dir, edge2 ) );

   /* if determinant is near zero, ray lies in plane of triangle */
   F32 det = mDot( edge1, pvec );

   if (det < EPSILON)
      return 0;

   /* calculate distance from vert0 to ray origin */
   Point3F tvec( orig - vert0 );

   /* calculate U parameter and test bounds */
   *u = mDot( tvec, pvec );
   if (*u < 0.0 || *u > det)
      return false;

   /* prepare to test V parameter */
   Point3F qvec( mCross( tvec, edge1 ) );

   /* calculate V parameter and test bounds */
   *v = mDot( dir, qvec );
   if (*v < 0.0 || *u + *v > det)
      return false;

   /* calculate t, scale parameters, ray intersects triangle */
   F32 inv_det = 1.0 / det;
   *t = mDot( edge2, qvec ) * inv_det;
   *u *= inv_det;
   *v *= inv_det;

   return true;
}


In engine\math\mathUtils.cpp:
Before line 52 which reads:

inline bool isPow2(const U32 number) { return (number & (number - 1)) == 0; }

Add:

/// Returns the area of a polygon.
F32 getArea( const Point3F* verts, S32 count );

/// Returns the barrycentric coordinate for a point on a triangle.
Point3F getBarrycentricCoord( const Point3F& point, const Point3F* tri );

/// Returns the intersection of a ray and a triangle.
bool rayTriangleIntersect( const Point3F& orig, const Point3F& dir, const Point3F& vert0, const Point3F& vert1, const Point3F& vert2, F32 *t, F32 *u, F32 *v );


In engine\sim\sceneObject.cpp:
Near line 11, after:

#include "platform/profiler.h"

Add:
#include "materials/materialPropertyMap.h"


Near line 205, change the end of the console function definition for containerRayCast from:
" - The x, y, z of the normal of the face that was struck.")

To:
" - The x, y, z of the normal of the face that was struck.\n"
" - The ID of the material that was struck." )


In the same function, near line 232, change:

dSprintf(returnBuffer, 256, "%d %g %g %g %g %g %g",
               ret, rinfo.point.x, rinfo.point.y, rinfo.point.z,
               rinfo.normal.x, rinfo.normal.y, rinfo.normal.z);

To:

dSprintf(returnBuffer, 256, "%d %g %g %g %g %g %g %d",
               ret, rinfo.point.x, rinfo.point.y, rinfo.point.z,
               rinfo.normal.x, rinfo.normal.y, rinfo.normal.z, 
               rinfo.material);

On lines 1235, 1327, and 1412, in function Container::castRay, after:
currentT = ri.t;
Add:
ptr->mObjToWorld.mulV(info->normal);



In engine\ts\tsCollision.cpp, after:
#include "sim/sceneObject.h"

Add:
#include "materials/materialList.h"
#include "materials/matInstance.h"

Near line 219, TSShapeInstance::castRay, after:
rayInfo->point += a;

Add:

//GuiTextureCanvas Change
      rayInfo->material = 0;

      // Find the material object id for the texture id
      // that TSMesh::castRay() set for us.
      if ( mMaterialList ) 
      {
         MatInstance* matInst = mMaterialList->getMaterialInst( rayInfo->material );
         if ( matInst && matInst->getMaterial() ) 
            rayInfo->material = matInst->getMaterial()->getId();
      }
      //GuiTextureCanvas Change



In engine\ts\tsMesh.cpp, after:
#include "materials/matInstance.h"
Add:
#include "math/mathUtils.h"

Near line 1987, before function TSMesh::addToHull, add the following function:

bool TSMesh::castRayTri( S32 frame, const Point3F& start, const Point3F& end, TriRayInfo* rayInfo )
{
   // Loop thru the triangles of the first frame.
   const S32 firstVert = vertsPerFrame * frame;

   F32 hit = F32_MAX;

   Point3F dir( end - start );
   dir.normalizeSafe();

   for ( S32 i=0; i < primitives.size(); i++ )
   {
      const TSDrawPrimitive& draw = primitives[i];

      AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::castRayTri, got non-indexed primitive!" );

      // gonna depend on what kind of primitive it is...
      if ( ( draw.matIndex & TSDrawPrimitive::TypeMask ) == TSDrawPrimitive::Triangles )
      {
         for ( S32 j=0; j < draw.numElements; j+=3 )
         {
            const U32 idx0 = indices[draw.start+j+0] + firstVert;
            const U32 idx1 = indices[draw.start+j+1] + firstVert;
            const U32 idx2 = indices[draw.start+j+2] + firstVert;

            F32 h, u, v;
            if ( MathUtils::rayTriangleIntersect( start, dir, verts[idx2], verts[idx1], 
               verts[idx0], &h, &v, &u ) && h < hit ) 
            {
               hit = h;

               rayInfo->distance = hit;
               rayInfo->point = start + ( dir * hit );
               rayInfo->material = draw.matIndex & TSDrawPrimitive::MaterialMask;

               Point3F temp[3] =
               {
                  verts[idx0],
                  verts[idx1],
                  verts[idx2]
               };
               Point3F bc = MathUtils::getBarrycentricCoord( rayInfo->point, temp );

               rayInfo->uv = Point2F( 
                  (bc.x * tverts[idx0].x) + (bc.y * tverts[idx1].x) + (bc.z * tverts[idx2].x ),
                  (bc.x * tverts[idx0].y) + (bc.y * tverts[idx1].y) + (bc.z * tverts[idx2].y ) );
            }
         }
      }
      else
      {
         AssertFatal( ( draw.matIndex & TSDrawPrimitive::Strip ) == TSDrawPrimitive::Strip, "TSMesh::castRayTri, unexpected primitive type!" );

         U32 idx0 = indices[draw.start + 0] + firstVert;
         U32 idx1;
         U32 idx2 = indices[draw.start + 1] + firstVert;
         U32* nextIdx = &idx1;
         for ( S32 j = 2; j < draw.numElements; j++ )
         {
            *nextIdx = idx2;
            nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
            idx2 = indices[draw.start + j] + firstVert;

            F32 h, u, v;
            if ( MathUtils::rayTriangleIntersect( start, dir, verts[idx2], verts[idx1], 
               verts[idx0], &h, &v, &u ) && h < hit )
            {
               hit = h;

               rayInfo->distance = hit;
               rayInfo->point = start + ( dir * hit );
               rayInfo->material = draw.matIndex & TSDrawPrimitive::MaterialMask;

               Point3F temp[3] =
               {
                  verts[idx0],
                  verts[idx1],
                  verts[idx2]
               };
               Point3F bc = MathUtils::getBarrycentricCoord( rayInfo->point, temp );

               rayInfo->uv = Point2F( 
                  (bc.x * tverts[idx0].x) + (bc.y * tverts[idx1].x) + (bc.z * tverts[idx2].x ),
                  (bc.x * tverts[idx0].y) + (bc.y * tverts[idx1].y) + (bc.z * tverts[idx2].y ) );
            }
         }
      }
   }

   return hit < F32_MAX;
}



Near line 3506, before function TSMesh::findTangent, add the following functions:

#define SMALL_FLOAT (1e-12)

//-----------------------------------------------------------------------------
// createTextureSpaceMatrix
//-----------------------------------------------------------------------------
void TSMesh::createTextureSpaceMatrix( MeshVertex *v0, MeshVertex *v1, MeshVertex *v2 )
{
   Point3F edge1, edge2;
   Point3F cp;

   // x, s, t
	edge1.set( v1->point.x - v0->point.x, v1->texCoord.x - v0->texCoord.x, v1->texCoord.y - v0->texCoord.y );
	edge2.set( v2->point.x - v0->point.x, v2->texCoord.x - v0->texCoord.x, v2->texCoord.y - v0->texCoord.y );

   mCross( edge1, edge2, &cp );
   if( fabs(cp.x) > SMALL_FLOAT )
   {
		v0->T.x = -cp.y / cp.x;
		v0->B.x = -cp.z / cp.x;

		v1->T.x = -cp.y / cp.x;
		v1->B.x = -cp.z / cp.x;

		v2->T.x = -cp.y / cp.x;
		v2->B.x = -cp.z / cp.x;
   }

   // y, s, t
	edge1.set( v1->point.y - v0->point.y, v1->texCoord.x - v0->texCoord.x, v1->texCoord.y - v0->texCoord.y );
	edge2.set( v2->point.y - v0->point.y, v2->texCoord.x - v0->texCoord.x, v2->texCoord.y - v0->texCoord.y );

   mCross( edge1, edge2, &cp );
   if( fabs(cp.x) > SMALL_FLOAT )
   {
		v0->T.y = -cp.y / cp.x;
		v0->B.y = -cp.z / cp.x;

		v1->T.y = -cp.y / cp.x;
		v1->B.y = -cp.z / cp.x;

		v2->T.y = -cp.y / cp.x;
		v2->B.y = -cp.z / cp.x;
   }

   // z, s, t
	edge1.set( v1->point.z - v0->point.z, v1->texCoord.x - v0->texCoord.x, v1->texCoord.y - v0->texCoord.y );
	edge2.set( v2->point.z - v0->point.z, v2->texCoord.x - v0->texCoord.x, v2->texCoord.y - v0->texCoord.y );

   mCross( edge1, edge2, &cp );
   if( fabs(cp.x) > SMALL_FLOAT )
   {
		v0->T.z = -cp.y / cp.x;
		v0->B.z = -cp.z / cp.x;

		v1->T.z = -cp.y / cp.x;
		v1->B.z = -cp.z / cp.x;

		v2->T.z = -cp.y / cp.x;
		v2->B.z = -cp.z / cp.x;
   }

   // v0
   v0->T.normalizeSafe();
   v0->B.normalizeSafe();
   mCross( v0->T, v0->B, &v0->N );
   if( mDot( v0->N, v0->normal ) < 0.0 )
   {
      v0->N = -v0->N;
   }

   // v1
   v1->T.normalizeSafe();
   v1->B.normalizeSafe();
   mCross( v1->T, v1->B, &v1->N );
   if( mDot( v1->N, v1->normal ) < 0.0 )
   {
      v1->N = -v1->N;
   }

   // v2
   v2->T.normalizeSafe();
   v2->B.normalizeSafe();
   mCross( v2->T, v2->B, &v2->N );
   if( mDot( v2->N, v2->normal ) < 0.0 )
   {
      v2->N = -v2->N;
   }

}

//-----------------------------------------------------------------------------
// Fills in texture space matrix portion of each vertex - for bumpmapping
//-----------------------------------------------------------------------------
void TSMesh::fillTextureSpaceInfo( MeshVertex *vertArray )
{
   for (S32 i=0; i<primitives.size(); i++)
   {
      TSDrawPrimitive & draw = primitives[i];
      GFXPrimitiveType drawType = getDrawType(draw.matIndex>>30);


      U32 numPrims = 0;
      U32 p1Index = 0;
      U32 p2Index = 0;

      U16 *baseIdx = &indices[draw.start];

      switch( drawType )
      {
         case GFXTriangleList:
         {
            for( U32 j=0; j<draw.numElements; j+=3 )
            {
               createTextureSpaceMatrix( &vertArray[baseIdx[j]], &vertArray[baseIdx[j+1]], &vertArray[baseIdx[j+2]] );
            }
            break;
         }

         case GFXTriangleStrip:
         {
            p1Index = baseIdx[0];
            p2Index = baseIdx[1];
            for( U32 j=2; j<draw.numElements; j++ )
            {
               createTextureSpaceMatrix( &vertArray[p1Index], &vertArray[p2Index], &vertArray[baseIdx[j]] );
               p1Index = p2Index;
               p2Index = baseIdx[j];
            }
            break;
         }
         case GFXTriangleFan:
         {
            p1Index = baseIdx[0];
            p2Index = baseIdx[1];
            for( U32 j=2; j<draw.numElements; j++ )
            {
               createTextureSpaceMatrix( &vertArray[p1Index], &vertArray[p2Index], &vertArray[baseIdx[j]] );
               p2Index = baseIdx[j];
            }
            break;
         }

         default:
            AssertFatal( false, "WTF?!" );
      }

   }

}


In engine\ts\tsMesh.h, after:
#include "sceneGraph/sceneState.h"
Add:
#include "sim/sceneObject.h"


Near line 72, before:

class TSMesh
{

Add:

struct TriRayInfo : public RayInfo
{
Point2F uv;
};

Near line 200, after:
virtual bool castRay(S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo);

Add:
virtual bool castRayTri(S32 frame, const Point3F & start, const Point3F & end, TriRayInfo * rayInfo);


Near line 235, after:
void createVBIB();

Add:
void createTextureSpaceMatrix( MeshVertex *v0, MeshVertex *v1, MeshVertex *v2 );
void fillTextureSpaceInfo( MeshVertex *vertArray );


Suggested usage is to map a surface via property map. Here is an example:

new GuiTextureCanvas( MonitorCanvas ) 
{
   guiControl = "optionsDlg";
};

new Material(MonitorMat) 
{
   guiTextureCanvas = "MonitorCanvas";

   baseTex[0] = "$gui"; 
   emissive[0] = true;

   mapTo = "MONITOR";
};

Because our model uses a material named MONITOR which is mapped to the faces of the monitor model, this property mapping does the work of associating that material with the optionsDlg gui.

Now it is up to us to add some scripting to interact with the object (I used mouse cursor object selection) to do a raycast and see if the object is a RigidShape. If it is, I do another raycast using the hit object and the special function GuiTextureCanvas::castRay which returns a material name.

If that material is a guiTextureCanvas, I can also see its name (in this case it is MonitorCanvas) and I know I can call up the doMouseClick function for the object and walla! interaction.

I will post up some example script usage soon.

Some enhancements to this resource would be:
1) Make this work for interior objects
2) Make this work for objects that are scaled in TSE. Right now only works well with a scale of "1 1 1", I imagine that is because the gui does not also scale with the object, so mouse clicks dont translate properly.
3) Port this to TGE


I also want to thank everyone who helped out on the original thread, this was a wonderful learning experience for me, and I'm sorry it took so long!

If there are any bugs, I will fix 'em and edit the resource :)


Enjoy!
Page«First 1 2 3 Next»
#41
11/13/2009 (3:39 am)
Ok, heres what i got:
I got the offscreen rendering working and i got the association between texture and canvas working. Didnt touch the interaction / raycasting code yet.

Instructions:

Copy these files to source/gui/core and add them to your project.


In gui/core/guiCanvas.cpp, at the top

after
#include "gfx/gfxInit.h"

#include "core/util/journal/process.h"


add
//  added for offscreen gui rendering

#include "gui/core/guiTextureCanvas.h"

in source/material/matInstance.cpp in MatInstance::setupPass

after
if ( !mProcessedMaterial->setupPass( state, sgData, mCurPass ) )
   
{
      
	mProcessedMaterial->cleanup(mCurPass - 1);

	mCurPass = -1;

        return false;
   
}
add:
if(mProcessedMaterial->guiTexCanvas)
   
{
        
	mProcessedMaterial->guiTexCanvas->setDirty();
   
}
in source/material/processedMaterial.cpp in the Constructor

after
VECTOR_SET_ASSOCIATION( mPasses );
add
//association with a gui tex canvas!
   guiTexCanvas = NULL;

in _setStageData()

change
// Load up all the textures for every possible stage
   for( i=0; i<Material::MAX_STAGES; i++ )
   {
      // DiffuseMap
      if( mMaterial->mDiffuseMapFilename[i].isNotEmpty() )
to
// Load up all the textures for every possible stage
   for( i=0; i<Material::MAX_STAGES; i++ )
   {
        if(mMaterial->mDiffuseMapFilename[i].isNotEmpty() && !dStrcmp( mMaterial->mDiffuseMapFilename[i].substr(0,4), "$gui" ) )
        {
            String subString(mMaterial->mDiffuseMapFilename[i].substr(4));
            StringTableEntry canvasName = StringTable->insert(subString.c_str());
            guiTexCanvas = dynamic_cast<GuiTextureCanvas*>(Sim::findObject(canvasName));
            if(guiTexCanvas)
            {
                mStages[i].setTex(MFT_DiffuseMap, guiTexCanvas->getTextureHandle());
            }
            else
                mStages[i].setTex(MFT_DiffuseMap, NULL);
                
            if(!mStages[i].getTex( MFT_DiffuseMap ))
                mMaterial->logError("Failed to load diffuse map %s for stage %i", _getTexturePath(mMaterial->mDiffuseMapFilename[i]).c_str(), i);
        }
      // DiffuseMap
      else if( mMaterial->mDiffuseMapFilename[i].isNotEmpty() )
in processedMaterial.h

add to the include section:
#include "guicoreguiTextureCanvas.h"
add to the public (i know, i know) section of the declarations:
GuiTextureCanvas* guiTexCanvas;


To associate a texture with a canvas, use this pattern (like with the original resource) :
new GuiTextureCanvas( MonitorCanvas )   
{  
   guiControl = "optionsDlg";  
};  
  
new Material(MonitorMat)   
{   
   diffuseMap[0] = "$guiMonitorCanvas";   
   emissive[0] = true;  
  
   mapTo = "MONITOR";  
};

As you see, the only difference is that the Name of the Canvas gets added to the prefix $gui.

Additional Intel:
Now the only thing thats missing is the ability to translate hits on the texture to gui coordinates ...
And at least Torque RayCasts also return the material they hit. So far i dont know any easy approach on how to tell which part of the texture was hit.



/// Addendum

If you get a black texture, its most likely because you missed a change to the initial gui canvas which came from the original resource and was mentioned in the opening post:

In GuiCanvas::renderFrame, near line 1219, add the following bold code:

GFX->setActiveDevice( 0 );
GFX->beginScene();

// Update the offscreen gui texture canvases.
GuiTextureCanvas::updateCanvases(); // <<<<<<

// do this at beginning of frame
updateReflections();

As of Beta2, in the very same method this should be around the line 1620 and looks like this now :

PROFILE_START(GFXBeginScene);

   bool beginSceneRes = GFX->beginScene();

   // Update the offscreen gui texture canvases.
   GuiTextureCanvas::updateCanvases(); // <<<<<<
   
   PROFILE_END();

Also most likely you will have to add
#include "GuiTextureCanvas.h"
to the end of the includes at the top of guicanvas.cpp (not .h!).
#42
11/13/2009 (3:50 pm)
I got the source code in without a sweat! Good job! =D

I only get black color on the materials though, most likely a script error on my end!
#43
11/13/2009 (7:25 pm)
I experience that too in some cases... its far from stable.
Especially since each gui can only exist in one canvas at a time. Im still trying to find a way to solve this problem, since i wanted to use this to simulate desktops in the world, but for each machine separately ... hmm
#44
01/13/2010 (4:13 am)
I got black too......
#45
03/30/2010 (10:18 am)
Has this been successfully ported to T3D of any version?
#46
03/30/2010 (10:20 am)
@Lethal

Where do you define the GuiTextureCanvas for use on an object?
#47
06/30/2010 (4:57 am)
@Lethal
Quote:add to the public (i know, i know) section of the declarations:
view plainprint?
GuiTextureCanvas* guiTexCanvas;

I may just be in need of coffee but am I putting this in the

class ProcessedMaterial
{
public:

And it is throwing a lot of UUID errors in rpcdce.h, winscard.h, and a few others.

Running T3D 1.1 beta 1
#48
08/29/2010 (11:04 pm)
double post
#49
08/29/2010 (11:06 pm)
@ J S
Look here for the fix for your problem:
http://www.torquepowered.com/community/forums/viewthread/114057

After I did those changes then I got it to compile.

I'm still having problems with making the static shape render anything other than black.

Can anyone supply a model which they know work? :)

I'm using T3D 1.1 beta 2
#50
09/02/2010 (2:41 am)
Sorry for the long pause ;)
and thanks to Aleksander for bugging me per mail, since i shamefully gotta admit i forgot about my posting here!

So, now code talk:
Actually i didnt test it since moving from 1.0.1 to beta2.
Also, i coded myself a texture-override feature for statics and shapebases that exchanges textures for arbitrary target like a switch and a system of canvas source objects that create canvases, textures and materials automatically in code. The problem with individual versions of guis for different instances of the same gui type was solved with only using internal names and a handwritten copy method for the gui, so you could request
Therefore i dont use the manually defined canvases anymore.

But a problem i ran into was the resolution of the canvas and the texture distortion.
If the uv-mapping is screwed up, the texture might be horribly distorted. But that doesnt seem to be the case with the black gui... hmm..
Now, i use a double tap system that forces the same resolution to canvas and actual texture in the canvas. I think out of the box its not successfully possible to change the canvasses resolution from script, since i remember coding my own methods for that. Yeah, there doesnt seem to be a method for that. I also decoupled the canvasses size from the guicontrol it owns (which enforces its size onto the offscreen-textue in the GuiTextureCanvas::setControl() method, while remaining a safeguard to not be smaller than the owned gui.
Also, i found that only 800x600 and 1024x768 give you sane results. Higher might work, but lower may cease to render the gui.
I also draw a giant black rectangle before the actual gui drawing to overcome strange results with my transparent gui windows. But i will model that to be an option, since i want to use them gui textures on transparent materials like windows or HUDs, which wouldnt work with the black background.

If you dont do something similar (the black background), the gui should render a pink background (which is the transparency color) or whatever is "behind" the gui. So it going black sounds strange.

Do you render a cursor on the gui?

try this :
// render cursor
    if(mShowTexCursor)
    {
        PrimBuild::color4i(255, 255, 255, 200);
        PrimBuild::begin(GFXTriangleFan, 3);
            PrimBuild::vertex2f(mCurPos.x, mCurPos.y);
            PrimBuild::vertex2f(mCurPos.x+10, mCurPos.y);
            PrimBuild::vertex2f(mCurPos.x, mCurPos.y+10);
        PrimBuild::end();
    }

inside the canvas render frame method before
GFX->popActiveRenderTarget();
at the end.
mCurPos is my variable that stores the current cursor pos, you will have your own. In the current version i simply grab the input of the default.bind.cs fire(), yaw() and pitch() methods and send them to the currently active canvas (if any) and then send them down the throat of overloaded virtual methods like onMouseDown() etc, so they send mouse movement and triggers to their owned controls the "natural" way. The texture canvas has to keep track of the cursor pos though, since the regular gui canvas relies on the actual platform cursor for that.

If you got that, you can try and move the cursor around. Using a gui with a running theora video texture also works great for testing. However, with the cursor its also easy to track if the resolutions are set correctly etc.
Also, you could use some gui control with a giant but narrow grid to display on the texture, which may also tell you something about distortions of whatever...

but i'd really start with the resolution.

If someones interested in certain parts of my described additions, lemme know and i may post some snippets. Cant quite post the whole thing now, since it stretches over several files (like an octopus :D ) now and i dont have time to diff the sh*t out of them. Maybe sometime in the future. Will also look here some more often now.
#51
09/02/2010 (5:00 pm)
@Lethal Concept
Wow! Thank you so much for your feedback!
I now have gone carefully through my gui file, and it is in the dimension of 1024x768, so I think that is not the issue? Also, the Gui is a simple GuiControl with at bitmap showing a grid so I could have seen any strange displacements, but alas, I see nothing but blackness :(

I also tried to add the mouse cursor but got some errors I couldn't figure out, and also I really don't need it for my project, but others may of course :)

I have some quick questions:
1. Does the size of the texture matter on which the gui is drawn? My test model is a box made in blender size 10x1x10, with one side assigned to a 512x512 size texture. It is this texture which I bind the Material to, which has the GuiTextureCanvas.
2. Is there any important properties of the model in question which needs to be fullfilled? Size, type, textures, etc?

I feel I'm really close! Everything compiles nicely, just get that blackness away!

If you have a testmodel, and/or testgui, which you know positively works then that would be an invaluable asset!

Thank you so much again :)
#52
09/02/2010 (5:05 pm)
As far as i saw it working here, the mere texture size (on the object) is not relevant.
But as i said, the texture the texturecanvas is creating is sized by the guicontrol you use in the canvas.

I do it like this:

void GuiTextureCanvas::setControl( GuiControl* control )
{
   if ( mGuiControl != control ) {
      mGuiControl = control;
   }

   if ( !mGuiControl ) 
   {
      mTextureHandle = NULL;
      //Con::errorf("WARNING: GuiTexCanvas %s (%d) couldnt find guicontrol: %s", getName(), getId(), mGuiControlName);
      return;
   }
   Point2I extent(getExtent());
   if(extent.x < mGuiControl->getExtent().x)
        extent.x = mGuiControl->getExtent().x;
   if(extent.y < mGuiControl->getExtent().y)
        extent.y = mGuiControl->getExtent().y;     

    setExtent(extent);
    _correctTexSize();
}


void GuiTextureCanvas::_correctTexSize()
{
    if (  !mTextureHandle || 
         mTextureHandle->getWidth() != getExtent().x ||
         mTextureHandle->getHeight() != getExtent().y ) 
   {
      mTextureHandle.set(  getExtent().x, 
                           getExtent().y, 
                           GFXFormatR8G8B8A8, 
                           &GFXDefaultRenderTargetProfile, 
                           "" );
   }
}

Still have to find some time to test it in B2, probably stuff changed...

And you dont need a special testgui or testobject. I first tested it on the cube model which ships with Torque. You just need to know the name of the texture target on the model, but thats not your problem obviously. Everything works as a testgui, but it best be some kind of gui that stretches over the whole screen (or at least the container it is in), so you dont just miss it because its hanging in a corner you cant see. You just have to make sure the guicontrol in question wasnt loaded into / added to another canvas instance (regular or texture), since that causes problems.

you may also want to check if the rendering method of the texturecanvas really is called, so try to run thru it in debug mode and place some breakpoints in the rendering method. you can also check if it uses sane values there.
#53
09/02/2010 (6:43 pm)
@Lethal Concept
Hi! You respond faster then your own shadow ;p

I added your code, swapped your old setControl with the new one. Went in without any pain. Black still!

So, I added a lot of Con::errorf()'s, in all the mayor methods in GuiTextureCanvas.
I got feedback in the console for the following methods:
GuiTextureCanvas::onAdd()
GuiTextureCanvas::setControl( GuiControl* control )
But these did not fire; (I put the Con's at the beginning of the methods so the returns didn't trigger either)
GuiTextureCanvas::renderFrame( bool preRenderOnly, bool bufferSwap )
GuiTextureCanvas::updateCanvases()

So if I understand correctly, the canvas isn't being rendered at all?
#54
09/02/2010 (8:20 pm)
Ah, i think i found it.

In the opening post, theres this:

In GuiCanvas::renderFrame, near line 1219, add the following bold code:

GFX->setActiveDevice( 0 );
GFX->beginScene();

// Update the offscreen gui texture canvases.
GuiTextureCanvas::updateCanvases(); // <<<<<<

// do this at beginning of frame
updateReflections();

and with Beta2, it looks like this (same method, around line 1620):

PROFILE_START(GFXBeginScene);

   bool beginSceneRes = GFX->beginScene();
   
   GuiTextureCanvas::updateCanvases(); // <<<<<<
   
   PROFILE_END();

And most likely you will have to add

#include "GuiTextureCanvas.h"
to the end of the includes at the top of guicanvas.cpp (not .h!).

Thats whats missing and therefor the texturecanvases weren drawing at all.
Same over here btw, the change must have slipped the merge process.
#55
09/02/2010 (8:24 pm)
That did it!! :D

Thank you so much! For the quick responses and all the help! :)
#56
09/02/2010 (8:28 pm)
You're welcome.

General advice when somethings not working: Step thru it and see if the code is really doing what you expect and is executed at all.
Programming is 90% control logic.
#57
03/09/2011 (9:51 pm)
Hi Lethal,
Great thanks for providing the T3D version of the texturecanvas. I have followed your steps to integrate it into T3D. I am having some problem to get the gui control shown on a model's surface. I can see the gui control on the surface in material preview window. But when direct view the model in the world space, there is no gui control shown. Do you have any idea what might be wrong?
#58
03/20/2012 (1:20 pm)
Hmm, shooting from the hip, I'd say that this is because the texture it replaces is kind of offset, so the gui isn't rendered in the visible/rendered part of the texture.

Did you use different models to test it?
I like to test most stuff with the simple cube.dae that came with some version of T3D. If it doesn't show up there, we can dig deeper.


Btw, to elaborate on something I wrote some posts back regarding the instances.

I ended up using custom script methods that copy gui templates and instanciate them. I call those script functions from within a special class that holds instances of GuiTextureCanvases. If there's demand, I might share some more detail on this, but you won't get around building a system around it.
#59
04/29/2012 (7:28 am)
does anyone have the original files from the download from this resource?
#60
08/18/2012 (9:35 pm)
I would also appreciate either the original files or even updated ones to incorporate this resource into my project.
Page«First 1 2 3 Next»