/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando * * * * $Archive:: /Commando/Code/Combat/sniper.cpp $* * * * $Author:: Byon_g $* * * * $Modtime:: 7/05/01 11:37a $* * * * $Revision:: 60 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "sniper.h" #include "render2d.h" #include "texture.h" #include "assets.h" #include "combat.h" #include "ccamera.h" #include "debug.h" #include "globalsettings.h" #include "timemgr.h" #include "input.h" /* ** */ Vector2 SNIPER_UV_SCALE( 1.0f/128.0f, 1.0f/128.0f ); Vector2 BLACK_UV_UL( 1, 1 ); Vector2 BLACK_UV_LR( 5, 7 ); Vector2 SNIPER_VIEW_UV_UL( 1, 2 ); Vector2 SNIPER_VIEW_UV_LR( 115, 115 ); Vector2 SNIPER_VIEW_UL( 193, 153 ); Vector2 SNIPER_VIEW_LR( 839, 853 ); Vector2 BOX_SIZE( 235, 127 ); Vector2 TOP_LINE_1( 149, 209 ); Vector2 TOP_LINE_2( 151, 426 ); Vector2 TOP_LINE_3( 151, 403 ); Vector2 BOTTOM_LINE_1( 543, 768 ); Vector2 BOTTOM_LINE_2( 34, 597 ); Vector2 BOTTOM_LINE_3( 519, 10 ); Vector2 CENTER_LINE_1( 144, 42 ); Vector2 CENTER_LINE_2( 166, 117 ); Vector2 LEFT_LINE_UL( 203, 723 ); Vector2 LEFT_LINE_LR( 222, 10 ); Vector2 LEFT_LINE_2( 247, 435 ); Vector2 ZOOM_UV_UL( 117, 41 ); Vector2 ZOOM_UV_LR( 128, 62 ); Vector2 ZOOM_OFFSET_TOP( 177, 620 ); Vector2 ZOOM_OFFSET_BOTTOM( 177, 316 ); /* ** */ #define SNIPER_LEFT_BLACK_COVER RectClass( 0, 0, settings->SniperView.Left, 1 ) #define SNIPER_RIGHT_BLACK_COVER RectClass( settings->SniperView.Right, 0, 1, 1 ) #define SNIPER_TOP_BLACK_COVER RectClass( settings->SniperView.Left, 0, settings->SniperView.Right, settings->SniperView.Top ) #define SNIPER_BOTTOM_BLACK_COVER RectClass( settings->SniperView.Left, settings->SniperView.Bottom, settings->SniperView.Right, 1 ) /* ** */ Render2DClass * _Sniper2DBaseRenderer; Render2DClass * _Sniper2DRenderer; #define HUD_SNIPER_TEXTURE "hud_sniper.tga" static void Info_Editor_Init( void ); static void Info_Editor_Update( void ); static void Info_Editor_Shutdown( void ); /* ** */ void SniperHUDClass::Init( void ) { _Sniper2DBaseRenderer = new Render2DClass(); _Sniper2DBaseRenderer->Set_Texture( HUD_SNIPER_TEXTURE ); _Sniper2DBaseRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() ); Build_Base(); _Sniper2DRenderer = new Render2DClass(); _Sniper2DRenderer->Set_Texture( HUD_SNIPER_TEXTURE ); _Sniper2DRenderer->Set_Coordinate_Range( Render2DClass::Get_Screen_Resolution() ); // Info_Editor_Init(); } /* ** */ void SniperHUDClass::Shutdown( void ) { if ( _Sniper2DBaseRenderer ) { delete _Sniper2DBaseRenderer; _Sniper2DBaseRenderer = NULL; } if ( _Sniper2DRenderer ) { delete _Sniper2DRenderer; _Sniper2DRenderer = NULL; } // Info_Editor_Shutdown(); } void SniperHUDClass::Build_Base( void ) { if ( _Sniper2DBaseRenderer == NULL ) { return; } _Sniper2DBaseRenderer->Reset(); RectClass uv; RectClass draw; uv.Set( SNIPER_VIEW_UV_UL, SNIPER_VIEW_UV_LR ); uv.Scale( SNIPER_UV_SCALE ); Vector2 screen_size = Render2DClass::Get_Screen_Resolution().Lower_Right(); Vector2 screen_center = screen_size * 0.5f; Vector2 screen_scale = screen_size * 0.001f; // Set tint color int tint = 0xFF0000FF; // Blue tint = 0xFF00FF00; // Green // Draw the center view draw.Set( SNIPER_VIEW_UL, SNIPER_VIEW_LR ); draw.Scale( screen_scale ); _Sniper2DBaseRenderer->Add_Quad( draw, uv, tint ); // Draw the black sides RectClass blackuv( BLACK_UV_UL, BLACK_UV_LR ); blackuv.Scale( SNIPER_UV_SCALE ); RectClass edge; edge.Set( 0, 0, draw.Left, screen_size.Y ); // Left _Sniper2DBaseRenderer->Add_Quad( edge, blackuv ); edge.Set( draw.Right, 0, screen_size.X, screen_size.Y ); // Right _Sniper2DBaseRenderer->Add_Quad( edge, blackuv ); edge.Set( draw.Left, 0, draw.Right, draw.Top ); // Top _Sniper2DBaseRenderer->Add_Quad( edge, blackuv ); edge.Set( draw.Left, draw.Bottom, draw.Right, screen_size.Y ); // Bottom _Sniper2DBaseRenderer->Add_Quad( edge, blackuv ); // Draw the center box Vector2 box_corner = BOX_SIZE; box_corner.Scale( screen_scale ); RectClass box( -box_corner, box_corner ); box += screen_center; // Center it _Sniper2DBaseRenderer->Add_Outline( box, 1, blackuv ); // Draw the top line Vector2 top_line_1 = TOP_LINE_1; top_line_1.Scale( screen_scale ); _Sniper2DBaseRenderer->Add_Line( Vector2(screen_center.X,0), Vector2(screen_center.X,top_line_1.Y), 1, blackuv ); // Draw the top line 2 Vector2 top_line_2 = TOP_LINE_2; top_line_2.Scale( screen_scale ); _Sniper2DBaseRenderer->Add_Line( Vector2(screen_center.X,box.Top), Vector2(screen_center.X,top_line_2.Y), 1, blackuv ); // Draw the top line 3 Vector2 top_line_3 = TOP_LINE_3; top_line_3.Scale( screen_scale ); _Sniper2DBaseRenderer->Add_Line( Vector2(screen_center.X,box.Top), Vector2(screen_center.X,top_line_3.Y), 3, blackuv ); // Draw the bottom line Vector2 bottom_line_1 = BOTTOM_LINE_1; bottom_line_1.Scale( screen_scale.Y, screen_scale.Y ); _Sniper2DBaseRenderer->Add_Line( Vector2(screen_center.X,bottom_line_1.X), Vector2(screen_center.X,bottom_line_1.Y), 1, blackuv ); // Draw the bottom line 2 Vector2 bottom_line_2 = BOTTOM_LINE_2; bottom_line_2.Scale( screen_scale ); _Sniper2DBaseRenderer->Add_Line( Vector2(screen_center.X - bottom_line_2.X,bottom_line_2.Y), Vector2(screen_center.X + bottom_line_2.X,bottom_line_2.Y), 1, blackuv ); // Draw the bottom line 3 float y; float left = screen_center.X + 3; float right = BOTTOM_LINE_3.X * screen_scale.X; float step = BOTTOM_LINE_3.Y * screen_scale.Y; for ( y = bottom_line_2.Y; y < bottom_line_1.Y; y += step ) { _Sniper2DBaseRenderer->Add_Line( Vector2(left,y), Vector2(right,y), 1, blackuv ); } // Draw the left lines left = LEFT_LINE_UL.X * screen_scale.X; right = LEFT_LINE_LR.X * screen_scale.X; for ( y = screen_center.Y; y < LEFT_LINE_UL.Y * screen_scale.Y; y += LEFT_LINE_LR.Y * screen_scale.Y ) { float flip = screen_size.Y - y; _Sniper2DBaseRenderer->Add_Line( Vector2( left, y ), Vector2( right,y ), 1, blackuv ); _Sniper2DBaseRenderer->Add_Line( Vector2( left, flip ), Vector2( right, flip ), 1, blackuv ); } // Draw the right line _Sniper2DBaseRenderer->Add_Line( Vector2(box.Right,screen_center.Y), Vector2(screen_size.X,screen_center.Y), 1, blackuv ); // Draw the center line Vector2 center_line( -screen_scale.X, screen_scale.X ); center_line *= CENTER_LINE_1.X; center_line += Vector2( screen_center.X, screen_center.X); _Sniper2DBaseRenderer->Add_Line( Vector2(center_line.X,screen_center.Y), Vector2(center_line.Y,screen_center.Y), 1, blackuv ); // Draw the center line 2 center_line = Vector2( screen_scale.X, screen_scale.X ); center_line.Scale( CENTER_LINE_2 ); center_line += Vector2( screen_center.X, screen_center.X); _Sniper2DBaseRenderer->Add_Line( Vector2(center_line.X,screen_center.Y), Vector2(center_line.Y,screen_center.Y), 3, blackuv ); center_line -= Vector2( screen_center.X, screen_center.X); center_line *= -1; center_line += Vector2( screen_center.X, screen_center.X); _Sniper2DBaseRenderer->Add_Line( Vector2(center_line.X,screen_center.Y), Vector2(center_line.Y,screen_center.Y), 3, blackuv ); // Draw the left line _Sniper2DBaseRenderer->Add_Line( Vector2(0, screen_center.Y), Vector2(LEFT_LINE_2.X*screen_scale.X,screen_center.Y), 1, blackuv ); } /* ** */ void SniperHUDClass::Update( void ) { // Info_Editor_Update(); if ( _Sniper2DRenderer == NULL ) { return; } _Sniper2DRenderer->Reset(); Vector2 screen_size = Render2DClass::Get_Screen_Resolution().Lower_Right(); Vector2 screen_scale = screen_size * 0.001f; // Set tint color int tint = 0xFF0000FF; // Blue tint = 0xFF00FF00; // Green // Draw Zoom Indicator RectClass uv; uv.Set( ZOOM_UV_UL, ZOOM_UV_LR ); RectClass draw = uv; uv.Scale( SNIPER_UV_SCALE ); float zoom_ratio = COMBAT_CAMERA->Get_Sniper_Zoom(); Vector2 pos = ((ZOOM_OFFSET_BOTTOM - ZOOM_OFFSET_TOP) * zoom_ratio) + ZOOM_OFFSET_TOP; pos.Scale( screen_scale ); draw += pos - draw.Center(); _Sniper2DRenderer->Add_Quad( draw, uv, tint ); #if 0 // Add Scanline static float _scan_line_offset = 0; RectClass scan_line = settings->SniperView; scan_line.Bottom = scan_line.Top + 0.005f; _scan_line_offset += TimeManager::Get_Frame_Seconds() * 0.1f; if ( _scan_line_offset > settings->SniperView.Height() + 0.05f ) { _scan_line_offset = -0.05f; } scan_line += Vector2( 0, _scan_line_offset ); _Sniper2DRenderer->Add_Quad( scan_line, Scale_UV( settings->SniperScanLineUV, sniper_texture_size ) ); // Add Distance Graph float dist = COMBAT_CAMERA->Get_Sniper_Distance(); float dist_ratio = WWMath::Clamp( dist / settings->SniperDistanceGraphMax, 0, 1 ); dist_ratio = WWMath::Sqrt( dist_ratio ); RectClass dist_screen = settings->SniperDistanceGraph; RectClass dist_uv = Scale_UV( settings->SniperDistanceGraphUV, sniper_texture_size ); dist_screen.Top = dist_screen.Bottom - dist_screen.Height() * dist_ratio; dist_uv.Top = dist_uv.Bottom - dist_uv.Height() * dist_ratio; _Sniper2DRenderer->Add_Quad( dist_screen, dist_uv ); #endif } /* ** */ void SniperHUDClass::Render( void ) { if ( _Sniper2DBaseRenderer ) { _Sniper2DBaseRenderer->Render(); } if ( _Sniper2DRenderer ) { _Sniper2DRenderer->Render(); } } #if 0 /* ** Info Display */ struct InfoEditorField { const char * Name; Vector2 * Value; bool operator == (InfoEditorField const & rec) const { return false; } bool operator != (InfoEditorField const & rec) const { return true; } }; static DynamicVectorClass InfoEditorFieldList; #define INFO_EDITOR_ADD(x) field.Name = #x; field.Value = &x; InfoEditorFieldList.Add( field ); static void Info_Editor_Init( void ) { InfoEditorField field; INFO_EDITOR_ADD( BLACK_UV_UL ); INFO_EDITOR_ADD( BLACK_UV_LR ); INFO_EDITOR_ADD( SNIPER_VIEW_UV_UL ); INFO_EDITOR_ADD( SNIPER_VIEW_UV_LR ); INFO_EDITOR_ADD( SNIPER_VIEW_UL ); INFO_EDITOR_ADD( SNIPER_VIEW_LR ); INFO_EDITOR_ADD( BOX_SIZE ); INFO_EDITOR_ADD( TOP_LINE_1 ); INFO_EDITOR_ADD( TOP_LINE_2 ); INFO_EDITOR_ADD( TOP_LINE_3 ); INFO_EDITOR_ADD( BOTTOM_LINE_1 ); INFO_EDITOR_ADD( BOTTOM_LINE_2 ); INFO_EDITOR_ADD( BOTTOM_LINE_3 ); INFO_EDITOR_ADD( CENTER_LINE_1 ); INFO_EDITOR_ADD( CENTER_LINE_2 ); INFO_EDITOR_ADD( LEFT_LINE_UL ); INFO_EDITOR_ADD( LEFT_LINE_LR ); INFO_EDITOR_ADD( LEFT_LINE_2 ); INFO_EDITOR_ADD( ZOOM_UV_UL ); INFO_EDITOR_ADD( ZOOM_UV_LR ); INFO_EDITOR_ADD( ZOOM_OFFSET_TOP ); INFO_EDITOR_ADD( ZOOM_OFFSET_BOTTOM ); } static void Info_Editor_Update( void ) { bool changed = false; static int index = 0; static float _move = 0; float move = Input::Get_Amount( INPUT_FUNCTION_MOVE_LEFT ) - Input::Get_Amount( INPUT_FUNCTION_MOVE_RIGHT ); if ( _move != move ) { _move = move; index += (int)-move; index = (int)WWMath::Wrap( index, (float)0, (float)(InfoEditorFieldList.Count()) ); if ( move != 0 ) { changed = true; } } float _forward = 0; float forward = Input::Get_Amount( INPUT_FUNCTION_MOVE_FORWARD ) - Input::Get_Amount( INPUT_FUNCTION_MOVE_BACKWARD ); forward *= 10; forward = WWMath::Clamp( forward, -1, 1 ); if ( _forward != forward ) { _forward = forward; InfoEditorFieldList[index].Value->V += forward; if ( forward != 0 ) { changed = true; } } float _left = 0; float left = Input::Get_Amount( INPUT_FUNCTION_TURN_LEFT ) - Input::Get_Amount( INPUT_FUNCTION_TURN_RIGHT ); left *= 10; left = WWMath::Clamp( left, -1, 1 ); if ( _left != left ) { _left = left; InfoEditorFieldList[index].Value->U += left; if ( left != 0 ) { changed = true; } } if ( changed ) { Debug_Say(( "Vector2 %s( %d, %d );\n", InfoEditorFieldList[index].Name, (int)InfoEditorFieldList[index].Value->U, (int)InfoEditorFieldList[index].Value->V )); } } static void Info_Editor_Shutdown( void ) { while ( InfoEditorFieldList.Count() > 0 ) { Debug_Say(( "Vector2 %s( %d, %d );\n", InfoEditorFieldList[0].Name, (int)InfoEditorFieldList[0].Value->U, (int)InfoEditorFieldList[0].Value->V )); InfoEditorFieldList.Delete(0); } } #endif