/*
** 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