/*************************************************************************************************\ gameTacMap.cpp : Implementation of the gameTacMap component. //---------------------------------------------------------------------------// // Copyright (C) Microsoft Corporation. All rights reserved. // //===========================================================================// \*************************************************************************************************/ #include "gameTacMap.h" #include "team.h" #include "comndr.h" #include "objMgr.h" #include "cellip.h" #include "gameCam.h" #include "Objective.h" #include "mission.h" #include #include "..\resource.h" extern unsigned char godMode; extern bool useLeftRightMouseProfile; #define SQUARE_BLIP 0 #define DOT_BLIP 1 #define TRIANGLE_BLIP 2 const float GameTacMap::s_blinkLength = .5f; float GameTacMap::s_lastBlinkTime = 0.f; extern bool ShowMovers; GameTacMap::GameTacMap() { top = 0; left = 0; right = 0; bottom = 0; buildingPoints = NULL; buildingCount = 0; navMarkerCount = 0; curNavMarker = -1; objectiveAnimationId = -1; objectiveFlashTime = 0.0f; objectiveNumFlashes = 0; } void GameTacMap::init( unsigned char* bitmapData, int dataSize ) { EllipseElement::init(); TGAFileHeader* pHeader = (TGAFileHeader*)bitmapData; bmpWidth = pHeader->width; bmpHeight = pHeader->height; textureHandle = gos_NewTextureFromMemory(gos_Texture_Solid,".tga",bitmapData,dataSize,0); char path[256]; strcpy( path, artPath ); strcat( path, "viewingrect.tga" ); viewRectHandle = mcTextureManager->loadTexture(path, gos_Texture_Alpha, 0 ); strcpy( path, artPath ); strcat( path, "blip.tga" ); blipHandle = mcTextureManager->loadTexture( path, gos_Texture_Alpha, 0 ); } void GameTacMap::update() { Stuff::Vector2DOf screen; screen.x = userInput->getMouseX(); screen.y = userInput->getMouseY(); float width = right - left; float height = bottom - top; if ( !inRegion(screen.x, screen.y) ) return; ControlGui::instance->setRolloverHelpText( IDS_TACMAP_HELP ); if ( userInput->isLeftClick() ) { screen.x -= left; screen.y -= top; Stuff::Vector3D world; tacMapToWorld( screen, width, height, world ); if (MissionInterfaceManager::instance()->getControlGui()->isAddingAirstrike() && MissionInterfaceManager::instance()->getControlGui()->isButtonPressed( ControlGui::SENSOR_PROBE )) MissionInterfaceManager::instance()->doMove(world); else { eye->setPosition( world, false ); ((GameCamera*)(eye))->setTarget( 0 ); } } else if ( userInput->isRightClick() && useLeftRightMouseProfile ) { screen.x -= left; screen.y -= top; Stuff::Vector3D world; tacMapToWorld( screen, width, height, world ); MissionInterfaceManager::instance()->doMove(world); } } bool GameTacMap::animate (long objectiveId, long nFlashes) { if (objectiveAnimationId == -1) { objectiveAnimationId = objectiveId - 1; objectiveFlashTime = 0.0f; objectiveNumFlashes = nFlashes; return true; } return false; } void GameTacMap::render() { if (turn < 2) //Terrain not setup yet. Left,Right,Top,Bottom are poopy! return; gos_VERTEX corners[5]; gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero ); gos_SetRenderState( gos_State_Specular,FALSE ); gos_SetRenderState( gos_State_AlphaTest, FALSE ); gos_SetRenderState( gos_State_Filter, gos_FilterNone ); gos_SetRenderState( gos_State_ZWrite, 0 ); gos_SetRenderState( gos_State_ZCompare, 0 ); gos_SetRenderState( gos_State_Texture, textureHandle ); for ( int i = 0; i < 4; ++i ) { corners[i].rhw = 1.0f; corners[i].argb = 0xffffffff; corners[i].frgb = 0; corners[i].z = 0.0f; } corners[0].x = corners[2].x = left; corners[1].x = corners[3].x = right; corners[3].y = corners[2].y = bottom; corners[0].y = corners[1].y = top; corners[0].u = 2.f/(float)bmpWidth; corners[3].u = 128.f/(float)bmpWidth; corners[2].u = 2.f/(float)bmpWidth; corners[1].u = 128.f/(float)bmpWidth; corners[0].v = 2.f/(float)bmpWidth; corners[3].v = 128.f/(float)bmpHeight; corners[2].v = 128.f/(float)bmpHeight; corners[1].v = 2.f/(float)bmpWidth; gos_DrawTriangles( corners, 3 ); gos_DrawTriangles( &corners[1], 3 ); Stuff::Vector2DOf screen; Stuff::Vector4D nScreen; Stuff::Vector3D world; //----------------------------------------------------------- // Render the objective markers long count = 0; for ( EList< CObjective*, CObjective* >::EIterator iter = Team::home->objectives.Begin(); !iter.IsDone(); iter++ ) { //We are there. Start flashing. if ((objectiveAnimationId == count) && objectiveNumFlashes) { objectiveFlashTime += frameLength; if ( objectiveFlashTime > .5f ) { objectiveFlashTime = 0.0f; objectiveNumFlashes--; } else if ( objectiveFlashTime > 0.25f) { (*iter)->RenderMarkers(this, 0); } if (objectiveNumFlashes == 0) { //Flashing is done. We now return you to your regularly scheduled program. objectiveAnimationId = 0; } } else { (*iter)->RenderMarkers(this, 0); } count++; } // this is the little viewing rect // Routine that InverseProjects is slightly less accurate but an order of magnitude faster. // Can make more accurate later at very little expense to performance. // Easy to fix with camera later. -fs screen.x = 1; screen.y = 1; nScreen.x = nScreen.y = 1.0f; nScreen.z = nScreen.w = 0.0f; eye->inverseProjectZ( nScreen, world ); worldToTacMap( world, corners[0] ); screen.y = Environment.screenHeight - 1; nScreen.y = (Environment.screenHeight * 0.6667f) - 1; nScreen.z = nScreen.w = 0.0f; eye->inverseProjectZ( nScreen, world ); worldToTacMap( world, corners[1] ); screen.x = Environment.screenWidth - 1; nScreen.x = Environment.screenWidth - 1; nScreen.z = nScreen.w = 0.0f; eye->inverseProjectZ( nScreen, world ); worldToTacMap( world, corners[2] ); screen.y = 1; nScreen.y = 1; nScreen.z = nScreen.w = 0.0f; eye->inverseProjectZ( nScreen, world ); worldToTacMap( world, corners[3] ); corners[0].argb = 0xffffffff; corners[1].argb = 0xffffffff; corners[2].argb = 0xffffffff; corners[3].argb = 0xffffffff; corners[0].u = corners[1].u = 0.078125f; corners[3].u = corners[2].u = .99875f; corners[0].v = corners[3].v = 0.078125f; corners[1].v = corners[2].v = .99875f; corners[4] = corners[0]; gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha); gos_SetRenderState( gos_State_ShadeMode, gos_ShadeGouraud); gos_SetRenderState( gos_State_MonoEnable, 0); gos_SetRenderState( gos_State_Perspective, 0); gos_SetRenderState( gos_State_Clipping, 2); gos_SetRenderState( gos_State_AlphaTest, 0); gos_SetRenderState( gos_State_Specular, 0); gos_SetRenderState( gos_State_Dither, 1); gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate); gos_SetRenderState( gos_State_Filter, gos_FilterBiLinear); gos_SetRenderState( gos_State_TextureAddress, gos_TextureWrap ); gos_SetRenderState( gos_State_ZCompare, 0); gos_SetRenderState( gos_State_ZWrite, 0); DWORD gosTextureHandle = mcTextureManager->get_gosTextureHandle(viewRectHandle); gos_SetRenderState( gos_State_Texture, gosTextureHandle ); gos_DrawQuads( &corners[0], 4 ); unsigned long colors[MAX_MOVERS]; unsigned long ringColors[MAX_MOVERS]; Stuff::Vector3D positions[MAX_MOVERS]; unsigned long ranges[MAX_MOVERS]; bool selected[MAX_MOVERS]; count = 0; //------------------------------------------------------------ // draw non-movers, must do separate check for vehicles, I'm not sure they // have sensors for ( i = 0; i < MAX_TEAMS; ++i ) { TeamSensorSystem* pSys = SensorManager->getTeamSensor( i ); if ( pSys ) { for ( int j = 0; j < pSys->numSensors; ++j ) { SensorSystem* pSensor = pSys->sensors[j]; if ( !pSensor ) continue; if ( pSensor->owner->isDestroyed() || pSensor->owner->isDisabled() || pSensor->owner->getStatus() == OBJECT_STATUS_SHUTDOWN ) continue; if ( pSensor->getRange() < 1.1 || pSensor->broken) continue; if (!pSensor->owner->getTeam()) continue; ObjectClass objClass = pSensor->owner->getObjectClass(); unsigned long colorBlip = pSensor->owner->getSelected() ? 0xff4bff4b : 0xff00cc00; unsigned long colorRing = 0xff00cc00; if ( pSensor->owner->getTeam()->isNeutral( Team::home ) ) { colorBlip = pSensor->owner->getSelected() ? 0xff4c4cff : 0xff0000ff; colorRing = 0xff0000ff; } else if ( pSensor->owner->getTeam()->isEnemy( Team::home ) ) // enemy { { colorBlip = pSensor->owner->getSelected() ? 0xffff3f3f : 0xffff0000; colorRing = 0xffff0000; } } if ( objClass != BATTLEMECH && objClass != GROUNDVEHICLE) { if ( objClass == ARTILLERY ) { // blink s_lastBlinkTime += frameLength; if ( s_lastBlinkTime > s_blinkLength ) { colorBlip = 0; colorRing = 0; s_lastBlinkTime = 0.f; } } colors[count] = colorBlip; ringColors[count] = colorRing; ranges[count] = pSensor->getRange(); selected[count] = 0; positions[count] = pSensor->owner->getPosition(); count++; } } } } unsigned long colorBlip, colorRing; //----------------------------------------------------- // draw the movers for (i=0;i<(ObjectManager->numMovers);i++) { MoverPtr mover = ObjectManager->getMover(i); if (mover && mover->getExists() && !(mover->isDestroyed() || mover->isDisabled())) { SensorSystem* pSensor = mover->getSensorSystem(); float range = pSensor ? pSensor->getRange() : 0; long contactStatus = mover->getContactStatus(Team::home->getId(), true); if (mover->getTeamId() == Team::home->id) { if (mover->getCommanderId() == Commander::home->getId()) { if (mover->isOnGUI()) { colorBlip = mover->getSelected() ? 0xff4bff4b : 0xff00cc00; mover->getStatus() == OBJECT_STATUS_SHUTDOWN ? colorRing = 0 : colorRing = 0xff00cc00; } else continue; } else { if (mover->isOnGUI() && land->IsGameSelectTerrainPosition(mover->getPosition()) && mover->pathLocks) { colorBlip = mover->getSelected() ? 0xff4b4bff : 0xff0000cc; mover->getStatus() == OBJECT_STATUS_SHUTDOWN ? colorRing = 0 : colorRing = 0xff0000cc; } else continue; } } else if (ShowMovers || (MPlayer && MPlayer->allUnitsDestroyed[MPlayer->commanderID]) || ((mover->getTeamId() != Team::home->id) && ( contactStatus != CONTACT_NONE ) && (mover->getStatus() != OBJECT_STATUS_SHUTDOWN) && (!mover->hasNullSignature()) && (mover->getEcmRange() <= 0.0f) ) ) //Do not draw ECM mechs!!) { //Not on our side. Draw by contact status colorBlip = mover->getSelected() ? 0xffff3f3f : 0xffff0000; colorRing = 0xffff0000; } else continue; colors[count] = colorBlip; ringColors[count] = colorRing; ranges[count] = range; selected[count] = mover->getSelected(); positions[count] = mover->getPosition(); count++; } } for ( i = 0; i < count; i++ ) { drawSensor( positions[i], ranges[i], ringColors[i] ); } bool bSel = 0; // draw unselected first for ( int j = 0; j < 2; j++ ) { for ( int i = 0; i < count; i++ ) { if ( selected[i] == bSel ) { drawBlip( positions[i], colors[i], DOT_BLIP ); } } bSel = 1; } } void GameTacMap::worldToTacMap( Stuff::Vector3D& world, gos_VERTEX& tac ) { TacMap::worldToTacMap( world, left, top, right - left, bottom - top, tac ); } void GameTacMap::initBuildings( unsigned char* data, int size ) { if ( data ) { long* pData = (long*)data; buildingCount = *pData++; if (buildingCount) { buildingPoints = new gos_VERTEX[buildingCount]; gos_VERTEX* pTmp = buildingPoints; for ( int i = 0; i < buildingCount; ++i, pTmp++) { pTmp->x = *pData++ + left; pTmp->y = *pData++ + top; pTmp->z = 0; pTmp->argb = BUILDING_COLOR; pTmp->frgb = 0; pTmp->rhw = .5; pTmp->u = 0.f; pTmp->v = 0.f; } } } } void GameTacMap::drawSensor( const Stuff::Vector3D& pos, float radius, long color ) { if ( color == 0 ) return; gos_VERTEX sqare[4]; if ( radius > 1 ) radius += land->metersPerCell * 6.f; // a little fudge radius *= ((float)(right - left))/(land->metersPerCell * land->realVerticesMapSide * 3.f); for ( int i = 0; i < 4; ++i ) { sqare[i].z = 0; sqare[i].rhw = .5; sqare[i].argb = color; sqare[i].frgb = 0; } worldToTacMap( (Stuff::Vector3D&)pos, sqare[0] ); sqare[1].x = sqare[0].x; sqare[1].y = sqare[0].y + 1; sqare[2].x = sqare[0].x + 1; sqare[2].y = sqare[0].y; sqare[3].x = sqare[0].x + 1; sqare[3].y = sqare[0].y + 1; // need to draw that round thing Stuff::Vector2DOf< long > center; Stuff::Vector2DOf< long > radii; center.x = float2long(sqare[1].x); center.y = float2long(sqare[1].y); radii.x = 2.0f * float2long(radius+.5); radii.y = 2.0f * float2long(radius+.5); EllipseElement circle( center, radii, color, 0 ); GUI_RECT rect = { left, top, right, bottom }; circle.setClip( rect ); circle.draw(); } void GameTacMap::drawBlip( const Stuff::Vector3D& pos, long color, int type ) { if ( color == 0 ) return; gos_VERTEX triangle[4]; gos_SetRenderState( gos_State_AlphaTest, 1); gos_SetRenderState( gos_State_Specular, 0); gos_SetRenderState( gos_State_Dither, 1); gos_SetRenderState( gos_State_Filter, gos_FilterBiLinear); gos_SetRenderState( gos_State_ZCompare, 0); gos_SetRenderState( gos_State_ZWrite, 0); unsigned long gosID = mcTextureManager->get_gosTextureHandle( blipHandle ); gos_SetRenderState( gos_State_Texture, gosID ); for ( int i = 0; i < 4; ++i ) { triangle[i].z = 0; triangle[i].rhw = .5; triangle[i].argb = color; triangle[i].frgb = 0; triangle[i].u = 0.f; triangle[i].v = 0.f; } worldToTacMap( (Stuff::Vector3D&)pos, triangle[0] ); triangle[0].x -= 2.f; triangle[1].x = triangle[0].x; triangle[2].x = triangle[3].x = triangle[0].x + 4.1f; triangle[0].y -= 2.f; triangle[3].y = triangle[0].y; triangle[1].y = triangle[2].y = triangle[0].y + 4.1f; triangle[2].u = triangle[3].u = .250001f; triangle[1].v = triangle[2].v = .250001f; gos_DrawQuads( triangle, 4 ); } void GameTacMap::setPos( const GUI_RECT& newPos ) { left = newPos.left; right = newPos.right; top = newPos.top; bottom = newPos.bottom; } //************************************************************************************************* // end of file ( TacMap.cpp ) //************************************************************************************************* // end of file ( gameTacMap.cpp )