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:
In engine\gui\core\guiTSControl.cpp, add the following console function:
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:
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:
In engine\math\mathUtils.cpp:
Before line 52 which reads:
inline bool isPow2(const U32 number) { return (number & (number - 1)) == 0; }
Add:
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:
To:
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:
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:
Near line 3506, before function TSMesh::findTangent, add the following functions:
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:
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!
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
}
if( guiTextureCanvasName )
{
guiTextureCanvas = dynamic_cast
}
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 ChangeIn 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!
About the author
#22
08/22/2007 (11:31 am)
@Yves - This resource is for TGEA and not TGE.
#23
I would like to test it but I prefer to ask before is someone has yet tryed it...
TNX :)
JoZ
02/12/2008 (9:51 am)
Has anyone tryed it in TGEA 1.0.3?I would like to test it but I prefer to ask before is someone has yet tryed it...
TNX :)
JoZ
#24
02/16/2008 (12:41 am)
Yes it's working in TGEA 1.0.3.
#25
03/27/2008 (9:41 pm)
I got this running in AFXA, I definitely need to update this resource! Wasn't fun going through my old instructions.
#26
04/02/2008 (4:19 am)
That's awesome. =)
#27
04/07/2008 (8:17 am)
Does this work in 1.7.0, and further more, does it allow for render to texture using a camera as the source?
#28
eb7898@hotmail.com
thx
04/10/2008 (3:50 pm)
Dave Young, if you can update this resource for 1.7....I will be happy to donate $ for your time.eb7898@hotmail.com
thx
#31
06/20/2008 (4:49 am)
so... anyone got any clues what the relevant equivalents are for setstagedata ect are now?
#34
03/22/2009 (2:15 am)
Is there any chance anyone has gotten this to work with TGEA 1.8.1? The function castRayTri must have the matrial lookup portion changed and I am having alot of trouble doing it.
#35
04/20/2009 (8:32 pm)
knock knock...anyone there ? Dave ?
#36
Any plan to update your resource? It's really very useful, while it't not clear how to use it?
Especially how to make mouse interact with the mapped GUI accurately. Would you please give some successful examples?
Thanks,
05/31/2009 (11:32 pm)
Hi, Dave,Any plan to update your resource? It's really very useful, while it't not clear how to use it?
Especially how to make mouse interact with the mapped GUI accurately. Would you please give some successful examples?
Thanks,
#37
I'd be interested in an update of this resource too. Also, any help of those that already tried this with T3D is appreciated. I dont care for interaction atm, i just want it painted into the world, but im struggling with the render targets atm.
11/10/2009 (6:11 pm)
Im currently trying to get this to work in T3D. I'd be interested in an update of this resource too. Also, any help of those that already tried this with T3D is appreciated. I dont care for interaction atm, i just want it painted into the world, but im struggling with the render targets atm.
#38
Atm im creating a new render target to draw this to, which leads to another application window so far. Also, the code which was in material.h/cpp got changed and split over two classes (material and processed material) which arent easily associated as far as i can see it.
Theres also some weird stuff going on, since the material moved the value of baseTex[0] to diffuseMap[0] after i created it. I still dont know where all these definitions are stored, but torque tried to delete the definition i wrote out of the file...
If someone else is interested, i can post the changes i did so far.
// edit: Proof!
http://flickr.com/gp/lethalconcept/YqTCMS
11/11/2009 (11:20 am)
I ported parts of it to T3D. I left out all the raycasting for now.Atm im creating a new render target to draw this to, which leads to another application window so far. Also, the code which was in material.h/cpp got changed and split over two classes (material and processed material) which arent easily associated as far as i can see it.
Theres also some weird stuff going on, since the material moved the value of baseTex[0] to diffuseMap[0] after i created it. I still dont know where all these definitions are stored, but torque tried to delete the definition i wrote out of the file...
If someone else is interested, i can post the changes i did so far.
// edit: Proof!
http://flickr.com/gp/lethalconcept/YqTCMS
#39
11/11/2009 (5:53 pm)
Im very interested in a t3d version! :)
#40
11/12/2009 (1:14 am)
Ok, i'll keep you updated here. 
Torque 3D Owner Maxime Jouin
Default Studio Name
Thanks for a quick reply, we really need this to work real soon...