/* ============ GetFirstBlockingObstacle ============ */ bool GetFirstBlockingObstacle( const obstacle_t *obstacles, int numObstacles, int skipObstacle, const idVec2 &startPos, const idVec2 &delta, float &blockingScale, int &blockingObstacle, int &blockingEdgeNum ) { int i, edgeNums[2]; float dist, scale1, scale2; idVec2 bounds[2]; // get bounds for the current movement delta bounds[0] = startPos - idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); bounds[1] = startPos + idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); bounds[FLOATSIGNBITNOTSET(delta.x)].x += delta.x; bounds[FLOATSIGNBITNOTSET(delta.y)].y += delta.y; // test for obstacles blocking the path blockingScale = idMath::INFINITY; dist = delta.Length(); for ( i = 0; i < numObstacles; i++ ) { if ( i == skipObstacle ) { continue; } if ( bounds[0].x > obstacles[i].bounds[1].x || bounds[0].y > obstacles[i].bounds[1].y || bounds[1].x < obstacles[i].bounds[0].x || bounds[1].y < obstacles[i].bounds[0].y ) { continue; } if ( obstacles[i].winding.RayIntersection( startPos, delta, scale1, scale2, edgeNums ) ) { if ( scale1 < blockingScale && scale1 * dist > -0.01f && scale2 * dist > 0.01f ) { blockingScale = scale1; blockingObstacle = i; blockingEdgeNum = edgeNums[0]; } } } return ( blockingScale < 1.0f ); }
/* ======================== idSWFSpriteInstance::SetMoveToScale ======================== */ bool idSWFSpriteInstance::UpdateMoveToScale( float speed ) { if ( parent == NULL ) { return false; } swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth ); if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) { idLib::Warning( "SetMoveToScale: Couldn't find our display entry in our parents display list" ); return false; } swfMatrix_t & matrix = thisDisplayEntry->matrix; float xscale = matrix.Scale( idVec2( 1.0f, 0.0f ) ).Length() * 100.0f; float yscale = matrix.Scale( idVec2( 0.0f, 1.0f ) ).Length() * 100.0f; float toX = xscale; if ( moveToXScale >= 0.0f ) { toX = moveToXScale * 100.0f; } float toY = yscale; if ( moveToYScale >= 0.0f ) { toY = moveToYScale * 100.0f; } int rXTo = idMath::Ftoi( toX + 0.5f ); int rYTo = idMath::Ftoi( toY + 0.5f ); int rXScale = idMath::Ftoi( xscale + 0.5f ); int rYScale = idMath::Ftoi( yscale + 0.5f ); if ( rXTo == rXScale && rYTo == rYScale ) { return false; } float newXScale = xscale; float newYScale = yscale; if ( rXTo != rXScale && toX >= 0.0f ) { if ( toX < xscale ) { newXScale -= speed; newXScale = idMath::ClampFloat( toX, 100.0f, newXScale ); } else if ( toX > xscale ) { newXScale += speed; newXScale = idMath::ClampFloat( 0.0f, toX, newXScale ); } } if ( rYTo != rYScale && toY >= 0.0f ) { if ( toY < yscale ) { newYScale -= speed; newYScale = idMath::ClampFloat( toY, 100.0f, newYScale ); } else if ( toY > yscale ) { newYScale += speed; newYScale = idMath::ClampFloat( 0.0f, toY, newYScale ); } } SetScale( newXScale, newYScale ); return true; }
/* ======================== idSWFSpriteInstance::SetScale ======================== */ void idSWFSpriteInstance::SetScale( float x, float y ) { if ( parent == NULL ) { return; } swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth ); if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) { idLib::Warning( "scale: Couldn't find our display entry in our parents display list" ); return; } float newScale = x / 100.0f; // this is done funky to maintain the current rotation idVec2 currentScale = thisDisplayEntry->matrix.Scale( idVec2( 1.0f, 0.0f ) ); if ( currentScale.Normalize() == 0.0f ) { thisDisplayEntry->matrix.xx = newScale; thisDisplayEntry->matrix.yx = 0.0f; } else { thisDisplayEntry->matrix.xx = currentScale.x * newScale; thisDisplayEntry->matrix.yx = currentScale.y * newScale; } newScale = y / 100.0f; // this is done funky to maintain the current rotation currentScale = thisDisplayEntry->matrix.Scale( idVec2( 0.0f, 1.0f ) ); if ( currentScale.Normalize() == 0.0f ) { thisDisplayEntry->matrix.yy = newScale; thisDisplayEntry->matrix.xy = 0.0f; } else { thisDisplayEntry->matrix.yy = currentScale.y * newScale; thisDisplayEntry->matrix.xy = currentScale.x * newScale; } }
/* ============ OptimizePath ============ */ int OptimizePath( const pathNode_t *root, const pathNode_t *leafNode, const obstacle_t *obstacles, int numObstacles, idVec2 optimizedPath[MAX_OBSTACLE_PATH] ) { int i, numPathPoints, edgeNums[2]; const pathNode_t *curNode, *nextNode; idVec2 curPos, curDelta, bounds[2]; float scale1, scale2, curLength; optimizedPath[0] = root->pos; numPathPoints = 1; for ( nextNode = curNode = root; curNode != leafNode; curNode = nextNode ) { for ( nextNode = leafNode; nextNode->parent != curNode; nextNode = nextNode->parent ) { // can only take shortcuts when going from one object to another if ( nextNode->obstacle == curNode->obstacle ) { continue; } curPos = curNode->pos; curDelta = nextNode->pos - curPos; curLength = curDelta.Length(); // get bounds for the current movement delta bounds[0] = curPos - idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); bounds[1] = curPos + idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); bounds[FLOATSIGNBITNOTSET(curDelta.x)].x += curDelta.x; bounds[FLOATSIGNBITNOTSET(curDelta.y)].y += curDelta.y; // test if the shortcut intersects with any obstacles for ( i = 0; i < numObstacles; i++ ) { if ( bounds[0].x > obstacles[i].bounds[1].x || bounds[0].y > obstacles[i].bounds[1].y || bounds[1].x < obstacles[i].bounds[0].x || bounds[1].y < obstacles[i].bounds[0].y ) { continue; } if ( obstacles[i].winding.RayIntersection( curPos, curDelta, scale1, scale2, edgeNums ) ) { if ( scale1 >= 0.0f && scale1 <= 1.0f && ( i != nextNode->obstacle || scale1 * curLength < curLength - 0.5f ) ) { break; } if ( scale2 >= 0.0f && scale2 <= 1.0f && ( i != nextNode->obstacle || scale2 * curLength < curLength - 0.5f ) ) { break; } } } if ( i >= numObstacles ) { break; } } // store the next position along the optimized path optimizedPath[numPathPoints++] = nextNode->pos; } return numPathPoints; }
/* ======================== idSWFSpriteInstance::SetRotation ======================== */ void idSWFSpriteInstance::SetRotation( float rot ) { if ( parent == NULL ) { return; } swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth ); if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) { idLib::Warning( "_rotation: Couldn't find our display entry in our parents display list" ); return; } swfMatrix_t & matrix = thisDisplayEntry->matrix; float xscale = matrix.Scale( idVec2( 1.0f, 0.0f ) ).Length(); float yscale = matrix.Scale( idVec2( 0.0f, 1.0f ) ).Length(); float s, c; idMath::SinCos( DEG2RAD( rot ), s, c ); matrix.xx = c * xscale; matrix.yx = s * xscale; matrix.xy = -s * yscale; matrix.yy = c * yscale; }
/* ================ sdAdEntity::UpdateImpression ================ */ void sdAdEntity::UpdateImpression( impressionInfo_t& impression, const renderView_t& view, const sdBounds2D& viewPort ) { assert( adSurface ); sdWorldToScreenConverter converter( view ); sdBounds2D screenBounds; idVec2 screenCenter; const idBounds& surfaceBounds = adSurface->geometry->bounds; idVec3 sufaceCenter = renderEntity.origin + ( surfaceBounds.GetCenter() * renderEntity.axis ); impression.screenWidth = viewPort.GetWidth(); impression.screenHeight = viewPort.GetHeight(); converter.SetExtents( idVec2( impression.screenWidth, impression.screenHeight ) ); converter.Transform( surfaceBounds, renderEntity.axis, renderEntity.origin, screenBounds ); converter.Transform( sufaceCenter, screenCenter ); sdBounds2D clippedImpressionBounds; idFrustum f; f.SetAxis( view.viewaxis ); f.SetOrigin( view.vieworg ); float dNear = 0.0f; float dFar = MAX_WORLD_SIZE; float dLeft = idMath::Tan( DEG2RAD( view.fov_x * 0.5f ) ) * dFar; float dUp = idMath::Tan( DEG2RAD( view.fov_y * 0.5f ) ) * dFar; f.SetSize( dNear, dFar, dLeft, dUp ); sdWorldToScreenConverter::TransformClipped( surfaceBounds, renderEntity.axis, renderEntity.origin, clippedImpressionBounds, f, idVec2( impression.screenWidth, impression.screenHeight ) ); impression.size = ( clippedImpressionBounds.GetMaxs() - clippedImpressionBounds.GetMins() ).Length(); // Angle calculation idVec3 objectNormal = adSurfaceNormal * renderEntity.axis; impression.angle = objectNormal * -view.viewaxis[ 0 ]; // Offscreen determination impression.inView = true; // If the center point is off screen, and if either of the two bounding points are offscreen // then the entire object is considered to be offscreen if ( !viewPort.ContainsPoint( screenCenter ) ) { if ( !viewPort.ContainsPoint( screenBounds.GetMins() ) || !viewPort.ContainsPoint( screenBounds.GetMaxs() ) ) { impression.inView = false; } } lastImpression = impression; }
void rvGEWorkspace::UpdateCursor ( float x, float y ) { idVec2 point; rvGESelectionMgr::EHitTest type; // First convert the worspace coord to a window coord point = WorkspaceToWindow ( idVec2( x, y ) ); // See if it hits anything type = mSelections.HitTest ( point.x, point.y ); // If it hits something then use it to update the cursor if ( rvGESelectionMgr::HT_NONE != type ) { UpdateCursor ( type ); } else { SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_ARROW ) ) ); } }
bool MeshLoaderB3D::ReadVrts() { const int max_tex_coords = 3; int flags, tex_coord_sets, tex_coord_set_size; _file->ReadInt(flags); _file->ReadInt(tex_coord_sets); _file->ReadInt(tex_coord_set_size); if (tex_coord_sets >= max_tex_coords || tex_coord_set_size >= 4) // Something is wrong { Sys_Printf("tex_coord_sets or tex_coord_set_size too big"); return false; } //------ Allocate Memory, for speed -----------// int sizeOfVertex = 3; bool hasNormal = false; bool hasVertexColors = false; if (flags & 1) { hasNormal = true; sizeOfVertex += 3; } if (flags & 2) { sizeOfVertex += 4; hasVertexColors=true; } sizeOfVertex += tex_coord_sets*tex_coord_set_size; unsigned int size = _stack[_stackIndex-1] - _file->Tell(); //106407 16800 unsigned int numVertex = size / sizeof(float) ; numVertex /= sizeOfVertex; srfTriangles_t* tri = R_AllocStaticTriSurf(); R_AllocStaticTriSurfVerts(tri, numVertex); tri->numVerts = numVertex; int idx = 0; while( CheckSize()) { float color[4]={1.0f, 1.0f, 1.0f, 1.0f}; _file->ReadVec3(tri->verts[idx].xyz); if (flags & 1) { _file->ReadVec3(tri->verts[idx].normal); } if (flags & 2) { _file->ReadFloat(color[0]); _file->ReadFloat(color[1]); _file->ReadFloat(color[2]); _file->ReadFloat(color[3]); } float u, v; for (int i = 0; i < tex_coord_sets; ++i) { //for (int j = 0; j < tex_coord_set_size; ++j) { _file->ReadFloat(u); _file->ReadFloat(v); //v = 1 - v; } } tri->verts[idx].st = idVec2(u, v); idx++; } modelSurface_t modelSurf; modelSurf.id = _surfaces.Size(); modelSurf.shader = declManager->FindMaterial("textures/ninja/ninja"); modelSurf.geometry = tri; _surfaces.Append(modelSurf); return true; }
/* ============ GetObstacles ============ */ int GetObstacles( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, int areaNum, const idVec3 &startPos, const idVec3 &seekPos, obstacle_t *obstacles, int maxObstacles, idBounds &clipBounds ) { int i, j, numListedClipModels, numObstacles, numVerts, clipMask, blockingObstacle, blockingEdgeNum; int wallEdges[MAX_AAS_WALL_EDGES], numWallEdges, verts[2], lastVerts[2], nextVerts[2]; float stepHeight, headHeight, blockingScale, min, max; idVec3 seekDelta, silVerts[32], start, end, nextStart, nextEnd; idVec2 expBounds[2], edgeDir, edgeNormal, nextEdgeDir, nextEdgeNormal, lastEdgeNormal; idVec2 obDelta; idPhysics *obPhys; idBox box; idEntity *obEnt; idClipModel *clipModel; idClipModel *clipModelList[ MAX_GENTITIES ]; numObstacles = 0; seekDelta = seekPos - startPos; expBounds[0] = physics->GetBounds()[0].ToVec2() - idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); expBounds[1] = physics->GetBounds()[1].ToVec2() + idVec2( CM_BOX_EPSILON, CM_BOX_EPSILON ); physics->GetAbsBounds().AxisProjection( -physics->GetGravityNormal(), stepHeight, headHeight ); stepHeight += aas->GetSettings()->maxStepHeight; // clip bounds for the obstacle search space clipBounds[0] = clipBounds[1] = startPos; clipBounds.AddPoint( seekPos ); clipBounds.ExpandSelf( MAX_OBSTACLE_RADIUS ); clipMask = physics->GetClipMask(); // find all obstacles touching the clip bounds numListedClipModels = gameLocal.clip.ClipModelsTouchingBounds( clipBounds, clipMask, clipModelList, MAX_GENTITIES ); for ( i = 0; i < numListedClipModels && numObstacles < MAX_OBSTACLES; i++ ) { clipModel = clipModelList[i]; obEnt = clipModel->GetEntity(); if ( !clipModel->IsTraceModel() ) { continue; } if ( obEnt->IsType( idActor::Type ) ) { obPhys = obEnt->GetPhysics(); // ignore myself, my enemy, and dead bodies if ( ( obPhys == physics ) || ( obEnt == ignore ) || ( obEnt->health <= 0 ) ) { continue; } // if the actor is moving idVec3 v1 = obPhys->GetLinearVelocity(); if ( v1.LengthSqr() > Square( 10.0f ) ) { idVec3 v2 = physics->GetLinearVelocity(); if ( v2.LengthSqr() > Square( 10.0f ) ) { // if moving in about the same direction if ( v1 * v2 > 0.0f ) { continue; } } } } else if ( obEnt->IsType( idMoveable::Type ) ) { // moveables are considered obstacles } else { // ignore everything else continue; } // check if we can step over the object clipModel->GetAbsBounds().AxisProjection( -physics->GetGravityNormal(), min, max ); if ( max < stepHeight || min > headHeight ) { // can step over this one continue; } // project a box containing the obstacle onto the floor plane box = idBox( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() ); numVerts = box.GetParallelProjectionSilhouetteVerts( physics->GetGravityNormal(), silVerts ); // create a 2D winding for the obstacle; obstacle_t &obstacle = obstacles[numObstacles++]; obstacle.winding.Clear(); for ( j = 0; j < numVerts; j++ ) { obstacle.winding.AddPoint( silVerts[j].ToVec2() ); } if ( ai_showObstacleAvoidance.GetBool() ) { for ( j = 0; j < numVerts; j++ ) { silVerts[j].z = startPos.z; } for ( j = 0; j < numVerts; j++ ) { gameRenderWorld->DebugArrow( colorWhite, silVerts[j], silVerts[(j+1)%numVerts], 4 ); } } // expand the 2D winding for collision with a 2D box obstacle.winding.ExpandForAxialBox( expBounds ); obstacle.winding.GetBounds( obstacle.bounds ); obstacle.entity = obEnt; } // if there are no dynamic obstacles the path should be through valid AAS space if ( numObstacles == 0 ) { return 0; } // if the current path doesn't intersect any dynamic obstacles the path should be through valid AAS space if ( PointInsideObstacle( obstacles, numObstacles, startPos.ToVec2() ) == -1 ) { if ( !GetFirstBlockingObstacle( obstacles, numObstacles, -1, startPos.ToVec2(), seekDelta.ToVec2(), blockingScale, blockingObstacle, blockingEdgeNum ) ) { return 0; } } // create obstacles for AAS walls if ( aas ) { float halfBoundsSize = ( expBounds[ 1 ].x - expBounds[ 0 ].x ) * 0.5f; numWallEdges = aas->GetWallEdges( areaNum, clipBounds, TFL_WALK, wallEdges, MAX_AAS_WALL_EDGES ); aas->SortWallEdges( wallEdges, numWallEdges ); lastVerts[0] = lastVerts[1] = 0; lastEdgeNormal.Zero(); nextVerts[0] = nextVerts[1] = 0; for ( i = 0; i < numWallEdges && numObstacles < MAX_OBSTACLES; i++ ) { aas->GetEdge( wallEdges[i], start, end ); aas->GetEdgeVertexNumbers( wallEdges[i], verts ); edgeDir = end.ToVec2() - start.ToVec2(); edgeDir.Normalize(); edgeNormal.x = edgeDir.y; edgeNormal.y = -edgeDir.x; if ( i < numWallEdges-1 ) { aas->GetEdge( wallEdges[i+1], nextStart, nextEnd ); aas->GetEdgeVertexNumbers( wallEdges[i+1], nextVerts ); nextEdgeDir = nextEnd.ToVec2() - nextStart.ToVec2(); nextEdgeDir.Normalize(); nextEdgeNormal.x = nextEdgeDir.y; nextEdgeNormal.y = -nextEdgeDir.x; } obstacle_t &obstacle = obstacles[numObstacles++]; obstacle.winding.Clear(); obstacle.winding.AddPoint( end.ToVec2() ); obstacle.winding.AddPoint( start.ToVec2() ); obstacle.winding.AddPoint( start.ToVec2() - edgeDir - edgeNormal * halfBoundsSize ); obstacle.winding.AddPoint( end.ToVec2() + edgeDir - edgeNormal * halfBoundsSize ); if ( lastVerts[1] == verts[0] ) { obstacle.winding[2] -= lastEdgeNormal * halfBoundsSize; } else { obstacle.winding[1] -= edgeDir; } if ( verts[1] == nextVerts[0] ) { obstacle.winding[3] -= nextEdgeNormal * halfBoundsSize; } else { obstacle.winding[0] += edgeDir; } obstacle.winding.GetBounds( obstacle.bounds ); obstacle.entity = NULL; memcpy( lastVerts, verts, sizeof( lastVerts ) ); lastEdgeNormal = edgeNormal; } } // show obstacles if ( ai_showObstacleAvoidance.GetBool() ) { for ( i = 0; i < numObstacles; i++ ) { obstacle_t &obstacle = obstacles[i]; for ( j = 0; j < obstacle.winding.GetNumPoints(); j++ ) { silVerts[j].ToVec2() = obstacle.winding[j]; silVerts[j].z = startPos.z; } for ( j = 0; j < obstacle.winding.GetNumPoints(); j++ ) { gameRenderWorld->DebugArrow( colorGreen, silVerts[j], silVerts[(j+1)%obstacle.winding.GetNumPoints()], 4 ); } } } return numObstacles; }
/* ============================= idGameBustOutWindow::UpdateBall ============================= */ void idGameBustOutWindow::UpdateBall( void ) { int ballnum,i,j; bool playSoundBounce = false; bool playSoundBrick = false; static int bounceChannel = 1; if ( ballsInPlay == 0 ) { return; } for ( ballnum = 0; ballnum < balls.Num(); ballnum++ ) { BOEntity *ball = balls[ballnum]; // Check for ball going below screen, lost ball if ( ball->position.y > 480.f ) { ball->removed = true; continue; } // Check world collision if ( ball->position.y < 20 && ball->velocity.y < 0 ) { ball->velocity.y = -ball->velocity.y; // Increase ball speed when it hits ceiling if ( !ballHitCeiling ) { ballSpeed *= 1.25f; ballHitCeiling = true; } playSoundBounce = true; } if ( ball->position.x > 608 && ball->velocity.x > 0 ) { ball->velocity.x = -ball->velocity.x; playSoundBounce = true; } else if ( ball->position.x < 8 && ball->velocity.x < 0 ) { ball->velocity.x = -ball->velocity.x; playSoundBounce = true; } // Check for Paddle collision idVec2 ballCenter = ball->position + idVec2( BALL_RADIUS, BALL_RADIUS ); collideDir_t collision = paddle->checkCollision( ballCenter, ball->velocity ); if ( collision == COLLIDE_UP ) { if ( ball->velocity.y > 0 ) { idVec2 paddleVec( paddleVelocity*2, 0 ); float centerX; if ( bigPaddleTime > gui->GetTime() ) { centerX = paddle->x + 80.f; } else { centerX = paddle->x + 48.f; } ball->velocity.y = -ball->velocity.y; paddleVec.x += (ball->position.x - centerX) * 2; ball->velocity += paddleVec; ball->velocity.NormalizeFast(); ball->velocity *= ballSpeed; playSoundBounce = true; } } else if ( collision == COLLIDE_LEFT || collision == COLLIDE_RIGHT ) { if ( ball->velocity.y > 0 ) { ball->velocity.x = -ball->velocity.x; playSoundBounce = true; } } collision = COLLIDE_NONE; // Check for collision with bricks for ( i=0; i<BOARD_ROWS; i++ ) { int num = board[i].Num(); for ( j=0; j<num; j++ ) { BOBrick *brick = (board[i])[j]; collision = brick->checkCollision( ballCenter, ball->velocity ); if ( collision ) { // Now break the brick if there was a collision brick->isBroken = true; brick->ent->fadeOut = true; if ( brick->powerup > POWERUP_NONE ) { CreatePowerup( brick ); } numBricks--; gameScore += 100; updateScore = true; // Go ahead an forcibly remove the last brick, no fade if ( numBricks == 0 ) { brick->ent->removed = true; } board[i].Remove( brick ); break; } } if ( collision ) { playSoundBrick = true; break; } } if ( collision == COLLIDE_DOWN || collision == COLLIDE_UP ) { ball->velocity.y *= -1; } else if ( collision == COLLIDE_LEFT || collision == COLLIDE_RIGHT ) { ball->velocity.x *= -1; } if ( playSoundBounce ) { session->sw->PlayShaderDirectly( "arcade_ballbounce", bounceChannel ); } else if ( playSoundBrick ) { session->sw->PlayShaderDirectly( "arcade_brickhit", bounceChannel ); } if ( playSoundBounce || playSoundBrick ) { bounceChannel++; if ( bounceChannel == 4 ) { bounceChannel = 1; } } } // Check to see if any balls were removed from play for ( ballnum=0; ballnum<balls.Num(); ballnum++ ) { if ( balls[ballnum]->removed ) { ballsInPlay--; balls.RemoveIndex( ballnum ); } } // If all the balls were removed, update the game accordingly if ( ballsInPlay == 0 ) { if ( ballsRemaining == 0 ) { gameOver = true; // Game Over sound session->sw->PlayShaderDirectly( "arcade_sadsound", S_UNIQUE_CHANNEL ); } else { ballsRemaining--; // Ball was lost, but game is not over session->sw->PlayShaderDirectly( "arcade_missedball", S_UNIQUE_CHANNEL ); } ClearPowerups(); updateScore = true; } }
/* ============== sdDeployMaskEditSession::UpdateProjection ============== */ void sdDeployMaskEditSession::UpdateProjection( const idVec3& position ) { if ( !decalMaterial ) { return; } if ( decalHandle == -1 ) { decalHandle = gameLocal.RegisterLoggedDecal( decalMaterial ); } gameLocal.ResetLoggedDecal( decalHandle ); gameDecalInfo_t* decalInfo = gameLocal.GetLoggedDecal( decalHandle ); sdDeployMaskInstance* mask = GetMask( position ); const sdHeightMapInstance* heightMap = GetHeightMap( position ); if ( mask != NULL && mask->IsValid() && heightMap != NULL ) { sdDeployMask::extents_t extents; GetExtents( position, *mask, extents ); float depth = 512.0f; int maxX, maxY; mask->GetDimensions( maxX, maxY ); sdDeployMask::extents_t expandedExtents; expandedExtents.minx = Max( 0, extents.minx - 2 ); expandedExtents.miny = Max( 0, extents.miny - 2 ); expandedExtents.maxx = Min( maxX, extents.maxx + 2 ); expandedExtents.maxy = Min( maxY, extents.maxy + 2 ); idList< const idMaterial* > megaTextureMaterials; const idStrList& megaTextureMaterialNames = gameLocal.GetMapInfo().GetMegatextureMaterials(); for ( int i = 0; i < megaTextureMaterialNames.Num(); i++ ) { megaTextureMaterials.Append( declHolder.FindMaterial( megaTextureMaterialNames[ i ] ) ); } idFixedWinding winding; int spawnID = WORLD_SPAWN_ID; for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) { for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) { gameDecalInfo_t* info = decalInfo; if ( !info ) { continue; } sdDeployMask::extents_t localExtents; localExtents.minx = i; localExtents.maxx = i; localExtents.miny = j; localExtents.maxy = j; idBounds bounds; mask->GetBounds( localExtents, bounds, heightMap ); idVec3 top = bounds.GetCenter(); top[ 2 ] = bounds.GetMaxs()[ 2 ]; deployResult_t localResult = mask->IsValid( localExtents ); idVec4 localColor; switch ( localResult ) { case DR_CLEAR: localColor = colorGreen; break; default: case DR_FAILED: localColor = colorDkRed; break; } if ( !( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ) { localColor.x *= 0.3f; localColor.y *= 0.3f; localColor.z *= 0.3f; } winding.Clear(); winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 0.0f ) ); winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 1.0f ) ); winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 1.0f ) ); winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 0.0f ) ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0, 0, 64.f + depth ), true, localColor, info->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); } } } }
/* =================== idSWF::HitTest =================== */ idSWFScriptObject* idSWF::HitTest( idSWFSpriteInstance* spriteInstance, const swfRenderState_t& renderState, int x, int y, idSWFScriptObject* parentObject ) { if( spriteInstance->parent != NULL ) { swfDisplayEntry_t* thisDisplayEntry = spriteInstance->parent->FindDisplayEntry( spriteInstance->depth ); if( thisDisplayEntry->cxf.mul.w + thisDisplayEntry->cxf.add.w < 0.001f ) { return NULL; } } if( !spriteInstance->isVisible ) { return NULL; } if( spriteInstance->scriptObject->HasValidProperty( "onRelease" ) || spriteInstance->scriptObject->HasValidProperty( "onPress" ) || spriteInstance->scriptObject->HasValidProperty( "onRollOver" ) || spriteInstance->scriptObject->HasValidProperty( "onRollOut" ) || spriteInstance->scriptObject->HasValidProperty( "onDrag" ) ) { parentObject = spriteInstance->scriptObject; } // rather than returning the first object we find, we actually want to return the last object we find idSWFScriptObject* returnObject = NULL; float xOffset = spriteInstance->xOffset; float yOffset = spriteInstance->yOffset; for( int i = 0; i < spriteInstance->displayList.Num(); i++ ) { const swfDisplayEntry_t& display = spriteInstance->displayList[i]; idSWFDictionaryEntry* entry = FindDictionaryEntry( display.characterID ); if( entry == NULL ) { continue; } swfRenderState_t renderState2; renderState2.matrix = display.matrix.Multiply( renderState.matrix ); renderState2.ratio = display.ratio; if( entry->type == SWF_DICT_SPRITE ) { idSWFScriptObject* object = HitTest( display.spriteInstance, renderState2, x, y, parentObject ); if( object != NULL && object->Get( "_visible" ).ToBool() ) { returnObject = object; } } else if( entry->type == SWF_DICT_SHAPE && ( parentObject != NULL ) ) { idSWFShape* shape = entry->shape; for( int i = 0; i < shape->fillDraws.Num(); i++ ) { const idSWFShapeDrawFill& fill = shape->fillDraws[i]; for( int j = 0; j < fill.indices.Num(); j += 3 ) { idVec2 xy1 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j + 0]] ); idVec2 xy2 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j + 1]] ); idVec2 xy3 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j + 2]] ); idMat3 edgeEquations; edgeEquations[0].Set( xy1.x + xOffset, xy1.y + yOffset, 1.0f ); edgeEquations[1].Set( xy2.x + xOffset, xy2.y + yOffset, 1.0f ); edgeEquations[2].Set( xy3.x + xOffset, xy3.y + yOffset, 1.0f ); edgeEquations.InverseSelf(); idVec3 p( x, y, 1.0f ); idVec3 signs = p * edgeEquations; bool bx = signs.x > 0; bool by = signs.y > 0; bool bz = signs.z > 0; if( bx == by && bx == bz ) { // point inside returnObject = parentObject; } } } } else if( entry->type == SWF_DICT_MORPH ) { // FIXME: this should be roughly the same as SWF_DICT_SHAPE } else if( entry->type == SWF_DICT_TEXT ) { // FIXME: this should be roughly the same as SWF_DICT_SHAPE } else if( entry->type == SWF_DICT_EDITTEXT ) { idSWFScriptObject* editObject = NULL; if( display.textInstance->scriptObject.HasProperty( "onRelease" ) || display.textInstance->scriptObject.HasProperty( "onPress" ) ) { // if the edit box itself can be clicked, then we want to return it when it's clicked on editObject = &display.textInstance->scriptObject; } else if( parentObject != NULL ) { // otherwise, we want to return the parent object editObject = parentObject; } if( editObject == NULL ) { continue; } if( display.textInstance->text.IsEmpty() ) { continue; } const idSWFEditText* shape = entry->edittext; const idSWFEditText* text = display.textInstance->GetEditText(); float textLength = display.textInstance->GetTextLength(); float lengthDiff = fabs( shape->bounds.br.x - shape->bounds.tl.x ) - textLength; idVec3 tl; idVec3 tr; idVec3 br; idVec3 bl; float xOffset = spriteInstance->xOffset; float yOffset = spriteInstance->yOffset; float topOffset = 0.0f; if( text->align == SWF_ET_ALIGN_LEFT ) { tl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) ); tr.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x - lengthDiff + xOffset, shape->bounds.tl.y + topOffset + yOffset ) ); br.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x - lengthDiff + xOffset, shape->bounds.br.y + topOffset + yOffset ) ); bl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) ); } else if( text->align == SWF_ET_ALIGN_RIGHT ) { tl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + lengthDiff + xOffset, shape->bounds.tl.y + topOffset + yOffset ) ); tr.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) ); br.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) ); bl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + lengthDiff + xOffset, shape->bounds.br.y + topOffset + yOffset ) ); } else if( text->align == SWF_ET_ALIGN_CENTER ) { float middle = ( ( shape->bounds.br.x + xOffset ) + ( shape->bounds.tl.x + xOffset ) ) / 2.0f; tl.ToVec2() = renderState2.matrix.Transform( idVec2( middle - ( textLength / 2.0f ), shape->bounds.tl.y + topOffset + yOffset ) ); tr.ToVec2() = renderState2.matrix.Transform( idVec2( middle + ( textLength / 2.0f ), shape->bounds.tl.y + topOffset + yOffset ) ); br.ToVec2() = renderState2.matrix.Transform( idVec2( middle + ( textLength / 2.0f ), shape->bounds.br.y + topOffset + yOffset ) ); bl.ToVec2() = renderState2.matrix.Transform( idVec2( middle - ( textLength / 2.0f ), shape->bounds.br.y + topOffset + yOffset ) ); } else { tl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) ); tr.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) ); br.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) ); bl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) ); } tl.z = 1.0f; tr.z = 1.0f; br.z = 1.0f; bl.z = 1.0f; idMat3 edgeEquations; edgeEquations[0] = tl; edgeEquations[1] = tr; edgeEquations[2] = br; edgeEquations.InverseSelf(); idVec3 p( x, y, 1.0f ); idVec3 signs = p * edgeEquations; bool bx = signs.x > 0; bool by = signs.y > 0; bool bz = signs.z > 0; if( bx == by && bx == bz ) { // point inside top right triangle returnObject = editObject; } edgeEquations[0] = tl; edgeEquations[1] = br; edgeEquations[2] = bl; edgeEquations.InverseSelf(); signs = p * edgeEquations; bx = signs.x > 0; by = signs.y > 0; bz = signs.z > 0; if( bx == by && bx == bz ) { // point inside bottom left triangle returnObject = editObject; } } } return returnObject; }
/* ============== sdDeployMenu::Update ============== */ void sdDeployMenu::Update( void ) { sdHudModule::Update(); idPlayer* localPlayer = gameLocal.GetLocalPlayer(); if ( !deployableObject || !localPlayer ) { return; } deployResult_t result = localPlayer->GetDeployResult( position, deployableObject ); if ( result != DR_OUT_OF_RANGE ) { if ( deployableRenderEntityHandle < 0 ) { deployableRenderEntityHandle = gameRenderWorld->AddEntityDef( &deployableRenderEntity ); } idVec4 color; switch ( deployableState ) { case DR_CLEAR: color = colorGreen; break; case DR_WARNING: color = colorOrange; break; case DR_CONDITION_FAILED: color = colorWhite; break; default: case DR_FAILED: color = colorDkRed; break; } if ( decalHandle == -1 ) { decalHandle = gameLocal.RegisterLoggedDecal( decalMaterial ); lastExpandedExtents.minx = -1; } if ( decalHandleOuter == -1 ) { decalHandleOuter = gameLocal.RegisterLoggedDecal( decalMaterialOuter ); lastExpandedExtents.minx = -1; } if ( decalHandleArrows == -1 ) { decalHandleArrows = gameLocal.RegisterLoggedDecal( decalMaterialArrows ); } gameLocal.ResetLoggedDecal( decalHandleArrows ); gameDecalInfo_t* decalInfo = gameLocal.GetLoggedDecal( decalHandle ); gameDecalInfo_t* decalInfoOuter = gameLocal.GetLoggedDecal( decalHandleOuter ); gameDecalInfo_t* decalInfoArrows = gameLocal.GetLoggedDecal( decalHandleArrows ); if ( !deployableObject->AllowRotation() ) { rotation = 0.0f; } idMat3 rotationStart; idAngles::YawToMat3( rotation, rotationStart ); const sdPlayZone* playZone = gameLocal.GetPlayZone( position, sdPlayZone::PZF_DEPLOYMENT ); const sdPlayZone* playZoneHeight = gameLocal.GetPlayZone( position, sdPlayZone::PZF_HEIGHTMAP ); const sdHeightMapInstance* heightMap = NULL; if ( playZoneHeight ) { heightMap = &playZoneHeight->GetHeightMap(); } const sdDeployMaskInstance* mask = NULL; if ( playZone ) { mask = playZone->GetMask( deployableObject->GetDeploymentMask() ); } if ( mask && mask->IsValid() && heightMap && heightMap->IsValid() ) { idBounds bounds( position ); bounds.ExpandSelf( deployableObject->GetObjectSize() ); sdDeployMask::extents_t extents; mask->CoordsForBounds( bounds, extents ); idBounds mainBounds; mask->GetBounds( extents, mainBounds, heightMap ); float depth = 512.0f; idVec3 top; idBounds moveArrowBounds = mainBounds; idBounds rotateArrowBounds = mainBounds; // straight arrows moveArrowBounds.GetMaxs().y = moveArrowBounds.GetCenter().y; moveArrowBounds.GetMins().y += 0.25f * ( mainBounds.GetMaxs().y - mainBounds.GetMins().y ); moveArrowBounds.GetMaxs().y += 0.25f * ( mainBounds.GetMaxs().y - mainBounds.GetMins().y ); moveArrowBounds.GetMins().x = moveArrowBounds.GetCenter().x; { idVec3 center = moveArrowBounds.GetCenter(); moveArrowBounds.TranslateSelf( -center ); for ( int index = 0; index < 3; index++ ) { moveArrowBounds.GetMins()[ index ] *= 0.25f; moveArrowBounds.GetMaxs()[ index ] *= 0.25f; } moveArrowBounds.TranslateSelf( center ); } // rotate arrows rotateArrowBounds.GetMins().x = rotateArrowBounds.GetCenter().x; { idVec3 center = rotateArrowBounds.GetCenter(); rotateArrowBounds.TranslateSelf( -center ); for ( int index = 0; index < 3; index++ ) { rotateArrowBounds.GetMins()[ index ] *= 0.2f; rotateArrowBounds.GetMaxs()[ index ] *= 0.2f; } rotateArrowBounds.TranslateSelf( center ); } top = mainBounds.GetCenter(); top[ 2 ] = mainBounds.GetMaxs()[ 2 ]; idList< const idMaterial* > megaTextureMaterials; const idStrList& megaTextureMaterialNames = gameLocal.GetMapInfo().GetMegatextureMaterials(); for ( int i = 0; i < megaTextureMaterialNames.Num(); i++ ) { megaTextureMaterials.Append( declHolder.FindMaterial( megaTextureMaterialNames[ i ] ) ); } idFixedWinding winding; int spawnID = WORLD_SPAWN_ID; if ( GetDeployMode() ) { // rotate mode idMat3 rotationOffset; idAngles::YawToMat3( 120.0f, rotationOffset ); // forward arrow winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.0f ) ); winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.5f ) ); winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.5f ) ); winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.0f ) ); winding.Rotate( mainBounds.GetCenter(), rotationStart ); idVec3 offset = rotationStart[ 0 ] * ( 16.f * idMath::Sin( ( gameLocal.time / 500.f ) ) ); for ( int i = 0; i < winding.GetNumPoints(); i++ ) { winding[ i ].ToVec3() += offset; } gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, idVec4( 0.87f, 0.59f, 0.f, 1.f ), decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); // rotate arrows winding.Clear(); winding += idVec5( idVec3( rotateArrowBounds.GetMins().x, rotateArrowBounds.GetMins().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.0f, 0.0f ) ); winding += idVec5( idVec3( rotateArrowBounds.GetMins().x, rotateArrowBounds.GetMaxs().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.0f, 1.0f ) ); winding += idVec5( idVec3( rotateArrowBounds.GetMaxs().x, rotateArrowBounds.GetMaxs().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 1.0f ) ); winding += idVec5( idVec3( rotateArrowBounds.GetMaxs().x, rotateArrowBounds.GetMins().y, rotateArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.0f ) ); winding.Rotate( mainBounds.GetCenter(), rotationStart * rotationOffset ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); winding.Rotate( mainBounds.GetCenter(), rotationOffset ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); } else { // move mode idMat3 rotationOffset; idAngles::YawToMat3( 90.0f, rotationOffset ); winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.0f ) ); winding += idVec5( idVec3( moveArrowBounds.GetMins().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 0.5f, 0.5f ) ); winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMaxs().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.5f ) ); winding += idVec5( idVec3( moveArrowBounds.GetMaxs().x, moveArrowBounds.GetMins().y, moveArrowBounds.GetMins().z - depth ), idVec2( 1.0f, 0.0f ) ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); winding.Rotate( mainBounds.GetCenter(), rotationOffset ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); winding.Rotate( mainBounds.GetCenter(), rotationOffset ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); winding.Rotate( mainBounds.GetCenter(), rotationOffset ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0.0f, 0.0f, 64.0f + depth ), true, colorWhite, decalInfoArrows->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); } // the grid int maxX, maxY; mask->GetDimensions( maxX, maxY ); sdDeployMask::extents_t expandedExtents; expandedExtents.minx = Max( 0, extents.minx - 2 ); expandedExtents.miny = Max( 0, extents.miny - 2 ); expandedExtents.maxx = Min( maxX, extents.maxx + 2 ); expandedExtents.maxy = Min( maxY, extents.maxy + 2 ); int w = expandedExtents.maxx - expandedExtents.minx + 1; int h = expandedExtents.maxx - expandedExtents.minx + 1; int terrIdx = 0; bool regen = false; if ( ( w * h ) > sizeof( lastTerritory ) / sizeof( lastTerritory[0] ) ) { common->Warning( "test territory size too large" ); return; } for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) { for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) { gameDecalInfo_t* info = ( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ? decalInfo : decalInfoOuter; if ( !info ) { continue; } sdDeployMask::extents_t localExtents; localExtents.minx = i; localExtents.maxx = i; localExtents.miny = j; localExtents.maxy = j; mask->GetBounds( localExtents, bounds, heightMap ); top = bounds.GetCenter(); top[ 2 ] = bounds.GetMaxs()[ 2 ]; deployResult_t localResult = localPlayer->CheckBoundsForDeployment( localExtents, *mask, deployableObject, playZoneHeight ); bool hasTerritory; if ( localResult == DR_CLEAR ) { hasTerritory = gameLocal.TerritoryForPoint( top, localPlayer->GetGameTeam(), true ) != NULL; } else { hasTerritory = false; } if ( hasTerritory != lastTerritory[ terrIdx ] ) { regen = true; } lastTerritory[ terrIdx++ ] = hasTerritory; } } if ( expandedExtents.minx != lastExpandedExtents.minx || expandedExtents.maxx != lastExpandedExtents.maxx || expandedExtents.miny != lastExpandedExtents.miny || expandedExtents.maxy != lastExpandedExtents.maxy || regen ) { gameLocal.ResetLoggedDecal( decalHandle ); gameLocal.ResetLoggedDecal( decalHandleOuter ); lastExpandedExtents = expandedExtents; terrIdx = 0; for ( int i = expandedExtents.minx; i <= expandedExtents.maxx; i++ ) { for ( int j = expandedExtents.miny; j <= expandedExtents.maxy; j++ ) { gameDecalInfo_t* info = ( ( i >= extents.minx ) && ( i <= extents.maxx ) && ( j >= extents.miny ) && ( j <= extents.maxy ) ) ? decalInfo : decalInfoOuter; if ( !info ) { continue; } sdDeployMask::extents_t localExtents; localExtents.minx = i; localExtents.maxx = i; localExtents.miny = j; localExtents.maxy = j; mask->GetBounds( localExtents, bounds, heightMap ); top = bounds.GetCenter(); top[ 2 ] = bounds.GetMaxs()[ 2 ]; //bool hasTerritory = gameLocal.TerritoryForPoint( top, localPlayer->GetGameTeam(), true ) != NULL; deployResult_t localResult = localPlayer->CheckBoundsForDeployment( localExtents, *mask, deployableObject, playZoneHeight ); idVec4 localColor; switch ( localResult ) { case DR_CLEAR: if ( !lastTerritory[ terrIdx ] ) { localColor = colorOrange; } else { localColor = colorGreen; } break; case DR_WARNING: localColor = colorOrange; break; case DR_FAILED: localColor = colorDkRed; break; } winding.Clear(); winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 0.0f ) ); winding += idVec5( idVec3( bounds.GetMins()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 0.0f, 1.0f ) ); winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMaxs()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 1.0f ) ); winding += idVec5( idVec3( bounds.GetMaxs()[ 0 ], bounds.GetMins()[ 1 ], bounds.GetMins()[ 2 ] - depth ), idVec2( 1.0f, 0.0f ) ); // gameRenderWorld->DebugBounds( localColor, bounds ); // gameRenderWorld->DrawText( va( "%i %i", i, j ), top, 0.5, colorWhite, gameLocal.GetLocalPlayer()->GetRenderView()->viewaxis ); gameRenderWorld->AddToProjectedDecal( winding, top + idVec3( 0, 0, 64.f + depth ), true, localColor, info->renderEntity.hModel, spawnID, megaTextureMaterials.Begin(), megaTextureMaterials.Num() ); terrIdx++; } } } } else { gameLocal.ResetLoggedDecal( decalHandle ); gameLocal.ResetLoggedDecal( decalHandleOuter ); lastExpandedExtents.minx = -1; } idVec3 modelPos = position; if ( playZoneHeight ) { const sdHeightMapInstance& heightMap = playZoneHeight->GetHeightMap(); if ( heightMap.IsValid() ) { modelPos.z = heightMap.GetHeight( modelPos ); } } sdDeployRequest::UpdateRenderEntity( deployableRenderEntity, color, modelPos ); deployableRenderEntity.axis = rotationStart; gameRenderWorld->UpdateEntityDef( deployableRenderEntityHandle, &deployableRenderEntity ); } else { if ( deployableRenderEntityHandle >= 0 ) { gameRenderWorld->FreeEntityDef( deployableRenderEntityHandle ); deployableRenderEntityHandle = -1; } FreeDecals(); } }