Porting RTS selection circle code to TGEA
by Peter Haffenreffer · in RTS Starter Kit · 10/16/2008 (11:43 am) · 11 replies
I am in the process of porting the selection circle code from the RTS kid to TGEA.
I am extremely close to having it work, and it actually does most of the time.
For some reason, the selection circle doesn't show up on some of the terrain chunks. It shows up on all of the terrain chunks on the parameter of the map, and all of the chunks that have some elevation to it. The circle just doesn't show up on the flat terrain.
I will post my code in the following replies.
I realize now that maybe posting all of the code may have not been the greatest idea, so I've uploaded the three files here:
www.mediafire.com/?sharekey=aab039d7c4e20a90d2db6fb9a8902bda
terrSelection.cpp needs to be added to your project. terrRenderer.h/cpp can just be copied over the files you have now.
I am extremely close to having it work, and it actually does most of the time.
For some reason, the selection circle doesn't show up on some of the terrain chunks. It shows up on all of the terrain chunks on the parameter of the map, and all of the chunks that have some elevation to it. The circle just doesn't show up on the flat terrain.
I will post my code in the following replies.
I realize now that maybe posting all of the code may have not been the greatest idea, so I've uploaded the three files here:
www.mediafire.com/?sharekey=aab039d7c4e20a90d2db6fb9a8902bda
terrSelection.cpp needs to be added to your project. terrRenderer.h/cpp can just be copied over the files you have now.
#2
Includes & static defines:
Change:
to:
Change:
to:
Further down in that function, change:
to:
and in the same function still:
to:
10/16/2008 (12:03 pm)
In terrRender.cppIncludes & static defines:
#include "gfx/primBuilder.h" #include "gui/core/guiTypes.h" static SelectionTriangle* sgCurrSelectionTris = NULL; static U32 sgNumSelectionTris = 0; GFXTexHandle TerrainRender::mSelectionCircle = NULL;
Change:
void TerrainRender::emitTerrChunk(SquareStackNode *n, F32 squareDistance, U32 lightMask, F32 zDelta, F32 squareDistanceLOD)
{
GridChunk *gc = mCurrentBlock->findChunk(n->pos);
EmitChunk *chunk = (EmitChunk *) FrameAllocator::alloc(sizeof(EmitChunk));
chunk->x = n->pos.x + mBlockOffset.x + mTerrainOffset.x;
chunk->y = n->pos.y + mBlockOffset.y + mTerrainOffset.y;
chunk->lightMask = lightMask;
...to:
void TerrainRender::emitTerrChunk(SquareStackNode *n, F32 squareDistance, U32 lightMask, SelectionField selectionMask, F32 zDelta, F32 squareDistanceLOD)
{
GridChunk *gc = mCurrentBlock->findChunk(n->pos);
EmitChunk *chunk = (EmitChunk *) FrameAllocator::alloc(sizeof(EmitChunk));
chunk->x = n->pos.x + mBlockOffset.x + mTerrainOffset.x;
chunk->y = n->pos.y + mBlockOffset.y + mTerrainOffset.y;
chunk->lightMask = lightMask;
chunk->selectionMask = selectionMask;
...Change:
void TerrainRender::processBlock(SceneState*, EdgeParent *topEdge, EdgeParent *rightEdge, EdgeParent *bottomEdge, EdgeParent *leftEdge)
{
SquareStackNode stack[TerrainBlock::BlockShift*4];
Point3F minPoint, maxPoint;
// Set up the root node of the stack...
stack[0].level = TerrainBlock::BlockShift;
stack[0].clipFlags = (BIT(mNumClipPlanes) - 1) | FarSphereMask; // test all the planes
stack[0].pos.set(0,0);
stack[0].top = topEdge;
stack[0].right = rightEdge;
stack[0].bottom = bottomEdge;
stack[0].left = leftEdge;
stack[0].lightMask = BIT(mDynamicLightCount) - 1; // test all the lights
...to:
void TerrainRender::processBlock(SceneState*, EdgeParent *topEdge, EdgeParent *rightEdge, EdgeParent *bottomEdge, EdgeParent *leftEdge)
{
SquareStackNode stack[TerrainBlock::BlockShift*4];
Point3F minPoint, maxPoint;
// Set up the root node of the stack...
stack[0].level = TerrainBlock::BlockShift;
stack[0].clipFlags = (BIT(mNumClipPlanes) - 1) | FarSphereMask; // test all the planes
stack[0].pos.set(0,0);
stack[0].top = topEdge;
stack[0].right = rightEdge;
stack[0].bottom = bottomEdge;
stack[0].left = leftEdge;
stack[0].lightMask = BIT(mDynamicLightCount) - 1; // test all the lights
for (U32 k = 0; k < mDynamicSelectionCount; k++)
stack[0].selectionMask.set(k);
...Further down in that function, change:
// If we have been marked as lit we need to see if that still holds true...
if(n->lightMask)
n->lightMask = testSquareLights(sq, n->level, n->pos, n->lightMask);
if(n->level == 2)
{
// We've tessellated far enough, stop here.
F32 squareDistanceLOD = squareDistance;
if (!mCurrentBlock->isTiling())
{
// Lock border LOD so no gaps
if (n->pos.x == 0 || n->pos.x >= (TerrainBlock::BlockSize-4))
squareDistanceLOD = 0.5f;
if (n->pos.y == 0 || n->pos.y >= (TerrainBlock::BlockSize-4))
squareDistanceLOD = 0.5f;
}
emitTerrChunk(n, squareDistance, n->lightMask, zDiff, squareDistanceLOD);
curStackSize--;
continue;
}
...to:
// If we have been marked as lit we need to see if that still holds true...
if(n->lightMask)
n->lightMask = testSquareLights(sq, n->level, n->pos, n->lightMask);
(n->selectionMask)
n->selectionMask = TestSquareSelections(sq, n->level, n->pos, n->selectionMask);
if(n->level == 2)
{
// We've tessellated far enough, stop here.
F32 squareDistanceLOD = squareDistance;
if (!mCurrentBlock->isTiling())
{
// Lock border LOD so no gaps
if (n->pos.x == 0 || n->pos.x >= (TerrainBlock::BlockSize-4))
squareDistanceLOD = 0.5f;
if (n->pos.y == 0 || n->pos.y >= (TerrainBlock::BlockSize-4))
squareDistanceLOD = 0.5f;
}
emitTerrChunk(n, squareDistance, n->lightMask, n->selectionMask, zDiff, squareDistanceLOD);
curStackSize--;
continue;
}
...and in the same function still:
for(S32 i = 1; i < 4; i++)
{
n[i].level = nextLevel;
n[i].clipFlags = nextClipFlags;
n[i].lightMask = n->lightMask;
}
...to:
for(S32 i = 1; i < 4; i++)
{
n[i].level = nextLevel;
n[i].clipFlags = nextClipFlags;
n[i].lightMask = n->lightMask;
].selectionMask = n->selectionMask;
}
...
#3
Here is my whole renderChunkNormal function:
continued on next post:
10/16/2008 (12:06 pm)
Still in terrRender.cpp:Here is my whole renderChunkNormal function:
void TerrainRender::renderChunkNormal(EmitChunk *chunk)
{
PROFILE_START(TerrainRender_renderChunkNormal);
bool skipEdge = false;
U32 startXFIndex = TerrBatch::mCurIndex;
if (!mCurrentBlock->isTiling())
{
if (chunk->x + 4 >= TerrainBlock::BlockSize || chunk->y + 4 >= TerrainBlock::BlockSize)
skipEdge = true;
}
// Emits a max of 96 indices
// Emits a max of 25 vertices
ChunkEdge *e0 = chunk->edge[0];
ChunkEdge *e1 = chunk->edge[1];
ChunkEdge *e2 = chunk->edge[2];
ChunkEdge *e3 = chunk->edge[3];
if(e0->xfIndex != TerrBatch::mCurXF)
{
if(!e0->xfIndex)
fixEdge(e0, chunk->x, chunk->y + 4, 1, 0);
TerrBatch::emit( *e0 );
}
if(e1->xfIndex != TerrBatch::mCurXF)
{
if(!e1->xfIndex)
fixEdge(e1, chunk->x + 4, chunk->y + 4, 0, -1);
TerrBatch::emit( *e1 );
}
if(e2->xfIndex != TerrBatch::mCurXF)
{
if(!e2->xfIndex)
fixEdge(e2, chunk->x, chunk->y, 1, 0);
TerrBatch::emit( *e2 );
}
if(e3->xfIndex != TerrBatch::mCurXF)
{
if(!e3->xfIndex)
fixEdge(e3, chunk->x, chunk->y + 4, 0, -1);
TerrBatch::emit( *e3 );
}
// Edges above, give us 12 verts
// Corners below are 4 more
U16 p0 = TerrBatch::emit(e0->p1);
U16 p1 = TerrBatch::emit(e0->p2);
U16 p2 = TerrBatch::emit(e2->p2);
U16 p3 = TerrBatch::emit(e2->p1);
// build the interior points (one more vert):
U16 ip0 = TerrBatch::emit(chunk->x + 2, chunk->y + 2);
F32 growFactor = chunk->growFactor;
// So now we have a total of 17 verts
// Keeping track of triangle information for drawing the selection circle
Vector< U32 > triangleDrawTypes;
Vector< U32 > triangleCounts;
U32 indexStart;
if(chunk->subDivLevel >= 1)
{
// just emit the fan for the whole square:
S32 i;
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
if(e0->pointCount)
{
TerrBatch::emitTriangle(ip0, p0, e0->pointIndex); // 3 indices
for(i = 1; i < e0->pointCount; i++)
TerrBatch::emitFanStep(e0->pointIndex + i); // 9 i
TerrBatch::emitFanStep(p1); // 3 i
}
else
{
TerrBatch::emitTriangle(ip0, p0, p1);
}
for(i = 0; i < e1->pointCount; i++)
TerrBatch::emitFanStep(e1->pointIndex + i); // 9 indices
TerrBatch::emitFanStep(p2); // 3 indices
for(i = e2->pointCount - 1; i >= 0; i--)
TerrBatch::emitFanStep(e2->pointIndex + i); // 6 i
TerrBatch::emitFanStep(p3); // 3 i
for(i = e3->pointCount - 1; i >= 0; i--)
TerrBatch::emitFanStep(e3->pointIndex + i); // 6 i
TerrBatch::emitFanStep(p0); // 3 i
// Total indices for this path: 42 indices
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
else
{
if(chunk->subDivLevel == 0)
{
// Add yet four verts more to the list! (now we're at 21)
U32 ip1 = TerrBatch::emitInterp(p0, ip0, chunk->x + 1, chunk->y + 3, growFactor);
U32 ip2 = TerrBatch::emitInterp(p1, ip0, chunk->x + 3, chunk->y + 3, growFactor);
U32 ip3 = TerrBatch::emitInterp(p2, ip0, chunk->x + 3, chunk->y + 1, growFactor);
U32 ip4 = TerrBatch::emitInterp(p3, ip0, chunk->x + 1, chunk->y + 1, growFactor);
// emit the 4 fans:
if((chunk->emptyFlags & CornerEmpty_0_1) != CornerEmpty_0_1)
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
TerrBatch::emitTriangle(ip1, p0, e0->pointIndex); // 3
if(e0->pointCount == 3)
TerrBatch::emitFanStep (e0->pointIndex + 1); // 3
TerrBatch::emitFanStep (ip0); // 3
if(e3->pointCount == 1)
TerrBatch::emitFanStep ( e3->pointIndex );
else
{
TerrBatch::emitFanStep ( e3->pointIndex + 1 ); // 3
TerrBatch::emitFanStep ( e3->pointIndex ); // 3
}
TerrBatch::emitFanStep ( p0 ); // 3
// Total emitted indices 18
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
if((chunk->emptyFlags & CornerEmpty_1_1) != CornerEmpty_1_1)
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
TerrBatch::emitTriangle( ip2, p1, e1->pointIndex );
if(e1->pointCount == 3)
TerrBatch::emitFanStep ( e1->pointIndex + 1 );
TerrBatch::emitFanStep ( ip0 );
if(e0->pointCount == 1)
TerrBatch::emitFanStep( e0->pointIndex );
else
{
TerrBatch::emitFanStep( e0->pointIndex + 1 );
TerrBatch::emitFanStep( e0->pointIndex + 2 );
}
TerrBatch::emitFanStep( p1 );
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
if((chunk->emptyFlags & CornerEmpty_1_0) != CornerEmpty_1_0)
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
if(e2->pointCount == 1)
TerrBatch::emitTriangle( ip3, p2, e2->pointIndex );
else
{
TerrBatch::emitTriangle( ip3, p2, e2->pointIndex + 2 );
TerrBatch::emitFanStep( e2->pointIndex + 1 );
}
TerrBatch::emitFanStep( ip0 );
if(e1->pointCount == 1)
TerrBatch::emitFanStep( e1->pointIndex );
else
{
TerrBatch::emitFanStep( e1->pointIndex + 1 );
TerrBatch::emitFanStep( e1->pointIndex + 2 );
}
TerrBatch::emitFanStep( p2 );
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
if((chunk->emptyFlags & CornerEmpty_0_0) != CornerEmpty_0_0)
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
if(e3->pointCount == 1)
TerrBatch::emitTriangle( ip4, p3, e3->pointIndex);
else
{
TerrBatch::emitTriangle( ip4, p3, e3->pointIndex + 2);
TerrBatch::emitFanStep( e3->pointIndex + 1 );
}
TerrBatch::emitFanStep( ip0 );
if(e2->pointCount == 1)
TerrBatch::emitFanStep( e2->pointIndex );
else
{
TerrBatch::emitFanStep( e2->pointIndex + 1 );
TerrBatch::emitFanStep( e2->pointIndex );
}
TerrBatch::emitFanStep( p3 );
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
// Four fans of 18 indices = 72 indices
}
else
{
// subDiv == -1
U32 ip1 = TerrBatch::emit(chunk->x + 1, chunk->y + 3);
U32 ip2 = TerrBatch::emit(chunk->x + 3, chunk->y + 3);
U32 ip3 = TerrBatch::emit(chunk->x + 3, chunk->y + 1);
U32 ip4 = TerrBatch::emit(chunk->x + 1, chunk->y + 1);
U32 ip5 = TerrBatch::emitInterp(e0->pointIndex + 1, ip0, chunk->x + 2, chunk->y + 3, growFactor);
U32 ip6 = TerrBatch::emitInterp(e1->pointIndex + 1, ip0, chunk->x + 3, chunk->y + 2, growFactor);
U32 ip7 = TerrBatch::emitInterp(e2->pointIndex + 1, ip0, chunk->x + 2, chunk->y + 1, growFactor);
U32 ip8 = TerrBatch::emitInterp(e3->pointIndex + 1, ip0, chunk->x + 1, chunk->y + 2, growFactor);continued on next post:
#4
10/16/2008 (12:07 pm)
// Or eight more points, in which case we hit 25 verts total..
// now do the squares:
if(chunk->emptyFlags & CornerEmpty_0_1)
{
if((chunk->emptyFlags & CornerEmpty_0_1) != CornerEmpty_0_1)
{
triangleDrawTypes.push_back( GFXTriangleList );
indexStart = TerrBatch::mCurIndex;
if(!(chunk->emptyFlags & SquareEmpty_0_3))
{
TerrBatch::emitTriangle(ip1, e3->pointIndex, p0);
TerrBatch::emitTriangle(ip1, p0, e0->pointIndex);
}
if(!(chunk->emptyFlags & SquareEmpty_1_3))
{
TerrBatch::emitTriangle(ip1, e0->pointIndex, e0->pointIndex + 1);
TerrBatch::emitTriangle(ip1, e0->pointIndex + 1, ip5);
}
if(!(chunk->emptyFlags & SquareEmpty_1_2))
{
TerrBatch::emitTriangle(ip1, ip5, ip0);
TerrBatch::emitTriangle(ip1, ip0, ip8);
}
if(!(chunk->emptyFlags & SquareEmpty_0_2))
{
TerrBatch::emitTriangle(ip1, ip8, e3->pointIndex + 1);
TerrBatch::emitTriangle(ip1, e3->pointIndex + 1, e3->pointIndex);
}
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
// 24 indices on this path ^^^
}
else
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
TerrBatch::emitTriangle( ip1, p0, e0->pointIndex );
TerrBatch::emitFanStep( e0->pointIndex + 1 );
TerrBatch::emitFanStep( ip5 );
TerrBatch::emitFanStep( ip0 );
TerrBatch::emitFanStep( ip8 );
TerrBatch::emitFanStep( e3->pointIndex + 1 );
TerrBatch::emitFanStep( e3->pointIndex );
TerrBatch::emitFanStep( p0 );
// And 24 here.
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
if(chunk->emptyFlags & CornerEmpty_1_1)
{
if((chunk->emptyFlags & CornerEmpty_1_1) != CornerEmpty_1_1)
{
triangleDrawTypes.push_back( GFXTriangleList );
indexStart = TerrBatch::mCurIndex;
if(!(chunk->emptyFlags & SquareEmpty_3_3))
{
TerrBatch::emitTriangle(ip2, e0->pointIndex + 2, p1);
TerrBatch::emitTriangle(ip2, p1, e1->pointIndex);
}
if(!(chunk->emptyFlags & SquareEmpty_3_2))
{
TerrBatch::emitTriangle(ip2, e1->pointIndex, e1->pointIndex + 1);
TerrBatch::emitTriangle(ip2, e1->pointIndex + 1, ip6);
}
if(!(chunk->emptyFlags & SquareEmpty_2_2))
{
TerrBatch::emitTriangle(ip2, ip6, ip0);
TerrBatch::emitTriangle(ip2, ip0, ip5);
}
if(!(chunk->emptyFlags & SquareEmpty_2_3))
{
TerrBatch::emitTriangle(ip2, ip5, e0->pointIndex + 1);
TerrBatch::emitTriangle(ip2, e0->pointIndex + 1, e0->pointIndex + 2);
}
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
}
else
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
TerrBatch::emitTriangle( ip2, p1, e1->pointIndex );
TerrBatch::emitFanStep ( e1->pointIndex + 1 );
TerrBatch::emitFanStep ( ip6 );
TerrBatch::emitFanStep ( ip0 );
TerrBatch::emitFanStep ( ip5 );
TerrBatch::emitFanStep ( e0->pointIndex + 1 );
TerrBatch::emitFanStep ( e0->pointIndex + 2 );
TerrBatch::emitFanStep ( p1 );
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
if(chunk->emptyFlags & CornerEmpty_1_0)
{
if((chunk->emptyFlags & CornerEmpty_1_0) != CornerEmpty_1_0)
{
triangleDrawTypes.push_back( GFXTriangleList );
indexStart = TerrBatch::mCurIndex;
if(!(chunk->emptyFlags & SquareEmpty_3_0))
{
TerrBatch::emitTriangle (ip3, e1->pointIndex + 2, p2);
TerrBatch::emitTriangle (ip3, p2, e2->pointIndex + 2);
}
if(!(chunk->emptyFlags & SquareEmpty_2_0))
{
TerrBatch::emitTriangle (ip3, e2->pointIndex + 2, e2->pointIndex + 1);
TerrBatch::emitTriangle (ip3, e2->pointIndex + 1, ip7);
}
if(!(chunk->emptyFlags & SquareEmpty_2_1))
{
TerrBatch::emitTriangle (ip3, ip7, ip0);
TerrBatch::emitTriangle (ip3, ip0, ip6);
}
if(!(chunk->emptyFlags & SquareEmpty_3_1))
{
TerrBatch::emitTriangle (ip3, ip6, e1->pointIndex + 1);
TerrBatch::emitTriangle (ip3, e1->pointIndex + 1, e1->pointIndex + 2);
}
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
}
else
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
TerrBatch::emitTriangle(ip3, p2, e2->pointIndex + 2 );
TerrBatch::emitFanStep( e2->pointIndex + 1 );
TerrBatch::emitFanStep( ip7 );
TerrBatch::emitFanStep( ip0 );
TerrBatch::emitFanStep( ip6 );
TerrBatch::emitFanStep( e1->pointIndex + 1 );
TerrBatch::emitFanStep( e1->pointIndex + 2 );
TerrBatch::emitFanStep( p2 );
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
if(chunk->emptyFlags & CornerEmpty_0_0)
{
if((chunk->emptyFlags & CornerEmpty_0_0) != CornerEmpty_0_0)
{
triangleDrawTypes.push_back( GFXTriangleList );
indexStart = TerrBatch::mCurIndex;
if(!(chunk->emptyFlags & SquareEmpty_0_0))
{
TerrBatch::emitTriangle(ip4, e2->pointIndex, p3);
TerrBatch::emitTriangle(ip4, p3, e3->pointIndex + 2);
}
if(!(chunk->emptyFlags & SquareEmpty_0_1))
{
TerrBatch::emitTriangle(ip4, e3->pointIndex + 2, e3->pointIndex + 1);
TerrBatch::emitTriangle(ip4, e3->pointIndex + 1, ip8);
}
if(!(chunk->emptyFlags & SquareEmpty_1_1))
{
TerrBatch::emitTriangle(ip4, ip8, ip0);
TerrBatch::emitTriangle(ip4, ip0, ip7);
}
if(!(chunk->emptyFlags & SquareEmpty_1_0))
{
TerrBatch::emitTriangle(ip4, ip7, e2->pointIndex + 1);
TerrBatch::emitTriangle(ip4, e2->pointIndex + 1, e2->pointIndex);
}
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
}
else
{
triangleDrawTypes.push_back( GFXTriangleFan );
indexStart = TerrBatch::mCurIndex;
TerrBatch::emitTriangle( ip4, p3, e3->pointIndex + 2 );
TerrBatch::emitFanStep( e3->pointIndex + 1 );continued on next post:
#5
10/16/2008 (12:08 pm)
And to finish off that function:TerrBatch::emitFanStep( ip8 );
TerrBatch::emitFanStep( ip0 );
TerrBatch::emitFanStep( ip7 );
TerrBatch::emitFanStep( e2->pointIndex + 1 );
TerrBatch::emitFanStep( e2->pointIndex );
TerrBatch::emitFanStep( p3 );
triangleCounts.push_back(TerrBatch::mCurIndex - indexStart);
}
}
// 4 chunks with 24 indices each: 96 indices
// Do dynamic selection here ( I guess ) -eric
if (chunk->selectionMask)
{
AssertFatal(triangleCounts.size() == triangleDrawTypes.size(), "triangle counts and triangle draw types not the same size");
for (U32 i = 0; i < MaxTerrainSelections; i++)
{
if (!chunk->selectionMask.test(i))
continue;
U32 k = 0;
for (U32 start = startXFIndex; start < TerrBatch::mCurIndex; ++k)
{
if (triangleDrawTypes[ k ] == GFXTriangleFan)
{
U32 count = triangleCounts[ k ];
U32 triCount = count - 2;
SelectionTriangle* selectionTris = (SelectionTriangle*)FrameAllocator::alloc(sizeof(SelectionTriangle) * triCount);
U32 j;
for (j = 0; j < (triCount-1); j++)
selectionTris[j].next = &selectionTris[j+1];
selectionTris[triCount-1].next = sgCurrSelectionTris;
sgCurrSelectionTris = selectionTris;
sgNumSelectionTris += triCount;
// Copy out tri data here...
for (j = 0; j < triCount; j++)
{
selectionTris[j].point1 = TerrBatch::mVertexStore[TerrBatch::mIndexStore[start + 0]].point;
selectionTris[j].point2 = TerrBatch::mVertexStore[TerrBatch::mIndexStore[start + j + 1]].point;
selectionTris[j].point3 = TerrBatch::mVertexStore[TerrBatch::mIndexStore[start + j + 2]].point;
buildSelectionTri(&selectionTris[j], &mTerrainSelections[i]);
}
start += count;
}
else
{
AssertFatal(triangleDrawTypes[ k ] == GFXTriangleList, "Error, bad start code!");
U32 count = triangleCounts[ k ];
AssertFatal((count / 3) * 3 == count, "Error, vertex count not divisible by 3!");
U32 triCount = count/3;
SelectionTriangle* selectionTris = (SelectionTriangle*)FrameAllocator::alloc(sizeof(SelectionTriangle) * triCount);
U32 j;
for (j = 0; j < (triCount-1); j++)
selectionTris[j].next = &selectionTris[j+1];
selectionTris[triCount-1].next = sgCurrSelectionTris;
sgCurrSelectionTris = selectionTris;
sgNumSelectionTris += triCount;
// Copy out tri data here...
for (j = 0; j < triCount; j++)
{
selectionTris[j].point1 = TerrBatch::mVertexStore[TerrBatch::mIndexStore[start + (j*3) + 0]].point;
selectionTris[j].point2 = TerrBatch::mVertexStore[TerrBatch::mIndexStore[start + (j*3) + 1]].point;
selectionTris[j].point3 = TerrBatch::mVertexStore[TerrBatch::mIndexStore[start + (j*3) + 2]].point;
buildSelectionTri(&selectionTris[j], &mTerrainSelections[i]);
}
start += count;
}
}
AssertFatal(k == triangleDrawTypes.size(), "Didn't iterate over all the trinagle draw types");
}
}
}
#6
In TerrRender::renderBlock(...):
add the following under buildLightArray():
change:
to:
and Finally, directly under
add:
I also added a console function for changing the selection circle texture:
10/16/2008 (12:08 pm)
And to finish off the changes in terrRender.cpp (still): In TerrRender::renderBlock(...):
add the following under buildLightArray():
buildSelectionArray();
change:
// Set up for the render... bool fixedfunction = GFX->getPixelShaderVersion() == 0.0; const MatrixF blockTransform = block->getTransform(); const Point3F cameraPosition = state->getCameraPosition(); GFX->setTextureStageColorOp(0, GFXTOPModulate); GFX->setTextureStageColorOp(1, GFXTOPDisable); GFX->setAlphaBlendEnable(false); GFX->setAlphaTestEnable(false); ...
to:
// Set up for the render... bool fixedfunction = GFX->getPixelShaderVersion() == 0.0; const MatrixF blockTransform = block->getTransform(); const Point3F cameraPosition = state->getCameraPosition(); GFX->setTextureStageColorOp(0, GFXTOPModulate); GFX->setTextureStageColorOp(1, GFXTOPDisable); GFX->setAlphaBlendEnable(false); GFX->setAlphaTestEnable(false); sgCurrSelectionTris = NULL; sgNumSelectionTris = 0; ...
and Finally, directly under
gChunkBatcher.renderChunkList(gChunkBatcher.mFog, NULL, sgData, fixedfunction ? TerrBatch::vertexTypeFog : TerrBatch::vertexTypeFullClipMapping, NULL, blockTransform, cameraPosition, NULL);
add:
//selections...
if (sgCurrSelectionTris && mSelectionCircle)
{
GFX->setAlphaBlendEnable( true );
GFX->setTextureStageColorOp( 0, GFXTOPModulate );
GFX->setSrcBlend( GFXBlendSrcAlpha );
GFX->setDestBlend( GFXBlendInvSrcAlpha );
GFX->setTexture( 0, mSelectionCircle );
GFX->setTextureStageAddressModeU( 0, GFXAddressBorder );
GFX->setTextureStageAddressModeV( 0, GFXAddressBorder );
SelectionTriangle* walk = sgCurrSelectionTris;
PrimBuild::begin( GFXTriangleList, sgNumSelectionTris * 3 );
while (walk)
{
if (walk->flags)
{
PrimBuild::color4f( walk->color.red, walk->color.green, walk->color.blue, walk->color.alpha );
PrimBuild::texCoord2f( walk->texco1.x, walk->texco1.y );
PrimBuild::vertex3fv( walk->point1 );
PrimBuild::color4f( walk->color.red, walk->color.green, walk->color.blue, walk->color.alpha );
PrimBuild::texCoord2f( walk->texco2.x, walk->texco2.y );
PrimBuild::vertex3fv( walk->point2 );
PrimBuild::color4f( walk->color.red, walk->color.green, walk->color.blue, walk->color.alpha );
PrimBuild::texCoord2f( walk->texco3.x, walk->texco3.y );
PrimBuild::vertex3fv( walk->point3 );
}
walk = walk->next;
}
PrimBuild::end();
GFX->setTexture( 0, NULL );
GFX->setSrcBlend( GFXBlendOne );
GFX->setDestBlend( GFXBlendOne );
}
...I also added a console function for changing the selection circle texture:
ConsoleFunction( SetSelectionCircleTexture, void, 2, 2, "(string filename)" )
{
if( argv[ 1 ] && argv[ 1 ][ 0 ] != '/0' )
TerrainRender::mSelectionCircle.set( argv[ 1 ], &GFXDefaultGUIProfile );
else
TerrainRender::mSelectionCircle = NULL;
}
#7
10/16/2008 (12:09 pm)
And, we need to add terrSelection.cpp#include "terrain\terrRender.h"
#include "CivilWarObjects\ui\guiRTSTSCtrl.h"
U32 TerrainRender::mDynamicSelectionCount;
TerrSelectionInfo TerrainRender::mTerrainSelections[MaxTerrainSelections];
SelectionField TerrainRender::TestSquareSelections(GridSquare *sq, S32 level, Point2I sqPos, SelectionField selectionMask)
{
SelectionField retMask;
F32 blockX = sqPos.x * mSquareSize + mBlockPos.x;
F32 blockY = sqPos.y * mSquareSize + mBlockPos.y;
F32 blockZ = fixedToFloat(sq->minHeight);
F32 blockSize = mSquareSize * (1 << level);
F32 blockHeight = fixedToFloat(sq->maxHeight - sq->minHeight);
Point3F vec;
S32 lastBit = mDynamicSelectionCount;
for (lastBit = mDynamicSelectionCount; lastBit > 0; lastBit--)
{
if (selectionMask.test(lastBit))
break;
}
for(S32 i = 0; i <= lastBit; i++)
{
if(selectionMask.test(i))
{
Point3F *pos = &mTerrainSelections[i].pos;
// test the visibility of this selection to box
// find closest point on box to selection and test
if(pos->z < blockZ)
vec.z = blockZ - pos->z;
else if(pos->z > (blockZ + blockHeight))
vec.z = pos->z - (blockZ + blockHeight);
else
vec.z = 0;
if(pos->x < blockX)
vec.x = blockX - pos->x;
else if(pos->x > blockX + blockSize)
vec.x = pos->x - (blockX + blockSize);
else
vec.x = 0;
if(pos->y < blockY)
vec.y = blockY - pos->y;
else if(pos->y > blockY + blockSize)
vec.y = pos->y - (blockY + blockSize);
else
vec.y = 0;
F32 dist = vec.lenSquared();
if(dist < mTerrainSelections[i].radiusSquared)
retMask.set(i);
}
}
return retMask;
}
void TerrainRender::addSelection(U32 index, SceneObject* obj, ColorF color)
{
// set the 'fo
TerrSelectionInfo & info = mTerrainSelections[index];
mCurrentBlock->getWorldTransform().mulP(obj->getPosition(), &info.pos);
Box3F box = obj->getObjBox();
info.radius = getMax(box.max.x - box.min.x, box.max.y - box.min.y);
info.radiusSquared = info.radius * info.radius;
//
info.r = color.red;
info.g = color.green;
info.b = color.blue;
Point3F dVec = mCamPos - obj->getPosition();
info.distSquared = mDot(dVec, dVec);
}
void TerrainRender::buildSelectionArray()
{
GuiRTSTSCtrl* playgui = dynamic_cast<GuiRTSTSCtrl*>(Sim::findObject( "mosbyPlayGui" ));
if (!playgui)
return;
GuiRTSTSCtrl::Selection& selection = playgui->getSelection();
GuiRTSTSCtrl::Selection& dragSelection = playgui->getDragSelection();
SceneObject* hitObject = playgui->getHitObject();
ColorF selectedColor = playgui->getSelectedColor();
ColorF selectColor = playgui->getToBeSelectedColor();
ColorF deselectColor = playgui->getToBeDeselectedColor();
// first do our current selection
U32 curIndex = 0;
for(U32 i = 0; i < playgui->getSelectionSize() && curIndex < MaxTerrainSelections; i++)
{
//don't draw things that are in the drag selection with this color
if(dragSelection.objInSet(selection[i]) || hitObject == selection[i])
continue;
addSelection(curIndex++, selection[i], selectedColor);
}
//now do the hit object if it exists and it's not terrain...
if (hitObject && curIndex < MaxTerrainSelections && !(hitObject->getTypeMask() & TerrainObjectType))
{
addSelection(curIndex++, hitObject, selectColor);
}
//and finally, drag selected items...
for(S32 i = 0; i < dragSelection.size() && curIndex < MaxTerrainSelections; i++)
{
if(hitObject == dragSelection[i])
continue;
if(selection.objInSet(dragSelection[i]))
addSelection(curIndex++, dragSelection[i], deselectColor);
else
addSelection(curIndex++, dragSelection[i], selectColor);
}
mDynamicSelectionCount = curIndex;
}
void TerrainRender::buildSelectionTri(SelectionTriangle* pTri, TerrSelectionInfo* pInfo)
{
// Get the plane normal
Point3F normal;
mCross((pTri->point1 - pTri->point2), (pTri->point3 - pTri->point2), &normal);
if (normal.lenSquared() < 1e-7)
{
pTri->flags = 0;
return;
}
PlaneF plane(pTri->point2, normal); // Assumes that mPlane.h normalizes incoming point
Point3F centerPoint;
F32 d = plane.distToPlane(pInfo->pos);
centerPoint = pInfo->pos - plane * d;
d = mFabs(d);
if (d >= pInfo->radius) {
pTri->flags = 0;
return;
}
F32 mr = mSqrt(pInfo->radiusSquared - d*d);
Point3F normalS;
Point3F normalT;
mCross(plane, Point3F(0, 1, 0), &normalS);
mCross(plane, normalS, &normalT);
PlaneF splane(centerPoint, normalS); // Assumes that mPlane.h normalizes incoming point
PlaneF tplane(centerPoint, normalT); // Assumes that mPlane.h normalizes incoming point
pTri->color.red = pInfo->r;
pTri->color.green = pInfo->g;
pTri->color.blue = pInfo->b;
pTri->color.alpha = 0.9f;
pTri->texco1.set(((splane.distToPlane(pTri->point1) / mr) + 1.0) / 2.0,
((tplane.distToPlane(pTri->point1) / mr) + 1.0) / 2.0);
pTri->texco2.set(((splane.distToPlane(pTri->point2) / mr) + 1.0) / 2.0,
((tplane.distToPlane(pTri->point2) / mr) + 1.0) / 2.0);
pTri->texco3.set(((splane.distToPlane(pTri->point3) / mr) + 1.0) / 2.0,
((tplane.distToPlane(pTri->point3) / mr) + 1.0) / 2.0);
pTri->flags = 1;
}
#8
02/21/2009 (11:59 pm)
So will this make it so u can make an RTS easier but still get TGEA'S features of graphics and all that?
#9
02/26/2009 (3:18 pm)
Hey your files link is dead =/ could you please re-post them?
#10
Snaggz - he has posted all the code you need in the thread. There's only one little change I needed to do because it was specific to his game:
08/19/2009 (5:25 am)
Good work Peter, I implemented it, needed a few changes for my own code base but it worked.Snaggz - he has posted all the code you need in the thread. There's only one little change I needed to do because it was specific to his game:
// Change mosbyPlayGui to PlayGui GuiRTSTSCtrl* playgui = dynamic_cast<GuiRTSTSCtrl*>(Sim::findObject( "mosbyPlayGui" ));
#11
08/06/2012 (9:09 pm)
is it possible to port this into T3D?
Torque Owner Peter Haffenreffer
Default Studio Name
Add the following forward declarations:
Add the following enums and structs:
enum TerrSelectionConstants { MaxTerrainSelections = 256, SelectionInts = (MaxTerrainSelections - 1) / 32 + 1, }; struct SelectionField { U32 mBits[SelectionInts]; SelectionField() { clear(); } SelectionField(const SelectionField& field) { *this = field; } bool test(U32 index) { //no checking for out of bounds for performance reasons... U32 word = index / 32; U32 bit = index % 32; return mBits[word] & (1 << bit); } void set(U32 index) { U32 word = index / 32; U32 bit = index % 32; mBits[word] |= 1 << bit; } void clear() { for (U32 k = 0; k < SelectionInts; k++) { mBits[k] = 0x00000000; } } bool isEmpty() { for (U32 k = 0; k < SelectionInts; k++) { if (mBits[k]) return false; } return true; } SelectionField& operator=(const SelectionField& field) { for (U32 k = 0; k < SelectionInts; k++) { mBits[k] = field.mBits[k]; } return *this; } operator bool() { return !isEmpty(); } }; struct SelectionTriangle { ColorF color; Point2F texco1; Point3F point1; Point2F texco2; Point3F point2; Point2F texco3; Point3F point3; SelectionTriangle* next; U32 flags; // 0 if inactive }; struct TerrSelectionInfo { Point3F pos; ///< world position F32 radius; ///< radius of the light F32 radiusSquared; ///< radius^2 F32 r, g, b; F32 distSquared; // distance to camera };Add the following to the EmitChunk and SquareStackNode structs:
Add the following static variables in TerrainRender:
Change:
to
Add the following function definitions: