mirror of
https://github.com/electronicarts/CnC_Generals_Zero_Hour.git
synced 2025-12-16 23:51:41 -05:00
Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: Generals
|
||||
//
|
||||
// Module: VideoDevice
|
||||
//
|
||||
// File name: BinkDevice.cpp
|
||||
//
|
||||
// Created: 10/22/01 TR
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "Lib/BaseType.h"
|
||||
#include "VideoDevice/Bink/BinkVideoPlayer.h"
|
||||
#include "Common/AudioAffect.h"
|
||||
#include "Common/GameAudio.h"
|
||||
#include "Common/GameMemory.h"
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/Registry.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Externals
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//----------------------------------------------------------------------------
|
||||
#define VIDEO_LANG_PATH_FORMAT "Data/%s/Movies/%s.%s"
|
||||
#define VIDEO_PATH "Data\\Movies"
|
||||
#define VIDEO_EXT "bik"
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Types
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Public Data
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::BinkVideoPlayer
|
||||
//============================================================================
|
||||
|
||||
BinkVideoPlayer::BinkVideoPlayer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::~BinkVideoPlayer
|
||||
//============================================================================
|
||||
|
||||
BinkVideoPlayer::~BinkVideoPlayer()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::init
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoPlayer::init( void )
|
||||
{
|
||||
// Need to load the stuff from the ini file.
|
||||
VideoPlayer::init();
|
||||
|
||||
initializeBinkWithMiles();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::deinit
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoPlayer::deinit( void )
|
||||
{
|
||||
TheAudio->releaseHandleForBink();
|
||||
VideoPlayer::deinit();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::reset
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoPlayer::reset( void )
|
||||
{
|
||||
VideoPlayer::reset();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::update
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoPlayer::update( void )
|
||||
{
|
||||
VideoPlayer::update();
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::loseFocus
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoPlayer::loseFocus( void )
|
||||
{
|
||||
VideoPlayer::loseFocus();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::regainFocus
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoPlayer::regainFocus( void )
|
||||
{
|
||||
VideoPlayer::regainFocus();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::createStream
|
||||
//============================================================================
|
||||
|
||||
VideoStreamInterface* BinkVideoPlayer::createStream( HBINK handle )
|
||||
{
|
||||
|
||||
if ( handle == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BinkVideoStream *stream = NEW BinkVideoStream;
|
||||
|
||||
if ( stream )
|
||||
{
|
||||
|
||||
stream->m_handle = handle;
|
||||
stream->m_next = m_firstStream;
|
||||
stream->m_player = this;
|
||||
m_firstStream = stream;
|
||||
|
||||
// never let volume go to 0, as Bink will interpret that as "play at full volume".
|
||||
Int mod = (Int) ((TheAudio->getVolume(AudioAffect_Speech) * 0.8f) * 100) + 1;
|
||||
Int volume = (32768*mod)/100;
|
||||
DEBUG_LOG(("BinkVideoPlayer::createStream() - About to set volume (%g -> %d -> %d\n",
|
||||
TheAudio->getVolume(AudioAffect_Speech), mod, volume));
|
||||
BinkSetVolume( stream->m_handle,0, volume);
|
||||
DEBUG_LOG(("BinkVideoPlayer::createStream() - set volume\n"));
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::open
|
||||
//============================================================================
|
||||
|
||||
VideoStreamInterface* BinkVideoPlayer::open( AsciiString movieTitle )
|
||||
{
|
||||
VideoStreamInterface* stream = NULL;
|
||||
|
||||
const Video* pVideo = getVideo(movieTitle);
|
||||
if (pVideo) {
|
||||
DEBUG_LOG(("BinkVideoPlayer::createStream() - About to open bink file\n"));
|
||||
|
||||
if (TheGlobalData->m_modDir.isNotEmpty())
|
||||
{
|
||||
char filePath[ _MAX_PATH ];
|
||||
sprintf( filePath, "%s%s\\%s.%s", TheGlobalData->m_modDir.str(), VIDEO_PATH, pVideo->m_filename.str(), VIDEO_EXT );
|
||||
HBINK handle = BinkOpen(filePath , BINKPRELOADALL );
|
||||
DEBUG_ASSERTLOG(!handle, ("opened bink file %s\n", filePath));
|
||||
if (handle)
|
||||
{
|
||||
return createStream( handle );
|
||||
}
|
||||
}
|
||||
|
||||
char localizedFilePath[ _MAX_PATH ];
|
||||
sprintf( localizedFilePath, VIDEO_LANG_PATH_FORMAT, GetRegistryLanguage().str(), pVideo->m_filename.str(), VIDEO_EXT );
|
||||
HBINK handle = BinkOpen(localizedFilePath , BINKPRELOADALL );
|
||||
DEBUG_ASSERTLOG(!handle, ("opened localized bink file %s\n", localizedFilePath));
|
||||
if (!handle)
|
||||
{
|
||||
char filePath[ _MAX_PATH ];
|
||||
sprintf( filePath, "%s\\%s.%s", VIDEO_PATH, pVideo->m_filename.str(), VIDEO_EXT );
|
||||
handle = BinkOpen(filePath , BINKPRELOADALL );
|
||||
DEBUG_ASSERTLOG(!handle, ("opened bink file %s\n", localizedFilePath));
|
||||
}
|
||||
|
||||
DEBUG_LOG(("BinkVideoPlayer::createStream() - About to create stream\n"));
|
||||
stream = createStream( handle );
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoPlayer::load
|
||||
//============================================================================
|
||||
|
||||
VideoStreamInterface* BinkVideoPlayer::load( AsciiString movieTitle )
|
||||
{
|
||||
return open(movieTitle); // load() used to have the same body as open(), so I'm combining them. Munkee.
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//============================================================================
|
||||
void BinkVideoPlayer::notifyVideoPlayerOfNewProvider( Bool nowHasValid )
|
||||
{
|
||||
if (!nowHasValid) {
|
||||
TheAudio->releaseHandleForBink();
|
||||
BinkSetSoundTrack(0, 0);
|
||||
} else {
|
||||
initializeBinkWithMiles();
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//============================================================================
|
||||
void BinkVideoPlayer::initializeBinkWithMiles()
|
||||
{
|
||||
Int retVal = 0;
|
||||
void *driver = TheAudio->getHandleForBink();
|
||||
|
||||
if ( driver )
|
||||
{
|
||||
retVal = BinkSoundUseDirectSound(driver);
|
||||
}
|
||||
if( !driver || retVal == 0)
|
||||
{
|
||||
BinkSetSoundTrack ( 0,0 );
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::BinkVideoStream
|
||||
//============================================================================
|
||||
|
||||
BinkVideoStream::BinkVideoStream()
|
||||
: m_handle(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::~BinkVideoStream
|
||||
//============================================================================
|
||||
|
||||
BinkVideoStream::~BinkVideoStream()
|
||||
{
|
||||
if ( m_handle != NULL )
|
||||
{
|
||||
BinkClose( m_handle );
|
||||
m_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::update
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoStream::update( void )
|
||||
{
|
||||
BinkWait( m_handle );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::isFrameReady
|
||||
//============================================================================
|
||||
|
||||
Bool BinkVideoStream::isFrameReady( void )
|
||||
{
|
||||
return !BinkWait( m_handle );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::frameDecompress
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoStream::frameDecompress( void )
|
||||
{
|
||||
BinkDoFrame( m_handle );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::frameRender
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoStream::frameRender( VideoBuffer *buffer )
|
||||
{
|
||||
if ( buffer )
|
||||
{
|
||||
void *mem = buffer->lock();
|
||||
|
||||
u32 flags;
|
||||
|
||||
switch ( buffer->format())
|
||||
{
|
||||
case VideoBuffer::TYPE_X8R8G8B8:
|
||||
flags = BINKSURFACE32;
|
||||
break;
|
||||
|
||||
case VideoBuffer::TYPE_R8G8B8:
|
||||
flags = BINKSURFACE24;
|
||||
break;
|
||||
|
||||
case VideoBuffer::TYPE_R5G6B5:
|
||||
flags = BINKSURFACE565;
|
||||
break;
|
||||
|
||||
case VideoBuffer::TYPE_X1R5G5B5:
|
||||
flags = BINKSURFACE555;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if ( mem != NULL )
|
||||
{
|
||||
|
||||
BinkCopyToBuffer ( m_handle, mem, buffer->pitch(), buffer->height(),
|
||||
buffer->xPos(), buffer->yPos(), flags );
|
||||
buffer->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::frameNext
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoStream::frameNext( void )
|
||||
{
|
||||
BinkNextFrame( m_handle );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::frameIndex
|
||||
//============================================================================
|
||||
|
||||
Int BinkVideoStream::frameIndex( void )
|
||||
{
|
||||
return m_handle->FrameNum - 1;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::totalFrames
|
||||
//============================================================================
|
||||
|
||||
Int BinkVideoStream::frameCount( void )
|
||||
{
|
||||
return m_handle->Frames;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// BinkVideoStream::frameGoto
|
||||
//============================================================================
|
||||
|
||||
void BinkVideoStream::frameGoto( Int index )
|
||||
{
|
||||
BinkGoto(m_handle, index, NULL );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// VideoStream::height
|
||||
//============================================================================
|
||||
|
||||
Int BinkVideoStream::height( void )
|
||||
{
|
||||
return m_handle->Height;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// VideoStream::width
|
||||
//============================================================================
|
||||
|
||||
Int BinkVideoStream::width( void )
|
||||
{
|
||||
return m_handle->Width;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DFunctionLexicon.cpp ///////////////////////////////////////////////////////////////////
|
||||
// Created: Colin Day, September 2001
|
||||
// Desc: Function lexicon for w3d specific function pointers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "GameClient/GameWindow.h"
|
||||
#include "W3DDevice/Common/W3DFunctionLexicon.h"
|
||||
#include "W3DDevice/GameClient/W3DGUICallbacks.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindow.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE DATA
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Game Window draw methods -----------------------------------------------------------------------
|
||||
static FunctionLexicon::TableEntry gameWinDrawTable [] =
|
||||
{
|
||||
|
||||
{ NAMEKEY_INVALID, "GameWinDefaultDraw", GameWinDefaultDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGameWinDefaultDraw", W3DGameWinDefaultDraw },
|
||||
|
||||
{ NAMEKEY_INVALID, "W3DGadgetPushButtonDraw", W3DGadgetPushButtonDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetPushButtonImageDraw", W3DGadgetPushButtonImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetCheckBoxDraw", W3DGadgetCheckBoxDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetCheckBoxImageDraw", W3DGadgetCheckBoxImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetRadioButtonDraw", W3DGadgetRadioButtonDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetRadioButtonImageDraw", W3DGadgetRadioButtonImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetTabControlDraw", W3DGadgetTabControlDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetTabControlImageDraw", W3DGadgetTabControlImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetListBoxDraw", W3DGadgetListBoxDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetListBoxImageDraw", W3DGadgetListBoxImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetComboBoxDraw", W3DGadgetComboBoxDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetComboBoxImageDraw", W3DGadgetComboBoxImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetHorizontalSliderDraw", W3DGadgetHorizontalSliderDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetHorizontalSliderImageDraw", W3DGadgetHorizontalSliderImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetVerticalSliderDraw", W3DGadgetVerticalSliderDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetVerticalSliderImageDraw", W3DGadgetVerticalSliderImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetProgressBarDraw", W3DGadgetProgressBarDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetProgressBarImageDraw", W3DGadgetProgressBarImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetStaticTextDraw", W3DGadgetStaticTextDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetStaticTextImageDraw", W3DGadgetStaticTextImageDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetTextEntryDraw", W3DGadgetTextEntryDraw },
|
||||
{ NAMEKEY_INVALID, "W3DGadgetTextEntryImageDraw", W3DGadgetTextEntryImageDraw },
|
||||
|
||||
{ NAMEKEY_INVALID, "W3DLeftHUDDraw", W3DLeftHUDDraw },
|
||||
{ NAMEKEY_INVALID, "W3DCameoMovieDraw", W3DCameoMovieDraw },
|
||||
{ NAMEKEY_INVALID, "W3DRightHUDDraw", W3DRightHUDDraw },
|
||||
{ NAMEKEY_INVALID, "W3DPowerDraw", W3DPowerDraw },
|
||||
{ NAMEKEY_INVALID, "W3DMainMenuDraw", W3DMainMenuDraw },
|
||||
{ NAMEKEY_INVALID, "W3DMainMenuFourDraw", W3DMainMenuFourDraw },
|
||||
{ NAMEKEY_INVALID, "W3DMetalBarMenuDraw", W3DMetalBarMenuDraw },
|
||||
{ NAMEKEY_INVALID, "W3DCreditsMenuDraw", W3DCreditsMenuDraw },
|
||||
{ NAMEKEY_INVALID, "W3DClockDraw", W3DClockDraw },
|
||||
{ NAMEKEY_INVALID, "W3DMainMenuMapBorder", W3DMainMenuMapBorder },
|
||||
{ NAMEKEY_INVALID, "W3DMainMenuButtonDropShadowDraw", W3DMainMenuButtonDropShadowDraw },
|
||||
{ NAMEKEY_INVALID, "W3DMainMenuRandomTextDraw", W3DMainMenuRandomTextDraw },
|
||||
{ NAMEKEY_INVALID, "W3DThinBorderDraw", W3DThinBorderDraw },
|
||||
{ NAMEKEY_INVALID, "W3DShellMenuSchemeDraw", W3DShellMenuSchemeDraw },
|
||||
{ NAMEKEY_INVALID, "W3DCommandBarBackgroundDraw", W3DCommandBarBackgroundDraw },
|
||||
{ NAMEKEY_INVALID, "W3DCommandBarTopDraw", W3DCommandBarTopDraw },
|
||||
{ NAMEKEY_INVALID, "W3DCommandBarGenExpDraw", W3DCommandBarGenExpDraw },
|
||||
{ NAMEKEY_INVALID, "W3DCommandBarHelpPopupDraw", W3DCommandBarHelpPopupDraw },
|
||||
|
||||
{ NAMEKEY_INVALID, "W3DCommandBarGridDraw", W3DCommandBarGridDraw },
|
||||
|
||||
|
||||
{ NAMEKEY_INVALID, "W3DCommandBarForegroundDraw", W3DCommandBarForegroundDraw },
|
||||
{ NAMEKEY_INVALID, "W3DNoDraw", W3DNoDraw },
|
||||
{ NAMEKEY_INVALID, "W3DDrawMapPreview", W3DDrawMapPreview },
|
||||
|
||||
{ NAMEKEY_INVALID, NULL, NULL },
|
||||
|
||||
};
|
||||
|
||||
// Game Window init methods -----------------------------------------------------------------------
|
||||
static FunctionLexicon::TableEntry layoutInitTable [] =
|
||||
{
|
||||
|
||||
{ NAMEKEY_INVALID, "W3DMainMenuInit", W3DMainMenuInit },
|
||||
|
||||
{ NAMEKEY_INVALID, NULL, NULL },
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DFunctionLexicon::W3DFunctionLexicon( void )
|
||||
{
|
||||
|
||||
} // end W3DFunctionLexicon
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DFunctionLexicon::~W3DFunctionLexicon( void )
|
||||
{
|
||||
|
||||
} // end ~W3DFunctionLexicon
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Initialize the function table specific for our implementations of
|
||||
* the w3d device */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DFunctionLexicon::init( void )
|
||||
{
|
||||
|
||||
// extend functionality
|
||||
FunctionLexicon::init();
|
||||
|
||||
// load our own tables
|
||||
loadTable( gameWinDrawTable, TABLE_GAME_WIN_DEVICEDRAW );
|
||||
loadTable( layoutInitTable, TABLE_WIN_LAYOUT_DEVICEINIT );
|
||||
|
||||
} // end init
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Reset */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DFunctionLexicon::reset( void )
|
||||
{
|
||||
|
||||
// Pay attention to the order of what happens in the base class as you reset
|
||||
|
||||
// extend
|
||||
FunctionLexicon::reset();
|
||||
|
||||
} // end reset
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Update */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DFunctionLexicon::update( void )
|
||||
{
|
||||
|
||||
// extend?
|
||||
FunctionLexicon::update();
|
||||
|
||||
} // end update
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DModuleFactory.cpp /////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, April 2001
|
||||
// Desc: W3D specific module
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "W3DDevice/Common/W3DModuleFactory.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DDebrisDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DDefaultDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DDependencyModelDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DModelDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DLaserDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DOverlordTankDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DOverlordTruckDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DOverlordAircraftDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DPoliceCarDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DProjectileStreamDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DRopeDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DSupplyDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DScienceModelDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTankDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTruckDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTankTruckDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTracerDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTreeDraw.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DPropDraw.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Initialize method */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DModuleFactory::init( void )
|
||||
{
|
||||
|
||||
// extending functionality
|
||||
ModuleFactory::init();
|
||||
|
||||
// add the specific module templates we need for the draw methods
|
||||
addModule( W3DDefaultDraw );
|
||||
addModule( W3DDebrisDraw );
|
||||
addModule( W3DModelDraw );
|
||||
addModule( W3DLaserDraw );
|
||||
addModule( W3DOverlordTankDraw );
|
||||
addModule( W3DOverlordTruckDraw );
|
||||
addModule( W3DOverlordAircraftDraw );
|
||||
addModule( W3DProjectileStreamDraw );
|
||||
addModule( W3DPoliceCarDraw );
|
||||
addModule( W3DRopeDraw );
|
||||
addModule( W3DScienceModelDraw );
|
||||
addModule( W3DSupplyDraw );
|
||||
addModule( W3DDependencyModelDraw );
|
||||
addModule( W3DTankDraw );
|
||||
addModule( W3DTruckDraw );
|
||||
addModule( W3DTracerDraw );
|
||||
addModule( W3DTankTruckDraw );
|
||||
addModule( W3DTreeDraw );
|
||||
addModule( W3DPropDraw );
|
||||
|
||||
} // end init
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DThingFactory.cpp //////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, February 2002
|
||||
// Desc: Device dependent thing factory access, for things like post processing the
|
||||
// Thing database where we might want to look at device dependent stuff like
|
||||
// model info and such
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
|
||||
#include "W3DDevice/Common/W3DThingFactory.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DThingFactory::W3DThingFactory( void )
|
||||
{
|
||||
|
||||
} // end W3DThingFactory
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DThingFactory::~W3DThingFactory( void )
|
||||
{
|
||||
|
||||
} // end ~W3DThingFactory
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//=============================================================================
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DConvert.cpp
|
||||
//
|
||||
// Created: Colin Day, April 2001
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
#include "W3DDevice/Common/W3DConvert.h"
|
||||
|
||||
//=============================================================================
|
||||
// Externals
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Defines
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Private Types
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Private Data
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Public Data
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Private Prototypes
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Private Functions
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// Public Functions
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
// W3DLogicalScreenToPixelScreen
|
||||
//=============================================================================
|
||||
/** Translate a W3D logical pixel coord with (-1,-1) at the lower left and
|
||||
* (1,1) at the upper right to a pixel screen coord with (0,0) at the
|
||||
* upper left */
|
||||
//=============================================================================
|
||||
void W3DLogicalScreenToPixelScreen( Real logX, Real logY,
|
||||
Int *screenX, Int *screenY,
|
||||
Int screenWidth, Int screenHeight )
|
||||
{
|
||||
*screenX = REAL_TO_INT((screenWidth * (logX + 1.0f)) / 2.0f);
|
||||
*screenY = REAL_TO_INT((screenHeight * (-logY + 1.0f)) / 2.0f);
|
||||
|
||||
} // end W3DLogicalScreenToPixelScreen
|
||||
|
||||
//=============================================================================
|
||||
// PixelScreenToW3DLogicalScreen
|
||||
//=============================================================================
|
||||
/** Translate a pixel coord with (0,0) at the upper left to the W3D logical
|
||||
* coord system used with (-1,-1) in the lower left corner and (1,1) the
|
||||
* upper right corner */
|
||||
//=============================================================================
|
||||
void PixelScreenToW3DLogicalScreen( Int screenX, Int screenY,
|
||||
Real *logX, Real *logY,
|
||||
Int screenWidth, Int screenHeight )
|
||||
{
|
||||
|
||||
*logX = ((2.0f * screenX) / (Real)screenWidth) - 1.0f;
|
||||
*logY = -(((2.0f * screenY) / (Real)screenHeight) - 1.0f);
|
||||
|
||||
} // end PixelScreenToW3DLogicalScreen
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DDebrisDraw.cpp ////////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, November 2001
|
||||
// Desc: Default w3d draw module
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common/FileSystem.h" // this is only here to pull in LOAD_TEST_ASSETS
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameClient/Shadow.h"
|
||||
#include "GameClient/FXList.h"
|
||||
#include "GameLogic/TerrainLogic.h"
|
||||
|
||||
#include "WW3D2/HAnim.h"
|
||||
#include "WW3D2/HLod.h"
|
||||
#include "WW3D2/RendObj.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DDebrisDraw.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "W3DDevice/GameClient/W3DShadow.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDebrisDraw::W3DDebrisDraw(Thing *thing, const ModuleData* moduleData) : DrawModule(thing, moduleData)
|
||||
{
|
||||
m_renderObject = NULL;
|
||||
for (int i = 0; i < STATECOUNT; ++i)
|
||||
m_anims[i] = NULL;
|
||||
m_fxFinal = NULL;
|
||||
m_state = INITIAL;
|
||||
m_frames = 0;
|
||||
m_shadow = NULL;
|
||||
m_finalStop = false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDebrisDraw::~W3DDebrisDraw(void)
|
||||
{
|
||||
if (TheW3DShadowManager && m_shadow)
|
||||
{
|
||||
TheW3DShadowManager->removeShadow(m_shadow);
|
||||
m_shadow = NULL;
|
||||
}
|
||||
if (m_renderObject)
|
||||
{
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object(m_renderObject);
|
||||
REF_PTR_RELEASE(m_renderObject);
|
||||
m_renderObject = NULL;
|
||||
}
|
||||
for (int i = 0; i < STATECOUNT; ++i)
|
||||
{
|
||||
REF_PTR_RELEASE(m_anims[i]);
|
||||
m_anims[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::setShadowsEnabled(Bool enable)
|
||||
{
|
||||
if (m_shadow)
|
||||
m_shadow->enableShadowRender(enable);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::setFullyObscuredByShroud(Bool fullyObscured)
|
||||
{
|
||||
if (m_shadow)
|
||||
m_shadow->enableShadowInvisible(fullyObscured);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::setModelName(AsciiString name, Color color, ShadowType t)
|
||||
{
|
||||
if (m_renderObject == NULL && !name.isEmpty())
|
||||
{
|
||||
Int hexColor = 0;
|
||||
if (color != 0)
|
||||
hexColor = color | 0xFF000000;
|
||||
m_renderObject = W3DDisplay::m_assetManager->Create_Render_Obj(name.str(), getDrawable()->getScale(), hexColor);
|
||||
DEBUG_ASSERTCRASH(m_renderObject, ("Debris model %s not found!\n",name.str()));
|
||||
if (m_renderObject)
|
||||
{
|
||||
W3DDisplay::m_3DScene->Add_Render_Object(m_renderObject);
|
||||
|
||||
m_renderObject->Set_User_Data(getDrawable()->getDrawableInfo());
|
||||
|
||||
Matrix3D transform;
|
||||
///@todo: Change back to identity once we figure out why objects show up at 0,0,0
|
||||
/// OBJECT_PILE
|
||||
// transform.Set(Vector3(0,0,9999));
|
||||
transform.Set(Vector3(0,0,0));
|
||||
m_renderObject->Set_Transform(transform);
|
||||
}
|
||||
|
||||
if (t != SHADOW_NONE)
|
||||
{
|
||||
Shadow::ShadowTypeInfo shadowInfo;
|
||||
shadowInfo.m_type = t;
|
||||
shadowInfo.m_sizeX=0;
|
||||
shadowInfo.m_sizeY=0;
|
||||
m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TheW3DShadowManager && m_shadow)
|
||||
{
|
||||
TheW3DShadowManager->removeShadow(m_shadow);
|
||||
m_shadow = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// save the model name and color
|
||||
m_modelName = name;
|
||||
m_modelColor = color;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::setAnimNames(AsciiString initial, AsciiString flying, AsciiString final, const FXList* finalFX)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < STATECOUNT; ++i)
|
||||
{
|
||||
REF_PTR_RELEASE(m_anims[i]);
|
||||
m_anims[i] = NULL;
|
||||
}
|
||||
|
||||
m_anims[INITIAL] = initial.isEmpty() ? NULL : W3DDisplay::m_assetManager->Get_HAnim(initial.str());
|
||||
m_anims[FLYING] = flying.isEmpty() ? NULL : W3DDisplay::m_assetManager->Get_HAnim(flying.str());
|
||||
if (stricmp(final.str(), "STOP") == 0)
|
||||
{
|
||||
m_finalStop = true;
|
||||
final = flying;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_finalStop = false;
|
||||
}
|
||||
m_anims[FINAL] = final.isEmpty() ? NULL : W3DDisplay::m_assetManager->Get_HAnim(final.str());
|
||||
m_state = 0;
|
||||
m_frames = 0;
|
||||
m_fxFinal = finalFX;
|
||||
|
||||
m_animInitial = initial;
|
||||
m_animFlying = flying;
|
||||
m_animFinal = final;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static Bool isAnimationComplete(RenderObjClass* r)
|
||||
{
|
||||
if (r->Class_ID() == RenderObjClass::CLASSID_HLOD)
|
||||
{
|
||||
HLodClass *hlod = (HLodClass*)r;
|
||||
return hlod->Is_Animation_Complete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
static Bool isNearlyZero(const Coord3D* vel)
|
||||
{
|
||||
const Real TINY = 0.01f;
|
||||
return fabs(vel->x) < TINY && fabs(vel->y) < TINY && fabs(vel->z) < TINY;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::reactToTransformChange( const Matrix3D *oldMtx,
|
||||
const Coord3D *oldPos,
|
||||
Real oldAngle )
|
||||
{
|
||||
|
||||
if( m_renderObject )
|
||||
m_renderObject->Set_Transform( *getDrawable()->getTransformMatrix() );
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
if (m_renderObject)
|
||||
{
|
||||
|
||||
Matrix3D scaledTransform;
|
||||
if (getDrawable()->getInstanceScale() != 1.0f)
|
||||
{ //do custom scaling of the W3D model.
|
||||
scaledTransform=*transformMtx;
|
||||
scaledTransform.Scale(getDrawable()->getInstanceScale());
|
||||
transformMtx = &scaledTransform;
|
||||
m_renderObject->Set_ObjectScale(getDrawable()->getInstanceScale());
|
||||
}
|
||||
m_renderObject->Set_Transform(*transformMtx);
|
||||
|
||||
static const RenderObjClass::AnimMode TheAnimModes[STATECOUNT] =
|
||||
{
|
||||
RenderObjClass::ANIM_MODE_ONCE,
|
||||
RenderObjClass::ANIM_MODE_LOOP,
|
||||
RenderObjClass::ANIM_MODE_ONCE
|
||||
};
|
||||
|
||||
Int oldState = m_state;
|
||||
Object* obj = getDrawable()->getObject();
|
||||
const Int MIN_FINAL_FRAMES = 3;
|
||||
if (m_state != FINAL && obj != NULL && !obj->isAboveTerrain() && m_frames > MIN_FINAL_FRAMES)
|
||||
{
|
||||
m_state = FINAL;
|
||||
}
|
||||
else if (m_state < FINAL && (isAnimationComplete(m_renderObject)))
|
||||
{
|
||||
++m_state;
|
||||
}
|
||||
HAnimClass* hanim = m_anims[m_state];
|
||||
if (hanim != NULL && (hanim != m_renderObject->Peek_Animation() || oldState != m_state))
|
||||
{
|
||||
RenderObjClass::AnimMode m = TheAnimModes[m_state];
|
||||
if (m_state == FINAL)
|
||||
{
|
||||
FXList::doFXPos(m_fxFinal, getDrawable()->getPosition(), getDrawable()->getTransformMatrix(), 0, NULL, 0.0f);
|
||||
if (m_finalStop)
|
||||
m = RenderObjClass::ANIM_MODE_MANUAL;
|
||||
}
|
||||
m_renderObject->Set_Animation(hanim, 0, m);
|
||||
}
|
||||
++m_frames;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// model name
|
||||
xfer->xferAsciiString( &m_modelName );
|
||||
|
||||
// model color
|
||||
xfer->xferColor( &m_modelColor );
|
||||
|
||||
// set the model and color
|
||||
if( xfer->getXferMode() == XFER_LOAD )
|
||||
setModelName( m_modelName, m_modelColor, SHADOW_NONE );
|
||||
|
||||
// animation initial
|
||||
xfer->xferAsciiString( &m_animInitial );
|
||||
|
||||
// anim flying
|
||||
xfer->xferAsciiString( &m_animFlying );
|
||||
|
||||
// anim final
|
||||
xfer->xferAsciiString( &m_animFinal );
|
||||
|
||||
// when loading, set the animations
|
||||
if( xfer->getXferMode() == XFER_LOAD )
|
||||
setAnimNames( m_animInitial, m_animFlying, m_animFinal, NULL );
|
||||
|
||||
// state
|
||||
xfer->xferInt( &m_state );
|
||||
|
||||
// frames
|
||||
xfer->xferInt( &m_frames );
|
||||
|
||||
// final stop
|
||||
xfer->xferBool( &m_finalStop );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDebrisDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DDefaultDraw.cpp ///////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, November 2001
|
||||
// Desc: Default w3d draw module
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common/FileSystem.h" // this is only here to pull in LOAD_TEST_ASSETS
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameClient/Shadow.h"
|
||||
#include "GameClient/FXList.h"
|
||||
#include "GameLogic/TerrainLogic.h"
|
||||
|
||||
#include "WW3D2/HAnim.h"
|
||||
#include "WW3D2/HLod.h"
|
||||
#include "WW3D2/RendObj.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DDefaultDraw.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "W3DDevice/GameClient/W3DShadow.h"
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDefaultDraw::W3DDefaultDraw(Thing *thing, const ModuleData* moduleData) : DrawModule(thing, moduleData)
|
||||
{
|
||||
#ifdef LOAD_TEST_ASSETS
|
||||
m_renderObject = NULL;
|
||||
m_shadow = NULL;
|
||||
if (!getDrawable()->getTemplate()->getLTAName().isEmpty())
|
||||
{
|
||||
m_renderObject = W3DDisplay::m_assetManager->Create_Render_Obj(getDrawable()->getTemplate()->getLTAName().str(), getDrawable()->getScale(), 0);
|
||||
|
||||
Shadow::ShadowTypeInfo shadowInfo;
|
||||
shadowInfo.m_type=(ShadowType)SHADOW_VOLUME;
|
||||
shadowInfo.m_sizeX=0; //use defaults
|
||||
shadowInfo.m_sizeY=0;
|
||||
shadowInfo.m_offsetX=0;
|
||||
shadowInfo.m_offsetY=0;
|
||||
m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo);
|
||||
|
||||
|
||||
DEBUG_ASSERTCRASH(m_renderObject, ("Test asset %s not found", getDrawable()->getTemplate()->getLTAName().str()));
|
||||
if (m_renderObject)
|
||||
{
|
||||
|
||||
W3DDisplay::m_3DScene->Add_Render_Object(m_renderObject);
|
||||
|
||||
m_renderObject->Set_User_Data(getDrawable()->getDrawableInfo());
|
||||
|
||||
Matrix3D transform;
|
||||
///@todo: Change back to identity once we figure out why objects show up at 0,0,0
|
||||
/// OBJECT_PILE
|
||||
// transform.Set(Vector3(0,0,9999));
|
||||
transform.Set(Vector3(0,0,0));
|
||||
m_renderObject->Set_Transform(transform);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::reactToTransformChange( const Matrix3D *oldMtx,
|
||||
const Coord3D *oldPos,
|
||||
Real oldAngle )
|
||||
{
|
||||
|
||||
if( m_renderObject )
|
||||
m_renderObject->Set_Transform( *getDrawable()->getTransformMatrix() );
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDefaultDraw::~W3DDefaultDraw(void)
|
||||
{
|
||||
#ifdef LOAD_TEST_ASSETS
|
||||
if (TheW3DShadowManager && m_shadow)
|
||||
{
|
||||
TheW3DShadowManager->removeShadow(m_shadow);
|
||||
m_shadow = NULL;
|
||||
}
|
||||
if (m_renderObject)
|
||||
{
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object(m_renderObject);
|
||||
REF_PTR_RELEASE(m_renderObject);
|
||||
m_renderObject = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::setShadowsEnabled(Bool enable)
|
||||
{
|
||||
#ifdef LOAD_TEST_ASSETS
|
||||
if (m_shadow)
|
||||
m_shadow->enableShadowRender(enable);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::setFullyObscuredByShroud(Bool fullyObscured)
|
||||
{
|
||||
#ifdef LOAD_TEST_ASSETS
|
||||
if (m_shadow)
|
||||
m_shadow->enableShadowInvisible(fullyObscured);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
#ifdef LOAD_TEST_ASSETS
|
||||
if(m_renderObject)
|
||||
{
|
||||
Matrix3D scaledTransform;
|
||||
if (getDrawable()->getInstanceScale() != 1.0f)
|
||||
{ //do custom scaling of the W3D model.
|
||||
scaledTransform=*transformMtx;
|
||||
scaledTransform.Scale(getDrawable()->getInstanceScale());
|
||||
transformMtx = &scaledTransform;
|
||||
m_renderObject->Set_ObjectScale(getDrawable()->getInstanceScale());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_renderObject->Set_Transform(*transformMtx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDefaultDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DDependencyModelDraw.cpp ////////////////////////////////////////////////////////////////////////////
|
||||
// Author: Graham Smallwood, October 2002
|
||||
// Desc: Draw module just like Model, except it can't draw unless somebody else explicitly says to, since they
|
||||
// have to draw first.
|
||||
//
|
||||
// This draw module can be used in a general case (although I don't see why), m_attachToDrawableBoneInContainer
|
||||
// is for the one present and main reason to use this module. Our transport needs to tell us it is okay to
|
||||
// draw after he draws.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameLogic/Module/ContainModule.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DDependencyModelDraw.h"
|
||||
|
||||
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDependencyModelDrawModuleData::W3DDependencyModelDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDependencyModelDrawModuleData::~W3DDependencyModelDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDependencyModelDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "AttachToBoneInContainer", INI::parseAsciiString, NULL, offsetof(W3DDependencyModelDrawModuleData, m_attachToDrawableBoneInContainer) },
|
||||
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDependencyModelDraw::W3DDependencyModelDraw( Thing *thing, const ModuleData* moduleData ) : W3DModelDraw( thing, moduleData )
|
||||
{
|
||||
m_dependencyCleared = FALSE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDependencyModelDraw::~W3DDependencyModelDraw()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// All this does is stop the call path if we haven't been cleared to draw yet
|
||||
void W3DDependencyModelDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
if( m_dependencyCleared )
|
||||
{
|
||||
// We've been cleared by the thing we were waiting to draw, so we can draw.
|
||||
W3DModelDraw::doDrawModule( transformMtx );
|
||||
m_dependencyCleared = FALSE;
|
||||
|
||||
|
||||
// A handy place to synchronize my drawable with container's
|
||||
Drawable *myDrawable = getDrawable();
|
||||
if ( ! myDrawable )
|
||||
return;
|
||||
|
||||
const Object *me = myDrawable->getObject();
|
||||
if ( ! me )
|
||||
return;
|
||||
|
||||
Drawable *theirDrawable = NULL;
|
||||
|
||||
if( me->getContainedBy() && !me->getContainedBy()->getContain()->isEnclosingContainerFor(me) )
|
||||
theirDrawable = me->getContainedBy()->getDrawable();
|
||||
|
||||
if( ! theirDrawable )
|
||||
return;
|
||||
|
||||
myDrawable->imitateStealthLook( *theirDrawable );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDependencyModelDraw::notifyDrawModuleDependencyCleared( )
|
||||
{
|
||||
m_dependencyCleared = TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDependencyModelDraw::adjustTransformMtx(Matrix3D& mtx) const
|
||||
{
|
||||
W3DModelDraw::adjustTransformMtx(mtx);
|
||||
|
||||
// We have an additional adjustment to make, we want to use a bone in our container if there is one
|
||||
const Object *me = getDrawable()->getObject();
|
||||
const W3DDependencyModelDrawModuleData *md = getW3DDependencyModelDrawModuleData();
|
||||
|
||||
if( md->m_attachToDrawableBoneInContainer.isNotEmpty()
|
||||
&& me
|
||||
&& me->getContainedBy()
|
||||
&& !me->getContainedBy()->getContain()->isEnclosingContainerFor(me)
|
||||
)
|
||||
{
|
||||
// If we are currently "riding on", then our client position is determined by the client position of
|
||||
// a particular bone in our container object. Our logic position is updated by OpenContain.
|
||||
const Drawable *theirDrawable = me->getContainedBy()->getDrawable();
|
||||
if( theirDrawable )
|
||||
{
|
||||
Matrix3D theirBoneMtx;
|
||||
if( theirDrawable->getCurrentWorldspaceClientBonePositions( md->m_attachToDrawableBoneInContainer.str(), theirBoneMtx ) )
|
||||
{
|
||||
mtx = theirBoneMtx;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx = *theirDrawable->getTransformMatrix();//TransformMatrix();
|
||||
DEBUG_LOG(("m_attachToDrawableBoneInContainer %s not found\n",getW3DDependencyModelDrawModuleData()->m_attachToDrawableBoneInContainer.str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDependencyModelDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDependencyModelDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
// Dependency status
|
||||
xfer->xferBool( &m_dependencyCleared );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DDependencyModelDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
|
||||
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DLaserDraw.cpp /////////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, May 2001
|
||||
// Desc: W3DLaserDraw
|
||||
// Updated: Kris Morness July 2002 -- made it data driven and added new features to make it flexible.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Color.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameClient/RayEffect.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameLogic/TerrainLogic.h"
|
||||
#include "GameLogic/Module/LaserUpdate.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DLaserDraw.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "WW3D2/RInfo.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
#include "WW3D2/Segline.h"
|
||||
#include "WWMath/Vector3.h"
|
||||
#include "WW3D2/AssetMgr.h"
|
||||
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DLaserDrawModuleData::W3DLaserDrawModuleData()
|
||||
{
|
||||
m_innerBeamWidth = 0.0f; //The total width of beam
|
||||
m_outerBeamWidth = 1.0f; //The total width of beam
|
||||
m_numBeams = 1; //Number of overlapping cylinders that make the beam. 1 beam will just use inner data.
|
||||
m_maxIntensityFrames = 0; //Laser stays at max intensity for specified time in ms.
|
||||
m_fadeFrames = 0; //Laser will fade and delete.
|
||||
m_scrollRate = 0.0f;
|
||||
m_tile = false;
|
||||
m_segments = 1;
|
||||
m_arcHeight = 0.0f;
|
||||
m_segmentOverlapRatio = 0.0f;
|
||||
m_tilingScalar = 1.0f;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DLaserDrawModuleData::~W3DLaserDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DLaserDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
ModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "NumBeams", INI::parseUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_numBeams ) },
|
||||
{ "InnerBeamWidth", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_innerBeamWidth ) },
|
||||
{ "OuterBeamWidth", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_outerBeamWidth ) },
|
||||
{ "InnerColor", INI::parseColorInt, NULL, offsetof( W3DLaserDrawModuleData, m_innerColor ) },
|
||||
{ "OuterColor", INI::parseColorInt, NULL, offsetof( W3DLaserDrawModuleData, m_outerColor ) },
|
||||
{ "MaxIntensityLifetime", INI::parseDurationUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_maxIntensityFrames ) },
|
||||
{ "FadeLifetime", INI::parseDurationUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_fadeFrames ) },
|
||||
{ "Texture", INI::parseAsciiString, NULL, offsetof( W3DLaserDrawModuleData, m_textureName ) },
|
||||
{ "ScrollRate", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_scrollRate ) },
|
||||
{ "Tile", INI::parseBool, NULL, offsetof( W3DLaserDrawModuleData, m_tile ) },
|
||||
{ "Segments", INI::parseUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_segments ) },
|
||||
{ "ArcHeight", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_arcHeight ) },
|
||||
{ "SegmentOverlapRatio", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_segmentOverlapRatio ) },
|
||||
{ "TilingScalar", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_tilingScalar ) },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DLaserDraw::W3DLaserDraw( Thing *thing, const ModuleData* moduleData ) :
|
||||
DrawModule( thing, moduleData ),
|
||||
m_line3D(NULL),
|
||||
m_texture(NULL),
|
||||
m_textureAspectRatio(1.0f),
|
||||
m_selfDirty(TRUE)
|
||||
{
|
||||
Vector3 dummyPos1( 0.0f, 0.0f, 0.0f );
|
||||
Vector3 dummyPos2( 1.0f, 1.0f, 1.0f );
|
||||
Int i;
|
||||
|
||||
const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData();
|
||||
|
||||
m_texture = WW3DAssetManager::Get_Instance()->Get_Texture( data->m_textureName.str() );
|
||||
if (m_texture)
|
||||
{
|
||||
if (!m_texture->Is_Initialized())
|
||||
m_texture->Init(); //make sure texture is actually loaded before accessing surface.
|
||||
|
||||
SurfaceClass::SurfaceDescription surfaceDesc;
|
||||
m_texture->Get_Level_Description(surfaceDesc);
|
||||
m_textureAspectRatio = (Real)surfaceDesc.Width/(Real)surfaceDesc.Height;
|
||||
}
|
||||
|
||||
//Get the color components for calculation purposes.
|
||||
Real innerRed, innerGreen, innerBlue, innerAlpha, outerRed, outerGreen, outerBlue, outerAlpha;
|
||||
GameGetColorComponentsReal( data->m_innerColor, &innerRed, &innerGreen, &innerBlue, &innerAlpha );
|
||||
GameGetColorComponentsReal( data->m_outerColor, &outerRed, &outerGreen, &outerBlue, &outerAlpha );
|
||||
|
||||
//Make sure our beams range between 1 and the maximum cap.
|
||||
#ifdef I_WANT_TO_BE_FIRED
|
||||
// srj sez: this data is const for a reason. casting away the constness because we don't like the values
|
||||
// isn't an acceptable solution. if you need to constrain the values, do so at parsing time, when
|
||||
// it's still legal to modify these values. (In point of fact, there's not even really any reason to limit
|
||||
// the numBeams or segments anymore.)
|
||||
data->m_numBeams = __min( __max( 1, data->m_numBeams ), MAX_LASER_LINES );
|
||||
data->m_segments = __min( __max( 1, data->m_segments ), MAX_SEGMENTS );
|
||||
data->m_tilingScalar = __max( 0.01f, data->m_tilingScalar );
|
||||
#endif
|
||||
|
||||
//Allocate an array of lines equal to the number of beams * segments
|
||||
m_line3D = NEW SegmentedLineClass *[ data->m_numBeams * data->m_segments ];
|
||||
|
||||
for( int segment = 0; segment < data->m_segments; segment++ )
|
||||
{
|
||||
//We don't care about segment positioning yet until we actually set the position
|
||||
|
||||
// create all the lines we need at the right transparency level
|
||||
for( i = data->m_numBeams - 1; i >= 0; i-- )
|
||||
{
|
||||
int index = segment * data->m_numBeams + i;
|
||||
|
||||
Real red, green, blue, alpha, width;
|
||||
|
||||
if( data->m_numBeams == 1 )
|
||||
{
|
||||
width = data->m_innerBeamWidth;
|
||||
alpha = innerAlpha;
|
||||
red = innerRed * innerAlpha;
|
||||
green = innerGreen * innerAlpha;
|
||||
blue = innerBlue * innerAlpha;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Calculate the scale between min and max values
|
||||
//0 means use min value, 1 means use max value
|
||||
//0.2 means min value + 20% of the diff between min and max
|
||||
Real scale = i / ( data->m_numBeams - 1.0f);
|
||||
|
||||
width = data->m_innerBeamWidth + scale * (data->m_outerBeamWidth - data->m_innerBeamWidth);
|
||||
alpha = innerAlpha + scale * (outerAlpha - innerAlpha);
|
||||
red = innerRed + scale * (outerRed - innerRed) * innerAlpha;
|
||||
green = innerGreen + scale * (outerGreen - innerGreen) * innerAlpha;
|
||||
blue = innerBlue + scale * (outerBlue - innerBlue) * innerAlpha;
|
||||
}
|
||||
|
||||
m_line3D[ index ] = NEW SegmentedLineClass;
|
||||
|
||||
SegmentedLineClass *line = m_line3D[ index ];
|
||||
if( line )
|
||||
{
|
||||
line->Set_Texture( m_texture );
|
||||
line->Set_Shader( ShaderClass::_PresetAdditiveShader ); //pick the alpha blending mode you want - see shader.h for others.
|
||||
line->Set_Width( width );
|
||||
line->Set_Color( Vector3( red, green, blue ) );
|
||||
line->Set_UV_Offset_Rate( Vector2(0.0f, data->m_scrollRate) ); //amount to scroll texture on each draw
|
||||
if( m_texture )
|
||||
{
|
||||
line->Set_Texture_Mapping_Mode(SegLineRendererClass::TILED_TEXTURE_MAP); //this tiles the texture across the line
|
||||
}
|
||||
|
||||
// add to scene
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( line ); //add it to our scene so it gets rendered with other objects.
|
||||
|
||||
// hide the render object until the first time we come to draw it and
|
||||
// set the correct position
|
||||
line->Set_Visible( 0 );
|
||||
}
|
||||
|
||||
|
||||
} // end for i
|
||||
|
||||
} //end segment loop
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DLaserDraw::~W3DLaserDraw( void )
|
||||
{
|
||||
const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData();
|
||||
|
||||
for( int i = 0; i < data->m_numBeams * data->m_segments; i++ )
|
||||
{
|
||||
|
||||
// remove line from scene
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_line3D[ i ] );
|
||||
|
||||
// delete line
|
||||
REF_PTR_RELEASE( m_line3D[ i ] );
|
||||
|
||||
} // end for i
|
||||
|
||||
delete [] m_line3D;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
Real W3DLaserDraw::getLaserTemplateWidth() const
|
||||
{
|
||||
const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData();
|
||||
return data->m_outerBeamWidth * 0.5f;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DLaserDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
//UnsignedInt currentFrame = TheGameClient->getFrame();
|
||||
const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData();
|
||||
|
||||
//Get the updatemodule that drives it...
|
||||
Drawable *draw = getDrawable();
|
||||
static NameKeyType key_LaserUpdate = NAMEKEY( "LaserUpdate" );
|
||||
LaserUpdate *update = (LaserUpdate*)draw->findClientUpdateModule( key_LaserUpdate );
|
||||
if( !update )
|
||||
{
|
||||
DEBUG_ASSERTCRASH( 0, ("W3DLaserDraw::doDrawModule() expects its owner drawable %s to have a ClientUpdate = LaserUpdate module.", draw->getTemplate()->getName().str() ));
|
||||
return;
|
||||
}
|
||||
|
||||
//If the update has moved the laser, it requires a reset of the laser.
|
||||
if (update->isDirty() || m_selfDirty)
|
||||
{
|
||||
update->setDirty(false);
|
||||
m_selfDirty = false;
|
||||
|
||||
Vector3 laserPoints[ 2 ];
|
||||
|
||||
for( int segment = 0; segment < data->m_segments; segment++ )
|
||||
{
|
||||
if( data->m_arcHeight > 0.0f && data->m_segments > 1 )
|
||||
{
|
||||
//CALCULATE A CURVED LINE BASED ON TOTAL LENGTH AND DESIRED HEIGHT INCREASE
|
||||
//To do this we will use a portion of the cos wave ranging between -0.25PI
|
||||
//and +0.25PI. 0PI is 1.0 and 0.25PI is 0.70 -- resulting in a somewhat
|
||||
//gentle curve depending on the line height and length. We also have to make
|
||||
//the line *level* for this phase of the calculations.
|
||||
|
||||
//Get the desired direct line
|
||||
Coord3D lineStart, lineEnd, lineVector;
|
||||
lineStart.set( update->getStartPos() );
|
||||
lineEnd.set( update->getEndPos() );
|
||||
//This is critical -- in the case we have sloped lines (at the end, we'll fix it)
|
||||
// lineEnd.z = lineStart.z;
|
||||
|
||||
//Get the length of the line
|
||||
lineVector.set( &lineEnd );
|
||||
lineVector.sub( &lineStart );
|
||||
Real lineLength = lineVector.length();
|
||||
|
||||
//Get the middle point (we'll use this to determine how far we are from
|
||||
//that to calculate our height -- middle point is the highest).
|
||||
Coord3D lineMiddle;
|
||||
lineMiddle.set( &lineStart );
|
||||
lineMiddle.add( &lineEnd );
|
||||
lineMiddle.scale( 0.5 );
|
||||
|
||||
//The half length is used to scale with the distance from middle to
|
||||
//get our cos( 0 to 0.25 PI) cos value
|
||||
Real halfLength = lineLength * 0.5f;
|
||||
|
||||
//Now calculate which segment we will use.
|
||||
Real startSegmentRatio = segment / ((Real)data->m_segments);
|
||||
Real endSegmentRatio = (segment + 1.0f) / ((Real)data->m_segments);
|
||||
|
||||
//Offset the segment ever-so-slightly to minimize overlap -- only apply
|
||||
//to segments that are not the start/end point
|
||||
if( segment > 0 )
|
||||
{
|
||||
startSegmentRatio -= data->m_segmentOverlapRatio;
|
||||
}
|
||||
if( segment < data->m_segments - 1 )
|
||||
{
|
||||
endSegmentRatio += data->m_segmentOverlapRatio;
|
||||
}
|
||||
|
||||
//Calculate our start segment position on the *ground*.
|
||||
Coord3D segmentStart, segmentEnd, vector;
|
||||
vector.set( &lineVector );
|
||||
vector.scale( startSegmentRatio );
|
||||
segmentStart.set( &lineStart );
|
||||
segmentStart.add( &vector );
|
||||
|
||||
//Calculate our end segment position on the *ground*.
|
||||
vector.set( &lineVector );
|
||||
vector.scale( endSegmentRatio );
|
||||
segmentEnd.set( &lineStart );
|
||||
segmentEnd.add( &vector );
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
//Now at this point, we have our segment line in the level positions that we want.
|
||||
//Calculate the raised height for the start/end segment positions using cosine.
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//Calculate the distance from midpoint for the start positions.
|
||||
vector.set( &lineMiddle );
|
||||
vector.sub( &segmentStart );
|
||||
Real dist = vector.length();
|
||||
Real scaledRadians = dist / halfLength * PI * 0.5f;
|
||||
Real height = cos( scaledRadians );
|
||||
height *= data->m_arcHeight;
|
||||
segmentStart.z += height;
|
||||
|
||||
//Now do the same thing for the end position.
|
||||
vector.set( &lineMiddle );
|
||||
vector.sub( &segmentEnd );
|
||||
dist = vector.length();
|
||||
scaledRadians = dist / halfLength * PI * 0.5f;
|
||||
height = cos( scaledRadians );
|
||||
height *= data->m_arcHeight;
|
||||
segmentEnd.z += height;
|
||||
|
||||
//This makes the laser skim the ground rather than penetrate it!
|
||||
laserPoints[ 0 ].Set( segmentStart.x, segmentStart.y,
|
||||
MAX( segmentStart.z, 2.0f + TheTerrainLogic->getGroundHeight(segmentStart.x, segmentStart.y) ) );
|
||||
laserPoints[ 1 ].Set( segmentEnd.x, segmentEnd.y,
|
||||
MAX( segmentEnd.z, 2.0f + TheTerrainLogic->getGroundHeight(segmentEnd.x, segmentEnd.y) ) );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//No arc -- way simpler!
|
||||
laserPoints[ 0 ].Set( update->getStartPos()->x, update->getStartPos()->y, update->getStartPos()->z );
|
||||
laserPoints[ 1 ].Set( update->getEndPos()->x, update->getEndPos()->y, update->getEndPos()->z );
|
||||
}
|
||||
|
||||
//Get the color components for calculation purposes.
|
||||
Real innerRed, innerGreen, innerBlue, innerAlpha, outerRed, outerGreen, outerBlue, outerAlpha;
|
||||
GameGetColorComponentsReal( data->m_innerColor, &innerRed, &innerGreen, &innerBlue, &innerAlpha );
|
||||
GameGetColorComponentsReal( data->m_outerColor, &outerRed, &outerGreen, &outerBlue, &outerAlpha );
|
||||
|
||||
for( Int i = data->m_numBeams - 1; i >= 0; i-- )
|
||||
{
|
||||
|
||||
Real alpha, width;
|
||||
int index = segment * data->m_numBeams + i;
|
||||
|
||||
if( data->m_numBeams == 1 )
|
||||
{
|
||||
width = data->m_innerBeamWidth * update->getWidthScale();
|
||||
alpha = innerAlpha;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Calculate the scale between min and max values
|
||||
//0 means use min value, 1 means use max value
|
||||
//0.2 means min value + 20% of the diff between min and max
|
||||
Real scale = i / ( data->m_numBeams - 1.0f);
|
||||
Real ultimateScale = update->getWidthScale();
|
||||
width = (data->m_innerBeamWidth + scale * (data->m_outerBeamWidth - data->m_innerBeamWidth));
|
||||
width *= ultimateScale;
|
||||
alpha = innerAlpha + scale * (outerAlpha - innerAlpha);
|
||||
}
|
||||
|
||||
|
||||
//Calculate the number of times to tile the line based on the height of the texture used.
|
||||
if( m_texture && data->m_tile )
|
||||
{
|
||||
//Calculate the length of the line.
|
||||
Vector3 lineVector;
|
||||
Vector3::Subtract( laserPoints[1], laserPoints[0], &lineVector );
|
||||
Real length = lineVector.Length();
|
||||
|
||||
//Adjust tile factor so texture is NOT stretched but tiled equally in both width and length.
|
||||
Real tileFactor = length/width*m_textureAspectRatio*data->m_tilingScalar;
|
||||
|
||||
//Set the tile factor
|
||||
m_line3D[ index ]->Set_Texture_Tile_Factor( tileFactor ); //number of times to tile texture across each segment
|
||||
}
|
||||
|
||||
m_line3D[ index ]->Set_Width( width );
|
||||
m_line3D[ index ]->Set_Points( 2, &laserPoints[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DLaserDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DLaserDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
const XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// Kris says there is no data to save for these, go ask him.
|
||||
// m_selfDirty is not saved, is runtime only
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DLaserDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
m_selfDirty = true; // so we update the first time after reload
|
||||
|
||||
} // end loadPostProcess
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FILE: W3DOverlordAircraftDraw.h
|
||||
// Author: Mark Lorenzen, April 2003
|
||||
// Desc: Units that recieve portable structure upgrades (like the OverlordTnk) have a super specific special need.
|
||||
// He needs his rider to draw explicitly after him,
|
||||
// and he needs direct access to get that rider when everyone else can't see it because of the OverlordContain.
|
||||
// In the case of aircraft (Helix, SpectreGunship, etc.) we need this draw module which mimics the OverlordTnkDraw
|
||||
// but does not draw treads, trackmarks, turrets, etc. Whee!
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameLogic/Module/ContainModule.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DOverlordAircraftDraw.h"
|
||||
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordAircraftDrawModuleData::W3DOverlordAircraftDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordAircraftDrawModuleData::~W3DOverlordAircraftDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordAircraftDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordAircraftDraw::W3DOverlordAircraftDraw( Thing *thing, const ModuleData* moduleData )
|
||||
: W3DModelDraw( thing, moduleData )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordAircraftDraw::~W3DOverlordAircraftDraw()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordAircraftDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
W3DModelDraw::doDrawModule(transformMtx);
|
||||
|
||||
// Our big thing is that we get our specific passenger (the turret thing) and then wake it up and make it draw
|
||||
// It depends on us because our renderObject is only made correct in the act of drawing.
|
||||
Object *me = getDrawable()->getObject();
|
||||
if( me
|
||||
&& me->getContain()
|
||||
&& me->getContain()->friend_getRider()
|
||||
&& me->getContain()->friend_getRider()->getDrawable()
|
||||
)
|
||||
{
|
||||
Drawable *riderDraw = me->getContain()->friend_getRider()->getDrawable();
|
||||
if ( riderDraw )
|
||||
{
|
||||
TintEnvelope *env = getDrawable()->getColorTintEnvelope();
|
||||
if ( env )
|
||||
riderDraw->setColorTintEnvelope( *env );
|
||||
|
||||
riderDraw->notifyDrawableDependencyCleared();
|
||||
riderDraw->draw( NULL );// What the hell? This param isn't used for anything
|
||||
}
|
||||
DEBUG_ASSERTCRASH( riderDraw, ("OverlordAircraftDraw finds no rider's drawable") );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordAircraftDraw::setHidden(Bool h)
|
||||
{
|
||||
W3DModelDraw::setHidden(h);
|
||||
|
||||
// We need to hide our rider, since he won't realize he's being contained in a contained container
|
||||
Object *me = getDrawable()->getObject();
|
||||
if( me
|
||||
&& me->getContain()
|
||||
&& me->getContain()->friend_getRider()
|
||||
&& me->getContain()->friend_getRider()->getDrawable()
|
||||
)
|
||||
{
|
||||
me->getContain()->friend_getRider()->getDrawable()->setDrawableHidden(h);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordAircraftDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordAircraftDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordAircraftDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FIEL: W3DOverlordTankDraw.cpp ////////////////////////////////////////////////////////////////////////////
|
||||
// Author: Graham Smallwood, October 2002
|
||||
// Desc: The Overlord has a super specific special need. He needs his rider to draw explicitly after him,
|
||||
// and he needs direct access to get that rider when everyone else can't see it because of the OverlordContain.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameLogic/Module/ContainModule.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DOverlordTankDraw.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTankDrawModuleData::W3DOverlordTankDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTankDrawModuleData::~W3DOverlordTankDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTankDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DTankDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTankDraw::W3DOverlordTankDraw( Thing *thing, const ModuleData* moduleData )
|
||||
: W3DTankDraw( thing, moduleData )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTankDraw::~W3DOverlordTankDraw()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTankDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
W3DTankDraw::doDrawModule(transformMtx);
|
||||
|
||||
// Our big thing is that we get our specific passenger (the turret thing) and then wake it up and make it draw
|
||||
// It depends on us because our renderObject is only made correct in the act of drawing.
|
||||
Object *me = getDrawable()->getObject();
|
||||
if( me
|
||||
&& me->getContain()
|
||||
&& me->getContain()->friend_getRider()
|
||||
&& me->getContain()->friend_getRider()->getDrawable()
|
||||
)
|
||||
{
|
||||
Drawable *riderDraw = me->getContain()->friend_getRider()->getDrawable();
|
||||
riderDraw->setColorTintEnvelope( *getDrawable()->getColorTintEnvelope() );
|
||||
|
||||
riderDraw->notifyDrawableDependencyCleared();
|
||||
riderDraw->draw( NULL );// What the hell? This param isn't used for anything
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTankDraw::setHidden(Bool h)
|
||||
{
|
||||
W3DTankDraw::setHidden(h);
|
||||
|
||||
// We need to hide our rider, since he won't realize he's being contained in a contained container
|
||||
Object *me = getDrawable()->getObject();
|
||||
if( me
|
||||
&& me->getContain()
|
||||
&& me->getContain()->friend_getRider()
|
||||
&& me->getContain()->friend_getRider()->getDrawable()
|
||||
)
|
||||
{
|
||||
me->getContain()->friend_getRider()->getDrawable()->setDrawableHidden(h);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTankDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DTankDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTankDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DTankDraw::xfer( xfer );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTankDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DTankDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FIEL: W3DOverlordTruckDraw.cpp ////////////////////////////////////////////////////////////////////////////
|
||||
// Author: Graham Smallwood, October 2002
|
||||
// Desc: The Overlord has a super specific special need. He needs his rider to draw explicitly after him,
|
||||
// and he needs direct access to get that rider when everyone else can't see it because of the OverlordContain.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameLogic/Module/ContainModule.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DOverlordTruckDraw.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTruckDrawModuleData::W3DOverlordTruckDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTruckDrawModuleData::~W3DOverlordTruckDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTruckDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DTruckDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTruckDraw::W3DOverlordTruckDraw( Thing *thing, const ModuleData* moduleData )
|
||||
: W3DTruckDraw( thing, moduleData )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DOverlordTruckDraw::~W3DOverlordTruckDraw()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTruckDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
W3DTruckDraw::doDrawModule(transformMtx);
|
||||
|
||||
// Our big thing is that we get our specific passenger (the turret thing) and then wake it up and make it draw
|
||||
// It depends on us because our renderObject is only made correct in the act of drawing.
|
||||
Object *me = getDrawable()->getObject();
|
||||
if( me
|
||||
&& me->getContain()
|
||||
&& me->getContain()->friend_getRider()
|
||||
&& me->getContain()->friend_getRider()->getDrawable()
|
||||
)
|
||||
{
|
||||
Drawable *riderDraw = me->getContain()->friend_getRider()->getDrawable();
|
||||
riderDraw->setColorTintEnvelope( *getDrawable()->getColorTintEnvelope() );
|
||||
|
||||
riderDraw->notifyDrawableDependencyCleared();
|
||||
riderDraw->draw( NULL );// What the hell? This param isn't used for anything
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTruckDraw::setHidden(Bool h)
|
||||
{
|
||||
W3DTruckDraw::setHidden(h);
|
||||
|
||||
// We need to hide our rider, since he won't realize he's being contained in a contained container
|
||||
Object *me = getDrawable()->getObject();
|
||||
if( me
|
||||
&& me->getContain()
|
||||
&& me->getContain()->friend_getRider()
|
||||
&& me->getContain()->friend_getRider()->getDrawable()
|
||||
)
|
||||
{
|
||||
me->getContain()->friend_getRider()->getDrawable()->setDrawableHidden(h);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTruckDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DTruckDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTruckDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DTruckDraw::xfer( xfer );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DOverlordTruckDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DTruckDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DPoliceCarDraw.cpp /////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, May 2001
|
||||
// Desc: W3DPoliceCarDraw
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
#include "Common/STLTypedefs.h"
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DPoliceCarDraw.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "common/RandomValue.h"
|
||||
#include "WW3D2/HAnim.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Create a dynamic light for the search light */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDynamicLight *W3DPoliceCarDraw::createDynamicLight( void )
|
||||
{
|
||||
W3DDynamicLight *light = NULL;
|
||||
|
||||
// get me a dynamic light from the scene
|
||||
light = W3DDisplay::m_3DScene->getADynamicLight();
|
||||
if( light )
|
||||
{
|
||||
|
||||
light->setEnabled( TRUE );
|
||||
light->Set_Ambient( Vector3( 0.0f, 0.0f, 0.0f ) );
|
||||
// Use all ambient, and no diffuse. This produces a circle of light on
|
||||
// even and uneven ground. Diffuse lighting shows up ground unevenness, which looks
|
||||
// funny on a searchlight. So no diffuse. jba.
|
||||
light->Set_Diffuse( Vector3( 0.0f, 0.0f, 0.0f ) );
|
||||
light->Set_Position( Vector3( 0.0f, 0.0f, 0.0f ) );
|
||||
light->Set_Far_Attenuation_Range( 5, 15 );
|
||||
|
||||
} // end if
|
||||
|
||||
return light;
|
||||
|
||||
} // end createDynamicSearchLight
|
||||
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DPoliceCarDraw::W3DPoliceCarDraw( Thing *thing, const ModuleData* moduleData ) : W3DTruckDraw( thing, moduleData )
|
||||
{
|
||||
m_light = NULL;
|
||||
m_curFrame = GameClientRandomValueReal(0, 10 );
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DPoliceCarDraw::~W3DPoliceCarDraw( void )
|
||||
{
|
||||
|
||||
// disable the light ... the scene will re-use it later
|
||||
if( m_light )
|
||||
{
|
||||
// Have it fade out over 5 frames.
|
||||
m_light->setFrameFade(0, 5);
|
||||
m_light->setDecayRange();
|
||||
m_light->setDecayColor();
|
||||
m_light = NULL;
|
||||
} // end if
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DPoliceCarDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
const Real floatAmt = 8.0f;
|
||||
const Real animAmt = 0.25;
|
||||
|
||||
// get pointers to our render objects that we'll need
|
||||
RenderObjClass* policeCarRenderObj = getRenderObject();
|
||||
if( policeCarRenderObj == NULL )
|
||||
return;
|
||||
|
||||
HAnimClass *anim = policeCarRenderObj->Peek_Animation();
|
||||
if (anim)
|
||||
{
|
||||
Real frames = anim->Get_Num_Frames();
|
||||
m_curFrame += animAmt;
|
||||
if (m_curFrame > frames-1) {
|
||||
m_curFrame = 0;
|
||||
}
|
||||
policeCarRenderObj->Set_Animation(anim, m_curFrame);
|
||||
}
|
||||
Real red = 0;
|
||||
Real green = 0;
|
||||
Real blue = 0;
|
||||
if (m_curFrame < 3) {
|
||||
red = 1; green = 0.5;
|
||||
} else if (m_curFrame < 6) {
|
||||
red = 1;
|
||||
} else if (m_curFrame < 7) {
|
||||
red = 1; green = 0.5;
|
||||
} else if (m_curFrame < 9) {
|
||||
red = 0.5+(9-m_curFrame)/4;
|
||||
blue = (m_curFrame-5)/6;
|
||||
} else if (m_curFrame < 12) {
|
||||
blue=1;
|
||||
} else if (m_curFrame <= 14) {
|
||||
green = (m_curFrame-11)/3;
|
||||
blue = (14-m_curFrame)/2;
|
||||
red = (m_curFrame-11)/3;
|
||||
}
|
||||
|
||||
// make us a light if we don't already have one
|
||||
if( m_light == NULL )
|
||||
m_light = createDynamicLight();
|
||||
|
||||
|
||||
// if we have a search light, position it
|
||||
if( m_light )
|
||||
{
|
||||
Coord3D pos = *getDrawable()->getPosition();
|
||||
m_light->Set_Diffuse( Vector3( red, green, blue) );
|
||||
m_light->Set_Ambient( Vector3( red/2, green/2, blue/2) );
|
||||
m_light->Set_Far_Attenuation_Range( 3, 20 );
|
||||
m_light->Set_Position( Vector3( pos.x,pos.y,pos.z+floatAmt ) );
|
||||
}
|
||||
W3DTruckDraw::doDrawModule(transformMtx);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPoliceCarDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DTruckDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPoliceCarDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DTruckDraw::xfer( xfer );
|
||||
|
||||
// John A says there is no data for these to save
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPoliceCarDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DTruckDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DProjectileStreamDraw.cpp ////////////////////////////////////////////////////////////
|
||||
// Tile a texture strung between Projectiles
|
||||
// Graham Smallwood, May 2002
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DProjectileStreamDraw.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "WW3D2/AssetMgr.h"
|
||||
#include "WW3D2/Segline.h"
|
||||
#include "WWMath/Vector3.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DProjectileStreamDrawModuleData::W3DProjectileStreamDrawModuleData()
|
||||
{
|
||||
m_textureName = "";
|
||||
m_width = 0.0f;
|
||||
m_tileFactor = 0.0f;
|
||||
m_scrollRate = 0.0f;
|
||||
m_maxSegments = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DProjectileStreamDrawModuleData::~W3DProjectileStreamDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DProjectileStreamDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
ModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "Texture", INI::parseAsciiString, NULL, offsetof(W3DProjectileStreamDrawModuleData, m_textureName) },
|
||||
{ "Width", INI::parseReal, NULL, offsetof(W3DProjectileStreamDrawModuleData, m_width) },
|
||||
{ "TileFactor", INI::parseReal, NULL, offsetof(W3DProjectileStreamDrawModuleData, m_tileFactor) },
|
||||
{ "ScrollRate", INI::parseReal, NULL, offsetof(W3DProjectileStreamDrawModuleData, m_scrollRate) },
|
||||
{ "MaxSegments", INI::parseInt, NULL, offsetof(W3DProjectileStreamDrawModuleData, m_maxSegments) },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DProjectileStreamDraw::~W3DProjectileStreamDraw()
|
||||
{
|
||||
for( Int lineIndex = 0; lineIndex < m_linesValid; lineIndex++ )
|
||||
{
|
||||
SegmentedLineClass *deadLine = m_allLines[lineIndex];
|
||||
if (deadLine)
|
||||
{ if (deadLine->Peek_Scene())
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( deadLine );
|
||||
REF_PTR_RELEASE( deadLine );
|
||||
}
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE( m_texture );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DProjectileStreamDraw::W3DProjectileStreamDraw( Thing *thing, const ModuleData* moduleData ) : DrawModule( thing, moduleData )
|
||||
{
|
||||
const W3DProjectileStreamDrawModuleData* d = getW3DProjectileStreamDrawModuleData();
|
||||
m_texture = WW3DAssetManager::Get_Instance()->Get_Texture( d->m_textureName.str() );
|
||||
for( Int index = 0; index < MAX_PROJECTILE_STREAM; index++ )
|
||||
m_allLines[index] = NULL;
|
||||
m_linesValid = 0;
|
||||
}
|
||||
|
||||
void W3DProjectileStreamDraw::setFullyObscuredByShroud(Bool fullyObscured)
|
||||
{
|
||||
if (fullyObscured)
|
||||
{ //we need to remove all our lines from the scene because they are hidden
|
||||
for( Int lineIndex = 0; lineIndex < m_linesValid; lineIndex++ )
|
||||
{
|
||||
SegmentedLineClass *deadLine = m_allLines[lineIndex];
|
||||
if (deadLine && deadLine->Peek_Scene())
|
||||
deadLine->Remove();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //we need to restore lines into scene
|
||||
for( Int lineIndex = 0; lineIndex < m_linesValid; lineIndex++ )
|
||||
{
|
||||
SegmentedLineClass *deadLine = m_allLines[lineIndex];
|
||||
if (deadLine && !deadLine->Peek_Scene())
|
||||
W3DDisplay::m_3DScene->Add_Render_Object(deadLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Map behavior states into W3D animations. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DProjectileStreamDraw::doDrawModule(const Matrix3D* )
|
||||
{
|
||||
// get object from logic
|
||||
Object *me = getDrawable()->getObject();
|
||||
if (me == NULL)
|
||||
return;
|
||||
|
||||
static NameKeyType key_ProjectileStreamUpdate = NAMEKEY("ProjectileStreamUpdate");
|
||||
ProjectileStreamUpdate* update = (ProjectileStreamUpdate*)me->findUpdateModule(key_ProjectileStreamUpdate);
|
||||
|
||||
const W3DProjectileStreamDrawModuleData *data = getW3DProjectileStreamDrawModuleData();
|
||||
|
||||
Vector3 allPoints[MAX_PROJECTILE_STREAM];
|
||||
Int pointsUsed;
|
||||
|
||||
update->getAllPoints( allPoints, &pointsUsed );
|
||||
|
||||
Vector3 stagingPoints[MAX_PROJECTILE_STREAM];
|
||||
Vector3 zeroVector(0, 0, 0);
|
||||
|
||||
Int linesMade = 0;
|
||||
Int currentMasterPoint = 0;
|
||||
UnsignedInt currentStagingPoint = 0;
|
||||
|
||||
if( data->m_maxSegments )
|
||||
{
|
||||
// If I have a drawing cap, I need to increase the start point in the array. The furthest (oldest)
|
||||
// point from the tank is in spot zero.
|
||||
currentMasterPoint = pointsUsed - data->m_maxSegments;
|
||||
currentMasterPoint = max( 0, currentMasterPoint ); // (but if they say to draw more than exists, draw all)
|
||||
}
|
||||
|
||||
// Okay. I have an array of ordered points that may have blanks in it. I need to copy to the staging area
|
||||
// until I hit a blank or the end. Then if I have a line made, I'll overwrite it, otherwise I'll make a new one.
|
||||
// I'll keep doing this until I run out of valid points.
|
||||
while( currentMasterPoint < pointsUsed )
|
||||
{
|
||||
while( currentMasterPoint < pointsUsed && allPoints[currentMasterPoint] != zeroVector )
|
||||
{
|
||||
// While I am not looking at a bad point (off edge or zero)
|
||||
stagingPoints[currentStagingPoint] = allPoints[currentMasterPoint];// copy to the staging
|
||||
currentStagingPoint++;// increment how many I have
|
||||
currentMasterPoint++;// increment what I am looking at
|
||||
}
|
||||
// Use or reuse a line
|
||||
if( currentStagingPoint > 1 )
|
||||
{
|
||||
// Don't waste a line on a double hole (0) or a one point line (1)
|
||||
makeOrUpdateLine( stagingPoints, currentStagingPoint, linesMade );
|
||||
linesMade++;// keep track of how many are real this frame
|
||||
}
|
||||
currentMasterPoint++;//I am either pointed off the edge anyway, or I am pointed at a zero I want to skip
|
||||
currentStagingPoint = 0;//start over in the staging area
|
||||
}
|
||||
|
||||
Int oldLinesValid = m_linesValid;
|
||||
for( Int lineIndex = linesMade; lineIndex < oldLinesValid; lineIndex++ )
|
||||
{
|
||||
// Delete any line we aren't using anymore.
|
||||
SegmentedLineClass *deadLine = m_allLines[lineIndex];
|
||||
if (deadLine->Peek_Scene())
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( deadLine );
|
||||
REF_PTR_RELEASE( deadLine );
|
||||
|
||||
m_allLines[lineIndex] = NULL;
|
||||
m_linesValid--;
|
||||
}
|
||||
}
|
||||
|
||||
void W3DProjectileStreamDraw::makeOrUpdateLine( Vector3 *points, UnsignedInt pointCount, Int lineIndex )
|
||||
{
|
||||
Bool newLine = FALSE;
|
||||
|
||||
if( m_allLines[lineIndex] == NULL )
|
||||
{
|
||||
//Need a new one if this is blank, otherwise I'll reset the existing one
|
||||
m_allLines[lineIndex] = NEW SegmentedLineClass;
|
||||
m_linesValid++;
|
||||
newLine = TRUE;
|
||||
}
|
||||
|
||||
SegmentedLineClass *line = m_allLines[lineIndex];
|
||||
|
||||
line->Set_Points(pointCount, points); //tell the line which points to use
|
||||
|
||||
if( newLine )
|
||||
{
|
||||
// This is one time stuff we only need to do if this is a new and not a change
|
||||
const W3DProjectileStreamDrawModuleData *data = getW3DProjectileStreamDrawModuleData();
|
||||
line->Set_Texture(m_texture); //set the texture
|
||||
line->Set_Shader(ShaderClass::_PresetAdditiveSpriteShader); //pick the alpha blending mode you want - see shader.h for others.
|
||||
line->Set_Width(data->m_width); //set line width in world units
|
||||
line->Set_Texture_Mapping_Mode(SegLineRendererClass::TILED_TEXTURE_MAP); //this tiles the texture across the line
|
||||
line->Set_Texture_Tile_Factor(data->m_tileFactor); //number of times to tile texture across each segment
|
||||
line->Set_UV_Offset_Rate(Vector2(0.0f,data->m_scrollRate)); //amount to scroll texture on each draw
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( line); //add it to our scene so it gets rendered with other objects.
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DProjectileStreamDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DProjectileStreamDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// Graham says there is no data that needs saving here
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DProjectileStreamDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DPropDraw.cpp ////////////////////////////////////////////////////////////////////////
|
||||
// Author: John Ahlquist, June 2--3
|
||||
// Desc: Simple prop drawing code.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DPropDraw.h"
|
||||
#include "W3DDevice/GameClient/BaseHeightMap.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DPropDrawModuleData::W3DPropDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DPropDrawModuleData::~W3DPropDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DPropDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
ModuleData::buildFieldParse(p);
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "ModelName", INI::parseAsciiString, NULL, offsetof(W3DPropDrawModuleData, m_modelName) },
|
||||
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DPropDraw::W3DPropDraw( Thing *thing, const ModuleData* moduleData ) : DrawModule( thing, moduleData ),
|
||||
m_propAdded(false)
|
||||
{
|
||||
|
||||
} // end W3DPropDraw
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DPropDraw::~W3DPropDraw( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DPropDraw::reactToTransformChange( const Matrix3D *oldMtx,
|
||||
const Coord3D *oldPos,
|
||||
Real oldAngle )
|
||||
{
|
||||
Drawable *draw = getDrawable();
|
||||
if (m_propAdded) {
|
||||
return;
|
||||
}
|
||||
if (draw->getPosition()->x==0.0f && draw->getPosition()->y == 0.0f) {
|
||||
return;
|
||||
}
|
||||
m_propAdded = true;
|
||||
const W3DPropDrawModuleData *moduleData = getW3DPropDrawModuleData();
|
||||
if (!moduleData) {
|
||||
return;
|
||||
}
|
||||
Real scale = draw->getScale();
|
||||
TheTerrainRenderObject->addProp((Int)draw->getID(), *draw->getPosition(),
|
||||
draw->getOrientation(), scale, moduleData->m_modelName);
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DPropDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPropDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPropDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// no data to save here, nobody will ever notice
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPropDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DRopeDraw.cpp ////////////////////////////////////////////////////////////////////////
|
||||
// Author: Steven Johnson, Aug 2002
|
||||
// Desc: Rope drawing
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/ClientRandomValue.h"
|
||||
#include "GameClient/Color.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DRopeDraw.h"
|
||||
#include "WW3D2/Line3D.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "Common/GameState.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DRopeDraw::W3DRopeDraw( Thing *thing, const ModuleData* moduleData ) : DrawModule( thing, moduleData )
|
||||
{
|
||||
m_curLen = 0.0f;
|
||||
m_maxLen = 1.0f;
|
||||
m_width = 0.5f;
|
||||
m_color.red = 0.0f;
|
||||
m_color.green = 0.0f;
|
||||
m_color.blue = 0.0f;
|
||||
m_curSpeed = 0.0f;
|
||||
m_maxSpeed = 0.0f;
|
||||
m_accel = 0.0f;
|
||||
m_wobbleLen = m_maxLen; // huge
|
||||
m_wobbleAmp = 0.0f;
|
||||
m_segments.clear();
|
||||
m_curWobblePhase = 0.0f;
|
||||
m_curZOffset = 0.0f;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::buildSegments()
|
||||
{
|
||||
DEBUG_ASSERTCRASH(m_segments.empty(), ("Hmmn, not empty"));
|
||||
m_segments.clear();
|
||||
|
||||
Int numSegs = ceil(m_maxLen / m_wobbleLen);
|
||||
Real eachLen = m_maxLen / (Real)numSegs;
|
||||
Coord3D pos = *getDrawable()->getPosition();
|
||||
for (int i = 0; i < numSegs; ++i, pos.z += eachLen)
|
||||
{
|
||||
SegInfo info;
|
||||
|
||||
Real axis = GameClientRandomValueReal(0, 2*PI);
|
||||
info.wobbleAxisX = Cos(axis);
|
||||
info.wobbleAxisY = Sin(axis);
|
||||
info.line = NEW Line3DClass( Vector3(pos.x,pos.y,pos.z),
|
||||
Vector3(pos.x,pos.y,pos.z+eachLen),
|
||||
m_width * 0.5f, // width
|
||||
m_color.red, // red
|
||||
m_color.green, // green
|
||||
m_color.blue, // blue
|
||||
1.0f ); // transparency
|
||||
|
||||
info.softLine = NEW Line3DClass( Vector3(pos.x,pos.y,pos.z),
|
||||
Vector3(pos.x,pos.y,pos.z+eachLen),
|
||||
m_width, // width
|
||||
m_color.red, // red
|
||||
m_color.green, // green
|
||||
m_color.blue, // blue
|
||||
0.5f ); // transparency
|
||||
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( info.line );
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( info.softLine );
|
||||
m_segments.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::tossSegments()
|
||||
{
|
||||
// remove tracer from the scene and delete
|
||||
for (std::vector<SegInfo>::iterator it = m_segments.begin(); it != m_segments.end(); ++it)
|
||||
{
|
||||
if (it->line)
|
||||
{
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object(it->line);
|
||||
REF_PTR_RELEASE((it->line));
|
||||
}
|
||||
if (it->softLine)
|
||||
{
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object(it->softLine);
|
||||
REF_PTR_RELEASE((it->softLine));
|
||||
}
|
||||
}
|
||||
m_segments.clear();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::initRopeParms(Real length, Real width, const RGBColor& color, Real wobbleLen, Real wobbleAmp, Real wobbleRate)
|
||||
{
|
||||
m_maxLen = max(1.0f, length);
|
||||
m_curLen = 0.0f;
|
||||
m_width = width;
|
||||
m_color = color;
|
||||
m_wobbleLen = min(m_maxLen, wobbleLen);
|
||||
m_wobbleAmp = wobbleAmp;
|
||||
m_wobbleRate = wobbleRate;
|
||||
m_curZOffset = 0.0f;
|
||||
|
||||
tossSegments();
|
||||
buildSegments();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::setRopeCurLen(Real length)
|
||||
{
|
||||
m_curLen = length;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::setRopeSpeed(Real curSpeed, Real maxSpeed, Real accel)
|
||||
{
|
||||
m_curSpeed = curSpeed;
|
||||
m_maxSpeed = maxSpeed;
|
||||
m_accel = accel;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DRopeDraw::~W3DRopeDraw()
|
||||
{
|
||||
tossSegments();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
if (m_segments.empty())
|
||||
{
|
||||
buildSegments();
|
||||
}
|
||||
|
||||
if (!m_segments.empty())
|
||||
{
|
||||
Real deflection = Sin(m_curWobblePhase) * m_wobbleAmp;
|
||||
const Coord3D* pos = getDrawable()->getPosition();
|
||||
Vector3 start(pos->x, pos->y, pos->z + m_curZOffset);
|
||||
Real eachLen = m_curLen / m_segments.size();
|
||||
for (std::vector<SegInfo>::iterator it = m_segments.begin(); it != m_segments.end(); ++it)
|
||||
{
|
||||
Vector3 end(pos->x + deflection*it->wobbleAxisX, pos->y + deflection*it->wobbleAxisY, start.Z - eachLen);
|
||||
if (it->line)
|
||||
(it->line)->Reset(start, end);
|
||||
if (it->softLine)
|
||||
(it->softLine)->Reset(start, end);
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
|
||||
m_curWobblePhase += m_wobbleRate;
|
||||
if (m_curWobblePhase > 2*PI)
|
||||
m_curWobblePhase -= 2*PI;
|
||||
|
||||
m_curZOffset += m_curSpeed;
|
||||
m_curSpeed += m_accel;
|
||||
if (m_curSpeed > m_maxSpeed)
|
||||
m_curSpeed = m_maxSpeed;
|
||||
else if (m_curSpeed < -m_maxSpeed)
|
||||
m_curSpeed = -m_maxSpeed;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
const XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// m_segments is not saved
|
||||
|
||||
// cur len
|
||||
xfer->xferReal( &m_curLen );
|
||||
|
||||
// max len
|
||||
xfer->xferReal( &m_maxLen );
|
||||
|
||||
// width
|
||||
xfer->xferReal( &m_width );
|
||||
|
||||
// color
|
||||
xfer->xferRGBColor( &m_color );
|
||||
|
||||
// cur speed
|
||||
xfer->xferReal( &m_curSpeed );
|
||||
|
||||
// max speed
|
||||
xfer->xferReal( &m_maxSpeed );
|
||||
|
||||
// acceleration
|
||||
xfer->xferReal( &m_accel );
|
||||
|
||||
// wobble len
|
||||
xfer->xferReal( &m_wobbleLen );
|
||||
|
||||
// wobble amp
|
||||
xfer->xferReal( &m_wobbleAmp );
|
||||
|
||||
// wobble rate
|
||||
xfer->xferReal( &m_wobbleRate );
|
||||
|
||||
// current wobble phase
|
||||
xfer->xferReal( &m_curWobblePhase );
|
||||
|
||||
// cur Z offset
|
||||
xfer->xferReal( &m_curZOffset );
|
||||
|
||||
if (xfer->getXferMode() == XFER_LOAD)
|
||||
tossSegments();
|
||||
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DRopeDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DScienceModelDraw.cpp ////////////////////////////////////////////////////////////////////////////
|
||||
// Author: Graham Smallwood, NOVEMBER 2002
|
||||
// Desc: Draw module just like Model, except it only draws if the local player has the specified science
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "W3DDevice/GameClient/Module/W3DScienceModelDraw.h"
|
||||
|
||||
#include "Common/Player.h"
|
||||
#include "Common/PlayerList.h"
|
||||
#include "Common/Science.h"
|
||||
#include "Common/Xfer.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DScienceModelDrawModuleData::W3DScienceModelDrawModuleData()
|
||||
{
|
||||
m_requiredScience = SCIENCE_INVALID;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DScienceModelDrawModuleData::~W3DScienceModelDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DScienceModelDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "RequiredScience", INI::parseScience, NULL, offsetof(W3DScienceModelDrawModuleData, m_requiredScience) },
|
||||
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DScienceModelDraw::W3DScienceModelDraw( Thing *thing, const ModuleData* moduleData ) : W3DModelDraw( thing, moduleData )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DScienceModelDraw::~W3DScienceModelDraw()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// All this does is stop the call path if we haven't been cleared to draw yet
|
||||
void W3DScienceModelDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
ScienceType science = getW3DScienceModelDrawModuleData()->m_requiredScience;
|
||||
if( science == SCIENCE_INVALID )
|
||||
{
|
||||
DEBUG_ASSERTCRASH(science != SCIENCE_INVALID, ("ScienceModelDraw has invalid science as condition.") );
|
||||
setHidden( TRUE );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !ThePlayerList->getLocalPlayer()->hasScience(science)
|
||||
&& ThePlayerList->getLocalPlayer()->isPlayerActive()
|
||||
)
|
||||
{
|
||||
// We just don't draw for people without our science except for Observers
|
||||
setHidden( TRUE );
|
||||
return;
|
||||
}
|
||||
|
||||
W3DModelDraw::doDrawModule(transformMtx);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DScienceModelDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DScienceModelDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DScienceModelDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DSupplyDraw.cpp ////////////////////////////////////////////////////////////////////////////
|
||||
// Author: Graham Smallwood, September 2002
|
||||
// Desc: Draw module reacts to SupplyStatus setting by hiding an equal number of the specified bone array.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DSupplyDraw.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DSupplyDrawModuleData::W3DSupplyDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DSupplyDrawModuleData::~W3DSupplyDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DSupplyDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "SupplyBonePrefix", INI::parseAsciiString, NULL, offsetof(W3DSupplyDrawModuleData, m_supplyBonePrefix) },
|
||||
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DSupplyDraw::W3DSupplyDraw( Thing *thing, const ModuleData* moduleData ) : W3DModelDraw( thing, moduleData )
|
||||
{
|
||||
m_totalBones = -1;
|
||||
m_lastNumberShown = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DSupplyDraw::~W3DSupplyDraw()
|
||||
{
|
||||
}
|
||||
|
||||
void W3DSupplyDraw::updateDrawModuleSupplyStatus( Int maxSupply, Int currentSupply )
|
||||
{
|
||||
W3DModelDraw::updateDrawModuleSupplyStatus( maxSupply, currentSupply );
|
||||
|
||||
AsciiString boneName = getW3DSupplyDrawModuleData()->m_supplyBonePrefix;
|
||||
if( m_totalBones == -1 )
|
||||
{
|
||||
m_totalBones = getDrawable()->getPristineBonePositions( boneName.str(), 1, NULL, NULL, INT_MAX );// The last arg is to guard the size of the arrays. I am not passing any in, I am just counting bones.
|
||||
m_lastNumberShown = m_totalBones;
|
||||
}
|
||||
|
||||
// Figure the % of our bones we should show, and if it is a different % than last time
|
||||
// start showing and hiding them.
|
||||
Int bonesToShow = ceil(m_totalBones * ( currentSupply / (float)maxSupply ));
|
||||
bonesToShow = min( bonesToShow, m_totalBones );
|
||||
|
||||
if( bonesToShow != m_lastNumberShown )
|
||||
{
|
||||
// Show/hide the bones that are now different, the indices between last and now (low, high].
|
||||
Int lowIndex = min( m_lastNumberShown, bonesToShow );
|
||||
Int highIndex = max( m_lastNumberShown, bonesToShow );
|
||||
Bool hide = bonesToShow < m_lastNumberShown;
|
||||
Int currentIndex = lowIndex + 1;
|
||||
|
||||
std::vector<ModelConditionInfo::HideShowSubObjInfo> boneVector;
|
||||
while( currentIndex <= highIndex )
|
||||
{
|
||||
char buffer[16];
|
||||
sprintf( buffer, "%s%02d", boneName.str(), currentIndex );
|
||||
ModelConditionInfo::HideShowSubObjInfo info;
|
||||
info.hide = hide;
|
||||
info.subObjName = buffer;
|
||||
boneVector.push_back(info);
|
||||
|
||||
++currentIndex;
|
||||
}
|
||||
doHideShowSubObjs(&boneVector);
|
||||
|
||||
m_lastNumberShown = bonesToShow;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DSupplyDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DSupplyDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
// Graham says there's no data to save here
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DSupplyDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
|
||||
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTankDraw.cpp //////////////////////////////////////////////////////////////////////////
|
||||
// Draw turreted tanks
|
||||
// Michael S. Booth, October 2001
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingFactory.h"
|
||||
#include "Common/GameAudio.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameLogic/Weapon.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "GameLogic/Module/PhysicsUpdate.h"
|
||||
#include "GameLogic/Module/BodyModule.h"
|
||||
#include "GameLogic/ScriptEngine.h"
|
||||
#include "GameLogic/Module/AIUpdate.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/ParticleSys.h"
|
||||
#include "W3DDevice/GameClient/W3DGameClient.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTankDraw.h"
|
||||
#include "WW3D2/matinfo.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
class Matrix3D;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankDrawModuleData::W3DTankDrawModuleData() :
|
||||
m_treadDebrisNameLeft("TrackDebrisDirtLeft"),
|
||||
m_treadDebrisNameRight("TrackDebrisDirtRight"),
|
||||
m_treadAnimationRate(0.0f),
|
||||
m_treadPivotSpeedFraction(0.6f),
|
||||
m_treadDriveSpeedFraction(0.3f)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankDrawModuleData::~W3DTankDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "TreadDebrisLeft", INI::parseAsciiString, NULL, offsetof(W3DTankDrawModuleData, m_treadDebrisNameLeft) },
|
||||
{ "TreadDebrisRight", INI::parseAsciiString, NULL, offsetof(W3DTankDrawModuleData, m_treadDebrisNameRight) },
|
||||
{ "TreadAnimationRate", INI::parseVelocityReal, NULL, offsetof(W3DTankDrawModuleData, m_treadAnimationRate) },
|
||||
{ "TreadPivotSpeedFraction", INI::parseReal, NULL, offsetof(W3DTankDrawModuleData, m_treadPivotSpeedFraction) },
|
||||
{ "TreadDriveSpeedFraction", INI::parseReal, NULL, offsetof(W3DTankDrawModuleData, m_treadDriveSpeedFraction) },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankDraw::W3DTankDraw( Thing *thing, const ModuleData* moduleData )
|
||||
: W3DModelDraw( thing, moduleData ),m_prevRenderObj(NULL), m_treadDebrisLeft(NULL), m_treadDebrisRight(NULL)
|
||||
{
|
||||
m_treadDebrisLeft = NULL;
|
||||
m_treadDebrisRight = NULL;
|
||||
|
||||
for (Int i=0; i<MAX_TREADS_PER_TANK; i++)
|
||||
m_treads[i].m_robj = NULL;
|
||||
|
||||
m_treadCount=0;
|
||||
//Assume all things face along x axis when created.
|
||||
m_lastDirection.x=1.0f;
|
||||
m_lastDirection.y=0.0f;
|
||||
m_lastDirection.z=0.0f;
|
||||
|
||||
createEmitters();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::tossEmitters( void )
|
||||
{
|
||||
if (m_treadDebrisLeft)
|
||||
{
|
||||
m_treadDebrisLeft->attachToObject(NULL);
|
||||
m_treadDebrisLeft->destroy();
|
||||
m_treadDebrisLeft = NULL;
|
||||
}
|
||||
if (m_treadDebrisRight)
|
||||
{
|
||||
m_treadDebrisRight->attachToObject(NULL);
|
||||
m_treadDebrisRight->destroy();
|
||||
m_treadDebrisRight = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::createEmitters( void )
|
||||
{
|
||||
if (!m_treadDebrisLeft)
|
||||
{
|
||||
const ParticleSystemTemplate *sysTemplate;
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankDrawModuleData()->m_treadDebrisNameLeft);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_treadDebrisLeft = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_treadDebrisLeft->attachToDrawable(getDrawable());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_treadDebrisLeft->setSaveable(FALSE);
|
||||
// they come into being stopped.
|
||||
m_treadDebrisLeft->stop();
|
||||
}
|
||||
}
|
||||
if (!m_treadDebrisRight)
|
||||
{
|
||||
const ParticleSystemTemplate *sysTemplate;
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankDrawModuleData()->m_treadDebrisNameRight);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_treadDebrisRight = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_treadDebrisRight->attachToDrawable(getDrawable());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_treadDebrisRight->setSaveable(FALSE);
|
||||
// they come into being stopped.
|
||||
m_treadDebrisRight->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankDraw::~W3DTankDraw()
|
||||
{
|
||||
for (Int i=0; i<MAX_TREADS_PER_TANK; i++)
|
||||
if (m_treads[i].m_robj)
|
||||
REF_PTR_RELEASE(m_treads[i].m_robj);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
|
||||
* Start creating debris from the tank treads
|
||||
*/
|
||||
void W3DTankDraw::startMoveDebris( void )
|
||||
{
|
||||
if (getDrawable()->isDrawableEffectivelyHidden())
|
||||
return;
|
||||
if (m_treadDebrisLeft)
|
||||
m_treadDebrisLeft->start();
|
||||
if (m_treadDebrisRight)
|
||||
m_treadDebrisRight->start();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Stop creating debris from the tank treads
|
||||
*/
|
||||
void W3DTankDraw::stopMoveDebris( void )
|
||||
{
|
||||
if (m_treadDebrisLeft)
|
||||
m_treadDebrisLeft->stop();
|
||||
if (m_treadDebrisRight)
|
||||
m_treadDebrisRight->stop();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::setHidden(Bool h)
|
||||
{
|
||||
W3DModelDraw::setHidden(h);
|
||||
if (h)
|
||||
{
|
||||
stopMoveDebris();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::setFullyObscuredByShroud(Bool fullyObscured)
|
||||
{
|
||||
if (fullyObscured != getFullyObscuredByShroud())
|
||||
{
|
||||
if (fullyObscured)
|
||||
stopMoveDebris();
|
||||
}
|
||||
W3DModelDraw::setFullyObscuredByShroud(fullyObscured);
|
||||
}
|
||||
|
||||
/**Update uv coordinates on each tread object to simulate movement*/
|
||||
void W3DTankDraw::updateTreadPositions(Real uvDelta)
|
||||
{
|
||||
Real offset_u;
|
||||
TreadObjectInfo *pTread=m_treads;
|
||||
|
||||
for (Int i=0; i<m_treadCount; i++)
|
||||
{
|
||||
if (pTread->m_type == TREAD_LEFT) //this tread needs to scroll forwards
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X + uvDelta;
|
||||
else
|
||||
if (pTread->m_type == TREAD_RIGHT) //this tread needs to scroll backwards
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X - uvDelta;
|
||||
|
||||
// ensure coordinates of offset are in [0, 1] range:
|
||||
offset_u = offset_u - WWMath::Floor(offset_u);
|
||||
pTread->m_materialSettings.customUVOffset.Set(offset_u,0);
|
||||
pTread++;
|
||||
}
|
||||
}
|
||||
|
||||
/**Grab pointers to the sub-meshes for each tread*/
|
||||
void W3DTankDraw::updateTreadObjects(void)
|
||||
{
|
||||
RenderObjClass *robj=getRenderObject();
|
||||
|
||||
//clear all previous tread pointers
|
||||
for (Int i=0; i<m_treadCount; i++)
|
||||
REF_PTR_RELEASE(m_treads[i].m_robj);
|
||||
m_treadCount = 0;
|
||||
|
||||
//Make sure this object has defined a speed for tread scrolling.
|
||||
if (getW3DTankDrawModuleData() && getW3DTankDrawModuleData()->m_treadAnimationRate && robj)
|
||||
{
|
||||
for (Int i=0; i < robj->Get_Num_Sub_Objects() && m_treadCount < MAX_TREADS_PER_TANK; i++)
|
||||
{
|
||||
RenderObjClass *subObj=robj->Get_Sub_Object(i);
|
||||
const char *meshName;
|
||||
//Check if subobject name starts with "TREADS".
|
||||
if (subObj && subObj->Class_ID() == RenderObjClass::CLASSID_MESH && subObj->Get_Name()
|
||||
&& ( (meshName=strchr(subObj->Get_Name(),'.') ) != 0 && *(meshName++))
|
||||
&&_strnicmp(meshName,"TREADS", 6) == 0)
|
||||
{ //check if sub-object has the correct material to do texture scrolling.
|
||||
MaterialInfoClass *mat=subObj->Get_Material_Info();
|
||||
if (mat)
|
||||
{ for (Int j=0; j<mat->Vertex_Material_Count(); j++)
|
||||
{
|
||||
VertexMaterialClass *vmaterial=mat->Peek_Vertex_Material(j);
|
||||
LinearOffsetTextureMapperClass *mapper=(LinearOffsetTextureMapperClass *)vmaterial->Peek_Mapper();
|
||||
if (mapper && mapper->Mapper_ID() == TextureMapperClass::MAPPER_ID_LINEAR_OFFSET)
|
||||
{ mapper->Set_UV_Offset_Delta(Vector2(0,0)); //disable automatic scrolling
|
||||
subObj->Add_Ref(); //increase reference since we're storing the pointer
|
||||
m_treads[m_treadCount].m_robj=subObj;
|
||||
m_treads[m_treadCount].m_type = TREAD_MIDDLE; //default type
|
||||
subObj->Set_User_Data(&m_treads[m_treadCount].m_materialSettings); //tell W3D about custom material settings
|
||||
m_treads[m_treadCount].m_materialSettings.customUVOffset=Vector2(0,0);
|
||||
switch (meshName[6]) //check next character after 'TREADS'
|
||||
{
|
||||
case 'L':
|
||||
case 'l': m_treads[m_treadCount].m_type = TREAD_LEFT;
|
||||
break;
|
||||
case 'R':
|
||||
case 'r': m_treads[m_treadCount].m_type = TREAD_RIGHT;
|
||||
break;
|
||||
}
|
||||
m_treadCount++;
|
||||
}
|
||||
}
|
||||
REF_PTR_RELEASE(mat);
|
||||
}
|
||||
}
|
||||
REF_PTR_RELEASE(subObj);
|
||||
}
|
||||
}
|
||||
|
||||
m_prevRenderObj = robj;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::onRenderObjRecreated(void)
|
||||
{
|
||||
updateTreadObjects();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Map behavior states into W3D animations. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
const Real DEBRIS_THRESHOLD = 0.00001f;
|
||||
|
||||
Bool frozen = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
|
||||
frozen = frozen || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
|
||||
if (frozen)
|
||||
return;
|
||||
if (getRenderObject()==NULL) return;
|
||||
if (getRenderObject() != m_prevRenderObj) {
|
||||
updateTreadObjects();
|
||||
}
|
||||
|
||||
// get object from logic
|
||||
Object *obj = getDrawable()->getObject();
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
// get object physics state
|
||||
PhysicsBehavior *physics = obj->getPhysics();
|
||||
if (physics == NULL)
|
||||
return;
|
||||
|
||||
const Coord3D *vel = physics->getVelocity();
|
||||
|
||||
// if tank is moving, kick up dust and debris
|
||||
Real velMag = vel->x*vel->x + vel->y*vel->y; // only care about moving on the ground
|
||||
|
||||
if (velMag > DEBRIS_THRESHOLD && !getDrawable()->isDrawableEffectivelyHidden() && !getFullyObscuredByShroud())
|
||||
startMoveDebris();
|
||||
else
|
||||
stopMoveDebris();
|
||||
|
||||
// kick debris higher the faster we move
|
||||
Coord3D velMult;
|
||||
velMag = (Real)sqrt( velMag );
|
||||
|
||||
velMult.x = 0.5f * velMag + 0.1f;
|
||||
if (velMult.x > 1.0f)
|
||||
velMult.x = 1.0f;
|
||||
|
||||
velMult.y = velMult.x;
|
||||
|
||||
velMult.z = velMag + 0.1f;
|
||||
if (velMult.z > 1.0f)
|
||||
velMult.z = 1.0f;
|
||||
|
||||
m_treadDebrisLeft->setVelocityMultiplier( &velMult );
|
||||
m_treadDebrisRight->setVelocityMultiplier( &velMult );
|
||||
|
||||
m_treadDebrisLeft->setBurstCountMultiplier( velMult.z );
|
||||
m_treadDebrisRight->setBurstCountMultiplier( velMult.z );
|
||||
|
||||
//Update movement of treads
|
||||
if (m_treadCount)
|
||||
{
|
||||
PhysicsTurningType turn=physics->getTurning();
|
||||
Real offset_u;
|
||||
Real treadScrollSpeed=getW3DTankDrawModuleData()->m_treadAnimationRate;
|
||||
TreadObjectInfo *pTread=m_treads;
|
||||
Real maxSpeed=obj->getAIUpdateInterface()->getCurLocomotorSpeed();
|
||||
|
||||
//For optimization sake, we only do complex tread scrolling when tank
|
||||
//is mostly stationary and turning
|
||||
if (turn != TURN_NONE && physics->getVelocityMagnitude()/maxSpeed < getW3DTankDrawModuleData()->m_treadPivotSpeedFraction)
|
||||
{
|
||||
//Check if we have turned enough since last draw to require animation
|
||||
Coord3D dir;
|
||||
obj->getUnitDirectionVector2D(dir);
|
||||
Real angleToGoal = dir.x * m_lastDirection.x + dir.y * m_lastDirection.y;
|
||||
|
||||
if (fabs(1.0f-angleToGoal) > 0.00001f) //check if difference in angle cosines is greater than some cutoff.
|
||||
{
|
||||
if (turn == TURN_NEGATIVE) //turning right
|
||||
updateTreadPositions(-treadScrollSpeed);
|
||||
else //turning left
|
||||
updateTreadPositions(treadScrollSpeed);
|
||||
}
|
||||
m_lastDirection=dir; //update for next frame
|
||||
}
|
||||
else
|
||||
if (physics->isMotive() && physics->getVelocityMagnitude()/maxSpeed >= getW3DTankDrawModuleData()->m_treadDriveSpeedFraction)
|
||||
{ //do simple scrolling based only on speed when tank is moving straight at high speed.
|
||||
//we stop scrolling when tank slows down to reduce the appearance of sliding
|
||||
//tread scrolling speed was not directly tied into tank velocity because it looked odd
|
||||
//under certain situations when tank moved sideways.
|
||||
for (Int i=0; i<m_treadCount; i++)
|
||||
{
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X - treadScrollSpeed;
|
||||
// ensure coordinates of offset are in [0, 1] range:
|
||||
offset_u = offset_u - WWMath::Floor(offset_u);
|
||||
pTread->m_materialSettings.customUVOffset.Set(offset_u,0);
|
||||
pTread++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
W3DModelDraw::doDrawModule(transformMtx);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
// John A and Mark W say there is no data to save here
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTankDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
// toss any existing ones and re-create 'em (since this module expects 'em to always be around)
|
||||
tossEmitters();
|
||||
createEmitters();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,787 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTankTruckDraw.cpp
|
||||
// Draw TankTrucks. Actually, this draws quad cannon which has both treads and wheels.
|
||||
// Author: Mark Wilczynski, August 2002
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingFactory.h"
|
||||
#include "Common/GameAudio.h"
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameLogic/Weapon.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "GameLogic/Module/PhysicsUpdate.h"
|
||||
#include "GameLogic/Module/BodyModule.h"
|
||||
#include "GameLogic/ScriptEngine.h"
|
||||
#include "GameLogic/Module/AIUpdate.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/ParticleSys.h"
|
||||
#include "W3DDevice/GameClient/W3DGameClient.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTankTruckDraw.h"
|
||||
#include "WW3D2/matinfo.h"
|
||||
|
||||
//#define SHOW_TANK_DEBRIS
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankTruckDrawModuleData::W3DTankTruckDrawModuleData():
|
||||
m_treadDebrisNameLeft("TrackDebrisDirtLeft"),
|
||||
m_treadDebrisNameRight("TrackDebrisDirtRight"),
|
||||
m_treadAnimationRate(0.0f),
|
||||
m_treadPivotSpeedFraction(0.6f),
|
||||
m_treadDriveSpeedFraction(0.3f)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankTruckDrawModuleData::~W3DTankTruckDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "Dust", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_dustEffectName) },
|
||||
{ "DirtSpray", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_dirtEffectName) },
|
||||
{ "PowerslideSpray", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_powerslideEffectName) },
|
||||
{ "LeftFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_frontLeftTireBoneName) },
|
||||
{ "RightFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_frontRightTireBoneName) },
|
||||
{ "LeftRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_rearLeftTireBoneName) },
|
||||
{ "RightRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_rearRightTireBoneName) },
|
||||
{ "MidLeftFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_midFrontLeftTireBoneName) },
|
||||
{ "MidRightFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_midFrontRightTireBoneName) },
|
||||
{ "MidLeftRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_midRearLeftTireBoneName) },
|
||||
{ "MidRightRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_midRearRightTireBoneName) },
|
||||
{ "TireRotationMultiplier", INI::parseReal, NULL, offsetof(W3DTankTruckDrawModuleData, m_rotationSpeedMultiplier) },
|
||||
{ "PowerslideRotationAddition", INI::parseReal, NULL, offsetof(W3DTankTruckDrawModuleData, m_powerslideRotationAddition) },
|
||||
{ "TreadDebrisLeft", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_treadDebrisNameLeft) },
|
||||
{ "TreadDebrisRight", INI::parseAsciiString, NULL, offsetof(W3DTankTruckDrawModuleData, m_treadDebrisNameRight) },
|
||||
{ "TreadAnimationRate", INI::parseVelocityReal, NULL, offsetof(W3DTankTruckDrawModuleData, m_treadAnimationRate) },
|
||||
{ "TreadPivotSpeedFraction", INI::parseReal, NULL, offsetof(W3DTankTruckDrawModuleData, m_treadPivotSpeedFraction) },
|
||||
{ "TreadDriveSpeedFraction", INI::parseReal, NULL, offsetof(W3DTankTruckDrawModuleData, m_treadDriveSpeedFraction) },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankTruckDraw::W3DTankTruckDraw( Thing *thing, const ModuleData* moduleData ) : W3DModelDraw( thing, moduleData ),
|
||||
m_dirtEffect(NULL), m_dustEffect(NULL), m_powerslideEffect(NULL), m_effectsInitialized(false),
|
||||
m_wasAirborne(false), m_isPowersliding(false), m_frontWheelRotation(0), m_rearWheelRotation(0),
|
||||
m_frontRightTireBone(0), m_frontLeftTireBone(0), m_rearLeftTireBone(0),m_rearRightTireBone(0),
|
||||
m_prevRenderObj(NULL)
|
||||
{
|
||||
//Truck Data
|
||||
m_landingSound = *(thing->getTemplate()->getPerUnitSound("TruckLandingSound"));
|
||||
m_powerslideSound = *(thing->getTemplate()->getPerUnitSound("TruckPowerslideSound"));
|
||||
|
||||
//Tank data
|
||||
m_treadDebrisLeft = NULL;
|
||||
m_treadDebrisRight = NULL;
|
||||
|
||||
for (Int i=0; i<MAX_TREADS_PER_TANK; i++)
|
||||
m_treads[i].m_robj = NULL;
|
||||
|
||||
m_treadCount=0;
|
||||
|
||||
#ifdef SHOW_TANK_DEBRIS
|
||||
if (getW3DTankTruckDrawModuleData())
|
||||
{
|
||||
ParticleSystemTemplate *sysTemplate;
|
||||
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankTruckDrawModuleData()->m_treadDebrisNameLeft);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_treadDebrisLeft = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_treadDebrisLeft->attachToDrawable(getDrawable());
|
||||
DEBUG_CRASH(("test me, may not work (srj)"));
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_treadDebrisLeft->setSaveable(FALSE);
|
||||
}
|
||||
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankTruckDrawModuleData()->m_treadDebrisNameRight);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_treadDebrisRight = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_treadDebrisRight->attachToDrawable(getDrawable());
|
||||
DEBUG_CRASH(("test me, may not work (srj)"));
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_treadDebrisRight->setSaveable(FALSE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTankTruckDraw::~W3DTankTruckDraw()
|
||||
{
|
||||
tossEmitters();
|
||||
|
||||
for (Int i=0; i<MAX_TREADS_PER_TANK; i++)
|
||||
if (m_treads[i].m_robj)
|
||||
REF_PTR_RELEASE(m_treads[i].m_robj);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
|
||||
* Start creating debris from the tank treads
|
||||
*/
|
||||
void W3DTankTruckDraw::startMoveDebris( void )
|
||||
{
|
||||
if (getDrawable()->isDrawableEffectivelyHidden())
|
||||
return;
|
||||
if (m_treadDebrisLeft)
|
||||
m_treadDebrisLeft->start();
|
||||
if (m_treadDebrisRight)
|
||||
m_treadDebrisRight->start();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Stop creating debris from the tank treads
|
||||
*/
|
||||
void W3DTankTruckDraw::stopMoveDebris( void )
|
||||
{
|
||||
if (m_treadDebrisLeft)
|
||||
m_treadDebrisLeft->stop();
|
||||
if (m_treadDebrisRight)
|
||||
m_treadDebrisRight->stop();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::tossEmitters()
|
||||
{
|
||||
if (m_dustEffect)
|
||||
{
|
||||
m_dustEffect->attachToObject(NULL);
|
||||
m_dustEffect->destroy();
|
||||
m_dustEffect = NULL;
|
||||
}
|
||||
if (m_dirtEffect)
|
||||
{
|
||||
m_dirtEffect->attachToObject(NULL);
|
||||
m_dirtEffect->destroy();
|
||||
m_dirtEffect = NULL;
|
||||
}
|
||||
if (m_powerslideEffect)
|
||||
{
|
||||
m_powerslideEffect->attachToObject(NULL);
|
||||
m_powerslideEffect->destroy();
|
||||
m_powerslideEffect = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::setFullyObscuredByShroud(Bool fullyObscured)
|
||||
{
|
||||
if (fullyObscured != getFullyObscuredByShroud())
|
||||
{
|
||||
if (fullyObscured)
|
||||
tossEmitters();
|
||||
else
|
||||
createEmitters();
|
||||
}
|
||||
W3DModelDraw::setFullyObscuredByShroud(fullyObscured);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
|
||||
* Start creating debris from the tank treads
|
||||
*/
|
||||
void W3DTankTruckDraw::createEmitters( void )
|
||||
{
|
||||
if (getDrawable()->isDrawableEffectivelyHidden())
|
||||
return;
|
||||
if (getW3DTankTruckDrawModuleData())
|
||||
{
|
||||
const ParticleSystemTemplate *sysTemplate;
|
||||
|
||||
if (!m_dustEffect) {
|
||||
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankTruckDrawModuleData()->m_dustEffectName);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_dustEffect = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_dustEffect->attachToObject(getDrawable()->getObject());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_dustEffect->setSaveable(FALSE);
|
||||
} else {
|
||||
if (!getW3DTankTruckDrawModuleData()->m_dustEffectName.isEmpty()) {
|
||||
DEBUG_LOG(("*** ERROR - Missing particle system '%s' in thing '%s'\n",
|
||||
getW3DTankTruckDrawModuleData()->m_dustEffectName.str(), getDrawable()->getObject()->getTemplate()->getName().str()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!m_dirtEffect) {
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankTruckDrawModuleData()->m_dirtEffectName);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_dirtEffect = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_dirtEffect->attachToObject(getDrawable()->getObject());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_dirtEffect->setSaveable(FALSE);
|
||||
} else {
|
||||
if (!getW3DTankTruckDrawModuleData()->m_dirtEffectName.isEmpty()) {
|
||||
DEBUG_LOG(("*** ERROR - Missing particle system '%s' in thing '%s'\n",
|
||||
getW3DTankTruckDrawModuleData()->m_dirtEffectName.str(), getDrawable()->getObject()->getTemplate()->getName().str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_powerslideEffect) {
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTankTruckDrawModuleData()->m_powerslideEffectName);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_powerslideEffect = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_powerslideEffect->attachToObject(getDrawable()->getObject());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_powerslideEffect->setSaveable(FALSE);
|
||||
} else {
|
||||
if (!getW3DTankTruckDrawModuleData()->m_powerslideEffectName.isEmpty()) {
|
||||
DEBUG_LOG(("*** ERROR - Missing particle system '%s' in thing '%s'\n",
|
||||
getW3DTankTruckDrawModuleData()->m_powerslideEffectName.str(), getDrawable()->getObject()->getTemplate()->getName().str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Stop creating debris from the tank treads
|
||||
*/
|
||||
void W3DTankTruckDraw::enableEmitters( Bool enable )
|
||||
{
|
||||
// don't check... if we are hidden the first time thru, then we'll never create the emitters.
|
||||
// eg, if we are loading a game and the unit is in a tunnel, he'll never get emitteres even when he exits.
|
||||
//if (!m_effectsInitialized)
|
||||
{
|
||||
createEmitters();
|
||||
m_effectsInitialized=true;
|
||||
}
|
||||
if (m_dustEffect)
|
||||
{
|
||||
if (enable)
|
||||
m_dustEffect->start();
|
||||
else
|
||||
m_dustEffect->stop();
|
||||
}
|
||||
if (m_dirtEffect)
|
||||
{
|
||||
if (enable)
|
||||
m_dirtEffect->start();
|
||||
else
|
||||
m_dirtEffect->stop();
|
||||
}
|
||||
if (m_powerslideEffect)
|
||||
{
|
||||
if (!enable)
|
||||
m_powerslideEffect->stop();
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::updateBones( void ) {
|
||||
if( getW3DTankTruckDrawModuleData() )
|
||||
{
|
||||
//Front tires
|
||||
if( !getW3DTankTruckDrawModuleData()->m_frontLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_frontLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_frontLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_frontLeftTireBone, ("Missing front-left tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_frontLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_frontRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_frontRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_frontRightTireBone, ("Missing front-right tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_frontRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_frontRightTireBone )
|
||||
{
|
||||
m_frontLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
//Rear tires
|
||||
if( !getW3DTankTruckDrawModuleData()->m_rearLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_rearLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_rearLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_rearLeftTireBone, ("Missing rear-left tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_rearLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_rearRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_rearRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_rearRightTireBone, ("Missing rear-left tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_rearRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_rearRightTireBone)
|
||||
{
|
||||
m_rearLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//midFront tires
|
||||
if( !getW3DTankTruckDrawModuleData()->m_midFrontLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_midFrontLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_midFrontLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midFrontLeftTireBone, ("Missing mid-front-left tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_midFrontLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_midFrontRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_midFrontRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midFrontRightTireBone, ("Missing mid-front-right tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_midFrontRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_midFrontRightTireBone )
|
||||
{
|
||||
m_midFrontLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//midRear tires
|
||||
if( !getW3DTankTruckDrawModuleData()->m_midRearLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_midRearLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_midRearLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midRearLeftTireBone, ("Missing mid-rear-left tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_midRearLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_midRearRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTankTruckDrawModuleData()->m_midRearRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midRearRightTireBone, ("Missing mid-rear-right tire bone %s in model %s\n", getW3DTankTruckDrawModuleData()->m_midRearRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_midRearRightTireBone)
|
||||
{
|
||||
m_midRearLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_prevRenderObj = getRenderObject();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::setHidden(Bool h)
|
||||
{
|
||||
W3DModelDraw::setHidden(h);
|
||||
if (h)
|
||||
{
|
||||
enableEmitters(false);
|
||||
#ifdef SHOW_TANK_DEBRIS
|
||||
stopMoveDebris();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**Update uv coordinates on each tread object to simulate movement*/
|
||||
void W3DTankTruckDraw::updateTreadPositions(Real uvDelta)
|
||||
{
|
||||
Real offset_u;
|
||||
TreadObjectInfo *pTread=m_treads;
|
||||
|
||||
for (Int i=0; i<m_treadCount; i++)
|
||||
{
|
||||
if (pTread->m_type == TREAD_MIDDLE) //this tread needs to scroll backwards
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X + uvDelta;
|
||||
else
|
||||
if (pTread->m_type == TREAD_LEFT) //this tread needs to scroll forwards
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X + uvDelta;
|
||||
else
|
||||
if (pTread->m_type == TREAD_RIGHT) //this tread needs to scroll backwards
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X - uvDelta;
|
||||
|
||||
// ensure coordinates of offset are in [0, 1] range:
|
||||
offset_u = offset_u - WWMath::Floor(offset_u);
|
||||
pTread->m_materialSettings.customUVOffset.Set(offset_u,0);
|
||||
pTread++;
|
||||
}
|
||||
}
|
||||
|
||||
/**Grab pointers to the sub-meshes for each tread*/
|
||||
void W3DTankTruckDraw::updateTreadObjects(void)
|
||||
{
|
||||
RenderObjClass *robj=getRenderObject();
|
||||
|
||||
//clear all previous tread pointers
|
||||
for (Int i=0; i<m_treadCount; i++)
|
||||
REF_PTR_RELEASE(m_treads[i].m_robj);
|
||||
m_treadCount = 0;
|
||||
|
||||
//Make sure this object has defined a speed for tread scrolling.
|
||||
if (getW3DTankTruckDrawModuleData() && getW3DTankTruckDrawModuleData()->m_treadAnimationRate && robj)
|
||||
{
|
||||
for (Int i=0; i < robj->Get_Num_Sub_Objects() && m_treadCount < MAX_TREADS_PER_TANK; i++)
|
||||
{
|
||||
RenderObjClass *subObj=robj->Get_Sub_Object(i);
|
||||
const char *meshName;
|
||||
//Check if subobject name starts with "TREADS".
|
||||
if (subObj && subObj->Class_ID() == RenderObjClass::CLASSID_MESH && subObj->Get_Name()
|
||||
&& ( (meshName=strchr(subObj->Get_Name(),'.') ) != 0 && *(meshName++))
|
||||
&&_strnicmp(meshName,"TREADS", 6) == 0)
|
||||
{ //check if sub-object has the correct material to do texture scrolling.
|
||||
MaterialInfoClass *mat=subObj->Get_Material_Info();
|
||||
if (mat)
|
||||
{ for (Int j=0; j<mat->Vertex_Material_Count(); j++)
|
||||
{
|
||||
VertexMaterialClass *vmaterial=mat->Peek_Vertex_Material(j);
|
||||
LinearOffsetTextureMapperClass *mapper=(LinearOffsetTextureMapperClass *)vmaterial->Peek_Mapper();
|
||||
if (mapper && mapper->Mapper_ID() == TextureMapperClass::MAPPER_ID_LINEAR_OFFSET)
|
||||
{ mapper->Set_UV_Offset_Delta(Vector2(0,0)); //disable automatic scrolling
|
||||
subObj->Add_Ref(); //increase reference since we're storing the pointer
|
||||
m_treads[m_treadCount].m_robj=subObj;
|
||||
m_treads[m_treadCount].m_type = TREAD_MIDDLE; //default type
|
||||
subObj->Set_User_Data(&m_treads[m_treadCount].m_materialSettings); //tell W3D about custom material settings
|
||||
m_treads[m_treadCount].m_materialSettings.customUVOffset=Vector2(0,0);
|
||||
//Commented out since on vehicles with wheels, it makes no sense to turn with treads.
|
||||
/* switch (meshName[6]) //check next character after 'TREADS'
|
||||
{
|
||||
case 'L':
|
||||
case 'l': m_treads[m_treadCount].m_type = TREAD_LEFT;
|
||||
break;
|
||||
case 'R':
|
||||
case 'r': m_treads[m_treadCount].m_type = TREAD_RIGHT;
|
||||
break;
|
||||
}*/
|
||||
m_treadCount++;
|
||||
}
|
||||
}
|
||||
REF_PTR_RELEASE(mat);
|
||||
}
|
||||
}
|
||||
REF_PTR_RELEASE(subObj);
|
||||
}
|
||||
}
|
||||
|
||||
m_prevRenderObj = robj;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::onRenderObjRecreated(void)
|
||||
{
|
||||
//DEBUG_LOG(("Old obj %x, newObj %x, new bones %d, old bones %d\n",
|
||||
// m_prevRenderObj, getRenderObject(), getRenderObject()->Get_Num_Bones(),
|
||||
// m_prevNumBones));
|
||||
m_prevRenderObj = NULL;
|
||||
m_frontLeftTireBone = 0;
|
||||
m_frontRightTireBone = 0;
|
||||
m_rearLeftTireBone = 0;
|
||||
m_rearRightTireBone = 0;
|
||||
m_midFrontLeftTireBone = 0;
|
||||
m_midFrontRightTireBone = 0;
|
||||
m_midRearLeftTireBone = 0;
|
||||
m_midRearRightTireBone = 0;
|
||||
updateBones();
|
||||
updateTreadObjects();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Map behavior states into W3D animations. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
|
||||
W3DModelDraw::doDrawModule(transformMtx);
|
||||
|
||||
if (!TheGlobalData->m_showClientPhysics)
|
||||
return;
|
||||
|
||||
Bool frozen = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
|
||||
frozen = frozen || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
|
||||
if (frozen)
|
||||
return;
|
||||
|
||||
const Real ACCEL_THRESHOLD = 0.01f;
|
||||
const Real SIZE_CAP = 2.0f;
|
||||
// get object from logic
|
||||
Object *obj = getDrawable()->getObject();
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
if (getRenderObject()==NULL) return;
|
||||
if (getRenderObject() != m_prevRenderObj) {
|
||||
updateBones();
|
||||
updateTreadObjects();
|
||||
}
|
||||
// get object physics state
|
||||
PhysicsBehavior *physics = obj->getPhysics();
|
||||
if (physics == NULL)
|
||||
return;
|
||||
|
||||
const Coord3D *vel = physics->getVelocity();
|
||||
Real speed = physics->getVelocityMagnitude();
|
||||
|
||||
|
||||
const TWheelInfo *wheelInfo = getDrawable()->getWheelInfo(); // note, can return null!
|
||||
if (wheelInfo && (m_frontLeftTireBone || m_rearLeftTireBone))
|
||||
{
|
||||
static Real rotation = 0;
|
||||
const Real rotationFactor = getW3DTankTruckDrawModuleData()->m_rotationSpeedMultiplier;
|
||||
m_frontWheelRotation += rotationFactor*speed;
|
||||
if (m_isPowersliding)
|
||||
{
|
||||
m_rearWheelRotation += rotationFactor*(speed+getW3DTankTruckDrawModuleData()->m_powerslideRotationAddition);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rearWheelRotation += rotationFactor*speed;
|
||||
}
|
||||
Matrix3D wheelXfrm(1);
|
||||
if (m_frontLeftTireBone)
|
||||
{
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontLeftHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_frontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_frontLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_frontLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontRightHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_frontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_frontRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_frontRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_rearLeftTireBone)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_rearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearLeftHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_rearLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_rearLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_rearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearRightHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_rearRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_rearRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_midFrontLeftTireBone)
|
||||
{
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontLeftHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_midFrontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_midFrontLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_midFrontLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontRightHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_midFrontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_midFrontRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_midFrontRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_midRearLeftTireBone)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_midRearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearLeftHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_midRearLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_midRearLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_midRearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearRightHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_midRearRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_midRearRightTireBone, wheelXfrm );
|
||||
}
|
||||
}
|
||||
|
||||
Bool wasPowersliding = m_isPowersliding;
|
||||
m_isPowersliding = false;
|
||||
if (physics->isMotive() && !obj->isSignificantlyAboveTerrain()) {
|
||||
enableEmitters(true);
|
||||
Coord3D accel = *physics->getAcceleration();
|
||||
accel.z = 0; // ignore gravitational force.
|
||||
Bool accelerating = accel.length()>ACCEL_THRESHOLD;
|
||||
//DEBUG_LOG(("Accel %f, speed %f\n", accel.length(), speed));
|
||||
if (accelerating) {
|
||||
Real dot = accel.x*vel->x + accel.y*vel->y;
|
||||
if (dot<0) {
|
||||
accelerating = false; // decelerating, actually.
|
||||
}
|
||||
}
|
||||
if (m_dustEffect) {
|
||||
// Need more dust the faster we go.
|
||||
if (speed>SIZE_CAP) {
|
||||
speed = SIZE_CAP;
|
||||
}
|
||||
m_dustEffect->setSizeMultiplier(speed);
|
||||
}
|
||||
if (m_dirtEffect) {
|
||||
if (wheelInfo && wheelInfo->m_framesAirborne>3) {
|
||||
Real factor = 1 + wheelInfo->m_framesAirborne/16;
|
||||
if (factor>2.0) factor = 2.0;
|
||||
m_dustEffect->setSizeMultiplier(factor*SIZE_CAP);
|
||||
m_dustEffect->trigger();
|
||||
m_landingSound.setPosition(obj->getPosition());
|
||||
TheAudio->addAudioEvent(&m_landingSound);
|
||||
} else {
|
||||
if (!accelerating || speed>2.0f) {
|
||||
m_dirtEffect->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_powerslideEffect) {
|
||||
if (physics->getTurning() == TURN_NONE) {
|
||||
m_powerslideEffect->stop();
|
||||
} else {
|
||||
m_isPowersliding = true;
|
||||
m_powerslideEffect->start();
|
||||
}
|
||||
}
|
||||
if (m_dirtEffect) {
|
||||
if (!accelerating || speed>2.0f) {
|
||||
m_dirtEffect->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
enableEmitters(false);
|
||||
|
||||
m_wasAirborne = obj->isSignificantlyAboveTerrain();
|
||||
|
||||
if(!wasPowersliding && m_isPowersliding) {
|
||||
// start sound
|
||||
m_powerslideSound.setObjectID(obj->getID());
|
||||
m_powerslideSound.setPlayingHandle(TheAudio->addAudioEvent(&m_powerslideSound));
|
||||
} else if (wasPowersliding && !m_isPowersliding) {
|
||||
TheAudio->removeAudioEvent(m_powerslideSound.getPlayingHandle());
|
||||
}
|
||||
|
||||
//Tank update
|
||||
#ifdef SHOW_TANK_DEBRIS
|
||||
const Real DEBRIS_THRESHOLD = 0.00001f;
|
||||
|
||||
// if tank is moving, kick up dust and debris
|
||||
Real velMag = vel->x*vel->x + vel->y*vel->y; // only care about moving on the ground
|
||||
|
||||
if (velMag > DEBRIS_THRESHOLD && !getDrawable()->isDrawableEffectivelyHidden() && !getFullyObscuredByShroud())
|
||||
startMoveDebris();
|
||||
else
|
||||
stopMoveDebris();
|
||||
|
||||
// kick debris higher the faster we move
|
||||
Coord3D velMult;
|
||||
velMag = (Real)sqrt( velMag );
|
||||
|
||||
velMult.x = 0.5f * velMag + 0.1f;
|
||||
if (velMult.x > 1.0f)
|
||||
velMult.x = 1.0f;
|
||||
|
||||
velMult.y = velMult.x;
|
||||
|
||||
velMult.z = velMag + 0.1f;
|
||||
if (velMult.z > 1.0f)
|
||||
velMult.z = 1.0f;
|
||||
|
||||
m_treadDebrisLeft->setVelocityMultiplier( &velMult );
|
||||
m_treadDebrisRight->setVelocityMultiplier( &velMult );
|
||||
|
||||
m_treadDebrisLeft->setBurstCountMultiplier( velMult.z );
|
||||
m_treadDebrisRight->setBurstCountMultiplier( velMult.z );
|
||||
#endif
|
||||
//Update movement of treads
|
||||
if (m_treadCount)
|
||||
{
|
||||
Real offset_u;
|
||||
Real treadScrollSpeed=getW3DTankTruckDrawModuleData()->m_treadAnimationRate;
|
||||
TreadObjectInfo *pTread=m_treads;
|
||||
Real maxSpeed=obj->getAIUpdateInterface()->getCurLocomotorSpeed();
|
||||
/* Commented out because these vehicles are presumed not to turn via treads.
|
||||
PhysicsTurningType turn=physics->getTurning();
|
||||
//For optimization sake, we only do complex tread scrolling when tank
|
||||
//is mostly stationary and turning
|
||||
if ((turn=physics->getTurning()) != TURN_NONE && physics->getSpeed()/maxSpeed < getW3DTankTruckDrawModuleData()->m_treadPivotSpeedFraction)
|
||||
{
|
||||
if (turn == TURN_NEGATIVE) //turning right
|
||||
updateTreadPositions(-treadScrollSpeed);
|
||||
else //turning left
|
||||
updateTreadPositions(treadScrollSpeed);
|
||||
}
|
||||
else*/
|
||||
if (physics->isMotive() && physics->getVelocityMagnitude()/maxSpeed >= getW3DTankTruckDrawModuleData()->m_treadDriveSpeedFraction)
|
||||
{ //do simple scrolling based only on speed when tank is moving straight at high speed.
|
||||
//we stop scrolling when tank slows down to reduce the appearance of sliding
|
||||
//tread scrolling speed was not directly tied into tank velocity because it looked odd
|
||||
//under certain situations when tank moved sideways.
|
||||
for (Int i=0; i<m_treadCount; i++)
|
||||
{
|
||||
offset_u = pTread->m_materialSettings.customUVOffset.X - treadScrollSpeed;
|
||||
// ensure coordinates of offset are in [0, 1] range:
|
||||
offset_u = offset_u - WWMath::Floor(offset_u);
|
||||
pTread->m_materialSettings.customUVOffset.Set(offset_u,0);
|
||||
pTread++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
// John A and Mark W say there is no data to save here
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTankTruckDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
// toss any existing ones (no need to re-create; we'll do that on demand)
|
||||
tossEmitters();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTracerDraw.cpp ////////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, December 2001
|
||||
// Desc: Tracer drawing
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTracerDraw.h"
|
||||
#include "WW3D2/Line3D.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTracerDraw::W3DTracerDraw( Thing *thing, const ModuleData* moduleData ) : DrawModule( thing, moduleData )
|
||||
{
|
||||
|
||||
// set opacity
|
||||
m_opacity = 1.0f;
|
||||
m_length = 20.0f;
|
||||
m_width = 0.5f;
|
||||
m_color.red = 0.9f;
|
||||
m_color.green = 0.8f;
|
||||
m_color.blue = 0.7f;
|
||||
m_speedInDistPerFrame = 1.0f;
|
||||
m_theTracer = NULL;
|
||||
|
||||
} // end W3DTracerDraw
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTracerDraw::setTracerParms(Real speed, Real length, Real width, const RGBColor& color, Real initialOpacity)
|
||||
{
|
||||
m_speedInDistPerFrame = speed;
|
||||
m_length = length;
|
||||
m_width = width;
|
||||
m_color = color;
|
||||
m_opacity = initialOpacity;
|
||||
if (m_theTracer)
|
||||
{
|
||||
Vector3 start( 0.0f, 0.0f, 0.0f );
|
||||
Vector3 stop( m_length, 0.0f, 0.0f );
|
||||
m_theTracer->Reset(start, stop, m_width);
|
||||
m_theTracer->Re_Color(m_color.red, m_color.green, m_color.blue);
|
||||
m_theTracer->Set_Opacity( m_opacity );
|
||||
// these calls nuke the internal transform, so re-set it here
|
||||
m_theTracer->Set_Transform( *getDrawable()->getTransformMatrix() );
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTracerDraw::~W3DTracerDraw( void )
|
||||
{
|
||||
// remove tracer from the scene and delete
|
||||
if( m_theTracer )
|
||||
{
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_theTracer );
|
||||
REF_PTR_RELEASE( m_theTracer );
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTracerDraw::reactToTransformChange( const Matrix3D *oldMtx,
|
||||
const Coord3D *oldPos,
|
||||
Real oldAngle )
|
||||
{
|
||||
if( m_theTracer )
|
||||
m_theTracer->Set_Transform( *getDrawable()->getTransformMatrix() );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTracerDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
|
||||
// create tracer
|
||||
if( m_theTracer == NULL )
|
||||
{
|
||||
|
||||
Vector3 start( 0.0f, 0.0f, 0.0f );
|
||||
Vector3 stop( m_length, 0.0f, 0.0f );
|
||||
|
||||
// create tracer render object for us to manipulate
|
||||
// poolify
|
||||
m_theTracer = NEW Line3DClass( start,
|
||||
stop,
|
||||
m_width, // width
|
||||
m_color.red, // red
|
||||
m_color.green, // green
|
||||
m_color.blue, // blue
|
||||
m_opacity ); // transparency
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( m_theTracer );
|
||||
|
||||
// set the transform for the tracer to that of the drawable
|
||||
m_theTracer->Set_Transform( *transformMtx );
|
||||
|
||||
}
|
||||
|
||||
UnsignedInt expDate = getDrawable()->getExpirationDate();
|
||||
if (expDate != 0)
|
||||
{
|
||||
Real decay = m_opacity / (expDate - TheGameLogic->getFrame());
|
||||
m_opacity -= decay;
|
||||
m_theTracer->Set_Opacity( m_opacity );
|
||||
}
|
||||
|
||||
// set the position for the tracer
|
||||
if (m_speedInDistPerFrame != 0.0f)
|
||||
{
|
||||
Matrix3D pos = m_theTracer->Get_Transform();
|
||||
pos.Translate( Vector3( m_speedInDistPerFrame, 0.0f, 0.0 ) );
|
||||
m_theTracer->Set_Transform( pos );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTracerDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTracerDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// no data to save here, nobody will ever notice
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTracerDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTreeDraw.cpp ////////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, December 2001
|
||||
// Desc: Tracer drawing
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTreeDraw.h"
|
||||
#include "W3DDevice/GameClient/BaseHeightMap.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTreeDrawModuleData::W3DTreeDrawModuleData() :
|
||||
m_framesToMoveInward(1),
|
||||
m_framesToMoveOutward(1),
|
||||
m_darkening(0.0f),
|
||||
m_maxOutwardMovement(1.0f)
|
||||
{
|
||||
|
||||
// Topple parameters. [7/7/2003]
|
||||
const Real START_VELOCITY_PERCENT = 0.2f;
|
||||
const Real START_ACCEL_PERCENT = 0.01f;
|
||||
const Real VELOCITY_BOUNCE_PERCENT = 0.3f; // multiply the velocity by this when you bounce
|
||||
const Real MINIMUM_TOPPLE_SPEED = 0.5f; // Won't let trees fall slower than this
|
||||
m_toppleFX = NULL;
|
||||
m_bounceFX = NULL;
|
||||
m_stumpName.clear();
|
||||
m_killWhenToppled = true;
|
||||
m_doTopple = false;
|
||||
m_doShadow = false;
|
||||
m_initialVelocityPercent = START_VELOCITY_PERCENT;
|
||||
m_initialAccelPercent = START_ACCEL_PERCENT;
|
||||
m_bounceVelocityPercent = VELOCITY_BOUNCE_PERCENT;
|
||||
m_minimumToppleSpeed = MINIMUM_TOPPLE_SPEED;
|
||||
m_sinkFrames = 10*LOGICFRAMES_PER_SECOND;
|
||||
m_sinkDistance = 20.0f;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTreeDrawModuleData::~W3DTreeDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTreeDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
ModuleData::buildFieldParse(p);
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "ModelName", INI::parseAsciiString, NULL, offsetof(W3DTreeDrawModuleData, m_modelName) },
|
||||
{ "TextureName", INI::parseAsciiString, NULL, offsetof(W3DTreeDrawModuleData, m_textureName) },
|
||||
{ "MoveOutwardTime", INI::parseDurationUnsignedInt, NULL, offsetof(W3DTreeDrawModuleData, m_framesToMoveOutward) },
|
||||
{ "MoveInwardTime", INI::parseDurationUnsignedInt, NULL, offsetof(W3DTreeDrawModuleData, m_framesToMoveInward) },
|
||||
{ "MoveOutwardDistanceFactor", INI::parseReal, NULL, offsetof(W3DTreeDrawModuleData, m_maxOutwardMovement) },
|
||||
{ "DarkeningFactor", INI::parseReal, NULL, offsetof(W3DTreeDrawModuleData, m_darkening) },
|
||||
|
||||
// Topple parameters [7/7/2003]
|
||||
{ "ToppleFX", INI::parseFXList, NULL, offsetof( W3DTreeDrawModuleData, m_toppleFX ) },
|
||||
{ "BounceFX", INI::parseFXList, NULL, offsetof( W3DTreeDrawModuleData, m_bounceFX ) },
|
||||
{ "StumpName", INI::parseAsciiString, NULL, offsetof( W3DTreeDrawModuleData, m_stumpName ) },
|
||||
{ "KillWhenFinishedToppling", INI::parseBool, NULL, offsetof( W3DTreeDrawModuleData, m_killWhenToppled ) },
|
||||
{ "DoTopple", INI::parseBool, NULL, offsetof( W3DTreeDrawModuleData, m_doTopple ) },
|
||||
{ "InitialVelocityPercent", INI::parsePercentToReal, NULL, offsetof( W3DTreeDrawModuleData, m_initialVelocityPercent ) },
|
||||
{ "InitialAccelPercent", INI::parsePercentToReal, NULL, offsetof( W3DTreeDrawModuleData, m_initialAccelPercent ) },
|
||||
{ "BounceVelocityPercent", INI::parsePercentToReal, NULL, offsetof( W3DTreeDrawModuleData, m_bounceVelocityPercent ) },
|
||||
{ "MinimumToppleSpeed", INI::parsePositiveNonZeroReal, NULL, offsetof( W3DTreeDrawModuleData, m_minimumToppleSpeed ) },
|
||||
{ "SinkDistance", INI::parsePositiveNonZeroReal, NULL, offsetof( W3DTreeDrawModuleData, m_sinkDistance ) },
|
||||
{ "SinkTime", INI::parseDurationUnsignedInt, NULL, offsetof(W3DTreeDrawModuleData, m_sinkFrames) },
|
||||
{ "DoShadow", INI::parseBool, NULL, offsetof( W3DTreeDrawModuleData, m_doShadow ) },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTreeDraw::W3DTreeDraw( Thing *thing, const ModuleData* moduleData ) : DrawModule( thing, moduleData ),
|
||||
m_treeAdded(false)
|
||||
{
|
||||
|
||||
} // end W3DTreeDraw
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTreeDraw::~W3DTreeDraw( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTreeDraw::reactToTransformChange( const Matrix3D *oldMtx,
|
||||
const Coord3D *oldPos,
|
||||
Real oldAngle )
|
||||
{
|
||||
Drawable *draw = getDrawable();
|
||||
if (m_treeAdded) {
|
||||
return;
|
||||
}
|
||||
if (draw->getPosition()->x==0.0f && draw->getPosition()->y == 0.0f) {
|
||||
return;
|
||||
}
|
||||
m_treeAdded = true;
|
||||
const W3DTreeDrawModuleData *moduleData = getW3DTreeDrawModuleData();
|
||||
if (!moduleData) {
|
||||
return;
|
||||
}
|
||||
Real scale = draw->getScale();
|
||||
Real scaleRandomness = draw->getTemplate()->getInstanceScaleFuzziness();
|
||||
scaleRandomness = 0.0f; // We use the scale fuzziness inside WB to generate random scales, so they don't change at load time. jba. [4/22/2003]
|
||||
TheTerrainRenderObject->addTree(draw->getID(), *draw->getPosition(),
|
||||
scale, draw->getOrientation(), scaleRandomness, moduleData);
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTreeDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTreeDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTreeDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
DrawModule::xfer( xfer );
|
||||
|
||||
// no data to save here, nobody will ever notice
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTreeDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
DrawModule::loadPostProcess();
|
||||
|
||||
} // end loadPostProcess
|
||||
|
||||
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTruckDraw.cpp
|
||||
// Draw Trucks. Actually, this draws rocket buggies.
|
||||
// Author: John Ahlquist, March 2002
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "Common/Thing.h"
|
||||
#include "Common/ThingFactory.h"
|
||||
#include "Common/GameAudio.h"
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/Xfer.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/ParticleSys.h"
|
||||
#include "GameLogic/AIPathfind.h"
|
||||
#include "GameLogic/Weapon.h"
|
||||
#include "GameLogic/GameLogic.h" // for logic frame count
|
||||
#include "GameLogic/PartitionManager.h"
|
||||
#include "GameLogic/Locomotor.h"
|
||||
#include "GameLogic/Module/PhysicsUpdate.h"
|
||||
#include "GameLogic/Module/BodyModule.h"
|
||||
#include "GameLogic/Module/AIUpdate.h"
|
||||
#include "GameLogic/ScriptEngine.h"
|
||||
#include "W3DDevice/GameClient/W3DGameClient.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DTruckDraw.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTruckDrawModuleData::W3DTruckDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTruckDrawModuleData::~W3DTruckDrawModuleData()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
|
||||
{
|
||||
W3DModelDrawModuleData::buildFieldParse(p);
|
||||
|
||||
static const FieldParse dataFieldParse[] =
|
||||
{
|
||||
{ "Dust", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_dustEffectName) },
|
||||
{ "DirtSpray", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_dirtEffectName) },
|
||||
{ "PowerslideSpray", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_powerslideEffectName) },
|
||||
|
||||
{ "LeftFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_frontLeftTireBoneName) },
|
||||
{ "RightFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_frontRightTireBoneName) },
|
||||
{ "LeftRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_rearLeftTireBoneName) },
|
||||
{ "RightRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_rearRightTireBoneName) },
|
||||
{ "MidLeftFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_midFrontLeftTireBoneName) },
|
||||
{ "MidRightFrontTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_midFrontRightTireBoneName) },
|
||||
{ "MidLeftRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_midRearLeftTireBoneName) },
|
||||
{ "MidRightRearTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_midRearRightTireBoneName) },
|
||||
{ "MidLeftMidTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_midMidLeftTireBoneName) },
|
||||
{ "MidRightMidTireBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_midMidRightTireBoneName) },
|
||||
|
||||
{ "TireRotationMultiplier", INI::parseReal, NULL, offsetof(W3DTruckDrawModuleData, m_rotationSpeedMultiplier) },
|
||||
{ "PowerslideRotationAddition", INI::parseReal, NULL, offsetof(W3DTruckDrawModuleData, m_powerslideRotationAddition) },
|
||||
{ "CabBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_cabBoneName) },
|
||||
{ "TrailerBone", INI::parseAsciiString, NULL, offsetof(W3DTruckDrawModuleData, m_trailerBoneName) },
|
||||
{ "CabRotationMultiplier", INI::parseReal, NULL, offsetof(W3DTruckDrawModuleData, m_cabRotationFactor) },
|
||||
{ "TrailerRotationMultiplier", INI::parseReal, NULL, offsetof(W3DTruckDrawModuleData, m_trailerRotationFactor) },
|
||||
{ "RotationDamping", INI::parseReal, NULL, offsetof(W3DTruckDrawModuleData, m_rotationDampingFactor) },
|
||||
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
p.add(dataFieldParse);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTruckDraw::W3DTruckDraw( Thing *thing, const ModuleData* moduleData ) : W3DModelDraw( thing, moduleData ),
|
||||
m_dirtEffect(NULL), m_dustEffect(NULL), m_powerslideEffect(NULL), m_effectsInitialized(false),
|
||||
m_wasAirborne(false), m_isPowersliding(false),
|
||||
m_frontWheelRotation(0), m_rearWheelRotation(0), m_midFrontWheelRotation(0), m_midRearWheelRotation(0),
|
||||
m_frontRightTireBone(0), m_frontLeftTireBone(0), m_rearLeftTireBone(0),m_rearRightTireBone(0),
|
||||
m_midFrontRightTireBone(0), m_midFrontLeftTireBone(0), m_midRearLeftTireBone(0),m_midRearRightTireBone(0),
|
||||
m_midMidRightTireBone(0), m_midMidLeftTireBone(0), m_prevRenderObj(NULL)
|
||||
{
|
||||
const AudioEventRTS * event;
|
||||
event = thing->getTemplate()->getPerUnitSound("TruckLandingSound");
|
||||
if (event) {
|
||||
m_landingSound = *event;
|
||||
}
|
||||
event = thing->getTemplate()->getPerUnitSound("TruckPowerslideSound");
|
||||
if (event) {
|
||||
m_powerslideSound = *event;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DTruckDraw::~W3DTruckDraw()
|
||||
{
|
||||
tossEmitters();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::tossEmitters()
|
||||
{
|
||||
if (m_dustEffect)
|
||||
{
|
||||
m_dustEffect->attachToObject(NULL);
|
||||
m_dustEffect->destroy();
|
||||
m_dustEffect = NULL;
|
||||
}
|
||||
if (m_dirtEffect)
|
||||
{
|
||||
m_dirtEffect->attachToObject(NULL);
|
||||
m_dirtEffect->destroy();
|
||||
m_dirtEffect = NULL;
|
||||
}
|
||||
if (m_powerslideEffect)
|
||||
{
|
||||
m_powerslideEffect->attachToObject(NULL);
|
||||
m_powerslideEffect->destroy();
|
||||
m_powerslideEffect = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::setFullyObscuredByShroud(Bool fullyObscured)
|
||||
{
|
||||
if (fullyObscured != getFullyObscuredByShroud())
|
||||
{
|
||||
if (fullyObscured)
|
||||
tossEmitters();
|
||||
else
|
||||
createEmitters();
|
||||
}
|
||||
W3DModelDraw::setFullyObscuredByShroud(fullyObscured);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
|
||||
* Start creating debris from the tank treads
|
||||
*/
|
||||
void W3DTruckDraw::createEmitters( void )
|
||||
{
|
||||
if (getDrawable()->isDrawableEffectivelyHidden())
|
||||
return;
|
||||
if (getW3DTruckDrawModuleData())
|
||||
{
|
||||
const ParticleSystemTemplate *sysTemplate;
|
||||
|
||||
if (!m_dustEffect) {
|
||||
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTruckDrawModuleData()->m_dustEffectName);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_dustEffect = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_dustEffect->attachToObject(getDrawable()->getObject());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_dustEffect->setSaveable(FALSE);
|
||||
} else {
|
||||
if (!getW3DTruckDrawModuleData()->m_dustEffectName.isEmpty()) {
|
||||
DEBUG_LOG(("*** ERROR - Missing particle system '%s' in thing '%s'\n",
|
||||
getW3DTruckDrawModuleData()->m_dustEffectName.str(), getDrawable()->getObject()->getTemplate()->getName().str()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!m_dirtEffect) {
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTruckDrawModuleData()->m_dirtEffectName);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_dirtEffect = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_dirtEffect->attachToObject(getDrawable()->getObject());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_dirtEffect->setSaveable(FALSE);
|
||||
} else {
|
||||
if (!getW3DTruckDrawModuleData()->m_dirtEffectName.isEmpty()) {
|
||||
DEBUG_LOG(("*** ERROR - Missing particle system '%s' in thing '%s'\n",
|
||||
getW3DTruckDrawModuleData()->m_dirtEffectName.str(), getDrawable()->getObject()->getTemplate()->getName().str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_powerslideEffect) {
|
||||
sysTemplate = TheParticleSystemManager->findTemplate(getW3DTruckDrawModuleData()->m_powerslideEffectName);
|
||||
if (sysTemplate)
|
||||
{
|
||||
m_powerslideEffect = TheParticleSystemManager->createParticleSystem( sysTemplate );
|
||||
m_powerslideEffect->attachToObject(getDrawable()->getObject());
|
||||
// important: mark it as do-not-save, since we'll just re-create it when we reload.
|
||||
m_powerslideEffect->setSaveable(FALSE);
|
||||
} else {
|
||||
if (!getW3DTruckDrawModuleData()->m_powerslideEffectName.isEmpty()) {
|
||||
DEBUG_LOG(("*** ERROR - Missing particle system '%s' in thing '%s'\n",
|
||||
getW3DTruckDrawModuleData()->m_powerslideEffectName.str(), getDrawable()->getObject()->getTemplate()->getName().str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Stop creating debris from the tank treads
|
||||
*/
|
||||
void W3DTruckDraw::enableEmitters( Bool enable )
|
||||
{
|
||||
// don't check... if we are hidden the first time thru, then we'll never create the emitters.
|
||||
// eg, if we are loading a game and the unit is in a tunnel, he'll never get emitteres even when he exits.
|
||||
//if (!m_effectsInitialized)
|
||||
{
|
||||
createEmitters();
|
||||
m_effectsInitialized=true;
|
||||
}
|
||||
if (m_dustEffect)
|
||||
{
|
||||
if (enable)
|
||||
m_dustEffect->start();
|
||||
else
|
||||
m_dustEffect->stop();
|
||||
}
|
||||
if (m_dirtEffect)
|
||||
{
|
||||
if (enable)
|
||||
m_dirtEffect->start();
|
||||
else
|
||||
m_dirtEffect->stop();
|
||||
}
|
||||
if (m_powerslideEffect)
|
||||
{
|
||||
if (!enable)
|
||||
m_powerslideEffect->stop();
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::updateBones( void )
|
||||
{
|
||||
if( getW3DTruckDrawModuleData() )
|
||||
{
|
||||
//Front tires
|
||||
if( !getW3DTruckDrawModuleData()->m_frontLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_frontLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_frontLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_frontLeftTireBone, ("Missing front-left tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_frontLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
}
|
||||
|
||||
if( !getW3DTruckDrawModuleData()->m_frontRightTireBoneName.isEmpty() )
|
||||
{
|
||||
m_frontRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_frontRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_frontRightTireBone, ("Missing front-right tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_frontRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
}
|
||||
|
||||
//Rear tires
|
||||
if( !getW3DTruckDrawModuleData()->m_rearLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_rearLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_rearLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_rearLeftTireBone, ("Missing rear-left tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_rearLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
}
|
||||
|
||||
if( !getW3DTruckDrawModuleData()->m_rearRightTireBoneName.isEmpty() )
|
||||
{
|
||||
m_rearRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_rearRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_rearRightTireBone, ("Missing rear-left tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_rearRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
}
|
||||
|
||||
//midFront tires
|
||||
if( !getW3DTruckDrawModuleData()->m_midFrontLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_midFrontLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_midFrontLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midFrontLeftTireBone, ("Missing mid-front-left tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_midFrontLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_midFrontRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_midFrontRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midFrontRightTireBone, ("Missing mid-front-right tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_midFrontRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_midFrontRightTireBone )
|
||||
{
|
||||
m_midFrontLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//midRear tires
|
||||
if( !getW3DTruckDrawModuleData()->m_midRearLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_midRearLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_midRearLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midRearLeftTireBone, ("Missing mid-rear-left tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_midRearLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_midRearRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_midRearRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midRearRightTireBone, ("Missing mid-rear-right tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_midRearRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_midRearRightTireBone)
|
||||
{
|
||||
m_midRearLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//midMid tires
|
||||
if( !getW3DTruckDrawModuleData()->m_midMidLeftTireBoneName.isEmpty() )
|
||||
{
|
||||
m_midMidLeftTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_midMidLeftTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midMidLeftTireBone, ("Missing mid-mid-left tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_midMidLeftTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
m_midMidRightTireBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_midMidRightTireBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_midMidRightTireBone, ("Missing mid-mid-right tire bone %s in model %s\n", getW3DTruckDrawModuleData()->m_midMidRightTireBoneName.str(), getRenderObject()->Get_Name()));
|
||||
|
||||
if (!m_midMidRightTireBone)
|
||||
{
|
||||
m_midMidLeftTireBone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Cab
|
||||
if( !getW3DTruckDrawModuleData()->m_cabBoneName.isEmpty() )
|
||||
{
|
||||
m_cabBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_cabBoneName.str());
|
||||
DEBUG_ASSERTCRASH(m_cabBone, ("Missing cab bone %s in model %s\n", getW3DTruckDrawModuleData()->m_cabBoneName.str(), getRenderObject()->Get_Name()));
|
||||
m_trailerBone = getRenderObject()->Get_Bone_Index(getW3DTruckDrawModuleData()->m_trailerBoneName.str());
|
||||
}
|
||||
}
|
||||
|
||||
m_prevRenderObj = getRenderObject();
|
||||
m_prevNumBones = m_prevRenderObj->Get_Num_Bones();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::setHidden(Bool h)
|
||||
{
|
||||
W3DModelDraw::setHidden(h);
|
||||
if (h)
|
||||
{
|
||||
enableEmitters(false);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::onRenderObjRecreated(void)
|
||||
{
|
||||
//DEBUG_LOG(("Old obj %x, newObj %x, new bones %d, old bones %d\n",
|
||||
// m_prevRenderObj, getRenderObject(), getRenderObject()->Get_Num_Bones(),
|
||||
// m_prevNumBones));
|
||||
m_prevRenderObj = NULL;
|
||||
m_frontLeftTireBone = 0;
|
||||
m_frontRightTireBone = 0;
|
||||
m_rearLeftTireBone = 0;
|
||||
m_rearRightTireBone = 0;
|
||||
m_midFrontLeftTireBone = 0;
|
||||
m_midFrontRightTireBone = 0;
|
||||
m_midRearLeftTireBone = 0;
|
||||
m_midRearRightTireBone = 0;
|
||||
m_midMidLeftTireBone = 0;
|
||||
m_midMidRightTireBone = 0;
|
||||
updateBones();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Rotate and position wheels and other truck parts. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::doDrawModule(const Matrix3D* transformMtx)
|
||||
{
|
||||
|
||||
W3DModelDraw::doDrawModule(transformMtx);
|
||||
|
||||
if (!TheGlobalData->m_showClientPhysics)
|
||||
return;
|
||||
const W3DTruckDrawModuleData *moduleData = getW3DTruckDrawModuleData();
|
||||
if (moduleData==NULL) return; // shouldn't ever happen.
|
||||
|
||||
Bool frozen = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
|
||||
frozen = frozen || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
|
||||
if (frozen)
|
||||
return;
|
||||
|
||||
const Real ACCEL_THRESHOLD = 0.01f;
|
||||
const Real SIZE_CAP = 2.0f;
|
||||
// get object from logic
|
||||
Object *obj = getDrawable()->getObject();
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
if (getRenderObject()==NULL) return;
|
||||
if (getRenderObject() != m_prevRenderObj) {
|
||||
DEBUG_LOG(("W3DTruckDraw::doDrawModule - shouldn't update bones. jba\n"));
|
||||
updateBones();
|
||||
}
|
||||
|
||||
// get object physics state
|
||||
PhysicsBehavior *physics = obj->getPhysics();
|
||||
if (physics == NULL)
|
||||
return;
|
||||
|
||||
const Coord3D *vel = physics->getVelocity();
|
||||
Real speed = physics->getVelocityMagnitude();
|
||||
|
||||
const TWheelInfo *wheelInfo = getDrawable()->getWheelInfo(); // note, can return null!
|
||||
AIUpdateInterface *ai = obj->getAI();
|
||||
if (m_cabBone && wheelInfo) {
|
||||
Matrix3D cabXfrm(1);
|
||||
cabXfrm.Make_Identity();
|
||||
Real desiredAngle = wheelInfo->m_wheelAngle*moduleData->m_cabRotationFactor;
|
||||
|
||||
// Check goal angle.
|
||||
if (ai && ai->getPath())
|
||||
{
|
||||
Coord3D pointOnPath;
|
||||
ai->getPath()->peekCachedPointOnPath(pointOnPath);
|
||||
Real angleToGoal = ThePartitionManager->getRelativeAngle2D( obj, &pointOnPath );
|
||||
//DEBUG_LOG(("To goal %f, desired %f ", 180*angleToGoal/PI, 180*desiredAngle/PI));
|
||||
if (angleToGoal<0) {
|
||||
if (desiredAngle<angleToGoal) desiredAngle=angleToGoal;
|
||||
if (desiredAngle>0) desiredAngle = 0;
|
||||
} else {
|
||||
if (desiredAngle>angleToGoal) desiredAngle = angleToGoal;
|
||||
if (desiredAngle<0) desiredAngle = 0;
|
||||
}
|
||||
//DEBUG_LOG(("final desired %f ", 180*desiredAngle/PI));
|
||||
}
|
||||
|
||||
Real deltaAngle = desiredAngle - m_curCabRotation;
|
||||
deltaAngle *= moduleData->m_rotationDampingFactor;
|
||||
m_curCabRotation += deltaAngle;
|
||||
cabXfrm.Rotate_Z(m_curCabRotation);
|
||||
getRenderObject()->Capture_Bone( m_cabBone );
|
||||
getRenderObject()->Control_Bone( m_cabBone, cabXfrm );
|
||||
if (m_trailerBone && wheelInfo) {
|
||||
desiredAngle = -wheelInfo->m_wheelAngle*moduleData->m_trailerRotationFactor;
|
||||
Real deltaAngle = desiredAngle - m_curTrailerRotation;
|
||||
deltaAngle *= moduleData->m_rotationDampingFactor;
|
||||
m_curTrailerRotation += deltaAngle;
|
||||
cabXfrm.Make_Identity();
|
||||
cabXfrm.Rotate_Z(m_curTrailerRotation);
|
||||
getRenderObject()->Capture_Bone( m_trailerBone );
|
||||
getRenderObject()->Control_Bone( m_trailerBone, cabXfrm );
|
||||
}
|
||||
}
|
||||
|
||||
if (m_frontLeftTireBone || m_rearLeftTireBone)
|
||||
{
|
||||
Real powerslideRotationAddition = moduleData->m_powerslideRotationAddition;
|
||||
if (ai) {
|
||||
Locomotor *loco = ai->getCurLocomotor();
|
||||
if (loco) {
|
||||
if (loco->isMovingBackwards()) {
|
||||
speed = -speed; // rotate wheels backwards. jba.
|
||||
powerslideRotationAddition = -powerslideRotationAddition;
|
||||
}
|
||||
}
|
||||
}
|
||||
const Real rotationFactor = moduleData->m_rotationSpeedMultiplier;
|
||||
m_frontWheelRotation += rotationFactor*speed;
|
||||
if (m_isPowersliding)
|
||||
{
|
||||
m_rearWheelRotation += rotationFactor*(speed + powerslideRotationAddition);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rearWheelRotation += rotationFactor*speed;
|
||||
}
|
||||
|
||||
// For now, just use the same values for mid wheels -- may want to do independent calcs later...
|
||||
m_midFrontWheelRotation = m_frontWheelRotation;
|
||||
m_midRearWheelRotation = m_rearWheelRotation;
|
||||
|
||||
Matrix3D wheelXfrm(1);
|
||||
|
||||
|
||||
|
||||
if (m_frontLeftTireBone && wheelInfo)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontLeftHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_frontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_frontLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_frontLeftTireBone, wheelXfrm );
|
||||
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontRightHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_frontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_frontRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_frontRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_rearLeftTireBone && wheelInfo)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_rearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearLeftHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_rearLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_rearLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_rearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearRightHeightOffset);
|
||||
|
||||
//@todo TROUBLE HERE, THE BONE INDICES DO NOT MATCH THE RENDEROBJECTS BONES, SOMETIMES
|
||||
|
||||
getRenderObject()->Capture_Bone( m_rearRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_rearRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_midFrontLeftTireBone && wheelInfo)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontLeftHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_midFrontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_midFrontLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_midFrontLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_frontRightHeightOffset);
|
||||
wheelXfrm.Rotate_Z(wheelInfo->m_wheelAngle);
|
||||
wheelXfrm.Rotate_Y(m_midFrontWheelRotation);
|
||||
getRenderObject()->Capture_Bone( m_midFrontRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_midFrontRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_midRearLeftTireBone && wheelInfo)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_midRearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearLeftHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_midRearLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_midRearLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_midRearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearRightHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_midRearRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_midRearRightTireBone, wheelXfrm );
|
||||
}
|
||||
if (m_midMidLeftTireBone && wheelInfo)
|
||||
{
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_midRearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearLeftHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_midMidLeftTireBone );
|
||||
getRenderObject()->Control_Bone( m_midMidLeftTireBone, wheelXfrm );
|
||||
|
||||
wheelXfrm.Make_Identity();
|
||||
wheelXfrm.Rotate_Y(m_midRearWheelRotation);
|
||||
wheelXfrm.Adjust_Z_Translation(wheelInfo->m_rearRightHeightOffset);
|
||||
getRenderObject()->Capture_Bone( m_midMidRightTireBone );
|
||||
getRenderObject()->Control_Bone( m_midMidRightTireBone, wheelXfrm );
|
||||
}
|
||||
}
|
||||
|
||||
Bool wasPowersliding = m_isPowersliding;
|
||||
m_isPowersliding = false;
|
||||
if (physics->isMotive() && !obj->isSignificantlyAboveTerrain()) {
|
||||
enableEmitters(true);
|
||||
Coord3D accel = *physics->getAcceleration();
|
||||
accel.z = 0; // ignore gravitational force.
|
||||
Bool accelerating = accel.length()>ACCEL_THRESHOLD;
|
||||
//DEBUG_LOG(("Accel %f, speed %f\n", accel.length(), speed));
|
||||
if (accelerating) {
|
||||
Real dot = accel.x*vel->x + accel.y*vel->y;
|
||||
if (dot<0) {
|
||||
accelerating = false; // decelerating, actually.
|
||||
}
|
||||
}
|
||||
if (m_dustEffect) {
|
||||
// Need more dust the faster we go.
|
||||
if (speed>SIZE_CAP) {
|
||||
speed = SIZE_CAP;
|
||||
}
|
||||
m_dustEffect->setSizeMultiplier(speed);
|
||||
}
|
||||
if (m_dirtEffect) {
|
||||
if (wheelInfo && wheelInfo->m_framesAirborne>3) {
|
||||
Real factor = 1 + wheelInfo->m_framesAirborne/16;
|
||||
if (factor>2.0) factor = 2.0;
|
||||
m_dustEffect->setSizeMultiplier(factor*SIZE_CAP);
|
||||
m_dustEffect->trigger();
|
||||
m_landingSound.setObjectID(obj->getID());
|
||||
TheAudio->addAudioEvent(&m_landingSound);
|
||||
} else {
|
||||
if (!accelerating || speed>2.0f) {
|
||||
m_dirtEffect->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_powerslideEffect) {
|
||||
if (physics->getTurning() == TURN_NONE) {
|
||||
m_powerslideEffect->stop();
|
||||
} else {
|
||||
m_isPowersliding = true;
|
||||
m_powerslideEffect->start();
|
||||
}
|
||||
}
|
||||
if (m_dirtEffect) {
|
||||
if (!accelerating || speed>2.0f) {
|
||||
m_dirtEffect->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
enableEmitters(false);
|
||||
|
||||
m_wasAirborne = obj->isSignificantlyAboveTerrain();
|
||||
|
||||
if(!wasPowersliding && m_isPowersliding) {
|
||||
// start sound
|
||||
m_powerslideSound.setObjectID(obj->getID());
|
||||
m_powerslideSound.setPlayingHandle(TheAudio->addAudioEvent(&m_powerslideSound));
|
||||
} else if (wasPowersliding && !m_isPowersliding) {
|
||||
TheAudio->removeAudioEvent(m_powerslideSound.getPlayingHandle());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::crc( Xfer *xfer )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::crc( xfer );
|
||||
|
||||
} // end crc
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer method
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::xfer( xfer );
|
||||
|
||||
// John A and Mark W say there is no data to save here
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DTruckDraw::loadPostProcess( void )
|
||||
{
|
||||
|
||||
// extend base class
|
||||
W3DModelDraw::loadPostProcess();
|
||||
|
||||
// toss any existing ones (no need to re-create; we'll do that on demand)
|
||||
tossEmitters();
|
||||
|
||||
} // end loadPostProcess
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: Heightmap.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: Heightmap.cpp
|
||||
//
|
||||
// Created: Mark W., John Ahlquist, April/May 2001
|
||||
//
|
||||
// Desc: Draw the terrain and scorchmarks in a scene.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "W3DDevice/GameClient/FlatHeightMap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include <texture.h>
|
||||
#include <tri.h>
|
||||
#include <colmath.h>
|
||||
#include <coltest.h>
|
||||
#include <rinfo.h>
|
||||
#include <camera.h>
|
||||
#include <d3dx8core.h>
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/PerfTimer.h"
|
||||
|
||||
#include "GameClient/TerrainVisual.h"
|
||||
#include "GameClient/View.h"
|
||||
#include "GameClient/Water.h"
|
||||
|
||||
#include "GameLogic/AIPathfind.h"
|
||||
#include "GameLogic/TerrainLogic.h"
|
||||
#include "W3DDevice/GameClient/TerrainTex.h"
|
||||
#include "W3DDevice/GameClient/W3DDynamicLight.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "W3DDevice/GameClient/W3DTerrainTracks.h"
|
||||
#include "W3DDevice/GameClient/W3DTerrainBackground.h"
|
||||
#include "W3DDevice/GameClient/W3DBibBuffer.h"
|
||||
#include "W3DDevice/GameClient/W3DTreeBuffer.h"
|
||||
#include "W3DDevice/GameClient/W3DRoadBuffer.h"
|
||||
#include "W3DDevice/GameClient/W3DBridgeBuffer.h"
|
||||
#include "W3DDevice/GameClient/W3DWaypointBuffer.h"
|
||||
#include "W3DDevice/GameClient/W3DCustomEdging.h"
|
||||
#include "W3DDevice/GameClient/WorldHeightMap.h"
|
||||
#include "W3DDevice/GameClient/W3DShaderManager.h"
|
||||
#include "W3DDevice/GameClient/W3DShadow.h"
|
||||
#include "W3DDevice/GameClient/W3DWater.h"
|
||||
#include "W3DDevice/GameClient/W3DShroud.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/Light.h"
|
||||
#include "WW3D2/Scene.h"
|
||||
#include "W3DDevice/GameClient/W3DPoly.h"
|
||||
#include "W3DDevice/GameClient/W3DCustomScene.h"
|
||||
|
||||
#include "Common/PerfTimer.h"
|
||||
#include "Common/UnitTimings.h" //Contains the DO_UNIT_TIMINGS define jba.
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
FlatHeightMapRenderObjClass *TheFlatHeightMap = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//-----------------------------------------------------------------------------
|
||||
#define SC_DETAIL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass detailOpaqueShader(SC_DETAIL_BLEND);
|
||||
|
||||
|
||||
#define DEFAULT_MAX_BATCH_SHORELINE_TILES 512 //maximum number of terrain tiles rendered per call (must fit in one VB)
|
||||
#define DEFAULT_MAX_MAP_SHORELINE_TILES 4096 //default size of array allocated to hold all map shoreline tiles.
|
||||
|
||||
#define ADJUST_FROM_INDEX_TO_REAL(k) ((k-m_map->getBorderSizeInline())*MAP_XY_FACTOR)
|
||||
inline Int IABS(Int x) { if (x>=0) return x; return -x;};
|
||||
|
||||
const Int CELLS_PER_TILE = 16; // In order to be efficient in texture, needs to be a power of 2. [3/24/2003]
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::freeMapResources
|
||||
//=============================================================================
|
||||
/** Frees the w3d resources used to draw the terrain. */
|
||||
//=============================================================================
|
||||
Int FlatHeightMapRenderObjClass::freeMapResources(void)
|
||||
{
|
||||
BaseHeightMapRenderObjClass::freeMapResources();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::~FlatHeightMapRenderObjClass
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
FlatHeightMapRenderObjClass::~FlatHeightMapRenderObjClass(void)
|
||||
{
|
||||
releaseTiles();
|
||||
TheFlatHeightMap = NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::FlatHeightMapRenderObjClass
|
||||
//=============================================================================
|
||||
/** Constructor. Mostly nulls out the member variables. */
|
||||
//=============================================================================
|
||||
FlatHeightMapRenderObjClass::FlatHeightMapRenderObjClass(void):
|
||||
m_tiles(NULL),
|
||||
m_tilesWidth(0),
|
||||
m_tilesHeight(0),
|
||||
m_numTiles(0),
|
||||
m_updateState(STATE_IDLE)
|
||||
{
|
||||
TheFlatHeightMap = this;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::adjustTerrainLOD
|
||||
//=============================================================================
|
||||
/** Adjust the terrain Level Of Detail. If adj > 0 , increases LOD 1 step, if
|
||||
adj < 0 decreases it one step, if adj==0, then just sets up for the current LOD */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::adjustTerrainLOD(Int adj)
|
||||
{
|
||||
BaseHeightMapRenderObjClass::adjustTerrainLOD(adj);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::ReleaseResources
|
||||
//=============================================================================
|
||||
/** Releases all w3d assets, to prepare for Reset device call. */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::ReleaseResources(void)
|
||||
{
|
||||
BaseHeightMapRenderObjClass::ReleaseResources();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::ReAcquireResources
|
||||
//=============================================================================
|
||||
/** Reallocates all W3D assets after a reset.. */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::ReAcquireResources(void)
|
||||
{
|
||||
if (m_map) {
|
||||
Int width = (m_map->getXExtent()+CELLS_PER_TILE-2)/CELLS_PER_TILE;
|
||||
Int height = (m_map->getYExtent()+CELLS_PER_TILE-2)/CELLS_PER_TILE;
|
||||
Int i, j;
|
||||
Int numTiles = width*height;
|
||||
m_tiles = new W3DTerrainBackground[numTiles];
|
||||
m_numTiles = numTiles;
|
||||
m_tilesWidth = width;
|
||||
m_tilesHeight = height;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->allocateTerrainBuffers(m_map, i*CELLS_PER_TILE, j*CELLS_PER_TILE, CELLS_PER_TILE);
|
||||
tile->setFlip(m_map);
|
||||
}
|
||||
}
|
||||
IRegion2D range;
|
||||
range.lo.x = 0;
|
||||
range.lo.y = 0;
|
||||
range.hi.x = m_map->getXExtent();
|
||||
range.hi.y = m_map->getYExtent();
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->doPartialUpdate(range, m_map, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
BaseHeightMapRenderObjClass::ReAcquireResources();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::reset
|
||||
//=============================================================================
|
||||
/** Updates the macro noise/lightmap texture (pass 3) */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::reset(void)
|
||||
{
|
||||
BaseHeightMapRenderObjClass::reset();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::oversizeTerrain
|
||||
//=============================================================================
|
||||
/** Sets the terrain oversize amount. */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::oversizeTerrain(Int tilesToOversize)
|
||||
{
|
||||
// Not needed with flat version. [3/20/2003]
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// HeightMapRenderObjClass::doPartialUpdate
|
||||
//=============================================================================
|
||||
/** Updates a partial block of vertices from [x0,y0 to x1,y1]
|
||||
The coordinates in partialRange are map cell coordinates, relative to the entire map.
|
||||
The vertex coordinates and texture coordinates, as well as static lighting are updated.
|
||||
*/
|
||||
void FlatHeightMapRenderObjClass::doPartialUpdate(const IRegion2D &partialRange, WorldHeightMap *htMap, RefRenderObjListIterator *pLightsIterator)
|
||||
{
|
||||
if (htMap) {
|
||||
REF_PTR_SET(m_map, htMap);
|
||||
}
|
||||
Int i, j;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->doPartialUpdate(partialRange, htMap, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::releaseTiles
|
||||
//=============================================================================
|
||||
/** Releases tiles.*/
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::releaseTiles(void)
|
||||
{
|
||||
if (m_tiles) {
|
||||
delete [] m_tiles;
|
||||
m_tiles = NULL;
|
||||
}
|
||||
m_tilesWidth = 0;
|
||||
m_tilesHeight = 0;
|
||||
m_numTiles = 0;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::initHeightData
|
||||
//=============================================================================
|
||||
/** Allocate a heightmap of x by y vertices and fill with initial height values.
|
||||
Also allocates all rendering resources such as vertex buffers, index buffers,
|
||||
shaders, and materials.*/
|
||||
//=============================================================================
|
||||
Int FlatHeightMapRenderObjClass::initHeightData(Int x, Int y, WorldHeightMap *pMap, RefRenderObjListIterator *pLightsIterator, Bool updateExtraPassTiles)
|
||||
{
|
||||
|
||||
BaseHeightMapRenderObjClass::initHeightData(x, y, pMap, pLightsIterator);
|
||||
|
||||
Int width = (pMap->getXExtent()+CELLS_PER_TILE-2)/CELLS_PER_TILE;
|
||||
Int height = (pMap->getYExtent()+CELLS_PER_TILE-2)/CELLS_PER_TILE;
|
||||
|
||||
Int numTiles = width*height;
|
||||
|
||||
Int i, j;
|
||||
pMap->clearFlipStates();
|
||||
if (m_tiles && m_tilesWidth==width && m_tilesHeight==height) {
|
||||
// current allocation matches. Just redo vertex & index buffers. [3/21/2003]
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->setFlip(pMap);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
releaseTiles();
|
||||
m_tiles = new W3DTerrainBackground[numTiles];
|
||||
m_numTiles = numTiles;
|
||||
m_tilesWidth = width;
|
||||
m_tilesHeight = height;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->allocateTerrainBuffers(pMap, i*CELLS_PER_TILE, j*CELLS_PER_TILE, CELLS_PER_TILE);
|
||||
tile->setFlip(pMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
IRegion2D range;
|
||||
range.lo.x = 0;
|
||||
range.lo.y = 0;
|
||||
range.hi.x = pMap->getXExtent();
|
||||
range.hi.y = pMap->getYExtent();
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->doPartialUpdate(range, pMap, true);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::On_Frame_Update
|
||||
//=============================================================================
|
||||
/** Updates the diffuse color values in the vertices as affected by the dynamic lights.*/
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::On_Frame_Update(void)
|
||||
{
|
||||
#ifdef DO_UNIT_TIMINGS
|
||||
#pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
|
||||
return;
|
||||
#endif
|
||||
|
||||
BaseHeightMapRenderObjClass::On_Frame_Update();
|
||||
|
||||
switch(m_updateState) {
|
||||
case STATE_IDLE: return;
|
||||
case STATE_MOVING : m_updateState = STATE_MOVING2; return;
|
||||
case STATE_MOVING2: {
|
||||
Int i, j;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->updateTexture();
|
||||
}
|
||||
}
|
||||
m_updateState = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::staticLightingChanged
|
||||
//=============================================================================
|
||||
/** Notification that all lighting needs to be recalculated. */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::staticLightingChanged( void )
|
||||
{
|
||||
BaseHeightMapRenderObjClass::staticLightingChanged();
|
||||
if (m_map==NULL) {
|
||||
return;
|
||||
}
|
||||
Int i, j;
|
||||
IRegion2D bounds;
|
||||
bounds.lo.x = 0;
|
||||
bounds.lo.y = 0;
|
||||
bounds.hi.x = m_tilesWidth*CELLS_PER_TILE;
|
||||
bounds.hi.y = m_tilesHeight*CELLS_PER_TILE;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->doPartialUpdate(bounds, m_map, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::updateCenter
|
||||
//=============================================================================
|
||||
/** Updates the positioning of the drawn portion of the height map in the
|
||||
heightmap. As the view slides around, this determines what is the actually
|
||||
rendered portion of the terrain. Only a 96x96 section is rendered at any time,
|
||||
even though maps can be up to 1024x1024. This function determines which subset
|
||||
is rendered. */
|
||||
//=============================================================================
|
||||
void FlatHeightMapRenderObjClass::updateCenter(CameraClass *camera , RefRenderObjListIterator *pLightsIterator)
|
||||
{
|
||||
#ifdef DO_UNIT_TIMINGS
|
||||
#pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
|
||||
return;
|
||||
#endif
|
||||
BaseHeightMapRenderObjClass::updateCenter(camera, pLightsIterator);
|
||||
m_needFullUpdate = false;
|
||||
Int i, j;
|
||||
Int culled = 0;
|
||||
static Int prevCulled = 0;
|
||||
Int t2X = 0;
|
||||
static Int prevT2X = 0;
|
||||
Int t4X = 0;
|
||||
static Int prevT4X = 0;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
tile->updateCenter(camera);
|
||||
if (tile->isCulled()) {
|
||||
culled++;
|
||||
}
|
||||
Int tx = tile->getTexMultiplier();
|
||||
if (tx==4) {
|
||||
t4X++;
|
||||
} else if (tx==2) {
|
||||
t2X++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (culled!=prevCulled || t4X!=prevT4X || t2X!=prevT2X) {
|
||||
DEBUG_LOG(("%d of %d culled, %d 4X, %d 2X.\n", culled, m_numTiles, t4X, t2X));
|
||||
prevCulled = culled;
|
||||
prevT2X = t2X;
|
||||
prevT4X = t4X;
|
||||
}
|
||||
m_updateState = STATE_MOVING;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FlatHeightMapRenderObjClass::Render
|
||||
//=============================================================================
|
||||
/** Renders (draws) the terrain. */
|
||||
//=============================================================================
|
||||
//DECLARE_PERF_TIMER(Terrain_Render)
|
||||
|
||||
void FlatHeightMapRenderObjClass::Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
//USE_PERF_TIMER(Terrain_Render)
|
||||
|
||||
Int devicePasses;
|
||||
W3DShaderManager::ShaderTypes st;
|
||||
Bool doCloud = TheGlobalData->m_useCloudMap;
|
||||
|
||||
Matrix3D tm(Transform);
|
||||
// If there are trees, tell them to draw at the transparent time to draw.
|
||||
if (m_treeBuffer) {
|
||||
m_treeBuffer->setIsTerrain();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DO_UNIT_TIMINGS
|
||||
#pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef EXTENDED_STATS
|
||||
if (DX8Wrapper::stats.m_disableTerrain) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
DX8Wrapper::Set_Light_Environment(rinfo.light_environment);
|
||||
|
||||
// Force shaders to update.
|
||||
m_stageTwoTexture->restore();
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
DX8Wrapper::Set_Texture(1,NULL);
|
||||
ShaderClass::Invalidate();
|
||||
|
||||
// tm.Scale(ObjSpaceExtent);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
|
||||
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
DX8Wrapper::Set_Shader(m_shaderClass);
|
||||
|
||||
if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) {
|
||||
doCloud = false;
|
||||
}
|
||||
|
||||
st=W3DShaderManager::ST_FLAT_TERRAIN_BASE; //set default shader
|
||||
|
||||
//set correct shader based on current settings
|
||||
if (TheGlobalData->m_useLightMap && doCloud)
|
||||
{ st=W3DShaderManager::ST_FLAT_TERRAIN_BASE_NOISE12;
|
||||
}
|
||||
else
|
||||
if (TheGlobalData->m_useLightMap)
|
||||
{ //lightmap only
|
||||
st=W3DShaderManager::ST_FLAT_TERRAIN_BASE_NOISE2;
|
||||
}
|
||||
else
|
||||
if (doCloud)
|
||||
{ //cloudmap only
|
||||
st=W3DShaderManager::ST_FLAT_TERRAIN_BASE_NOISE1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Find number of passes required to render current shader
|
||||
devicePasses=W3DShaderManager::getShaderPasses(st);
|
||||
|
||||
if (m_disableTextures)
|
||||
devicePasses=1; //force to 1 lighting-only pass
|
||||
|
||||
//Specify all textures that this shader may need.
|
||||
W3DShaderManager::setTexture(0,m_stageZeroTexture);
|
||||
if (m_shroud && rinfo.Additional_Pass_Count() && !m_disableTextures)
|
||||
{
|
||||
W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture());
|
||||
}
|
||||
|
||||
W3DShaderManager::setTexture(1,NULL); // Set by the tile later. [3/31/2003]
|
||||
W3DShaderManager::setTexture(2,m_stageTwoTexture); //cloud
|
||||
W3DShaderManager::setTexture(3,m_stageThreeTexture);//noise
|
||||
//Disable writes to destination alpha channel (if there is one)
|
||||
if (DX8Wrapper::getBackBufferFormat() == WW3D_FORMAT_A8R8G8B8) {
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
|
||||
}
|
||||
|
||||
Int pass;
|
||||
Int yCoordMax = 0;
|
||||
Int yCoordMin = m_map->getXExtent();
|
||||
Int xCoordMax = 0;
|
||||
Int xCoordMin = m_map->getYExtent();
|
||||
for (pass=0; pass<devicePasses; pass++) {
|
||||
Bool disableTex = m_disableTextures;
|
||||
if (m_disableTextures ) {
|
||||
DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaque2DShader);
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
} else {
|
||||
W3DShaderManager::setShader(st, pass);
|
||||
}
|
||||
|
||||
Int i, j;
|
||||
for (i=0; i<m_tilesWidth; i++) {
|
||||
for (j=0; j<m_tilesHeight; j++) {
|
||||
W3DTerrainBackground *tile = m_tiles+j*m_tilesWidth+i;
|
||||
if (pass>0) {
|
||||
disableTex = TRUE; // doing cloud/noise
|
||||
}
|
||||
if (!tile->isCulled()) {
|
||||
tile->drawVisiblePolys(rinfo, disableTex);
|
||||
if (i*CELLS_PER_TILE<xCoordMin) {
|
||||
xCoordMin = i*CELLS_PER_TILE;
|
||||
}
|
||||
if (j*CELLS_PER_TILE<yCoordMin) {
|
||||
yCoordMin = j*CELLS_PER_TILE;
|
||||
}
|
||||
if ((i+1)*CELLS_PER_TILE>xCoordMax) {
|
||||
xCoordMax = (i+1)*CELLS_PER_TILE;
|
||||
}
|
||||
if ((j+1)*CELLS_PER_TILE>yCoordMax) {
|
||||
yCoordMax = (j+1)*CELLS_PER_TILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pass) //shader was applied at least once?
|
||||
W3DShaderManager::resetShader(st);
|
||||
#if 1
|
||||
|
||||
//Draw feathered shorelines
|
||||
renderShoreLines(&rinfo.Camera);
|
||||
|
||||
#ifdef DO_ROADS
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
DX8Wrapper::Set_Texture(1,NULL);
|
||||
m_stageTwoTexture->restore();
|
||||
|
||||
ShaderClass::Invalidate();
|
||||
if (!ShaderClass::Is_Backface_Culling_Inverted()) {
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
if (Scene) {
|
||||
RTS3DScene *pMyScene = (RTS3DScene *)Scene;
|
||||
RefRenderObjListIterator pDynamicLightsIterator(pMyScene->getDynamicLights());
|
||||
m_roadBuffer->drawRoads(&rinfo.Camera, doCloud?m_stageTwoTexture:NULL, TheGlobalData->m_useLightMap?m_stageThreeTexture:NULL,
|
||||
m_disableTextures,xCoordMin-m_map->getBorderSizeInline(), xCoordMax-m_map->getBorderSizeInline(), yCoordMin-m_map->getBorderSizeInline(), yCoordMax-m_map->getBorderSizeInline(), &pDynamicLightsIterator);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DO_SCORCH
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
DX8Wrapper::Set_Texture(1,NULL);
|
||||
m_stageTwoTexture->restore();
|
||||
|
||||
ShaderClass::Invalidate();
|
||||
if (!ShaderClass::Is_Backface_Culling_Inverted()) {
|
||||
drawScorches();
|
||||
}
|
||||
#endif
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
DX8Wrapper::Set_Texture(1,NULL);
|
||||
m_stageTwoTexture->restore();
|
||||
ShaderClass::Invalidate();
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
m_bridgeBuffer->drawBridges(&rinfo.Camera, m_disableTextures, m_stageTwoTexture);
|
||||
|
||||
if (TheTerrainTracksRenderObjClassSystem)
|
||||
TheTerrainTracksRenderObjClassSystem->flush();
|
||||
|
||||
ShaderClass::Invalidate();
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
m_waypointBuffer->drawWaypoints(rinfo);
|
||||
|
||||
m_bibBuffer->renderBibs();
|
||||
#endif
|
||||
// We do some custom blending, so tell the shader class to reset everything.
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
DX8Wrapper::Set_Texture(1,NULL);
|
||||
m_stageTwoTexture->restore();
|
||||
ShaderClass::Invalidate();
|
||||
DX8Wrapper::Set_Material(NULL);
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DMOTD.cpp //////////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DMOTD.cpp
|
||||
//
|
||||
// Created: Colin Day, August 2001
|
||||
//
|
||||
// Desc: Message of the day
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "Common/NameKeyGenerator.h"
|
||||
#include "GameClient/GameWindow.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/DisplayStringManager.h"
|
||||
#include "GameClient/GadgetSlider.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static NameKeyType closeButtonID = NAMEKEY_INVALID;
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// MOTDSystem =================================================================
|
||||
/** Message of the day */
|
||||
//=============================================================================
|
||||
WindowMsgHandledType MOTDSystem( GameWindow *window, UnsignedInt msg,
|
||||
WindowMsgData mData1, WindowMsgData mData2 )
|
||||
{
|
||||
switch( msg )
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
case GWM_CREATE:
|
||||
{
|
||||
|
||||
// load id's needed
|
||||
closeButtonID = TheNameKeyGenerator->nameToKey( "MOTD.wnd:CloseMOTD" );
|
||||
|
||||
break;
|
||||
|
||||
} // end create
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
case GWM_DESTROY:
|
||||
{
|
||||
|
||||
break;
|
||||
|
||||
} // end case
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
case GBM_SELECTED:
|
||||
{
|
||||
GameWindow *control = (GameWindow *)mData1;
|
||||
Int controlID = control->winGetWindowId();
|
||||
|
||||
if( controlID == closeButtonID )
|
||||
window->winHide( !window->winIsHidden() );
|
||||
|
||||
break;
|
||||
|
||||
} // end selected
|
||||
|
||||
default:
|
||||
return MSG_IGNORED;
|
||||
} // end switch
|
||||
|
||||
return MSG_HANDLED;
|
||||
|
||||
} // end MOTDSystem
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DCheckBox.cpp //////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DCheckBox.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D methods needed to implement the checkbox UI control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GadgetCheckBox.h"
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// drawCheckBoxText ===========================================================
|
||||
/** Draw the text for a checkbox */
|
||||
//=============================================================================
|
||||
static void drawCheckBoxText( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size, textPos;
|
||||
Int width, height;
|
||||
Color textColor, dropColor;
|
||||
DisplayString *text = instData->getTextDisplayString();
|
||||
|
||||
// sanity
|
||||
if( text == NULL || text->getTextLength() == 0 )
|
||||
return;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the right text color
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
dropColor = window->winGetDisabledTextBorderColor();
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
textColor = window->winGetHiliteTextColor();
|
||||
dropColor = window->winGetHiliteTextBorderColor();
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
dropColor = window->winGetEnabledTextBorderColor();
|
||||
} // end enabled only
|
||||
|
||||
// set our font to that of our parent if not the same
|
||||
if( text->getFont() != window->winGetFont() )
|
||||
text->setFont( window->winGetFont() );
|
||||
|
||||
// get text size
|
||||
text->getSize( &width, &height );
|
||||
|
||||
// where to draw
|
||||
textPos.x = origin.x + size.y;//(size.x / 2) - (width / 2);
|
||||
textPos.y = origin.y + (size.y / 2) - (height / 2);
|
||||
|
||||
// draw it
|
||||
text->draw( textPos.x, textPos.y, textColor, dropColor );
|
||||
|
||||
} // end drawCheckBoxText
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetCheckBoxDraw ======================================================
|
||||
/** Draw colored check box using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetCheckBoxDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int checkOffsetFromLeft;
|
||||
Color backColor,
|
||||
backBorder,
|
||||
boxColor,
|
||||
boxBorder;
|
||||
ICoord2D origin, size, start, end;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// compute start of check offset
|
||||
checkOffsetFromLeft = size.x / 16;
|
||||
|
||||
//
|
||||
// get the colors we should be using to draw, see GadgetCheckBox.h
|
||||
// draw appropriate state, see GadgetCheckBox.h for info
|
||||
//
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
// disabled background
|
||||
backColor = GadgetCheckBoxGetDisabledColor( window );
|
||||
backBorder = GadgetCheckBoxGetDisabledBorderColor( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
boxColor = GadgetCheckBoxGetDisabledCheckedBoxColor( window );
|
||||
boxBorder = GadgetCheckBoxGetDisabledCheckedBoxBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = GadgetCheckBoxGetDisabledUncheckedBoxColor( window );
|
||||
boxBorder = GadgetCheckBoxGetDisabledUncheckedBoxBorderColor( window );
|
||||
}
|
||||
|
||||
} // end if
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
// hilited background
|
||||
backColor = GadgetCheckBoxGetHiliteColor( window );
|
||||
backBorder = GadgetCheckBoxGetHiliteBorderColor( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
boxColor = GadgetCheckBoxGetHiliteCheckedBoxColor( window );
|
||||
boxBorder = GadgetCheckBoxGetHiliteCheckedBoxBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = GadgetCheckBoxGetHiliteUncheckedBoxColor( window );
|
||||
boxBorder = GadgetCheckBoxGetHiliteUncheckedBoxBorderColor( window );
|
||||
}
|
||||
|
||||
} // end else if
|
||||
else
|
||||
{
|
||||
|
||||
// enabled background
|
||||
backColor = GadgetCheckBoxGetEnabledColor( window );
|
||||
backBorder = GadgetCheckBoxGetEnabledBorderColor( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
boxColor = GadgetCheckBoxGetEnabledCheckedBoxColor( window );
|
||||
boxBorder = GadgetCheckBoxGetEnabledCheckedBoxBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = GadgetCheckBoxGetEnabledUncheckedBoxColor( window );
|
||||
boxBorder = GadgetCheckBoxGetEnabledUncheckedBoxBorderColor( window );
|
||||
}
|
||||
|
||||
} // end else
|
||||
|
||||
// draw background border
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw the background
|
||||
start.x++;
|
||||
start.y++;
|
||||
end.x--;
|
||||
end.y--;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw box border
|
||||
start.x = origin.x + checkOffsetFromLeft;
|
||||
start.y = origin.y + (size.y / 3);
|
||||
end.x = start.x + (size.y / 3);
|
||||
end.y = start.y + (size.y / 3);
|
||||
TheWindowManager->winOpenRect( boxBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw "x" for button
|
||||
if( boxColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
TheWindowManager->winDrawLine( boxColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
TheWindowManager->winDrawLine( boxColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, end.y, end.x, start.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the button text
|
||||
if( instData->getTextLength() )
|
||||
drawCheckBoxText( window, instData );
|
||||
|
||||
} // end W3DGadgetCheckBoxDraw
|
||||
|
||||
// W3DGadgetCheckBoxImageDraw =================================================
|
||||
/** Draw check box with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetCheckBoxImageDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int checkOffsetFromLeft;
|
||||
const Image *boxImage = NULL;//*backgroundImage = NULL,
|
||||
ICoord2D origin, start, end, size;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// compute screen coords
|
||||
start.x = origin.x + instData->m_imageOffset.x;
|
||||
start.y = origin.y + instData->m_imageOffset.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
|
||||
// compute start of check offset
|
||||
checkOffsetFromLeft = 0;
|
||||
|
||||
//
|
||||
// get the colors we should be using to draw, see GadgetCheckBoxButton.h
|
||||
// draw appropriate state, see GadgetCheckBoxButton.h for info
|
||||
//
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
// disabled background
|
||||
// backgroundImage = GadgetCheckBoxGetDisabledImage( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
boxImage = GadgetCheckBoxGetDisabledCheckedBoxImage( window );
|
||||
else
|
||||
boxImage = GadgetCheckBoxGetDisabledUncheckedBoxImage( window );
|
||||
|
||||
} // end if
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
// hilited background
|
||||
// backgroundImage = GadgetCheckBoxGetHiliteImage( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
boxImage = GadgetCheckBoxGetHiliteCheckedBoxImage( window );
|
||||
else
|
||||
boxImage = GadgetCheckBoxGetHiliteUncheckedBoxImage( window );
|
||||
|
||||
} // end else if
|
||||
else
|
||||
{
|
||||
|
||||
// enabled background
|
||||
// backgroundImage = GadgetCheckBoxGetEnabledImage( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
boxImage = GadgetCheckBoxGetEnabledCheckedBoxImage( window );
|
||||
else
|
||||
boxImage = GadgetCheckBoxGetEnabledUncheckedBoxImage( window );
|
||||
|
||||
} // end else
|
||||
|
||||
// draw background image
|
||||
// if( backgroundImage )
|
||||
// TheWindowManager->winDrawImage( backgroundImage, start.x, start.y,
|
||||
// end.x, end.y );
|
||||
|
||||
// draw the box image
|
||||
if( boxImage )
|
||||
{
|
||||
|
||||
start.x = origin.x + instData->m_imageOffset.x + checkOffsetFromLeft;
|
||||
start.y = origin.y + 3;
|
||||
end.x = start.x + (size.y - 6);
|
||||
end.y = start.y + (size.y - 6);
|
||||
TheWindowManager->winDrawImage( boxImage, start.x, start.y,
|
||||
end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the text
|
||||
if( instData->getTextLength() )
|
||||
drawCheckBoxText( window, instData );
|
||||
|
||||
} // end W3DGadgetCheckBoxImageDraw
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DComboBox.cpp ///////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DComboBox.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation for the Combo box control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetComboBox.h"
|
||||
#include "GameClient/GadgetListBox.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetComboBoxDraw =======================================================
|
||||
/** Draw colored list box using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetComboBoxDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int width, height, fontHeight, x, y;
|
||||
Color background, border, titleColor, titleBorder;
|
||||
// ComboBoxData *combo = (ComboBoxData *)window->winGetUserData();
|
||||
ICoord2D size;
|
||||
DisplayString *title = instData->getTextDisplayString();
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &x, &y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get font height
|
||||
fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
|
||||
|
||||
// alias width and height from size
|
||||
width = size.x;
|
||||
height = size.y;
|
||||
|
||||
// get the right colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
background = GadgetComboBoxGetDisabledColor( window );
|
||||
border = GadgetComboBoxGetDisabledBorderColor( window );
|
||||
titleColor = window->winGetDisabledTextColor();
|
||||
titleBorder = window->winGetDisabledTextBorderColor();
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
background = GadgetComboBoxGetHiliteColor( window );
|
||||
border = GadgetComboBoxGetHiliteBorderColor( window );
|
||||
titleColor = window->winGetHiliteTextColor();
|
||||
titleBorder = window->winGetHiliteTextBorderColor();
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
background = GadgetComboBoxGetEnabledColor( window );
|
||||
border = GadgetComboBoxGetEnabledBorderColor( window );
|
||||
titleColor = window->winGetEnabledTextColor();
|
||||
titleBorder = window->winGetEnabledTextBorderColor();
|
||||
} // end else, enabled
|
||||
|
||||
// Draw the title
|
||||
if( title && title->getTextLength() )
|
||||
{
|
||||
|
||||
// set the font of this text to that of the window if not already
|
||||
if( title->getFont() != window->winGetFont() )
|
||||
title->setFont( window->winGetFont() );
|
||||
|
||||
// draw the text
|
||||
title->draw( x + 1, y, titleColor, titleBorder );
|
||||
|
||||
y += fontHeight + 1;
|
||||
height -= fontHeight + 1;
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the back border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
x, y, x + width, y + height );
|
||||
|
||||
// draw background
|
||||
if( background != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winFillRect( background, WIN_DRAW_LINE_WIDTH,
|
||||
x + 1, y + 1,
|
||||
x + width - 1, y + height - 1 );
|
||||
|
||||
} // end W3DGadgetComboBoxDraw
|
||||
|
||||
// W3DGadgetComboBoxImageDraw ==================================================
|
||||
/** Draw combo box with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetComboBoxImageDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int width, height, x, y;
|
||||
const Image *image;
|
||||
// ComboBoxData *combo = (ComboBoxData *)window->winGetUserData();
|
||||
ICoord2D size;
|
||||
Color titleColor, titleBorder;
|
||||
DisplayString *title = instData->getTextDisplayString();
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &x, &y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// save off width and height so we can change them
|
||||
width = size.x;
|
||||
height = size.y;
|
||||
|
||||
// get the image
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
image = GadgetComboBoxGetDisabledImage( window );
|
||||
titleColor = window->winGetDisabledTextColor();
|
||||
titleBorder = window->winGetDisabledTextBorderColor();
|
||||
}
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
image = GadgetComboBoxGetHiliteImage( window );
|
||||
titleColor = window->winGetHiliteTextColor();
|
||||
titleBorder = window->winGetHiliteTextBorderColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
image = GadgetComboBoxGetEnabledImage( window );
|
||||
titleColor = window->winGetEnabledTextColor();
|
||||
titleBorder = window->winGetEnabledTextBorderColor();
|
||||
}
|
||||
|
||||
// draw the back image
|
||||
if( image )
|
||||
{
|
||||
ICoord2D start, end;
|
||||
|
||||
start.x = x + instData->m_imageOffset.x;
|
||||
start.y = y + instData->m_imageOffset.y;
|
||||
end.x = start.x + width;
|
||||
end.y = start.y + height;
|
||||
TheWindowManager->winDrawImage( image,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// Draw the title
|
||||
if( title && title->getTextLength() )
|
||||
{
|
||||
|
||||
// set font to font of the window if not already
|
||||
if( title->getFont() != window->winGetFont() )
|
||||
title->setFont( window->winGetFont() );
|
||||
|
||||
// draw the text
|
||||
title->draw( x + 1, y, titleColor, titleBorder );
|
||||
|
||||
y += TheWindowManager->winFontHeight( instData->getFont() );
|
||||
height -= TheWindowManager->winFontHeight( instData->getFont() ) + 1;
|
||||
|
||||
} // end if
|
||||
|
||||
|
||||
} // end W3DGadgetComboBoxImageDraw
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: .cpp /////////////////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project:
|
||||
//
|
||||
// File name: .cpp
|
||||
//
|
||||
// Created:
|
||||
//
|
||||
// Desc:
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetSlider.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
// W3DGadgetHorizontalSliderDraw ==============================================
|
||||
/** Draw colored horizontal slider using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetHorizontalSliderDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Color backBorder, backColor;
|
||||
ICoord2D origin, size, start, end;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the right colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
backBorder = GadgetSliderGetDisabledBorderColor( window );
|
||||
backColor = GadgetSliderGetDisabledColor( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
backBorder = GadgetSliderGetHiliteBorderColor( window );
|
||||
backColor = GadgetSliderGetHiliteColor( window );
|
||||
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
|
||||
backBorder = GadgetSliderGetEnabledBorderColor( window );
|
||||
backColor = GadgetSliderGetEnabledColor( window );
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// draw background border and rect over whole control
|
||||
if( backBorder != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
if( backColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = start.x + size.x - 2;
|
||||
end.y = start.y + size.y - 2;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
|
||||
} // end W3DGadgetHorizontalSliderDraw
|
||||
|
||||
// W3DGadgetHorizontalSliderImageDraw =========================================
|
||||
/** Draw horizontal slider with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetHorizontalSliderImageDraw( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
const Image *fillSquare, *blankSquare, *highlightSquare;
|
||||
ICoord2D origin, size, start, end, highlightOffset;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
highlightSquare = GadgetSliderGetHiliteImageLeft( window );
|
||||
blankSquare = GadgetSliderGetDisabledImageRight( window );
|
||||
fillSquare = GadgetSliderGetDisabledImageLeft( window );
|
||||
|
||||
SliderData *s = (SliderData *)window->winGetUserData();
|
||||
|
||||
Real xMulti = INT_TO_REAL(TheDisplay->getWidth()) / 800;
|
||||
|
||||
// figure out how many boxes we draw for this slider
|
||||
Int numBoxes = 0;
|
||||
Int numSelectedBoxes = 0;
|
||||
Int numHighlightBoxes = 0;
|
||||
Int boxWidth = fillSquare->getImageWidth()* xMulti;
|
||||
Int boxPadding = 2;
|
||||
start.x = origin.x;
|
||||
end.x = start.x + boxWidth;
|
||||
Real selectedPercent = (s->position - s->minVal)/INT_TO_REAL((s->maxVal - s->minVal));
|
||||
Int maxSelectedX = origin.x + REAL_TO_INT(selectedPercent * size.x);
|
||||
while(end.x < origin.x + size.x )
|
||||
{
|
||||
if (start.x <= maxSelectedX && end.x < origin.x + size.x && s->position != s->minVal)
|
||||
++numSelectedBoxes;
|
||||
start.x = end.x + boxPadding;
|
||||
end.x = start.x + boxWidth;
|
||||
++numBoxes;
|
||||
}
|
||||
numHighlightBoxes = numBoxes + 1;
|
||||
Int distanceCovered = end.x - origin.x - boxWidth;
|
||||
highlightOffset.x = -(boxWidth + boxPadding)/2;
|
||||
highlightOffset.y = boxWidth/3;
|
||||
Int blankness = size.x - distanceCovered;
|
||||
origin.x += blankness/2;
|
||||
|
||||
Int i;
|
||||
if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
ICoord2D backgroundStart, backgroundEnd;
|
||||
backgroundStart.y = origin.y + highlightOffset.y;
|
||||
backgroundEnd.y = backgroundStart.y + boxWidth + boxPadding;
|
||||
for (i=0; i<numHighlightBoxes; ++i)
|
||||
{
|
||||
backgroundStart.x = origin.x + highlightOffset.x + i*(boxWidth+boxPadding);
|
||||
backgroundEnd.x = backgroundStart.x + boxWidth + boxPadding;
|
||||
TheWindowManager->winDrawImage( highlightSquare,
|
||||
backgroundStart.x, backgroundStart.y,
|
||||
backgroundEnd.x, backgroundEnd.y );
|
||||
}
|
||||
}
|
||||
|
||||
start.y = origin.y;
|
||||
end.y = start.y + boxWidth;
|
||||
for (i=0; i<numSelectedBoxes; ++i)
|
||||
{
|
||||
start.x = origin.x + i*(boxWidth+boxPadding);
|
||||
end.x = start.x + boxWidth;
|
||||
TheWindowManager->winDrawImage( fillSquare,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
}
|
||||
for (i=numSelectedBoxes; i<numBoxes; ++i)
|
||||
{
|
||||
start.x = origin.x + i*(boxWidth+boxPadding);
|
||||
end.x = start.x + boxWidth;
|
||||
TheWindowManager->winDrawImage( blankSquare,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
}
|
||||
}
|
||||
|
||||
// W3DGadgetHorizontalSliderImageDraw =========================================
|
||||
/** Draw horizontal slider with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetHorizontalSliderImageDrawB( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
const Image *fillSquare, *blankSquare, *highlightSquare;//, *progressArrow;
|
||||
ICoord2D origin, size, start, end;
|
||||
Int xOffset, yOffset;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
SliderData *s = (SliderData *)window->winGetUserData();
|
||||
|
||||
Real xMulti = INT_TO_REAL(TheDisplay->getWidth()) / 800;
|
||||
Real yMulti = INT_TO_REAL(TheDisplay->getHeight())/ 600;
|
||||
// get image offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
UnicodeString tooltip, tmp;
|
||||
tooltip.format(L"mult:%g/%g, img offset:%d,%d", xMulti, yMulti, xOffset, yOffset);
|
||||
|
||||
tmp.format(L"\norigin: %d,%d size:%d,%d", origin.x, origin.y, size.x, size.y);
|
||||
tooltip.concat(tmp);
|
||||
|
||||
tmp.format(L"\ns= %d <--> %d, numTicks=%g, pos = %d", s->minVal, s->maxVal, s->numTicks, s->position);
|
||||
tooltip.concat(tmp);
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
highlightSquare = GadgetSliderGetHiliteImageLeft( window );
|
||||
ICoord2D backgroundStart, backgroundEnd;
|
||||
backgroundStart.x = origin.x - (highlightSquare->getImageWidth() * xMulti)/2;
|
||||
backgroundStart.y = origin.y + (highlightSquare->getImageHeight() *yMulti)/3;
|
||||
backgroundEnd.y = backgroundStart.y + highlightSquare->getImageHeight()* yMulti;
|
||||
backgroundEnd.x = backgroundStart.x + highlightSquare->getImageWidth() * xMulti;
|
||||
|
||||
tmp.format(L"\nHighlighted: (%d,%d) -> (%d,%d), step %d/%g, full %d/%d", backgroundStart.x, backgroundStart.y,
|
||||
backgroundEnd.x, backgroundEnd.y, highlightSquare->getImageWidth(), highlightSquare->getImageWidth() * xMulti,
|
||||
origin.x, size.x);
|
||||
tooltip.concat(tmp);
|
||||
|
||||
while(backgroundStart.x < origin.x + size.x)
|
||||
{
|
||||
TheWindowManager->winDrawImage( highlightSquare,
|
||||
backgroundStart.x, backgroundStart.y,
|
||||
backgroundEnd.x, backgroundEnd.y );
|
||||
backgroundStart.x = backgroundEnd.x;
|
||||
backgroundEnd.x = backgroundStart.x + highlightSquare->getImageWidth() * xMulti;
|
||||
}
|
||||
tmp.format(L"\n bsX = %d, beX = %d (%d < %d+%d or %d?)", backgroundStart.x, backgroundEnd.x,
|
||||
backgroundStart.x, origin.x, size.x, origin.x + size.x);
|
||||
tooltip.concat(tmp);
|
||||
}
|
||||
|
||||
fillSquare = GadgetSliderGetDisabledImageLeft( window );
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.y = start.y + fillSquare->getImageHeight() * yMulti;
|
||||
end.x = start.x + fillSquare->getImageWidth()* xMulti;
|
||||
|
||||
tmp.format(L"\ntop: start=%d,%d, end=%d,%d", start.x, start.y, end.x, end.y);
|
||||
tooltip.concat(tmp);
|
||||
|
||||
while(start.x <= origin.x + (s->numTicks * (s->position - s->minVal)) && end.x < origin.x + size.x && s->position != s->minVal)
|
||||
{
|
||||
TheWindowManager->winDrawImage( fillSquare,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x = end.x + 2;
|
||||
end.x = start.x + fillSquare->getImageWidth()* xMulti;
|
||||
|
||||
}
|
||||
|
||||
blankSquare = GadgetSliderGetDisabledImageRight( window );
|
||||
end.x = start.x + blankSquare->getImageWidth()* xMulti;
|
||||
|
||||
while(end.x < origin.x + size.x )
|
||||
{
|
||||
TheWindowManager->winDrawImage( blankSquare,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x = end.x + 2;
|
||||
end.x = start.x + blankSquare->getImageWidth()* xMulti;
|
||||
}
|
||||
|
||||
instData->setTooltipText(tooltip);
|
||||
|
||||
// if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
// {
|
||||
// progressArrow = GadgetSliderGetHiliteImageRight( window );
|
||||
// if(!progressArrow)
|
||||
// return;
|
||||
// Int transPos = (s->numTicks * (s->position - s->minVal)) - progressArrow->getImageWidth() /2;
|
||||
// start.x = origin.x + transPos;
|
||||
// start.y = origin.y + fillSquare->getImageHeight()/3*2;
|
||||
// end.y = start.y + progressArrow->getImageHeight();
|
||||
// end.x = start.x + progressArrow->getImageWidth();
|
||||
// TheWindowManager->winDrawImage( progressArrow,
|
||||
// start.x, start.y,
|
||||
// end.x, end.y );
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// W3DGadgetHorizontalSliderImageDraw =========================================
|
||||
/** Draw horizontal slider with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetHorizontalSliderImageDrawA( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
const Image *leftImageLeft, *rightImageLeft, *centerImageLeft, *smallCenterImageLeft;
|
||||
const Image *leftImageRight, *rightImageRight, *centerImageRight, *smallCenterImageRight;
|
||||
ICoord2D origin, size, start, end;
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
SliderData *s = (SliderData *)window->winGetUserData();
|
||||
Int transPos = (s->numTicks * (s->position - s->minVal)) + HORIZONTAL_SLIDER_THUMB_WIDTH/2;
|
||||
IRegion2D clipLeft, clipRight;
|
||||
|
||||
// get image offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
// get the right images
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
leftImageRight = leftImageLeft = GadgetSliderGetDisabledImageLeft( window );
|
||||
rightImageRight = rightImageLeft = GadgetSliderGetDisabledImageRight( window );
|
||||
// centerImageRight = centerImageLeft = GadgetSliderGetDisabledImageCenter( window );
|
||||
// smallCenterImageRight = smallCenterImageLeft = GadgetSliderGetDisabledImageSmallCenter( window );
|
||||
|
||||
} // end if, disabled
|
||||
else //if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
leftImageLeft = GadgetSliderGetHiliteImageLeft( window );
|
||||
rightImageLeft = GadgetSliderGetHiliteImageRight( window );
|
||||
centerImageLeft = GadgetSliderGetHiliteImageCenter( window );
|
||||
smallCenterImageLeft = GadgetSliderGetHiliteImageSmallCenter( window );
|
||||
|
||||
leftImageRight = GadgetSliderGetEnabledImageLeft( window );
|
||||
rightImageRight = GadgetSliderGetEnabledImageRight( window );
|
||||
centerImageRight = GadgetSliderGetEnabledImageCenter( window );
|
||||
smallCenterImageRight = GadgetSliderGetEnabledImageSmallCenter( window );
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// sanity, we need to have these images to make it look right
|
||||
if( leftImageLeft == NULL || rightImageLeft == NULL ||
|
||||
centerImageLeft == NULL || smallCenterImageLeft == NULL ||
|
||||
leftImageRight == NULL || rightImageRight == NULL ||
|
||||
centerImageRight == NULL || smallCenterImageRight == NULL )
|
||||
return;
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D leftSize, rightSize;
|
||||
leftSize.x = leftImageLeft->getImageWidth();
|
||||
leftSize.y = leftImageLeft->getImageHeight();
|
||||
rightSize.x = rightImageLeft->getImageWidth();
|
||||
rightSize.y = rightImageLeft->getImageHeight();
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D leftEnd, rightStart;
|
||||
leftEnd.x = origin.x + leftSize.x + xOffset;
|
||||
leftEnd.y = origin.y + size.y + yOffset;
|
||||
rightStart.x = origin.x + size.x - rightSize.x + xOffset;
|
||||
rightStart.y = origin.y + size.y - leftSize.y + yOffset;
|
||||
|
||||
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerWidth, pieces;
|
||||
|
||||
// get width we have to draw our repeating center in
|
||||
centerWidth = rightStart.x - leftEnd.x;
|
||||
|
||||
// how many whole repeating pieces will fit in that width
|
||||
pieces = centerWidth / centerImageLeft->getImageWidth();
|
||||
|
||||
// draw the pieces
|
||||
start.x = leftEnd.x;
|
||||
start.y = origin.y + size.y - leftSize.y + yOffset;
|
||||
end.y =origin.y + size.y + yOffset;
|
||||
|
||||
clipLeft.lo.x = origin.x;
|
||||
clipLeft.lo.y = rightStart.y;
|
||||
clipLeft.hi.y = leftEnd.y;
|
||||
clipLeft.hi.x = origin.x + transPos;
|
||||
clipRight.lo.x = origin.x + transPos;
|
||||
clipRight.lo.y = rightStart.y;
|
||||
clipRight.hi.y = leftEnd.y;
|
||||
clipRight.hi.x = origin.x + size.x;
|
||||
|
||||
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + centerImageLeft->getImageWidth();
|
||||
TheDisplay->setClipRegion(&clipLeft);
|
||||
TheWindowManager->winDrawImage( centerImageLeft,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
TheDisplay->setClipRegion(&clipRight);
|
||||
TheWindowManager->winDrawImage( centerImageRight,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += centerImageLeft->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
//
|
||||
// how many small repeating pieces will fit in the gap from where the
|
||||
// center repeating bar stopped and the right image, draw them
|
||||
// and overlapping underneath where the right end will go
|
||||
//
|
||||
centerWidth = rightStart.x - start.x;
|
||||
pieces = centerWidth / smallCenterImageLeft->getImageWidth() + 1;
|
||||
end.y = leftEnd.y;//start.y + smallCenterImageLeft->getImageHeight();
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + smallCenterImageLeft->getImageWidth();
|
||||
TheDisplay->setClipRegion(&clipLeft);
|
||||
TheWindowManager->winDrawImage( smallCenterImageLeft,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
TheDisplay->setClipRegion(&clipRight);
|
||||
TheWindowManager->winDrawImage( smallCenterImageRight,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += smallCenterImageLeft->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
// draw left end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = rightStart.y;
|
||||
end = leftEnd;
|
||||
TheDisplay->setClipRegion(&clipLeft);
|
||||
TheWindowManager->winDrawImage(leftImageLeft, start.x, start.y, end.x, end.y);
|
||||
TheDisplay->setClipRegion(&clipRight);
|
||||
TheWindowManager->winDrawImage(leftImageRight, start.x, start.y, end.x, end.y);
|
||||
// draw right end
|
||||
start = rightStart;
|
||||
end.x = start.x + rightSize.x;
|
||||
end.y = leftEnd.y;
|
||||
TheDisplay->setClipRegion(&clipLeft);
|
||||
TheWindowManager->winDrawImage(rightImageLeft, start.x, start.y, end.x, end.y);
|
||||
TheDisplay->setClipRegion(&clipRight);
|
||||
TheWindowManager->winDrawImage(rightImageRight, start.x, start.y, end.x, end.y);
|
||||
|
||||
TheDisplay->enableClipping(FALSE);
|
||||
} // end W3DGadgetHorizontalSliderImageDraw
|
||||
|
||||
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// FILE: W3DListBox.cpp ///////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DListBox.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation for the list box control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetListBox.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// drawHiliteBar ==============================================================
|
||||
/** Draw image for the hilite bar */
|
||||
//=============================================================================
|
||||
static void drawHiliteBar( const Image *left, const Image *right,
|
||||
const Image *center, const Image *smallCenter,
|
||||
Int startX, Int startY,
|
||||
Int endX, Int endY )
|
||||
{
|
||||
ICoord2D barWindowSize; // end point of bar from window origin
|
||||
Int xOffset = 0, yOffset = 0; // incase we want this functionality later
|
||||
ICoord2D start, end;
|
||||
Int i;
|
||||
IRegion2D clipRegion;
|
||||
|
||||
|
||||
|
||||
barWindowSize.x = endX - startX;
|
||||
barWindowSize.y = endY - startY;
|
||||
|
||||
//
|
||||
// the bar window size will always be at least big enough to accomodate
|
||||
// the left and right ends
|
||||
//
|
||||
if( barWindowSize.x < left->getImageWidth() + right->getImageWidth() )
|
||||
barWindowSize.x = left->getImageWidth() + right->getImageWidth();
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D leftSize, rightSize;
|
||||
leftSize.x = left->getImageWidth();
|
||||
leftSize.y = left->getImageHeight();
|
||||
rightSize.x = right->getImageWidth();
|
||||
rightSize.y = right->getImageHeight();
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D leftEnd, rightStart;
|
||||
leftEnd.x = startX + leftSize.x + xOffset;
|
||||
leftEnd.y = startY + barWindowSize.y + yOffset;
|
||||
rightStart.x = startX + barWindowSize.x - rightSize.x + xOffset;
|
||||
rightStart.y = startY + yOffset;
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerWidth, pieces;
|
||||
|
||||
// get width we have to draw our repeating center in
|
||||
centerWidth = rightStart.x - leftEnd.x;
|
||||
|
||||
// how many whole repeating pieces will fit in that width
|
||||
pieces = centerWidth / center->getImageWidth();
|
||||
|
||||
|
||||
|
||||
// draw the pieces
|
||||
start.x = leftEnd.x;
|
||||
start.y = startY + yOffset;
|
||||
end.y = start.y + barWindowSize.y;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + center->getImageWidth();
|
||||
TheWindowManager->winDrawImage( center,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += center->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
//
|
||||
// how many small repeating pieces will fit in the gap from where the
|
||||
// center repeating bar stopped and the right image, draw them
|
||||
// and overlapping underneath where the right end will go
|
||||
//
|
||||
// set the text clip region to the outline of the listbox
|
||||
clipRegion.lo.x = leftEnd.x;
|
||||
clipRegion.lo.y = startY + yOffset;
|
||||
clipRegion.hi.x = leftEnd.x + centerWidth;
|
||||
clipRegion.hi.y = start.y + barWindowSize.y;
|
||||
TheDisplay->setClipRegion(&clipRegion);
|
||||
centerWidth = rightStart.x - start.x;
|
||||
if( centerWidth )
|
||||
{
|
||||
|
||||
pieces = centerWidth / smallCenter->getImageWidth() + 1;
|
||||
end.y = start.y + barWindowSize.y;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + smallCenter->getImageWidth();
|
||||
TheWindowManager->winDrawImage( smallCenter,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += smallCenter->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
} // end if
|
||||
TheDisplay->enableClipping(FALSE);
|
||||
// draw left end
|
||||
start.x = startX + xOffset;
|
||||
start.y = startY + yOffset;
|
||||
end = leftEnd;
|
||||
TheWindowManager->winDrawImage(left, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw right end
|
||||
start = rightStart;
|
||||
end.x = start.x + rightSize.x;
|
||||
end.y = start.y + barWindowSize.y;
|
||||
TheWindowManager->winDrawImage(right, start.x, start.y, end.x, end.y);
|
||||
|
||||
} // end drawHiliteBar
|
||||
|
||||
// drawListBoxText ============================================================
|
||||
/** Draw the text for a listbox */
|
||||
//=============================================================================
|
||||
static void drawListBoxText( GameWindow *window, WinInstanceData *instData,
|
||||
Int x, Int y, Int width, Int height,
|
||||
Bool useImages )
|
||||
{
|
||||
Int drawY;
|
||||
ListboxData *list = (ListboxData *)window->winGetUserData();
|
||||
Int i;
|
||||
Bool selected;
|
||||
Int listLineHeight;
|
||||
Color textColor;
|
||||
// W3DGameWindow *w3dWindow = static_cast<W3DGameWindow *>(window);
|
||||
IRegion2D clipRegion;
|
||||
ICoord2D start, end;
|
||||
|
||||
//
|
||||
// save the clipping information region cause we're going to use it here
|
||||
// in drawing the text
|
||||
//
|
||||
// TheWindowManager->winGetClipRegion( &clipRegion );
|
||||
|
||||
// set clip region to inside the outline box.
|
||||
// TheWindowManager->winSetClipRegion( x, y, width, height );
|
||||
|
||||
// set the text clip region to the outline of the listbox
|
||||
clipRegion.lo.x = x + 1;
|
||||
clipRegion.lo.y = y -3;
|
||||
clipRegion.hi.x = x + width - 1;
|
||||
clipRegion.hi.y = y + height - 1;
|
||||
|
||||
drawY = y - list->displayPos;
|
||||
|
||||
for( i = 0; ; i++ )
|
||||
{
|
||||
|
||||
if( i > 0 )
|
||||
if( list->listData[(i - 1)].listHeight >
|
||||
(list->displayPos + list->displayHeight) )
|
||||
break;
|
||||
|
||||
if( i == list->endPos )
|
||||
break;
|
||||
|
||||
if( list->listData[i].listHeight < list->displayPos )
|
||||
{
|
||||
drawY += (list->listData[i].height + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
listLineHeight = list->listData[i].height + 1;
|
||||
//textColor = list->listData[i].textColor;
|
||||
selected = FALSE;
|
||||
|
||||
if( list->multiSelect )
|
||||
{
|
||||
Int j = 0;
|
||||
|
||||
while( list->selections[j] >= 0 )
|
||||
{
|
||||
if( i == list->selections[j] )
|
||||
{
|
||||
selected = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( i == list->selectPos )
|
||||
selected = TRUE;
|
||||
}
|
||||
|
||||
// this item is selected, draw the selection color or image
|
||||
if( selected )
|
||||
{
|
||||
|
||||
if( useImages )
|
||||
{
|
||||
const Image *left, *right, *center, *smallCenter;
|
||||
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
left = GadgetListBoxGetDisabledSelectedItemImageLeft( window );
|
||||
right = GadgetListBoxGetDisabledSelectedItemImageRight( window );
|
||||
center = GadgetListBoxGetDisabledSelectedItemImageCenter( window );
|
||||
smallCenter = GadgetListBoxGetDisabledSelectedItemImageSmallCenter( window );
|
||||
|
||||
} // end if
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
left = GadgetListBoxGetHiliteSelectedItemImageLeft( window );
|
||||
right = GadgetListBoxGetHiliteSelectedItemImageRight( window );
|
||||
center = GadgetListBoxGetHiliteSelectedItemImageCenter( window );
|
||||
smallCenter = GadgetListBoxGetHiliteSelectedItemImageSmallCenter( window );
|
||||
|
||||
} // end else if
|
||||
else
|
||||
{
|
||||
|
||||
left = GadgetListBoxGetEnabledSelectedItemImageLeft( window );
|
||||
right = GadgetListBoxGetEnabledSelectedItemImageRight( window );
|
||||
center = GadgetListBoxGetEnabledSelectedItemImageCenter( window );
|
||||
smallCenter = GadgetListBoxGetEnabledSelectedItemImageSmallCenter( window );
|
||||
|
||||
} // end else
|
||||
|
||||
// draw select image across area
|
||||
|
||||
//
|
||||
// where are we going to draw ... taking into account the clipping
|
||||
// region of the edge of the listbox
|
||||
//
|
||||
start.x = x;
|
||||
start.y = drawY;
|
||||
end.x = start.x + width;
|
||||
end.y = start.y + listLineHeight;
|
||||
|
||||
if( end.y > clipRegion.hi.y )
|
||||
end.y = clipRegion.hi.y;
|
||||
if( start.y < clipRegion.lo.y )
|
||||
start.y = clipRegion.lo.y;
|
||||
|
||||
if( left && right && center && smallCenter )
|
||||
drawHiliteBar( left, right, center, smallCenter, start.x + 1, start.y, end.x , end.y );
|
||||
|
||||
} // end if, use images
|
||||
else
|
||||
{
|
||||
Color selectColor = WIN_COLOR_UNDEFINED,
|
||||
selectBorder = WIN_COLOR_UNDEFINED;
|
||||
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
selectColor = GadgetListBoxGetDisabledSelectedItemColor( window );
|
||||
selectBorder = GadgetListBoxGetDisabledSelectedItemBorderColor( window );
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
selectColor = GadgetListBoxGetHiliteSelectedItemColor( window );
|
||||
selectBorder = GadgetListBoxGetHiliteSelectedItemBorderColor( window );
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
selectColor = GadgetListBoxGetEnabledSelectedItemColor( window );
|
||||
selectBorder = GadgetListBoxGetEnabledSelectedItemBorderColor( window );
|
||||
} // end else, enabled
|
||||
|
||||
// draw border
|
||||
|
||||
//
|
||||
// where are we going to draw ... taking into account the clipping
|
||||
// region of the edge of the listbox
|
||||
//
|
||||
start.x = x;
|
||||
start.y = drawY;
|
||||
end.x = start.x + width;
|
||||
end.y = start.y + listLineHeight;
|
||||
|
||||
if( end.y > clipRegion.hi.y )
|
||||
end.y = clipRegion.hi.y;
|
||||
if( start.y < clipRegion.lo.y )
|
||||
start.y = clipRegion.lo.y;
|
||||
|
||||
if( selectBorder != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winOpenRect( selectBorder,
|
||||
WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
|
||||
// draw filled inner rect
|
||||
|
||||
//
|
||||
// where are we going to draw ... taking into account the clipping
|
||||
// region of the edge of the listbox
|
||||
//
|
||||
start.x = x + 1;
|
||||
start.y = drawY + 1;
|
||||
end.x = start.x + width - 2;
|
||||
end.y = start.y + listLineHeight - 2;
|
||||
|
||||
if( end.y > clipRegion.hi.y )
|
||||
end.y = clipRegion.hi.y;
|
||||
if( start.y < clipRegion.lo.y )
|
||||
start.y = clipRegion.lo.y;
|
||||
|
||||
if( selectColor != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winFillRect( selectColor,
|
||||
WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
|
||||
} // end else, draw selection with colors
|
||||
|
||||
} // end if
|
||||
|
||||
|
||||
|
||||
|
||||
Color dropColor = TheWindowManager->winMakeColor( 0, 0, 0, 255 );
|
||||
DisplayString *string;
|
||||
|
||||
ListEntryCell *cells = list->listData[i].cell;
|
||||
Int columnX = x;
|
||||
IRegion2D columnRegion;
|
||||
if( cells )
|
||||
{
|
||||
// loop through all the cells
|
||||
for( Int j = 0; j < list->columns; j++ )
|
||||
{
|
||||
// setup the Clip Region size
|
||||
|
||||
columnRegion.lo.x = columnX;
|
||||
columnRegion.lo.y = drawY;
|
||||
if(list->columns == 1 && list->slider && list->slider->winIsHidden())
|
||||
columnRegion.hi.x = columnX + width-3;
|
||||
else
|
||||
columnRegion.hi.x = columnX + list->columnWidth[j];
|
||||
columnRegion.hi.y = drawY + list->listData[i].height;
|
||||
if(columnRegion.lo.y < clipRegion.lo.y )
|
||||
columnRegion.lo.y = clipRegion.lo.y;
|
||||
if( columnRegion.hi.y > clipRegion.hi.y )
|
||||
columnRegion.hi.y = clipRegion.hi.y;
|
||||
|
||||
// Display the Text Case;
|
||||
if(cells[j].cellType == LISTBOX_TEXT)
|
||||
{
|
||||
textColor = cells[j].color;
|
||||
string = (DisplayString *)cells[j].data;
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) == TRUE )
|
||||
{
|
||||
string->setWordWrap(0);
|
||||
// make sure the font of the text is the same as the windows
|
||||
if( string->getFont() != window->winGetFont() )
|
||||
string->setFont( window->winGetFont() );
|
||||
|
||||
// draw this text after setting the clip region for it
|
||||
string->setClipRegion( &columnRegion );
|
||||
string->draw( columnX + TEXT_X_OFFSET,
|
||||
drawY,
|
||||
textColor,
|
||||
dropColor );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// make sure the font of the text is the same as the windows
|
||||
if( string->getFont() != window->winGetFont() )
|
||||
string->setFont( window->winGetFont() );
|
||||
|
||||
// set clip region and draw
|
||||
string->setClipRegion( &columnRegion );
|
||||
string->draw( columnX + TEXT_X_OFFSET,
|
||||
drawY,
|
||||
textColor,
|
||||
dropColor );
|
||||
}//else
|
||||
}// if
|
||||
else if(cells[j].cellType == LISTBOX_IMAGE && cells[j].data)
|
||||
{
|
||||
Int width, height;
|
||||
if (cells[j].width > 0)
|
||||
width = cells[j].width;
|
||||
else
|
||||
width = list->columnWidth[j];
|
||||
if(cells[j].height > 0)
|
||||
height = cells[j].height;
|
||||
else
|
||||
height = list->listData[i].height;
|
||||
if(j == 0)
|
||||
width--;
|
||||
Int offsetX,offsetY;
|
||||
if(width < list->columnWidth[j])
|
||||
offsetX = columnX + ((list->columnWidth[j] - width) / 2);
|
||||
else
|
||||
offsetX = columnX;
|
||||
if(height < list->listData[i].height)
|
||||
offsetY = drawY + ((list->listData[i].height - height) / 2);
|
||||
else
|
||||
offsetY = drawY;
|
||||
|
||||
offsetY++;
|
||||
if(offsetX <x+1)
|
||||
offsetX = x+1;
|
||||
TheDisplay->setClipRegion( &columnRegion );
|
||||
TheWindowManager->winDrawImage( (const Image *)cells[j].data,
|
||||
offsetX, offsetY,
|
||||
offsetX + width, offsetY + height,cells[j].color );
|
||||
|
||||
}//else
|
||||
columnX = columnX + list->columnWidth[j];
|
||||
}// for
|
||||
}//if
|
||||
|
||||
|
||||
drawY += listLineHeight;
|
||||
TheDisplay->enableClipping(FALSE);
|
||||
}
|
||||
|
||||
// TheWindowManager->winSetClipRegion( clipRegion.lo.x, clipRegion.lo.y,
|
||||
// clipRegion.hi.x, clipRegion.hi.y );
|
||||
|
||||
} // end drawListBoxText
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetListBoxDraw =======================================================
|
||||
/** Draw colored list box using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetListBoxDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int width, height, fontHeight, x, y;
|
||||
Color background, border, titleColor, titleBorder;
|
||||
ListboxData *list = (ListboxData *)window->winGetUserData();
|
||||
ICoord2D size;
|
||||
DisplayString *title = instData->getTextDisplayString();
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &x, &y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get font height
|
||||
fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
|
||||
|
||||
// alias width and height from size
|
||||
width = size.x;
|
||||
height = size.y;
|
||||
|
||||
// get the right colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
background = GadgetListBoxGetDisabledColor( window );
|
||||
border = GadgetListBoxGetDisabledBorderColor( window );
|
||||
titleColor = window->winGetDisabledTextColor();
|
||||
titleBorder = window->winGetDisabledTextBorderColor();
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
background = GadgetListBoxGetHiliteColor( window );
|
||||
border = GadgetListBoxGetHiliteBorderColor( window );
|
||||
titleColor = window->winGetHiliteTextColor();
|
||||
titleBorder = window->winGetHiliteTextBorderColor();
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
background = GadgetListBoxGetEnabledColor( window );
|
||||
border = GadgetListBoxGetEnabledBorderColor( window );
|
||||
titleColor = window->winGetEnabledTextColor();
|
||||
titleBorder = window->winGetEnabledTextBorderColor();
|
||||
} // end else, enabled
|
||||
|
||||
// Draw the title
|
||||
if( title && title->getTextLength() )
|
||||
{
|
||||
|
||||
// set the font of this text to that of the window if not already
|
||||
if( title->getFont() != window->winGetFont() )
|
||||
title->setFont( window->winGetFont() );
|
||||
|
||||
// draw the text
|
||||
title->draw( x + 1, y, titleColor, titleBorder );
|
||||
|
||||
y += fontHeight + 1;
|
||||
height -= fontHeight + 1;
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the back border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
x, y, x + width, y + height );
|
||||
|
||||
// draw background
|
||||
if( background != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winFillRect( background, WIN_DRAW_LINE_WIDTH,
|
||||
x + 1, y + 1,
|
||||
x + width - 1, y + height - 1 );
|
||||
|
||||
// If ScrollBar was requested ... adjust width.
|
||||
if( list->slider && !list->slider->winIsHidden())
|
||||
{
|
||||
ICoord2D sliderSize;
|
||||
|
||||
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
|
||||
width -= (sliderSize.x +3);
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the text
|
||||
drawListBoxText( window, instData, x, y + 4 , width, height-4, TRUE );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetListBoxDraw
|
||||
|
||||
// W3DGadgetListBoxImageDraw ==================================================
|
||||
/** Draw list box with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetListBoxImageDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int width, height, x, y;
|
||||
const Image *image;
|
||||
ListboxData *list = (ListboxData *)window->winGetUserData();
|
||||
ICoord2D size;
|
||||
Color titleColor, titleBorder;
|
||||
DisplayString *title = instData->getTextDisplayString();
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &x, &y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// save off width and height so we can change them
|
||||
width = size.x;
|
||||
height = size.y;
|
||||
|
||||
// If ScrollBar was requested ... adjust width.
|
||||
if( list->slider )
|
||||
{
|
||||
ICoord2D sliderSize;
|
||||
|
||||
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
|
||||
width -= sliderSize.x;
|
||||
|
||||
} // end if
|
||||
|
||||
// get the image
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
image = GadgetListBoxGetDisabledImage( window );
|
||||
titleColor = window->winGetDisabledTextColor();
|
||||
titleBorder = window->winGetDisabledTextBorderColor();
|
||||
}
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
image = GadgetListBoxGetHiliteImage( window );
|
||||
titleColor = window->winGetHiliteTextColor();
|
||||
titleBorder = window->winGetHiliteTextBorderColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
image = GadgetListBoxGetEnabledImage( window );
|
||||
titleColor = window->winGetEnabledTextColor();
|
||||
titleBorder = window->winGetEnabledTextBorderColor();
|
||||
}
|
||||
|
||||
// draw the back image
|
||||
if( image )
|
||||
{
|
||||
ICoord2D start, end;
|
||||
|
||||
start.x = x + instData->m_imageOffset.x;
|
||||
start.y = y + instData->m_imageOffset.y;
|
||||
end.x = start.x + width;
|
||||
end.y = start.y + height;
|
||||
TheWindowManager->winDrawImage( image,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// Draw the title
|
||||
if( title && title->getTextLength() )
|
||||
{
|
||||
|
||||
// set font to font of the window if not already
|
||||
if( title->getFont() != window->winGetFont() )
|
||||
title->setFont( window->winGetFont() );
|
||||
|
||||
// draw the text
|
||||
title->draw( x + 1, y, titleColor, titleBorder );
|
||||
|
||||
y += TheWindowManager->winFontHeight( instData->getFont() );
|
||||
height -= TheWindowManager->winFontHeight( instData->getFont() ) + 1;
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the listbox text
|
||||
drawListBoxText( window, instData, x, y+4, width, height-4, TRUE );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetListBoxImageDraw
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DProgressBar.cpp ///////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DProgressBar.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation for the progress bar GUI control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetProgressBar.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetProgressBarDraw ===================================================
|
||||
/** Draw colored Progress Bar using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetProgressBarDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size, start, end;
|
||||
Color backColor, backBorder, barColor, barBorder;
|
||||
Int progress = (Int)window->winGetUserData();
|
||||
|
||||
// get window size and position
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the right colors to use
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
backColor = GadgetProgressBarGetDisabledColor( window );
|
||||
backBorder = GadgetProgressBarGetDisabledBorderColor( window );
|
||||
barColor = GadgetProgressBarGetDisabledBarColor( window );
|
||||
barBorder = GadgetProgressBarGetDisabledBarBorderColor( window );
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
backColor = GadgetProgressBarGetHiliteColor( window );
|
||||
backBorder = GadgetProgressBarGetHiliteBorderColor( window );
|
||||
barColor = GadgetProgressBarGetHiliteBarColor( window );
|
||||
barBorder = GadgetProgressBarGetHiliteBarBorderColor( window );
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
backColor = GadgetProgressBarGetEnabledColor( window );
|
||||
backBorder = GadgetProgressBarGetEnabledBorderColor( window );
|
||||
barColor = GadgetProgressBarGetEnabledBarColor( window );
|
||||
barBorder = GadgetProgressBarGetEnabledBarBorderColor( window );
|
||||
} // end else, enabled
|
||||
|
||||
// draw background border
|
||||
if( backBorder != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw background fill
|
||||
if( backColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = start.x + size.x - 2;
|
||||
end.y = start.y + size.y - 2;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the progress so far
|
||||
if( progress )
|
||||
{
|
||||
|
||||
// draw bar border
|
||||
if( barBorder != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + (size.x * progress) / 100;
|
||||
end.y = start.y + size.y;
|
||||
if(end.x- start.x > 1 )
|
||||
{
|
||||
TheWindowManager->winOpenRect( barBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
}
|
||||
|
||||
} // end if
|
||||
|
||||
// draw bar fill
|
||||
if( barColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = start.x + (size.x * progress) / 100 - 2;
|
||||
end.y = start.y + size.y - 2;
|
||||
// TheWindowManager->winOpenRect( barColor, WIN_DRAW_LINE_WIDTH,
|
||||
// start.x, start.y, end.x, end.y );
|
||||
|
||||
if(end.x- start.x > 1 )
|
||||
{
|
||||
TheWindowManager->winFillRect( barColor,WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
TheWindowManager->winDrawLine(GameMakeColor(255,255,255,255),WIN_DRAW_LINE_WIDTH, start.x, start.y, end.x, start.y);
|
||||
TheWindowManager->winDrawLine(GameMakeColor(200,200,200,255),WIN_DRAW_LINE_WIDTH, start.x, start.y, start.x, end.y);
|
||||
}
|
||||
|
||||
} // end if
|
||||
|
||||
} // end if
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetProgressBarDraw
|
||||
|
||||
// W3DGadgetProgressBarImageDraw ==============================================
|
||||
/** Draw Progress Bar with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetProgressBarImageDrawA( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size;
|
||||
const Image *barCenter, *barRight, *left, *right, *center;
|
||||
Int progress = (Int)window->winGetUserData();
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
// get window size and position
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
barCenter = GadgetProgressBarGetEnabledBarImageCenter( window );
|
||||
barRight = GadgetProgressBarGetEnabledBarImageRight( window );
|
||||
left = GadgetProgressBarGetEnabledImageLeft( window );
|
||||
right = GadgetProgressBarGetEnabledImageRight( window );
|
||||
center = GadgetProgressBarGetEnabledImageCenter( window );
|
||||
|
||||
if(!barCenter || !barRight || !left || !right || !center)
|
||||
return;
|
||||
|
||||
Int width = barCenter->getImageWidth();
|
||||
// Int height = barCenter->getImageHeight();
|
||||
|
||||
Int drawWidth = (size.x * progress) / 100;
|
||||
Int pieces = drawWidth / width;
|
||||
Int x = origin.x;
|
||||
for( i = 0; i < pieces; i ++)
|
||||
{
|
||||
|
||||
TheWindowManager->winDrawImage( barCenter,
|
||||
x, origin.y,
|
||||
x + width, origin.y + size.y );
|
||||
x += width;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void W3DGadgetProgressBarImageDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size, start, end;
|
||||
const Image *backLeft, *backRight, *backCenter,
|
||||
*barRight, *barCenter;//*backSmallCenter,*barLeft,, *barSmallCenter;
|
||||
Int progress = (Int)window->winGetUserData();
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
|
||||
// get window size and position
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
// get the right images to use
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
backLeft = GadgetProgressBarGetDisabledImageLeft( window );
|
||||
//barLeft = GadgetProgressBarGetDisabledBarImageLeft( window );
|
||||
backRight = GadgetProgressBarGetDisabledImageRight( window );
|
||||
barRight = GadgetProgressBarGetDisabledBarImageRight( window );
|
||||
backCenter = GadgetProgressBarGetDisabledImageCenter( window );
|
||||
barCenter = GadgetProgressBarGetDisabledBarImageCenter( window );
|
||||
//backSmallCenter = GadgetProgressBarGetDisabledImageSmallCenter( window );
|
||||
//barSmallCenter = GadgetProgressBarGetDisabledBarImageSmallCenter( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
backLeft = GadgetProgressBarGetHiliteImageLeft( window );
|
||||
//barLeft = GadgetProgressBarGetHiliteBarImageLeft( window );
|
||||
backRight = GadgetProgressBarGetHiliteImageRight( window );
|
||||
barRight = GadgetProgressBarGetHiliteBarImageRight( window );
|
||||
backCenter = GadgetProgressBarGetHiliteImageCenter( window );
|
||||
barCenter = GadgetProgressBarGetHiliteBarImageCenter( window );
|
||||
//backSmallCenter = GadgetProgressBarGetHiliteImageSmallCenter( window );
|
||||
//barSmallCenter = GadgetProgressBarGetHiliteBarImageSmallCenter( window );
|
||||
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
|
||||
backLeft = GadgetProgressBarGetEnabledImageLeft( window );
|
||||
//barLeft = GadgetProgressBarGetEnabledBarImageLeft( window );
|
||||
backRight = GadgetProgressBarGetEnabledImageRight( window );
|
||||
barRight = GadgetProgressBarGetEnabledBarImageRight( window );
|
||||
backCenter = GadgetProgressBarGetEnabledImageCenter( window );
|
||||
barCenter = GadgetProgressBarGetEnabledBarImageCenter( window );
|
||||
//backSmallCenter = GadgetProgressBarGetEnabledImageSmallCenter( window );
|
||||
//barSmallCenter = GadgetProgressBarGetEnabledBarImageSmallCenter( window );
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// sanity
|
||||
if( backLeft == NULL || backRight == NULL ||
|
||||
backCenter == NULL ||
|
||||
barRight == NULL)
|
||||
// backSmallCenter == NULL ||barLeft == NULL ||barCenter == NULL || barSmallCenter == NULL )
|
||||
return;
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D leftSize, rightSize;
|
||||
leftSize.x = backLeft->getImageWidth();
|
||||
leftSize.y = backLeft->getImageHeight();
|
||||
rightSize.x = backRight->getImageWidth();
|
||||
rightSize.y = backRight->getImageHeight();
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D leftEnd, rightStart;
|
||||
leftEnd.x = origin.x + leftSize.x + xOffset;
|
||||
leftEnd.y = origin.y + size.y + yOffset;
|
||||
rightStart.x = origin.x + size.x - rightSize.x + xOffset;
|
||||
rightStart.y = origin.y + yOffset;
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerWidth, pieces;
|
||||
|
||||
// get width we have to draw our repeating center in
|
||||
centerWidth = rightStart.x - leftEnd.x;
|
||||
|
||||
// how many whole repeating pieces will fit in that width
|
||||
pieces = centerWidth / backCenter->getImageWidth();
|
||||
|
||||
// draw the pieces
|
||||
start.x = leftEnd.x;
|
||||
start.y = origin.y + yOffset;
|
||||
end.y = start.y + size.y;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + backCenter->getImageWidth();
|
||||
TheWindowManager->winDrawImage( backCenter,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += backCenter->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
//
|
||||
// how many small repeating pieces will fit in the gap from where the
|
||||
// center repeating bar stopped and the right image, draw them
|
||||
// and overlapping underneath where the right end will go
|
||||
//
|
||||
// centerWidth = rightStart.x - start.x;
|
||||
// pieces = centerWidth / backCenter->getImageWidth() + 1;
|
||||
// end.y = start.y + size.y;
|
||||
// IRegion2D clipRegion;
|
||||
//
|
||||
// TheDisplay->setClipRegion()
|
||||
// for( i = 0; i < pieces; i++ )
|
||||
// {
|
||||
//
|
||||
// end.x = start.x + backCenter->getImageWidth();
|
||||
// TheWindowManager->winDrawImage( backCenter,
|
||||
// start.x, start.y,
|
||||
// end.x, end.y );
|
||||
// start.x += backCenter->getImageWidth();
|
||||
//
|
||||
// } // end for i
|
||||
//
|
||||
IRegion2D reg;
|
||||
reg.lo.x = start.x;
|
||||
reg.lo.y = start.y;
|
||||
reg.hi.x = rightStart.x;
|
||||
reg.hi.y = end.y;
|
||||
centerWidth = rightStart.x - start.x;
|
||||
if( centerWidth > 0)
|
||||
{
|
||||
TheDisplay->setClipRegion(®);
|
||||
end.x = start.x + backCenter->getImageWidth();
|
||||
TheWindowManager->winDrawImage( backCenter,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
TheDisplay->enableClipping(FALSE);
|
||||
}
|
||||
|
||||
|
||||
// draw left end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end = leftEnd;
|
||||
TheWindowManager->winDrawImage(backLeft, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw right end
|
||||
start = rightStart;
|
||||
end.x = start.x + rightSize.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawImage(backRight, start.x, start.y, end.x, end.y);
|
||||
|
||||
|
||||
ICoord2D barWindowSize; // end point of bar from window origin
|
||||
|
||||
barWindowSize.x = ((size.x - 20) * progress) / 100;
|
||||
barWindowSize.y = size.y;
|
||||
|
||||
pieces = barWindowSize.x / barCenter->getImageWidth();
|
||||
// draw the pieces
|
||||
start.x = origin.x +10;
|
||||
start.y = origin.y + yOffset +5;
|
||||
end.y = start.y + size.y - 10;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + barCenter->getImageWidth();
|
||||
TheWindowManager->winDrawImage( barCenter,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += barCenter->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
start.x = origin.x + 10 + barCenter->getImageWidth() * pieces;
|
||||
//pieces = (size.x - barWindowSize.x -20) / barRight->getImageWidth();
|
||||
//Changed By Saad for flashing grey piece
|
||||
pieces = ((size.x - 20) / barCenter->getImageWidth()) - pieces;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + barRight->getImageWidth();
|
||||
TheWindowManager->winDrawImage( barRight,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += barRight->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
} // end W3DGadgetProgressBarImageDraw
|
||||
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// FILE: W3DPushButton.cpp ////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DPushButton.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation for the push button control element
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/Gadget.h"
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetPushButton.h"
|
||||
#include "GameClient/Display.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindow.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
void W3DGadgetPushButtonImageDrawThree(GameWindow *window, WinInstanceData *instData );
|
||||
void W3DGadgetPushButtonImageDrawOne(GameWindow *window, WinInstanceData *instData );
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
// drawButtonText =============================================================
|
||||
/** Draw button text to the screen */
|
||||
//=============================================================================
|
||||
static void drawButtonText( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size, textPos;
|
||||
Int width, height;
|
||||
Color textColor, dropColor;
|
||||
DisplayString *text = instData->getTextDisplayString();
|
||||
|
||||
// sanity
|
||||
if( text == NULL || text->getTextLength() == 0 )
|
||||
return;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// set whether or not we center the wrapped text
|
||||
text->setWordWrapCentered( BitTest( instData->getStatus(), WIN_STATUS_WRAP_CENTERED ));
|
||||
text->setWordWrap(size.x);
|
||||
// get the right text color
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
dropColor = window->winGetDisabledTextBorderColor();
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
textColor = window->winGetHiliteTextColor();
|
||||
dropColor = window->winGetHiliteTextBorderColor();
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
dropColor = window->winGetEnabledTextBorderColor();
|
||||
} // end enabled only
|
||||
|
||||
// set our font to that of our parent if not the same
|
||||
if( text->getFont() != window->winGetFont() )
|
||||
text->setFont( window->winGetFont() );
|
||||
|
||||
// get text size
|
||||
text->getSize( &width, &height );
|
||||
|
||||
// where to draw
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_SHORTCUT_BUTTON ) )
|
||||
{
|
||||
// Oh god... this is a total hack for shortcut buttons to handle rendering text top left corner...
|
||||
textPos.x = origin.x + 2;
|
||||
textPos.y = origin.y + 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
textPos.x = origin.x + (size.x / 2) - (width / 2);
|
||||
textPos.y = origin.y + (size.y / 2) - (height / 2);
|
||||
}
|
||||
|
||||
// draw it
|
||||
text->draw( textPos.x, textPos.y, textColor, dropColor );
|
||||
|
||||
} // end drawButtonText
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetPushButtonDraw ====================================================
|
||||
/** Draw colored pushbutton using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetPushButtonDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Color color, border;
|
||||
ICoord2D origin, size, start, end;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
//
|
||||
// get pointer to image we want to draw depending on our state,
|
||||
// see GadgetPushButton.h for info
|
||||
//
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
color = GadgetButtonGetDisabledSelectedColor( window );
|
||||
border = GadgetButtonGetDisabledSelectedBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
color = GadgetButtonGetDisabledColor( window );
|
||||
border = GadgetButtonGetDisabledBorderColor( window );
|
||||
}
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
color = GadgetButtonGetHiliteSelectedColor( window );
|
||||
border = GadgetButtonGetHiliteSelectedBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
color = GadgetButtonGetHiliteColor( window );
|
||||
border = GadgetButtonGetHiliteBorderColor( window );
|
||||
}
|
||||
|
||||
} // end else if, hilited and enabled
|
||||
else
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
color = GadgetButtonGetEnabledSelectedColor( window );
|
||||
border = GadgetButtonGetEnabledSelectedBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
color = GadgetButtonGetEnabledColor( window );
|
||||
border = GadgetButtonGetEnabledBorderColor( window );
|
||||
}
|
||||
|
||||
} // end else, enabled only
|
||||
|
||||
// compute draw position
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
// draw inside border
|
||||
start.x++;
|
||||
start.y++;
|
||||
end.x--;
|
||||
end.y--;
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the button text
|
||||
if( instData->getTextLength() )
|
||||
drawButtonText( window, instData );
|
||||
|
||||
// if we have a video buffer, draw the video buffer
|
||||
if ( instData->m_videoBuffer )
|
||||
{
|
||||
TheDisplay->drawVideoBuffer( instData->m_videoBuffer, origin.x, origin.y, origin.x + size.x, origin.y + size.y );
|
||||
}
|
||||
|
||||
PushButtonData *pData = (PushButtonData *)window->winGetUserData();
|
||||
if( pData )
|
||||
{
|
||||
if( pData->overlayImage )
|
||||
{
|
||||
//Render the overlay image now.
|
||||
TheDisplay->drawImage( pData->overlayImage, origin.x, origin.y, origin.x + size.x, origin.y + size.y );
|
||||
}
|
||||
|
||||
if( pData->drawClock )
|
||||
{
|
||||
if( pData->drawClock == NORMAL_CLOCK )
|
||||
{
|
||||
TheDisplay->drawRectClock(origin.x, origin.y, size.x, size.y, pData->percentClock,pData->colorClock);
|
||||
}
|
||||
else if( pData->drawClock == INVERSE_CLOCK )
|
||||
{
|
||||
TheDisplay->drawRemainingRectClock( origin.x, origin.y, size.x, size.y, pData->percentClock,pData->colorClock );
|
||||
}
|
||||
pData->drawClock = NO_CLOCK;
|
||||
window->winSetUserData(pData);
|
||||
}
|
||||
|
||||
if( pData->drawBorder && pData->colorBorder != GAME_COLOR_UNDEFINED )
|
||||
{
|
||||
TheDisplay->drawOpenRect(origin.x -1, origin.y - 1, size.x + 2, size.y + 2,1 , pData->colorBorder);
|
||||
}
|
||||
}
|
||||
|
||||
} // end W3DGadgetPushButtonDraw
|
||||
|
||||
|
||||
|
||||
|
||||
// W3DGadgetPushButtonImageDraw ===============================================
|
||||
/** Draw pushbutton with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetPushButtonImageDraw( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
// if we return NULL then we'll call the one picture drawing code, if we return a value
|
||||
// then we'll call the 3 picture drawing code
|
||||
if( GadgetButtonGetMiddleEnabledImage( window ) )
|
||||
{
|
||||
if( BitTest( instData->getState(), WIN_STATUS_USE_OVERLAY_STATES ) )
|
||||
{
|
||||
ICoord2D size, start;
|
||||
// get window position
|
||||
window->winGetScreenPosition( &start.x, &start.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
// offset position by image offset
|
||||
start.x += instData->m_imageOffset.x;
|
||||
start.y += instData->m_imageOffset.y;
|
||||
|
||||
DEBUG_CRASH( ("Button at %d,%d is attempting to render with W3DGadgetPushButtonImageDrawThree(), but is using overlay states! Forcing the code to use W3DGadgetPushButtonImageDrawOne() instead.", start.x, start.y ) );
|
||||
W3DGadgetPushButtonImageDrawOne( window, instData );
|
||||
}
|
||||
else
|
||||
{
|
||||
W3DGadgetPushButtonImageDrawThree( window, instData );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
W3DGadgetPushButtonImageDrawOne( window, instData );
|
||||
}
|
||||
}
|
||||
|
||||
void W3DGadgetPushButtonImageDrawOne( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
const Image *image = NULL;
|
||||
ICoord2D size, start, end;
|
||||
|
||||
//
|
||||
// get pointer to image we want to draw depending on our state,
|
||||
// see GadgetPushButton.h for info
|
||||
//
|
||||
image = GadgetButtonGetEnabledImage( window );
|
||||
|
||||
if( !BitTest( window->winGetStatus(), WIN_STATUS_USE_OVERLAY_STATES ) )
|
||||
{
|
||||
//Certain buttons have the option to specify specific images for
|
||||
//altered states. If they do, then we won't render the auto-overlay versions.
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
image = GadgetButtonGetDisabledSelectedImage( window );
|
||||
else
|
||||
image = GadgetButtonGetDisabledImage( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
image = GadgetButtonGetHiliteSelectedImage( window );
|
||||
else
|
||||
image = GadgetButtonGetHiliteImage( window );
|
||||
|
||||
} // end else if, hilited and enabled
|
||||
else
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
image = GadgetButtonGetHiliteSelectedImage( window );
|
||||
} // end else, enabled only
|
||||
}
|
||||
|
||||
|
||||
// draw the image
|
||||
if( image )
|
||||
{
|
||||
|
||||
// get window position
|
||||
window->winGetScreenPosition( &start.x, &start.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
|
||||
// offset position by image offset
|
||||
start.x += instData->m_imageOffset.x;
|
||||
start.y += instData->m_imageOffset.y;
|
||||
|
||||
// find end point
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
|
||||
Display::DrawImageMode drawMode=Display::DRAW_IMAGE_ALPHA;
|
||||
Int colorMultiplier = 0xffffffff;
|
||||
|
||||
if(BitTest( window->winGetStatus(), WIN_STATUS_USE_OVERLAY_STATES ) )
|
||||
{
|
||||
//we're using a new drawing system which does "grayscale" disabled buttons using original color artwork.
|
||||
if( !BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) )
|
||||
{
|
||||
if( !BitTest( window->winGetStatus(), WIN_STATUS_NOT_READY ) )
|
||||
{
|
||||
//The button is disabled -- but if the button isn't "ready", we don't want to do this because
|
||||
//we want to show the button in color with just the clock overlay.
|
||||
if( !BitTest( window->winGetStatus(), WIN_STATUS_ALWAYS_COLOR ) )
|
||||
{
|
||||
drawMode=Display::DRAW_IMAGE_GRAYSCALE;
|
||||
}
|
||||
else
|
||||
{
|
||||
colorMultiplier = 0xff909090; //RGB values are 144/255 (90) -- Alpha is opaque (ff) --> ff909090;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TheDisplay->drawImage( image, start.x, start.y, end.x, end.y, colorMultiplier, drawMode );
|
||||
} // end if
|
||||
|
||||
// draw the button text
|
||||
if( instData->getTextLength() )
|
||||
drawButtonText( window, instData );
|
||||
|
||||
// get window position
|
||||
window->winGetScreenPosition( &start.x, &start.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
|
||||
// if we have a video buffer, draw the video buffer
|
||||
if ( instData->m_videoBuffer )
|
||||
{
|
||||
TheDisplay->drawVideoBuffer( instData->m_videoBuffer, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
PushButtonData *pData = (PushButtonData *)window->winGetUserData();
|
||||
|
||||
if( pData )
|
||||
{
|
||||
if( pData->overlayImage )
|
||||
{
|
||||
//Render the overlay image now.
|
||||
TheDisplay->drawImage( pData->overlayImage, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
|
||||
if( pData->drawClock )
|
||||
{
|
||||
if( pData->drawClock == NORMAL_CLOCK )
|
||||
{
|
||||
TheDisplay->drawRectClock(start.x, start.y, size.x, size.y, pData->percentClock,pData->colorClock);
|
||||
}
|
||||
else if( pData->drawClock == INVERSE_CLOCK )
|
||||
{
|
||||
TheDisplay->drawRemainingRectClock( start.x, start.y, size.x, size.y, pData->percentClock,pData->colorClock );
|
||||
}
|
||||
pData->drawClock = NO_CLOCK;
|
||||
window->winSetUserData(pData);
|
||||
}
|
||||
|
||||
if( pData->drawBorder && pData->colorBorder != GAME_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
TheDisplay->drawOpenRect(start.x - 1, start.y - 1, size.x + 2, size.y + 2, 1, pData->colorBorder);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Now render overlays that pertain to the correct state.
|
||||
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_FLASHING ) )
|
||||
{
|
||||
//Handle cameo flashing (let the flashing stack with overlay states)
|
||||
static const Image *hilitedOverlayIcon = TheMappedImageCollection->findImageByName( "Cameo_push" );
|
||||
TheDisplay->drawImage( hilitedOverlayIcon, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_USE_OVERLAY_STATES ) )
|
||||
{
|
||||
image = NULL;
|
||||
static const Image *pushedOverlayIcon = TheMappedImageCollection->findImageByName( "Cameo_push" );
|
||||
static const Image *hilitedOverlayIcon = TheMappedImageCollection->findImageByName( "Cameo_hilited" );
|
||||
if( pushedOverlayIcon && hilitedOverlayIcon )
|
||||
{
|
||||
if(BitTest(window->winGetStatus(), WIN_STATUS_ENABLED))
|
||||
{
|
||||
if (BitTest( instData->getState(), WIN_STATE_HILITED ))
|
||||
{
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
//The button is hilited and pushed
|
||||
TheDisplay->drawImage( pushedOverlayIcon, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
else
|
||||
{
|
||||
//The button is hilited
|
||||
TheDisplay->drawImage( hilitedOverlayIcon, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
}
|
||||
else if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
//The button appears to be pushed -- CHECK_LIKE buttons that are on.
|
||||
TheDisplay->drawImage( pushedOverlayIcon, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end W3DGadgetPushButtonImageDraw
|
||||
|
||||
|
||||
void W3DGadgetPushButtonImageDrawThree(GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
|
||||
const Image *leftImage, *rightImage, *centerImage;
|
||||
ICoord2D origin, size, start, end;
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get image offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
|
||||
//
|
||||
// get pointer to image we want to draw depending on our state,
|
||||
// see GadgetPushButton.h for info
|
||||
//
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
leftImage = GadgetButtonGetLeftDisabledSelectedImage( window );
|
||||
rightImage = GadgetButtonGetRightDisabledSelectedImage( window );
|
||||
centerImage = GadgetButtonGetMiddleDisabledSelectedImage( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
leftImage = GadgetButtonGetLeftDisabledImage( window );
|
||||
rightImage = GadgetButtonGetRightDisabledImage( window );
|
||||
centerImage = GadgetButtonGetMiddleDisabledImage( window );
|
||||
|
||||
}
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
leftImage = GadgetButtonGetLeftHiliteSelectedImage( window );
|
||||
rightImage = GadgetButtonGetRightHiliteSelectedImage( window );
|
||||
centerImage = GadgetButtonGetMiddleHiliteSelectedImage( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
leftImage = GadgetButtonGetLeftHiliteImage( window );
|
||||
rightImage = GadgetButtonGetRightHiliteImage( window );
|
||||
centerImage = GadgetButtonGetMiddleHiliteImage( window );
|
||||
|
||||
}
|
||||
|
||||
} // end else if, hilited and enabled
|
||||
else
|
||||
{
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
leftImage = GadgetButtonGetLeftEnabledSelectedImage( window );
|
||||
rightImage = GadgetButtonGetRightEnabledSelectedImage( window );
|
||||
centerImage = GadgetButtonGetMiddleEnabledSelectedImage( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
leftImage = GadgetButtonGetLeftEnabledImage( window );
|
||||
rightImage = GadgetButtonGetRightEnabledImage( window );
|
||||
centerImage = GadgetButtonGetMiddleEnabledImage( window );
|
||||
|
||||
}
|
||||
|
||||
} // end else, enabled only
|
||||
|
||||
// sanity, we need to have these images to make it look right
|
||||
if( leftImage == NULL || rightImage == NULL ||
|
||||
centerImage == NULL )
|
||||
return;
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D leftSize, rightSize;
|
||||
leftSize.x = leftImage->getImageWidth();
|
||||
leftSize.y = leftImage->getImageHeight();
|
||||
rightSize.x = rightImage->getImageWidth();
|
||||
rightSize.y = rightImage->getImageHeight();
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D leftEnd, rightStart;
|
||||
leftEnd.x = origin.x + leftSize.x + xOffset;
|
||||
leftEnd.y = origin.y + size.y + yOffset;
|
||||
rightStart.x = origin.x + size.x - rightSize.x + xOffset;
|
||||
rightStart.y = origin.y + yOffset;
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerWidth, pieces;
|
||||
|
||||
// get width we have to draw our repeating center in
|
||||
centerWidth = rightStart.x - leftEnd.x;
|
||||
|
||||
if( centerWidth <= 0)
|
||||
{
|
||||
// draw left end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end.y = leftEnd.y;
|
||||
end.x = origin.x + xOffset + size.x/2;
|
||||
TheWindowManager->winDrawImage(leftImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw right end
|
||||
start.y = rightStart.y;
|
||||
start.x = end.x;
|
||||
end.x = origin.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawImage(rightImage, start.x, start.y, end.x, end.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// how many whole repeating pieces will fit in that width
|
||||
pieces = centerWidth / centerImage->getImageWidth();
|
||||
|
||||
// draw the pieces
|
||||
start.x = leftEnd.x;
|
||||
start.y = origin.y + yOffset;
|
||||
end.y = start.y + size.y + yOffset; //centerImage->getImageHeight() + yOffset;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + centerImage->getImageWidth();
|
||||
TheWindowManager->winDrawImage( centerImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += centerImage->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
// we will draw the image but clip the parts we don't want to show
|
||||
IRegion2D reg;
|
||||
reg.lo.x = start.x;
|
||||
reg.lo.y = start.y;
|
||||
reg.hi.x = rightStart.x;
|
||||
reg.hi.y = end.y;
|
||||
centerWidth = rightStart.x - start.x;
|
||||
if( centerWidth > 0)
|
||||
{
|
||||
TheDisplay->setClipRegion(®);
|
||||
end.x = start.x + centerImage->getImageWidth();
|
||||
TheWindowManager->winDrawImage( centerImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
TheDisplay->enableClipping(FALSE);
|
||||
}
|
||||
|
||||
// draw left end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end = leftEnd;
|
||||
TheWindowManager->winDrawImage(leftImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw right end
|
||||
start = rightStart;
|
||||
end.x = start.x + rightSize.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawImage(rightImage, start.x, start.y, end.x, end.y);
|
||||
}
|
||||
|
||||
// draw the button text
|
||||
if( instData->getTextLength() )
|
||||
drawButtonText( window, instData );
|
||||
|
||||
// get window position
|
||||
window->winGetScreenPosition( &start.x, &start.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
|
||||
// if we have a video buffer, draw the video buffer
|
||||
if ( instData->m_videoBuffer )
|
||||
{
|
||||
TheDisplay->drawVideoBuffer( instData->m_videoBuffer, start.x, start.y, start.x + size.x, start.y + size.y );
|
||||
}
|
||||
PushButtonData *pData = (PushButtonData *)window->winGetUserData();
|
||||
|
||||
if( pData )
|
||||
{
|
||||
if( pData->overlayImage )
|
||||
{
|
||||
//Render the overlay image now.
|
||||
TheDisplay->drawImage( pData->overlayImage, origin.x, origin.y, origin.x + size.x, origin.y + size.y );
|
||||
}
|
||||
|
||||
if( pData->drawClock )
|
||||
{
|
||||
if( pData->drawClock == NORMAL_CLOCK )
|
||||
{
|
||||
TheDisplay->drawRectClock(start.x, start.y, size.x, size.y, pData->percentClock,pData->colorClock);
|
||||
}
|
||||
else if( pData->drawClock == INVERSE_CLOCK )
|
||||
{
|
||||
TheDisplay->drawRemainingRectClock( start.x, start.y, size.x, size.y, pData->percentClock,pData->colorClock );
|
||||
}
|
||||
pData->drawClock = NO_CLOCK;
|
||||
window->winSetUserData(pData);
|
||||
}
|
||||
|
||||
if( pData->drawBorder && pData->colorBorder != GAME_COLOR_UNDEFINED )
|
||||
{
|
||||
TheDisplay->drawOpenRect(start.x - 1, start.y - 1, size.x + 2, size.y + 2, 1, pData->colorBorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DRadioButton.cpp ///////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DRadioButton.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D methods needed to implement the RadioButton UI control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetRadioButton.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// drawRadioButtonText ========================================================
|
||||
/** Draw the text for a RadioButton */
|
||||
//=============================================================================
|
||||
static void drawRadioButtonText( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size, textPos;
|
||||
Int width, height;
|
||||
Color textColor, dropColor;
|
||||
DisplayString *text = instData->getTextDisplayString();
|
||||
|
||||
// sanity
|
||||
if( text == NULL || text->getTextLength() == 0 )
|
||||
return;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the right text color
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
dropColor = window->winGetDisabledTextBorderColor();
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
textColor = window->winGetHiliteTextColor();
|
||||
dropColor = window->winGetHiliteTextBorderColor();
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
dropColor = window->winGetEnabledTextBorderColor();
|
||||
} // end enabled only
|
||||
|
||||
// set our font to that of our parent if not the same
|
||||
if( text->getFont() != window->winGetFont() )
|
||||
text->setFont( window->winGetFont() );
|
||||
|
||||
// get text size
|
||||
text->getSize( &width, &height );
|
||||
|
||||
// set the location for our text
|
||||
textPos.x = origin.x + (size.x / 2) - (width / 2);
|
||||
textPos.y = origin.y + (size.y / 2) - (height / 2);
|
||||
|
||||
// draw it
|
||||
text->draw( textPos.x, textPos.y, textColor, dropColor );
|
||||
|
||||
} // end drawRadioButtonText
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetRadioButtonDraw ===================================================
|
||||
/** Draw colored check box using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetRadioButtonDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Int checkOffsetFromLeft;
|
||||
Color backColor,
|
||||
backBorder,
|
||||
boxColor,
|
||||
boxBorder;
|
||||
ICoord2D origin, size, start, end;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// compute start of check offset
|
||||
checkOffsetFromLeft = size.x / 16;
|
||||
|
||||
//
|
||||
// get the colors we should be using to draw, see GadgetRadioButton.h
|
||||
// draw appropriate state, see GadgetRadioButton.h for info
|
||||
//
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
// disabled background
|
||||
backColor = GadgetRadioGetDisabledColor( window );
|
||||
backBorder = GadgetRadioGetDisabledBorderColor( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
boxColor = GadgetRadioGetDisabledCheckedBoxColor( window );
|
||||
boxBorder = GadgetRadioGetDisabledCheckedBoxBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = GadgetRadioGetDisabledUncheckedBoxColor( window );
|
||||
boxBorder = GadgetRadioGetDisabledUncheckedBoxBorderColor( window );
|
||||
}
|
||||
|
||||
} // end if
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
// hilited background
|
||||
backColor = GadgetRadioGetHiliteColor( window );
|
||||
backBorder = GadgetRadioGetHiliteBorderColor( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
boxColor = GadgetRadioGetHiliteCheckedBoxColor( window );
|
||||
boxBorder = GadgetRadioGetHiliteCheckedBoxBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = GadgetRadioGetHiliteUncheckedBoxColor( window );
|
||||
boxBorder = GadgetRadioGetHiliteUncheckedBoxBorderColor( window );
|
||||
}
|
||||
|
||||
} // end else if
|
||||
else
|
||||
{
|
||||
|
||||
// enabled background
|
||||
backColor = GadgetRadioGetEnabledColor( window );
|
||||
backBorder = GadgetRadioGetEnabledBorderColor( window );
|
||||
|
||||
// check box
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
boxColor = GadgetRadioGetEnabledCheckedBoxColor( window );
|
||||
boxBorder = GadgetRadioGetEnabledCheckedBoxBorderColor( window );
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = GadgetRadioGetEnabledUncheckedBoxColor( window );
|
||||
boxBorder = GadgetRadioGetEnabledUncheckedBoxBorderColor( window );
|
||||
}
|
||||
|
||||
} // end else
|
||||
|
||||
// draw background border
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw the background
|
||||
start.x++;
|
||||
start.y++;
|
||||
end.x--;
|
||||
end.y--;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
|
||||
|
||||
// draw box border
|
||||
start.x = origin.x + size.y;
|
||||
start.y = origin.y;
|
||||
end.x = start.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawLine( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw box for button
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = origin.x + size.y -1;
|
||||
end.y = origin.y + size.y -1;
|
||||
TheWindowManager->winFillRect( boxColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw box border
|
||||
start.x = origin.x + size.x - size.y;
|
||||
start.y = origin.y;
|
||||
end.x = start.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawLine( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
// draw box for button
|
||||
start.x = origin.x + size.x - size.y;
|
||||
start.y = origin.y + 1;
|
||||
end.x = origin.x + size.x -1;
|
||||
end.y = origin.y + size.y -1;
|
||||
TheWindowManager->winFillRect( boxColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
// draw the button text
|
||||
if( instData->getTextLength() )
|
||||
drawRadioButtonText( window, instData );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetRadioButtonDraw
|
||||
|
||||
|
||||
void W3DGadgetRadioButtonImageDraw( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
const Image *leftImage, *rightImage, *centerImage;
|
||||
ICoord2D origin, size, start, end;
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
IRegion2D clipLeft;
|
||||
|
||||
// get image offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
|
||||
{
|
||||
//backgroundImage = GadgetRadioGetEnabledCheckedBoxImage( window );
|
||||
leftImage = GadgetRadioGetSelectedImage( window );
|
||||
centerImage = GadgetRadioGetSelectedUncheckedBoxImage( window );
|
||||
rightImage = GadgetRadioGetSelectedCheckedBoxImage( window );
|
||||
|
||||
}
|
||||
else if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
// disabled background
|
||||
leftImage = GadgetRadioGetDisabledImage( window );
|
||||
centerImage = GadgetRadioGetDisabledUncheckedBoxImage( window );
|
||||
rightImage = GadgetRadioGetDisabledCheckedBoxImage( window );
|
||||
|
||||
} // end if
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
// hilited background
|
||||
leftImage = GadgetRadioGetHiliteImage( window );
|
||||
centerImage = GadgetRadioGetHiliteUncheckedBoxImage( window );
|
||||
rightImage = GadgetRadioGetHiliteCheckedBoxImage( window );
|
||||
|
||||
} // end else if
|
||||
else
|
||||
{
|
||||
// enabled background
|
||||
leftImage = GadgetRadioGetEnabledImage( window );
|
||||
centerImage = GadgetRadioGetEnabledUncheckedBoxImage( window );
|
||||
rightImage = GadgetRadioGetEnabledCheckedBoxImage( window );
|
||||
|
||||
} // end else
|
||||
|
||||
// sanity, we need to have these images to make it look right
|
||||
if( leftImage == NULL || centerImage == NULL ||
|
||||
rightImage == NULL )
|
||||
return;
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D leftSize, rightSize;
|
||||
leftSize.x = leftImage->getImageWidth();
|
||||
leftSize.y = leftImage->getImageHeight();
|
||||
rightSize.x = rightImage->getImageWidth();
|
||||
rightSize.y = rightImage->getImageHeight();
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D leftEnd, rightStart;
|
||||
leftEnd.x = origin.x + leftSize.x + xOffset;
|
||||
leftEnd.y = origin.y + size.y + yOffset;
|
||||
rightStart.x = origin.x + size.x - rightSize.x + xOffset;
|
||||
rightStart.y = origin.y + size.y + yOffset;
|
||||
|
||||
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerWidth, pieces;
|
||||
|
||||
// get width we have to draw our repeating center in
|
||||
centerWidth = rightStart.x - leftEnd.x;
|
||||
|
||||
// how many whole repeating pieces will fit in that width
|
||||
pieces = centerWidth / centerImage->getImageWidth();
|
||||
pieces++;
|
||||
// draw the pieces
|
||||
start.x = leftEnd.x;
|
||||
start.y = origin.y + yOffset;
|
||||
end.y =origin.y + size.y + yOffset;
|
||||
|
||||
clipLeft.lo.x = leftEnd.x;
|
||||
clipLeft.lo.y = origin.y;
|
||||
clipLeft.hi.y = leftEnd.y;
|
||||
clipLeft.hi.x = rightStart.x ;
|
||||
|
||||
|
||||
TheDisplay->setClipRegion(&clipLeft);
|
||||
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
end.x = start.x + centerImage->getImageWidth();
|
||||
TheWindowManager->winDrawImage( centerImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += centerImage->getImageWidth();
|
||||
} // end for i
|
||||
|
||||
TheDisplay->enableClipping(FALSE);
|
||||
// draw left end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end = leftEnd;
|
||||
TheWindowManager->winDrawImage(leftImage, start.x, start.y, end.x, end.y);
|
||||
// draw right end
|
||||
start.x = rightStart.x;
|
||||
start.y = origin.y + yOffset;
|
||||
end.x = origin.x + size.x;
|
||||
end.y = leftEnd.y;
|
||||
TheWindowManager->winDrawImage(rightImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw the text
|
||||
if( instData->getTextLength() )
|
||||
drawRadioButtonText( window, instData );
|
||||
|
||||
|
||||
} // end W3DGadgetHorizontalSliderImageDraw
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DStaticText.cpp ////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DStaticText.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation of the static text GUI control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "Common/GlobalData.h"
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetStaticText.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindow.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
//enum { DRAW_BUF_LEN = 2048 };
|
||||
//static WideChar drawBuf[ DRAW_BUF_LEN ];
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
// drawStaticTextText =========================================================
|
||||
/** Draw the text for a static text window */
|
||||
//=============================================================================
|
||||
static void drawStaticTextText( GameWindow *window, WinInstanceData *instData,
|
||||
Color textColor, Color textDropColor )
|
||||
{
|
||||
TextData *tData = (TextData *)window->winGetUserData();
|
||||
Int textWidth, textHeight, wordWrap;
|
||||
DisplayString *text = tData->text;
|
||||
ICoord2D origin, size, textPos;
|
||||
IRegion2D clipRegion;
|
||||
// sanity
|
||||
if( text == NULL || text->getTextLength() == 0 )
|
||||
return;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// Set the text Wrap width
|
||||
wordWrap = size.x - 10;
|
||||
//if(wordWrap == 89)
|
||||
// wordWrap = 95;
|
||||
text->setWordWrap(wordWrap);
|
||||
if( BitTest(window->winGetStatus(), WIN_STATUS_WRAP_CENTERED) )
|
||||
text->setWordWrapCentered(TRUE);
|
||||
else
|
||||
text->setWordWrapCentered(FALSE);
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_HOTKEY_TEXT ) && TheGlobalData)
|
||||
text->setUseHotkey(TRUE, TheGlobalData->m_hotKeyTextColor);
|
||||
else
|
||||
text->setUseHotkey(FALSE, 0);
|
||||
|
||||
|
||||
// how much space will this text take up
|
||||
text->getSize( &textWidth, &textHeight );
|
||||
|
||||
//Init the clip region
|
||||
clipRegion.lo.x = origin.x ;
|
||||
clipRegion.lo.y = origin.y ;
|
||||
clipRegion.hi.x = origin.x + size.x ;
|
||||
clipRegion.hi.y = origin.y + size.y;
|
||||
|
||||
// horizontal centering?
|
||||
if( tData->centered )
|
||||
{
|
||||
textPos.x = origin.x + (size.x / 2) - (textWidth / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
textPos.x = origin.x + tData->leftMargin;
|
||||
}
|
||||
|
||||
// vertical centering?
|
||||
if ( tData->centeredVertically )
|
||||
{
|
||||
textPos.y = origin.y + (size.y / 2) - (textHeight / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
textPos.y = origin.y + tData->topMargin;
|
||||
}
|
||||
|
||||
// draw the text
|
||||
text->setClipRegion(&clipRegion);
|
||||
text->draw( textPos.x, textPos.y, textColor, textDropColor );
|
||||
|
||||
} // end drawStaticTextText
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetStaticTextDraw ====================================================
|
||||
/** Draw colored text field using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetStaticTextDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
TextData *tData = (TextData *)window->winGetUserData();
|
||||
Color backColor, backBorder, textColor, textOutlineColor;
|
||||
ICoord2D size, origin, start, end;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the colors we will use
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
backColor = GadgetStaticTextGetDisabledColor( window );
|
||||
backBorder = GadgetStaticTextGetDisabledBorderColor( window );
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
textOutlineColor = window->winGetDisabledTextBorderColor();
|
||||
|
||||
} // end if, disabled
|
||||
else
|
||||
{
|
||||
|
||||
backColor = GadgetStaticTextGetEnabledColor( window );
|
||||
backBorder = GadgetStaticTextGetEnabledBorderColor( window );
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
textOutlineColor = window->winGetEnabledTextBorderColor();
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// draw the back border
|
||||
if( backBorder != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the back fill area
|
||||
if( backColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = start.x + size.x - 2;
|
||||
end.y = start.y + size.y - 2;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
} // end if
|
||||
|
||||
// draw the text
|
||||
if( tData->text && (textColor != WIN_COLOR_UNDEFINED) )
|
||||
drawStaticTextText( window, instData, textColor, textOutlineColor );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetStaticTextDraw
|
||||
|
||||
// W3DGadgetStaticTextImageDraw ===============================================
|
||||
/** Draw colored text field with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetStaticTextImageDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
TextData *tData = (TextData *)window->winGetUserData();
|
||||
Color textColor, textOutlineColor;
|
||||
ICoord2D size, origin, start, end;
|
||||
const Image *image;
|
||||
|
||||
// get window position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the colors we will use
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
image = GadgetStaticTextGetDisabledImage( window );
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
textOutlineColor = window->winGetDisabledTextBorderColor();
|
||||
|
||||
} // end if, disabled
|
||||
else
|
||||
{
|
||||
|
||||
image = GadgetStaticTextGetEnabledImage( window );
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
textOutlineColor = window->winGetEnabledTextBorderColor();
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// draw the back image
|
||||
if( image )
|
||||
{
|
||||
|
||||
start.x = origin.x + instData->m_imageOffset.x;
|
||||
start.y = origin.y + instData->m_imageOffset.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawImage( image, start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the text
|
||||
if( tData->text && (textColor != WIN_COLOR_UNDEFINED) )
|
||||
drawStaticTextText( window, instData, textColor, textOutlineColor );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetStaticTextImageDraw
|
||||
|
||||
@@ -0,0 +1,652 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTabControl.cpp ///////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: projects\RTS\code\gameenginedevice\Source\W3DDevice\GameClient\GUI\Gadget\W3DTabControl.cpp
|
||||
//
|
||||
// Created: Graham Smallwood, November 2001
|
||||
//
|
||||
// Desc: W3D methods needed to implement the TabControl UI control
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetTabControl.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindow.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetRadioButtonDraw ===================================================
|
||||
/** Draw tabs with standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetTabControlDraw( GameWindow *tabControl, WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size;
|
||||
|
||||
// get window position and size
|
||||
tabControl->winGetScreenPosition( &origin.x, &origin.y );
|
||||
tabControl->winGetSize( &size.x, &size.y );
|
||||
|
||||
W3DGameWinDefaultDraw(tabControl, instData);//draw the background
|
||||
|
||||
if( BitTest( tabControl->winGetStatus(), WIN_STATUS_BORDER ) == TRUE &&
|
||||
!BitTest( tabControl->winGetStatus(), WIN_STATUS_SEE_THRU ) )
|
||||
{//draw border if desired
|
||||
tabControl->winDrawBorder();
|
||||
}
|
||||
|
||||
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
|
||||
|
||||
Int tabX, tabY, tabWidth, tabHeight, tabDeltaX, tabDeltaY;
|
||||
tabX = origin.x + tabData->tabsLeftLimit;
|
||||
tabY = origin.y + tabData->tabsTopLimit;
|
||||
tabWidth = tabData->tabWidth;
|
||||
tabHeight = tabData->tabHeight;
|
||||
if( (tabData->tabEdge == TP_TOP_SIDE) || (tabData->tabEdge == TP_BOTTOM_SIDE) )
|
||||
{
|
||||
tabDeltaX = tabWidth;
|
||||
tabDeltaY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tabDeltaX = 0;
|
||||
tabDeltaY = tabHeight;
|
||||
}
|
||||
|
||||
Color color, border;
|
||||
|
||||
if( tabData->tabCount >= 1 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[0] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabZero( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabZero( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 0 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabZero( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabZero( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabZero( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabZero( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 2 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[1] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabOne( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabOne( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 1 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabOne( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabOne( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabOne( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabOne( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 3 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[2] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabTwo( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabTwo( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 2 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabTwo( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabTwo( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabTwo( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabTwo( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 4 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[3] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabThree( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabThree( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 3 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabThree( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabThree( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabThree( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabThree( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 5 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[4] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabFour( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabFour( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 4 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabFour( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabFour( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabFour( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabFour( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 6 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[5] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabFive( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabFive( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 5 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabFive( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabFive( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabFive( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabFive( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 7 )//Doesn't exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[6] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabSix( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabSix( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 6 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabSix( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabSix( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabSix( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabSix( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 8 )//Doesn't exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[7] )
|
||||
{//Disabled
|
||||
color = GadgetTabControlGetDisabledColorTabSeven( tabControl );
|
||||
border = GadgetTabControlGetDisabledBorderColorTabSeven( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 7 )
|
||||
{//Hilited/Active
|
||||
color = GadgetTabControlGetHiliteColorTabSeven( tabControl );
|
||||
border = GadgetTabControlGetHiliteBorderColorTabSeven( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
color = GadgetTabControlGetEnabledColorTabSeven( tabControl );
|
||||
border = GadgetTabControlGetEnabledBorderColorTabSeven( tabControl );
|
||||
}
|
||||
|
||||
// box and border
|
||||
if( border != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winOpenRect( border, WIN_DRAW_LINE_WIDTH,
|
||||
tabX, tabY, tabX + tabWidth, tabY + tabHeight );
|
||||
}
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
TheWindowManager->winFillRect( color, WIN_DRAW_LINE_WIDTH,
|
||||
tabX + 1, tabY + 1, tabX + tabWidth - 1, tabY + tabHeight - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
} // end W3DGadgetTabControlDraw
|
||||
|
||||
// W3DGadgetRadioButtonImageDraw ==============================================
|
||||
/** Draw tabs with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetTabControlImageDraw( GameWindow *tabControl,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
ICoord2D origin, size;
|
||||
|
||||
// get window position and size
|
||||
tabControl->winGetScreenPosition( &origin.x, &origin.y );
|
||||
tabControl->winGetSize( &size.x, &size.y );
|
||||
|
||||
W3DGameWinDefaultDraw(tabControl, instData);//draw the background
|
||||
|
||||
if( BitTest( tabControl->winGetStatus(), WIN_STATUS_BORDER ) == TRUE &&
|
||||
!BitTest( tabControl->winGetStatus(), WIN_STATUS_SEE_THRU ) )
|
||||
{//draw border if desired
|
||||
tabControl->winDrawBorder();
|
||||
}
|
||||
|
||||
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
|
||||
|
||||
Int tabX, tabY, tabWidth, tabHeight, tabDeltaX, tabDeltaY;
|
||||
tabX = origin.x + tabData->tabsLeftLimit;
|
||||
tabY = origin.y + tabData->tabsTopLimit;
|
||||
tabWidth = tabData->tabWidth;
|
||||
tabHeight = tabData->tabHeight;
|
||||
if( (tabData->tabEdge == TP_TOP_SIDE) || (tabData->tabEdge == TP_BOTTOM_SIDE) )
|
||||
{
|
||||
tabDeltaX = tabWidth;
|
||||
tabDeltaY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tabDeltaX = 0;
|
||||
tabDeltaY = tabHeight;
|
||||
}
|
||||
|
||||
const Image *image = NULL;
|
||||
|
||||
if( tabData->tabCount >= 1 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[0] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabZero( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 0 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabZero( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabZero( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 2 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[1] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabOne( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 1 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabOne( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabOne( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 3 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[2] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabTwo( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 2 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabTwo( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabTwo( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 4 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[3] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabThree( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 3 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabThree( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabThree( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 5 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[4] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabFour( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 4 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabFour( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabFour( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 6 )//Does exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[5] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabFive( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 5 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabFive( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabFive( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 7 )//Doesn't exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[6] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabSix( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 6 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabSix( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabSix( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
tabX += tabDeltaX;
|
||||
tabY += tabDeltaY;
|
||||
|
||||
if( tabData->tabCount >= 8 )//Doesn't exist
|
||||
{
|
||||
if( tabData->subPaneDisabled[7] )
|
||||
{//Disabled
|
||||
image = GadgetTabControlGetDisabledImageTabSeven( tabControl );
|
||||
}
|
||||
else if( tabData->activeTab == 7 )
|
||||
{//Hilited/Active
|
||||
image = GadgetTabControlGetHiliteImageTabSeven( tabControl );
|
||||
}
|
||||
else
|
||||
{//Just enabled
|
||||
image = GadgetTabControlGetEnabledImageTabSeven( tabControl );
|
||||
}
|
||||
|
||||
if( image != NULL )
|
||||
{
|
||||
TheWindowManager->winDrawImage( image,
|
||||
tabX,
|
||||
tabY,
|
||||
tabX + tabWidth,
|
||||
tabY + tabHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} // end W3DGadgetTabControlImageDraw
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTextEntry.cpp /////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DTextEntry.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation for the text entry gadget
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GadgetTextEntry.h"
|
||||
#include "GameClient/IMEManager.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// drawTextEntryText ==========================================================
|
||||
//=============================================================================
|
||||
static void drawTextEntryText( GameWindow *window, WinInstanceData *instData,
|
||||
Color textColor, Color textDropColor,
|
||||
Color compositeColor, Color compositeDropColor,
|
||||
Int x, Int y, Int width, Int fontHeight )
|
||||
{
|
||||
static Byte drawCnt = 0;
|
||||
EntryData *e = (EntryData *)window->winGetUserData();
|
||||
// Int charPos = e->charPos;
|
||||
Int cursorPos;
|
||||
|
||||
// WideChar buffer[ ENTRY_TEXT_LEN + 1 ];
|
||||
// WideChar *bufptr = buffer;
|
||||
// Color constructColor = TheWindowManager->winMakeColor( 192, 0, 192, 255 );
|
||||
DisplayString *text = e->text;
|
||||
IRegion2D clipRegion;
|
||||
ICoord2D origin, size;
|
||||
Int compositeCursorPos = 0;
|
||||
|
||||
// Check to see if the IME manager is composing text
|
||||
e->constructText->setText(UnicodeString::TheEmptyString);
|
||||
if ( TheIMEManager && TheIMEManager->isAttachedTo( window) && TheIMEManager->isComposing())
|
||||
{
|
||||
// The user is composing a string.
|
||||
// Show the composition in the text gadget.
|
||||
UnicodeString composition;
|
||||
|
||||
TheIMEManager->getCompositionString( composition );
|
||||
|
||||
if ( e->secretText )
|
||||
{
|
||||
e->sText->setText( UnicodeString::TheEmptyString );
|
||||
Int len = composition.getLength() + e->text->getTextLength();
|
||||
for ( int i = 0; i < len; i++ )
|
||||
{
|
||||
e->sText->appendChar( '*' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e->constructText->setText( composition );
|
||||
compositeCursorPos = TheIMEManager->getCompositionCursorPosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// get out of here if no text color to show up
|
||||
if( textColor == WIN_COLOR_UNDEFINED )
|
||||
return;
|
||||
|
||||
// if our text is "secret" we will print only '*' characters
|
||||
if( e->secretText )
|
||||
text = e->sText;
|
||||
|
||||
// make sure our font is the same as our parents
|
||||
if( text->getFont() != window->winGetFont() )
|
||||
text->setFont( window->winGetFont() );
|
||||
if( e->constructText->getFont() != window->winGetFont() )
|
||||
e->constructText->setFont( window->winGetFont() );
|
||||
|
||||
// get the size of our text, and construct text
|
||||
Int textWidth = text->getWidth();
|
||||
|
||||
if (!e->drawTextFromStart)
|
||||
{
|
||||
// clip the text to the edit window size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
clipRegion.lo.x = x;
|
||||
clipRegion.hi.x = x + width ;
|
||||
clipRegion.lo.y = y;
|
||||
clipRegion.hi.y = y + fontHeight;
|
||||
text->setClipRegion( &clipRegion );
|
||||
e->constructText->setClipRegion( &clipRegion );
|
||||
|
||||
// set construct window position if needed
|
||||
//if( e->constructList && e->constructText->getTextLength() )
|
||||
// e->constructList->winSetPosition( (x + textWidth1), (y + fontHeight) );
|
||||
|
||||
x+= 2;
|
||||
// draw the text
|
||||
if(textWidth < width)
|
||||
{
|
||||
text->draw( x, y, textColor, textDropColor );
|
||||
cursorPos = textWidth + x;
|
||||
}
|
||||
else
|
||||
{
|
||||
Int div = textWidth / (width / 2) - 1;
|
||||
text->draw(x - (div * (width/2)), y, textColor, textDropColor);
|
||||
cursorPos = textWidth - (div * (width/2)) + x;
|
||||
}
|
||||
|
||||
//cursorPos = x + textWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
clipRegion.lo.x = origin.x;
|
||||
clipRegion.hi.x = origin.x + size.x;
|
||||
clipRegion.lo.y = origin.y;
|
||||
clipRegion.hi.y = origin.y + size.y;
|
||||
text->setClipRegion( &clipRegion );
|
||||
e->constructText->setClipRegion( &clipRegion );
|
||||
|
||||
// set construct window position if needed
|
||||
//if( e->constructList && e->constructText->getTextLength() )
|
||||
// e->constructList->winSetPosition( (x + textWidth1), (y + fontHeight) );
|
||||
|
||||
x+= 5;
|
||||
// draw the text
|
||||
text->draw( x, y, textColor, textDropColor );
|
||||
cursorPos = textWidth + x;
|
||||
}
|
||||
|
||||
if (e->constructText->getTextLength() > 0 )
|
||||
{
|
||||
e->constructText->draw( x + textWidth, y, compositeColor, compositeDropColor );
|
||||
cursorPos += e->constructText->getWidth( compositeCursorPos );
|
||||
}
|
||||
|
||||
// draw blinking cursor
|
||||
GameWindow *parent;
|
||||
parent = window->winGetParent();
|
||||
if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
|
||||
parent = NULL;
|
||||
|
||||
if( (window == TheWindowManager->winGetFocus() || (parent && parent == TheWindowManager->winGetFocus())) && ((drawCnt++ >> 3) & 0x1) )
|
||||
TheWindowManager->winFillRect( textColor, WIN_DRAW_LINE_WIDTH,
|
||||
cursorPos, origin.y + 3,
|
||||
cursorPos + 2, origin.y + size.y - 3 );
|
||||
window->winSetCursorPosition( cursorPos + 2 - origin.x, 0 );
|
||||
|
||||
} // end drawTextEntryText
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetTextEntryDraw =====================================================
|
||||
/** Draw colored entry field using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetTextEntryDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
EntryData *e = (EntryData *)window->winGetUserData();
|
||||
ICoord2D origin, size, start, end;
|
||||
Color backBorder, backColor, textColor, textBorder,
|
||||
compositeColor, compositeBorder;
|
||||
|
||||
// cancel unichar flag
|
||||
e->receivedUnichar = FALSE;
|
||||
|
||||
// get size and position of window
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the right colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
compositeColor = window->winGetDisabledTextColor();
|
||||
compositeBorder = window->winGetDisabledTextBorderColor();
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
textBorder = window->winGetDisabledTextBorderColor();
|
||||
backColor = GadgetTextEntryGetDisabledColor( window );
|
||||
backBorder = GadgetTextEntryGetDisabledBorderColor( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
compositeColor = window->winGetIMECompositeTextColor();
|
||||
compositeBorder = window->winGetIMECompositeBorderColor();
|
||||
textColor = window->winGetHiliteTextColor();
|
||||
textBorder = window->winGetHiliteTextBorderColor();
|
||||
backColor = GadgetTextEntryGetHiliteColor( window );
|
||||
backBorder = GadgetTextEntryGetHiliteBorderColor( window );
|
||||
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
|
||||
compositeColor = window->winGetIMECompositeTextColor();
|
||||
compositeBorder = window->winGetIMECompositeBorderColor();
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
textBorder = window->winGetEnabledTextBorderColor();
|
||||
backColor = GadgetTextEntryGetEnabledColor( window );
|
||||
backBorder = GadgetTextEntryGetEnabledBorderColor( window );
|
||||
|
||||
} // end else, just enabled
|
||||
|
||||
// draw the back border
|
||||
if( backBorder != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the filled back
|
||||
if( backColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = start.x + size.x - 2;
|
||||
end.y = start.y + size.y - 2;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the text
|
||||
Int fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
|
||||
Int startOffset = 5;
|
||||
Int width;
|
||||
|
||||
width = size.x - (2 * startOffset);
|
||||
start.x = origin.x + startOffset; // offset a little bit into the entry
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) )
|
||||
start.y = size.y / 2 - fontHeight / 2;
|
||||
else
|
||||
start.y = origin.y + startOffset; // offset a little bit into the entry
|
||||
|
||||
// draw the edit text
|
||||
drawTextEntryText( window, instData, textColor, textBorder, compositeColor, compositeBorder,
|
||||
start.x, start.y, width, fontHeight );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetTextEntryDraw
|
||||
|
||||
// W3DGadgetTextEntryImageDraw ================================================
|
||||
/** Draw horizontal slider with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetTextEntryImageDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
EntryData *e = (EntryData *)window->winGetUserData();
|
||||
ICoord2D origin, size, start, end;
|
||||
Color textColor, textBorder;
|
||||
Color compositeColor, compositeBorder;
|
||||
const Image *leftImage, *rightImage, *centerImage, *smallCenterImage;
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
|
||||
// cancel unichar flag
|
||||
e->receivedUnichar = FALSE;
|
||||
|
||||
// get size and position of window
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get image offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
// get the right colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
textColor = window->winGetDisabledTextColor();
|
||||
textBorder = window->winGetDisabledTextBorderColor();
|
||||
compositeColor = window->winGetDisabledTextColor();
|
||||
compositeBorder = window->winGetDisabledTextBorderColor();
|
||||
leftImage = GadgetTextEntryGetDisabledImageLeft( window );
|
||||
rightImage = GadgetTextEntryGetDisabledImageRight( window );
|
||||
centerImage = GadgetTextEntryGetDisabledImageCenter( window );
|
||||
smallCenterImage = GadgetTextEntryGetDisabledImageSmallCenter( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
textColor = window->winGetHiliteTextColor();
|
||||
textBorder = window->winGetHiliteTextBorderColor();
|
||||
compositeColor = window->winGetIMECompositeTextColor();
|
||||
compositeBorder = window->winGetIMECompositeBorderColor();
|
||||
leftImage = GadgetTextEntryGetHiliteImageLeft( window );
|
||||
rightImage = GadgetTextEntryGetHiliteImageRight( window );
|
||||
centerImage = GadgetTextEntryGetHiliteImageCenter( window );
|
||||
smallCenterImage = GadgetTextEntryGetHiliteImageSmallCenter( window );
|
||||
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
|
||||
textColor = window->winGetEnabledTextColor();
|
||||
textBorder = window->winGetEnabledTextBorderColor();
|
||||
compositeColor = window->winGetIMECompositeTextColor();
|
||||
compositeBorder = window->winGetIMECompositeBorderColor();
|
||||
leftImage = GadgetTextEntryGetEnabledImageLeft( window );
|
||||
rightImage = GadgetTextEntryGetEnabledImageRight( window );
|
||||
centerImage = GadgetTextEntryGetEnabledImageCenter( window );
|
||||
smallCenterImage = GadgetTextEntryGetEnabledImageSmallCenter( window );
|
||||
|
||||
} // end else, just enabled
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D leftSize, rightSize;
|
||||
leftSize.x = leftImage->getImageWidth();
|
||||
leftSize.y = leftImage->getImageHeight();
|
||||
rightSize.x = rightImage->getImageWidth();
|
||||
rightSize.y = rightImage->getImageHeight();
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D leftEnd, rightStart;
|
||||
leftEnd.x = origin.x + leftSize.x + xOffset;
|
||||
leftEnd.y = origin.y + size.y + yOffset;
|
||||
rightStart.x = origin.x + size.x - rightSize.x + xOffset;
|
||||
rightStart.y = origin.y + yOffset;
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerWidth, pieces;
|
||||
|
||||
// get width we have to draw our repeating center in
|
||||
centerWidth = rightStart.x - leftEnd.x;
|
||||
|
||||
// how many whole repeating pieces will fit in that width
|
||||
pieces = centerWidth / centerImage->getImageWidth();
|
||||
|
||||
// draw the pieces
|
||||
start.x = leftEnd.x;
|
||||
start.y = origin.y + yOffset;
|
||||
end.y = start.y + size.y;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + centerImage->getImageWidth();
|
||||
TheWindowManager->winDrawImage( centerImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += centerImage->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
//
|
||||
// how many small repeating pieces will fit in the gap from where the
|
||||
// center repeating bar stopped and the right image, draw them
|
||||
// and overlapping underneath where the right end will go
|
||||
//
|
||||
centerWidth = rightStart.x - start.x;
|
||||
pieces = centerWidth / smallCenterImage->getImageWidth() + 1;
|
||||
end.y = start.y + size.y;
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
end.x = start.x + smallCenterImage->getImageWidth();
|
||||
TheWindowManager->winDrawImage( smallCenterImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.x += smallCenterImage->getImageWidth();
|
||||
|
||||
} // end for i
|
||||
|
||||
// draw left end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end = leftEnd;
|
||||
TheWindowManager->winDrawImage(leftImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw right end
|
||||
start = rightStart;
|
||||
end.x = start.x + rightSize.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawImage(rightImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw the text
|
||||
Int fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
|
||||
Int startOffset = 5;
|
||||
Int width;
|
||||
|
||||
width = size.x - (2 * startOffset);
|
||||
start.x = origin.x + startOffset; // offset a little bit into the entry
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) )
|
||||
start.y = size.y / 2 - fontHeight / 2;
|
||||
else
|
||||
start.y = origin.y + startOffset; // offset a little bit into the entry
|
||||
|
||||
// draw the edit text
|
||||
drawTextEntryText( window, instData, textColor, textBorder, compositeColor, compositeBorder,
|
||||
start.x, start.y, width, fontHeight );
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetTextEntryImageDraw
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: .cpp /////////////////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project:
|
||||
//
|
||||
// File name: .cpp
|
||||
//
|
||||
// Created:
|
||||
//
|
||||
// Desc:
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GadgetSlider.h"
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "W3DDevice/GameClient/W3DGadget.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGadgetVerticalSliderDraw ================================================
|
||||
/** Draw colored vertical slider using standard graphics */
|
||||
//=============================================================================
|
||||
void W3DGadgetVerticalSliderDraw( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
Color backBorder, backColor;
|
||||
ICoord2D origin, size, start, end;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get the right colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
backBorder = GadgetSliderGetDisabledBorderColor( window );
|
||||
backColor = GadgetSliderGetDisabledColor( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
backBorder = GadgetSliderGetHiliteBorderColor( window );
|
||||
backColor = GadgetSliderGetHiliteColor( window );
|
||||
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
|
||||
backBorder = GadgetSliderGetEnabledBorderColor( window );
|
||||
backColor = GadgetSliderGetEnabledColor( window );
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// draw background border and rect over whole control
|
||||
if( backBorder != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x;
|
||||
start.y = origin.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
if( backColor != WIN_COLOR_UNDEFINED )
|
||||
{
|
||||
|
||||
start.x = origin.x + 1;
|
||||
start.y = origin.y + 1;
|
||||
end.x = start.x + size.x - 2;
|
||||
end.y = start.y + size.y - 2;
|
||||
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
|
||||
start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
|
||||
|
||||
} // end W3DGadgetVerticalSliderDraw
|
||||
|
||||
// W3DGadgetVerticalSliderImageDraw ===========================================
|
||||
/** Draw vertical slider with user supplied images */
|
||||
//=============================================================================
|
||||
void W3DGadgetVerticalSliderImageDraw( GameWindow *window,
|
||||
WinInstanceData *instData )
|
||||
{
|
||||
const Image *topImage, *bottomImage, *centerImage, *smallCenterImage;
|
||||
ICoord2D origin, size, start, end;
|
||||
Int xOffset, yOffset;
|
||||
Int i;
|
||||
|
||||
// get screen position and size
|
||||
window->winGetScreenPosition( &origin.x, &origin.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
// get image offset
|
||||
xOffset = instData->m_imageOffset.x;
|
||||
yOffset = instData->m_imageOffset.y;
|
||||
|
||||
// get the right images
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
topImage = GadgetSliderGetDisabledImageTop( window );
|
||||
bottomImage = GadgetSliderGetDisabledImageBottom( window );
|
||||
centerImage = GadgetSliderGetDisabledImageCenter( window );
|
||||
smallCenterImage = GadgetSliderGetDisabledImageSmallCenter( window );
|
||||
|
||||
} // end if, disabled
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
topImage = GadgetSliderGetHiliteImageTop( window );
|
||||
bottomImage = GadgetSliderGetHiliteImageBottom( window );
|
||||
centerImage = GadgetSliderGetHiliteImageCenter( window );
|
||||
smallCenterImage = GadgetSliderGetHiliteImageSmallCenter( window );
|
||||
|
||||
} // end else if, hilited
|
||||
else
|
||||
{
|
||||
|
||||
topImage = GadgetSliderGetEnabledImageTop( window );
|
||||
bottomImage = GadgetSliderGetEnabledImageBottom( window );
|
||||
centerImage = GadgetSliderGetEnabledImageCenter( window );
|
||||
smallCenterImage = GadgetSliderGetEnabledImageSmallCenter( window );
|
||||
|
||||
} // end else, enabled
|
||||
|
||||
// sanity, we need to have these images to make it look right
|
||||
if( topImage == NULL || bottomImage == NULL ||
|
||||
centerImage == NULL || smallCenterImage == NULL )
|
||||
return;
|
||||
|
||||
// get image sizes for the ends
|
||||
ICoord2D topSize, bottomSize;
|
||||
topSize.x = topImage->getImageWidth();
|
||||
topSize.y = topImage->getImageHeight();
|
||||
bottomSize.x = bottomImage->getImageWidth();
|
||||
bottomSize.y = bottomImage->getImageHeight();
|
||||
|
||||
if(topSize.y + bottomSize.y >= size.y)
|
||||
{
|
||||
// draw top end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end.x = origin.x + xOffset + topSize.x;
|
||||
end.y = origin.y + size.y /2;
|
||||
TheWindowManager->winDrawImage(topImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw bottom end
|
||||
start.y = origin.y + size.y /2;
|
||||
end.x = origin.x + xOffset + bottomSize.x;
|
||||
end.y = origin.y + yOffset + size.y;
|
||||
TheWindowManager->winDrawImage(bottomImage, start.x, start.y, end.x, end.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// get two key points used in the end drawing
|
||||
ICoord2D topEnd, bottomStart;
|
||||
topEnd.x = origin.x + topSize.x + xOffset;
|
||||
topEnd.y = origin.y + topSize.y + yOffset;
|
||||
bottomStart.x = origin.x + xOffset;
|
||||
bottomStart.y = origin.y + size.y - bottomSize.y + yOffset;
|
||||
|
||||
// draw the center repeating bar
|
||||
Int centerHeight, pieces;
|
||||
|
||||
// get size we have to draw our repeating center in
|
||||
centerHeight = bottomStart.y - topEnd.y;
|
||||
|
||||
// how many whole repeating pieces will fit in that size
|
||||
pieces = centerHeight / centerImage->getImageHeight();
|
||||
|
||||
// draw the pieces
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = topEnd.y;
|
||||
end.x = start.x + centerImage->getImageWidth();
|
||||
end.y = start.y + centerImage->getImageHeight();
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
TheWindowManager->winDrawImage( centerImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.y += centerImage->getImageHeight();
|
||||
end.y += centerImage->getImageHeight();
|
||||
|
||||
} // end for i
|
||||
|
||||
//
|
||||
// how many small repeating pieces will fit in the gap from where the
|
||||
// center repeating bar stopped and the bottom image, draw them
|
||||
// and overlapping underneath where the bottom end will go
|
||||
//
|
||||
centerHeight = bottomStart.y - start.y;
|
||||
pieces = centerHeight / smallCenterImage->getImageHeight() + 1;
|
||||
end.y = start.y + smallCenterImage->getImageHeight();
|
||||
for( i = 0; i < pieces; i++ )
|
||||
{
|
||||
|
||||
TheWindowManager->winDrawImage( smallCenterImage,
|
||||
start.x, start.y,
|
||||
end.x, end.y );
|
||||
start.y += smallCenterImage->getImageHeight();
|
||||
end.y += smallCenterImage->getImageHeight();
|
||||
|
||||
} // end for i
|
||||
|
||||
// draw top end
|
||||
start.x = origin.x + xOffset;
|
||||
start.y = origin.y + yOffset;
|
||||
end = topEnd;
|
||||
TheWindowManager->winDrawImage(topImage, start.x, start.y, end.x, end.y);
|
||||
|
||||
// draw bottom end
|
||||
start = bottomStart;
|
||||
end.x = start.x + bottomSize.x;
|
||||
end.y = start.y + bottomSize.y;
|
||||
TheWindowManager->winDrawImage(bottomImage, start.x, start.y, end.x, end.y);
|
||||
}
|
||||
|
||||
|
||||
} // end W3DGadgetVerticalSliderImageDraw
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DGameFont.cpp //////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DGameFont.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation for managing font definitions
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "Common/Debug.h"
|
||||
#include "W3DDevice/GameClient/W3DGameFont.h"
|
||||
#include "WW3D2/WW3D.h"
|
||||
#include "WW3D2/AssetMgr.h"
|
||||
#include "WW3D2/Render2DSentence.h"
|
||||
#include "GameClient/GlobalLanguage.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DFontLibrary::loadFontData ===============================================
|
||||
/** Load a font */
|
||||
//=============================================================================
|
||||
Bool W3DFontLibrary::loadFontData( GameFont *font )
|
||||
{
|
||||
FontCharsClass *fontChar;
|
||||
|
||||
// sanity
|
||||
if( font == NULL )
|
||||
return FALSE;
|
||||
|
||||
if ((UnsignedInt)font->pointSize > 100) //sanity check the size - anything over 100 is probably wrong. -MW
|
||||
fontChar = NULL;
|
||||
else
|
||||
{ // get the font data from the asset manager
|
||||
fontChar = WW3DAssetManager::
|
||||
Get_Instance()->Get_FontChars( font->nameString.str(), font->pointSize,
|
||||
font->bold ? true : false );
|
||||
}
|
||||
|
||||
if( fontChar == NULL )
|
||||
{
|
||||
|
||||
DEBUG_LOG(( "W3D load font: unable to find font '%s' from asset manager\n",
|
||||
font->nameString.str() ));
|
||||
DEBUG_ASSERTCRASH(fontChar, ("Missing or Corrupted Font. Pleas see log for details"));
|
||||
return FALSE;
|
||||
|
||||
} // end if
|
||||
|
||||
// assign font data
|
||||
font->fontData = fontChar;
|
||||
font->height = fontChar->Get_Char_Height();
|
||||
|
||||
FontCharsClass *unicodeFontChar = NULL;
|
||||
|
||||
// load unicode of same point size
|
||||
if(TheGlobalLanguageData)
|
||||
unicodeFontChar = WW3DAssetManager::
|
||||
Get_Instance()->Get_FontChars( TheGlobalLanguageData->m_unicodeFontName.str(), font->pointSize,
|
||||
font->bold ? true : false );
|
||||
else
|
||||
unicodeFontChar = WW3DAssetManager::
|
||||
Get_Instance()->Get_FontChars( "Arial Unicode MS", font->pointSize,
|
||||
font->bold ? true : false );
|
||||
|
||||
if ( unicodeFontChar )
|
||||
{
|
||||
fontChar->AlternateUnicodeFont = unicodeFontChar;
|
||||
}
|
||||
|
||||
// all done and loaded
|
||||
return TRUE;
|
||||
|
||||
} // end loadFont
|
||||
|
||||
// W3DFontLibrary::releaseFontData ============================================
|
||||
/** Release font data */
|
||||
//=============================================================================
|
||||
void W3DFontLibrary::releaseFontData( GameFont *font )
|
||||
{
|
||||
|
||||
// presently we don't need to do anything because fonts are handled in
|
||||
// the W3D asset manager which is all taken for of us
|
||||
if (font && font->fontData)
|
||||
{
|
||||
if(((FontCharsClass *)(font->fontData))->AlternateUnicodeFont)
|
||||
((FontCharsClass *)(font->fontData))->AlternateUnicodeFont->Release_Ref();
|
||||
((FontCharsClass *)(font->fontData))->Release_Ref();
|
||||
}
|
||||
font->fontData = NULL;
|
||||
|
||||
} // end releaseFont
|
||||
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DGameWindow.cpp ////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DGameWindow.cpp
|
||||
//
|
||||
// Created: Colin Day, June 2001
|
||||
//
|
||||
// Desc: W3D implementation of a game window
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/Gadget.h"
|
||||
#include "GameClient/GameWindowGlobal.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindow.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindowManager.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
enum
|
||||
{
|
||||
BORDER_CORNER_SIZE = 15,
|
||||
BORDER_LINE_SIZE = 20,
|
||||
};
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static Bool bordersInit = FALSE;
|
||||
static const Image *borderPieces[NUM_BORDER_PIECES] = { 0 };
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// initBorders ================================================================
|
||||
//=============================================================================
|
||||
static void initBorders( void )
|
||||
{
|
||||
|
||||
borderPieces[ BORDER_CORNER_UL ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderCornerUL" ) );
|
||||
|
||||
borderPieces[ BORDER_CORNER_UR ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderCornerUR" ) );
|
||||
|
||||
borderPieces[ BORDER_CORNER_LL ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderCornerLL" ) );
|
||||
|
||||
borderPieces[ BORDER_CORNER_LR ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderCornerLR" ) );
|
||||
|
||||
borderPieces[ BORDER_VERTICAL_LEFT ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderLeft" ) );
|
||||
|
||||
borderPieces[ BORDER_VERTICAL_LEFT_SHORT ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderLeftShort" ) );
|
||||
|
||||
borderPieces[ BORDER_HORIZONTAL_TOP ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderTop" ) );
|
||||
|
||||
borderPieces[ BORDER_HORIZONTAL_TOP_SHORT ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderTopShort" ) );
|
||||
|
||||
borderPieces[ BORDER_VERTICAL_RIGHT ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderRight" ) );
|
||||
|
||||
borderPieces[ BORDER_VERTICAL_RIGHT_SHORT ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderRightShort" ) );
|
||||
|
||||
borderPieces[ BORDER_HORIZONTAL_BOTTOM ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderBottom" ) );
|
||||
|
||||
borderPieces[ BORDER_HORIZONTAL_BOTTOM_SHORT ] =
|
||||
TheMappedImageCollection->findImageByName( AsciiString( "BorderBottomShort" ) );
|
||||
|
||||
bordersInit = TRUE;
|
||||
|
||||
}
|
||||
|
||||
// W3DGameWindow::blitBorderRect ==============================================
|
||||
//=============================================================================
|
||||
void W3DGameWindow::blitBorderRect( Int x, Int y, Int width, Int height )
|
||||
{
|
||||
Int Offset = 15;
|
||||
Int OffsetLower = 5;
|
||||
// init image loc if needed
|
||||
if( bordersInit == FALSE )
|
||||
initBorders();
|
||||
|
||||
// save original x, y
|
||||
Int originalX = x;
|
||||
Int originalY = y;
|
||||
Int maxX = x + width;
|
||||
Int maxY = y + height;
|
||||
Int x2, y2; // used for simultaneous drawing of line pairs
|
||||
Int size = 20;
|
||||
Int halfSize = size / 2;
|
||||
|
||||
// Draw Horizontal Lines
|
||||
// All border pieces are based on a 10 pixel offset from the centerline
|
||||
y = originalY - Offset;
|
||||
y2 = maxY - OffsetLower;
|
||||
x2 = maxX - (OffsetLower + BORDER_LINE_SIZE);
|
||||
|
||||
for( x=(originalX + OffsetLower); x <= x2; x += BORDER_LINE_SIZE )
|
||||
{
|
||||
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_HORIZONTAL_TOP ],
|
||||
x, y, x + size, y + size );
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_HORIZONTAL_BOTTOM ],
|
||||
x, y2, x + size, y2 + size );
|
||||
|
||||
}
|
||||
|
||||
x2 = maxX - 5;//BORDER_CORNER_SIZE;
|
||||
|
||||
// x == place to draw remainder if any
|
||||
if( (x2 - x) >= (BORDER_LINE_SIZE / 2) )
|
||||
{
|
||||
|
||||
//Blit Half piece
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_HORIZONTAL_TOP_SHORT ],
|
||||
x, y, x + halfSize, y + size );
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_HORIZONTAL_BOTTOM_SHORT ],
|
||||
x, y2, x + halfSize, y2 + size );
|
||||
|
||||
x += (BORDER_LINE_SIZE / 2);
|
||||
|
||||
}
|
||||
|
||||
// x2 - x ... must now be less than a half piece
|
||||
// check for equals and if not blit an adjusted half piece border pieces have
|
||||
// a two pixel repeat so we will blit one pixel over if necessary to line up
|
||||
// the art, but we'll cover-up the overlap with the corners
|
||||
if( x < x2 )
|
||||
{
|
||||
x -= ((BORDER_LINE_SIZE / 2) - (((x2 - x) + 1) & ~1));
|
||||
|
||||
//Blit Half piece
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_HORIZONTAL_TOP_SHORT ],
|
||||
x, y, x + halfSize, y + size );
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_HORIZONTAL_BOTTOM_SHORT ],
|
||||
x, y2, x + halfSize, y2 + size );
|
||||
|
||||
}
|
||||
|
||||
// Draw Vertical Lines
|
||||
// All border pieces are based on a 10 pixel offset from the centerline
|
||||
x = originalX - Offset;
|
||||
x2 = maxX - OffsetLower;
|
||||
y2 = maxY - (OffsetLower + BORDER_LINE_SIZE);
|
||||
|
||||
for( y=(originalY + OffsetLower); y <= y2; y += BORDER_LINE_SIZE )
|
||||
{
|
||||
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_VERTICAL_LEFT ],
|
||||
x, y, x + size, y + size );
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_VERTICAL_RIGHT ],
|
||||
x2, y, x2 + size, y + size );
|
||||
|
||||
}
|
||||
|
||||
y2 = maxY - OffsetLower;//BORDER_CORNER_SIZE;
|
||||
|
||||
// y == place to draw remainder if any
|
||||
if( (y2 - y) >= (BORDER_LINE_SIZE / 2) )
|
||||
{
|
||||
|
||||
//Blit Half piece
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_VERTICAL_LEFT_SHORT ],
|
||||
x, y, x + size, y + halfSize );
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_VERTICAL_RIGHT_SHORT ],
|
||||
x2, y, x2 + size, y + halfSize );
|
||||
|
||||
y += (BORDER_LINE_SIZE / 2);
|
||||
}
|
||||
|
||||
// y2 - y ... must now be less than a half piece
|
||||
// check for equals and if not blit an adjusted half piece border pieces have
|
||||
// a two pixel repeat so we will blit one pixel over if necessary to line up
|
||||
// the art, but we'll cover-up the overlap with the corners
|
||||
if( y < y2 )
|
||||
{
|
||||
y -= ((BORDER_LINE_SIZE / 2) - (((y2 - y) + 1) & ~1));
|
||||
|
||||
//Blit Half piece
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_VERTICAL_LEFT_SHORT ],
|
||||
x, y, x + size, y + halfSize );
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_VERTICAL_RIGHT_SHORT ],
|
||||
x2, y, x2 + size, y + halfSize );
|
||||
|
||||
}
|
||||
|
||||
// Draw Corners
|
||||
x = originalX - BORDER_CORNER_SIZE ;
|
||||
y = originalY - BORDER_CORNER_SIZE;
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_CORNER_UL ],
|
||||
x, y, x + size, y + size );
|
||||
x = maxX - 5;//BORDER_CORNER_SIZE;
|
||||
y = originalY - BORDER_CORNER_SIZE;
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_CORNER_UR ],
|
||||
x, y, x + size, y + size );
|
||||
x = originalX - BORDER_CORNER_SIZE;
|
||||
y = maxY - 5;//BORDER_CORNER_SIZE;
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_CORNER_LL ],
|
||||
x, y, x + size, y + size );
|
||||
x = maxX - 5;//BORDER_CORNER_SIZE;
|
||||
y = maxY - 5;//BORDER_CORNER_SIZE;
|
||||
TheDisplay->drawImage( borderPieces[ BORDER_CORNER_LR ],
|
||||
x, y, x + size, y + size );
|
||||
|
||||
} // end blitBorderRect
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DGameWindow::W3DGameWindow ===============================================
|
||||
//=============================================================================
|
||||
W3DGameWindow::W3DGameWindow( void )
|
||||
{
|
||||
|
||||
// override the default draw with our own default draw function for W3D
|
||||
winSetDrawFunc( TheWindowManager->getDefaultDraw() );
|
||||
|
||||
m_textPos.x = m_textPos.y = 0;
|
||||
m_currTextColor = WIN_COLOR_UNDEFINED;
|
||||
m_needPolyDraw = FALSE;
|
||||
m_newTextPos = FALSE;
|
||||
|
||||
} // end W3DGameWindow
|
||||
|
||||
// W3DGameWindow::~W3DGameWindow ==============================================
|
||||
//=============================================================================
|
||||
W3DGameWindow::~W3DGameWindow( void )
|
||||
{
|
||||
|
||||
} // end ~W3DGameWindow
|
||||
|
||||
// W3DGameWinDefaultDraw ======================================================
|
||||
/** The default redraw callback. Draws the background using either
|
||||
* the drawData or the background color unless the background color
|
||||
* is set to -1 indicating that default drawing is turned off. */
|
||||
//=============================================================================
|
||||
void W3DGameWinDefaultDraw( GameWindow *window, WinInstanceData *instData )
|
||||
{
|
||||
Real borderWidth = 1.0f;
|
||||
ICoord2D origin;
|
||||
ICoord2D size;
|
||||
W3DGameWindow *w3dWindow = (W3DGameWindow *)window;
|
||||
|
||||
/** @todo NOTE that we're making a W3DGameWindow cast here, it seems
|
||||
logical because we are in a W3D draw function so it's reasonable to assume
|
||||
that we have a W3DGameWindow. However, we may want to revisit this
|
||||
type of casting in the future, we have the same problems with the
|
||||
ObjectModules where we cast object modules for their individual methods.
|
||||
Also note that the other W3D implementations of GUI controls are making
|
||||
a similar cast for their device implementation functions */
|
||||
|
||||
// get the window position in the screen coordinates
|
||||
w3dWindow->winGetScreenPosition( &origin.x, &origin.y );
|
||||
|
||||
// get size of window
|
||||
w3dWindow->winGetSize( &size.x, &size.y );
|
||||
|
||||
// image drawing vs color drawing
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_IMAGE ) )
|
||||
{
|
||||
const Image *image;
|
||||
|
||||
// get image
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
image = window->winGetDisabledImage( 0 );
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
image = window->winGetHiliteImage( 0 );
|
||||
else
|
||||
image = window->winGetEnabledImage( 0 );
|
||||
|
||||
if( image )
|
||||
{
|
||||
ICoord2D start, end;
|
||||
|
||||
start.x = origin.x + instData->m_imageOffset.x;
|
||||
start.y = origin.y + instData->m_imageOffset.y;
|
||||
end.x = start.x + size.x;
|
||||
end.y = start.y + size.y;
|
||||
TheWindowManager->winDrawImage( image, start.x, start.y, end.x, end.y );
|
||||
|
||||
} // end if
|
||||
|
||||
} // end if
|
||||
else
|
||||
{
|
||||
Color color, borderColor;
|
||||
|
||||
// get colors
|
||||
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
|
||||
{
|
||||
|
||||
color = window->winGetDisabledColor( 0 );
|
||||
borderColor = window->winGetDisabledBorderColor( 0 );
|
||||
|
||||
} // end if
|
||||
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
|
||||
{
|
||||
|
||||
color = window->winGetHiliteColor( 0 );
|
||||
borderColor = window->winGetHiliteBorderColor( 0 );
|
||||
|
||||
} // end else if
|
||||
else
|
||||
{
|
||||
|
||||
color = window->winGetEnabledColor( 0 );
|
||||
borderColor = window->winGetEnabledBorderColor( 0 );
|
||||
|
||||
} // end else
|
||||
|
||||
//
|
||||
// draw the border at the edges
|
||||
//
|
||||
if( borderColor != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winOpenRect( borderColor, borderWidth,
|
||||
origin.x, origin.y,
|
||||
origin.x + size.x, origin.y + size.y );
|
||||
|
||||
// draw filled background
|
||||
if( color != WIN_COLOR_UNDEFINED )
|
||||
TheWindowManager->winFillRect( color, borderWidth,
|
||||
origin.x + borderWidth,
|
||||
origin.y + borderWidth,
|
||||
origin.x + size.x - borderWidth,
|
||||
origin.y + size.y - borderWidth );
|
||||
|
||||
} // end else
|
||||
|
||||
// if we have a video buffer, draw the video buffer
|
||||
if ( instData->m_videoBuffer )
|
||||
{
|
||||
ICoord2D pos, size;
|
||||
window->winGetScreenPosition( &pos.x, &pos.y );
|
||||
window->winGetSize( &size.x, &size.y );
|
||||
|
||||
TheDisplay->drawVideoBuffer( instData->m_videoBuffer, pos.x, pos.y, pos.x + size.x, pos.y + size.y );
|
||||
}
|
||||
|
||||
} // end W3DGameWinDefaultDraw
|
||||
|
||||
// W3DGameWindow::winDrawBorder ===============================================
|
||||
//=============================================================================
|
||||
void W3DGameWindow::winDrawBorder( void )
|
||||
{
|
||||
Bool found = FALSE;
|
||||
Int originalX, originalY;
|
||||
Int x, y;
|
||||
Int width;
|
||||
Int i, bits;
|
||||
|
||||
/** @todo this WinDrawBorder is the old Nox function for drawing the borders
|
||||
* on various windows and controls. We should derive classes of game
|
||||
* windows for the different GUI controls and move the specific pieces of
|
||||
* code that apply for those gadgets to those classes */
|
||||
|
||||
// based on window class pass different regions to real draw
|
||||
|
||||
winGetScreenPosition( &originalX, &originalY );
|
||||
|
||||
for( i = 0; (i < (sizeof(UnsignedInt) * 8)) && (found == FALSE); i++ )
|
||||
{
|
||||
|
||||
bits = (1 << i);
|
||||
|
||||
if( m_instData.getStyle() & bits )
|
||||
{
|
||||
|
||||
switch( m_instData.getStyle() & bits )
|
||||
{
|
||||
case GWS_CHECK_BOX:
|
||||
found = TRUE;
|
||||
break;
|
||||
|
||||
case GWS_ENTRY_FIELD:
|
||||
{
|
||||
// EntryData *e = (EntryData *)m_userData;
|
||||
width = m_size.x;
|
||||
|
||||
x = originalX;
|
||||
y = originalY;
|
||||
|
||||
// Calculate space for Label
|
||||
if( m_instData.getTextLength() )
|
||||
{
|
||||
Int textWidth = 0;
|
||||
|
||||
TheWindowManager->winGetTextSize( m_instData.getFont(),
|
||||
m_instData.getText(),
|
||||
&textWidth, NULL, 0 );
|
||||
width -= textWidth + 6;
|
||||
x += textWidth + 6;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
// Colin: The very notion of entry width makes no sense to me since
|
||||
// we already have a gadget width, and the max characters for
|
||||
// an entry box so I am removing this.
|
||||
// Adjust entry box if an entryWidth is provided
|
||||
if( (e->entryWidth > 0) && (width > e->entryWidth) )
|
||||
{
|
||||
width = e->entryWidth;
|
||||
x = originalX + (m_size.x - e->entryWidth);
|
||||
}
|
||||
*/
|
||||
|
||||
blitBorderRect( x, y, width, m_size.y );
|
||||
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Sliders may need a bar for the button
|
||||
// it is assumed that the smaller size component (width, height)
|
||||
// is the axis of the slider
|
||||
case GWS_VERT_SLIDER:
|
||||
case GWS_HORZ_SLIDER:
|
||||
// blitBorderLine( originalX, originalY, window->size.x, window->size.y );
|
||||
|
||||
found = TRUE;
|
||||
break;
|
||||
|
||||
case GWS_SCROLL_LISTBOX:
|
||||
{
|
||||
ListboxData *list = (ListboxData *)m_userData;
|
||||
Int sliderAdjustment = 0;
|
||||
Int labelAdjustment = 0;
|
||||
|
||||
if( list->scrollBar )
|
||||
{
|
||||
GameWindow *child = list->slider->winGetChild();
|
||||
ICoord2D size;
|
||||
|
||||
child->winGetSize( &size.x, &size.y );
|
||||
sliderAdjustment = size.y;
|
||||
|
||||
} // end if
|
||||
|
||||
if( m_instData.getTextLength() )
|
||||
labelAdjustment = 4;
|
||||
|
||||
blitBorderRect( (originalX - 3),
|
||||
(originalY - (3 + labelAdjustment)),
|
||||
(m_size.x + 3 - sliderAdjustment),
|
||||
(m_size.y + 6) );
|
||||
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case GWS_RADIO_BUTTON:
|
||||
case GWS_STATIC_TEXT:
|
||||
case GWS_PROGRESS_BAR:
|
||||
case GWS_PUSH_BUTTON:
|
||||
case GWS_USER_WINDOW:
|
||||
case GWS_TAB_CONTROL:
|
||||
blitBorderRect( originalX, originalY, m_size.x, m_size.y );
|
||||
|
||||
found = TRUE;
|
||||
break;
|
||||
|
||||
} // end switch
|
||||
|
||||
} // end if
|
||||
|
||||
} // end for i
|
||||
|
||||
} // end WinDrawBorder
|
||||
|
||||
// W3DGameWindow::winSetFont ==================================================
|
||||
/** Set the font for a widow */
|
||||
//=============================================================================
|
||||
void W3DGameWindow::winSetFont( GameFont *font )
|
||||
{
|
||||
|
||||
// extending functionality
|
||||
GameWindow::winSetFont( font );
|
||||
|
||||
// assign font to text renderer
|
||||
m_textRenderer.Set_Font( static_cast<FontCharsClass *>(font->fontData) );
|
||||
|
||||
// this is a visual change
|
||||
m_needPolyDraw = TRUE;
|
||||
|
||||
} // end WinSetFont
|
||||
|
||||
// W3DGameWindow::winSetText ==================================================
|
||||
/** Set the text for window */
|
||||
//=============================================================================
|
||||
Int W3DGameWindow::winSetText( UnicodeString newText )
|
||||
{
|
||||
|
||||
// extending functionality
|
||||
GameWindow::winSetText( newText );
|
||||
|
||||
// rebuild the sentence in our text renderer
|
||||
m_textRenderer.Build_Sentence( m_instData.getText().str(),NULL, NULL );
|
||||
|
||||
// this is a visual change
|
||||
m_needPolyDraw = TRUE;
|
||||
|
||||
return WIN_ERR_OK;
|
||||
|
||||
} // end WinSetText
|
||||
|
||||
// W3DGameWindow::winSetPosition ==============================================
|
||||
/** Set window position */
|
||||
//=============================================================================
|
||||
Int W3DGameWindow::winSetPosition( Int x, Int y )
|
||||
{
|
||||
ICoord2D prevPos;
|
||||
|
||||
// get previous position
|
||||
prevPos.x = m_region.lo.x;
|
||||
prevPos.y = m_region.lo.y;
|
||||
|
||||
// extending functionality
|
||||
GameWindow::winSetPosition( x, y );
|
||||
|
||||
// update any text position change
|
||||
m_textPos.x += m_region.lo.x - prevPos.x;
|
||||
m_textPos.y += m_region.lo.y - prevPos.y;
|
||||
m_newTextPos = TRUE;
|
||||
|
||||
return WIN_ERR_OK;
|
||||
|
||||
} // end WinSetPosition
|
||||
|
||||
// W3DGameWindow::getTextSize =================================================
|
||||
/** Get the size of the text in our inst data */
|
||||
//=============================================================================
|
||||
void W3DGameWindow::getTextSize( Int *width, Int *height )
|
||||
{
|
||||
Vector2 extents = m_textRenderer.Get_Text_Extents( m_instData.getText().str() );
|
||||
|
||||
if( width )
|
||||
*width = extents.X;
|
||||
if( height )
|
||||
*height = extents.Y;
|
||||
|
||||
} // end getTextSize
|
||||
|
||||
// W3DGameWindow::getTextLoc ==================================================
|
||||
// Set our text rendering location */
|
||||
//=============================================================================
|
||||
void W3DGameWindow::setTextLoc( Int x, Int y )
|
||||
{
|
||||
|
||||
if( m_textPos.x != x )
|
||||
{
|
||||
|
||||
m_textPos.x = x;
|
||||
m_newTextPos = TRUE;
|
||||
|
||||
}
|
||||
if( m_textPos.y != y )
|
||||
{
|
||||
|
||||
m_textPos.y = y;
|
||||
m_newTextPos = TRUE;
|
||||
|
||||
} // end if
|
||||
|
||||
} // end setTextLoc
|
||||
|
||||
// W3DGameWindow::drawText ====================================================
|
||||
/** Draw the text in our 2d sentence renderer */
|
||||
//=============================================================================
|
||||
void W3DGameWindow::drawText( Color color )
|
||||
{
|
||||
Bool needDraw = FALSE;
|
||||
|
||||
// if new text pos we need to redraw
|
||||
if( m_newTextPos )
|
||||
{
|
||||
|
||||
m_newTextPos = FALSE;
|
||||
needDraw = TRUE;
|
||||
|
||||
} // end if
|
||||
|
||||
// if color switch, set new color
|
||||
if( m_currTextColor != color )
|
||||
{
|
||||
|
||||
m_currTextColor = color;
|
||||
needDraw = TRUE;
|
||||
|
||||
} // end if
|
||||
|
||||
// draw the quads if needed
|
||||
if( needDraw || m_needPolyDraw )
|
||||
{
|
||||
UnsignedInt outline = TheWindowManager->winMakeColor( 0, 0, 0, 255 );
|
||||
|
||||
m_textRenderer.Reset_Polys();
|
||||
m_textRenderer.Set_Location( Vector2( m_textPos.x + 1, m_textPos.y + 1 ) );
|
||||
m_textRenderer.Draw_Sentence( outline );
|
||||
|
||||
m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) );
|
||||
m_textRenderer.Draw_Sentence( m_currTextColor );
|
||||
|
||||
m_needPolyDraw = FALSE;
|
||||
|
||||
} // end if
|
||||
|
||||
// do the render
|
||||
m_textRenderer.Render();
|
||||
|
||||
} // end drawText
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DGameWindowManager.cpp /////////////////////////////////////////////////////////////////
|
||||
// Created: Colin Day, June 2001
|
||||
// Desc: W3D implementation of the window manager, responsible for all
|
||||
// interactions with the game windowing system for menus and
|
||||
// window controls.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "GameClient/Image.h"
|
||||
#include "W3DDevice/GameClient/W3DGameWindowManager.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DGameWindowManager::W3DGameWindowManager( void )
|
||||
{
|
||||
|
||||
} // end W3DGameWindowManager
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DGameWindowManager::~W3DGameWindowManager( void )
|
||||
{
|
||||
|
||||
} // end ~W3DGameWindowManager
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameWindowManager::init( void )
|
||||
{
|
||||
|
||||
// extend
|
||||
GameWindowManager::init();
|
||||
|
||||
} // end init
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Motion blur vertex shader
|
||||
; John Ahlquist April 2002
|
||||
; Currently unused prototype code. jba.
|
||||
|
||||
#define CV_ZERO 0
|
||||
#define CV_ONE 1
|
||||
|
||||
#define V_POSITION v0
|
||||
#define V_DIFFUSE v1
|
||||
#define V_TEXTURE v2
|
||||
|
||||
vs.1.1
|
||||
|
||||
|
||||
mov oPos, V_POSITION
|
||||
mov oT0, V_TEXTURE
|
||||
mov oT1, V_TEXTURE
|
||||
mov oT2, V_TEXTURE
|
||||
mov oT3, V_TEXTURE
|
||||
mov oD0, V_DIFFUSE
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Trees pixel shader. Not actually used at this time. jba.
|
||||
; Created: John Ahlquist, June 2003
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
|
||||
mov r0, v0
|
||||
mul r0, r0, t0
|
||||
mul_x2 r0.rgb, r0, c1 ; modulate 2 * c1
|
||||
mov r0.a, t0.a
|
||||
@@ -0,0 +1,47 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
//vertex shader for grass..
|
||||
// v0 - Vertex Position
|
||||
// v1 - Normal vector - used for other fun stuff.
|
||||
// - v1.x = index for the motion wave data
|
||||
// - v1.y = color scale factor for darkening.
|
||||
// - v1.z = z coordinate value of the base of the tree/grass/bush.
|
||||
// v2 - Diffuse color
|
||||
// v7 - Vertex Texture Data u,v
|
||||
// c4-7 - Composite World-View-Projection Matrix
|
||||
// c8 - Tilt vector.
|
||||
// c32 - offset for shroud texture mapping
|
||||
// c33 - scale for shroud texture mapping
|
||||
|
||||
vs.1.1
|
||||
|
||||
|
||||
mov r2, v1.wwzw ; move the z value for the tree into r2
|
||||
sub r2, v0, r2 ; subtract the z from the base coordinate.
|
||||
mov a0.x, v1 ; get the index for the wave value.
|
||||
mov r0, c[a0.x+8] ; load the correct wave entry for this tree/grass
|
||||
mad r1, r2.zzzw,r0,v0 ; multiply the z value by wave value to get the xy skew value for the wave motion
|
||||
; and add it to the coordinate value.
|
||||
m4x4 oPos, r1, c4 ; Transform vertex to screen coords.
|
||||
mov r2, v1.yyyw ; Get the color scale from v1.y
|
||||
mul oD0, v2,r2 ; Scale and move diffuse color into color register.
|
||||
mov oT0, v7 ; Move texture coords into texture register.
|
||||
|
||||
add r1, v0, c32 ; offset coordinate
|
||||
mul oT1, r1, c33 ;
|
||||
@@ -0,0 +1,36 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
tex t1 ; get texture 1
|
||||
|
||||
mul r0, t1, t0 ;multiply blend between 2 textures
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t1 ; get texture 1
|
||||
|
||||
mov r0, t1 ; Load terrain
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
@@ -0,0 +1,37 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
tex t1 ; get texture 1
|
||||
tex t2 ; get texture 2
|
||||
|
||||
mul r0, t1, t0 ; multiply shroud into terrain
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
mul r0, r0, t2 ;modulate with texture2
|
||||
@@ -0,0 +1,39 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
tex t1 ; get texture 1
|
||||
tex t2 ; get texture 2
|
||||
tex t3 ; get texture 3
|
||||
|
||||
mul r0, t1, t0 ; multiply shroud into terrain
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
mul r0, r0, t2 ;modulate with texture 2
|
||||
mul r0, r0, t3 ;modulate with texture 3
|
||||
@@ -0,0 +1,55 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
;dp3 r1, c1, t0
|
||||
;add r0,r1,-c2
|
||||
;mul r0,r0,c3
|
||||
;mov r0,t0 ;do nothing
|
||||
|
||||
//Inverted image
|
||||
;dp3 r1, t0, c0 ;black & white conversion
|
||||
;mul r0, 1-r1, c1 ;modulate inverted by filter color
|
||||
;lrp r0, c2, r0, t0 ;blend modified image into original image so smooth fade in/out
|
||||
|
||||
//Red inverted image
|
||||
dp3 r1, t0, c0 ;black & white conversion
|
||||
mul r1, r1, c1 ;modulate by filter color (inverse of red)
|
||||
lrp r0, c2, 1-r1, t0 ;blend modified image into original image so smooth fade in/out
|
||||
|
||||
;Code to clamp and expand dynamic range
|
||||
;add_sat r1,r1,-c7 ;clamp out low values - 30
|
||||
;add_sat r1,r1,c5 ;clamp out upper values +60
|
||||
;add r1,r1,-c6 ;shift to center range at 0
|
||||
|
||||
|
||||
;add r0,r0,-c5
|
||||
;mul_x4 r0,r0,c6
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
;dp3 r1, c1, t0
|
||||
;add r0,r1,-c2
|
||||
;mul r0,r0,c3
|
||||
;mov r0,t0 ;do nothing
|
||||
|
||||
dp3 r1, t0, c0 ;black & white conversion
|
||||
mul r1, r1, c1 ;modulate by filter color
|
||||
lrp r0, c2, r1, t0 ;blend modified image into original image so smooth fade in/out
|
||||
|
||||
;Code to clamp and expand dynamic range
|
||||
;add_sat r1,r1,-c7 ;clamp out low values - 30
|
||||
;add_sat r1,r1,c5 ;clamp out upper values +60
|
||||
;add r1,r1,-c6 ;shift to center range at 0
|
||||
|
||||
|
||||
;add r0,r0,-c5
|
||||
;mul_x4 r0,r0,c6
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Motion blur pixel shader
|
||||
; Created: John Ahlquist, April 2002
|
||||
; Currently unused prototype code. jba.
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0
|
||||
; Define t0 as a standard 3-vector from bumpmap
|
||||
tex t1
|
||||
|
||||
; Perform EMBM to get a local normal bump reflection.
|
||||
texbem t2, t1 ; compute new (u,v) values
|
||||
tex t3
|
||||
; result goes in output color multiplied by diffuse
|
||||
;mul r0, t2, v0
|
||||
|
||||
mul r0.rgb, v0, t0
|
||||
+add r0.a, v0, t0
|
||||
mul r1, t2, c0
|
||||
add r0.rgb, r0, r1
|
||||
+mul r0.a, r0, t3
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, June 2002
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get road texture
|
||||
tex t1 ; get cloud shadow texture
|
||||
tex t2 ; get noise texture
|
||||
|
||||
mul r0, t0, t1 ;modulate with cloud
|
||||
mul r0, r0, t2 ;modulate with noise
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
@@ -0,0 +1,35 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
tex t1 ; get texture 1
|
||||
|
||||
lrp r0, v0.a, t1, t0 ;alpha blend between 2 textures
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
@@ -0,0 +1,37 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
tex t1 ; get texture 1
|
||||
tex t2 ; get texture 2
|
||||
|
||||
lrp r0, v0.a, t1, t0 ;alpha blend between 2 textures
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
mul r0, r0, t2 ;modulate with texture2
|
||||
@@ -0,0 +1,39 @@
|
||||
;
|
||||
; Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
;
|
||||
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
;// //
|
||||
;// (c) 2001-2003 Electronic Arts Inc. //
|
||||
;// //
|
||||
;////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
; Terrain pixel shader
|
||||
; Created: Mark Wilczynski, August 2001
|
||||
|
||||
; Declare pixel shader version 1.1
|
||||
ps.1.1
|
||||
|
||||
tex t0 ; get texture 0
|
||||
tex t1 ; get texture 1
|
||||
tex t2 ; get texture 2
|
||||
tex t3 ; get texture 3
|
||||
|
||||
lrp r0, v0.a, t1, t0 ;alpha blend between 2 textures
|
||||
mul r0, r0, v0 ;apply diffuse lighting
|
||||
mul r0, r0, t2 ;modulate with texture 2
|
||||
mul r0, r0, t3 ;modulate with texture 3
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "Common/Debug.h"
|
||||
#include "W3DDevice/GameClient/W3DBufferManager.h"
|
||||
|
||||
W3DBufferManager *TheW3DBufferManager=NULL; //singleton
|
||||
|
||||
static int FVFTypeIndexList[W3DBufferManager::MAX_FVF]=
|
||||
{
|
||||
D3DFVF_XYZ,
|
||||
D3DFVF_XYZ|D3DFVF_DIFFUSE,
|
||||
D3DFVF_XYZ|D3DFVF_TEX1,
|
||||
D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1,
|
||||
D3DFVF_XYZ|D3DFVF_TEX2,
|
||||
D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX2,
|
||||
D3DFVF_XYZ|D3DFVF_NORMAL,
|
||||
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE,
|
||||
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
|
||||
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1,
|
||||
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2,
|
||||
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX2,
|
||||
D3DFVF_XYZRHW,
|
||||
D3DFVF_XYZRHW|D3DFVF_DIFFUSE,
|
||||
D3DFVF_XYZRHW|D3DFVF_TEX1,
|
||||
D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1,
|
||||
D3DFVF_XYZRHW|D3DFVF_TEX2,
|
||||
D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX2
|
||||
};
|
||||
|
||||
Int W3DBufferManager::getDX8Format(VBM_FVF_TYPES format)
|
||||
{
|
||||
return FVFTypeIndexList[format];
|
||||
}
|
||||
|
||||
W3DBufferManager::W3DBufferManager(void)
|
||||
{
|
||||
m_numEmptySlotsAllocated=0;
|
||||
m_numEmptyVertexBuffersAllocated=0;
|
||||
m_numEmptyIndexSlotsAllocated=0;
|
||||
m_numEmptyIndexBuffersAllocated=0;
|
||||
|
||||
for (Int i=0; i<MAX_FVF; i++)
|
||||
m_W3DVertexBuffers[i]=NULL;
|
||||
for (i=0; i<MAX_FVF; i++)
|
||||
for (Int j=0; j<MAX_VB_SIZES; j++)
|
||||
m_W3DVertexBufferSlots[i][j]=NULL;
|
||||
|
||||
m_W3DIndexBuffers=NULL;
|
||||
for (Int j=0; j<MAX_IB_SIZES; j++)
|
||||
m_W3DIndexBufferSlots[j]=NULL;
|
||||
}
|
||||
|
||||
W3DBufferManager::~W3DBufferManager(void)
|
||||
{
|
||||
freeAllSlots();
|
||||
freeAllBuffers();
|
||||
}
|
||||
|
||||
void W3DBufferManager::freeAllSlots(void)
|
||||
{
|
||||
Int i,j;
|
||||
|
||||
for (i=0; i<MAX_FVF; i++)
|
||||
{
|
||||
for (j=0; j<MAX_VB_SIZES; j++)
|
||||
{
|
||||
//Release all slots allocated for each size
|
||||
W3DVertexBufferSlot *vbSlot = m_W3DVertexBufferSlots[i][j];
|
||||
while (vbSlot)
|
||||
{
|
||||
if (vbSlot->m_prevSameVB)
|
||||
vbSlot->m_prevSameVB->m_nextSameVB=vbSlot->m_nextSameVB;
|
||||
else
|
||||
vbSlot->m_VB->m_usedSlots=NULL;
|
||||
|
||||
if (vbSlot->m_nextSameVB)
|
||||
vbSlot->m_nextSameVB->m_prevSameVB=vbSlot->m_prevSameVB;
|
||||
vbSlot=vbSlot->m_nextSameSize;
|
||||
m_numEmptySlotsAllocated--;
|
||||
}
|
||||
m_W3DVertexBufferSlots[i][j]=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (j=0; j<MAX_IB_SIZES; j++)
|
||||
{
|
||||
//Release all slots allocated for each size
|
||||
W3DIndexBufferSlot *ibSlot = m_W3DIndexBufferSlots[j];
|
||||
while (ibSlot)
|
||||
{
|
||||
if (ibSlot->m_prevSameIB)
|
||||
ibSlot->m_prevSameIB->m_nextSameIB=ibSlot->m_nextSameIB;
|
||||
else
|
||||
ibSlot->m_IB->m_usedSlots=NULL;
|
||||
|
||||
if (ibSlot->m_nextSameIB)
|
||||
ibSlot->m_nextSameIB->m_prevSameIB=ibSlot->m_prevSameIB;
|
||||
ibSlot=ibSlot->m_nextSameSize;
|
||||
m_numEmptyIndexSlotsAllocated--;
|
||||
}
|
||||
m_W3DIndexBufferSlots[j]=NULL;
|
||||
}
|
||||
|
||||
DEBUG_ASSERTCRASH(m_numEmptySlotsAllocated==0, ("Failed to free all empty vertex buffer slots"));
|
||||
DEBUG_ASSERTCRASH(m_numEmptyIndexSlotsAllocated==0, ("Failed to free all empty index buffer slots"));
|
||||
}
|
||||
|
||||
void W3DBufferManager::freeAllBuffers(void)
|
||||
{
|
||||
Int i;
|
||||
|
||||
//Make sure all slots are free
|
||||
freeAllSlots(); ///<release all slots to pool.
|
||||
|
||||
for (i=0; i<MAX_FVF; i++)
|
||||
{
|
||||
W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
|
||||
while (vb)
|
||||
{ DEBUG_ASSERTCRASH(vb->m_usedSlots == NULL, ("Freeing Non-Empty Vertex Buffer"));
|
||||
REF_PTR_RELEASE(vb->m_DX8VertexBuffer);
|
||||
m_numEmptyVertexBuffersAllocated--;
|
||||
vb=vb->m_nextVB; //get next vertex buffer of this type
|
||||
}
|
||||
m_W3DVertexBuffers[i]=NULL;
|
||||
}
|
||||
|
||||
W3DIndexBuffer *ib = m_W3DIndexBuffers;
|
||||
while (ib)
|
||||
{ DEBUG_ASSERTCRASH(ib->m_usedSlots == NULL, ("Freeing Non-Empty Index Buffer"));
|
||||
REF_PTR_RELEASE(ib->m_DX8IndexBuffer);
|
||||
m_numEmptyIndexBuffersAllocated--;
|
||||
ib=ib->m_nextIB; //get next vertex buffer of this type
|
||||
}
|
||||
m_W3DIndexBuffers=NULL;
|
||||
|
||||
DEBUG_ASSERTCRASH(m_numEmptyVertexBuffersAllocated==0, ("Failed to free all empty vertex buffers"));
|
||||
DEBUG_ASSERTCRASH(m_numEmptyIndexBuffersAllocated==0, ("Failed to free all empty index buffers"));
|
||||
}
|
||||
|
||||
void W3DBufferManager::ReleaseResources(void)
|
||||
{
|
||||
for (Int i=0; i<MAX_FVF; i++)
|
||||
{
|
||||
W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
|
||||
while (vb)
|
||||
{
|
||||
REF_PTR_RELEASE(vb->m_DX8VertexBuffer);
|
||||
vb=vb->m_nextVB; //get next vertex buffer of this type
|
||||
}
|
||||
}
|
||||
|
||||
W3DIndexBuffer *ib = m_W3DIndexBuffers;
|
||||
while (ib)
|
||||
{
|
||||
REF_PTR_RELEASE(ib->m_DX8IndexBuffer);
|
||||
ib=ib->m_nextIB; //get next vertex buffer of this type
|
||||
}
|
||||
}
|
||||
|
||||
Bool W3DBufferManager::ReAcquireResources(void)
|
||||
{
|
||||
for (Int i=0; i<MAX_FVF; i++)
|
||||
{
|
||||
W3DVertexBuffer *vb = m_W3DVertexBuffers[i];
|
||||
while (vb)
|
||||
{ DEBUG_ASSERTCRASH( vb->m_DX8VertexBuffer == NULL, ("ReAcquire of existing vertex buffer"));
|
||||
vb->m_DX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(FVFTypeIndexList[vb->m_format],vb->m_size,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
DEBUG_ASSERTCRASH( vb->m_DX8VertexBuffer, ("Failed ReAcquire of vertex buffer"));
|
||||
if (!vb->m_DX8VertexBuffer)
|
||||
return FALSE;
|
||||
vb=vb->m_nextVB; //get next vertex buffer of this type
|
||||
}
|
||||
}
|
||||
|
||||
W3DIndexBuffer *ib = m_W3DIndexBuffers;
|
||||
while (ib)
|
||||
{ DEBUG_ASSERTCRASH( ib->m_DX8IndexBuffer == NULL, ("ReAcquire of existing index buffer"));
|
||||
ib->m_DX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(ib->m_size,DX8IndexBufferClass::USAGE_DEFAULT));
|
||||
DEBUG_ASSERTCRASH( ib->m_DX8IndexBuffer, ("Failed ReAcquire of index buffer"));
|
||||
if (!ib->m_DX8IndexBuffer)
|
||||
return FALSE;
|
||||
ib=ib->m_nextIB; //get next vertex buffer of this type
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**Searches through previously allocated vertex buffer slots and returns a matching type. If none found,
|
||||
creates a new slot and adds it to the pool. Returns an integer slotId used to reference the VB.
|
||||
Returns -1 in case of failure.
|
||||
*/
|
||||
W3DBufferManager::W3DVertexBufferSlot *W3DBufferManager::getSlot(VBM_FVF_TYPES fvfType, Int size)
|
||||
{
|
||||
W3DVertexBufferSlot *vbSlot=NULL;
|
||||
|
||||
//round size to next multiple of minimum slot size.
|
||||
//should help avoid fragmentation.
|
||||
size = (size + (MIN_SLOT_SIZE-1)) & (~(MIN_SLOT_SIZE-1));
|
||||
Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
|
||||
|
||||
DEBUG_ASSERTCRASH(sizeIndex < MAX_VB_SIZES && size, ("Allocating too large vertex buffer slot"));
|
||||
|
||||
if ((vbSlot=m_W3DVertexBufferSlots[fvfType][sizeIndex]) != 0)
|
||||
{ //found a previously allocated slot matching required size
|
||||
m_W3DVertexBufferSlots[fvfType][sizeIndex]=vbSlot->m_nextSameSize;
|
||||
if (vbSlot->m_nextSameSize)
|
||||
vbSlot->m_nextSameSize->m_prevSameSize=NULL;
|
||||
return vbSlot;
|
||||
}
|
||||
else
|
||||
{ //need to allocate a new slot
|
||||
return allocateSlotStorage(fvfType, size);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**Returns vertex buffer space back to pool so it can be reused later*/
|
||||
void W3DBufferManager::releaseSlot(W3DVertexBufferSlot *vbSlot)
|
||||
{
|
||||
Int sizeIndex = (vbSlot->m_size >> MIN_SLOT_SIZE_SHIFT)-1;
|
||||
|
||||
vbSlot->m_nextSameSize=m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex];
|
||||
if (m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex])
|
||||
m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex]->m_prevSameSize=vbSlot;
|
||||
|
||||
m_W3DVertexBufferSlots[vbSlot->m_VB->m_format][sizeIndex]=vbSlot;
|
||||
}
|
||||
|
||||
/**Reserves space inside existing vertex buffer or allocates a new one to fit the required size.
|
||||
*/
|
||||
W3DBufferManager::W3DVertexBufferSlot * W3DBufferManager::allocateSlotStorage(VBM_FVF_TYPES fvfType, Int size)
|
||||
{
|
||||
|
||||
W3DVertexBuffer *pVB;
|
||||
W3DVertexBufferSlot *vbSlot;
|
||||
// Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
|
||||
|
||||
DEBUG_ASSERTCRASH(m_numEmptySlotsAllocated < MAX_NUMBER_SLOTS, ("Nore more VB Slots"));
|
||||
|
||||
pVB=m_W3DVertexBuffers[fvfType];
|
||||
while (pVB)
|
||||
{
|
||||
if ((pVB->m_size - pVB->m_startFreeIndex) >= size)
|
||||
{ //found enough free space in this vertex buffer
|
||||
|
||||
if (m_numEmptySlotsAllocated < MAX_NUMBER_SLOTS)
|
||||
{ //we're allowing more slots to be allocated.
|
||||
vbSlot=&m_W3DVertexBufferEmptySlots[m_numEmptySlotsAllocated];
|
||||
vbSlot->m_size=size;
|
||||
vbSlot->m_start=pVB->m_startFreeIndex;
|
||||
vbSlot->m_VB=pVB;
|
||||
//Link to VB list of slots
|
||||
vbSlot->m_nextSameVB=pVB->m_usedSlots;
|
||||
vbSlot->m_prevSameVB=NULL; //this will be the new head
|
||||
if (pVB->m_usedSlots)
|
||||
pVB->m_usedSlots->m_prevSameVB=vbSlot;
|
||||
vbSlot->m_prevSameSize=vbSlot->m_nextSameSize=NULL;
|
||||
pVB->m_usedSlots=vbSlot;
|
||||
pVB->m_startFreeIndex += size;
|
||||
m_numEmptySlotsAllocated++;
|
||||
return vbSlot;
|
||||
}
|
||||
}
|
||||
pVB = pVB->m_nextVB;
|
||||
}
|
||||
|
||||
pVB=m_W3DVertexBuffers[fvfType]; //save old list head
|
||||
|
||||
//Didn't find any vertex buffers with room, create a new one
|
||||
DEBUG_ASSERTCRASH(m_numEmptyVertexBuffersAllocated < MAX_VERTEX_BUFFERS_CREATED, ("Reached Max Static VB Shadow Geometry"));
|
||||
|
||||
if (m_numEmptyVertexBuffersAllocated < MAX_VERTEX_BUFFERS_CREATED)
|
||||
{
|
||||
m_W3DVertexBuffers[fvfType] = &m_W3DEmptyVertexBuffers[m_numEmptyVertexBuffersAllocated];
|
||||
m_W3DVertexBuffers[fvfType]->m_nextVB=pVB; //link to list
|
||||
m_numEmptyVertexBuffersAllocated++;
|
||||
|
||||
pVB=m_W3DVertexBuffers[fvfType]; //get new list head
|
||||
|
||||
Int vbSize=__max(DEFAULT_VERTEX_BUFFER_SIZE,size);
|
||||
|
||||
pVB->m_DX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(FVFTypeIndexList[fvfType],vbSize,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
pVB->m_format=fvfType;
|
||||
pVB->m_startFreeIndex=size;
|
||||
pVB->m_size=vbSize;
|
||||
vbSlot=&m_W3DVertexBufferEmptySlots[m_numEmptySlotsAllocated];
|
||||
m_numEmptySlotsAllocated++;
|
||||
pVB->m_usedSlots=vbSlot;
|
||||
vbSlot->m_size=size;
|
||||
vbSlot->m_start=0;
|
||||
vbSlot->m_VB=pVB;
|
||||
vbSlot->m_prevSameVB=vbSlot->m_nextSameVB=NULL;
|
||||
vbSlot->m_prevSameSize=vbSlot->m_nextSameSize=NULL;
|
||||
return vbSlot;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//******************************** Index Buffer code ******************************************************
|
||||
/**Searches through previously allocated index buffer slots and returns a matching type. If none found,
|
||||
creates a new slot and adds it to the pool. Returns an integer slotId used to reference the VB.
|
||||
Returns -1 in case of failure.
|
||||
*/
|
||||
W3DBufferManager::W3DIndexBufferSlot *W3DBufferManager::getSlot(Int size)
|
||||
{
|
||||
W3DIndexBufferSlot *ibSlot=NULL;
|
||||
|
||||
//round size to next multiple of minimum slot size.
|
||||
//should help avoid fragmentation.
|
||||
size = (size + (MIN_SLOT_SIZE-1)) & (~(MIN_SLOT_SIZE-1));
|
||||
Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
|
||||
|
||||
DEBUG_ASSERTCRASH(sizeIndex < MAX_IB_SIZES && size, ("Allocating too large index buffer slot"));
|
||||
|
||||
if ((ibSlot=m_W3DIndexBufferSlots[sizeIndex]) != 0)
|
||||
{ //found a previously allocated slot matching required size
|
||||
m_W3DIndexBufferSlots[sizeIndex]=ibSlot->m_nextSameSize;
|
||||
if (ibSlot->m_nextSameSize)
|
||||
ibSlot->m_nextSameSize->m_prevSameSize=NULL;
|
||||
return ibSlot;
|
||||
}
|
||||
else
|
||||
{ //need to allocate a new slot
|
||||
return allocateSlotStorage(size);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**Returns index buffer space back to pool so it can be reused later*/
|
||||
void W3DBufferManager::releaseSlot(W3DIndexBufferSlot *ibSlot)
|
||||
{
|
||||
Int sizeIndex = (ibSlot->m_size >> MIN_SLOT_SIZE_SHIFT)-1;
|
||||
|
||||
ibSlot->m_nextSameSize=m_W3DIndexBufferSlots[sizeIndex];
|
||||
if (m_W3DIndexBufferSlots[sizeIndex])
|
||||
m_W3DIndexBufferSlots[sizeIndex]->m_prevSameSize=ibSlot;
|
||||
|
||||
m_W3DIndexBufferSlots[sizeIndex]=ibSlot;
|
||||
}
|
||||
|
||||
/**Reserves space inside existing index buffer or allocates a new one to fit the required size.
|
||||
*/
|
||||
W3DBufferManager::W3DIndexBufferSlot * W3DBufferManager::allocateSlotStorage(Int size)
|
||||
{
|
||||
|
||||
W3DIndexBuffer *pIB;
|
||||
W3DIndexBufferSlot *ibSlot;
|
||||
// Int sizeIndex = (size >> MIN_SLOT_SIZE_SHIFT)-1;
|
||||
|
||||
DEBUG_ASSERTCRASH(m_numEmptyIndexSlotsAllocated < MAX_NUMBER_SLOTS, ("Nore more IB Slots"));
|
||||
|
||||
pIB=m_W3DIndexBuffers;
|
||||
while (pIB)
|
||||
{
|
||||
if ((pIB->m_size - pIB->m_startFreeIndex) >= size)
|
||||
{ //found enough free space in this index buffer
|
||||
|
||||
if (m_numEmptyIndexSlotsAllocated < MAX_NUMBER_SLOTS)
|
||||
{ //we're allowing more slots to be allocated.
|
||||
ibSlot=&m_W3DIndexBufferEmptySlots[m_numEmptyIndexSlotsAllocated];
|
||||
ibSlot->m_size=size;
|
||||
ibSlot->m_start=pIB->m_startFreeIndex;
|
||||
ibSlot->m_IB=pIB;
|
||||
//Link to IB list of slots
|
||||
ibSlot->m_nextSameIB=pIB->m_usedSlots;
|
||||
ibSlot->m_prevSameIB=NULL; //this will be the new head
|
||||
if (pIB->m_usedSlots)
|
||||
pIB->m_usedSlots->m_prevSameIB=ibSlot;
|
||||
ibSlot->m_prevSameSize=ibSlot->m_nextSameSize=NULL;
|
||||
pIB->m_usedSlots=ibSlot;
|
||||
pIB->m_startFreeIndex += size;
|
||||
m_numEmptyIndexSlotsAllocated++;
|
||||
return ibSlot;
|
||||
}
|
||||
}
|
||||
pIB = pIB->m_nextIB;
|
||||
}
|
||||
|
||||
pIB=m_W3DIndexBuffers; //save old list head
|
||||
|
||||
//Didn't find any index buffers with room, create a new one
|
||||
DEBUG_ASSERTCRASH(m_numEmptyIndexBuffersAllocated < MAX_INDEX_BUFFERS_CREATED, ("Reached Max Static IB Shadow Geometry"));
|
||||
|
||||
if (m_numEmptyIndexBuffersAllocated < MAX_INDEX_BUFFERS_CREATED)
|
||||
{
|
||||
m_W3DIndexBuffers = &m_W3DEmptyIndexBuffers[m_numEmptyIndexBuffersAllocated];
|
||||
m_W3DIndexBuffers->m_nextIB=pIB; //link to list
|
||||
m_numEmptyIndexBuffersAllocated++;
|
||||
|
||||
pIB=m_W3DIndexBuffers; //get new list head
|
||||
|
||||
Int ibSize=__max(DEFAULT_INDEX_BUFFER_SIZE,size);
|
||||
|
||||
pIB->m_DX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(ibSize,DX8IndexBufferClass::USAGE_DEFAULT));
|
||||
pIB->m_startFreeIndex=size;
|
||||
pIB->m_size=ibSize;
|
||||
ibSlot=&m_W3DIndexBufferEmptySlots[m_numEmptyIndexSlotsAllocated];
|
||||
m_numEmptyIndexSlotsAllocated++;
|
||||
pIB->m_usedSlots=ibSlot;
|
||||
ibSlot->m_size=size;
|
||||
ibSlot->m_start=0;
|
||||
ibSlot->m_IB=pIB;
|
||||
ibSlot->m_prevSameIB=ibSlot->m_nextSameIB=NULL;
|
||||
ibSlot->m_prevSameSize=ibSlot->m_nextSameSize=NULL;
|
||||
return ibSlot;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// FILE: W3DShadow.cpp ///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Real time shadow representations
|
||||
//
|
||||
// Author: Mark Wilczynski, February 2002
|
||||
//
|
||||
//
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "always.h"
|
||||
#include "GameClient/View.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
#include "WW3D2/Light.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/HLod.h"
|
||||
#include "WW3D2/mesh.h"
|
||||
#include "WW3D2/meshmdl.h"
|
||||
#include "Lib/BaseType.h"
|
||||
#include "W3DDevice/GameClient/W3DGranny.h"
|
||||
#include "W3DDevice/GameClient/Heightmap.h"
|
||||
#include "D3dx8math.h"
|
||||
#include "common/GlobalData.h"
|
||||
#include "W3DDevice/GameClient/W3DVolumetricShadow.h"
|
||||
#include "W3DDevice/GameClient/W3DProjectedShadow.h"
|
||||
#include "W3DDevice/GameClient/W3DShadow.h"
|
||||
#include "WW3D2/statistics.h"
|
||||
#include "Common/Debug.h"
|
||||
#include "Common/PerfTimer.h"
|
||||
|
||||
#define SUN_DISTANCE_FROM_GROUND 10000.0f //distance of sun (our only light source).
|
||||
|
||||
// Global Variables and Functions /////////////////////////////////////////////
|
||||
W3DShadowManager *TheW3DShadowManager=NULL;
|
||||
const FrustumClass *shadowCameraFrustum;
|
||||
|
||||
Vector3 LightPosWorld[ MAX_SHADOW_LIGHTS ] =
|
||||
{
|
||||
|
||||
Vector3( 94.0161f, 50.499f, 200.0f)
|
||||
};
|
||||
|
||||
//DECLARE_PERF_TIMER(shadowsRender)
|
||||
void DoShadows(RenderInfoClass & rinfo, Bool stencilPass)
|
||||
{
|
||||
//USE_PERF_TIMER(shadowsRender)
|
||||
shadowCameraFrustum=&rinfo.Camera.Get_Frustum();
|
||||
Int projectionCount=0;
|
||||
|
||||
//Projected shadows render first because they may fill the stencil buffer
|
||||
//which will be used by the shadow volumes
|
||||
if (stencilPass == FALSE && TheW3DProjectedShadowManager)
|
||||
{
|
||||
if (TheW3DShadowManager->isShadowScene())
|
||||
projectionCount=TheW3DProjectedShadowManager->renderShadows(rinfo);
|
||||
}
|
||||
|
||||
if (stencilPass == TRUE && TheW3DVolumetricShadowManager)
|
||||
{
|
||||
|
||||
// TheW3DShadowManager->loadTerrainShadows();
|
||||
|
||||
//This function gets called many times by the W3D renderer
|
||||
//so we use this flag to make sure shadows rendered only once per frame.
|
||||
if (TheW3DShadowManager->isShadowScene())
|
||||
TheW3DVolumetricShadowManager->renderShadows(projectionCount);
|
||||
}
|
||||
if (TheW3DShadowManager && stencilPass) //reset so no more shadow processing this frame.
|
||||
TheW3DShadowManager->queueShadows(FALSE);
|
||||
|
||||
}
|
||||
|
||||
W3DShadowManager::W3DShadowManager( void )
|
||||
{
|
||||
DEBUG_ASSERTCRASH(TheW3DVolumetricShadowManager == NULL && TheW3DProjectedShadowManager == NULL,
|
||||
("Creating new shadow managers without deleting old ones"));
|
||||
|
||||
m_shadowColor = 0x7fa0a0a0;
|
||||
m_isShadowScene = FALSE;
|
||||
m_stencilShadowMask = 0; //all bits can be used for storing shadows.
|
||||
|
||||
Vector3 lightRay(-TheGlobalData->m_terrainLightPos[0].x,
|
||||
-TheGlobalData->m_terrainLightPos[0].y, -TheGlobalData->m_terrainLightPos[0].z);
|
||||
lightRay.Normalize();
|
||||
|
||||
LightPosWorld[0]=lightRay*SUN_DISTANCE_FROM_GROUND;
|
||||
|
||||
TheW3DVolumetricShadowManager = NEW W3DVolumetricShadowManager;
|
||||
TheProjectedShadowManager = TheW3DProjectedShadowManager = NEW W3DProjectedShadowManager;
|
||||
}
|
||||
|
||||
W3DShadowManager::~W3DShadowManager( void )
|
||||
{
|
||||
delete TheW3DVolumetricShadowManager;
|
||||
TheW3DVolumetricShadowManager = NULL;
|
||||
delete TheW3DProjectedShadowManager;
|
||||
TheProjectedShadowManager = TheW3DProjectedShadowManager = NULL;
|
||||
}
|
||||
|
||||
/** Do one-time initilalization of shadow systems that need to be
|
||||
active for full duration of game*/
|
||||
Bool W3DShadowManager::init( void )
|
||||
{
|
||||
Bool result=TRUE;
|
||||
|
||||
if (TheW3DVolumetricShadowManager && TheW3DVolumetricShadowManager->init())
|
||||
{
|
||||
if (TheW3DVolumetricShadowManager->ReAcquireResources())
|
||||
result = TRUE;
|
||||
}
|
||||
if ( TheW3DProjectedShadowManager && TheW3DProjectedShadowManager->init())
|
||||
{
|
||||
if (TheW3DProjectedShadowManager->ReAcquireResources())
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Do per-map reset. This frees up shadows from all objects since
|
||||
they may not exist on the next map*/
|
||||
void W3DShadowManager::Reset( void )
|
||||
{
|
||||
|
||||
if (TheW3DVolumetricShadowManager)
|
||||
TheW3DVolumetricShadowManager->reset();
|
||||
if (TheW3DProjectedShadowManager)
|
||||
TheW3DProjectedShadowManager->reset();
|
||||
}
|
||||
|
||||
Bool W3DShadowManager::ReAcquireResources()
|
||||
{
|
||||
Bool result = TRUE;
|
||||
|
||||
if (TheW3DVolumetricShadowManager && !TheW3DVolumetricShadowManager->ReAcquireResources())
|
||||
result = FALSE;
|
||||
if (TheW3DProjectedShadowManager && !TheW3DProjectedShadowManager->ReAcquireResources())
|
||||
result = FALSE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void W3DShadowManager::ReleaseResources(void)
|
||||
{
|
||||
if (TheW3DVolumetricShadowManager)
|
||||
TheW3DVolumetricShadowManager->ReleaseResources();
|
||||
if (TheW3DProjectedShadowManager)
|
||||
TheW3DProjectedShadowManager->ReleaseResources();
|
||||
}
|
||||
|
||||
Shadow *W3DShadowManager::addShadow( RenderObjClass *robj, Shadow::ShadowTypeInfo *shadowInfo, Drawable *draw)
|
||||
{
|
||||
ShadowType type = SHADOW_VOLUME;
|
||||
|
||||
if (shadowInfo)
|
||||
type = shadowInfo->m_type;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case SHADOW_VOLUME:
|
||||
if (TheW3DVolumetricShadowManager)
|
||||
return (Shadow *)TheW3DVolumetricShadowManager->addShadow(robj, shadowInfo, draw);
|
||||
break;
|
||||
case SHADOW_PROJECTION:
|
||||
case SHADOW_DECAL:
|
||||
if (TheW3DProjectedShadowManager)
|
||||
return (Shadow *)TheW3DProjectedShadowManager->addShadow(robj, shadowInfo, draw);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void W3DShadowManager::removeShadow(Shadow *shadow)
|
||||
{
|
||||
shadow->release();
|
||||
}
|
||||
|
||||
void W3DShadowManager::removeAllShadows(void)
|
||||
{
|
||||
if (TheW3DVolumetricShadowManager)
|
||||
TheW3DVolumetricShadowManager->removeAllShadows();
|
||||
if (TheW3DProjectedShadowManager)
|
||||
TheW3DProjectedShadowManager->removeAllShadows();
|
||||
}
|
||||
|
||||
/**Force update of all shadows even when light source and object have not moved*/
|
||||
void W3DShadowManager::invalidateCachedLightPositions(void)
|
||||
{
|
||||
if (TheW3DVolumetricShadowManager)
|
||||
TheW3DVolumetricShadowManager->invalidateCachedLightPositions();
|
||||
if (TheW3DProjectedShadowManager)
|
||||
TheW3DProjectedShadowManager->invalidateCachedLightPositions();
|
||||
}
|
||||
|
||||
Vector3 &W3DShadowManager::getLightPosWorld(Int lightIndex)
|
||||
{
|
||||
return LightPosWorld[lightIndex];
|
||||
}
|
||||
|
||||
void W3DShadowManager::setLightPosition(Int lightIndex, Real x, Real y, Real z)
|
||||
{
|
||||
if (lightIndex != 0)
|
||||
return; ///@todo: Add support for multiple lights
|
||||
|
||||
LightPosWorld[lightIndex]=Vector3(x,y,z);
|
||||
}
|
||||
|
||||
void W3DShadowManager::setTimeOfDay(TimeOfDay tod)
|
||||
{
|
||||
//Ray to light source
|
||||
const GlobalData::TerrainLighting *ol=&TheGlobalData->m_terrainObjectsLighting[tod][0];
|
||||
|
||||
Vector3 lightRay(-ol->lightPos.x,-ol->lightPos.y,-ol->lightPos.z);
|
||||
|
||||
lightRay.Normalize();
|
||||
lightRay *= SUN_DISTANCE_FROM_GROUND;
|
||||
|
||||
setLightPosition(0, lightRay.X, lightRay.Y, lightRay.Z);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TileData.cpp
|
||||
// Class to handle tile data.
|
||||
// Author: John Ahlquist, April 2001
|
||||
|
||||
#include "W3DDevice/GameClient/TileData.h"
|
||||
#include "W3DDevice/GameClient/WorldHeightMap.h"
|
||||
|
||||
|
||||
|
||||
//
|
||||
// TileData - no destructor.
|
||||
//
|
||||
|
||||
//
|
||||
// TileData - create a new texture tile .
|
||||
//
|
||||
TileData::TileData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#define TILE_PIXEL_EXTENT_MIP1 32
|
||||
#define TILE_PIXEL_EXTENT_MIP2 16
|
||||
#define TILE_PIXEL_EXTENT_MIP3 8
|
||||
#define TILE_PIXEL_EXTENT_MIP4 4
|
||||
#define TILE_PIXEL_EXTENT_MIP5 2
|
||||
#define TILE_PIXEL_EXTENT_MIP6 1
|
||||
|
||||
Bool TileData::hasRGBDataForWidth(Int width)
|
||||
{
|
||||
if (width == TILE_PIXEL_EXTENT) return(true);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP1) return(true);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP2) return(true);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP3) return(true);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP4) return(true);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP5) return(true);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP6) return(true);
|
||||
return(false);
|
||||
}
|
||||
|
||||
UnsignedByte * TileData::getRGBDataForWidth(Int width)
|
||||
{
|
||||
// default
|
||||
if (width == TILE_PIXEL_EXTENT_MIP1) return(m_tileDataMip32);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP2) return(m_tileDataMip16);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP3) return(m_tileDataMip8);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP4) return(m_tileDataMip4);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP5) return(m_tileDataMip2);
|
||||
if (width == TILE_PIXEL_EXTENT_MIP6) return(m_tileDataMip1);
|
||||
return(m_tileData);
|
||||
}
|
||||
|
||||
void TileData::updateMips(void)
|
||||
{
|
||||
doMip(m_tileData, TILE_PIXEL_EXTENT, m_tileDataMip32);
|
||||
doMip(m_tileDataMip32, TILE_PIXEL_EXTENT_MIP1, m_tileDataMip16);
|
||||
doMip(m_tileDataMip16, TILE_PIXEL_EXTENT_MIP2, m_tileDataMip8);
|
||||
doMip(m_tileDataMip8, TILE_PIXEL_EXTENT_MIP3, m_tileDataMip4);
|
||||
doMip(m_tileDataMip4, TILE_PIXEL_EXTENT_MIP4, m_tileDataMip2);
|
||||
doMip(m_tileDataMip2, TILE_PIXEL_EXTENT_MIP5, m_tileDataMip1);
|
||||
}
|
||||
|
||||
|
||||
void TileData::doMip(UnsignedByte *pHiRes, Int hiRow, UnsignedByte *pLoRes)
|
||||
{
|
||||
Int i, j;
|
||||
for (i=0; i<hiRow; i+=2) {
|
||||
for (j=0; j<hiRow; j+=2) {
|
||||
Int pxl;
|
||||
Int ndx = (j*hiRow+i)*TILE_BYTES_PER_PIXEL;
|
||||
Int loNdx = (j/2)*(hiRow/2) + (i/2);
|
||||
loNdx *= TILE_BYTES_PER_PIXEL;
|
||||
Int p;
|
||||
for (p=0; p<TILE_BYTES_PER_PIXEL; p++,ndx++,loNdx++) {
|
||||
pxl = pHiRes[ndx] + pHiRes[ndx+TILE_BYTES_PER_PIXEL] + pHiRes[ndx+TILE_BYTES_PER_PIXEL*hiRow] + pHiRes[ndx+TILE_BYTES_PER_PIXEL*hiRow+TILE_BYTES_PER_PIXEL] +2;
|
||||
pxl /= 4;
|
||||
pLoRes[loNdx] = pxl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "W3DDevice/GameClient/W3DAssetManagerExposed.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
|
||||
void ReloadAllTextures(void)
|
||||
{
|
||||
W3DAssetManager::Get_Instance()->Release_All_Textures();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DBibBuffer.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DBibBuffer.cpp
|
||||
//
|
||||
// Created: John Ahlquist, May 2001
|
||||
//
|
||||
// Desc: Draw buffer to handle all the bibs in a scene.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "W3DDevice/GameClient/W3DBibBuffer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include <texture.h>
|
||||
#include "common/GlobalData.h"
|
||||
#include "common/RandomValue.h"
|
||||
#include "W3DDevice/GameClient/TerrainTex.h"
|
||||
#include "W3DDevice/GameClient/HeightMap.h"
|
||||
#include "W3DDevice/GameClient/W3DDynamicLight.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/DX8Renderer.h"
|
||||
#include "WW3D2/Mesh.h"
|
||||
#include "WW3D2/MeshMdl.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//-----------------------------------------------------------------------------
|
||||
// A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer.
|
||||
#define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass detailAlphaShader(SC_ALPHA_DETAIL);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::loadBibsInVertexAndIndexBuffers
|
||||
//=============================================================================
|
||||
/** Loads the bibs into the vertex buffer for drawing. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::loadBibsInVertexAndIndexBuffers(void)
|
||||
{
|
||||
if (!m_indexBib || !m_vertexBib || !m_initialized) {
|
||||
return;
|
||||
}
|
||||
if (!m_anythingChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_curNumBibVertices = 0;
|
||||
m_curNumBibIndices = 0;
|
||||
m_curNumNormalBibIndices = 0;
|
||||
m_curNumNormalBibVertex = 0;
|
||||
|
||||
if (m_numBibs==0) {
|
||||
return;
|
||||
}
|
||||
|
||||
VertexFormatXYZDUV1 *vb;
|
||||
UnsignedShort *ib;
|
||||
// Lock the buffers.
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBib, D3DLOCK_DISCARD);
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexBib, D3DLOCK_DISCARD);
|
||||
vb=(VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
|
||||
ib = lockIdxBuffer.Get_Index_Array();
|
||||
// Add to the index buffer & vertex buffer.
|
||||
UnsignedShort *curIb = ib;
|
||||
|
||||
VertexFormatXYZDUV1 *curVb = vb;
|
||||
|
||||
Int curBib;
|
||||
|
||||
// Calculate a static lighting value to use for all the bibs.
|
||||
Real shadeR, shadeG, shadeB;
|
||||
shadeR = TheGlobalData->m_terrainAmbient[0].red;
|
||||
shadeG = TheGlobalData->m_terrainAmbient[0].green;
|
||||
shadeB = TheGlobalData->m_terrainAmbient[0].blue;
|
||||
shadeR += TheGlobalData->m_terrainDiffuse[0].red;
|
||||
shadeG += TheGlobalData->m_terrainDiffuse[0].green;
|
||||
shadeB += TheGlobalData->m_terrainDiffuse[0].blue;
|
||||
if (shadeR>1.0f) shadeR=1.0f;
|
||||
if (shadeG>1.0f) shadeG=1.0f;
|
||||
if (shadeB>1.0f) shadeB=1.0f;
|
||||
shadeR*=255.0f;
|
||||
shadeG*=255.0f;
|
||||
shadeB*=255.0f;
|
||||
|
||||
Int diffuse = (REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | (255 << 24));
|
||||
Int doHighlight;
|
||||
try {
|
||||
for (doHighlight=0; doHighlight<=1; doHighlight++)
|
||||
{
|
||||
if (doHighlight==1)
|
||||
{
|
||||
m_curNumNormalBibIndices = m_curNumBibIndices;
|
||||
m_curNumNormalBibVertex = m_curNumBibVertices;
|
||||
}
|
||||
for (curBib=0; curBib<m_numBibs; curBib++) {
|
||||
if (m_bibs[curBib].m_unused) continue;
|
||||
if (m_bibs[curBib].m_highlight != (Bool)doHighlight) continue;
|
||||
Int startVertex = m_curNumBibVertices;
|
||||
Int i;
|
||||
Int numVertex = 4;
|
||||
if (m_curNumBibVertices+numVertex+2>= m_vertexBibSize) {
|
||||
break;
|
||||
}
|
||||
Int numIndex = 6;
|
||||
if (m_curNumBibIndices+numIndex+6 >= m_indexBibSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (i=0; i<numVertex; i++) {
|
||||
|
||||
// Update the uv values. The W3D models each have their own texture, and
|
||||
// we use one texture with all images in one, so we have to change the uvs to
|
||||
// match.
|
||||
Real U, V;
|
||||
Vector3 vLoc=m_bibs[curBib].m_corners[i];
|
||||
switch (i) {
|
||||
case 0 :
|
||||
U=0;V=1;
|
||||
break;
|
||||
case 1:
|
||||
U=1;V=1;
|
||||
break;
|
||||
case 2:
|
||||
U=1;V=0;
|
||||
break;
|
||||
case 3:
|
||||
U=0;V=0;
|
||||
break;
|
||||
}
|
||||
|
||||
curVb->u1 = U;
|
||||
curVb->v1 = V;
|
||||
curVb->x = vLoc.X;
|
||||
curVb->y = vLoc.Y;
|
||||
curVb->z = vLoc.Z;
|
||||
curVb->diffuse = diffuse;
|
||||
curVb++;
|
||||
m_curNumBibVertices++;
|
||||
}
|
||||
|
||||
*curIb++ = startVertex + 0;
|
||||
*curIb++ = startVertex + 1;
|
||||
*curIb++ = startVertex + 2;
|
||||
*curIb++ = startVertex + 0;
|
||||
*curIb++ = startVertex + 2;
|
||||
*curIb++ = startVertex + 3;
|
||||
m_curNumBibIndices+=6;
|
||||
}
|
||||
}
|
||||
IndexBufferExceptionFunc();
|
||||
} catch(...) {
|
||||
IndexBufferExceptionFunc();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::~W3DBibBuffer
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
W3DBibBuffer::~W3DBibBuffer(void)
|
||||
{
|
||||
freeBibBuffers();
|
||||
REF_PTR_RELEASE(m_bibTexture);
|
||||
REF_PTR_RELEASE(m_highlightBibTexture);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::W3DBibBuffer
|
||||
//=============================================================================
|
||||
/** Constructor. Sets m_initialized to true if it finds the w3d models it needs
|
||||
for the bibs. */
|
||||
//=============================================================================
|
||||
W3DBibBuffer::W3DBibBuffer(void)
|
||||
{
|
||||
m_initialized = false;
|
||||
m_vertexBib = NULL;
|
||||
m_indexBib = NULL;
|
||||
m_bibTexture = NULL;
|
||||
m_curNumBibVertices=0;
|
||||
m_curNumBibIndices=0;
|
||||
clearAllBibs();
|
||||
m_indexBibSize = INITIAL_BIB_INDEX;
|
||||
m_vertexBibSize = INITIAL_BIB_VERTEX;
|
||||
allocateBibBuffers();
|
||||
|
||||
m_bibTexture = NEW_REF(TextureClass, ("TBBib.tga"));
|
||||
m_highlightBibTexture = NEW_REF(TextureClass, ("TBRedBib.tga"));
|
||||
m_bibTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_bibTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_highlightBibTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_highlightBibTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::freeBibBuffers
|
||||
//=============================================================================
|
||||
/** Frees the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::freeBibBuffers(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_vertexBib);
|
||||
REF_PTR_RELEASE(m_indexBib);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::allocateBibBuffers
|
||||
//=============================================================================
|
||||
/** Allocates the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::allocateBibBuffers(void)
|
||||
{
|
||||
m_vertexBib=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_vertexBibSize+4,DX8VertexBufferClass::USAGE_DYNAMIC));
|
||||
m_indexBib=NEW_REF(DX8IndexBufferClass,(m_indexBibSize+4, DX8IndexBufferClass::USAGE_DYNAMIC));
|
||||
m_curNumBibVertices=0;
|
||||
m_curNumBibIndices=0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::clearAllBibs
|
||||
//=============================================================================
|
||||
/** Removes all bibs. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::clearAllBibs(void)
|
||||
{
|
||||
m_numBibs=0;
|
||||
m_anythingChanged = true;
|
||||
/* test bib
|
||||
Vector3 corners[4];
|
||||
corners[0].Set(0, 0, 20);
|
||||
corners[1].Set(100, 0, 20);
|
||||
corners[2].Set(100,100,20);
|
||||
corners[3].Set(0,100,20);
|
||||
addBib(corners, 1, false);
|
||||
*/
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::removeHighlighting
|
||||
//=============================================================================
|
||||
/** Clears highlighting flag. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::removeHighlighting(void)
|
||||
{
|
||||
Int bibIndex;
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
m_bibs[bibIndex].m_highlight = false;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::addBib
|
||||
//=============================================================================
|
||||
/** Adds a bib. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::addBib(Vector3 corners[4], ObjectID id, Bool highlight)
|
||||
{
|
||||
Int bibIndex;
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
if (!m_bibs[bibIndex].m_unused && m_bibs[bibIndex].m_objectID == id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bibIndex==m_numBibs) {
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
if (m_bibs[bibIndex].m_unused) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bibIndex==m_numBibs) {
|
||||
if (m_numBibs >= MAX_BIBS) {
|
||||
return;
|
||||
}
|
||||
m_numBibs++;
|
||||
}
|
||||
m_anythingChanged = true;
|
||||
m_bibs[bibIndex].m_corners[0] = corners[0];
|
||||
m_bibs[bibIndex].m_corners[1] = corners[1];
|
||||
m_bibs[bibIndex].m_corners[2] = corners[2];
|
||||
m_bibs[bibIndex].m_corners[3] = corners[3];
|
||||
m_bibs[bibIndex].m_highlight = highlight;
|
||||
m_bibs[bibIndex].m_color = 0; // for now.
|
||||
m_bibs[bibIndex].m_unused = false; // for now.
|
||||
m_bibs[bibIndex].m_objectID = id;
|
||||
m_bibs[bibIndex].m_drawableID = INVALID_DRAWABLE_ID;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::addBib
|
||||
//=============================================================================
|
||||
/** Adds a bib. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::addBibDrawable(Vector3 corners[4], DrawableID id, Bool highlight)
|
||||
{
|
||||
Int bibIndex;
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
if (!m_bibs[bibIndex].m_unused && m_bibs[bibIndex].m_drawableID == id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bibIndex==m_numBibs) {
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
if (m_bibs[bibIndex].m_unused) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bibIndex==m_numBibs) {
|
||||
if (m_numBibs >= MAX_BIBS) {
|
||||
return;
|
||||
}
|
||||
m_numBibs++;
|
||||
}
|
||||
m_anythingChanged = true;
|
||||
m_bibs[bibIndex].m_corners[0] = corners[0];
|
||||
m_bibs[bibIndex].m_corners[1] = corners[1];
|
||||
m_bibs[bibIndex].m_corners[2] = corners[2];
|
||||
m_bibs[bibIndex].m_corners[3] = corners[3];
|
||||
m_bibs[bibIndex].m_highlight = highlight;
|
||||
m_bibs[bibIndex].m_color = 0; // for now.
|
||||
m_bibs[bibIndex].m_unused = false; // for now.
|
||||
m_bibs[bibIndex].m_objectID = INVALID_ID;
|
||||
m_bibs[bibIndex].m_drawableID = id;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::removeBib
|
||||
//=============================================================================
|
||||
/** Removes a bib. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::removeBib(ObjectID id)
|
||||
{
|
||||
Int bibIndex;
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
if (m_bibs[bibIndex].m_objectID == id) {
|
||||
m_bibs[bibIndex].m_unused = true;
|
||||
m_bibs[bibIndex].m_objectID = INVALID_ID;
|
||||
m_bibs[bibIndex].m_drawableID = INVALID_DRAWABLE_ID;
|
||||
m_anythingChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::removeBib
|
||||
//=============================================================================
|
||||
/** Removes a bib. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::removeBibDrawable(DrawableID id)
|
||||
{
|
||||
Int bibIndex;
|
||||
for (bibIndex=0; bibIndex<m_numBibs; bibIndex++) {
|
||||
if (m_bibs[bibIndex].m_drawableID == id) {
|
||||
m_bibs[bibIndex].m_unused = true;
|
||||
m_bibs[bibIndex].m_objectID = INVALID_ID;
|
||||
m_bibs[bibIndex].m_drawableID = INVALID_DRAWABLE_ID;
|
||||
m_anythingChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DBibBuffer::drawBibs
|
||||
//=============================================================================
|
||||
/** Draws the bibs. Uses camera to cull. */
|
||||
//=============================================================================
|
||||
void W3DBibBuffer::renderBibs()
|
||||
{
|
||||
|
||||
loadBibsInVertexAndIndexBuffers();
|
||||
|
||||
if (m_curNumBibIndices == 0) {
|
||||
return;
|
||||
}
|
||||
// Setup the vertex buffer, shader & texture.
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBib,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexBib);
|
||||
DX8Wrapper::Set_Shader(detailAlphaShader);
|
||||
if (m_curNumNormalBibIndices) {
|
||||
DX8Wrapper::Set_Texture(0,m_bibTexture);
|
||||
DX8Wrapper::Draw_Triangles( 0, m_curNumNormalBibIndices/3, 0, m_curNumNormalBibVertex);
|
||||
}
|
||||
if (m_curNumBibIndices>m_curNumNormalBibIndices) {
|
||||
DX8Wrapper::Set_Texture(0,m_highlightBibTexture);
|
||||
DX8Wrapper::Draw_Triangles( m_curNumNormalBibIndices, (m_curNumBibIndices-m_curNumNormalBibIndices)/3,
|
||||
m_curNumNormalBibVertex, m_curNumBibVertices-m_curNumNormalBibVertex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DCustomEdging.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DCustomEdging.cpp
|
||||
//
|
||||
// Created: John Ahlquist, May 2001
|
||||
//
|
||||
// Desc: Draw buffer to handle all the custom tile edges in a scene.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "W3DDevice/GameClient/W3DCustomEdging.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include <texture.h>
|
||||
#include "common/GlobalData.h"
|
||||
#include "common/RandomValue.h"
|
||||
#include "W3DDevice/GameClient/TerrainTex.h"
|
||||
#include "W3DDevice/GameClient/HeightMap.h"
|
||||
#include "W3DDevice/GameClient/W3DDynamicLight.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/DX8Renderer.h"
|
||||
#include "WW3D2/Mesh.h"
|
||||
#include "WW3D2/MeshMdl.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//-----------------------------------------------------------------------------
|
||||
// A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer.
|
||||
#define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass detailAlphaTestShader(SC_ALPHA_DETAIL);
|
||||
|
||||
|
||||
#define SC_NO_ALPHA ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass detailShader(SC_NO_ALPHA);
|
||||
|
||||
#define SC_DETAIL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass detailOpaqueShader(SC_DETAIL_BLEND);
|
||||
|
||||
/*
|
||||
#define SC_ALPHA_MIRROR ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass mirrorAlphaShader(SC_ALPHA_DETAIL);
|
||||
|
||||
// ShaderClass::PASS_ALWAYS,
|
||||
|
||||
#define SC_ALPHA_2D ( SHADE_CNST(PASS_ALWAYS, DEPTH_WRITE_DISABLE, COLOR_WRITE_ENABLE, \
|
||||
SRCBLEND_SRC_ALPHA, DSTBLEND_ONE_MINUS_SRC_ALPHA, FOG_DISABLE, GRADIENT_DISABLE, \
|
||||
SECONDARY_GRADIENT_DISABLE, TEXTURING_ENABLE, DETAILCOLOR_DISABLE, DETAILALPHA_DISABLE, \
|
||||
ALPHATEST_DISABLE, CULL_MODE_ENABLE, DETAILCOLOR_DISABLE, DETAILALPHA_DISABLE) )
|
||||
ShaderClass ShaderClass::_PresetAlpha2DShader(SC_ALPHA_2D);
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::loadEdgingsInVertexAndIndexBuffers
|
||||
//=============================================================================
|
||||
/** Loads the trees into the vertex buffer for drawing. */
|
||||
//=============================================================================
|
||||
void W3DCustomEdging::loadEdgingsInVertexAndIndexBuffers(WorldHeightMap *pMap, Int minX, Int maxX, Int minY, Int maxY)
|
||||
{
|
||||
if (!m_indexEdging || !m_vertexEdging || !m_initialized) {
|
||||
return;
|
||||
}
|
||||
if (!m_anythingChanged) {
|
||||
return;
|
||||
}
|
||||
m_anythingChanged = false;
|
||||
m_curNumEdgingVertices = 0;
|
||||
m_curNumEdgingIndices = 0;
|
||||
VertexFormatXYZDUV2 *vb;
|
||||
UnsignedShort *ib;
|
||||
// Lock the buffers.
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexEdging);
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexEdging);
|
||||
vb=(VertexFormatXYZDUV2*)lockVtxBuffer.Get_Vertex_Array();
|
||||
ib = lockIdxBuffer.Get_Index_Array();
|
||||
|
||||
UnsignedShort *curIb = ib;
|
||||
|
||||
VertexFormatXYZDUV2 *curVb = vb;
|
||||
|
||||
if (minX<0) minX = 0;
|
||||
if (minY<0) minY = 0;
|
||||
if (maxX >= pMap->getXExtent()) maxX = pMap->getXExtent()-1;
|
||||
if (maxY >= pMap->getYExtent()) maxY = pMap->getYExtent()-1;
|
||||
Int row;
|
||||
Int column;
|
||||
try {
|
||||
for (row=minY; row<maxY-1; row++) {
|
||||
for (column = minX; column < maxX-1; column++) {
|
||||
Int cellNdx = column+row*pMap->getXExtent();
|
||||
Int blend = pMap->m_blendTileNdxes[cellNdx];
|
||||
if (blend == 0) continue; // no blend.
|
||||
|
||||
if (pMap->m_blendedTiles[blend].customBlendEdgeClass<0) continue; // alpha blend.
|
||||
Int i, j;
|
||||
Real uOffset;
|
||||
Real vOffset;
|
||||
|
||||
if (pMap->m_blendedTiles[blend].horiz) {
|
||||
uOffset = 0;
|
||||
vOffset = 0.25f * (1 + (row&1));
|
||||
if (pMap->m_blendedTiles[blend].inverted) {
|
||||
uOffset = 0.75f;
|
||||
}
|
||||
} else if (pMap->m_blendedTiles[blend].vert) {
|
||||
vOffset = 0.75;
|
||||
uOffset = 0.25f * (1 + (column&1));
|
||||
if (pMap->m_blendedTiles[blend].inverted) {
|
||||
vOffset = 0.0f;
|
||||
}
|
||||
} else if (pMap->m_blendedTiles[blend].rightDiagonal) {
|
||||
if (pMap->m_blendedTiles[blend].longDiagonal) {
|
||||
vOffset = 0.25;
|
||||
uOffset = 0.5;
|
||||
if (pMap->m_blendedTiles[blend].inverted) {
|
||||
uOffset = 0.5f;
|
||||
vOffset = 0.5f;
|
||||
}
|
||||
} else {
|
||||
vOffset = .75;
|
||||
uOffset = 0;
|
||||
if (pMap->m_blendedTiles[blend].inverted) {
|
||||
uOffset = 0.0f;
|
||||
vOffset = 0.0f;
|
||||
}
|
||||
}
|
||||
} else if (pMap->m_blendedTiles[blend].leftDiagonal) {
|
||||
if (pMap->m_blendedTiles[blend].longDiagonal) {
|
||||
uOffset = 0.25f;
|
||||
vOffset = 0.25f;
|
||||
if (pMap->m_blendedTiles[blend].inverted) {
|
||||
uOffset = 0.25f;
|
||||
vOffset = 0.5f;
|
||||
}
|
||||
} else {
|
||||
vOffset = 0.75;
|
||||
uOffset = 0.75f;
|
||||
if (pMap->m_blendedTiles[blend].inverted) {
|
||||
uOffset = 0.75f;
|
||||
vOffset = 0.0f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
Region2D range;
|
||||
pMap->getUVForBlend(pMap->m_blendedTiles[blend].customBlendEdgeClass, &range);
|
||||
|
||||
uOffset = range.lo.x + range.width()*uOffset;
|
||||
vOffset = range.lo.y + range.height()*vOffset;
|
||||
|
||||
UnsignedByte alpha[4];
|
||||
float UA[4], VA[4];
|
||||
Bool flipForBlend;
|
||||
pMap->getAlphaUVData(column-pMap->getDrawOrgX(), row-pMap->getDrawOrgY(), UA, VA, alpha, &flipForBlend, false);
|
||||
|
||||
|
||||
Int startVertex = m_curNumEdgingVertices;
|
||||
for (j=0; j<2; j++) {
|
||||
for (i=0; i<2; i++) {
|
||||
if (m_curNumEdgingVertices >= MAX_EDGE_VERTEX) return;
|
||||
cellNdx = column+i+(row+j)*pMap->getXExtent();
|
||||
|
||||
Int diffuse = TheTerrainRenderObject->getStaticDiffuse(column+i, row+j);
|
||||
curVb->diffuse = 0x80000000 + (diffuse&0x00FFFFFF); // set alpha to 5b.
|
||||
Real theZ;
|
||||
theZ = ((float)pMap->getDataPtr()[cellNdx])*MAP_HEIGHT_SCALE;
|
||||
Real X = (column+i)*MAP_XY_FACTOR;
|
||||
Real Y = (row+j)*MAP_XY_FACTOR;
|
||||
curVb->u2 = uOffset + i*0.25f*range.width();
|
||||
curVb->v2 = vOffset + (1-j)*0.25f*range.height();
|
||||
Int ndx;
|
||||
if (j==0) ndx=i;
|
||||
if (j==1) ndx = 3-i;
|
||||
curVb->u1 = UA[ndx];
|
||||
curVb->v1 = VA[ndx];
|
||||
curVb->x = X;
|
||||
curVb->y = Y;
|
||||
curVb->z = theZ;
|
||||
curVb++;
|
||||
m_curNumEdgingVertices++;
|
||||
}
|
||||
}
|
||||
Int yOffset = 2;
|
||||
if (m_curNumEdgingIndices+6 > MAX_EDGE_INDEX) return;
|
||||
#ifdef FLIP_TRIANGLES // jba - reduces "diamonding" in some cases, not others. Better cliffs, though.
|
||||
if (flipForBlend) {
|
||||
*curIb++ = startVertex + 1;
|
||||
*curIb++ = startVertex + yOffset;
|
||||
*curIb++ = startVertex ;
|
||||
*curIb++ = startVertex + 1;
|
||||
*curIb++ = startVertex + 1+yOffset;
|
||||
*curIb++ = startVertex + yOffset;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
*curIb++ = startVertex;
|
||||
*curIb++ = startVertex + 1+yOffset;
|
||||
*curIb++ = startVertex + yOffset;
|
||||
*curIb++ = startVertex ;
|
||||
*curIb++ = startVertex + 1;
|
||||
*curIb++ = startVertex + 1+yOffset;
|
||||
}
|
||||
m_curNumEdgingIndices+=6;
|
||||
}
|
||||
}
|
||||
IndexBufferExceptionFunc();
|
||||
} catch(...) {
|
||||
IndexBufferExceptionFunc();
|
||||
}
|
||||
m_anythingChanged = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::~W3DCustomEdging
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
W3DCustomEdging::~W3DCustomEdging(void)
|
||||
{
|
||||
freeEdgingBuffers();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::W3DCustomEdging
|
||||
//=============================================================================
|
||||
/** Constructor. Sets m_initialized to true if it finds the w3d models it needs
|
||||
for the trees. */
|
||||
//=============================================================================
|
||||
W3DCustomEdging::W3DCustomEdging(void)
|
||||
{
|
||||
m_initialized = false;
|
||||
m_vertexEdging = NULL;
|
||||
m_indexEdging = NULL;
|
||||
clearAllEdging();
|
||||
allocateEdgingBuffers();
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::freeEdgingBuffers
|
||||
//=============================================================================
|
||||
/** Frees the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DCustomEdging::freeEdgingBuffers(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_vertexEdging);
|
||||
REF_PTR_RELEASE(m_indexEdging);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::allocateEdgingBuffers
|
||||
//=============================================================================
|
||||
/** Allocates the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DCustomEdging::allocateEdgingBuffers(void)
|
||||
{
|
||||
m_vertexEdging=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV2,MAX_EDGE_VERTEX+4,DX8VertexBufferClass::USAGE_DYNAMIC));
|
||||
m_indexEdging=NEW_REF(DX8IndexBufferClass,(2*MAX_EDGE_INDEX+4, DX8IndexBufferClass::USAGE_DYNAMIC));
|
||||
m_curNumEdgingVertices=0;
|
||||
m_curNumEdgingIndices=0;
|
||||
//m_edgeTexture = MSGNEW("TextureClass") TextureClass("EdgingTemplate.tga","EdgingTemplate.tga", TextureClass::MIP_LEVELS_3);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::clearAllEdging
|
||||
//=============================================================================
|
||||
/** Removes all trees. */
|
||||
//=============================================================================
|
||||
void W3DCustomEdging::clearAllEdging(void)
|
||||
{
|
||||
m_curNumEdgingVertices=0;
|
||||
m_curNumEdgingIndices=0;
|
||||
m_anythingChanged = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DCustomEdging::drawEdging
|
||||
//=============================================================================
|
||||
/** Draws the trees. Uses camera to cull. */
|
||||
//=============================================================================
|
||||
void W3DCustomEdging::drawEdging(WorldHeightMap *pMap, Int minX, Int maxX, Int minY, Int maxY,
|
||||
TextureClass * terrainTexture, TextureClass * cloudTexture, TextureClass * noiseTexture)
|
||||
{
|
||||
static Bool foo = false;
|
||||
if (foo) {
|
||||
return;
|
||||
}
|
||||
//m_anythingChanged = true;
|
||||
loadEdgingsInVertexAndIndexBuffers(pMap, minX, maxX, minY, maxY);
|
||||
|
||||
if (m_curNumEdgingIndices == 0) {
|
||||
return;
|
||||
}
|
||||
TextureClass *edgeTex = pMap->getEdgeTerrainTexture();
|
||||
// Setup the vertex buffer, shader & texture.
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexEdging,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexEdging);
|
||||
DX8Wrapper::Set_Shader(detailAlphaTestShader);
|
||||
#ifdef _DEBUG
|
||||
//DX8Wrapper::Set_Shader(detailShader); // shows clipping.
|
||||
#endif
|
||||
|
||||
DX8Wrapper::Set_Texture(0,terrainTexture);
|
||||
DX8Wrapper::Set_Texture(1,edgeTex);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x7B);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAFUNC,D3DCMP_LESSEQUAL); //pass pixels who's alpha is not zero
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, true); //test pixels if transparent(clipped) before rendering.
|
||||
DX8Wrapper::Draw_Triangles( m_curEdgingIndexOffset, m_curNumEdgingIndices/3, 0, m_curNumEdgingVertices);
|
||||
|
||||
DX8Wrapper::Set_Texture(0,edgeTex);
|
||||
DX8Wrapper::Set_Texture(1, NULL);
|
||||
// Draw the custom edge.
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x84);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL); //pass pixels who's alpha is not zero
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, true); //test pixels if transparent(clipped) before rendering.
|
||||
DX8Wrapper::Draw_Triangles( m_curEdgingIndexOffset, m_curNumEdgingIndices/3, 0, m_curNumEdgingVertices);
|
||||
|
||||
#if 0 // Dumps out unmasked data.
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE,false);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, false); //test pixels if transparent(clipped) before rendering.
|
||||
DX8Wrapper::Draw_Triangles( m_curEdgingIndexOffset, m_curNumEdgingIndices/3, 0, m_curNumEdgingVertices);
|
||||
#endif
|
||||
DX8Wrapper::Set_Texture(1, NULL);
|
||||
if (cloudTexture) {
|
||||
DX8Wrapper::Set_Shader(detailOpaqueShader);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
DX8Wrapper::Set_Texture(1,edgeTex);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
DX8Wrapper::Set_Texture(0,cloudTexture);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
#if 1
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
|
||||
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_TEXCOORDINDEX, 1 );
|
||||
#endif
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x80);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAFUNC,D3DCMP_NOTEQUAL); //pass pixels who's alpha is not zero
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, true); //test pixels if transparent(clipped) before rendering.
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE,true);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND,D3DBLEND_ZERO);
|
||||
DX8Wrapper::Draw_Triangles( m_curEdgingIndexOffset, m_curNumEdgingIndices/3, 0, m_curNumEdgingVertices);
|
||||
}
|
||||
if (noiseTexture) {
|
||||
DX8Wrapper::Set_Texture(1, NULL);
|
||||
DX8Wrapper::Set_Texture(0,noiseTexture);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
DX8Wrapper::Set_Texture(1,edgeTex);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x80);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAFUNC,D3DCMP_NOTEQUAL); //pass pixels who's alpha is not zero
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, true); //test pixels if transparent(clipped) before rendering.
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE,true);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND,D3DBLEND_ZERO);
|
||||
DX8Wrapper::Draw_Triangles( m_curEdgingIndexOffset, m_curNumEdgingIndices/3, 0, m_curNumEdgingVertices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: Generals
|
||||
//
|
||||
// Module: Debug
|
||||
//
|
||||
// File name: W3DGameDevice/GameClisnt/W3DDebugDisplay.cpp
|
||||
//
|
||||
// Created: 11/13/01 TR
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "W3DDevice/GameClient/W3DDebugDisplay.h"
|
||||
#include "GameClient/GameFont.h"
|
||||
#include "GameClient/DisplayStringManager.h"
|
||||
#include "GameClient/DisplayString.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Externals
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Types
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Public Data
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//============================================================================
|
||||
// W3DDebugDisplay::W3DDebugDisplay
|
||||
//============================================================================
|
||||
|
||||
W3DDebugDisplay::W3DDebugDisplay()
|
||||
: m_displayString(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DDebugDisplay::~W3DDebugDisplay
|
||||
//============================================================================
|
||||
|
||||
W3DDebugDisplay::~W3DDebugDisplay()
|
||||
{
|
||||
if ( m_displayString )
|
||||
{
|
||||
TheDisplayStringManager->freeDisplayString( m_displayString );
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DDebugDisplay::init
|
||||
//============================================================================
|
||||
|
||||
void W3DDebugDisplay::init( void )
|
||||
{
|
||||
m_displayString = TheDisplayStringManager->newDisplayString();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DDebugDisplay::drawText
|
||||
//============================================================================
|
||||
|
||||
void W3DDebugDisplay::drawText( Int x, Int y, Char *text )
|
||||
{
|
||||
if ( m_font == NULL || m_displayString == NULL )
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
::Color textColor = GameMakeColor( 255, 255, 255, 255 );
|
||||
::Color dropColor = GameMakeColor( 0, 0, 0, 255 );
|
||||
|
||||
UnicodeString unicode;
|
||||
|
||||
unicode.translate( AsciiString( text ) );
|
||||
m_displayString->setText( unicode );
|
||||
m_displayString->draw( x*m_fontWidth, 13 + y*m_fontHeight, textColor, dropColor );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DDebugDisplay::setFont
|
||||
//============================================================================
|
||||
|
||||
void W3DDebugDisplay::setFont( GameFont *font )
|
||||
{
|
||||
m_font = font;
|
||||
if ( m_displayString )
|
||||
{
|
||||
m_displayString->setFont( m_font );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DDebugIcons.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: Heightmap.cpp
|
||||
//
|
||||
// Created: John Ahlquist, March 2002
|
||||
//
|
||||
// Desc: Draws huge numbers of debug icons for pathfinding quickly.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "W3DDevice/GameClient/W3DDebugIcons.h"
|
||||
|
||||
#include "Common/GlobalData.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "Common/MapObject.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
|
||||
#if defined _DEBUG || defined _INTERNAL
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_OPAQUE ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_DISABLE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_ALPHA ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_ALPHA_Z ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_OPAQUE_Z ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_DISABLE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
|
||||
void addIcon(const Coord3D *pos, Real width, Int numFramesDuration, RGBColor color)
|
||||
{
|
||||
W3DDebugIcons::addIcon(pos, width, numFramesDuration, color);
|
||||
}
|
||||
|
||||
|
||||
struct DebugIcon {
|
||||
Coord3D position;
|
||||
Real width; // all are squares centered about pos.
|
||||
RGBColor color;
|
||||
Int endFrame; // Frame when this disappears.
|
||||
};
|
||||
|
||||
DebugIcon *W3DDebugIcons::m_debugIcons = NULL;
|
||||
Int W3DDebugIcons::m_numDebugIcons = 0;
|
||||
|
||||
W3DDebugIcons::~W3DDebugIcons(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_vertexMaterialClass);
|
||||
if (m_debugIcons) delete m_debugIcons;
|
||||
m_debugIcons = NULL;
|
||||
m_numDebugIcons = 0;
|
||||
}
|
||||
|
||||
W3DDebugIcons::W3DDebugIcons(void)
|
||||
|
||||
{
|
||||
//go with a preset material for now.
|
||||
m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
allocateIconsArray();
|
||||
}
|
||||
|
||||
|
||||
bool W3DDebugIcons::Cast_Ray(RayCollisionTestClass & raytest)
|
||||
{
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//@todo: MW Handle both of these properly!!
|
||||
W3DDebugIcons::W3DDebugIcons(const W3DDebugIcons & src)
|
||||
{
|
||||
*this = src;
|
||||
}
|
||||
|
||||
W3DDebugIcons & W3DDebugIcons::operator = (const W3DDebugIcons & that)
|
||||
{
|
||||
DEBUG_CRASH(("oops"));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void W3DDebugIcons::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
||||
{
|
||||
Vector3 ObjSpaceCenter(TheGlobalData->m_waterExtentX,TheGlobalData->m_waterExtentY,50*MAP_XY_FACTOR);
|
||||
float length = ObjSpaceCenter.Length();
|
||||
|
||||
sphere.Init(ObjSpaceCenter, length);
|
||||
}
|
||||
|
||||
void W3DDebugIcons::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
||||
{
|
||||
Vector3 minPt(-2*TheGlobalData->m_waterExtentX,-2*TheGlobalData->m_waterExtentY,0);
|
||||
Vector3 maxPt(2*TheGlobalData->m_waterExtentX,2*TheGlobalData->m_waterExtentY,100*MAP_XY_FACTOR);
|
||||
box.Init(minPt,maxPt);
|
||||
}
|
||||
|
||||
Int W3DDebugIcons::Class_ID(void) const
|
||||
{
|
||||
return RenderObjClass::CLASSID_UNKNOWN;
|
||||
}
|
||||
|
||||
RenderObjClass * W3DDebugIcons::Clone(void) const
|
||||
{
|
||||
return NEW W3DDebugIcons(*this); // poolify
|
||||
}
|
||||
|
||||
|
||||
void W3DDebugIcons::allocateIconsArray(void)
|
||||
{
|
||||
m_debugIcons = NEW DebugIcon[MAX_ICONS];
|
||||
m_numDebugIcons = 0;
|
||||
}
|
||||
|
||||
|
||||
void W3DDebugIcons::compressIconsArray(void)
|
||||
{
|
||||
if (m_debugIcons && m_numDebugIcons > 0) {
|
||||
Int newNum = 0;
|
||||
Int i;
|
||||
for (i=0; i<m_numDebugIcons; i++) {
|
||||
if (m_debugIcons[i].endFrame >= TheGameLogic->getFrame() && i>newNum) {
|
||||
m_debugIcons[newNum] = m_debugIcons[i];
|
||||
newNum++;
|
||||
}
|
||||
}
|
||||
m_numDebugIcons = newNum;
|
||||
}
|
||||
}
|
||||
|
||||
static Int maxIcons = 0;
|
||||
|
||||
void W3DDebugIcons::addIcon(const Coord3D *pos, Real width, Int numFramesDuration, RGBColor color)
|
||||
{
|
||||
if (pos==NULL) {
|
||||
if (m_numDebugIcons > maxIcons) {
|
||||
DEBUG_LOG(("Max icons %d\n", m_numDebugIcons));
|
||||
maxIcons = m_numDebugIcons;
|
||||
}
|
||||
m_numDebugIcons = 0;
|
||||
return;
|
||||
}
|
||||
if (m_numDebugIcons>= MAX_ICONS) return;
|
||||
if (m_debugIcons==NULL) return;
|
||||
m_debugIcons[m_numDebugIcons].position = *pos;
|
||||
m_debugIcons[m_numDebugIcons].width = width;
|
||||
m_debugIcons[m_numDebugIcons].color = color;
|
||||
m_debugIcons[m_numDebugIcons].endFrame = TheGameLogic->getFrame()+numFramesDuration;
|
||||
m_numDebugIcons++;
|
||||
}
|
||||
|
||||
/** Render draws into the current 3d context. */
|
||||
void W3DDebugIcons::Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
//
|
||||
if (WW3D::Are_Static_Sort_Lists_Enabled()) {
|
||||
WW3D::Add_To_Static_Sort_List(this, 1);
|
||||
return;
|
||||
}
|
||||
//
|
||||
Bool anyVanished = false;
|
||||
if (m_numDebugIcons==0) return;
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
DX8Wrapper::Set_Texture(0, NULL);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
Matrix3D tm(Transform);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
|
||||
Int numRect = m_numDebugIcons;
|
||||
static Real offset = 30;
|
||||
const Int MAX_RECT = 5000; // cap drawing n rects.
|
||||
if (numRect > MAX_RECT) numRect = MAX_RECT;
|
||||
offset+= 0.5f;
|
||||
Int k;
|
||||
for (k=0; k<m_numDebugIcons;) {
|
||||
Int curIndex = 0;
|
||||
Int numVertex = 0;
|
||||
DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,DX8_FVF_XYZNDUV2,numRect*4);
|
||||
DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,numRect*6);
|
||||
{
|
||||
DynamicVBAccessClass::WriteLockClass lock(&vb_access);
|
||||
VertexFormatXYZNDUV2* vb= lock.Get_Formatted_Vertex_Array();
|
||||
DynamicIBAccessClass::WriteLockClass lockib(&ib_access);
|
||||
if (!vb) return;
|
||||
|
||||
UnsignedShort *ib=lockib.Get_Index_Array();
|
||||
UnsignedShort *curIb = ib;
|
||||
|
||||
// VertexFormatXYZNDUV2 *curVb = vb;
|
||||
Real shadeR, shadeG, shadeB;
|
||||
shadeR = 0;
|
||||
shadeG = 0;
|
||||
shadeB = 255;
|
||||
try {
|
||||
for(; numVertex<numRect*4 && k<m_numDebugIcons; k++) {
|
||||
Int theAlpha = 64;
|
||||
const Int FADE_FRAMES = 100;
|
||||
Int framesLeft = m_debugIcons[k].endFrame - TheGameLogic->getFrame();
|
||||
if (framesLeft < 1) {
|
||||
anyVanished = true;
|
||||
continue;
|
||||
}
|
||||
if (framesLeft<FADE_FRAMES) {
|
||||
theAlpha *= (Real)framesLeft/FADE_FRAMES;
|
||||
}
|
||||
RGBColor clr = m_debugIcons[k].color;
|
||||
Real halfWidth = m_debugIcons[k].width/2;
|
||||
Int diffuse = clr.getAsInt() | ((int)theAlpha << 24);
|
||||
Coord3D pt1 = m_debugIcons[k].position;
|
||||
vb->x= pt1.x-halfWidth;
|
||||
vb->y= pt1.y-halfWidth;
|
||||
vb->z= pt1.z;
|
||||
vb->diffuse=diffuse; // b g<<8 r<<16 a<<24.
|
||||
vb->u1=0 ;
|
||||
vb->v1=0 ;
|
||||
vb++;
|
||||
vb->x= pt1.x+halfWidth;
|
||||
vb->y= pt1.y-halfWidth;
|
||||
vb->z= pt1.z;
|
||||
vb->diffuse=diffuse; // b g<<8 r<<16 a<<24.
|
||||
vb->u1=0 ;
|
||||
vb->v1=0 ;
|
||||
vb++;
|
||||
vb->x= pt1.x+halfWidth;
|
||||
vb->y= pt1.y+halfWidth;
|
||||
vb->z= pt1.z;
|
||||
vb->diffuse=diffuse; // b g<<8 r<<16 a<<24.
|
||||
vb->u1=0 ;
|
||||
vb->v1=0 ;
|
||||
vb++;
|
||||
vb->x= pt1.x-halfWidth;
|
||||
vb->y= pt1.y+halfWidth;
|
||||
vb->z= pt1.z;
|
||||
vb->diffuse=diffuse; // b g<<8 r<<16 a<<24.
|
||||
vb->u1=0 ;
|
||||
vb->v1=0 ;
|
||||
vb++;
|
||||
*curIb++ = numVertex;
|
||||
*curIb++ = numVertex+1;
|
||||
*curIb++ = numVertex+2;
|
||||
*curIb++ = numVertex;
|
||||
*curIb++ = numVertex+2;
|
||||
*curIb++ = numVertex+3;
|
||||
curIndex += 6;
|
||||
numVertex += 4;
|
||||
}
|
||||
IndexBufferExceptionFunc();
|
||||
} catch(...) {
|
||||
IndexBufferExceptionFunc();
|
||||
}
|
||||
|
||||
}
|
||||
if (numVertex == 0) break;
|
||||
DX8Wrapper::Set_Shader(ShaderClass(SC_ALPHA));
|
||||
DX8Wrapper::Set_Index_Buffer(ib_access,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(vb_access);
|
||||
DX8Wrapper::Draw_Triangles( 0,curIndex/3, 0, numVertex); //draw a quad, 2 triangles, 4 verts
|
||||
}
|
||||
|
||||
if (anyVanished) {
|
||||
compressIconsArray();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _DEBUG or _INTERNAL
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DDisplayString.cpp /////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DDisplayString.cpp
|
||||
//
|
||||
// Created: Colin Day, July 2001
|
||||
//
|
||||
// Desc: Display string W3D implementation, display strings hold
|
||||
// double byte characters and all the data we need to render
|
||||
// those strings to the screen.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplayString.h"
|
||||
#include "GameClient/HotKey.h"
|
||||
#include "GameClient/GameFont.h"
|
||||
#include "GameClient/GlobalLanguage.h"
|
||||
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
// PRIVATE TYPES //////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE DATA ///////////////////////////////////////////////////////////////
|
||||
|
||||
// PUBLIC DATA ////////////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
|
||||
|
||||
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DDisplayString::W3DDisplayString =========================================
|
||||
/** */
|
||||
//=============================================================================
|
||||
W3DDisplayString::W3DDisplayString( void )
|
||||
{
|
||||
|
||||
m_textChanged = FALSE;
|
||||
m_textPos.x = 0;
|
||||
m_textPos.y = 0;
|
||||
m_currTextColor = 0;
|
||||
m_currDropColor = 0;
|
||||
m_size.x = 0;
|
||||
m_size.y = 0;
|
||||
m_fontChanged = FALSE;
|
||||
m_clipRegion.lo.x = 0;
|
||||
m_clipRegion.lo.y = 0;
|
||||
m_clipRegion.hi.x = 0;
|
||||
m_clipRegion.hi.y = 0;
|
||||
m_lastResourceFrame = 0;
|
||||
m_useHotKey = FALSE;
|
||||
m_hotKeyPos.x = 0;
|
||||
m_hotKeyPos.y = 0;
|
||||
m_hotKeyColor = GameMakeColor(255,255,255,255);
|
||||
|
||||
} // end W3DDisplayString
|
||||
|
||||
// W3DDisplayString::~W3DDisplayString ========================================
|
||||
/** */
|
||||
//=============================================================================
|
||||
W3DDisplayString::~W3DDisplayString( void )
|
||||
{
|
||||
|
||||
} // end ~W3DDisplayString
|
||||
|
||||
// W3DDisplayString::textChanged ==============================================
|
||||
/** This method automatically gets called from some methods in the display
|
||||
* class so that we can write our own code here to to appropriate things
|
||||
* on the changing of string data */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::notifyTextChanged( void )
|
||||
{
|
||||
|
||||
// extend functionality
|
||||
DisplayString::notifyTextChanged();
|
||||
if(TheGlobalLanguageData)
|
||||
{
|
||||
if(TheGlobalLanguageData->m_useHardWrap == TRUE)
|
||||
{
|
||||
m_textRenderer.Set_Use_Hard_Word_Wrap(true);
|
||||
m_textRendererHotKey.Set_Use_Hard_Word_Wrap(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_textRenderer.Set_Use_Hard_Word_Wrap(false);
|
||||
m_textRendererHotKey.Set_Use_Hard_Word_Wrap(false);
|
||||
}
|
||||
}
|
||||
|
||||
// get our new text extents
|
||||
computeExtents();
|
||||
|
||||
//
|
||||
// set a flag so that if it comes that we need to render this string
|
||||
// we know we must first build the sentence
|
||||
//
|
||||
m_textChanged = TRUE;
|
||||
|
||||
// reset data for our text renderer
|
||||
m_textRenderer.Reset();
|
||||
m_textRendererHotKey.Reset();
|
||||
|
||||
} // end notifyTextChanged
|
||||
|
||||
// W3DDisplayString::Draw =====================================================
|
||||
/** Draw the text at the specified location in in the specified colors
|
||||
* in the parameters. Since we keep an instance of the rendered text
|
||||
* texture around, this is the time to check to see if any of our
|
||||
* properties have changed since the last render, like color, or
|
||||
* position, or content. If they have, we need to rebuild the sentence
|
||||
* texture for rendering */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor )
|
||||
{
|
||||
draw(x,y, color, dropColor, 1, 1);
|
||||
}
|
||||
void W3DDisplayString::draw( Int x, Int y, Color color, Color dropColor, Int xDrop, Int yDrop )
|
||||
{
|
||||
Bool needNewPolys = FALSE;
|
||||
|
||||
// sanity
|
||||
if( getTextLength() == 0 )
|
||||
return; // nothing to draw
|
||||
|
||||
// if our font or text has changed we need to build a new sentence
|
||||
if( m_fontChanged || m_textChanged )
|
||||
{
|
||||
if(m_useHotKey)
|
||||
{
|
||||
m_textRenderer.Set_Hot_Key_Parse(TRUE);
|
||||
m_textRenderer.Build_Sentence( getText().str(), &m_hotKeyPos.x, &m_hotKeyPos.y );
|
||||
m_hotkey.translate(TheHotKeyManager->searchHotKey(getText()));
|
||||
if(!m_hotkey.isEmpty())
|
||||
m_textRendererHotKey.Build_Sentence(m_hotkey.str(), NULL, NULL);
|
||||
else
|
||||
{
|
||||
m_useHotKey = FALSE;
|
||||
m_textRendererHotKey.Reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_textRenderer.Build_Sentence( getText().str(), NULL, NULL );
|
||||
m_fontChanged = FALSE;
|
||||
m_textChanged = FALSE;
|
||||
needNewPolys = TRUE;
|
||||
|
||||
} // end if
|
||||
|
||||
//
|
||||
// if our position has changed, or our colors have chagned, or our
|
||||
// text data has changed, we need to redo the texture quads
|
||||
//
|
||||
if( needNewPolys ||
|
||||
x != m_textPos.x ||
|
||||
y != m_textPos.y ||
|
||||
color != m_currTextColor ||
|
||||
dropColor != m_currDropColor )
|
||||
{
|
||||
|
||||
// save the new attributes of the text position and color
|
||||
m_textPos.x = x;
|
||||
m_textPos.y = y;
|
||||
m_currTextColor = color;
|
||||
m_currDropColor = dropColor;
|
||||
|
||||
// reset the quads
|
||||
m_textRenderer.Reset_Polys();
|
||||
|
||||
// draw the shadow
|
||||
m_textRenderer.Set_Location( Vector2( m_textPos.x + xDrop, m_textPos.y + yDrop) );
|
||||
m_textRenderer.Draw_Sentence( m_currDropColor );
|
||||
|
||||
// draw the text
|
||||
m_textRenderer.Set_Location( Vector2( m_textPos.x, m_textPos.y ) );
|
||||
m_textRenderer.Draw_Sentence( m_currTextColor );
|
||||
|
||||
if(m_useHotKey)
|
||||
{
|
||||
m_textRendererHotKey.Reset_Polys();
|
||||
m_textRendererHotKey.Set_Location( Vector2( m_textPos.x + m_hotKeyPos.x , m_textPos.y +m_hotKeyPos.y) );
|
||||
m_textRendererHotKey.Draw_Sentence( m_hotKeyColor );
|
||||
m_textRendererHotKey.Render();
|
||||
}
|
||||
|
||||
} // end if
|
||||
|
||||
// render the text
|
||||
m_textRenderer.Render();
|
||||
|
||||
// we are for sure using display resources now
|
||||
if( TheGameClient )
|
||||
usingResources( TheGameClient->getFrame() );
|
||||
|
||||
} // end draw
|
||||
|
||||
// W3DDisplayString::getSize ==================================================
|
||||
/** Get the render size width and height of the string in this instance
|
||||
* with the font associated with it */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::getSize( Int *width, Int *height )
|
||||
{
|
||||
|
||||
// assign the width and height we have stored to parameters present
|
||||
if( width )
|
||||
*width = m_size.x;
|
||||
if( height )
|
||||
*height = m_size.y;
|
||||
|
||||
} // end getSize
|
||||
|
||||
// DisplayString::appendChar ==================================================
|
||||
/** Get text with up to charPos characters, -1 = all characters */
|
||||
//=============================================================================
|
||||
|
||||
Int W3DDisplayString::getWidth( Int charPos )
|
||||
{
|
||||
FontCharsClass * font;
|
||||
Int width = 0;
|
||||
Int count = 0;
|
||||
|
||||
font = m_textRenderer.Peek_Font();
|
||||
|
||||
if ( font )
|
||||
{
|
||||
const WideChar *text = m_textString.str();
|
||||
WideChar ch;
|
||||
|
||||
while ( (ch = *text++ ) != 0 && ( charPos == -1 || count < charPos ) )
|
||||
{
|
||||
if ( ch != (WideChar)'\n' )
|
||||
{
|
||||
width += font->Get_Char_Spacing( ch );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
// W3DDisplayString::setFont ==================================================
|
||||
/** Set the font for this particular display string */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::setFont( GameFont *font )
|
||||
{
|
||||
|
||||
// sanity
|
||||
if( font == NULL )
|
||||
return;
|
||||
|
||||
// if the new font is the same as our existing font do nothing
|
||||
if( m_font == font )
|
||||
return;
|
||||
|
||||
// extending functionality
|
||||
DisplayString::setFont( font );
|
||||
|
||||
// set the font in our renderer
|
||||
m_textRenderer.Set_Font( static_cast<FontCharsClass *>(m_font->fontData) );
|
||||
|
||||
m_textRendererHotKey.Set_Font( static_cast<FontCharsClass *>(TheFontLibrary->getFont(font->nameString,font->pointSize, TRUE)->fontData) );
|
||||
// recompute extents for text with new font
|
||||
computeExtents();
|
||||
|
||||
// set flag telling us the font has changed since last render
|
||||
m_fontChanged = TRUE;
|
||||
|
||||
} // end setFont
|
||||
|
||||
// W3DDisplayString::setClipRegion ============================================
|
||||
/** Set the clipping region for the text */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::setClipRegion( IRegion2D *region )
|
||||
{
|
||||
|
||||
// extend functionality
|
||||
DisplayString::setClipRegion( region );
|
||||
|
||||
// only consider regions that are actual changes
|
||||
if( region->lo.x != m_clipRegion.lo.x ||
|
||||
region->lo.y != m_clipRegion.lo.y ||
|
||||
region->hi.x != m_clipRegion.hi.x ||
|
||||
region->hi.y != m_clipRegion.hi.y )
|
||||
{
|
||||
|
||||
// assign new region
|
||||
m_clipRegion = *region;
|
||||
|
||||
// set new region in renderer
|
||||
m_textRenderer.Set_Clipping_Rect( RectClass( m_clipRegion.lo.x,
|
||||
m_clipRegion.lo.y,
|
||||
m_clipRegion.hi.x,
|
||||
m_clipRegion.hi.y ) );
|
||||
m_textRendererHotKey.Set_Clipping_Rect( RectClass( m_clipRegion.lo.x,
|
||||
m_clipRegion.lo.y,
|
||||
m_clipRegion.hi.x,
|
||||
m_clipRegion.hi.y ) );
|
||||
} // end if
|
||||
|
||||
} // end setClipRegion
|
||||
|
||||
// W3DDisplayString::computeExtents ===========================================
|
||||
/** Update the width and height of our string */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::computeExtents( void )
|
||||
{
|
||||
UnsignedInt len = getTextLength();
|
||||
|
||||
// if we have no string, or no font we don't have a size yet
|
||||
if( len == 0 || m_font == NULL )
|
||||
{
|
||||
|
||||
m_size.x = 0;
|
||||
m_size.y = 0;
|
||||
|
||||
} // end if
|
||||
else
|
||||
{
|
||||
|
||||
Vector2 extents = m_textRenderer.Get_Formatted_Text_Extents(getText().str()); //Get_Text_Extents( getText().str() );
|
||||
m_size.x = extents.X;
|
||||
m_size.y = extents.Y;
|
||||
|
||||
} // end else
|
||||
|
||||
} // end computeExtents
|
||||
|
||||
// W3DDisplayString::setWordWrap ===========================================
|
||||
/** Set the wordwrap of the m_textRenderer */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::setWordWrap( Int wordWrap )
|
||||
{
|
||||
// set the Word Wrap
|
||||
if(m_textRenderer.Set_Wrapping_Width(wordWrap))
|
||||
notifyTextChanged();
|
||||
}// void setWordWrap( Int wordWrap )
|
||||
|
||||
void W3DDisplayString::setUseHotkey( Bool useHotkey, Color hotKeyColor )
|
||||
{
|
||||
m_useHotKey = useHotkey;
|
||||
m_hotKeyColor = hotKeyColor;
|
||||
m_textRenderer.Set_Hot_Key_Parse(useHotkey);
|
||||
notifyTextChanged();
|
||||
}
|
||||
|
||||
// W3DDisplayString::setWordWrapCentered ======================================
|
||||
/** Set the whether or not we want to center each new line in a text string */
|
||||
//=============================================================================
|
||||
void W3DDisplayString::setWordWrapCentered( Bool isCentered )
|
||||
{
|
||||
// set the Word Wrap
|
||||
if( m_textRenderer.Set_Word_Wrap_Centered(isCentered) )
|
||||
notifyTextChanged();
|
||||
}// void setWordWrap( Int wordWrap )
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DDisplayStringManager.cpp //////////////////////////////////////////////////////////////
|
||||
// Created: Colin Day, July 2001
|
||||
// Desc: Display string Manager for W3D
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/Debug.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameClient/GameText.h"
|
||||
#include "GameClient/DisplayString.h"
|
||||
#include "GameClient/DrawGroupInfo.h"
|
||||
#include "GameClient/GlobalLanguage.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplayStringManager.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDisplayStringManager::W3DDisplayStringManager( void )
|
||||
{
|
||||
for (Int i = 0; i < MAX_GROUPS; ++i)
|
||||
{
|
||||
m_groupNumeralStrings[i] = NULL;
|
||||
}
|
||||
|
||||
m_formationLetterDisplayString = NULL;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DDisplayStringManager::~W3DDisplayStringManager( void )
|
||||
{
|
||||
for (Int i = 0; i < MAX_GROUPS; ++i)
|
||||
{
|
||||
if (m_groupNumeralStrings[i])
|
||||
freeDisplayString(m_groupNumeralStrings[i]);
|
||||
m_groupNumeralStrings[i] = NULL;
|
||||
}
|
||||
|
||||
if (m_formationLetterDisplayString)
|
||||
freeDisplayString( m_formationLetterDisplayString );
|
||||
m_formationLetterDisplayString = NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDisplayStringManager::postProcessLoad( void )
|
||||
{
|
||||
// Get the font.
|
||||
GameFont *font = TheFontLibrary->getFont(
|
||||
TheDrawGroupInfo->m_fontName,
|
||||
TheDrawGroupInfo->m_fontSize,
|
||||
TheDrawGroupInfo->m_fontIsBold );
|
||||
|
||||
for (Int i = 0; i < MAX_GROUPS; ++i)
|
||||
{
|
||||
m_groupNumeralStrings[i] = newDisplayString();
|
||||
m_groupNumeralStrings[i]->setFont(font);
|
||||
|
||||
#ifdef KRIS_BRUTAL_HACK_FOR_AIRCRAFT_CARRIER_DEBUGGING
|
||||
UnicodeString displayNumber;
|
||||
displayNumber.format( L"%d", i);
|
||||
m_groupNumeralStrings[i]->setText( displayNumber );
|
||||
#else
|
||||
AsciiString displayNumber;
|
||||
displayNumber.format("NUMBER:%d", i);
|
||||
m_groupNumeralStrings[i]->setText(TheGameText->fetch(displayNumber));
|
||||
#endif
|
||||
}
|
||||
|
||||
m_formationLetterDisplayString = newDisplayString();
|
||||
m_formationLetterDisplayString->setFont(font);
|
||||
AsciiString displayLetter;
|
||||
displayLetter.format("LABEL:FORMATION");
|
||||
m_formationLetterDisplayString->setText(TheGameText->fetch(displayLetter));
|
||||
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Allocate a new display string and tie it to the master list so we
|
||||
* can keep track of it */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
DisplayString *W3DDisplayStringManager::newDisplayString( void )
|
||||
{
|
||||
DisplayString *newString = newInstance(W3DDisplayString);
|
||||
|
||||
// sanity
|
||||
if( newString == NULL )
|
||||
{
|
||||
|
||||
DEBUG_LOG(( "newDisplayString: Could not allcoate new W3D display string\n" ));
|
||||
assert( 0 );
|
||||
return NULL;
|
||||
|
||||
} // end if
|
||||
|
||||
// assign a default font
|
||||
if (TheGlobalLanguageData && TheGlobalLanguageData->m_defaultDisplayStringFont.name.isNotEmpty())
|
||||
{
|
||||
newString->setFont(TheFontLibrary->getFont(
|
||||
TheGlobalLanguageData->m_defaultDisplayStringFont.name,
|
||||
TheGlobalLanguageData->m_defaultDisplayStringFont.size,
|
||||
TheGlobalLanguageData->m_defaultDisplayStringFont.bold) );
|
||||
}
|
||||
else
|
||||
newString->setFont( TheFontLibrary->getFont( AsciiString("Times New Roman"), 12, FALSE ) );
|
||||
|
||||
// link string to list
|
||||
link( newString );
|
||||
|
||||
// return our new string
|
||||
return newString;
|
||||
|
||||
} // end newDisplayString
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Remove a display string from the master list and delete the data */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDisplayStringManager::freeDisplayString( DisplayString *string )
|
||||
{
|
||||
|
||||
// sanity
|
||||
if( string == NULL )
|
||||
return;
|
||||
|
||||
// unlink
|
||||
unLink( string );
|
||||
|
||||
// if the string happens to fall where our current checkpoint was, set the checkpoint to null
|
||||
if ( m_currentCheckpoint == string) {
|
||||
m_currentCheckpoint = NULL;
|
||||
}
|
||||
|
||||
// free data
|
||||
string->deleteInstance();
|
||||
|
||||
} // end freeDisplayString
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Update method for our display string Manager ... if it's been too
|
||||
* long since the last time a string has been rendered, we will free
|
||||
* the rendering resources of the string, if it needs to render again
|
||||
* the DisplayString will have to rebuild the rendering data before
|
||||
* the draw will work */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DDisplayStringManager::update( void )
|
||||
{
|
||||
// call base in case we add something later
|
||||
DisplayStringManager::update();
|
||||
|
||||
W3DDisplayString *string = static_cast<W3DDisplayString *>(m_stringList);
|
||||
|
||||
// if the m_currentCheckpoint is valid, use it for the starting point for the search
|
||||
if (m_currentCheckpoint) {
|
||||
string = static_cast<W3DDisplayString *>(m_currentCheckpoint);
|
||||
}
|
||||
|
||||
UnsignedInt currFrame = TheGameClient->getFrame();
|
||||
const UnsignedInt w3dCleanupTime = 60; /** any string not rendered after
|
||||
this many frames will have its
|
||||
render resources freed */
|
||||
|
||||
int numStrings = 10;
|
||||
// looping through all the strings eats up a lot of ambient time. Instead,
|
||||
// loop through 10 (arbitrarily chosen) or till the end is hit.
|
||||
while ( numStrings-- && string)
|
||||
{
|
||||
|
||||
//
|
||||
// has this string "expired" in terms of using resources, a string
|
||||
// with a resource frame of zero isn't using any resources at all
|
||||
//
|
||||
if( string->m_lastResourceFrame != 0 &&
|
||||
currFrame - string->m_lastResourceFrame > w3dCleanupTime )
|
||||
{
|
||||
|
||||
// free the resources
|
||||
string->m_textRenderer.Reset();
|
||||
string->m_textRendererHotKey.Reset();
|
||||
//
|
||||
// mark data in the string as changed so that if it needs to
|
||||
// be drawn again it will know to reconstruct the render data
|
||||
//
|
||||
string->m_textChanged = TRUE;
|
||||
|
||||
//
|
||||
// set the last resource frame to zero, this allows us to ignore it
|
||||
// in future cleanup passes of this update routine
|
||||
//
|
||||
string->m_lastResourceFrame = 0;
|
||||
|
||||
} // end if
|
||||
|
||||
// move to next string
|
||||
string = static_cast<W3DDisplayString *>(string->next());
|
||||
|
||||
} // end while
|
||||
|
||||
// reset the starting point for our next search
|
||||
m_currentCheckpoint = string;
|
||||
} // end update
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
DisplayString *W3DDisplayStringManager::getGroupNumeralString( Int numeral )
|
||||
{
|
||||
if (numeral < 0 || numeral > MAX_GROUPS - 1 )
|
||||
{
|
||||
DEBUG_CRASH(("Numeral '%d' out of range.\n", numeral));
|
||||
return m_groupNumeralStrings[0];
|
||||
}
|
||||
|
||||
return m_groupNumeralStrings[numeral];
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DDynamicLight.cpp
|
||||
// Class to handle dynamic lights.
|
||||
// Author: John Ahlquist, April 2001
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "W3DDevice/GameClient/W3DDynamicLight.h"
|
||||
|
||||
W3DDynamicLight::W3DDynamicLight(void):
|
||||
LightClass(LightClass::POINT)
|
||||
{
|
||||
|
||||
m_priorEnable = false;
|
||||
m_enabled = true;
|
||||
|
||||
}
|
||||
|
||||
W3DDynamicLight::~W3DDynamicLight(void)
|
||||
{
|
||||
}
|
||||
|
||||
void W3DDynamicLight::On_Frame_Update(void)
|
||||
{
|
||||
if (!m_enabled) {
|
||||
return;
|
||||
}
|
||||
Real factor = 1.0f;
|
||||
if (m_curIncreaseFrameCount>0 && m_increaseFrameCount>0) {
|
||||
// increasing
|
||||
m_curIncreaseFrameCount--;
|
||||
factor = (m_increaseFrameCount-m_curIncreaseFrameCount)/(Real)m_increaseFrameCount;
|
||||
|
||||
} else if (m_decayFrameCount==0) {
|
||||
factor = 1.0; // never decays,
|
||||
} else {
|
||||
m_curDecayFrameCount--;
|
||||
if (m_curDecayFrameCount == 0) {
|
||||
m_enabled = false;
|
||||
return;
|
||||
}
|
||||
factor = m_curDecayFrameCount/(Real)m_decayFrameCount;
|
||||
}
|
||||
if (m_decayRange) {
|
||||
this->FarAttenEnd = factor*m_targetRange;
|
||||
if (FarAttenEnd < FarAttenStart) {
|
||||
FarAttenEnd = FarAttenStart;
|
||||
}
|
||||
}
|
||||
if (m_decayColor) {
|
||||
this->Ambient = m_targetAmbient*factor;
|
||||
this->Diffuse = m_targetDiffuse*factor;
|
||||
}
|
||||
}
|
||||
|
||||
void W3DDynamicLight::setFrameFade(UnsignedInt frameIncreaseTime, UnsignedInt decayFrameTime)
|
||||
{
|
||||
m_decayFrameCount = decayFrameTime;
|
||||
m_curDecayFrameCount = decayFrameTime;
|
||||
m_curIncreaseFrameCount = frameIncreaseTime;
|
||||
m_increaseFrameCount = frameIncreaseTime;
|
||||
m_targetAmbient = Ambient;
|
||||
m_targetDiffuse = Diffuse;
|
||||
m_targetRange = FarAttenEnd;
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DFileSystem.cpp ////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// W3D implementation of a file factory. This replaces the W3D file factory,
|
||||
// and uses GDI assets, so that
|
||||
// W3D files and targa files are loaded using the GDI file interface.
|
||||
// Note - this only servers up read only files.
|
||||
//
|
||||
// Author: John Ahlquist, Sept 2001
|
||||
// Colin Day, November 2001
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// for now we maintain old legacy files
|
||||
// #define MAINTAIN_LEGACY_FILES
|
||||
|
||||
#include "Common/Debug.h"
|
||||
#include "Common/File.h"
|
||||
#include "Common/FileSystem.h"
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/MapObject.h"
|
||||
#include "Common/Registry.h"
|
||||
#include "W3DDevice/GameClient/W3DFileSystem.h"
|
||||
// DEFINES ////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <io.h>
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Game file access. At present this allows us to access test assets, assets from
|
||||
* legacy GDI assets, and the current flat directory access for textures, models etc */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
typedef enum
|
||||
{
|
||||
FILE_TYPE_COMPLETELY_UNKNOWN = 0, // MBL 08.15.2002 - compile error with FILE_TYPE_UNKNOWN, is constant
|
||||
FILE_TYPE_W3D,
|
||||
FILE_TYPE_TGA,
|
||||
FILE_TYPE_DDS,
|
||||
} GameFileType;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
GameFileClass::GameFileClass( char const *filename )
|
||||
{
|
||||
|
||||
m_fileExists = FALSE;
|
||||
m_theFile = NULL;
|
||||
m_filePath[ 0 ] = 0;
|
||||
m_filename[0] = 0;
|
||||
|
||||
if( filename )
|
||||
Set_Name( filename );
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
GameFileClass::GameFileClass( void )
|
||||
{
|
||||
|
||||
m_fileExists = FALSE;
|
||||
m_theFile = NULL;
|
||||
m_filePath[ 0 ] = 0;
|
||||
m_filename[ 0 ] = 0;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
GameFileClass::~GameFileClass()
|
||||
{
|
||||
|
||||
Close();
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Gets the file name */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
char const * GameFileClass::File_Name( void ) const
|
||||
{
|
||||
|
||||
return m_filename;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
inline static Bool isImageFileType( GameFileType fileType )
|
||||
{
|
||||
return (fileType == FILE_TYPE_TGA || fileType == FILE_TYPE_DDS);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
Sets the file name, and finds the GDI asset if present.
|
||||
|
||||
|
||||
Well, that is the worst comment ever for the most important function there is.
|
||||
Everything comes through this. This builds the directory and tests for the file
|
||||
in several different places.
|
||||
|
||||
First we look in Language subfolders so that our Perforce build can handle files that have
|
||||
been localized but were in Generals.
|
||||
|
||||
Then we do the normal TheFileSystem lookup. In there it does LocalFile (Art/Textures) then it does
|
||||
big files (which internally are also Art/Textures).
|
||||
|
||||
Finally we try UserData.
|
||||
*/
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
char const * GameFileClass::Set_Name( char const *filename )
|
||||
{
|
||||
|
||||
if( Is_Open() )
|
||||
Close();
|
||||
|
||||
// save the filename
|
||||
strncpy( m_filename, filename, _MAX_PATH );
|
||||
|
||||
char name[_MAX_PATH];
|
||||
const Int EXT_LEN = 32;
|
||||
char extension[EXT_LEN];
|
||||
extension[0] = 0;
|
||||
strcpy(name, filename);
|
||||
Int i = strlen(name);
|
||||
i--;
|
||||
Int extLen = 1;
|
||||
while(i>0 && extLen < EXT_LEN) {
|
||||
if (name[i] == '.') {
|
||||
strcpy(extension, name+i);
|
||||
name[i] = 0;
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
extLen++;
|
||||
}
|
||||
Int j = 0;
|
||||
// Strip out spaces.
|
||||
for (i=0; name[i]; i++) {
|
||||
if (name[i] != ' ') {
|
||||
name[j] = name[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
name[j] = 0;
|
||||
|
||||
// test the extension to recognize a few key file types
|
||||
GameFileType fileType = FILE_TYPE_COMPLETELY_UNKNOWN; // MBL FILE_TYPE_UNKNOWN change due to compile error
|
||||
if( stricmp( extension, ".w3d" ) == 0 )
|
||||
fileType = FILE_TYPE_W3D;
|
||||
else if( stricmp( extension, ".tga" ) == 0 )
|
||||
fileType = FILE_TYPE_TGA;
|
||||
else if( stricmp( extension, ".dds" ) == 0 )
|
||||
fileType = FILE_TYPE_DDS;
|
||||
|
||||
|
||||
|
||||
// We need to be able to grab w3d's from a localization dir, since Germany hates exploding people units.
|
||||
if( fileType == FILE_TYPE_W3D )
|
||||
{
|
||||
static const char *localizedPathFormat = "Data/%s/Art/W3D/";
|
||||
sprintf(m_filePath,localizedPathFormat, GetRegistryLanguage().str());
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end if
|
||||
|
||||
// We need to be able to grab images from a localization dir, because Art has a fetish for baked-in text. Munkee.
|
||||
if( isImageFileType(fileType) )
|
||||
{
|
||||
static const char *localizedPathFormat = "Data/%s/Art/Textures/";
|
||||
sprintf(m_filePath,localizedPathFormat, GetRegistryLanguage().str());
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end else if
|
||||
|
||||
// see if the file exists
|
||||
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
|
||||
|
||||
|
||||
|
||||
// Now try the main lookup of hitting local files and big files
|
||||
if( m_fileExists == FALSE )
|
||||
{
|
||||
// all .w3d files are in W3D_DIR_PATH, all .tga files are in TGA_DIR_PATH
|
||||
if( fileType == FILE_TYPE_W3D )
|
||||
{
|
||||
|
||||
strcpy( m_filePath, W3D_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end if
|
||||
else if( isImageFileType(fileType) )
|
||||
{
|
||||
|
||||
strcpy( m_filePath, TGA_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end else if
|
||||
else
|
||||
strcpy( m_filePath, filename );
|
||||
|
||||
// see if the file exists
|
||||
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// maintain legacy compatibility directories for now
|
||||
#ifdef MAINTAIN_LEGACY_FILES
|
||||
if( m_fileExists == FALSE )
|
||||
{
|
||||
|
||||
if( fileType == FILE_TYPE_W3D )
|
||||
{
|
||||
|
||||
strcpy( m_filePath, LEGACY_W3D_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end if
|
||||
else if( isImageFileType(fileType) )
|
||||
{
|
||||
|
||||
strcpy( m_filePath, LEGACY_TGA_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end else if
|
||||
|
||||
// see if the file exists
|
||||
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
|
||||
|
||||
} // end if
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// if file is still not found, try the test art folders
|
||||
#ifdef LOAD_TEST_ASSETS
|
||||
if( m_fileExists == FALSE )
|
||||
{
|
||||
|
||||
if( fileType == FILE_TYPE_W3D )
|
||||
{
|
||||
|
||||
strcpy( m_filePath, TEST_W3D_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end if
|
||||
else if( isImageFileType(fileType) )
|
||||
{
|
||||
|
||||
strcpy( m_filePath, TEST_TGA_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end else if
|
||||
|
||||
// see if the file exists
|
||||
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
|
||||
|
||||
} // end if
|
||||
#endif
|
||||
|
||||
// We allow the user to load their own images for various assets (like the control bar)
|
||||
if( m_fileExists == FALSE && TheGlobalData)
|
||||
{
|
||||
if( fileType == FILE_TYPE_W3D )
|
||||
{
|
||||
sprintf(m_filePath,USER_W3D_DIR_PATH, TheGlobalData->getPath_UserData().str());
|
||||
//strcpy( m_filePath, USER_W3D_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end if
|
||||
if( isImageFileType(fileType) )
|
||||
{
|
||||
sprintf(m_filePath,USER_TGA_DIR_PATH, TheGlobalData->getPath_UserData().str());
|
||||
//strcpy( m_filePath, USER_TGA_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end else if
|
||||
|
||||
// see if the file exists
|
||||
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
|
||||
|
||||
} // end if
|
||||
|
||||
|
||||
// We Need to be able to "temporarily copy over the map preview for whichever directory it came from
|
||||
if( m_fileExists == FALSE && TheGlobalData)
|
||||
{
|
||||
if( fileType == FILE_TYPE_TGA ) // just TGA, since we don't dds previews
|
||||
{
|
||||
sprintf(m_filePath,MAP_PREVIEW_DIR_PATH, TheGlobalData->getPath_UserData().str());
|
||||
//strcpy( m_filePath, USER_TGA_DIR_PATH );
|
||||
strcat( m_filePath, filename );
|
||||
|
||||
} // end else if
|
||||
|
||||
// see if the file exists
|
||||
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
|
||||
|
||||
} // end if
|
||||
|
||||
return m_filename;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** If we found a gdi asset, the file is available. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
bool GameFileClass::Is_Available( int forced )
|
||||
{
|
||||
|
||||
// not maintaining any GDF compatibility, all files should be where the m_filePath says
|
||||
return m_fileExists;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Is the file open. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
bool GameFileClass::Is_Open(void) const
|
||||
{
|
||||
return m_theFile != NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Open the named file. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int GameFileClass::Open(char const *filename, int rights)
|
||||
{
|
||||
Set_Name(filename);
|
||||
if (Is_Available(false)) {
|
||||
return(Open(rights));
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Open the file using the current file name. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int GameFileClass::Open(int rights)
|
||||
{
|
||||
if( rights != READ )
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
// just open up the file in m_filePath
|
||||
m_theFile = TheFileSystem->openFile( m_filePath, File::READ | File::BINARY );
|
||||
|
||||
return (m_theFile != NULL);
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Read. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int GameFileClass::Read(void *buffer, int len)
|
||||
{
|
||||
if (m_theFile) {
|
||||
return m_theFile->read(buffer, len);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Seek. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int GameFileClass::Seek(int pos, int dir)
|
||||
{
|
||||
File::seekMode mode = File::CURRENT;
|
||||
switch (dir) {
|
||||
default:
|
||||
case SEEK_CUR: mode = File::CURRENT; break;
|
||||
case SEEK_SET: mode = File::START; break;
|
||||
case SEEK_END: mode = File::END; break;
|
||||
}
|
||||
if (m_theFile) {
|
||||
return m_theFile->seek(pos, mode);
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Size. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int GameFileClass::Size(void)
|
||||
{
|
||||
if (m_theFile) {
|
||||
return m_theFile->size();
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Write. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
int GameFileClass::Write(void const *buffer, Int len)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Close. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void GameFileClass::Close(void)
|
||||
{
|
||||
if (m_theFile) {
|
||||
m_theFile->close();
|
||||
m_theFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// W3DFileSystem Class ////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
extern W3DFileSystem *TheW3DFileSystem = NULL;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Constructor. Creating an instance of this class overrices the default
|
||||
W3D file factory. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DFileSystem::W3DFileSystem(void)
|
||||
{
|
||||
_TheFileFactory = this; // override the w3d file factory.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Destructor. This removes the W3D file factory, so shouldn't be done until
|
||||
after W3D is shutdown. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DFileSystem::~W3DFileSystem(void)
|
||||
{
|
||||
_TheFileFactory = NULL; // remove the w3d file factory.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Gets a file with the specified filename. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
FileClass * W3DFileSystem::Get_File( char const *filename )
|
||||
{
|
||||
return NEW GameFileClass( filename ); // poolify
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Releases a file returned by Get_File. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DFileSystem::Return_File( FileClass *file )
|
||||
{
|
||||
delete file;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DGameClient.cpp /////////////////////////////////////////////////
|
||||
//
|
||||
// W3DImplementaion of the GameClient. If there were a client/server
|
||||
// architecture, this game interface could be thought of as the "client"
|
||||
// that the user uses to interact with the logic of the game world which
|
||||
// would be known as the "server"
|
||||
//
|
||||
// Author: Colin Day, April 2001
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
|
||||
// USER INCLUDES //////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/ThingFactory.h"
|
||||
#include "Common/ModuleFactory.h"
|
||||
#include "Common/RandomValue.h"
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/GameLOD.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameClient/ParticleSys.h"
|
||||
#include "GameClient/RayEffect.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
#include "W3DDevice/GameClient/W3DGameClient.h"
|
||||
#include "W3DDevice/GameClient/W3DStatusCircle.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "W3DDevice/GameClient/W3DShadow.h"
|
||||
#include "W3DDevice/GameClient/heightmap.h"
|
||||
#include "WW3D2/Part_emt.h"
|
||||
#include "WW3D2/HAnim.h"
|
||||
#include "WW3D2/HTree.h"
|
||||
#include "WW3D2/AnimObj.h" ///< @todo superhack for demo, remove!
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DGameClient::W3DGameClient()
|
||||
{
|
||||
|
||||
} // end W3DGameClient
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DGameClient::~W3DGameClient()
|
||||
{
|
||||
|
||||
} // end ~W3DGameClient
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Initialize resources for the w3d game client */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::init( void )
|
||||
{
|
||||
|
||||
// extending initialization routine
|
||||
GameClient::init();
|
||||
|
||||
} // end init
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Per frame udpate, note we are extending functionality */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::update( void )
|
||||
{
|
||||
|
||||
// call base
|
||||
GameClient::update();
|
||||
|
||||
} // end update
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Reset this device client system. Note we are extending reset functionality from
|
||||
* the device independent client */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::reset( void )
|
||||
{
|
||||
|
||||
// call base class
|
||||
GameClient::reset();
|
||||
|
||||
} // end reset
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** allocate a new drawable using the thing template for initialization.
|
||||
* if we want to have the thing manager actually contain the pools of
|
||||
* object and drawable storage it seems OK to have it be friends with the
|
||||
* GameLogic/Client for those purposes, or we could put the allocation pools
|
||||
* in the GameLogic and GameClient themselves */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
Drawable *W3DGameClient::friend_createDrawable( const ThingTemplate *tmplate,
|
||||
DrawableStatus statusBits )
|
||||
{
|
||||
Drawable *draw = NULL;
|
||||
|
||||
// sanity
|
||||
if( tmplate == NULL )
|
||||
return NULL;
|
||||
|
||||
draw = newInstance(Drawable)( tmplate, statusBits );
|
||||
|
||||
return draw;
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::addScorch(const Coord3D *pos, Real radius, Scorches type)
|
||||
{
|
||||
if (TheTerrainRenderObject)
|
||||
{
|
||||
Vector3 loc(pos->x, pos->y, pos->z);
|
||||
TheTerrainRenderObject->addScorch(loc, radius, type);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** create an effect that requires a start and end location */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::createRayEffectByTemplate( const Coord3D *start,
|
||||
const Coord3D *end,
|
||||
const ThingTemplate* tmpl )
|
||||
{
|
||||
Drawable *draw = TheThingFactory->newDrawable(tmpl);
|
||||
|
||||
if( draw )
|
||||
{
|
||||
Coord3D pos;
|
||||
|
||||
// add to world, the location of the drawable is at the midpoint of laser
|
||||
pos.x = (end->x - start->x) * 0.5f + start->x;
|
||||
pos.y = (end->y - start->y) * 0.5f + start->y;
|
||||
pos.z = (end->z - start->z) * 0.5f + start->z;
|
||||
draw->setPosition( &pos );
|
||||
|
||||
// add this ray effect to the list of ray effects
|
||||
TheRayEffects->addRayEffect( draw, start, end );
|
||||
|
||||
} // end if
|
||||
|
||||
} // end createRayEffectByTemplate
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Tell all the drawables what time of day it is now */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::setTimeOfDay( TimeOfDay tod )
|
||||
{
|
||||
|
||||
GameClient::setTimeOfDay(tod);
|
||||
|
||||
//tell cloud/water plane to update its lighting/texture
|
||||
if (TheWaterRenderObj)
|
||||
TheWaterRenderObj->setTimeOfDay(tod);
|
||||
if (TheW3DShadowManager)
|
||||
TheW3DShadowManager->setTimeOfDay(tod);
|
||||
|
||||
//tell the display to update its lighting
|
||||
TheDisplay->setTimeOfDay( tod );
|
||||
|
||||
} // end setTimeOfDay
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::setTeamColor(Int red, Int green, Int blue)
|
||||
{
|
||||
|
||||
W3DStatusCircle::setColor(red, green, blue);
|
||||
|
||||
} // end setTeamColor
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** temporary entry point for adjusting LOD for development testing. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::adjustLOD( Int adj )
|
||||
{
|
||||
if (TheGlobalData == NULL)
|
||||
return;
|
||||
|
||||
TheWritableGlobalData->m_textureReductionFactor += adj;
|
||||
|
||||
if (TheWritableGlobalData->m_textureReductionFactor > 4)
|
||||
TheWritableGlobalData->m_textureReductionFactor = 4; //16x less resolution is probably enough.
|
||||
if (TheWritableGlobalData->m_textureReductionFactor < 0)
|
||||
TheWritableGlobalData->m_textureReductionFactor = 0;
|
||||
|
||||
if (WW3D::Get_Texture_Reduction() != TheWritableGlobalData->m_textureReductionFactor)
|
||||
{ WW3D::Set_Texture_Reduction(TheWritableGlobalData->m_textureReductionFactor,32);
|
||||
TheGameLODManager->setCurrentTextureReduction(TheWritableGlobalData->m_textureReductionFactor);
|
||||
if( TheTerrainRenderObject )
|
||||
TheTerrainRenderObject->setTextureLOD( TheWritableGlobalData->m_textureReductionFactor );
|
||||
}
|
||||
|
||||
} // end adjustLOD
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Tell the terrain that an object moved, so it can knock down trees or crush grass
|
||||
or whatever is appropriate. jba. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DGameClient::notifyTerrainObjectMoved(Object *obj)
|
||||
{
|
||||
if (TheTerrainRenderObject) {
|
||||
TheTerrainRenderObject->unitMoved(obj);
|
||||
}
|
||||
|
||||
} // end setTimeOfDay
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,736 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DInGameUI.cpp //////////////////////////////////////////////////////////////////////////
|
||||
// Author: Colin Day, April 2001
|
||||
// Desct: In game user interface implementation for W3D
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
#include "Common/ThingFactory.h"
|
||||
#include "GameLogic/TerrainLogic.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/GadgetListBox.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameClient/GameWindowManager.h"
|
||||
#include "GameClient/GadgetSlider.h"
|
||||
#include "GameClient/ControlBar.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
#include "W3DDevice/GameClient/W3DGUICallbacks.h"
|
||||
#include "W3DDevice/GameClient/W3DInGameUI.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "W3DDevice/Common/W3DConvert.h"
|
||||
#include "WW3D2/WW3D.h"
|
||||
#include "WW3D2/HAnim.h"
|
||||
|
||||
#include "Common/UnitTimings.h" //Contains the DO_UNIT_TIMINGS define jba.
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "W3DDevice/GameClient/HeightMap.h"
|
||||
#include "WW3D2/DX8IndexBuffer.h"
|
||||
#include "WW3D2/DX8VertexBuffer.h"
|
||||
#include "WW3D2/VertMaterial.h"
|
||||
class DebugHintObject : public RenderObjClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
DebugHintObject(void);
|
||||
DebugHintObject(const DebugHintObject & src);
|
||||
DebugHintObject & operator = (const DebugHintObject &);
|
||||
~DebugHintObject(void);
|
||||
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const;
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual Bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & aabox) const;
|
||||
|
||||
int updateBlock(void);
|
||||
void freeMapResources(void);
|
||||
void setLocAndColorAndSize(const Coord3D *loc, Int argb, Int size);
|
||||
|
||||
protected:
|
||||
|
||||
Coord3D m_myLoc;
|
||||
Int m_myColor; // argb
|
||||
Int m_mySize;
|
||||
|
||||
DX8IndexBufferClass *m_indexBuffer;
|
||||
ShaderClass m_shaderClass; //shader or rendering state for heightmap
|
||||
VertexMaterialClass *m_vertexMaterialClass;
|
||||
DX8VertexBufferClass *m_vertexBufferTile; //First vertex buffer.
|
||||
|
||||
void initData(void);
|
||||
};
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_ALPHA ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
|
||||
DebugHintObject::~DebugHintObject(void)
|
||||
{
|
||||
freeMapResources();
|
||||
}
|
||||
|
||||
DebugHintObject::DebugHintObject(void) :
|
||||
m_indexBuffer(NULL),
|
||||
m_vertexMaterialClass(NULL),
|
||||
m_vertexBufferTile(NULL),
|
||||
m_myColor(0),
|
||||
m_mySize(0)
|
||||
{
|
||||
initData();
|
||||
}
|
||||
|
||||
Bool DebugHintObject::Cast_Ray(RayCollisionTestClass & raytest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugHintObject::DebugHintObject(const DebugHintObject & src)
|
||||
{
|
||||
*this = src;
|
||||
}
|
||||
|
||||
DebugHintObject & DebugHintObject::operator = (const DebugHintObject & that)
|
||||
{
|
||||
DEBUG_CRASH(("oops"));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DebugHintObject::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
||||
{
|
||||
Vector3 ObjSpaceCenter((float)1000*0.5f,(float)1000*0.5f,(float)0);
|
||||
float length = ObjSpaceCenter.Length();
|
||||
sphere.Init(ObjSpaceCenter, length);
|
||||
}
|
||||
|
||||
void DebugHintObject::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
||||
{
|
||||
Vector3 minPt(0,0,0);
|
||||
Vector3 maxPt((float)1000,(float)1000,(float)1000);
|
||||
box.Init(minPt,maxPt);
|
||||
}
|
||||
|
||||
Int DebugHintObject::Class_ID(void) const
|
||||
{
|
||||
return RenderObjClass::CLASSID_UNKNOWN;
|
||||
}
|
||||
|
||||
RenderObjClass * DebugHintObject::Clone(void) const
|
||||
{
|
||||
DEBUG_CRASH(("oops"));
|
||||
return NEW DebugHintObject(*this);
|
||||
}
|
||||
|
||||
|
||||
void DebugHintObject::freeMapResources(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
REF_PTR_RELEASE(m_vertexBufferTile);
|
||||
REF_PTR_RELEASE(m_vertexMaterialClass);
|
||||
}
|
||||
|
||||
//Allocate a heightmap of x by y vertices.
|
||||
//data must be an array matching this size.
|
||||
void DebugHintObject::initData(void)
|
||||
{
|
||||
freeMapResources(); //free old data and ib/vb
|
||||
|
||||
m_indexBuffer = NEW_REF(DX8IndexBufferClass,(3));
|
||||
|
||||
// Fill up the IB
|
||||
{
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer);
|
||||
UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
|
||||
ib[0]=0;
|
||||
ib[1]=1;
|
||||
ib[2]=2;
|
||||
}
|
||||
|
||||
m_vertexBufferTile = NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,3,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
|
||||
//go with a preset material for now.
|
||||
m_vertexMaterialClass = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
|
||||
//use a multi-texture shader: (text1*diffuse)*text2.
|
||||
m_shaderClass = ShaderClass::ShaderClass(SC_ALPHA);
|
||||
}
|
||||
|
||||
void DebugHintObject::setLocAndColorAndSize(const Coord3D *loc, Int argb, Int size)
|
||||
{
|
||||
m_myLoc = *loc;
|
||||
m_myColor = argb;
|
||||
m_mySize = size;
|
||||
|
||||
if (m_myLoc.z < 0 && TheTerrainRenderObject)
|
||||
{
|
||||
m_myLoc.z = TheTerrainRenderObject->getHeightMapHeight(m_myLoc.x, m_myLoc.y, NULL);
|
||||
}
|
||||
|
||||
if (m_vertexBufferTile)
|
||||
{
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexBufferTile);
|
||||
VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
|
||||
|
||||
Real x1 = m_mySize * 0.866; // cos(30)
|
||||
Real y1 = m_mySize * 0.5; // sin(30)
|
||||
|
||||
// note, pts must go in a counterclockwise order!
|
||||
vb[0].x = 0;
|
||||
vb[0].y = m_mySize;
|
||||
vb[0].z = 0;
|
||||
vb[0].diffuse = m_myColor;
|
||||
vb[0].u1 = 0;
|
||||
vb[0].v1 = 0;
|
||||
|
||||
vb[1].x = -x1;
|
||||
vb[1].y = -y1;
|
||||
vb[1].z = 0;
|
||||
vb[1].diffuse = m_myColor;
|
||||
vb[1].u1 = 0;
|
||||
vb[1].v1 = 0;
|
||||
|
||||
vb[2].x = x1;
|
||||
vb[2].y = -y1;
|
||||
vb[2].z = 0;
|
||||
vb[2].diffuse = m_myColor;
|
||||
vb[2].u1 = 0;
|
||||
vb[2].v1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DebugHintObject::Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
SphereClass bounds(Vector3(m_myLoc.x, m_myLoc.y, m_myLoc.z), m_mySize);
|
||||
if (!rinfo.Camera.Cull_Sphere(bounds))
|
||||
{
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
DX8Wrapper::Set_Shader(m_shaderClass);
|
||||
DX8Wrapper::Set_Texture(0, NULL);
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferTile);
|
||||
|
||||
Matrix3D tm(Transform);
|
||||
Vector3 vec(m_myLoc.x, m_myLoc.y, m_myLoc.z);
|
||||
tm.Set_Translation(vec);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD, tm);
|
||||
|
||||
DX8Wrapper::Draw_Triangles( 0, 1, 0, 3);
|
||||
}
|
||||
}
|
||||
#endif // _DEBUG
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DEFINITIONS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DInGameUI::W3DInGameUI()
|
||||
{
|
||||
Int i;
|
||||
|
||||
for( i = 0; i < MAX_MOVE_HINTS; i++ )
|
||||
{
|
||||
|
||||
m_moveHintRenderObj[ i ] = NULL;
|
||||
m_moveHintAnim[ i ] = NULL;
|
||||
|
||||
} // end for i
|
||||
|
||||
m_buildingPlacementAnchor = NULL;
|
||||
m_buildingPlacementArrow = NULL;
|
||||
|
||||
} // end W3DInGameUI
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
W3DInGameUI::~W3DInGameUI()
|
||||
{
|
||||
Int i;
|
||||
|
||||
// remove render objects for hints
|
||||
for( i = 0; i < MAX_MOVE_HINTS; i++ )
|
||||
{
|
||||
|
||||
REF_PTR_RELEASE( m_moveHintRenderObj[ i ] );
|
||||
REF_PTR_RELEASE( m_moveHintAnim[ i ] );
|
||||
|
||||
} // end for i
|
||||
|
||||
REF_PTR_RELEASE( m_buildingPlacementAnchor );
|
||||
REF_PTR_RELEASE( m_buildingPlacementArrow );
|
||||
|
||||
} // end ~W3DInGameUI
|
||||
|
||||
// loadText ===================================================================
|
||||
/** Load text from the file */
|
||||
//=============================================================================
|
||||
static void loadText( char *filename, GameWindow *listboxText )
|
||||
{
|
||||
if (!listboxText)
|
||||
return;
|
||||
GadgetListBoxReset(listboxText);
|
||||
|
||||
FILE *fp;
|
||||
|
||||
// open the file
|
||||
fp = fopen( filename, "r" );
|
||||
if( fp == NULL )
|
||||
return;
|
||||
|
||||
char buffer[ 1024 ];
|
||||
UnicodeString line;
|
||||
Color color = GameMakeColor(255, 255, 255, 255);
|
||||
while( fgets( buffer, 1024, fp ) != NULL )
|
||||
{
|
||||
line.translate(buffer);
|
||||
line.trim();
|
||||
if (line.isEmpty())
|
||||
line = UnicodeString(L" ");
|
||||
GadgetListBoxAddEntryText(listboxText, line, color, -1, -1);
|
||||
} // end while
|
||||
|
||||
// close the file
|
||||
fclose( fp );
|
||||
|
||||
} // end loadText
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::init( void )
|
||||
{
|
||||
|
||||
// extending functionality
|
||||
InGameUI::init();
|
||||
// for the beta, they didn't want the help menu showing up, but I left this as a bock
|
||||
// comment because we'll probably want to add this back in.
|
||||
/*
|
||||
// create the MOTD
|
||||
GameWindow *motd = TheWindowManager->winCreateFromScript( AsciiString("MOTD.wnd") );
|
||||
if( motd )
|
||||
{
|
||||
NameKeyType listboxTextID = TheNameKeyGenerator->nameToKey( "MOTD.wnd:ListboxMOTD" );
|
||||
GameWindow *listboxText = TheWindowManager->winGetWindowFromId(motd, listboxTextID);
|
||||
|
||||
loadText( "HelpScreen.txt", listboxText );
|
||||
|
||||
// hide it for now
|
||||
motd->winHide( TRUE );
|
||||
|
||||
} // end if*/
|
||||
|
||||
|
||||
} // end init
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Update in game UI */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::update( void )
|
||||
{
|
||||
|
||||
// call base
|
||||
InGameUI::update();
|
||||
|
||||
} // end update
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Reset the in game ui */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::reset( void )
|
||||
{
|
||||
|
||||
// call base
|
||||
InGameUI::reset();
|
||||
|
||||
} // end reset
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Draw member for the W3D implemenation of the game user interface */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::draw( void )
|
||||
{
|
||||
preDraw();
|
||||
|
||||
// draw selection region if drag selecting
|
||||
if( m_isDragSelecting )
|
||||
drawSelectionRegion();
|
||||
|
||||
// for each view draw hints
|
||||
/// @todo should the UI be iterating through views like this?
|
||||
if( TheDisplay )
|
||||
{
|
||||
View *view;
|
||||
|
||||
for( view = TheDisplay->getFirstView();
|
||||
view;
|
||||
view = TheDisplay->getNextView( view ) )
|
||||
{
|
||||
|
||||
// draw move hints
|
||||
drawMoveHints( view );
|
||||
|
||||
// draw attack hints
|
||||
drawAttackHints( view );
|
||||
|
||||
// draw placement angle selection if needed
|
||||
drawPlaceAngle( view );
|
||||
|
||||
} // end for view
|
||||
|
||||
} // end if
|
||||
|
||||
// repaint all our windows
|
||||
|
||||
#ifdef EXTENDED_STATS
|
||||
if (!DX8Wrapper::stats.m_disableConsole) {
|
||||
#endif
|
||||
|
||||
#ifdef DO_UNIT_TIMINGS
|
||||
#pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
|
||||
extern Bool g_UT_startTiming;
|
||||
if (!g_UT_startTiming)
|
||||
#endif
|
||||
|
||||
postDraw();
|
||||
|
||||
TheWindowManager->winRepaint();
|
||||
|
||||
#ifdef EXTENDED_STATS
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end draw
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** draw 2d selection region on screen */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::drawSelectionRegion( void )
|
||||
{
|
||||
Real width = 2.0f;
|
||||
UnsignedInt color = 0x9933FF33; //0xAARRGGBB
|
||||
|
||||
TheDisplay->drawOpenRect( m_dragSelectRegion.lo.x,
|
||||
m_dragSelectRegion.lo.y,
|
||||
m_dragSelectRegion.hi.x - m_dragSelectRegion.lo.x,
|
||||
m_dragSelectRegion.hi.y - m_dragSelectRegion.lo.y,
|
||||
width,
|
||||
color );
|
||||
|
||||
} // end drawSelectionRegion
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Draw the visual feedback for clicking in the world and telling units
|
||||
* to move there */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::drawMoveHints( View *view )
|
||||
{
|
||||
Int i;
|
||||
// Real width = 1.0f;
|
||||
// UnsignedInt color = 0x9933FF33; //0xAARRGGBB
|
||||
|
||||
for( i = 0; i < MAX_MOVE_HINTS; i++ )
|
||||
{
|
||||
Int elapsed = TheGameClient->getFrame() - m_moveHint[i].frame;
|
||||
|
||||
if( elapsed <= 40 )
|
||||
{
|
||||
RectClass rect;
|
||||
|
||||
// if this hint is not in this view ignore it
|
||||
/// @todo write this to check if point is visible in view
|
||||
// if( view->pointInView( &m_moveHint[ i ].pos == FALSE )
|
||||
// continue;
|
||||
|
||||
// create render object and add to scene of needed
|
||||
if( m_moveHintRenderObj[ i ] == NULL )
|
||||
{
|
||||
RenderObjClass *hint;
|
||||
HAnimClass *anim;
|
||||
|
||||
// create hint object
|
||||
hint = W3DDisplay::m_assetManager->Create_Render_Obj(TheGlobalData->m_moveHintName.str());
|
||||
|
||||
AsciiString animName;
|
||||
animName.format("%s.%s", TheGlobalData->m_moveHintName.str(), TheGlobalData->m_moveHintName.str());
|
||||
anim = W3DDisplay::m_assetManager->Get_HAnim(animName.str());
|
||||
|
||||
// sanity
|
||||
if( hint == NULL )
|
||||
{
|
||||
|
||||
DEBUG_CRASH(("unable to create hint"));
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
// asign render objects to GUI data
|
||||
m_moveHintRenderObj[ i ] = hint;
|
||||
|
||||
// note that 'anim' is returned from Get_HAnim with an AddRef, so we don't need to addref it again.
|
||||
// however, we do need to release the contents of moveHintAnim (if any)
|
||||
REF_PTR_RELEASE(m_moveHintAnim[i]);
|
||||
m_moveHintAnim[i] = anim;
|
||||
|
||||
} // end if, create render objects
|
||||
|
||||
// show the render object if hidden
|
||||
if( m_moveHintRenderObj[ i ]->Is_Hidden() == 1 ) {
|
||||
m_moveHintRenderObj[ i ]->Set_Hidden( 0 );
|
||||
// add to scene
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( m_moveHintRenderObj[ i ] );
|
||||
if (m_moveHintAnim[i])
|
||||
m_moveHintRenderObj[i]->Set_Animation(m_moveHintAnim[i], 0, RenderObjClass::ANIM_MODE_ONCE);
|
||||
}
|
||||
|
||||
// move this hint render object to the position and align with terrain
|
||||
Matrix3D transform;
|
||||
PathfindLayerEnum layer = TheTerrainLogic->alignOnTerrain( 0, m_moveHint[ i ].pos, true, transform );
|
||||
|
||||
Real waterZ;
|
||||
if (layer == LAYER_GROUND && TheTerrainLogic->isUnderwater(m_moveHint[ i ].pos.x, m_moveHint[ i ].pos.y, &waterZ))
|
||||
{
|
||||
Coord3D tmp = m_moveHint[ i ].pos;
|
||||
tmp.z = waterZ;
|
||||
Coord3D normal;
|
||||
normal.x = 0;
|
||||
normal.y = 0;
|
||||
normal.z = 1;
|
||||
makeAlignToNormalMatrix(0, tmp, normal, transform);
|
||||
}
|
||||
|
||||
m_moveHintRenderObj[ i ]->Set_Transform( transform );
|
||||
|
||||
#if 0
|
||||
// if there is a source then draw line from source to destination
|
||||
Object *obj = TheGameLogic->getObject( m_moveHint[ i ].sourceID );
|
||||
if( obj )
|
||||
{
|
||||
Drawable *source = obj->getDrawable();
|
||||
|
||||
if( source )
|
||||
{
|
||||
Coord3D pos;
|
||||
ICoord2D start, end;
|
||||
|
||||
// project start and end point to screen point
|
||||
source->getPosition( &pos );
|
||||
view->worldToScreen( &pos, &start );
|
||||
view->worldToScreen( &hintPos, &end );
|
||||
|
||||
// draw the line
|
||||
TheDisplay->drawLine( start.x, start.y, end.x, end.y, width, color );
|
||||
|
||||
} // end if
|
||||
} // end if
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// hide hint marker
|
||||
if( m_moveHintRenderObj[ i ] )
|
||||
if( m_moveHintRenderObj[ i ]->Is_Hidden() == 0 ) {
|
||||
m_moveHintRenderObj[ i ]->Set_Hidden( 1 );
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_moveHintRenderObj[ i ] );
|
||||
}
|
||||
|
||||
} // end else
|
||||
|
||||
} // end for i
|
||||
|
||||
} // end drawMoveHints
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Draw visual back for clicking to attack a unit in the world */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::drawAttackHints( View *view )
|
||||
{
|
||||
|
||||
} // end drawAttackHints
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Draw the angle selection for placing building if needed */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DInGameUI::drawPlaceAngle( View *view )
|
||||
{
|
||||
// Coord2D v, p, o;
|
||||
//Real size = 15.0f;
|
||||
|
||||
//Create the anchor & arrow if not already created!
|
||||
if( !m_buildingPlacementAnchor )
|
||||
{
|
||||
m_buildingPlacementAnchor = W3DDisplay::m_assetManager->Create_Render_Obj( "Locater01" );
|
||||
|
||||
// sanity
|
||||
if( !m_buildingPlacementAnchor )
|
||||
{
|
||||
DEBUG_CRASH( ("Unable to create BuildingPlacementAnchor (Locator01.w3d) -- cursor for placing buildings") );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( !m_buildingPlacementArrow )
|
||||
{
|
||||
m_buildingPlacementArrow = W3DDisplay::m_assetManager->Create_Render_Obj( "Locater02" );
|
||||
|
||||
// sanity
|
||||
if( !m_buildingPlacementArrow )
|
||||
{
|
||||
DEBUG_CRASH( ("Unable to create BuildingPlacementArrow (Locator02.w3d) -- cursor for placing buildings") );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Bool anchorInScene = m_buildingPlacementAnchor->Peek_Scene() != NULL;
|
||||
Bool arrowInScene = m_buildingPlacementArrow->Peek_Scene() != NULL;
|
||||
|
||||
// get out of here if this display isn't up anyway
|
||||
if( isPlacementAnchored() == FALSE )
|
||||
{
|
||||
if( anchorInScene )
|
||||
{
|
||||
//If our anchor is in the scene, remove it from the scene but don't delete it.
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_buildingPlacementAnchor );
|
||||
}
|
||||
if( arrowInScene )
|
||||
{
|
||||
//If our arrow is in the scene, remove it from the scene but don't delete it.
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_buildingPlacementArrow );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// get the anchor points
|
||||
ICoord2D start, end;
|
||||
getPlacementPoints( &start, &end );
|
||||
|
||||
|
||||
|
||||
|
||||
Coord3D vector;
|
||||
vector.x = end.x - start.x;
|
||||
vector.y = end.y - start.y;
|
||||
vector.z = 0.0f;
|
||||
Real length = vector.length();
|
||||
|
||||
Bool showArrow = length >= 5.0f;
|
||||
|
||||
if( showArrow )
|
||||
{
|
||||
if( anchorInScene )
|
||||
{
|
||||
//We're switching to the arrow!
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_buildingPlacementAnchor );
|
||||
}
|
||||
if( !arrowInScene )
|
||||
{
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( m_buildingPlacementArrow );
|
||||
arrowInScene = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( arrowInScene )
|
||||
{
|
||||
//We're switching to the anchor!
|
||||
W3DDisplay::m_3DScene->Remove_Render_Object( m_buildingPlacementArrow );
|
||||
}
|
||||
if( !anchorInScene )
|
||||
{
|
||||
W3DDisplay::m_3DScene->Add_Render_Object( m_buildingPlacementAnchor );
|
||||
anchorInScene = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
//The proper way to orient the placement arrow is to copy the matrix from the m_placeIcon[0]!
|
||||
if( anchorInScene )
|
||||
{
|
||||
if ( m_placeIcon[ 0 ] )
|
||||
m_buildingPlacementAnchor->Set_Transform( *m_placeIcon[ 0 ]->getTransformMatrix() );
|
||||
}
|
||||
else if( arrowInScene )
|
||||
{
|
||||
if ( m_placeIcon[ 0 ] )
|
||||
m_buildingPlacementArrow->Set_Transform( *m_placeIcon[ 0 ]->getTransformMatrix() );
|
||||
}
|
||||
|
||||
|
||||
//m_buildingPlacementArrow->Set_Transform(
|
||||
|
||||
// draw a little box at the start to show the "anchor" point
|
||||
//Real rectSize = 4.0f;
|
||||
//TheDisplay->drawFillRect( start.x - rectSize / 2, start.y - rectSize / 2,
|
||||
// rectSize, rectSize, color );
|
||||
|
||||
// compute vector for line
|
||||
//v.x = end.x - start.x;
|
||||
//v.y = end.y - start.y;
|
||||
//v.normalize();
|
||||
|
||||
// compute opposite vector
|
||||
//o.x = -v.x;
|
||||
//o.y = -v.y;
|
||||
|
||||
// compute perpendicular vector one way
|
||||
//p.x = -v.y;
|
||||
//p.y = v.x;
|
||||
|
||||
// draw the line
|
||||
//start.x = o.x * size + p.x * (size/2.0f) + end.x;
|
||||
//start.y = o.y * size + p.y * (size/2.0f) + end.y;
|
||||
//TheDisplay->drawLine( start.x, start.y, end.x, end.y, width, color );
|
||||
|
||||
// compute perpendicular vector other way
|
||||
//p.x = v.y;
|
||||
//p.y = -v.x;
|
||||
|
||||
// draw the line
|
||||
//start.x = o.x * size + p.x * (size/2.0f) + end.x;
|
||||
//start.y = o.y * size + p.y * (size/2.0f) + end.y;
|
||||
//TheDisplay->drawLine( start.x, start.y, end.x, end.y, width, color );
|
||||
|
||||
} // end drawPlaceAngle
|
||||
|
||||
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DMouse.cpp /////////////////////////////////////////////////////////////////////////////
|
||||
// Author: Mark W.
|
||||
// Desc: W3D Mouse cursor implementations
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "Common/GameMemory.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/RendObj.h"
|
||||
#include "WW3D2/HAnim.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
|
||||
#include "assetmgr.h"
|
||||
|
||||
#include "W3DDevice/Common/W3DConvert.h"
|
||||
#include "W3DDevice/GameClient/W3DMouse.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
#include "W3DDevice/GameClient/W3DScene.h"
|
||||
#include "GameClient/Display.h"
|
||||
#include "GameClient/Image.h"
|
||||
#include "GameClient/InGameUI.h"
|
||||
#include "mutex.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//Since there can't be more than 1 mouse, might as well keep these static.
|
||||
static CriticalSectionClass mutex;
|
||||
static Bool isThread;
|
||||
static TextureClass *cursorTextures[Mouse::NUM_MOUSE_CURSORS][MAX_2D_CURSOR_ANIM_FRAMES]; ///<Textures for each cursor type
|
||||
static const Image *cursorImages[Mouse::NUM_MOUSE_CURSORS]; ///<Images for use with the RM_POLYGON method.
|
||||
static RenderObjClass *cursorModels[Mouse::NUM_MOUSE_CURSORS]; ///< W3D models for each cursor type
|
||||
static HAnimClass *cursorAnims[Mouse::NUM_MOUSE_CURSORS]; ///< W3D animations for each cursor type
|
||||
|
||||
///Mouse polling/update thread function
|
||||
static class MouseThreadClass : public ThreadClass
|
||||
{
|
||||
|
||||
public:
|
||||
MouseThreadClass::MouseThreadClass() : ThreadClass() {}
|
||||
|
||||
void Thread_Function();
|
||||
|
||||
} thread;
|
||||
|
||||
void MouseThreadClass::Thread_Function()
|
||||
{
|
||||
|
||||
//poll mouse and update position
|
||||
|
||||
while (running)
|
||||
{
|
||||
isThread=TRUE;
|
||||
if (TheMouse)
|
||||
TheMouse->draw();
|
||||
isThread=FALSE;
|
||||
Switch_Thread();
|
||||
}
|
||||
}
|
||||
|
||||
W3DMouse::W3DMouse( void )
|
||||
{
|
||||
// zero our event list
|
||||
for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
for (Int j=0; j<MAX_2D_CURSOR_ANIM_FRAMES; j++)
|
||||
cursorTextures[i][j]=NULL;
|
||||
cursorModels[i]=NULL;
|
||||
cursorAnims[i]=NULL;
|
||||
}
|
||||
|
||||
m_currentD3DCursor=NONE;
|
||||
m_currentW3DCursor=NONE;
|
||||
m_currentPolygonCursor=NONE;
|
||||
m_currentAnimFrame = 0;
|
||||
m_currentD3DFrame = 0;
|
||||
m_currentFrames = 0;
|
||||
m_currentFMS= 1.0f/1000.0f;
|
||||
|
||||
m_camera = NULL;
|
||||
m_drawing = FALSE;
|
||||
|
||||
} // end Win32Mouse
|
||||
|
||||
W3DMouse::~W3DMouse( void )
|
||||
{
|
||||
LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
|
||||
|
||||
if (m_pDev)
|
||||
{
|
||||
m_pDev->ShowCursor(FALSE); //kill DX8 cursor
|
||||
Win32Mouse::setCursor(ARROW); //enable default windows cursor
|
||||
}
|
||||
|
||||
freeD3DAssets();
|
||||
freeW3DAssets();
|
||||
|
||||
thread.Stop();
|
||||
|
||||
} // end Win32Mouse
|
||||
|
||||
void W3DMouse::initPolygonAssets(void)
|
||||
{
|
||||
CriticalSectionClass::LockClass m(mutex);
|
||||
|
||||
//don't allow the mouse thread to initialize
|
||||
//wait for main app to do initialization.
|
||||
if (isThread)
|
||||
return;
|
||||
|
||||
//Check if texture assets already loaded
|
||||
if (m_currentRedrawMode == RM_POLYGON && cursorImages[1] == NULL)
|
||||
{
|
||||
for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
m_currentPolygonCursor = m_currentCursor;
|
||||
if (!m_cursorInfo[i].imageName.isEmpty())
|
||||
cursorImages[i]=TheMappedImageCollection->findImageByName(m_cursorInfo[i].imageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void W3DMouse::freePolygonAssets(void)
|
||||
{
|
||||
|
||||
for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
cursorImages[i]=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**Release the textures required to display the selected cursor*/
|
||||
Bool W3DMouse::releaseD3DCursorTextures(MouseCursor cursor)
|
||||
{
|
||||
if (cursor == NONE || !cursorTextures[cursor][0])
|
||||
return TRUE; //no texture for this cursor or texture never loaded
|
||||
|
||||
for (Int i=0; i<MAX_2D_CURSOR_ANIM_FRAMES; i++)
|
||||
{
|
||||
REF_PTR_RELEASE(m_currentD3DSurface[i]);
|
||||
REF_PTR_RELEASE(cursorTextures[cursor][i]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**Load the textures required to display the selected cursor*/
|
||||
Bool W3DMouse::loadD3DCursorTextures(MouseCursor cursor)
|
||||
{
|
||||
if (cursor == NONE || cursorTextures[cursor][0])
|
||||
return TRUE; //no texture for this cursor or texture already loaded
|
||||
|
||||
WW3DAssetManager *am=WW3DAssetManager::Get_Instance();
|
||||
Int animFrames=m_cursorInfo[cursor].numFrames;
|
||||
|
||||
if (!animFrames)
|
||||
return FALSE; //no animation frames defined.
|
||||
|
||||
const char *baseName=m_cursorInfo[cursor].textureName.str();
|
||||
char FrameName[64];
|
||||
|
||||
//Clamp to reasonable number
|
||||
if (animFrames > MAX_2D_CURSOR_ANIM_FRAMES)
|
||||
animFrames = MAX_2D_CURSOR_ANIM_FRAMES;
|
||||
|
||||
m_currentFrames=0;
|
||||
|
||||
if (animFrames == 1)
|
||||
{ //single animation frame without trailing numbers
|
||||
sprintf(FrameName,"%s.tga",baseName);
|
||||
cursorTextures[cursor][0]= am->Get_Texture(FrameName);
|
||||
m_currentD3DSurface[0]=cursorTextures[cursor][0]->Get_Surface_Level();
|
||||
m_currentFrames = 1;
|
||||
}
|
||||
else
|
||||
for (Int i=0; i<animFrames; i++)
|
||||
{
|
||||
sprintf(FrameName,"%s%04d.tga",baseName,i);
|
||||
if ((cursorTextures[cursor][i]=am->Get_Texture(FrameName)) != NULL)
|
||||
{ m_currentD3DSurface[m_currentFrames]=cursorTextures[cursor][i]->Get_Surface_Level();
|
||||
m_currentFrames++;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void W3DMouse::initD3DAssets(void)
|
||||
{
|
||||
//Nothing to do here unless we want to preload all possible cursors which would
|
||||
//probably not be practical for memory reasons.
|
||||
|
||||
CriticalSectionClass::LockClass m(mutex);
|
||||
|
||||
//don't allow the mouse thread to initialize
|
||||
//wait for main app to do initialization.
|
||||
if (isThread)
|
||||
return;
|
||||
|
||||
WW3DAssetManager *am=WW3DAssetManager::Get_Instance();
|
||||
|
||||
//Check if texture assets already loaded
|
||||
if (m_currentRedrawMode == RM_DX8 && cursorTextures[1] == NULL && am)
|
||||
{
|
||||
for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
for (Int j=0; j < MAX_2D_CURSOR_ANIM_FRAMES; j++)
|
||||
{
|
||||
cursorTextures[i][j]=NULL;//am->Get_Texture(m_cursorInfo[i].textureName.str());
|
||||
m_currentD3DSurface[i]=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void W3DMouse::freeD3DAssets(void)
|
||||
{
|
||||
//free pointers to texture surfaces.
|
||||
for (Int i=0; i<MAX_2D_CURSOR_ANIM_FRAMES; i++)
|
||||
REF_PTR_RELEASE(m_currentD3DSurface[i]);
|
||||
|
||||
//free textures.
|
||||
for (i=0; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
for (Int j=0; j<MAX_2D_CURSOR_ANIM_FRAMES; j++)
|
||||
REF_PTR_RELEASE(cursorTextures[i][j]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void W3DMouse::initW3DAssets(void)
|
||||
{
|
||||
CriticalSectionClass::LockClass m(mutex);
|
||||
|
||||
//don't allow the mouse thread to initialize
|
||||
//wait for main app to do initialization.
|
||||
if (isThread)
|
||||
return;
|
||||
|
||||
//Check if model assets already loaded
|
||||
if ((cursorModels[1] == NULL && W3DDisplay::m_assetManager))
|
||||
{
|
||||
for (Int i=1; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
if (!m_cursorInfo[i].W3DModelName.isEmpty())
|
||||
{
|
||||
if (m_orthoCamera)
|
||||
cursorModels[i] = W3DDisplay::m_assetManager->Create_Render_Obj(m_cursorInfo[i].W3DModelName.str(), m_cursorInfo[i].W3DScale*m_orthoZoom, 0);
|
||||
else
|
||||
cursorModels[i] = W3DDisplay::m_assetManager->Create_Render_Obj(m_cursorInfo[i].W3DModelName.str(), m_cursorInfo[i].W3DScale, 0);
|
||||
if (cursorModels[i])
|
||||
{
|
||||
cursorModels[i]->Set_Position(Vector3(0.0f, 0.0f, -1.0f));
|
||||
//W3DDisplay::m_3DInterfaceScene->Add_Render_Object(cursorModels[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cursorAnims[1] == NULL && W3DDisplay::m_assetManager))
|
||||
{
|
||||
for (Int i=1; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
if (!m_cursorInfo[i].W3DAnimName.isEmpty())
|
||||
{
|
||||
DEBUG_ASSERTCRASH(cursorAnims[i] == NULL, ("hmm, leak festival"));
|
||||
cursorAnims[i] = W3DDisplay::m_assetManager->Get_HAnim(m_cursorInfo[i].W3DAnimName.str());
|
||||
if (cursorAnims[i] && cursorModels[i])
|
||||
{
|
||||
cursorModels[i]->Set_Animation(cursorAnims[i], 0, (m_cursorInfo[i].loop) ? RenderObjClass::ANIM_MODE_LOOP : RenderObjClass::ANIM_MODE_ONCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create the camera
|
||||
m_camera = NEW_REF( CameraClass, () );
|
||||
m_camera->Set_Position( Vector3( 0, 1, 1 ) );
|
||||
Vector2 min = Vector2( -1, -1 );
|
||||
Vector2 max = Vector2( +1, +1 );
|
||||
m_camera->Set_View_Plane( min, max );
|
||||
m_camera->Set_Clip_Planes( 0.995f, 20.0f );
|
||||
if (m_orthoCamera)
|
||||
m_camera->Set_Projection_Type( CameraClass::ORTHO );
|
||||
}
|
||||
|
||||
void W3DMouse::freeW3DAssets(void)
|
||||
{
|
||||
|
||||
for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
|
||||
{
|
||||
if (W3DDisplay::m_3DInterfaceScene && cursorModels[i])
|
||||
{
|
||||
W3DDisplay::m_3DInterfaceScene->Remove_Render_Object(cursorModels[i]);
|
||||
}
|
||||
REF_PTR_RELEASE(cursorModels[i]);
|
||||
REF_PTR_RELEASE(cursorAnims[i]);
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE(m_camera);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Initialize our device */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DMouse::init( void )
|
||||
{
|
||||
|
||||
//check if system already initialized and texture assets loaded.
|
||||
Win32Mouse::init();
|
||||
setCursor(ARROW); //set default starting cursor image
|
||||
|
||||
WWASSERT(!thread.Is_Running());
|
||||
|
||||
|
||||
isThread=FALSE;
|
||||
if (m_currentRedrawMode == RM_DX8)
|
||||
thread.Execute();
|
||||
thread.Set_Priority(0);
|
||||
|
||||
} // end int
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Reset */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DMouse::reset( void )
|
||||
{
|
||||
|
||||
// extend
|
||||
Win32Mouse::reset();
|
||||
|
||||
} // end reset
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Super basic simplistic cursor */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void W3DMouse::setCursor( MouseCursor cursor )
|
||||
{
|
||||
|
||||
CriticalSectionClass::LockClass m(mutex);
|
||||
|
||||
m_directionFrame=0;
|
||||
if (m_currentRedrawMode == RM_WINDOWS)
|
||||
{ //Windows default cursor needs to refreshed whenever we get a WM_SETCURSOR
|
||||
m_currentD3DCursor=NONE;
|
||||
m_currentW3DCursor=NONE;
|
||||
m_currentPolygonCursor=NONE;
|
||||
setCursorDirection(cursor);
|
||||
if (m_drawing) //only allow cursor to change when drawing the cursor (once per frame) to fix flickering.
|
||||
Win32Mouse::setCursor(cursor);
|
||||
m_currentCursor = cursor;
|
||||
return;
|
||||
}
|
||||
|
||||
// extend
|
||||
Mouse::setCursor( cursor );
|
||||
|
||||
// if we're already on this cursor ignore the rest of code to stop cursor flickering.
|
||||
if( m_currentCursor == cursor && m_currentD3DCursor == cursor)
|
||||
return;
|
||||
|
||||
//make sure Windows didn't reset our cursor
|
||||
if (m_currentRedrawMode == RM_DX8)
|
||||
{
|
||||
SetCursor(NULL); //Kill Windows Cursor
|
||||
|
||||
LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
|
||||
Bool doImageChange=FALSE;
|
||||
|
||||
if (m_pDev != NULL)
|
||||
{
|
||||
m_pDev->ShowCursor(FALSE); //disable DX8 cursor
|
||||
if (cursor != m_currentD3DCursor)
|
||||
{ if (!isThread)
|
||||
{ releaseD3DCursorTextures(m_currentD3DCursor);
|
||||
//Since this type of cursor is updated from a non-D3D thread, we need
|
||||
//to preallocate all surfaces in main thread.
|
||||
loadD3DCursorTextures(cursor);
|
||||
}
|
||||
}
|
||||
if (m_currentD3DSurface[0])
|
||||
doImageChange=TRUE;
|
||||
}
|
||||
//For DX8 Cursors, we continually set the image on every call even when
|
||||
//it didn't change. This is needed to prevent the cursor from flickering.
|
||||
if (doImageChange)
|
||||
{
|
||||
HRESULT res;
|
||||
m_currentHotSpot = m_cursorInfo[cursor].hotSpotPosition;
|
||||
m_currentFMS = m_cursorInfo[cursor].fps/1000.0f;
|
||||
m_currentAnimFrame = 0; //reset animation when cursor changes
|
||||
res = m_pDev->SetCursorProperties(m_currentHotSpot.x,m_currentHotSpot.y,m_currentD3DSurface[(Int)m_currentAnimFrame]->Peek_D3D_Surface());
|
||||
m_pDev->ShowCursor(TRUE); //Enable DX8 cursor
|
||||
m_currentD3DFrame=(Int)m_currentAnimFrame;
|
||||
m_currentD3DCursor = cursor;
|
||||
m_lastAnimTime=timeGetTime();
|
||||
}
|
||||
}
|
||||
else if (m_currentRedrawMode == RM_POLYGON)
|
||||
{
|
||||
SetCursor(NULL); //Kill Windows Cursor
|
||||
m_currentD3DCursor=NONE;
|
||||
m_currentW3DCursor=NONE;
|
||||
m_currentPolygonCursor = cursor;
|
||||
m_currentHotSpot = m_cursorInfo[cursor].hotSpotPosition;
|
||||
}
|
||||
else if (m_currentRedrawMode == RM_W3D)
|
||||
{
|
||||
SetCursor(NULL); //Kill Windows Cursor
|
||||
m_currentD3DCursor=NONE;
|
||||
m_currentPolygonCursor=NONE;
|
||||
if (cursor != m_currentW3DCursor)
|
||||
{
|
||||
// set the new model visible
|
||||
if (!cursorModels[1])
|
||||
initW3DAssets();
|
||||
|
||||
if (cursorModels[1])
|
||||
{
|
||||
if (cursorModels[m_currentW3DCursor])
|
||||
{
|
||||
W3DDisplay::m_3DInterfaceScene->Remove_Render_Object(cursorModels[m_currentW3DCursor]);
|
||||
}
|
||||
|
||||
m_currentW3DCursor=cursor;
|
||||
|
||||
if (cursorModels[m_currentW3DCursor])
|
||||
{
|
||||
W3DDisplay::m_3DInterfaceScene->Add_Render_Object(cursorModels[m_currentW3DCursor]);
|
||||
if (m_cursorInfo[m_currentW3DCursor].loop == FALSE && cursorAnims[m_currentW3DCursor])
|
||||
{
|
||||
cursorModels[m_currentW3DCursor]->Set_Animation(cursorAnims[m_currentW3DCursor], 0, RenderObjClass::ANIM_MODE_ONCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentW3DCursor=cursor;
|
||||
}
|
||||
}
|
||||
|
||||
// save current cursor
|
||||
m_currentCursor = cursor;
|
||||
|
||||
} // end setCursor
|
||||
|
||||
extern HWND ApplicationHWnd;
|
||||
|
||||
void W3DMouse::draw(void)
|
||||
{
|
||||
CriticalSectionClass::LockClass m(mutex);
|
||||
|
||||
m_drawing = TRUE;
|
||||
|
||||
//make sure the correct cursor image is selected
|
||||
setCursor(m_currentCursor);
|
||||
|
||||
if (m_currentRedrawMode == RM_DX8 && m_currentD3DCursor != NONE)
|
||||
{
|
||||
//called from upate thread or rendering loop. Tells D3D where
|
||||
//to draw the mouse cursor.
|
||||
LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
|
||||
if (m_pDev)
|
||||
{ m_pDev->ShowCursor(TRUE); //Enable DX8 cursor
|
||||
|
||||
if (TheDisplay && !TheDisplay->getWindowed())
|
||||
{ //if we're full-screen, need to manually move cursor image
|
||||
POINT ptCursor;
|
||||
|
||||
GetCursorPos( &ptCursor );
|
||||
ScreenToClient( ApplicationHWnd, &ptCursor );
|
||||
m_pDev->SetCursorPosition( ptCursor.x, ptCursor.y, D3DCURSOR_IMMEDIATE_UPDATE);
|
||||
}
|
||||
//Check if animated cursor and new frame
|
||||
if (m_currentFrames > 1)
|
||||
{
|
||||
Int msTime=timeGetTime();
|
||||
m_currentAnimFrame += (msTime-m_lastAnimTime) * m_currentFMS;
|
||||
m_currentAnimFrame=fmod(m_currentAnimFrame,m_currentFrames);
|
||||
m_lastAnimTime=msTime;
|
||||
|
||||
if ((Int)m_currentAnimFrame != m_currentD3DFrame)
|
||||
{
|
||||
m_currentD3DFrame=(Int)m_currentAnimFrame;
|
||||
m_pDev->SetCursorProperties(m_currentHotSpot.x,m_currentHotSpot.y,m_currentD3DSurface[m_currentD3DFrame]->Peek_D3D_Surface());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_currentRedrawMode == RM_POLYGON)
|
||||
{
|
||||
const Image *image=cursorImages[m_currentPolygonCursor];
|
||||
if (image)
|
||||
{
|
||||
TheDisplay->drawImage(image,m_currMouse.pos.x-m_currentHotSpot.x,m_currMouse.pos.y-m_currentHotSpot.y,
|
||||
m_currMouse.pos.x+image->getImageWidth()-m_currentHotSpot.x, m_currMouse.pos.y+image->getImageHeight()-m_currentHotSpot.y);
|
||||
}
|
||||
}
|
||||
else if (m_currentRedrawMode == RM_WINDOWS)
|
||||
{
|
||||
}
|
||||
else if (m_currentRedrawMode == RM_W3D)
|
||||
{
|
||||
if ( W3DDisplay::m_3DInterfaceScene && m_camera && m_visible)
|
||||
{
|
||||
if (cursorModels[m_currentW3DCursor])
|
||||
{
|
||||
Real xPercent = (1.0f - (TheDisplay->getWidth() - m_currMouse.pos.x) / (Real)TheDisplay->getWidth());
|
||||
Real yPercent = ((TheDisplay->getHeight() - m_currMouse.pos.y) / (Real)TheDisplay->getHeight());
|
||||
|
||||
Real x, y, z = -1.0f;
|
||||
|
||||
if (m_orthoCamera)
|
||||
{
|
||||
x = xPercent*2 - 1;
|
||||
y = yPercent*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
//W3D Screen coordinates are -1 to 1, so we need to do some conversion:
|
||||
Real logX, logY;
|
||||
PixelScreenToW3DLogicalScreen(m_currMouse.pos.x - 0, m_currMouse.pos.y - 0, &logX, &logY, TheDisplay->getWidth(), TheDisplay->getHeight());
|
||||
|
||||
Vector3 rayStart;
|
||||
Vector3 rayEnd;
|
||||
rayStart = m_camera->Get_Position(); //get camera location
|
||||
m_camera->Un_Project(rayEnd,Vector2(logX,logY)); //get world space point
|
||||
rayEnd -= rayStart; //vector camera to world space point
|
||||
rayEnd.Normalize(); //make unit vector
|
||||
rayEnd *= m_camera->Get_Depth(); //adjust length to reach far clip plane
|
||||
rayEnd += rayStart; //get point on far clip plane along ray from camera.
|
||||
|
||||
x = Vector3::Find_X_At_Z(z, rayStart, rayEnd);
|
||||
y = Vector3::Find_Y_At_Z(z, rayStart, rayEnd);
|
||||
}
|
||||
|
||||
Matrix3D tm(1);
|
||||
tm.Set_Translation(Vector3(x, y, z));
|
||||
Coord2D offset = {0, 0};
|
||||
if (TheInGameUI && TheInGameUI->isScrolling())
|
||||
{
|
||||
offset = TheInGameUI->getScrollAmount();
|
||||
offset.normalize();
|
||||
Real theta = atan2(-offset.y, offset.x);
|
||||
theta -= (Real)M_PI/2;
|
||||
tm.Rotate_Z(theta);
|
||||
}
|
||||
cursorModels[m_currentW3DCursor]->Set_Transform(tm);
|
||||
|
||||
WW3D::Render( W3DDisplay::m_3DInterfaceScene, m_camera );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@todo: In DX8 mode the mouse is drawn in another thread which isn't allowed
|
||||
//access to D3D so we can't do any drawing here.
|
||||
// draw the cursor text
|
||||
if (!isThread)
|
||||
drawCursorText();
|
||||
|
||||
// draw tooltip text
|
||||
if (m_visible && !isThread)
|
||||
drawTooltip();
|
||||
|
||||
m_drawing = FALSE;
|
||||
}
|
||||
|
||||
void W3DMouse::setRedrawMode(RedrawMode mode)
|
||||
{
|
||||
MouseCursor cursor = getMouseCursor();
|
||||
|
||||
//Turn off the previous cursor mode
|
||||
setCursor(NONE);
|
||||
|
||||
m_currentRedrawMode=mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case RM_WINDOWS:
|
||||
{ //Windows mouse doesn't need an update thread.
|
||||
if (thread.Is_Running())
|
||||
thread.Stop();
|
||||
freeD3DAssets(); //using Windows resources
|
||||
freeW3DAssets();
|
||||
freePolygonAssets();
|
||||
m_currentD3DCursor = NONE;
|
||||
m_currentW3DCursor = NONE;
|
||||
m_currentPolygonCursor = NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case RM_W3D:
|
||||
{ //Model mouse updated only at render time so doesn't
|
||||
//require thread.
|
||||
if (thread.Is_Running())
|
||||
thread.Stop();
|
||||
freeD3DAssets(); //using packed Image data, not textures.
|
||||
freePolygonAssets();
|
||||
m_currentD3DCursor = NONE;
|
||||
m_currentPolygonCursor = NONE;
|
||||
initW3DAssets();
|
||||
}
|
||||
break;
|
||||
|
||||
case RM_POLYGON:
|
||||
{ //Polygon mouse updated only at render time so doesn't
|
||||
//require thread.
|
||||
if (thread.Is_Running())
|
||||
thread.Stop();
|
||||
freeD3DAssets(); //using packed Image data, not textures.
|
||||
freeW3DAssets();
|
||||
m_currentD3DCursor = NONE;
|
||||
m_currentW3DCursor = NONE;
|
||||
m_currentPolygonCursor = NONE;
|
||||
initPolygonAssets();
|
||||
}
|
||||
break;
|
||||
|
||||
case RM_DX8:
|
||||
{ //this cursor type is drawn by DX8 and can be refreshed
|
||||
//independent of rendering rate. Uses another thread to do
|
||||
//position updates.
|
||||
initD3DAssets(); //make sure textures loaded.
|
||||
freeW3DAssets();
|
||||
freePolygonAssets();
|
||||
if (!thread.Is_Running())
|
||||
thread.Execute();
|
||||
m_currentW3DCursor = NONE;
|
||||
m_currentPolygonCursor = NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setCursor(NONE);
|
||||
setCursor(cursor);
|
||||
}
|
||||
|
||||
void W3DMouse::setCursorDirection(MouseCursor cursor)
|
||||
{
|
||||
Coord2D offset = {0, 0};
|
||||
//Check if we have a directional cursor that needs different images for each direction
|
||||
if (m_cursorInfo[cursor].numDirections > 1 && TheInGameUI && TheInGameUI->isScrolling())
|
||||
{
|
||||
offset = TheInGameUI->getScrollAmount();
|
||||
if (offset.x || offset.y)
|
||||
{
|
||||
offset.normalize();
|
||||
Real theta = atan2(offset.y, offset.x);
|
||||
theta = fmod(theta+M_PI*2,M_PI*2);
|
||||
Int numDirections=m_cursorInfo[m_currentCursor].numDirections;
|
||||
//Figure out which of our predrawn cursor orientations best matches the
|
||||
//actual cursor direction. Frame 0 is assumed to point right and continue
|
||||
//clockwise.
|
||||
m_directionFrame=(Int)(theta/(2.0f*M_PI/(Real)numDirections)+0.5f);
|
||||
if (m_directionFrame >= numDirections)
|
||||
m_directionFrame = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_directionFrame=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_directionFrame = 0;
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DParticleSys.cpp
|
||||
// W3D Particle System implementation
|
||||
// Author: Michael S. Booth, November 2001
|
||||
|
||||
#include "common/GlobalData.h"
|
||||
#include "GameClient/Color.h"
|
||||
#include "W3DDevice/GameClient/W3DParticleSys.h"
|
||||
#include "W3DDevice/GameClient/W3DAssetManager.h"
|
||||
#include "W3DDevice/GameClient/W3DDisplay.h"
|
||||
#include "W3DDevice/GameClient/heightmap.h"
|
||||
#include "W3DDevice/GameClient/W3DSmudge.h"
|
||||
#include "W3DDevice/GameClient/W3DSnow.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------ Performance Timers
|
||||
//#include "Common/PerfMetrics.h"
|
||||
//#include "Common/PerfTimer.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "Common/QuickTrig.h"
|
||||
W3DParticleSystemManager::W3DParticleSystemManager()
|
||||
{
|
||||
m_pointGroup = NULL;
|
||||
m_streakLine = NULL;
|
||||
m_posBuffer = NULL;
|
||||
m_RGBABuffer = NULL;
|
||||
m_sizeBuffer = NULL;
|
||||
m_angleBuffer = NULL;
|
||||
m_readyToRender = false;
|
||||
|
||||
m_onScreenParticleCount = 0;
|
||||
|
||||
m_pointGroup = NEW PointGroupClass();
|
||||
//m_streakLine = NULL;
|
||||
m_streakLine = NEW StreakLineClass();
|
||||
|
||||
m_posBuffer = NEW_REF( ShareBufferClass<Vector3>, (MAX_POINTS_PER_GROUP, "W3DParticleSystemManager::m_posBuffer") );
|
||||
m_RGBABuffer = NEW_REF( ShareBufferClass<Vector4>, (MAX_POINTS_PER_GROUP, "W3DParticleSystemManager::m_RGBABuffer") );
|
||||
m_sizeBuffer = NEW_REF( ShareBufferClass<float>, (MAX_POINTS_PER_GROUP, "W3DParticleSystemManager::m_sizeBuffer") );
|
||||
m_angleBuffer = NEW_REF( ShareBufferClass<uint8>, (MAX_POINTS_PER_GROUP, "W3DParticleSystemManager::m_angleBuffer") );
|
||||
}
|
||||
|
||||
W3DParticleSystemManager::~W3DParticleSystemManager()
|
||||
{
|
||||
delete m_pointGroup;
|
||||
|
||||
// W3DDisplay::m_3DScene->Remove_Render_Object( m_streakLine );
|
||||
|
||||
if (m_streakLine)
|
||||
{
|
||||
REF_PTR_RELEASE(m_streakLine);
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE(m_posBuffer);
|
||||
REF_PTR_RELEASE(m_RGBABuffer);
|
||||
REF_PTR_RELEASE(m_sizeBuffer);
|
||||
REF_PTR_RELEASE(m_angleBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack because DoParticles is called from Flush(), which is called
|
||||
* multiple times per frame. We only want to render once.
|
||||
* @todo Clean up the flag/Flush hack.
|
||||
*/
|
||||
void W3DParticleSystemManager::queueParticleRender()
|
||||
{
|
||||
m_readyToRender = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nasty hack to render particles last. Called directly by WW3D::Flush()
|
||||
*/
|
||||
void DoParticles( RenderInfoClass &rinfo )
|
||||
{
|
||||
if (TheParticleSystemManager)
|
||||
TheParticleSystemManager->doParticles(rinfo);
|
||||
}
|
||||
|
||||
void W3DParticleSystemManager::doParticles(RenderInfoClass &rinfo)
|
||||
{
|
||||
|
||||
if (m_readyToRender == false)
|
||||
return;
|
||||
|
||||
// external mechanism must tell us when it's OK to render again...
|
||||
m_readyToRender = false;
|
||||
|
||||
//reset each frame
|
||||
/// @todo lorenzen sez: this should be debug only:
|
||||
m_onScreenParticleCount = 0;
|
||||
|
||||
Int visibleSmudgeCount = 0;
|
||||
if (TheSmudgeManager)
|
||||
TheSmudgeManager->setSmudgeCountLastFrame(0); //keep track of visible smudges
|
||||
|
||||
const FrustumClass & frustum = rinfo.Camera.Get_Frustum();
|
||||
AABoxClass bbox;
|
||||
|
||||
//Get a bounding box around our visible universe. Bounded by terrain and the sky
|
||||
//so much tighter fitting volume than what's actually visible. This will cull
|
||||
//particles falling under the ground.
|
||||
|
||||
TheTerrainRenderObject->getMaximumVisibleBox(frustum, &bbox, TRUE);
|
||||
|
||||
//@todo lorenzen sez: put these in registers for sure
|
||||
Real bcX = bbox.Center.X;
|
||||
Real bcY = bbox.Center.Y;
|
||||
Real bcZ = bbox.Center.Z;
|
||||
Real beX = bbox.Extent.X;
|
||||
Real beY = bbox.Extent.Y;
|
||||
Real beZ = bbox.Extent.Z;
|
||||
|
||||
unsigned int personalities[MAX_POINTS_PER_GROUP];
|
||||
|
||||
|
||||
m_fieldParticleCount = 0;
|
||||
|
||||
SmudgeSet *set=NULL;
|
||||
if (TheSmudgeManager)
|
||||
set=TheSmudgeManager->addSmudgeSet(); //global smudge set through which all smudges are rendered.
|
||||
|
||||
ParticleSystemManager::ParticleSystemList &particleSysList = TheParticleSystemManager->getAllParticleSystems();
|
||||
for( ParticleSystemManager::ParticleSystemListIt it = particleSysList.begin(); it != particleSysList.end(); ++it)
|
||||
{
|
||||
ParticleSystem *sys = (*it);
|
||||
if (!sys) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// only look at particle/point style systems
|
||||
if (sys->isUsingDrawables())
|
||||
continue;
|
||||
|
||||
//temporary hack that checks if texture name starts with "SMUD" - if so, we can assume it's a smudge type
|
||||
if (/*sys->isUsingSmudge()*/ *((DWORD *)sys->getParticleTypeName().str()) == 0x44554D53)
|
||||
{
|
||||
if (TheSmudgeManager && ((W3DSmudgeManager*)TheSmudgeManager)->getHardwareSupport() && TheGlobalData->m_useHeatEffects)
|
||||
{
|
||||
//set-up all the per-particle
|
||||
for (Particle *p = sys->getFirstParticle(); p; p = p->m_systemNext)
|
||||
{
|
||||
const Coord3D *pos = p->getPosition();
|
||||
Real psize = p->getSize();
|
||||
|
||||
//Cull particle to edges of screen and terrain.
|
||||
if (WWMath::Fabs( pos->x - bcX ) > ( beX + psize ) )
|
||||
continue;
|
||||
|
||||
if (WWMath::Fabs( pos->y - bcY ) > ( beY + psize ) )
|
||||
continue;
|
||||
|
||||
if (WWMath::Fabs( pos->z - bcZ ) > ( beZ + psize ) )
|
||||
continue;
|
||||
|
||||
Smudge *smudge = set->addSmudgeToSet();
|
||||
|
||||
smudge->m_pos.Set( pos->x, pos->y, pos->z );
|
||||
smudge->m_offset.Set( GameClientRandomValueReal(-0.06f,0.06f), GameClientRandomValueReal(-0.03f,0.03f) );
|
||||
smudge->m_size = psize;
|
||||
smudge->m_opacity = p->getAlpha();
|
||||
visibleSmudgeCount++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/// @todo lorenzen sez: declare these outside the sys loop, and put some in registers
|
||||
// initialize them here still, of course
|
||||
// build W3D particle buffer
|
||||
Int count = 0;
|
||||
Vector3 *posArray = m_posBuffer->Get_Array();
|
||||
Real *sizeArray = m_sizeBuffer->Get_Array();
|
||||
Vector4 *RGBAArray = m_RGBABuffer->Get_Array();
|
||||
uint8 *angleArray = m_angleBuffer->Get_Array();
|
||||
const Coord3D *pos;
|
||||
const RGBColor *color;
|
||||
Real psize;
|
||||
|
||||
|
||||
|
||||
//set-up all the per-particle
|
||||
for (Particle *p = sys->getFirstParticle(); p; p = p->m_systemNext)
|
||||
{
|
||||
pos = p->getPosition();
|
||||
psize = p->getSize();
|
||||
|
||||
//Cull particle to edges of screen and terrain.
|
||||
if (WWMath::Fabs(pos->x - bcX) > (beX + psize))
|
||||
continue;
|
||||
|
||||
if (WWMath::Fabs(pos->y - bcY) > (beY + psize))
|
||||
continue;
|
||||
|
||||
if (WWMath::Fabs(pos->z - bcZ) > (beZ + psize))
|
||||
continue;
|
||||
|
||||
m_fieldParticleCount += ( sys->getPriority() == AREA_EFFECT && sys->m_isGroundAligned != FALSE );
|
||||
|
||||
//@todo lorenzen sez: use pointer arithmetic for these arrays
|
||||
personalities[count] = p->getPersonality();
|
||||
|
||||
posArray[count].X = pos->x;
|
||||
posArray[count].Y = pos->y;
|
||||
posArray[count].Z = pos->z;
|
||||
|
||||
sizeArray[count] = psize;
|
||||
|
||||
color = p->getColor();
|
||||
RGBAArray[count].X = color->red;
|
||||
RGBAArray[count].Y = color->green;
|
||||
RGBAArray[count].Z = color->blue;
|
||||
RGBAArray[count].W = p->getAlpha();
|
||||
|
||||
angleArray[count] = (uint8)(p->getAngle() * 255.0f / (2.0f * PI));
|
||||
|
||||
if (++count == MAX_POINTS_PER_GROUP)
|
||||
break;
|
||||
}
|
||||
|
||||
if ( count == 0 )
|
||||
continue; //this system has no particles to render
|
||||
|
||||
TextureClass *texture = W3DDisplay::m_assetManager->Get_Texture( sys->getParticleTypeName().str() );
|
||||
|
||||
if ( m_streakLine && sys->isUsingStreak() && (count >= 2) )
|
||||
{
|
||||
m_streakLine->Reset_Line();
|
||||
|
||||
m_streakLine->Set_Texture( texture );
|
||||
texture->Release_Ref();//release reference since it's held by streakline
|
||||
switch( sys->getShaderType() )
|
||||
{
|
||||
case ParticleSystemInfo::ADDITIVE:
|
||||
m_streakLine->Set_Shader( ShaderClass::_PresetAdditiveSpriteShader );
|
||||
break;
|
||||
case ParticleSystemInfo::ALPHA:
|
||||
m_streakLine->Set_Shader( ShaderClass::_PresetAlphaSpriteShader );
|
||||
break;
|
||||
case ParticleSystemInfo::ALPHA_TEST:
|
||||
m_streakLine->Set_Shader( ShaderClass::_PresetATestSpriteShader );
|
||||
break;
|
||||
case ParticleSystemInfo::MULTIPLY:
|
||||
m_streakLine->Set_Shader( ShaderClass::_PresetMultiplicativeSpriteShader );
|
||||
break;
|
||||
}
|
||||
|
||||
//UPDATE THE STREAK'S ARRAYS
|
||||
m_streakLine->Set_LocsWidthsColors(
|
||||
count,
|
||||
m_posBuffer->Get_Array(),
|
||||
m_sizeBuffer->Get_Array(),
|
||||
m_RGBABuffer->Get_Array(),
|
||||
&personalities[0]
|
||||
);
|
||||
|
||||
//WWASSERT( m_streakLine->Get_Num_Points() == count );
|
||||
|
||||
// This is the happy place for this!
|
||||
RGBAArray[0].X = 0;//eliminates the scissor edge on the trailing edge of the streak
|
||||
RGBAArray[0].Y = 0;
|
||||
RGBAArray[0].Z = 0;
|
||||
RGBAArray[0].W = 0;
|
||||
|
||||
|
||||
//RENDER STREAK!
|
||||
m_streakLine->Render( rinfo );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
WWASSERT( m_pointGroup );
|
||||
|
||||
if ( m_pointGroup ) // this catches the particle and volumeparticle cases
|
||||
{
|
||||
// render all the systems' particles
|
||||
m_pointGroup->Set_Texture( texture );
|
||||
texture->Release_Ref();//release reference since it's held by pointGroup
|
||||
m_pointGroup->Set_Flag( PointGroupClass::TRANSFORM, true ); // transform to screen space
|
||||
|
||||
switch( sys->getShaderType() )
|
||||
{
|
||||
case ParticleSystemInfo::ADDITIVE:
|
||||
m_pointGroup->Set_Shader( ShaderClass::_PresetAdditiveSpriteShader );
|
||||
break;
|
||||
case ParticleSystemInfo::ALPHA:
|
||||
m_pointGroup->Set_Shader( ShaderClass::_PresetAlphaSpriteShader );
|
||||
break;
|
||||
case ParticleSystemInfo::ALPHA_TEST:
|
||||
m_pointGroup->Set_Shader( ShaderClass::_PresetATestSpriteShader );
|
||||
break;
|
||||
case ParticleSystemInfo::MULTIPLY:
|
||||
m_pointGroup->Set_Shader( ShaderClass::_PresetMultiplicativeSpriteShader );
|
||||
break;
|
||||
}
|
||||
|
||||
/// @todo Use both QUADS and TRIS for particles
|
||||
m_pointGroup->Set_Point_Mode( PointGroupClass::QUADS );
|
||||
m_pointGroup->Set_Arrays( m_posBuffer, m_RGBABuffer, NULL, m_sizeBuffer, m_angleBuffer, NULL, count );
|
||||
m_pointGroup->Set_Billboard(sys->shouldBillboard());
|
||||
|
||||
/// @todo Support animated texture particles
|
||||
/// @todo lorenzen sez: unimplemented code wastes cpu cycles
|
||||
m_pointGroup->Set_Point_Frame( 0 );
|
||||
|
||||
//RENDER IT!
|
||||
if( sys->getVolumeParticleDepth() > 1 )
|
||||
{
|
||||
m_pointGroup->RenderVolumeParticle( rinfo, sys->getVolumeParticleDepth() );
|
||||
}
|
||||
else
|
||||
m_pointGroup->Render( rinfo );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @todo lorenzen sez: this should be debug only:
|
||||
//add particle count to total
|
||||
m_onScreenParticleCount += count;
|
||||
|
||||
/*
|
||||
// draw the wind vector for this particle system on the screen
|
||||
UnsignedInt width = TheDisplay->getWidth();
|
||||
UnsignedInt height = TheDisplay->getHeight();
|
||||
Coord3D worldStart, worldEnd;
|
||||
ICoord2D pixelStart, pixelEnd;
|
||||
sys->getPosition( &worldStart );
|
||||
worldEnd.x = Cos( sys->getWindAngle() ) * 50.0f + worldStart.x;
|
||||
worldEnd.y = Sin( sys->getWindAngle() ) * 50.0f + worldStart.y;
|
||||
worldEnd.z = worldStart.z;
|
||||
TheTacticalView->worldToScreen( &worldStart, &pixelStart );
|
||||
TheTacticalView->worldToScreen( &worldEnd, &pixelEnd );
|
||||
Color colorStart = GameMakeColor( 255, 255, 255, 255 );
|
||||
Color colorEnd = GameMakeColor( 255, 128, 128, 255 );
|
||||
TheDisplay->drawLine( pixelStart.x, pixelStart.y, pixelEnd.x, pixelEnd.y, 1.0f, colorStart, colorEnd );
|
||||
*/
|
||||
|
||||
|
||||
}// next system
|
||||
|
||||
/// @todo lorenzen sez: this should be debug only:
|
||||
TheParticleSystemManager->setOnScreenParticleCount(m_onScreenParticleCount);
|
||||
|
||||
//Draw any particles belonging to weather effects
|
||||
if (TheSnowManager)
|
||||
((W3DSnowManager *)TheSnowManager)->render(rinfo);
|
||||
|
||||
//Now process screen smudges which are particles that distort the background behind them.
|
||||
if(TheSmudgeManager)
|
||||
{
|
||||
((W3DSmudgeManager *)TheSmudgeManager)->render(rinfo);
|
||||
TheSmudgeManager->reset(); //clear all the smudges after rendering since we fill again each frame.
|
||||
TheSmudgeManager->setSmudgeCountLastFrame(visibleSmudgeCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "W3DDevice/GameClient/W3DPoly.h"
|
||||
#include "Lib/BaseType.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Delete all vertices in polygon */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void ClipPolyClass::Reset(void)
|
||||
{
|
||||
Verts.Delete_All(false);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Add a new vertex to polygon */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void ClipPolyClass::Add_Vertex(const Vector3 & point)
|
||||
{
|
||||
Verts.Add(point);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
/** Clip polygon to given plane, returning new polygon in dest. */
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void ClipPolyClass::Clip(const PlaneClass & plane,ClipPolyClass & dest) const
|
||||
{
|
||||
dest.Reset();
|
||||
|
||||
// temporary variables used in clipping
|
||||
Int i = 0;
|
||||
Int vcount = Verts.Count();
|
||||
Int iprev = vcount - 1;
|
||||
Bool cur_point_in_front;
|
||||
Bool prev_point_in_front;
|
||||
Real alpha;
|
||||
Vector3 int_point;
|
||||
|
||||
if (vcount <= 2) return;
|
||||
|
||||
// perform clipping
|
||||
prev_point_in_front = !plane.In_Front(Verts[iprev]); // Note, plane normal is outward so we invert this test
|
||||
for (Int j=0; j<vcount; j++) {
|
||||
|
||||
cur_point_in_front = !plane.In_Front(Verts[i]); // Note, plane nomral is out so we invert this test
|
||||
if (prev_point_in_front) {
|
||||
|
||||
if (cur_point_in_front) {
|
||||
|
||||
// Previous vertex was in front of plane and this vertex is in
|
||||
// front of the plane so we emit this vertex.
|
||||
dest.Add_Vertex(Verts[i]);
|
||||
|
||||
} else {
|
||||
|
||||
// Previous vert was in front, this vert is behind, compute
|
||||
// the intersection and emit the point.
|
||||
plane.Compute_Intersection(Verts[iprev],Verts[i],&alpha);
|
||||
Vector3::Lerp(Verts[iprev],Verts[i],alpha,&int_point);
|
||||
dest.Add_Vertex(int_point);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (cur_point_in_front) {
|
||||
|
||||
// segment is going from the back halfspace to the front halfspace
|
||||
// compute the intersection and emit it, then continue
|
||||
// the edge into the front halfspace and emit the end point.
|
||||
plane.Compute_Intersection(Verts[iprev],Verts[i],&alpha);
|
||||
Vector3::Lerp(Verts[iprev],Verts[i],alpha,&int_point);
|
||||
dest.Add_Vertex(int_point);
|
||||
dest.Add_Vertex(Verts[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
prev_point_in_front = cur_point_in_front;
|
||||
iprev = i;
|
||||
|
||||
//i = (i+1)%(Verts.Count());
|
||||
i++;
|
||||
if (i>=vcount) {
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DPropBuffer.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DPropBuffer.cpp
|
||||
//
|
||||
// Created: John Ahlquist, May 2001
|
||||
//
|
||||
// Desc: Draw buffer to handle all the props in a scene.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "W3DDevice/GameClient/W3DPropBuffer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include "Common/Geometry.h"
|
||||
#include "Common/PerfTimer.h"
|
||||
#include "Common/Player.h"
|
||||
#include "Common/PlayerList.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
#include "WW3D2/RInfo.h"
|
||||
#include "WW3D2/Light.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/dx8renderer.h"
|
||||
#include "W3DDevice/GameClient/Module/W3DPropDraw.h"
|
||||
#include "W3DDevice/GameClient/W3DShroud.h"
|
||||
#include "W3DDevice/GameClient/BaseHeightMap.h"
|
||||
#include "GameLogic/PartitionManager.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::cull
|
||||
//=============================================================================
|
||||
/** Culls the props, marking the visible flag. If a prop becomes visible, it sets
|
||||
it's sortKey */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::cull(CameraClass * camera)
|
||||
{
|
||||
Int curProp;
|
||||
|
||||
for (curProp=0; curProp<m_numProps; curProp++) {
|
||||
Bool visible = !camera->Cull_Sphere(m_props[curProp].bounds);
|
||||
m_props[curProp].visible=visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::~W3DPropBuffer
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
W3DPropBuffer::~W3DPropBuffer(void)
|
||||
{
|
||||
Int i;
|
||||
for (i=0; i<MAX_TYPES; i++) {
|
||||
REF_PTR_RELEASE(m_propTypes[i].m_robj);
|
||||
}
|
||||
REF_PTR_RELEASE(m_light);
|
||||
REF_PTR_RELEASE(m_propShroudMaterialPass);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::W3DPropBuffer
|
||||
//=============================================================================
|
||||
/** Constructor. Sets m_initialized to true if it finds the w3d models it needs
|
||||
for the props. */
|
||||
//=============================================================================
|
||||
W3DPropBuffer::W3DPropBuffer(void)
|
||||
{
|
||||
memset(this, sizeof(W3DPropBuffer), 0);
|
||||
m_initialized = false;
|
||||
clearAllProps();
|
||||
m_light = NEW_REF( LightClass, (LightClass::DIRECTIONAL) );
|
||||
m_propShroudMaterialPass = NEW_REF(W3DShroudMaterialPassClass,());
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::clearAllProps
|
||||
//=============================================================================
|
||||
/** Removes all props. */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::clearAllProps(void)
|
||||
{
|
||||
m_numProps=0;
|
||||
Int i;
|
||||
for (i=0; i<MAX_TYPES; i++) {
|
||||
REF_PTR_RELEASE(m_propTypes[i].m_robj);
|
||||
m_propTypes[i].m_robjName.clear();
|
||||
}
|
||||
m_numPropTypes = 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::addPropTypes
|
||||
//=============================================================================
|
||||
/** Adds a type of prop (model & texture). */
|
||||
//=============================================================================
|
||||
Int W3DPropBuffer::addPropType(const AsciiString &modelName)
|
||||
{
|
||||
if (m_numPropTypes>=MAX_TYPES) {
|
||||
DEBUG_CRASH(("Too many kinds of props in map. Reduce kinds of props, or raise prop limit. jba."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_propTypes[m_numPropTypes].m_robj = WW3DAssetManager::Get_Instance()->Create_Render_Obj(modelName.str());
|
||||
if (m_propTypes[m_numPropTypes].m_robj==NULL) {
|
||||
DEBUG_CRASH(("Unable to find model for prop %s\n", modelName.str()));
|
||||
return -1;
|
||||
}
|
||||
m_propTypes[m_numPropTypes].m_robjName = modelName;
|
||||
|
||||
SphereClass bounds = m_propTypes[m_numPropTypes].m_robj->Get_Bounding_Sphere();
|
||||
m_propTypes[m_numPropTypes].m_bounds = bounds;
|
||||
m_numPropTypes++;
|
||||
return m_numPropTypes-1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::addProp
|
||||
//=============================================================================
|
||||
/** Adds a prop. Name is the W3D model name, supported models are
|
||||
ALPINE, DECIDUOUS and SHRUB. */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::addProp(Int id, Coord3D location, Real angle,Real scale, const AsciiString &modelName)
|
||||
{
|
||||
if (m_numProps >= MAX_PROPS) {
|
||||
return;
|
||||
}
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
Int propType = -1;
|
||||
Int i;
|
||||
for (i=0; i<m_numPropTypes; i++) {
|
||||
if (m_propTypes[i].m_robjName.compareNoCase(modelName)==0) {
|
||||
propType = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (propType<0) {
|
||||
propType = addPropType(modelName);
|
||||
if (propType<0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix3D mtx(true);
|
||||
mtx.Rotate_Z(angle);
|
||||
mtx.Scale(scale);
|
||||
mtx.Set_Translation(Vector3(location.x, location.y, location.z));
|
||||
|
||||
m_props[m_numProps].location = location;
|
||||
m_props[m_numProps].id = id;
|
||||
m_props[m_numProps].ss = OBJECTSHROUD_INVALID;
|
||||
m_props[m_numProps].m_robj = m_propTypes[propType].m_robj->Clone();
|
||||
m_props[m_numProps].m_robj->Set_Transform(mtx);
|
||||
m_props[m_numProps].m_robj->Set_ObjectScale(scale);
|
||||
m_props[m_numProps].propType = propType;
|
||||
// Translate the bounding sphere of the model.
|
||||
m_props[m_numProps].bounds = m_propTypes[propType].m_bounds;
|
||||
m_props[m_numProps].bounds.Center += Vector3(location.x, location.y, location.z);
|
||||
// Initially set it invisible. cull will update it's visiblity flag.
|
||||
m_props[m_numProps].visible = false;
|
||||
|
||||
m_numProps++;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::updatePropPosition
|
||||
//=============================================================================
|
||||
/** Updates a prop's position */
|
||||
//=============================================================================
|
||||
Bool W3DPropBuffer::updatePropPosition(Int id, const Coord3D &location, Real angle, Real scale)
|
||||
{
|
||||
Int i;
|
||||
for (i=0; i<m_numProps; i++) {
|
||||
if (m_props[i].id == id) {
|
||||
Matrix3D mtx(true);
|
||||
mtx.Rotate_Z(angle);
|
||||
mtx.Scale(scale);
|
||||
mtx.Set_Translation(Vector3(location.x, location.y, location.z));
|
||||
m_props[i].location = location;
|
||||
m_props[i].m_robj->Set_Transform(mtx);
|
||||
m_props[i].m_robj->Set_ObjectScale(scale);
|
||||
// Translate the bounding sphere of the model.
|
||||
m_props[i].bounds = m_propTypes[m_props[i].propType].m_bounds;
|
||||
m_props[i].bounds.Center += Vector3(location.x, location.y, location.z);
|
||||
m_anythingChanged = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::removeProp
|
||||
//=============================================================================
|
||||
/** Removes a prop. */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::removeProp(Int id)
|
||||
{
|
||||
Int i;
|
||||
for (i=0; i<m_numProps; i++) {
|
||||
if (m_props[i].id == id) {
|
||||
m_props[i].location.set(0,0,0);
|
||||
m_props[i].propType = -1;
|
||||
REF_PTR_RELEASE(m_props[i].m_robj);
|
||||
// Translate the bounding sphere of the model.
|
||||
m_props[i].bounds.Center = Vector3(0,0,0);
|
||||
m_props[i].bounds.Radius = 1;
|
||||
m_anythingChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::removePropsForConstruction
|
||||
//=============================================================================
|
||||
/** Removes any props that would be under a building. */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::removePropsForConstruction(const Coord3D* pos, const GeometryInfo& geom, Real angle )
|
||||
{
|
||||
// Just iterate all trees, as even non-collidable ones get removed. jba. [7/11/2003]
|
||||
Int i;
|
||||
for (i=0; i<m_numProps; i++) {
|
||||
if (m_props[i].m_robj == NULL) {
|
||||
continue; // already deleted.
|
||||
}
|
||||
Real radius = m_props[i].bounds.Radius;
|
||||
GeometryInfo info(GEOMETRY_CYLINDER, false, 5*radius, 2*radius, 2*radius);
|
||||
if (ThePartitionManager->geomCollidesWithGeom( pos, geom, angle, &m_props[i].location, info, 0.0f)) {
|
||||
// remove it [7/11/2003]
|
||||
m_props[i].location.set(0,0,0);
|
||||
m_props[i].propType = -1;
|
||||
REF_PTR_RELEASE(m_props[i].m_robj);
|
||||
// Translate the bounding sphere of the model.
|
||||
m_props[i].bounds.Center = Vector3(0,0,0);
|
||||
m_props[i].bounds.Radius = 1;
|
||||
m_anythingChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::notifyShroudChanged
|
||||
//=============================================================================
|
||||
/** Sets the shroud to status, so it is recomputed. */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::notifyShroudChanged()
|
||||
{
|
||||
Int i;
|
||||
for (i=0; i<m_numProps; i++) {
|
||||
m_props[i].ss = ThePartitionManager?OBJECTSHROUD_INVALID:OBJECTSHROUD_CLEAR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DECLARE_PERF_TIMER(Prop_Render)
|
||||
|
||||
//=============================================================================
|
||||
// W3DPropBuffer::drawProps
|
||||
//=============================================================================
|
||||
/** Draws the props. Uses camera to cull. */
|
||||
//=============================================================================
|
||||
void W3DPropBuffer::drawProps(RenderInfoClass &rinfo)
|
||||
{
|
||||
USE_PERF_TIMER(Prop_Render)
|
||||
|
||||
Int i;
|
||||
if (m_doCull) {
|
||||
cull(&rinfo.Camera);
|
||||
}
|
||||
const GlobalData::TerrainLighting *objectLighting = TheGlobalData->m_terrainObjectsLighting[TheGlobalData->m_timeOfDay];
|
||||
|
||||
LightEnvironmentClass lightEnv;
|
||||
Vector3 center(0,0,0); // arbitrary center point. [6/6/2003]
|
||||
Vector3 ambient(objectLighting[0].ambient.red, objectLighting[0].ambient.green, objectLighting[0].ambient.blue);
|
||||
lightEnv.Reset(center, ambient);
|
||||
|
||||
Matrix3D mtx;
|
||||
const Vector3 zeroVector(0.0f, 0.0f, 0.0f);
|
||||
const Vector3 xVector(1.0f, 0.0f, 0.0f);
|
||||
const Vector3 yVector(0.0f, 1.0f, 0.0f);
|
||||
|
||||
for (i = 0; i < MAX_GLOBAL_LIGHTS; ++i)
|
||||
{
|
||||
m_light->Set_Ambient(zeroVector);
|
||||
m_light->Set_Diffuse(Vector3(objectLighting[i].diffuse.red,
|
||||
objectLighting[i].diffuse.green,
|
||||
objectLighting[i].diffuse.blue));
|
||||
m_light->Set_Specular(zeroVector);
|
||||
mtx.Set(xVector, yVector, Vector3(objectLighting[i].lightPos.x, objectLighting[i].lightPos.y, objectLighting[i].lightPos.z), zeroVector);
|
||||
m_light->Set_Transform(mtx);
|
||||
lightEnv.Add_Light(*m_light);
|
||||
}
|
||||
|
||||
rinfo.light_environment = &lightEnv;
|
||||
for (i=0; i<m_numProps; i++) {
|
||||
if (!m_props[i].visible) {
|
||||
continue;
|
||||
}
|
||||
if (m_props[i].m_robj==NULL) {
|
||||
continue;
|
||||
}
|
||||
if (!ThePlayerList || !ThePartitionManager) {
|
||||
// in Worldbuilder. No shroud either. jba. [6/9/2003]
|
||||
m_props[i].ss = OBJECTSHROUD_CLEAR;
|
||||
}
|
||||
if (m_props[i].ss == OBJECTSHROUD_INVALID) {
|
||||
Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
|
||||
m_props[i].ss = ThePartitionManager->getPropShroudStatusForPlayer(localPlayerIndex, &m_props[i].location);
|
||||
}
|
||||
if (m_props[i].ss >= OBJECTSHROUD_SHROUDED) {
|
||||
continue;
|
||||
}
|
||||
if (m_props[i].ss <= OBJECTSHROUD_INVALID) {
|
||||
continue;
|
||||
}
|
||||
if (TheTerrainRenderObject->getShroud() && m_props[i].ss != CELLSHROUD_CLEAR) {
|
||||
rinfo.Push_Material_Pass(m_propShroudMaterialPass);
|
||||
m_props[i].m_robj->Render(rinfo);
|
||||
rinfo.Pop_Material_Pass();
|
||||
} else {
|
||||
m_props[i].m_robj->Render(rinfo);
|
||||
}
|
||||
}
|
||||
rinfo.light_environment = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** CRC */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPropBuffer::crc( Xfer *xfer )
|
||||
{
|
||||
// empty. jba [8/11/2003]
|
||||
} // end CRC
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Xfer
|
||||
* Version Info:
|
||||
* 1: Initial version */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPropBuffer::xfer( Xfer *xfer )
|
||||
{
|
||||
|
||||
// version
|
||||
XferVersion currentVersion = 1;
|
||||
XferVersion version = currentVersion;
|
||||
xfer->xferVersion( &version, currentVersion );
|
||||
|
||||
|
||||
} // end xfer
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Load post process */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void W3DPropBuffer::loadPostProcess( void )
|
||||
{
|
||||
// empty. jba [8/11/2003]
|
||||
} // end loadPostProcess
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,816 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DShroud.cpp /////////////////////////////////////////////////////////////////////////////
|
||||
// Created: Mark Wilczynski, Jan 2002
|
||||
// Desc: Code to support rendering of shrouded units/terrain.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Lib/BaseType.h"
|
||||
#include "camera.h"
|
||||
#include "simplevec.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "common/MapObject.h"
|
||||
#include "common/PerfTimer.h"
|
||||
#include "W3DDevice/GameClient/HeightMap.h"
|
||||
#include "W3DDevice/GameClient/W3DPoly.h"
|
||||
#include "W3DDevice/GameClient/W3DShaderManager.h"
|
||||
#include "assetmgr.h"
|
||||
#include "W3DDevice/GameClient/W3DShroud.h"
|
||||
#include "WW3D2/textureloader.h"
|
||||
#include "common/GlobalData.h"
|
||||
#include "GameLogic/PartitionManager.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// In Global Data now
|
||||
|
||||
//#define SHROUD_COLOR 0x00ffffff //temporary test of gray shroud instead of pure black.
|
||||
//#define MIN_SHROUD_LEVEL 0 //for gray fog
|
||||
|
||||
//Int SHROUD_COLOR=0x00808080; //temporary test of gray shroud instead of pure black.
|
||||
//Int MIN_SHROUD_LEVEL=50; //for gray fog
|
||||
|
||||
//#define SHROUD_COLOR 0x00eeeebff //temporary test of gray shroud instead of pure black.
|
||||
//#define MIN_SHROUD_LEVEL 254 //for gray fog
|
||||
|
||||
//#define SHROUD_COLOR 0x00bbbbbb //temporary test of gray shroud instead of pure black.
|
||||
//#define SHROUD_COLOR 0x00004080 //temporary test of blue shroud instead of pure black.
|
||||
|
||||
//#define MIN_SHROUD_LEVEL 100 //for black fog
|
||||
|
||||
//#define MAX_MAP_SHROUDSIZE 1024 //maximum number of shroud cells across entire map.
|
||||
//#define MAX_VISIBLE_SHROUDSIZE (MAX_MAP_SHROUDSIZE+1) //maximum number of shroud vertices visible at any given time
|
||||
#define DEFAULT_SHROUD_CELL_SIZE MAP_XY_FACTOR //assume shroud at same resolution as terrain cells.
|
||||
#define DEFAULT_TERRAIN_SIZE 1024 //assumed size of largest terrain possible (in vertices)
|
||||
#define DEFAULT_VISIBLE_TERRAIN 96 //assumed size of visible terrain cells.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
W3DShroud::W3DShroud(void)
|
||||
{
|
||||
m_finalFogData=NULL;
|
||||
m_currentFogData=NULL;
|
||||
m_pSrcTexture=NULL;
|
||||
m_pDstTexture=NULL;
|
||||
m_srcTextureData=NULL;
|
||||
m_srcTexturePitch=NULL;
|
||||
m_dstTextureWidth=m_numMaxVisibleCellsX=0;
|
||||
m_dstTextureHeight=m_numMaxVisibleCellsY=0;
|
||||
m_boderShroudLevel = (W3DShroudLevel)TheGlobalData->m_shroudAlpha; //assume border is black
|
||||
m_clearDstTexture = TRUE; //force clearing of destination texture;
|
||||
|
||||
m_cellWidth=DEFAULT_SHROUD_CELL_SIZE;
|
||||
m_cellHeight=DEFAULT_SHROUD_CELL_SIZE;
|
||||
m_numCellsX=0;
|
||||
m_numCellsY=0;
|
||||
m_shroudFilter=TextureFilterClass::FILTER_TYPE_DEFAULT;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
W3DShroud::~W3DShroud(void)
|
||||
{
|
||||
ReleaseResources();
|
||||
if (m_pSrcTexture)
|
||||
m_pSrcTexture->Release();
|
||||
m_pSrcTexture=NULL;
|
||||
if (m_finalFogData)
|
||||
delete [] m_finalFogData;
|
||||
if (m_currentFogData)
|
||||
delete [] m_currentFogData;
|
||||
m_drawFogOfWar=FALSE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**Called to initialize a new shroud for a new map. Should be done after the map is loaded
|
||||
into the terrain object. worldCellSize is the world-space dimensions of each shroud cell.
|
||||
The system will generate enough cells to cover the full map.
|
||||
*/
|
||||
void W3DShroud::init(WorldHeightMap *pMap, Real worldCellSizeX, Real worldCellSizeY)
|
||||
{
|
||||
DEBUG_ASSERTCRASH( m_pSrcTexture == NULL, ("ReAcquire of existing shroud textures"));
|
||||
DEBUG_ASSERTCRASH( pMap != NULL, ("Shroud init with NULL WorldHeightMap"));
|
||||
|
||||
Int dstTextureWidth=0;
|
||||
Int dstTextureHeight=0;
|
||||
m_cellWidth=worldCellSizeX;
|
||||
m_cellHeight=worldCellSizeY;
|
||||
|
||||
//Precompute a bounding box for entire shroud layer
|
||||
if (pMap)
|
||||
{
|
||||
m_numCellsX = REAL_TO_INT_CEIL((Real)(pMap->getXExtent() - 1 - pMap->getBorderSizeInline()*2)*MAP_XY_FACTOR/m_cellWidth);
|
||||
m_numCellsY = REAL_TO_INT_CEIL((Real)(pMap->getYExtent() - 1 - pMap->getBorderSizeInline()*2)*MAP_XY_FACTOR/m_cellHeight);
|
||||
|
||||
//Maximum visible cells will depend on maximum drawable terrain size plus 1 for partial cells (since
|
||||
//shroud cells are larger than terrain cells).
|
||||
dstTextureWidth=m_numMaxVisibleCellsX=REAL_TO_INT_FLOOR((Real)(pMap->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1;
|
||||
dstTextureHeight=m_numMaxVisibleCellsY=REAL_TO_INT_FLOOR((Real)(pMap->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1;
|
||||
|
||||
dstTextureWidth = m_numCellsX;
|
||||
dstTextureHeight = m_numCellsY;
|
||||
|
||||
dstTextureWidth += 2; //enlarge by 2 pixels so we can have a border color all the way around.
|
||||
unsigned int depth = 1;
|
||||
dstTextureHeight += 2; //enlarge by 2 pixels so we can have border color all the way around.
|
||||
TextureLoader::Validate_Texture_Size((unsigned int &)dstTextureWidth,(unsigned int &)dstTextureHeight, depth);
|
||||
}
|
||||
|
||||
|
||||
UnsignedInt srcWidth,srcHeight;
|
||||
|
||||
srcWidth=m_numCellsX;
|
||||
//vertical size is larger by 1 pixel so that we have some unused pixels to use in clearing the video texture.
|
||||
//To clear the video texture, I will copy pixels from this unused area. There is no other way to clear a video
|
||||
//memory texture to a known value because you can't lock it - only copy into it.
|
||||
srcHeight=m_numCellsY;
|
||||
srcHeight += 1;
|
||||
|
||||
#ifdef DO_FOG_INTERPOLATION
|
||||
m_finalFogData = new W3DShroudLevel[srcWidth*srcHeight];
|
||||
m_currentFogData = new W3DShroudLevel[srcWidth*srcHeight];
|
||||
//Clear the fog to black
|
||||
memset(m_currentFogData,0,srcWidth*srcHeight);
|
||||
memset(m_finalFogData,0,srcWidth*srcHeight);
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
m_pSrcTexture = DX8Wrapper::_Create_DX8_Surface(srcWidth,srcHeight, WW3D_FORMAT_A4R4G4B4);
|
||||
else
|
||||
#endif
|
||||
m_pSrcTexture = DX8Wrapper::_Create_DX8_Surface(srcWidth,srcHeight, WW3D_FORMAT_R5G6B5);
|
||||
|
||||
DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Failed to Allocate Shroud Src Surface"));
|
||||
|
||||
D3DLOCKED_RECT rect;
|
||||
|
||||
//Get a pointer to source surface pixels.
|
||||
HRESULT res = m_pSrcTexture->LockRect(&rect,NULL,D3DLOCK_NO_DIRTY_UPDATE);
|
||||
m_pSrcTexture->UnlockRect();
|
||||
|
||||
DEBUG_ASSERTCRASH( res == D3D_OK, ("Failed to lock shroud src surface"));
|
||||
res = 0;// just to avoid compiler warnings
|
||||
|
||||
m_srcTextureData=rect.pBits;
|
||||
m_srcTexturePitch=rect.Pitch;
|
||||
|
||||
//clear entire texture to black
|
||||
memset(m_srcTextureData,0,m_srcTexturePitch*srcHeight);
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
fillShroudData(TheGlobalData->m_shroudAlpha); //initialize shroud to a known value
|
||||
#endif
|
||||
|
||||
if (dstTextureWidth != m_dstTextureWidth || dstTextureHeight != m_dstTextureHeight ) ///@todo: Check if size has changed - probably never
|
||||
ReleaseResources(); //need a new sized shroud
|
||||
|
||||
if (!m_pDstTexture )
|
||||
{ m_dstTextureWidth = dstTextureWidth;
|
||||
m_dstTextureHeight = dstTextureHeight;
|
||||
ReAcquireResources(); //allocate video memory surface
|
||||
}
|
||||
|
||||
//Force a refresh of shroud data since we just created a new source texture.
|
||||
if (ThePartitionManager)
|
||||
ThePartitionManager->refreshShroudForLocalPlayer();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Called on map reset.
|
||||
void W3DShroud::reset()
|
||||
{
|
||||
//Free old shroud data since it may no longer fit new map.
|
||||
if (m_pSrcTexture)
|
||||
m_pSrcTexture->Release();
|
||||
m_pSrcTexture=NULL;
|
||||
if (m_finalFogData)
|
||||
delete [] m_finalFogData;
|
||||
m_finalFogData=NULL;
|
||||
if (m_currentFogData)
|
||||
delete [] m_currentFogData;
|
||||
m_currentFogData=NULL;
|
||||
m_clearDstTexture = TRUE; //always refill the destination texture after a reset
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Release any resources that can't survive a D3D device reset.
|
||||
void W3DShroud::ReleaseResources(void)
|
||||
{
|
||||
REF_PTR_RELEASE (m_pDstTexture);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Restore resources that are lost on D3D device reset.
|
||||
Bool W3DShroud::ReAcquireResources(void)
|
||||
{
|
||||
if (!m_dstTextureWidth)
|
||||
return TRUE; //nothing to reaquire since shroud was never initialized with valid data
|
||||
|
||||
DEBUG_ASSERTCRASH( m_pDstTexture == NULL, ("ReAcquire of existing shroud texture"));
|
||||
|
||||
// Create destination texture (stored in video memory).
|
||||
// Since we control the video memory copy, we can do partial updates more efficiently. Or do shift blits.
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
m_pDstTexture = MSGNEW("TextureClass") TextureClass(m_dstTextureWidth,m_dstTextureHeight,WW3D_FORMAT_A4R4G4B4,MIP_LEVELS_1, TextureClass::POOL_DEFAULT);
|
||||
else
|
||||
#endif
|
||||
m_pDstTexture = MSGNEW("TextureClass") TextureClass(m_dstTextureWidth,m_dstTextureHeight,WW3D_FORMAT_R5G6B5,MIP_LEVELS_1, TextureClass::POOL_DEFAULT);
|
||||
|
||||
DEBUG_ASSERTCRASH( m_pDstTexture != NULL, ("Failed ReAcquire of shroud texture"));
|
||||
|
||||
if (!m_pDstTexture)
|
||||
{ //could not create a valid texture
|
||||
m_dstTextureWidth = 0;
|
||||
m_dstTextureHeight = 0;
|
||||
return FALSE;
|
||||
}
|
||||
m_pDstTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_pDstTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_pDstTexture->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE);
|
||||
m_clearDstTexture = TRUE; //force clearing of destination texture first time it's used.
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
W3DShroudLevel W3DShroud::getShroudLevel(Int x, Int y)
|
||||
{
|
||||
DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Reading empty shroud"));
|
||||
|
||||
if (x < m_numCellsX && y < m_numCellsY)
|
||||
{
|
||||
UnsignedShort pixel=*(UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch);
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
//in this mode, alpha channel holds intensity
|
||||
return (W3DShroudLevel)((1.0f-((Real)(pixel >> 12)/15.0f))*255.0f);
|
||||
else
|
||||
#endif
|
||||
//in this mode, green has the best precision at 6 bits.
|
||||
return (W3DShroudLevel)((Real)((pixel >> 5)&0x3f)/63.0f*255.0f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void W3DShroud::setShroudLevel(Int x, Int y, W3DShroudLevel level, Bool textureOnly)
|
||||
{
|
||||
DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Writing empty shroud. Usually means that map failed to load."));
|
||||
|
||||
if (!m_pSrcTexture)
|
||||
return;
|
||||
|
||||
if (x < m_numCellsX && y < m_numCellsY)
|
||||
{
|
||||
if (level < TheGlobalData->m_shroudAlpha)
|
||||
level = TheGlobalData->m_shroudAlpha;
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
{
|
||||
///@todo: optimize this case if we end up using fog shroud.
|
||||
Int redVal = TheGlobalData->m_shroudColor.red;
|
||||
Int greenVal = TheGlobalData->m_shroudColor.green;
|
||||
Int blueVal = TheGlobalData->m_shroudColor.blue;
|
||||
// Int redVal = (SHROUD_COLOR >> 16) & 0xff;
|
||||
// Int greenVal = (SHROUD_COLOR >> 8) & 0xff;
|
||||
// Int blueVal = SHROUD_COLOR & 0xff;
|
||||
Int alphaVal = 255 - level;
|
||||
|
||||
UnsignedShort pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
|
||||
*(UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch)=pixel;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef DO_FOG_INTERPOLATION
|
||||
if (!textureOnly)
|
||||
m_finalFogData[x+y*m_numCellsX]=level;
|
||||
#endif
|
||||
UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
|
||||
UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
|
||||
UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
|
||||
// UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(SHROUD_COLOR&0xff)/255.0f));
|
||||
// UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff00)>>8)/255.0f));
|
||||
// UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff0000)>>16)/255.0f));
|
||||
if (level == 255)
|
||||
{ //unshrouded pixels should be fully lit
|
||||
redpixel = 255;
|
||||
greenpixel = 255;
|
||||
bluepixel = 255;
|
||||
}
|
||||
|
||||
UnsignedShort *texel = (UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch);
|
||||
|
||||
// For those interested, MLorenzen has this bock commented out until he gets back on Mon, Sept. 30 2002
|
||||
// If this code is still here by mid october, nuke it!
|
||||
// UnsignedInt texelRed = ((*texel >> 8 ) & 0xf8);
|
||||
// UnsignedInt texelGreen =((*texel >> 3 ) & 0xfc);
|
||||
// UnsignedInt texelBlue = ((*texel << 3 ) & 0xf8);
|
||||
// if (texelRed < texelGreen && texelGreen > texelBlue)
|
||||
// {
|
||||
// bluepixel += redpixel;
|
||||
// bluepixel -= redpixel;
|
||||
// }
|
||||
|
||||
*texel = ( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Quickly sets the shroud level of entire map to a single value
|
||||
void W3DShroud::fillShroudData(W3DShroudLevel level)
|
||||
{
|
||||
|
||||
Int x,y;
|
||||
UnsignedShort pixel;
|
||||
|
||||
if (level < TheGlobalData->m_shroudAlpha)
|
||||
level = TheGlobalData->m_shroudAlpha;
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
//convert value to pixel format
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
{
|
||||
Int redVal = TheGlobalData->m_shroudColor.red;
|
||||
Int greenVal = TheGlobalData->m_shroudColor.green;
|
||||
Int blueVal = TheGlobalData->m_shroudColor.blue;
|
||||
// Int redVal = (SHROUD_COLOR >> 16) & 0xff;
|
||||
// Int greenVal = (SHROUD_COLOR >> 8) & 0xff;
|
||||
// Int blueVal = SHROUD_COLOR & 0xff;
|
||||
Int alphaVal = 255 - level;
|
||||
|
||||
pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
|
||||
UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
|
||||
UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
|
||||
// UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(SHROUD_COLOR&0xff)/255.0f));
|
||||
// UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff00)>>8)/255.0f));
|
||||
// UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff0000)>>16)/255.0f));
|
||||
|
||||
if (level == 255)
|
||||
{ //unshrouded pixels should be fully lit
|
||||
redpixel = 255;
|
||||
greenpixel = 255;
|
||||
bluepixel = 255;
|
||||
}
|
||||
pixel=( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
|
||||
}
|
||||
|
||||
UnsignedShort *ptr=(UnsignedShort *)m_srcTextureData;
|
||||
Int pitch = m_srcTexturePitch >> 1; //2 bytes per pointer increment
|
||||
for (y=0; y<m_numCellsY; y++)
|
||||
{
|
||||
for (x=0; x<m_numCellsX; x++)
|
||||
ptr[x]=pixel;
|
||||
ptr += pitch;
|
||||
}
|
||||
|
||||
#ifdef DO_FOG_INTERPOLATION
|
||||
//Set the final shroud state. May differe from current state because of time interpolation.
|
||||
W3DShroudLevel *cptr=m_finalFogData;
|
||||
pitch = m_numCellsX;
|
||||
for (y=0; y<m_numCellsY; y++)
|
||||
{
|
||||
for (x=0; x<m_numCellsX; x++)
|
||||
cptr[x]=level;
|
||||
ptr += pitch;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void W3DShroud::fillBorderShroudData(W3DShroudLevel level, SurfaceClass* pDestSurface)
|
||||
{
|
||||
Int x,y;
|
||||
UnsignedShort pixel;
|
||||
|
||||
if (level < TheGlobalData->m_shroudAlpha)
|
||||
level = TheGlobalData->m_shroudAlpha;
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
//convert value to pixel format
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
{
|
||||
Int redVal = TheGlobalData->m_shroudColor.red;
|
||||
Int greenVal = TheGlobalData->m_shroudColor.green;
|
||||
Int blueVal = TheGlobalData->m_shroudColor.blue;
|
||||
Int alphaVal = 255 - level;
|
||||
|
||||
pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
|
||||
UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
|
||||
UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
|
||||
|
||||
if (level == 255)
|
||||
{ //unshrouded pixels should be fully lit
|
||||
redpixel = 255;
|
||||
greenpixel = 255;
|
||||
bluepixel = 255;
|
||||
}
|
||||
pixel=( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
|
||||
}
|
||||
|
||||
//Skip to unused texels within the shroud data
|
||||
UnsignedShort *ptr=(UnsignedShort *)m_srcTextureData + m_numCellsY*(m_srcTexturePitch >> 1);
|
||||
|
||||
//Fill unused texels with border color
|
||||
for (x=0; x<m_numCellsX; x++)
|
||||
ptr[x]=pixel;
|
||||
|
||||
//Fill destination texture with border color
|
||||
|
||||
RECT srcRect;
|
||||
|
||||
//create a rectangle enclosing bottom row of unused pixels long enough
|
||||
//to cover destination width.
|
||||
srcRect.left=0;
|
||||
srcRect.top=m_numCellsY;
|
||||
srcRect.right= m_numCellsX;
|
||||
srcRect.bottom= m_numCellsY+1;
|
||||
|
||||
POINT dstPoint={0,0};
|
||||
|
||||
Int numFullCopies = m_dstTextureWidth/srcRect.right;
|
||||
Int numExtraPixels = m_dstTextureWidth%srcRect.right;
|
||||
|
||||
for (y=0; y<m_dstTextureHeight; y++)
|
||||
{
|
||||
dstPoint.y=y;
|
||||
dstPoint.x=0;
|
||||
|
||||
for (x=0; x<numFullCopies; x++)
|
||||
{
|
||||
dstPoint.x = x * srcRect.right; //advance to next set of pixel in row.
|
||||
|
||||
DX8Wrapper::_Copy_DX8_Rects(
|
||||
m_pSrcTexture,
|
||||
&srcRect,
|
||||
1,
|
||||
pDestSurface->Peek_D3D_Surface(),
|
||||
&dstPoint);
|
||||
}
|
||||
if (numExtraPixels)
|
||||
{ Int oldVal=srcRect.right;
|
||||
dstPoint.x = numFullCopies * oldVal;
|
||||
srcRect.right = numExtraPixels;
|
||||
DX8Wrapper::_Copy_DX8_Rects(
|
||||
m_pSrcTexture,
|
||||
&srcRect,
|
||||
1,
|
||||
pDestSurface->Peek_D3D_Surface(),
|
||||
&dstPoint);
|
||||
srcRect.right = oldVal;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**Set the shroud color within the border area of the map*/
|
||||
void W3DShroud::setBorderShroudLevel(W3DShroudLevel level)
|
||||
{
|
||||
m_boderShroudLevel = level;
|
||||
m_clearDstTexture = TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///@todo: remove this
|
||||
TextureClass *DummyTexture=NULL;
|
||||
|
||||
//#define LOAD_DUMMY_SHROUD
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//DECLARE_PERF_TIMER(shroudCopy)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates video memory surface with currently visible shroud data */
|
||||
void W3DShroud::render(CameraClass *cam)
|
||||
{
|
||||
if (!m_pSrcTexture)
|
||||
return; //nothing to update from. Must be in reset state.
|
||||
|
||||
if (DX8Wrapper::_Get_D3D_Device8() && (DX8Wrapper::_Get_D3D_Device8()->TestCooperativeLevel()) != D3D_OK)
|
||||
return; //device not ready to render anything
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn != m_drawFogOfWar)
|
||||
{
|
||||
//fog state has changed since last time shroud system was initialized
|
||||
reset();
|
||||
ReleaseResources();
|
||||
init(TheTerrainRenderObject->getMap(),m_cellWidth,m_cellHeight);
|
||||
ThePartitionManager->refreshShroudForLocalPlayer();
|
||||
m_drawFogOfWar=TheGlobalData->m_fogOfWarOn;
|
||||
m_clearDstTexture=TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Updating unallocated shroud texture"));
|
||||
|
||||
#ifdef LOAD_DUMMY_SHROUD
|
||||
|
||||
static doInit=1;
|
||||
if (doInit)
|
||||
{
|
||||
//some temporary code here to debug the shroud.
|
||||
|
||||
///@todo: remove this debug buffer fill.
|
||||
fillShroudData(1.0f); //force to all shrouded
|
||||
|
||||
Short *src=(Short *)m_srcTextureData;
|
||||
//fill with some dummy values
|
||||
src[0]=(char)0xff;
|
||||
src[1]=(char)0xff;
|
||||
src[m_numCellsX]=(char)0xff;
|
||||
src[m_numCellsX+1]=(char)0xff;
|
||||
src[m_numCellsX*2]=(char)0xff;
|
||||
|
||||
src[m_numCellsX*9+8]=(char)0xff;
|
||||
src[m_numCellsX*8+8]=(char)0xff;
|
||||
src[m_numCellsX*7+8]=(char)0xff;
|
||||
src[m_numCellsX*8+9]=(char)0xff;
|
||||
src[m_numCellsX*8+7]=(char)0xff;
|
||||
|
||||
DummyTexture=WW3DAssetManager::Get_Instance()->Get_Texture("shroud1024.tga");
|
||||
|
||||
Short *dataDest=(Short *)((char *)m_srcTextureData); //offset to correct row of full sysmem shroud
|
||||
Int pitchDest = m_srcTexturePitch >> 1; //2 bytes per pixel so divide byte count by 2.
|
||||
|
||||
//Copy the dummy shroud into our game shroud.
|
||||
SurfaceClass *pSurface=DummyTexture->Get_Surface_Level(0);
|
||||
Int pitch;
|
||||
Int *dataSrc=(Int *)((char *)pSurface->Lock(&pitch)); //offset to correct row of full sysmem shroud
|
||||
pitch >>= 2; //4 bytes per pixel so divide byte count by 4.
|
||||
SurfaceClass::SurfaceDescription desc;
|
||||
pSurface->Get_Description(desc);
|
||||
|
||||
//Check if source data is larger than our current shroud
|
||||
desc.Width = __min(desc.Width,m_numCellsX);
|
||||
desc.Height = __min(desc.Height,m_numCellsY);
|
||||
|
||||
for (Int y=0; y<desc.Height; y++)
|
||||
{
|
||||
for (Int x=0; x<desc.Width; x++)
|
||||
{
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
|
||||
{
|
||||
dataDest[x]=((TheGlobalData->m_shroudColor.getAsInt()>>4)&0xf) | (((TheGlobalData->m_shroudColor.getAsInt()>>12)&0xf)<<4) | (((TheGlobalData->m_shroudColor.getAsInt()>>20)&0xf)<<8) | ((((255-(dataSrc[x] & 0xff))>>4)&0xf)<<12);
|
||||
// dataDest[x]=((SHROUD_COLOR>>4)&0xf) | (((SHROUD_COLOR>>12)&0xf)<<4) | (((SHROUD_COLOR>>20)&0xf)<<8) | ((((255-(dataSrc[x] & 0xff))>>4)&0xf)<<12);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
dataDest[x]=((dataSrc[x]>>3)&0x1f) | (((dataSrc[x]>>10)&0x3f)<<5) | (((dataSrc[x]>>19)&0x1f)<<11);
|
||||
}
|
||||
}
|
||||
|
||||
dataDest += pitchDest; //skip to next row.
|
||||
dataSrc += pitch; //skip to next row of shroud
|
||||
}
|
||||
|
||||
pSurface->Unlock();
|
||||
|
||||
REF_PTR_RELEASE (pSurface);
|
||||
REF_PTR_RELEASE (DummyTexture);
|
||||
|
||||
doInit=0;
|
||||
}
|
||||
|
||||
#endif //LOAD_DUMMY_SHROUD
|
||||
|
||||
|
||||
WorldHeightMap *hm=TheTerrainRenderObject->getMap();
|
||||
Int visStartX=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgX()-hm->getBorderSizeInline())*MAP_XY_FACTOR/m_cellWidth); //start of rendered heightmap rectangle
|
||||
if (visStartX < 0)
|
||||
visStartX = 0; //no shroud is applied in border area so it always starts at > 0
|
||||
Int visStartY=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgY()-hm->getBorderSizeInline())*MAP_XY_FACTOR/m_cellHeight);
|
||||
if (visStartY < 0)
|
||||
visStartY = 0; //no shroud is applied in border area so it always starts at > 0
|
||||
|
||||
// Do it all [3/11/2003]
|
||||
visStartX = 0;
|
||||
visStartY = 0;
|
||||
|
||||
Int visEndX=visStartX+REAL_TO_INT_FLOOR((Real)(hm->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; //size of rendered heightmap rectangle
|
||||
Int visEndY=visStartY+REAL_TO_INT_FLOOR((Real)(hm->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1;
|
||||
|
||||
// Do it all [3/11/2003]
|
||||
visEndX = m_numCellsX;
|
||||
visEndY = m_numCellsY;
|
||||
|
||||
if (visEndX > m_numCellsX)
|
||||
{
|
||||
visStartX -= visEndX - m_numCellsX; //shift visible rectangle to fall within terrain bounds
|
||||
if (visStartX < 0)
|
||||
visStartX = 0;
|
||||
visEndX = m_numCellsX;
|
||||
}
|
||||
|
||||
if (visEndY > m_numCellsY)
|
||||
{
|
||||
visStartY -= visEndY - m_numCellsY; //shift visible rectangle to fall within terrain bounds
|
||||
if (visStartY < 0)
|
||||
visStartY = 0;
|
||||
visEndY = m_numCellsY;
|
||||
}
|
||||
|
||||
m_drawOriginX = (Real)visStartX * m_cellWidth;
|
||||
m_drawOriginY = (Real)visStartY * m_cellHeight;
|
||||
|
||||
//If system memory usage becomes too large, we should store shroud as Bytes. Update
|
||||
//a system memory texture with data. Then copy this to video memory. For now we're
|
||||
//holding shroud data directly in a texture to avoid the extra copy.
|
||||
/* pSurface=m_pSrcTexture->Get_Surface_Level(0);
|
||||
data=(Short *)((char *)pSurface->Lock(&pitch) + visStartY*pitch); //offset to correct row of full sysmem shroud
|
||||
pitch >>= 1; //we have 2 bytes per pixel, so divide pitch by 2
|
||||
|
||||
Byte *sd=shroudData+visStartY*MAX_MAP_SHROUDSIZE; //pointer to first shroud row
|
||||
|
||||
for (Int y=visStartY; y<(visStartY+visSizeY); y++)
|
||||
{
|
||||
for (Int x=visStartX; x<(visStartX+visSizeX); x++)
|
||||
{
|
||||
data[x]=sd[x]|(sd[x]<<8);
|
||||
}
|
||||
data += pitch; //skip to next row.
|
||||
sd += MAX_MAP_SHROUDSIZE; //skip to next row of shroud
|
||||
}
|
||||
|
||||
pSurface->Unlock();
|
||||
*/
|
||||
if (m_pDstTexture->Get_Filter().Get_Mag_Filter() != m_shroudFilter)
|
||||
{
|
||||
m_pDstTexture->Get_Filter().Set_Mag_Filter(m_shroudFilter);
|
||||
m_pDstTexture->Get_Filter().Set_Min_Filter(m_shroudFilter);
|
||||
}
|
||||
|
||||
//Update video memory texture with sysmem copy
|
||||
SurfaceClass* pDestSurface;
|
||||
{
|
||||
pDestSurface=m_pDstTexture->Get_Surface_Level(0);
|
||||
}
|
||||
|
||||
RECT srcRect;
|
||||
POINT dstPoint={1,1}; //first row/column is reserved for border.
|
||||
|
||||
srcRect.left=visStartX;
|
||||
srcRect.top=visStartY;
|
||||
srcRect.right=visEndX;
|
||||
srcRect.bottom=visEndY;
|
||||
|
||||
#ifdef DO_FOG_INTERPOLATION
|
||||
//interpolate current shroud state to the final one
|
||||
interpolateFogLevels(&srcRect);
|
||||
#endif
|
||||
|
||||
if (m_clearDstTexture)
|
||||
{ //we need to clear unused parts of the destination texture to a known
|
||||
//color in order to keep map border in the state we want.
|
||||
m_clearDstTexture=FALSE;
|
||||
|
||||
fillBorderShroudData(m_boderShroudLevel, pDestSurface);
|
||||
}
|
||||
|
||||
{
|
||||
//USE_PERF_TIMER(shroudCopy)
|
||||
DX8Wrapper::_Copy_DX8_Rects(
|
||||
m_pSrcTexture,
|
||||
&srcRect,
|
||||
1,
|
||||
pDestSurface->Peek_D3D_Surface(),
|
||||
&dstPoint);
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE (pDestSurface);
|
||||
}
|
||||
|
||||
#define FOG_INTERPOLATION_RATE (255.0f/1000.0f) //take one second to go from black to fully lit.
|
||||
//-----------------------------------------------------------------------------
|
||||
void W3DShroud::interpolateFogLevels(RECT *rect)
|
||||
{
|
||||
static UnsignedInt prevTime = timeGetTime();
|
||||
|
||||
UnsignedInt timeDiff=timeGetTime()-prevTime;
|
||||
|
||||
if (!timeDiff)
|
||||
return; //no time has elapsed
|
||||
|
||||
prevTime +=timeDiff; //update for next frame
|
||||
|
||||
Int maxFogChange=FOG_INTERPOLATION_RATE * (Real)timeDiff; //maximum amount of fog change allowed in frame.
|
||||
if (maxFogChange > 255)
|
||||
maxFogChange = 255;
|
||||
W3DShroudLevel levelDelta = maxFogChange;
|
||||
|
||||
W3DShroudLevel *startLevel=m_currentFogData;
|
||||
W3DShroudLevel *finalLevel=m_finalFogData;
|
||||
|
||||
for (Int j=0; j<m_numCellsY; j++)
|
||||
{
|
||||
for (Int i=0; i<m_numCellsX; i++,startLevel++,finalLevel++)
|
||||
if (*startLevel != *finalLevel)
|
||||
{ //fog needs fading.
|
||||
if (*startLevel == *finalLevel)
|
||||
continue;
|
||||
else
|
||||
if (*finalLevel < *startLevel)
|
||||
{
|
||||
if ((*startLevel - *finalLevel) < levelDelta)
|
||||
*startLevel = *finalLevel; //change too large so clamp to final value.
|
||||
else
|
||||
*startLevel -= levelDelta;
|
||||
}
|
||||
else
|
||||
if (*finalLevel > *startLevel)
|
||||
{
|
||||
if ((*finalLevel - *startLevel) < levelDelta)
|
||||
*startLevel = *finalLevel; //change too large so clamp to final value.
|
||||
else
|
||||
*startLevel += levelDelta;
|
||||
}
|
||||
setShroudLevel(i,j,*startLevel,TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void W3DShroud::setShroudFilter(Bool enable)
|
||||
{
|
||||
if (enable)
|
||||
m_shroudFilter=TextureFilterClass::FILTER_TYPE_DEFAULT;
|
||||
else
|
||||
m_shroudFilter=TextureFilterClass::FILTER_TYPE_NONE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Set render states required to draw shroud pass.
|
||||
void W3DShroudMaterialPassClass::Install_Materials(void) const
|
||||
{
|
||||
if (TheTerrainRenderObject->getShroud())
|
||||
{
|
||||
W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture());
|
||||
W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Restore render states that W3D doesn't know about.
|
||||
void W3DShroudMaterialPassClass::UnInstall_Materials(void) const
|
||||
{
|
||||
W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Set render states required to draw shroud pass.
|
||||
void W3DMaskMaterialPassClass::Install_Materials(void) const
|
||||
{
|
||||
W3DShaderManager::setShader(W3DShaderManager::ST_MASK_TEXTURE, 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///Restore render states that W3D doesn't know about.
|
||||
void W3DMaskMaterialPassClass::UnInstall_Materials(void) const
|
||||
{
|
||||
if (m_allowUninstall)
|
||||
W3DShaderManager::resetShader(W3DShaderManager::ST_MASK_TEXTURE);
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// W3DSmudge.cpp ////////////////////////////////////////////////////////////////////////////////
|
||||
// Smudge System implementation
|
||||
// Author: Mark Wilczynski, June 2003
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Lib/Basetype.h"
|
||||
#include "always.h"
|
||||
#include "W3DDevice/GameClient/W3DSmudge.h"
|
||||
#include "W3DDevice/GameClient/W3DShaderManager.h"
|
||||
#include "Common/GameMemory.h"
|
||||
#include "GameClient/view.h"
|
||||
#include "GameClient/display.h"
|
||||
#include "WW3D2/texture.h"
|
||||
#include "WW3D2/dx8indexbuffer.h"
|
||||
#include "WW3D2/dx8wrapper.h"
|
||||
#include "WW3D2/rinfo.h"
|
||||
#include "WW3D2/camera.h"
|
||||
#include "WW3D2/sortingrenderer.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
SmudgeManager *TheSmudgeManager=NULL;
|
||||
|
||||
W3DSmudgeManager::W3DSmudgeManager(void)
|
||||
{
|
||||
}
|
||||
|
||||
W3DSmudgeManager::~W3DSmudgeManager()
|
||||
{
|
||||
ReleaseResources();
|
||||
}
|
||||
|
||||
void W3DSmudgeManager::init(void)
|
||||
{
|
||||
SmudgeManager::init();
|
||||
ReAcquireResources();
|
||||
}
|
||||
|
||||
void W3DSmudgeManager::reset (void)
|
||||
{
|
||||
SmudgeManager::reset(); //base
|
||||
}
|
||||
|
||||
void W3DSmudgeManager::ReleaseResources(void)
|
||||
{
|
||||
#ifdef USE_COPY_RECTS
|
||||
REF_PTR_RELEASE(m_backgroundTexture);
|
||||
#endif
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
}
|
||||
|
||||
//Make sure (SMUDGE_DRAW_SIZE * 12) < 65535 because that's the max index buffer size.
|
||||
#define SMUDGE_DRAW_SIZE 500 //draw at most 50 smudges per call. Tweak value to improve CPU/GPU parallelism.
|
||||
|
||||
void W3DSmudgeManager::ReAcquireResources(void)
|
||||
{
|
||||
ReleaseResources();
|
||||
|
||||
SurfaceClass *surface=DX8Wrapper::_Get_DX8_Back_Buffer();
|
||||
SurfaceClass::SurfaceDescription surface_desc;
|
||||
|
||||
surface->Get_Description(surface_desc);
|
||||
REF_PTR_RELEASE(surface);
|
||||
|
||||
#ifdef USE_COPY_RECTS
|
||||
m_backgroundTexture = MSGNEW("TextureClass") TextureClass(TheTacticalView->getWidth(),TheTacticalView->getHeight(),surface_desc.Format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT, true);
|
||||
#endif
|
||||
|
||||
m_backBufferWidth = surface_desc.Width;
|
||||
m_backBufferHeight = surface_desc.Height;
|
||||
|
||||
m_indexBuffer=NEW_REF(DX8IndexBufferClass,(SMUDGE_DRAW_SIZE*4*3)); //allocate 4 triangles per smudge, each with 3 indices.
|
||||
|
||||
// Fill up the IB with static vertex indices that will be used for all smudges.
|
||||
{
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer);
|
||||
UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
|
||||
//quad of 4 triangles:
|
||||
// 0-----3
|
||||
// |\ /|
|
||||
// | 4 |
|
||||
// |/ \|
|
||||
// 1-----2
|
||||
Int vbCount=0;
|
||||
for (Int i=0; i<SMUDGE_DRAW_SIZE; i++)
|
||||
{
|
||||
//Top
|
||||
ib[0]=vbCount;
|
||||
ib[1]=vbCount+4;
|
||||
ib[2]=vbCount+3;
|
||||
//Right
|
||||
ib[3]=vbCount+3;
|
||||
ib[4]=vbCount+4;
|
||||
ib[5]=vbCount+2;
|
||||
//Bottom
|
||||
ib[6]=vbCount+2;
|
||||
ib[7]=vbCount+4;
|
||||
ib[8]=vbCount+1;
|
||||
//Left
|
||||
ib[9]=vbCount+1;
|
||||
ib[10]=vbCount+4;
|
||||
ib[11]=vbCount+0;
|
||||
|
||||
vbCount += 5;
|
||||
ib+=12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Copies a portion of the current render target into a specified buffer*/
|
||||
Int copyRect(unsigned char *buf, Int bufSize, int oX, int oY, int width, int height)
|
||||
{
|
||||
IDirect3DSurface8 *surface=NULL; ///<previous render target
|
||||
IDirect3DSurface8 *tempSurface=NULL;
|
||||
Int result = 0;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
|
||||
|
||||
if (!m_pDev)
|
||||
goto error;
|
||||
|
||||
m_pDev->GetRenderTarget(&surface);
|
||||
|
||||
if (!surface)
|
||||
goto error;
|
||||
|
||||
D3DSURFACE_DESC desc;
|
||||
|
||||
surface->GetDesc(&desc);
|
||||
|
||||
RECT srcRect;
|
||||
srcRect.left=oX;
|
||||
srcRect.top=oY;
|
||||
srcRect.right=oX+width;
|
||||
srcRect.bottom=oY+height;
|
||||
|
||||
POINT dstPoint;
|
||||
dstPoint.x=0;
|
||||
dstPoint.y=0;
|
||||
|
||||
hr=m_pDev->CreateImageSurface( width, height, desc.Format, &tempSurface);
|
||||
|
||||
if (hr != S_OK)
|
||||
goto error;
|
||||
|
||||
hr=m_pDev->CopyRects(surface,&srcRect,1,tempSurface,&dstPoint);
|
||||
|
||||
if (hr != S_OK)
|
||||
goto error;
|
||||
|
||||
D3DLOCKED_RECT lrect;
|
||||
|
||||
hr=tempSurface->LockRect(&lrect,NULL,D3DLOCK_READONLY);
|
||||
|
||||
if (hr != S_OK)
|
||||
goto error;
|
||||
|
||||
tempSurface->GetDesc(&desc);
|
||||
|
||||
if (desc.Size < bufSize)
|
||||
bufSize = desc.Size;
|
||||
|
||||
memcpy(buf,lrect.pBits,bufSize);
|
||||
result = bufSize;
|
||||
|
||||
error:
|
||||
if (surface)
|
||||
surface->Release();
|
||||
if (tempSurface)
|
||||
tempSurface->Release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define UNIQUE_COLOR (0x12345678)
|
||||
#define BLOCK_SIZE (8)
|
||||
|
||||
Bool W3DSmudgeManager::testHardwareSupport(void)
|
||||
{
|
||||
if (m_hardwareSupportStatus == SMUDGE_SUPPORT_UNKNOWN)
|
||||
{ //we have not done the test yet.
|
||||
|
||||
IDirect3DTexture8 *backTexture=W3DShaderManager::getRenderTexture();
|
||||
if (!backTexture)
|
||||
{ //do trivial test first to see if render target exists.
|
||||
m_hardwareSupportStatus = SMUDGE_SUPPORT_NO;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!W3DShaderManager::isRenderingToTexture())
|
||||
return FALSE; //can't do the test unless we're rendering to texture.
|
||||
|
||||
VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
DX8Wrapper::Set_Material(vmat);
|
||||
REF_PTR_RELEASE(vmat); //no need to keep a reference since it's a preset.
|
||||
|
||||
ShaderClass shader=ShaderClass::_PresetOpaqueShader;
|
||||
shader.Set_Depth_Compare(ShaderClass::PASS_ALWAYS);
|
||||
shader.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE);
|
||||
DX8Wrapper::Set_Shader(shader);
|
||||
DX8Wrapper::Set_Texture(0,NULL);
|
||||
DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices
|
||||
|
||||
struct _TRANS_LIT_TEX_VERTEX {
|
||||
Vector4 p;
|
||||
DWORD color; // diffuse color
|
||||
float u;
|
||||
float v;
|
||||
} v[4];
|
||||
|
||||
//bottom right
|
||||
v[0].p = Vector4( BLOCK_SIZE-0.5f, BLOCK_SIZE-0.5f, 0.0f, 1.0f );
|
||||
v[0].u = BLOCK_SIZE/(Real)TheDisplay->getWidth(); v[0].v = BLOCK_SIZE/(Real)TheDisplay->getHeight();;
|
||||
//top right
|
||||
v[1].p = Vector4( BLOCK_SIZE-0.5f, 0-0.5f, 0.0f, 1.0f );
|
||||
v[1].u = BLOCK_SIZE/(Real)TheDisplay->getWidth(); v[1].v = 0;
|
||||
//bottom left
|
||||
v[2].p = Vector4( 0-0.5f, BLOCK_SIZE-0.5f, 0.0f, 1.0f );
|
||||
v[2].u = 0; v[2].v = BLOCK_SIZE/(Real)TheDisplay->getHeight();
|
||||
//top left
|
||||
v[3].p = Vector4( 0-0.5f, 0-0.5f, 0.0f, 1.0f );
|
||||
v[3].u = 0; v[3].v = 0;
|
||||
|
||||
v[0].color = UNIQUE_COLOR;
|
||||
v[1].color = UNIQUE_COLOR;
|
||||
v[2].color = UNIQUE_COLOR;
|
||||
v[3].color = UNIQUE_COLOR;
|
||||
|
||||
LPDIRECT3DDEVICE8 pDev=DX8Wrapper::_Get_D3D_Device8();
|
||||
|
||||
//draw polygons like this is very inefficient but for only 2 triangles, it's
|
||||
//not worth bothering with index/vertex buffers.
|
||||
pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
|
||||
|
||||
pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANS_LIT_TEX_VERTEX));
|
||||
|
||||
DWORD refData[BLOCK_SIZE*BLOCK_SIZE];
|
||||
memset(refData,0,sizeof(refData));
|
||||
Int bufSize=copyRect((unsigned char *)refData,sizeof(refData),0,0,BLOCK_SIZE,BLOCK_SIZE); //copy area we just rendered using solid color
|
||||
if (!bufSize)
|
||||
{
|
||||
m_hardwareSupportStatus = SMUDGE_SUPPORT_NO;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DX8Wrapper::Set_DX8_Texture(0,backTexture);
|
||||
|
||||
DWORD testData[BLOCK_SIZE*BLOCK_SIZE];
|
||||
memset(testData,0xff,sizeof(testData));
|
||||
|
||||
v[0].color = 0xffffffff;
|
||||
v[1].color = 0xffffffff;
|
||||
v[2].color = 0xffffffff;
|
||||
v[3].color = 0xffffffff;
|
||||
|
||||
pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANS_LIT_TEX_VERTEX));
|
||||
bufSize=copyRect((unsigned char *)testData,sizeof(testData),0,0,BLOCK_SIZE,BLOCK_SIZE);
|
||||
|
||||
if (!bufSize)
|
||||
{
|
||||
m_hardwareSupportStatus = SMUDGE_SUPPORT_NO;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//compare the 2 buffers to see if they match.
|
||||
if (memcmp(testData,refData,bufSize) == 0)
|
||||
{
|
||||
m_hardwareSupportStatus = SMUDGE_SUPPORT_YES;
|
||||
return TRUE;
|
||||
}
|
||||
m_hardwareSupportStatus = SMUDGE_SUPPORT_NO;
|
||||
}
|
||||
|
||||
return (SMUDGE_SUPPORT_YES == m_hardwareSupportStatus);
|
||||
}
|
||||
|
||||
void W3DSmudgeManager::render(RenderInfoClass &rinfo)
|
||||
{
|
||||
//Verify that the card supports the effect.
|
||||
if (!testHardwareSupport())
|
||||
return;
|
||||
|
||||
CameraClass &camera=rinfo.Camera;
|
||||
Vector3 vsVert;
|
||||
Vector4 ssVert;
|
||||
Real uvSpanX,uvSpanY;
|
||||
Vector3 vertex_offsets[4] = {
|
||||
Vector3(-0.5f, 0.5f, 0.0f),
|
||||
Vector3(-0.5f, -0.5f, 0.0f),
|
||||
Vector3(0.5f, -0.5f, 0.0f),
|
||||
Vector3(0.5f, 0.5f, 0.0f)
|
||||
};
|
||||
|
||||
#define THE_COLOR (0x00ffeedd)
|
||||
|
||||
UnsignedInt vertexDiffuse[5]={THE_COLOR,THE_COLOR,THE_COLOR,THE_COLOR,THE_COLOR};
|
||||
|
||||
Matrix4x4 proj;
|
||||
Matrix3D view;
|
||||
|
||||
camera.Get_View_Matrix(&view);
|
||||
camera.Get_Projection_Matrix(&proj);
|
||||
|
||||
SurfaceClass::SurfaceDescription surface_desc;
|
||||
#ifdef USE_COPY_RECTS
|
||||
SurfaceClass *background=m_backgroundTexture->Get_Surface_Level();
|
||||
background->Get_Description(surface_desc);
|
||||
#else
|
||||
D3DSURFACE_DESC D3DDesc;
|
||||
|
||||
IDirect3DTexture8 *backTexture=W3DShaderManager::getRenderTexture();
|
||||
if (!backTexture || !W3DShaderManager::isRenderingToTexture())
|
||||
return; //this card doesn't support render targets.
|
||||
|
||||
backTexture->GetLevelDesc(0,&D3DDesc);
|
||||
|
||||
surface_desc.Width = D3DDesc.Width;
|
||||
surface_desc.Height = D3DDesc.Height;
|
||||
#endif
|
||||
|
||||
Real texClampX = (Real)TheTacticalView->getWidth()/(Real)surface_desc.Width;
|
||||
Real texClampY = (Real)TheTacticalView->getHeight()/(Real)surface_desc.Height;
|
||||
|
||||
Real texScaleX = texClampX*0.5f;
|
||||
Real texScaleY = texClampY*0.5f;
|
||||
|
||||
//Do a first pass over the smudges to determine how many are visible
|
||||
//and to fill in their world-space positions and screen uv coordinates.
|
||||
//TODO: Optimize out this extra pass!
|
||||
//TODO: Find size of screen rectangle that actually needs copying.
|
||||
|
||||
SmudgeSet *set=m_usedSmudgeSetList.Head(); //first set that didn't fit into render batch.
|
||||
Int count = 0;
|
||||
|
||||
if (set)
|
||||
{ //there are possibly some smudges to render, so make sure background particles have finished drawing.
|
||||
SortingRendererClass::Flush(); //draw sorted translucent polys like particles.
|
||||
}
|
||||
|
||||
while (set)
|
||||
{
|
||||
Smudge *smudge=set->getUsedSmudgeList().Head();
|
||||
|
||||
while (smudge)
|
||||
{
|
||||
//Get view-space center
|
||||
Matrix3D::Transform_Vector(view,smudge->m_pos,&vsVert);
|
||||
|
||||
//Get 5 view-space vertices
|
||||
Smudge::smudgeVertex *verts=smudge->m_verts;
|
||||
|
||||
//Do center vertex outside 'for' loop since it's different.
|
||||
verts[4].pos = vsVert;
|
||||
|
||||
for (Int i=0; i<4; i++)
|
||||
{
|
||||
verts[i].pos = vsVert + vertex_offsets[i] * smudge->m_size;
|
||||
//Ge uv coordinates for each vertex
|
||||
ssVert = proj * verts[i].pos;
|
||||
Real oow = 1.0f/ssVert.W;
|
||||
ssVert *= oow; //returned in camera space which is -1,-1 (bottom-left) to 1,1 (top-right)
|
||||
//convert camera space to uv space: 0,0 (top-left), 1,1 (bottom-right)
|
||||
verts[i].uv.Set((ssVert.X+1.0f)*texScaleX,(1.0f-ssVert.Y)*texScaleY);
|
||||
|
||||
Vector2 &thisUV=verts[i].uv;
|
||||
|
||||
//Clamp coordinates so we're not referencing texels outside the view.
|
||||
if (thisUV.X > texClampX)
|
||||
smudge->m_offset.X = 0;
|
||||
else
|
||||
if (thisUV.X < 0)
|
||||
smudge->m_offset.X = 0;
|
||||
|
||||
if (thisUV.Y > texClampY)
|
||||
smudge->m_offset.Y = 0;
|
||||
else
|
||||
if (thisUV.Y < 0)
|
||||
smudge->m_offset.Y = 0;
|
||||
|
||||
}
|
||||
|
||||
//Finish center vertex
|
||||
//Ge uv coordinates by interpolating corner uv coordinates and applying desired offset.
|
||||
uvSpanX=verts[3].uv.X - verts[0].uv.X;
|
||||
uvSpanY=verts[1].uv.Y - verts[0].uv.Y;
|
||||
verts[4].uv.X=verts[0].uv.X+uvSpanX*(0.5f+smudge->m_offset.X);
|
||||
verts[4].uv.Y=verts[0].uv.Y+uvSpanY*(0.5f+smudge->m_offset.X);
|
||||
|
||||
count++; //increment visible smudge count.
|
||||
smudge=smudge->Succ();
|
||||
}
|
||||
|
||||
set=set->Succ(); //advance to next node.
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
#ifdef USE_COPY_RECTS
|
||||
REF_PTR_RELEASE(background);
|
||||
#endif
|
||||
return; //nothing to render.
|
||||
}
|
||||
|
||||
#ifdef USE_COPY_RECTS
|
||||
SurfaceClass *backBuffer=DX8Wrapper::_Get_DX8_Back_Buffer();
|
||||
|
||||
backBuffer->Get_Description(surface_desc);
|
||||
|
||||
//Copy the area of backbuffer occupied by smudges into an alternate buffer.
|
||||
background->Copy(0,0,0,0,surface_desc.Width,surface_desc.Height,backBuffer);
|
||||
|
||||
REF_PTR_RELEASE(background);
|
||||
REF_PTR_RELEASE(backBuffer);
|
||||
#endif
|
||||
|
||||
Matrix4x4 identity(true);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,identity);
|
||||
DX8Wrapper::Set_Transform(D3DTS_VIEW,identity);
|
||||
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
|
||||
//DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueSpriteShader);
|
||||
|
||||
DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader);
|
||||
#ifdef USE_COPY_RECTS
|
||||
DX8Wrapper::Set_Texture(0,m_backgroundTexture);
|
||||
#else
|
||||
DX8Wrapper::Set_DX8_Texture(0,backTexture);
|
||||
//Need these states in case texture is non-power-of-2
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSW, D3DTADDRESS_CLAMP);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
|
||||
#endif
|
||||
VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
DX8Wrapper::Set_Material(vmat);
|
||||
REF_PTR_RELEASE(vmat);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
//Disable reading texture alpha since it's undefined.
|
||||
//DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2);
|
||||
|
||||
Int smudgesRemaining=count;
|
||||
set=m_usedSmudgeSetList.Head(); //first smudge set that needs rendering.
|
||||
Smudge *remainingSmudgeStart=set->getUsedSmudgeList().Head(); //first smudge that needs rendering.
|
||||
|
||||
while (smudgesRemaining) //keep drawing smudges until we run out.
|
||||
{
|
||||
//Now that we know how many smudges need rendering, allocate vertex buffer space and copy verts.
|
||||
count=smudgesRemaining;
|
||||
|
||||
if (count > SMUDGE_DRAW_SIZE)
|
||||
count = SMUDGE_DRAW_SIZE;
|
||||
|
||||
Int smudgesInRenderBatch=0;
|
||||
|
||||
DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,count*5); //allocate 5 verts per smudge.
|
||||
{
|
||||
DynamicVBAccessClass::WriteLockClass lock(&vb_access);
|
||||
VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array();
|
||||
|
||||
while (set)
|
||||
{
|
||||
Smudge *smudge=remainingSmudgeStart;
|
||||
|
||||
while (smudge)
|
||||
{
|
||||
Smudge::smudgeVertex *smVerts = smudge->m_verts;
|
||||
|
||||
//Check if we exceeded maximum number of smudges allowed per draw call.
|
||||
if (smudgesInRenderBatch >= count)
|
||||
{ remainingSmudgeStart = smudge;
|
||||
goto flushSmudges;
|
||||
}
|
||||
|
||||
//Set center vertex opacity.
|
||||
vertexDiffuse[4] = ((Int)(smudge->m_opacity * 255.0f) << 24) | THE_COLOR;
|
||||
|
||||
for (Int i=0; i<5; i++)
|
||||
{
|
||||
verts->x=smVerts->pos.X;
|
||||
verts->y=smVerts->pos.Y;
|
||||
verts->z=smVerts->pos.Z;
|
||||
verts->nx=0; //keep AGP write-combining active
|
||||
verts->ny=0;
|
||||
verts->nz=0;
|
||||
verts->diffuse=vertexDiffuse[i]; //set to transparent
|
||||
verts->u1=smVerts->uv.X;
|
||||
verts->v1=smVerts->uv.Y;
|
||||
verts->u2=0; //keep AGP write-combining active
|
||||
verts->v2=0;
|
||||
verts++;
|
||||
smVerts++;
|
||||
}
|
||||
|
||||
smudgesInRenderBatch++;
|
||||
smudge=smudge->Succ();
|
||||
}
|
||||
|
||||
set=set->Succ(); //advance to next node.
|
||||
|
||||
if (set) //start next batch at beginning of set.
|
||||
remainingSmudgeStart = set->getUsedSmudgeList().Head();
|
||||
}
|
||||
flushSmudges:
|
||||
DX8Wrapper::Set_Vertex_Buffer(vb_access);
|
||||
}
|
||||
|
||||
DX8Wrapper::Draw_Triangles( 0,smudgesInRenderBatch*4, 0, smudgesInRenderBatch*5);
|
||||
|
||||
//Debug Code which draws outline around smudge
|
||||
/* DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
|
||||
DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_COLOROP,D3DTOP_SELECTARG2);
|
||||
DX8Wrapper::Draw_Triangles( 0,smudgesInRenderBatch*4, 0, smudgesInRenderBatch*5);
|
||||
DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
|
||||
DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
|
||||
*/
|
||||
smudgesRemaining -= smudgesInRenderBatch;
|
||||
}
|
||||
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
|
||||
DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// FILE: W3DSnow.h /////////////////////////////////////////////////////////
|
||||
|
||||
#include "W3DDevice/GameClient/W3DSnow.h"
|
||||
#include "W3DDevice/GameClient/heightmap.h"
|
||||
#include "GameClient/View.h"
|
||||
#include "WW3D2/dx8wrapper.h"
|
||||
#include "WW3D2/rinfo.h"
|
||||
#include "WW3D2/camera.h"
|
||||
#include "WW3D2/assetmgr.h"
|
||||
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
#define D3DFVF_POINTVERTEX (D3DFVF_XYZ)
|
||||
#define SNOW_BUFFER_SIZE 4096 //size of vertex buffer holding particles.
|
||||
#define SNOW_BATCH_SIZE 2048 //we render at most this many particles per drawprimitive call. This number * 6 must be less than 65536 to fit into index buffer.
|
||||
|
||||
struct POINTVERTEX
|
||||
{
|
||||
Vector3 v; //center of particle.
|
||||
};
|
||||
|
||||
W3DSnowManager::W3DSnowManager(void)
|
||||
{
|
||||
m_indexBuffer=NULL;
|
||||
m_snowTexture=NULL;
|
||||
m_VertexBufferD3D=NULL;
|
||||
}
|
||||
|
||||
W3DSnowManager::~W3DSnowManager()
|
||||
{
|
||||
ReleaseResources();
|
||||
}
|
||||
|
||||
void W3DSnowManager::init( void )
|
||||
{
|
||||
SnowManager::init();
|
||||
ReAcquireResources();
|
||||
}
|
||||
|
||||
/** Releases all W3D/D3D assets before a reset.. */
|
||||
void W3DSnowManager::ReleaseResources(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_snowTexture);
|
||||
|
||||
if (m_VertexBufferD3D)
|
||||
m_VertexBufferD3D->Release();
|
||||
|
||||
m_VertexBufferD3D=NULL;
|
||||
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
}
|
||||
|
||||
/** (Re)allocates all W3D/D3D assets after a reset.. */
|
||||
Bool W3DSnowManager::ReAcquireResources(void)
|
||||
{
|
||||
ReleaseResources();
|
||||
|
||||
if (!TheWeatherSetting->m_snowEnabled)
|
||||
return TRUE; //no need for resources if snow is disabled.
|
||||
|
||||
if (TheWeatherSetting->m_usePointSprites && DX8Wrapper::Get_Current_Caps()->Support_PointSprites())
|
||||
{
|
||||
LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
|
||||
|
||||
DEBUG_ASSERTCRASH(m_pDev, ("Trying to ReAquireResources on W3DSnowManager without device"));
|
||||
|
||||
if (m_VertexBufferD3D == NULL)
|
||||
{ // Create vertex buffer
|
||||
|
||||
if (FAILED(m_pDev->CreateVertexBuffer
|
||||
(
|
||||
SNOW_BUFFER_SIZE*sizeof(POINTVERTEX),
|
||||
D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC|D3DUSAGE_POINTS,
|
||||
D3DFVF_POINTVERTEX,
|
||||
D3DPOOL_DEFAULT,
|
||||
&m_VertexBufferD3D
|
||||
)))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_indexBuffer=NEW_REF(DX8IndexBufferClass,(SNOW_BATCH_SIZE *6)); //allocate 2 triangles per flake, each with 3 indices.
|
||||
|
||||
// Fill up the IB with static vertex indices that will be used for all smudges.
|
||||
{
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer);
|
||||
UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
|
||||
//quad of 4 triangles:
|
||||
// 0-----3
|
||||
// |\ /|
|
||||
// | X |
|
||||
// |/ \|
|
||||
// 1-----2
|
||||
Int vbCount=0;
|
||||
for (Int i=0; i<SNOW_BATCH_SIZE; i++)
|
||||
{
|
||||
//Top
|
||||
ib[0]=vbCount+3;
|
||||
ib[1]=vbCount;
|
||||
ib[2]=vbCount+2;
|
||||
//Bottom
|
||||
ib[3]=vbCount+2;
|
||||
ib[4]=vbCount;
|
||||
ib[5]=vbCount+1;
|
||||
|
||||
vbCount += 4;
|
||||
ib+=6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_snowTexture = WW3DAssetManager::Get_Instance()->Get_Texture(TheWeatherSetting->m_snowTexture.str());
|
||||
|
||||
m_dwBase = SNOW_BUFFER_SIZE;
|
||||
m_dwDiscard = SNOW_BUFFER_SIZE;
|
||||
m_dwFlush = SNOW_BATCH_SIZE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void W3DSnowManager::updateIniSettings(void)
|
||||
{
|
||||
//Call base class
|
||||
SnowManager::updateIniSettings();
|
||||
|
||||
if (m_snowTexture && stricmp(m_snowTexture->Get_Texture_Name(),TheWeatherSetting->m_snowTexture.str()) != 0)
|
||||
{
|
||||
REF_PTR_RELEASE(m_snowTexture);
|
||||
m_snowTexture = WW3DAssetManager::Get_Instance()->Get_Texture(TheWeatherSetting->m_snowTexture.str());
|
||||
}
|
||||
}
|
||||
|
||||
void W3DSnowManager::reset( void )
|
||||
{
|
||||
SnowManager::reset();
|
||||
}
|
||||
|
||||
void W3DSnowManager::update(void)
|
||||
{
|
||||
|
||||
m_time += WW3D::Get_Frame_Time() / 1000.0f;
|
||||
|
||||
//find current time offset, adjusting for overflow
|
||||
m_time=fmod(m_time,m_fullTimePeriod);
|
||||
}
|
||||
|
||||
#define MAXIMUM_CAMERA_DISTANCE 100000 //maximum distance of camera position from world origin.
|
||||
#define ISPOW2(x) (x && (x & (x-1)) == 0) //is a number a power of 2?
|
||||
#define MODPOW2(x,y) ((x) & (y-1)) //mod '%' operator for powers of 2.
|
||||
|
||||
// Helper function to stuff a FLOAT into a DWORD argument
|
||||
inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }
|
||||
|
||||
/*Recursively subdivide the large snow box enclosing the camera until we reach some predefined leaf size. This
|
||||
method is used so that very few off-screen particles end up getting rendered. Culling them individually would
|
||||
be too expensive since we're dealing with 1000's for this effect.*/
|
||||
void W3DSnowManager::renderSubBox(RenderInfoClass &rinfo, Int originX, Int originY, Int cubeDimX, Int cubeDimY )
|
||||
{
|
||||
//check if this box is too large and needs subdivision
|
||||
Int boxDimX=cubeDimX - originX;
|
||||
Int boxDimY=cubeDimY - originY;
|
||||
Int halfX=REAL_TO_INT_CEIL(boxDimX*0.5f);
|
||||
Int halfY=REAL_TO_INT_CEIL(boxDimY*0.5f);
|
||||
|
||||
CameraClass &camera=rinfo.Camera;
|
||||
MinMaxAABoxClass mmbox;
|
||||
|
||||
if (boxDimX > m_leafDim)
|
||||
{ //subdivide the box
|
||||
if (boxDimY > m_leafDim)
|
||||
{ //subdivide in both directions
|
||||
//Upper left
|
||||
mmbox.MinCorner.Set(originX*m_emitterSpacing-m_cullOverscan, (originY + halfY)*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set((originX + halfX)*m_emitterSpacing+m_cullOverscan, cubeDimY*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX, originY + halfY, originX + halfX, cubeDimY);
|
||||
//Upper right
|
||||
mmbox.MinCorner.Set((originX + halfX)*m_emitterSpacing-m_cullOverscan, (originY + halfY)*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set(cubeDimX*m_emitterSpacing+m_cullOverscan, cubeDimY*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX + halfX, originY + halfY,cubeDimX, cubeDimY);
|
||||
//Lower left
|
||||
mmbox.MinCorner.Set(originX*m_emitterSpacing-m_cullOverscan, originY*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set((originX + halfX)*m_emitterSpacing+m_cullOverscan, (originY + halfY)*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX,originY,originX + halfX, originY + halfY);
|
||||
//Lower right
|
||||
mmbox.MinCorner.Set((originX + halfX)*m_emitterSpacing-m_cullOverscan, originY*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set(cubeDimX*m_emitterSpacing+m_cullOverscan, (originY + halfY)*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX + halfX, originY, cubeDimX, originY + halfY);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ //only subdivide in x direction.
|
||||
//Left
|
||||
mmbox.MinCorner.Set(originX*m_emitterSpacing-m_cullOverscan, originY*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set((originX + halfX)*m_emitterSpacing+m_cullOverscan, cubeDimY*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX, originY, originX + halfX, cubeDimY);
|
||||
//Right
|
||||
mmbox.MinCorner.Set((originX + halfX)*m_emitterSpacing-m_cullOverscan, originY*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set(cubeDimX*m_emitterSpacing+m_cullOverscan, cubeDimY*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX + halfX, originY, cubeDimX, cubeDimY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (boxDimY > m_leafDim)
|
||||
{ //only subdivide in y direction
|
||||
//Top
|
||||
mmbox.MinCorner.Set(originX*m_emitterSpacing-m_cullOverscan, (originY+halfY)*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set(cubeDimX*m_emitterSpacing+m_cullOverscan, cubeDimY*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX, originY+halfY,cubeDimX, cubeDimY);
|
||||
//Bottom
|
||||
mmbox.MinCorner.Set(originX*m_emitterSpacing-m_cullOverscan, originY*m_emitterSpacing-m_cullOverscan, m_snowCeiling-m_boxDimensions);
|
||||
mmbox.MaxCorner.Set(cubeDimX*m_emitterSpacing+m_cullOverscan, (originY + halfY)*m_emitterSpacing+m_cullOverscan, m_snowCeiling);
|
||||
if (CollisionMath::Overlap_Test(camera.Get_Frustum(),mmbox) != CollisionMath::OUTSIDE)
|
||||
renderSubBox(rinfo, originX, originY, cubeDimX, originY + halfY);
|
||||
return;
|
||||
}
|
||||
|
||||
//Box too small to subdivide so render it.
|
||||
|
||||
//Find total number of particles that need rendering.
|
||||
Int totalPart=(cubeDimY-originY)*(cubeDimX-originX);
|
||||
|
||||
if (!totalPart)
|
||||
return; //nothing to render.
|
||||
|
||||
Int y=originY; //loop counter.
|
||||
Int cubeOriginXRemainder = originX; //loop counter - adjusted when not all particles fit into render buffer.
|
||||
Vector3 snowCenter;
|
||||
|
||||
m_totalRendered += totalPart;
|
||||
|
||||
while (totalPart)
|
||||
{
|
||||
Int batchSize=totalPart;
|
||||
|
||||
if (batchSize > m_dwFlush)
|
||||
batchSize = m_dwFlush;
|
||||
|
||||
if((m_dwBase + batchSize) > m_dwDiscard)
|
||||
m_dwBase = 0;
|
||||
|
||||
POINTVERTEX* verts;
|
||||
|
||||
if(m_VertexBufferD3D->Lock(m_dwBase * sizeof(POINTVERTEX), batchSize * sizeof(POINTVERTEX),
|
||||
(unsigned char **) &verts, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD) != D3D_OK )
|
||||
return; //couldn't lock buffer.
|
||||
|
||||
Int numberInBatch=0;
|
||||
|
||||
for (;y<cubeDimY; y++)
|
||||
{
|
||||
for (Int x=cubeOriginXRemainder; x<cubeDimX; x++)
|
||||
{
|
||||
if (numberInBatch >= batchSize)
|
||||
{ cubeOriginXRemainder = x;
|
||||
goto flush_particles;
|
||||
}
|
||||
|
||||
//Get initial height from noise table. We add a large value to make sure it's positive. Then
|
||||
//modulate by table dimensions to find a value.
|
||||
Int noiseOffset=MODPOW2(x+MAXIMUM_CAMERA_DISTANCE,SNOW_NOISE_X)+MODPOW2(y+MAXIMUM_CAMERA_DISTANCE,SNOW_NOISE_Y)*SNOW_NOISE_X;
|
||||
if (noiseOffset > (SNOW_NOISE_X * SNOW_NOISE_Y))
|
||||
noiseOffset = 0; //this should never happen but check to prevent buffer over/under flow.
|
||||
|
||||
//find current height
|
||||
Real h0=m_snowCeiling-fmod(m_heightTraveled+m_startingHeights[noiseOffset],m_boxDimensions);
|
||||
|
||||
//find world-space position of snow flake
|
||||
snowCenter.Set(x*m_emitterSpacing,y*m_emitterSpacing,h0);
|
||||
|
||||
//Adjust position so snow flakes don't fall straight down.
|
||||
snowCenter.X += m_amplitude * WWMath::Fast_Sin( h0 * m_frequencyScaleX + (Real)x);
|
||||
snowCenter.Y += m_amplitude * WWMath::Fast_Sin( h0 * m_frequencyScaleY + (Real)y);
|
||||
|
||||
*(Vector3 *)verts=snowCenter;
|
||||
verts++;
|
||||
|
||||
numberInBatch++;
|
||||
}
|
||||
//getting here means we did not overflow the render buffer, so reset x origin to normal.
|
||||
cubeOriginXRemainder = originX; //reset to normal amount
|
||||
}
|
||||
|
||||
flush_particles:
|
||||
m_VertexBufferD3D->Unlock();
|
||||
//Render any particles that may be queued up.
|
||||
if (numberInBatch)
|
||||
{
|
||||
Debug_Statistics::Record_DX8_Polys_And_Vertices(numberInBatch*2,numberInBatch*4,ShaderClass::_PresetOpaqueShader);
|
||||
DX8Wrapper::_Get_D3D_Device8()->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, numberInBatch);
|
||||
totalPart -= numberInBatch;
|
||||
m_dwBase += numberInBatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void W3DSnowManager::render(RenderInfoClass &rinfo)
|
||||
{
|
||||
if (!TheWeatherSetting->m_snowEnabled || !m_isVisible)
|
||||
return;
|
||||
|
||||
Int usePointSprites = DX8Wrapper::Get_Current_Caps()->Support_PointSprites() && TheWeatherSetting->m_usePointSprites;
|
||||
|
||||
//make sure the noise table is powers of 2 in dimensions.
|
||||
WWASSERT(ISPOW2(SNOW_NOISE_X) && ISPOW2(SNOW_NOISE_Y));
|
||||
|
||||
//CameraClass &camera=rinfo.Camera;
|
||||
|
||||
const Coord3D &cPos=TheTacticalView->get3DCameraPosition();
|
||||
Vector3 camPos(cPos.x,cPos.y,cPos.z);
|
||||
|
||||
//Number of emitters from cube center to edge of visible extent.
|
||||
Int mumEmittersInHalf=(Int)floor(m_boxDimensions / m_emitterSpacing * 0.5f);
|
||||
|
||||
//Find origin of visible cube surrounding camera.
|
||||
Int cubeCenterX=(Int)floor(camPos.X/m_emitterSpacing);
|
||||
Int cubeCenterY=(Int)floor(camPos.Y/m_emitterSpacing);
|
||||
|
||||
//Find extents of visible cube surrounding camera.
|
||||
Int cubeOriginX=cubeCenterX - mumEmittersInHalf; //top/left extents.
|
||||
Int cubeOriginY=cubeCenterY - mumEmittersInHalf;
|
||||
Int cubeDimX=cubeCenterX + mumEmittersInHalf; //bottom/right extents.
|
||||
Int cubeDimY=cubeCenterY + mumEmittersInHalf;
|
||||
|
||||
const FrustumClass & frustum = rinfo.Camera.Get_Frustum();
|
||||
AABoxClass bbox;
|
||||
|
||||
//Get a bounding box around our visible universe. Bounded by terrain and the sky
|
||||
//so much tighter fitting volume than what's actually visible. This will cull
|
||||
//particles falling under the ground.
|
||||
|
||||
TheTerrainRenderObject->getMaximumVisibleBox(frustum, &bbox, TRUE);
|
||||
|
||||
//Particles move outside the visible box as a result of local sine movement
|
||||
//so adjust bounding box to include them.
|
||||
bbox.Extent.X += m_amplitude+m_quadSize;
|
||||
bbox.Extent.Y += m_amplitude+m_quadSize;
|
||||
|
||||
//Clip our visible snow rendering box
|
||||
if ((cubeOriginX * m_emitterSpacing ) < (bbox.Center.X - bbox.Extent.X))
|
||||
cubeOriginX = (Int)floor ((bbox.Center.X - bbox.Extent.X)/m_emitterSpacing);
|
||||
|
||||
if ((cubeOriginY * m_emitterSpacing ) < (bbox.Center.Y - bbox.Extent.Y))
|
||||
cubeOriginY = (Int)floor ((bbox.Center.Y - bbox.Extent.Y)/m_emitterSpacing);
|
||||
|
||||
if ((cubeDimX * m_emitterSpacing ) > (bbox.Center.X + bbox.Extent.X))
|
||||
cubeDimX = (Int)floor ((bbox.Center.X + bbox.Extent.X)/m_emitterSpacing);
|
||||
|
||||
if ((cubeDimY * m_emitterSpacing ) > (bbox.Center.Y + bbox.Extent.Y))
|
||||
cubeDimY = (Int)floor ((bbox.Center.Y + bbox.Extent.Y)/m_emitterSpacing);
|
||||
|
||||
if ((cubeDimY - cubeOriginY) < 0 || (cubeDimX-cubeOriginX) < 0)
|
||||
return; //entire snow box is culled by either x or y screen boundary.
|
||||
|
||||
//Find total number of particles that need rendering.
|
||||
Int totalPart=(cubeDimY-cubeOriginY)*(cubeDimX-cubeOriginX);
|
||||
|
||||
if (totalPart <= 0)
|
||||
return; //nothing to render.
|
||||
|
||||
//Height at the top of the cube with camera at center.
|
||||
m_snowCeiling = camPos.Z + m_boxDimensions/2.0f;
|
||||
|
||||
//Offset to allow cube extents to move with camera.
|
||||
Real cameraOffset = fmod (camPos.Z,m_boxDimensions);
|
||||
m_heightTraveled=m_time*m_velocity+cameraOffset; //height that snow flake traveled this frame.
|
||||
|
||||
Matrix4x4 identity(true);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,identity);
|
||||
|
||||
DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader);
|
||||
|
||||
VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
DX8Wrapper::Set_Material(vmat);
|
||||
REF_PTR_RELEASE(vmat);
|
||||
|
||||
//make sure we have all the resources we need
|
||||
if (usePointSprites && !m_VertexBufferD3D)
|
||||
ReAcquireResources();
|
||||
|
||||
if (!usePointSprites && !m_indexBuffer)
|
||||
ReAcquireResources();
|
||||
|
||||
DX8Wrapper::Set_Texture(0,m_snowTexture);
|
||||
|
||||
if (!usePointSprites)
|
||||
{
|
||||
renderAsQuads(rinfo,cubeOriginX,cubeOriginY,cubeDimX,cubeDimY);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 snowCenter;
|
||||
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
|
||||
// Set the render states for using point sprites
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSPRITEENABLE, TRUE );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSCALEENABLE, TRUE );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSIZE, FtoDW(m_pointSize) );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSIZE_MIN, FtoDW(m_minPointSize) );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSIZE_MAX, FtoDW(m_maxPointSize) );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSCALE_A, FtoDW(0.00f) );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSCALE_B, FtoDW(0.00f) );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSCALE_C, FtoDW(1.00f) );
|
||||
|
||||
DX8Wrapper::_Get_D3D_Device8()->SetStreamSource( 0, m_VertexBufferD3D, sizeof(POINTVERTEX) );
|
||||
DX8Wrapper::_Get_D3D_Device8()->SetVertexShader( D3DFVF_POINTVERTEX );
|
||||
m_dwBase = SNOW_BUFFER_SIZE; //start with a new vertex buffer each frame.
|
||||
|
||||
m_leafDim = 45; //cull boxes that are 20x20 emitters in size. Making them much smaller will result in too many draw calls.
|
||||
m_totalRendered = 0; //keep track of how many particles were rendered.
|
||||
|
||||
//Particle centers can deviate from center by by amplitude of sine offset. They also have radius m_quadSize.
|
||||
//Enlarge culling bounds to compensate.
|
||||
m_cullOverscan = m_amplitude+m_quadSize;
|
||||
renderSubBox(rinfo,cubeOriginX,cubeOriginY,cubeDimX,cubeDimY);
|
||||
|
||||
// Reset render states
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSPRITEENABLE, FALSE );
|
||||
DX8Wrapper::Set_DX8_Render_State( D3DRS_POINTSCALEENABLE, FALSE );
|
||||
|
||||
}
|
||||
|
||||
/**For hardware that doesn't support point sprites*/
|
||||
void W3DSnowManager::renderAsQuads(RenderInfoClass &rinfo, Int cubeOriginX, Int cubeOriginY, Int cubeDimX, Int cubeDimY)
|
||||
{
|
||||
|
||||
Matrix4x4 proj;
|
||||
Matrix3D view;
|
||||
Vector3 snowCenter;
|
||||
Vector3 snowCenterVS;
|
||||
|
||||
CameraClass &camera=rinfo.Camera;
|
||||
|
||||
camera.Get_View_Matrix(&view);
|
||||
camera.Get_Projection_Matrix(&proj);
|
||||
|
||||
Vector3 vertex_offsets[4] = {
|
||||
Vector3(-0.5f, 0.5f, 0.0f),
|
||||
Vector3(-0.5f, -0.5f, 0.0f),
|
||||
Vector3(0.5f, -0.5f, 0.0f),
|
||||
Vector3(0.5f, 0.5f, 0.0f)
|
||||
};
|
||||
|
||||
Vector2 quad_uvs[4] = {
|
||||
Vector2(0.0f, 0.0f),
|
||||
Vector2(0.0f, 1.0f),
|
||||
Vector2(1.0f, 1.0f),
|
||||
Vector2(1.0f, 0.0f)
|
||||
};
|
||||
|
||||
|
||||
//pre-multiple the offsets by particle size
|
||||
for (Int i=0; i<4; i++)
|
||||
{
|
||||
vertex_offsets[i] *= m_quadSize;
|
||||
}
|
||||
|
||||
Matrix4x4 identity(true);
|
||||
DX8Wrapper::Set_Transform(D3DTS_VIEW,identity);
|
||||
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
|
||||
|
||||
Int y=cubeOriginY; //loop counter.
|
||||
Int cubeOriginXRemainder = cubeOriginX; //loop counter - adjusted when not all particles fit into render buffer.
|
||||
|
||||
//Find total number of particles that need rendering.
|
||||
Int totalPart=(cubeDimY-cubeOriginY)*(cubeDimX-cubeOriginX);
|
||||
|
||||
m_totalRendered += totalPart;
|
||||
|
||||
while (totalPart)
|
||||
{
|
||||
Int batchSize=totalPart;
|
||||
|
||||
if (batchSize > SNOW_BATCH_SIZE)
|
||||
batchSize = SNOW_BATCH_SIZE;
|
||||
|
||||
Int numberInBatch=0;
|
||||
|
||||
DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,batchSize*4); //allocate 4 verts per flake
|
||||
{
|
||||
DynamicVBAccessClass::WriteLockClass lock(&vb_access);
|
||||
VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array();
|
||||
|
||||
for (;y<cubeDimY; y++)
|
||||
{
|
||||
for (Int x=cubeOriginXRemainder; x<cubeDimX; x++)
|
||||
{
|
||||
if (numberInBatch >= batchSize)
|
||||
{ cubeOriginXRemainder = x;
|
||||
goto flush_particles;
|
||||
}
|
||||
|
||||
//Get initial height from noise table. We add a large value to make sure it's positive. Then
|
||||
//modulate by table dimensions to find a value.
|
||||
Int noiseOffset=MODPOW2(x+MAXIMUM_CAMERA_DISTANCE,SNOW_NOISE_X)+MODPOW2(y+MAXIMUM_CAMERA_DISTANCE,SNOW_NOISE_Y)*SNOW_NOISE_X;
|
||||
if (noiseOffset > (SNOW_NOISE_X * SNOW_NOISE_Y))
|
||||
noiseOffset = 0; //this should never happen but check to prevent buffer over/under flow.
|
||||
|
||||
//find current height
|
||||
Real h0=m_snowCeiling-fmod(m_heightTraveled+m_startingHeights[noiseOffset],m_boxDimensions);
|
||||
|
||||
//find world-space position of snow flake
|
||||
snowCenter.Set(x*m_emitterSpacing,y*m_emitterSpacing,h0);
|
||||
|
||||
//Get view-space position
|
||||
Matrix3D::Transform_Vector(view,snowCenter,&snowCenterVS);
|
||||
|
||||
//Adjust position so snow flakes don't fall straight down.
|
||||
snowCenterVS.X += m_amplitude * WWMath::Fast_Sin( h0 * m_frequencyScaleX + (Real)x);
|
||||
snowCenterVS.Y += m_amplitude * WWMath::Fast_Sin( h0 * m_frequencyScaleY + (Real)y);
|
||||
|
||||
for (Int i=0; i<4; i++)
|
||||
{
|
||||
*(Vector3 *)verts=snowCenterVS + vertex_offsets[i];
|
||||
verts->nx=0; //keep AGP write-combining active
|
||||
verts->ny=0;
|
||||
verts->nz=0;
|
||||
verts->diffuse=0xffffffff; //set to opaque
|
||||
verts->u1=quad_uvs[i].X;
|
||||
verts->v1=quad_uvs[i].Y;
|
||||
verts->u2=0; //keep AGP write-combining active
|
||||
verts->v2=0;
|
||||
verts++;
|
||||
}
|
||||
|
||||
numberInBatch++;
|
||||
}
|
||||
//getting here means we did not overflow the render buffer, so reset x origin to normal.
|
||||
cubeOriginXRemainder = cubeOriginX; //reset to normal amount
|
||||
}
|
||||
flush_particles:
|
||||
numberInBatch; //need something at goto destination - stupid c compiler.
|
||||
}
|
||||
|
||||
//Render any particles that may be queued up.
|
||||
if (numberInBatch)
|
||||
{
|
||||
DX8Wrapper::Set_Vertex_Buffer(vb_access);
|
||||
DX8Wrapper::Draw_Triangles( 0,numberInBatch*2, 0, numberInBatch*4);
|
||||
totalPart -= numberInBatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "W3DDevice/GameClient/W3DStatusCircle.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include <texture.h>
|
||||
#include <tri.h>
|
||||
#include <colmath.h>
|
||||
#include <coltest.h>
|
||||
#include <rinfo.h>
|
||||
#include <camera.h>
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/Shader.h"
|
||||
#include "Common/GlobalData.h"
|
||||
#include "common/MapObject.h"
|
||||
#include "GameLogic/GameLogic.h"
|
||||
#include "GameLogic/ScriptEngine.h"
|
||||
|
||||
#define SC_DETAIL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_ALPHA ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending
|
||||
#define SC_ALPHA_Z ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
|
||||
ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
// Texturing, no zbuffer, disabled zbuffer write, no gradient, add src to dest.
|
||||
#define SC_ADD ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ONE, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_DISABLE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
#define VERTEX_BUFFER_TILE_LENGTH 32 //tiles of side length 32 (grid of 33x33 vertices).
|
||||
#define VERTS_IN_BLOCK_ROW (VERTEX_BUFFER_TILE_LENGTH+1)
|
||||
|
||||
|
||||
static ShaderClass detailOpaqueShader(SC_ALPHA);
|
||||
Bool W3DStatusCircle::m_needUpdate;
|
||||
Int W3DStatusCircle::m_diffuse=255; // blue.
|
||||
|
||||
W3DStatusCircle::~W3DStatusCircle(void)
|
||||
{
|
||||
freeMapResources();
|
||||
}
|
||||
|
||||
W3DStatusCircle::W3DStatusCircle(void)
|
||||
{
|
||||
m_indexBuffer=NULL;
|
||||
m_vertexMaterialClass=NULL;
|
||||
m_vertexBufferCircle=NULL;
|
||||
m_vertexBufferScreen=NULL;
|
||||
}
|
||||
|
||||
|
||||
bool W3DStatusCircle::Cast_Ray(RayCollisionTestClass & raytest)
|
||||
{
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//@todo: MW Handle both of these properly!!
|
||||
W3DStatusCircle::W3DStatusCircle(const W3DStatusCircle & src)
|
||||
{
|
||||
*this = src;
|
||||
}
|
||||
|
||||
W3DStatusCircle & W3DStatusCircle::operator = (const W3DStatusCircle & that)
|
||||
{
|
||||
assert(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void W3DStatusCircle::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
||||
{
|
||||
Vector3 ObjSpaceCenter((float)1000*0.5f,(float)1000*0.5f,(float)0);
|
||||
float length = ObjSpaceCenter.Length();
|
||||
|
||||
sphere.Init(ObjSpaceCenter, length);
|
||||
}
|
||||
|
||||
void W3DStatusCircle::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
||||
{
|
||||
Vector3 minPt(0,0,0);
|
||||
Vector3 maxPt((float)1000,(float)1000,(float)1000);
|
||||
box.Init(minPt,maxPt);
|
||||
}
|
||||
|
||||
Int W3DStatusCircle::Class_ID(void) const
|
||||
{
|
||||
return RenderObjClass::CLASSID_UNKNOWN;
|
||||
}
|
||||
|
||||
RenderObjClass * W3DStatusCircle::Clone(void) const
|
||||
{
|
||||
return NEW W3DStatusCircle(*this);
|
||||
}
|
||||
|
||||
|
||||
Int W3DStatusCircle::freeMapResources(void)
|
||||
{
|
||||
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
REF_PTR_RELEASE(m_vertexBufferScreen);
|
||||
REF_PTR_RELEASE(m_vertexBufferCircle);
|
||||
REF_PTR_RELEASE(m_vertexMaterialClass);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NUM_TRI 20
|
||||
//Allocate a heightmap of x by y vertices.
|
||||
//data must be an array matching this size.
|
||||
Int W3DStatusCircle::initData(void)
|
||||
{
|
||||
Int i;
|
||||
|
||||
m_needUpdate = true;
|
||||
freeMapResources(); //free old data and ib/vb
|
||||
|
||||
m_numTriangles = NUM_TRI;
|
||||
m_indexBuffer=NEW_REF(DX8IndexBufferClass,(m_numTriangles*3));
|
||||
|
||||
// Fill up the IB
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer);
|
||||
UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
|
||||
|
||||
for (i=0; i<3*m_numTriangles; i+=3)
|
||||
{
|
||||
ib[0]=i;
|
||||
ib[1]=i+1;
|
||||
ib[2]=i+2;
|
||||
|
||||
ib+=3; //skip the 3 indices we just filled
|
||||
}
|
||||
|
||||
m_vertexBufferCircle=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_numTriangles*3,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
m_vertexBufferScreen=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,2*3,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
|
||||
//go with a preset material for now.
|
||||
m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
|
||||
m_shaderClass = ShaderClass::ShaderClass(SC_ALPHA);// _PresetOpaque2DShader;//; //_PresetOpaqueShader;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** updateCircleVB puts a circle with a team color vertex buffer. */
|
||||
|
||||
Int W3DStatusCircle::updateCircleVB(void)
|
||||
{
|
||||
Int i, k;
|
||||
Real shade;
|
||||
DX8VertexBufferClass *pVB = m_vertexBufferCircle;
|
||||
if (m_vertexBufferCircle )
|
||||
{
|
||||
m_needUpdate = false;
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB);
|
||||
VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
|
||||
|
||||
const Real theZ = 0.0f;
|
||||
const Real theRadius = 0.02f;
|
||||
const Int theAlpha = 127;
|
||||
Int diffuse = m_diffuse + (theAlpha<<24); // b g<<8 r<<16 a<<24.
|
||||
Int limit = m_numTriangles;
|
||||
float curAngle = 0;
|
||||
float deltaAngle = 2*PI/limit;
|
||||
for (i=0; i<limit; i++)
|
||||
{
|
||||
|
||||
shade=0.7f*255.0f;
|
||||
for (k=0; k<3; k++) {
|
||||
vb->z= theZ;
|
||||
if (k==0) {
|
||||
vb->x= 0;
|
||||
vb->y= 0;
|
||||
} else if (k==1) {
|
||||
Vector3 vec(theRadius,0,theZ);
|
||||
vec.Rotate_Z(curAngle);
|
||||
vb->x= vec.X;
|
||||
vb->y= vec.Y;
|
||||
} else if (k==2) {
|
||||
Real angle = curAngle+deltaAngle;
|
||||
if (i==limit-1) {
|
||||
angle = 0;
|
||||
}
|
||||
Vector3 vec(theRadius,0,theZ);
|
||||
vec.Rotate_Z(angle);
|
||||
vb->x= vec.X;
|
||||
vb->y= vec.Y;
|
||||
}
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
}
|
||||
curAngle += deltaAngle;
|
||||
|
||||
}
|
||||
return 0; //success.
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** updateCircleVB puts a circle with a team color vertex buffer. */
|
||||
|
||||
Int W3DStatusCircle::updateScreenVB(Int diffuse)
|
||||
{
|
||||
DX8VertexBufferClass *pVB = m_vertexBufferScreen;
|
||||
if (m_vertexBufferScreen )
|
||||
{
|
||||
m_needUpdate = false;
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB);
|
||||
VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
|
||||
|
||||
vb->x = -1;
|
||||
vb->y = -1;
|
||||
vb->z = 0;
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
|
||||
vb->x = 1;
|
||||
vb->y = 1;
|
||||
vb->z = 0;
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
|
||||
vb->x = -1;
|
||||
vb->y = 1;
|
||||
vb->z = 0;
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
|
||||
vb->x = -1;
|
||||
vb->y = -1;
|
||||
vb->z = 0;
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
|
||||
vb->x = 1;
|
||||
vb->y = -1;
|
||||
vb->z = 0;
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
|
||||
vb->x = 1;
|
||||
vb->y = 1;
|
||||
vb->z = 0;
|
||||
vb->diffuse = diffuse;
|
||||
vb->u1=0;
|
||||
vb->v1=0;
|
||||
vb++;
|
||||
return 0; //success.
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void W3DStatusCircle::Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
if (!TheGameLogic->isInGame() || TheGameLogic->getGameMode() == GAME_SHELL)
|
||||
return;
|
||||
|
||||
if (m_indexBuffer == NULL) {
|
||||
initData();
|
||||
}
|
||||
if (m_indexBuffer == NULL) {
|
||||
return;
|
||||
}
|
||||
Bool setIndex = false;
|
||||
Matrix3D tm(true);
|
||||
if( TheGlobalData->m_showTeamDot )
|
||||
{
|
||||
if (m_needUpdate) {
|
||||
updateCircleVB();
|
||||
}
|
||||
//Apply the shader and material
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
DX8Wrapper::Set_Shader(m_shaderClass);
|
||||
DX8Wrapper::Set_Texture(0, NULL);
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferCircle);
|
||||
setIndex = true;
|
||||
|
||||
Vector3 vec(0.95f, 0.67f, 0);
|
||||
Matrix3x3 rot(true);
|
||||
|
||||
tm.Set_Translation(vec);
|
||||
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
DX8Wrapper::Draw_Triangles( 0,NUM_TRI, 0, (m_numTriangles*3));
|
||||
}
|
||||
|
||||
|
||||
ScriptEngine::TFade fade = TheScriptEngine->getFade();
|
||||
if (fade == ScriptEngine::FADE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!setIndex) {
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
|
||||
DX8Wrapper::Set_Texture(0, NULL);
|
||||
}
|
||||
|
||||
tm.Make_Identity();
|
||||
Real intensity = TheScriptEngine->getFadeValue();
|
||||
Int clr = 255*intensity;
|
||||
Int diffuse = (0xff<<24)|(clr<<16)|(clr<<8)|clr; // b g<<8 r<<16 a<<24.
|
||||
updateScreenVB(diffuse);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
DX8Wrapper::Set_Shader(ShaderClass(SC_ADD));
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferScreen);
|
||||
DX8Wrapper::Apply_Render_State_Changes();
|
||||
switch (fade) {
|
||||
default:
|
||||
case ScriptEngine::FADE_ADD:
|
||||
DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3));
|
||||
break;
|
||||
case ScriptEngine::FADE_SUBTRACT:
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT );
|
||||
DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3));
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD );
|
||||
break;
|
||||
case ScriptEngine::FADE_SATURATE:
|
||||
// 4x multiply
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR);
|
||||
DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3));
|
||||
DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3));
|
||||
break;
|
||||
case ScriptEngine::FADE_MULTIPLY:
|
||||
// Straight multiply
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_ZERO);
|
||||
DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR);
|
||||
DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3));
|
||||
break;
|
||||
}
|
||||
ShaderClass::Invalidate();
|
||||
}
|
||||
@@ -0,0 +1,810 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTerrainBackground.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// EA Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2003 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DTerrainBackground.cpp
|
||||
//
|
||||
// Created: John Ahlquist, March 2003
|
||||
//
|
||||
// Desc: Draw buffer to handle backup terrain at lower res.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "W3DDevice/GameClient/W3DTerrainBackground.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include <texture.h>
|
||||
#include "common/GlobalData.h"
|
||||
#include "GameClient/View.h"
|
||||
#include "W3DDevice/GameClient/TerrainTex.h"
|
||||
#include "W3DDevice/GameClient/HeightMap.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/DX8Renderer.h"
|
||||
#include "WW3D2/Camera.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//-----------------------------------------------------------------------------
|
||||
// A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer.
|
||||
#define SC_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
|
||||
ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
|
||||
ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
|
||||
ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
|
||||
|
||||
static ShaderClass detailShader(SC_DETAIL);
|
||||
|
||||
const Int PIXELS_PER_GRID = 8; // default tex resolution allocated for each tile. jba. [3/24/2003]
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::loadTerrainInVertexAndIndexBuffers
|
||||
//=============================================================================
|
||||
/** Loads the terrain into the vertex buffer for drawing. */
|
||||
//=============================================================================
|
||||
void W3DTerrainBackground::setFlip(WorldHeightMap *htMap)
|
||||
{
|
||||
if (m_map==NULL) return;
|
||||
if (htMap) {
|
||||
REF_PTR_SET(m_map, htMap);
|
||||
}
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
setFlipRecursive(0, 0, m_width);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
const Int STEP=4;
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::doPartialUpdate
|
||||
//=============================================================================
|
||||
/** Updates a partial block of vertices from [x0,y0 to x1,y1]
|
||||
The coordinates in partialRange are map cell coordinates, relative to the entire map.
|
||||
The vertex coordinates and texture coordinates, as well as static lighting are updated.
|
||||
*/
|
||||
void W3DTerrainBackground::doPartialUpdate(const IRegion2D &partialRange, WorldHeightMap *htMap, Bool doTextures )
|
||||
{
|
||||
if (m_map==NULL) return;
|
||||
if (htMap) {
|
||||
REF_PTR_SET(m_map, htMap);
|
||||
}
|
||||
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
doTesselatedUpdate(partialRange, htMap, doTextures);
|
||||
|
||||
return;
|
||||
|
||||
Int requiredVertexSize = (m_width+1) * (m_width+1) + 6;
|
||||
if (m_vertexTerrainSize<requiredVertexSize || m_vertexTerrain==NULL) {
|
||||
m_vertexTerrainSize = requiredVertexSize;
|
||||
REF_PTR_RELEASE(m_vertexTerrain);
|
||||
REF_PTR_RELEASE(m_indexTerrain);
|
||||
m_vertexTerrain=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_vertexTerrainSize+4,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
}
|
||||
|
||||
Int requiredIndexSize = (m_width+1) * (m_width+1) + 6;
|
||||
if (m_indexTerrainSize<requiredIndexSize || m_indexTerrain==NULL) {
|
||||
m_indexTerrainSize = requiredIndexSize;
|
||||
REF_PTR_RELEASE(m_indexTerrain);
|
||||
m_indexTerrain=NEW_REF(DX8IndexBufferClass,(m_indexTerrainSize+4,DX8IndexBufferClass::USAGE_DEFAULT));
|
||||
}
|
||||
Int minX = m_xOrigin;
|
||||
Int minY = m_yOrigin;
|
||||
Int maxX = m_xOrigin + m_width;
|
||||
Int maxY = m_yOrigin + m_width;
|
||||
Int limitX = m_map->getXExtent()-1;
|
||||
Int limitY = m_map->getYExtent()-1;
|
||||
if (maxX>limitX) maxX = limitX;
|
||||
if (maxY>limitY) maxY = limitY;
|
||||
|
||||
if (partialRange.lo.x > maxX) return;
|
||||
if (partialRange.lo.y > maxY) return;
|
||||
if (partialRange.hi.x < minX) return;
|
||||
if (partialRange.hi.y < minY) return;
|
||||
|
||||
m_curNumTerrainVertices = 0;
|
||||
//m_curNumTerrainIndices = 0;
|
||||
VertexFormatXYZDUV2 *vb;
|
||||
UnsignedShort *ib;
|
||||
// Lock the buffer.
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTerrain);
|
||||
vb=(VertexFormatXYZDUV2*)lockVtxBuffer.Get_Vertex_Array();
|
||||
// Add to the vertex buffer.
|
||||
|
||||
VertexFormatXYZDUV2 *curVb = vb;
|
||||
MinMaxAABoxClass bounds;
|
||||
bounds.Init_Empty();
|
||||
|
||||
Int i, j;
|
||||
for (j=minY; j<=maxY; j+=STEP) {
|
||||
for (i=minX; i<=maxX; i+=STEP) {
|
||||
if (m_curNumTerrainVertices >= m_vertexTerrainSize) return;
|
||||
curVb->diffuse = (0<<24)|TheTerrainRenderObject->getStaticDiffuse(i,j);
|
||||
Vector3 pos;
|
||||
pos.Z = ((float)m_map->getHeight(i,j)*MAP_HEIGHT_SCALE);
|
||||
pos.X = (i)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
|
||||
pos.Y = (j)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
|
||||
curVb->u1 = (float)(i-minX)/(float)(m_width);
|
||||
curVb->v1 = 1.0f - (float)(j-minY)/(float)(m_width);
|
||||
curVb->x = pos.X;
|
||||
curVb->y = pos.Y;
|
||||
curVb->z = pos.Z;
|
||||
curVb++;
|
||||
m_curNumTerrainVertices++;
|
||||
bounds.Add_Point(pos);
|
||||
}
|
||||
}
|
||||
m_bounds.Init(bounds);
|
||||
|
||||
if (m_terrainTexture == NULL || doTextures) {
|
||||
REF_PTR_RELEASE(m_terrainTexture);
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
m_terrainTexture = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, PIXELS_PER_GRID);
|
||||
// DEBUG ONLY. jba. m_terrainTexture = (TerrainTextureClass *)NEW_REF(TextureClass, ("TBBib.tga"));
|
||||
m_terrainTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_terrainTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
}
|
||||
|
||||
if (m_curNumTerrainIndices == 0) {
|
||||
// Only do the index buffer if it has never been done. Index values don't change. jba.
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTerrain);
|
||||
ib = lockIdxBuffer.Get_Index_Array();
|
||||
UnsignedShort *curIb = ib;
|
||||
Int yOffset = ((maxX - minX)/STEP+1);
|
||||
Int width = yOffset;
|
||||
Int height = (maxY - minY)/STEP;
|
||||
*curIb++ = width-1;
|
||||
m_curNumTerrainIndices++;
|
||||
for (j=0; j<height; j++) {
|
||||
*curIb++ = j*yOffset + yOffset + width-1;
|
||||
m_curNumTerrainIndices++;
|
||||
for (i=width-2; i>=0; i--) {
|
||||
if (m_curNumTerrainIndices+2 > m_indexTerrainSize) return;
|
||||
*curIb++ = j*yOffset + i;
|
||||
*curIb++ = j*yOffset + i+yOffset;
|
||||
m_curNumTerrainIndices+=2;
|
||||
}
|
||||
j++;
|
||||
if (j<height) {
|
||||
*curIb++ = j*yOffset + yOffset;
|
||||
m_curNumTerrainIndices++;
|
||||
for (i=1; i<width; i++) {
|
||||
if (m_curNumTerrainIndices+2 > m_indexTerrainSize) return;
|
||||
*curIb++ = j*yOffset + i;
|
||||
*curIb++ = j*yOffset + i+yOffset;
|
||||
m_curNumTerrainIndices+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::fillVBRecursive
|
||||
//=============================================================================
|
||||
/** Fills in vertex & index buffers.
|
||||
*/
|
||||
Bool W3DTerrainBackground::advanceLeft(ICoord2D &left, Int xOffset, Int yOffset, Int width)
|
||||
{
|
||||
while (left.y < yOffset+width) {
|
||||
left.y++;
|
||||
if (m_map->getFlipState(left.x+m_xOrigin, left.y+m_yOrigin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (left.x < xOffset+width-1) {
|
||||
left.x++;
|
||||
if (m_map->getFlipState(left.x+m_xOrigin, left.y+m_yOrigin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::fillVBRecursive
|
||||
//=============================================================================
|
||||
/** Fills in vertex & index buffers.
|
||||
*/
|
||||
Bool W3DTerrainBackground::advanceRight(ICoord2D &right, Int xOffset, Int yOffset, Int width)
|
||||
{
|
||||
while (right.x < xOffset+width) {
|
||||
right.x++;
|
||||
if (m_map->getFlipState(right.x+m_xOrigin, right.y+m_yOrigin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (right.y < yOffset+width-1) {
|
||||
right.y++;
|
||||
if (m_map->getFlipState(right.x+m_xOrigin, right.y+m_yOrigin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::fillVBRecursive
|
||||
//=============================================================================
|
||||
/** Fills in vertex & index buffers.
|
||||
*/
|
||||
void W3DTerrainBackground::fillVBRecursive(UnsignedShort *ib, Int xOffset, Int yOffset,
|
||||
Int width, UnsignedShort *ndx, Int &curIndex)
|
||||
{
|
||||
|
||||
Int bottomLeftNdx = ndx[xOffset+yOffset*(m_width+1)];
|
||||
Int topRightNdx = ndx[xOffset+width + (yOffset+width)*(m_width+1)];
|
||||
|
||||
Int limitX = m_map->getXExtent()-1;
|
||||
Int limitY = m_map->getYExtent()-1;
|
||||
Int i, j;
|
||||
Bool match = true;
|
||||
Int minX = m_xOrigin+xOffset;
|
||||
Int minY = m_yOrigin+yOffset;
|
||||
Int cornerHeight = m_map->getHeight(minX, minY);
|
||||
|
||||
for (i=0; i<=width; i++) {
|
||||
for (j=0; j<=width; j++) {
|
||||
Int k = minX+i;
|
||||
k = k<limitX?k:limitX;
|
||||
Int l = minY+j;
|
||||
l = l<limitY?l:limitY;
|
||||
if (cornerHeight!=m_map->getHeight(k, l)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (width==1) {
|
||||
match = true;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
|
||||
|
||||
UnsignedShort prevNdxLeft;
|
||||
UnsignedShort prevNdxRight;
|
||||
ICoord2D left;
|
||||
left.x = xOffset;
|
||||
left.y = yOffset;
|
||||
ICoord2D right;
|
||||
right.x = xOffset;
|
||||
right.y = yOffset;
|
||||
advanceLeft(left, xOffset, yOffset, width);
|
||||
advanceRight(right, xOffset, yOffset, width);
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = bottomLeftNdx;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
prevNdxRight = ndx[right.x+right.y*(m_width+1)];
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxRight;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
prevNdxLeft = ndx[left.x+left.y*(m_width+1)];
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxLeft;
|
||||
}
|
||||
curIndex++;
|
||||
Bool didLeft = true;
|
||||
Bool didRight = true;
|
||||
while (didLeft || didRight) {
|
||||
didLeft = advanceLeft(left, xOffset, yOffset, width);
|
||||
if (didLeft) {
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxLeft;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxRight;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
prevNdxLeft = ndx[left.x+left.y*(m_width+1)];
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxLeft;
|
||||
}
|
||||
curIndex++;
|
||||
}
|
||||
didRight = advanceRight(right, xOffset, yOffset, width);
|
||||
if (didRight) {
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxLeft;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxRight;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
prevNdxRight = ndx[right.x+right.y*(m_width+1)];
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxRight;
|
||||
}
|
||||
curIndex++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxLeft;
|
||||
}
|
||||
|
||||
curIndex++;
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = prevNdxRight;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
if (ib) {
|
||||
ib[curIndex] = topRightNdx;
|
||||
}
|
||||
curIndex++;
|
||||
|
||||
return;
|
||||
}
|
||||
Int halfWidth = width/2;
|
||||
|
||||
fillVBRecursive(ib, xOffset, yOffset, halfWidth, ndx, curIndex);
|
||||
fillVBRecursive(ib, xOffset, yOffset+halfWidth, halfWidth, ndx, curIndex);
|
||||
fillVBRecursive(ib, xOffset+halfWidth, yOffset, halfWidth, ndx, curIndex);
|
||||
fillVBRecursive(ib, xOffset+halfWidth, yOffset+halfWidth, halfWidth, ndx, curIndex);
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::fillVBRecursive
|
||||
//=============================================================================
|
||||
/** Fills in vertex & index buffers.
|
||||
*/
|
||||
void W3DTerrainBackground::setFlipRecursive(Int xOffset, Int yOffset, Int width)
|
||||
{
|
||||
|
||||
Int limitX = m_map->getXExtent()-1;
|
||||
Int limitY = m_map->getYExtent()-1;
|
||||
Int i, j;
|
||||
Bool match = true;
|
||||
Int minX = m_xOrigin+xOffset;
|
||||
Int minY = m_yOrigin+yOffset;
|
||||
Int cornerHeight = m_map->getHeight(minX, minY);
|
||||
|
||||
for (i=0; i<=width; i++) {
|
||||
for (j=0; j<=width; j++) {
|
||||
Int k = minX+i;
|
||||
k = k<limitX?k:limitX;
|
||||
Int l = minY+j;
|
||||
l = l<limitY?l:limitY;
|
||||
if (cornerHeight!=m_map->getHeight(k, l)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (width==1) {
|
||||
match = true;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
m_map->setFlipState(minX, minY, true);
|
||||
m_map->setFlipState(minX+width, minY, true);
|
||||
m_map->setFlipState(minX+width, minY+width, true);
|
||||
m_map->setFlipState(minX, minY+width, true);
|
||||
return;
|
||||
}
|
||||
Int halfWidth = width/2;
|
||||
|
||||
|
||||
setFlipRecursive(xOffset, yOffset, halfWidth);
|
||||
setFlipRecursive(xOffset, yOffset+halfWidth, halfWidth);
|
||||
setFlipRecursive(xOffset+halfWidth, yOffset, halfWidth);
|
||||
setFlipRecursive(xOffset+halfWidth, yOffset+halfWidth, halfWidth);
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::doTesselatedUpdate
|
||||
//=============================================================================
|
||||
/** Updates a partial block of vertices from [x0,y0 to x1,y1]
|
||||
The coordinates in partialRange are map cell coordinates, relative to the entire map.
|
||||
The vertex coordinates and texture coordinates, as well as static lighting are updated.
|
||||
*/
|
||||
void W3DTerrainBackground::doTesselatedUpdate(const IRegion2D &partialRange, WorldHeightMap *htMap, Bool doTextures )
|
||||
{
|
||||
if (m_map==NULL) return;
|
||||
if (htMap) {
|
||||
REF_PTR_SET(m_map, htMap);
|
||||
}
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
Int minX = m_xOrigin;
|
||||
Int minY = m_yOrigin;
|
||||
Int maxX = m_xOrigin + m_width;
|
||||
Int maxY = m_yOrigin + m_width;
|
||||
Int limitX = m_map->getXExtent()-1;
|
||||
Int limitY = m_map->getYExtent()-1;
|
||||
|
||||
if (partialRange.lo.x > maxX) return;
|
||||
if (partialRange.lo.y > maxY) return;
|
||||
if (partialRange.hi.x < minX) return;
|
||||
if (partialRange.hi.y < minY) return;
|
||||
|
||||
setFlip(htMap);
|
||||
|
||||
Int count = (m_width+1)*(m_width+1);
|
||||
|
||||
UnsignedShort *ndx = new UnsignedShort[count];
|
||||
|
||||
Int requiredVertex = 0;
|
||||
Int i, j;
|
||||
for (j=minY; j<=maxY; j++) {
|
||||
for (i=minX; i<=maxX; i++) {
|
||||
Int ndxNdx = i-minX + (m_width+1)*(j-minY);
|
||||
DEBUG_ASSERTCRASH(ndxNdx<count, ("Bad ndxNdx"));
|
||||
ndx[ndxNdx] = 0;
|
||||
if (m_map->getFlipState(i, j)) {
|
||||
requiredVertex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_vertexTerrainSize<requiredVertex || m_vertexTerrain==NULL) {
|
||||
m_vertexTerrainSize = requiredVertex;
|
||||
REF_PTR_RELEASE(m_vertexTerrain);
|
||||
m_vertexTerrain=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV2,m_vertexTerrainSize+4,DX8VertexBufferClass::USAGE_DEFAULT));
|
||||
}
|
||||
|
||||
m_curNumTerrainVertices = 0;
|
||||
VertexFormatXYZDUV2 *vb;
|
||||
// Lock the buffer.
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTerrain);
|
||||
vb=(VertexFormatXYZDUV2*)lockVtxBuffer.Get_Vertex_Array();
|
||||
VertexFormatXYZDUV2 *curVb = vb;
|
||||
// Add to the vertex buffer.
|
||||
for (j=minY; j<=maxY; j++) {
|
||||
for (i=minX; i<=maxX; i++) {
|
||||
if (m_map->getFlipState(i, j)) {
|
||||
curVb->diffuse = (0<<24)|TheTerrainRenderObject->getStaticDiffuse(i,j);
|
||||
Vector3 pos;
|
||||
Int k = i<limitX?i:limitX;
|
||||
Int l = j<limitY?j:limitY;
|
||||
pos.Z = ((float)m_map->getHeight(k,l)*MAP_HEIGHT_SCALE);
|
||||
pos.X = (i)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
|
||||
pos.Y = (j)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
|
||||
curVb->u1 = (float)(i-minX)/(float)(m_width);
|
||||
curVb->v1 = 1.0f - (float)(j-minY)/(float)(m_width);
|
||||
curVb->x = pos.X;
|
||||
curVb->y = pos.Y;
|
||||
curVb->z = pos.Z;
|
||||
curVb++;
|
||||
Int ndxNdx = i-minX + (m_width+1)*(j-minY);
|
||||
DEBUG_ASSERTCRASH(ndxNdx<count, ("Bad ndxNdx"));
|
||||
ndx[ndxNdx] = m_curNumTerrainVertices;
|
||||
m_curNumTerrainVertices++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Int requiredIndex = 0;
|
||||
|
||||
fillVBRecursive(NULL, 0, 0, m_width, ndx, requiredIndex);
|
||||
|
||||
if (m_indexTerrainSize<requiredIndex || m_indexTerrain==NULL) {
|
||||
m_indexTerrainSize = requiredIndex;
|
||||
REF_PTR_RELEASE(m_indexTerrain);
|
||||
m_indexTerrain=NEW_REF(DX8IndexBufferClass,(m_indexTerrainSize+4,DX8IndexBufferClass::USAGE_DEFAULT));
|
||||
}
|
||||
|
||||
m_curNumTerrainIndices = 0;
|
||||
|
||||
UnsignedShort *ib;
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTerrain);
|
||||
ib = lockIdxBuffer.Get_Index_Array();
|
||||
fillVBRecursive(ib, 0, 0, m_width, ndx, m_curNumTerrainIndices);
|
||||
delete ndx;
|
||||
ndx = NULL;
|
||||
|
||||
MinMaxAABoxClass bounds;
|
||||
bounds.Init_Empty();
|
||||
|
||||
for (j=minY; j<=maxY; j+=1) {
|
||||
for (i=minX; i<=maxX; i+=1) {
|
||||
Vector3 pos;
|
||||
Int k = i<limitX?i:limitX;
|
||||
Int l = j<limitY?j:limitY;
|
||||
pos.Z = ((float)m_map->getHeight(k,l)*MAP_HEIGHT_SCALE);
|
||||
pos.X = (i)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
|
||||
pos.Y = (j)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
|
||||
bounds.Add_Point(pos);
|
||||
}
|
||||
}
|
||||
m_bounds.Init(bounds);
|
||||
|
||||
if (m_terrainTexture == NULL || doTextures) {
|
||||
REF_PTR_RELEASE(m_terrainTexture);
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
m_terrainTexture = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, PIXELS_PER_GRID);
|
||||
// DEBUG ONLY. jba. m_terrainTexture = (TerrainTextureClass *)NEW_REF(TextureClass, ("TBBib.tga"));
|
||||
m_terrainTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_terrainTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::~W3DTerrainBackground
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
W3DTerrainBackground::~W3DTerrainBackground(void)
|
||||
{
|
||||
freeTerrainBuffers();
|
||||
REF_PTR_RELEASE(m_terrainTexture);
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::W3DTerrainBackground
|
||||
//=============================================================================
|
||||
/** Constructor. Sets m_initialized to true if it finds the w3d models it needs
|
||||
for the bibs. */
|
||||
//=============================================================================
|
||||
W3DTerrainBackground::W3DTerrainBackground(void):
|
||||
m_vertexTerrain(NULL),
|
||||
m_vertexTerrainSize(0),
|
||||
m_initialized(FALSE),
|
||||
m_indexTerrain(NULL),
|
||||
m_indexTerrainSize(0),
|
||||
m_terrainTexture(NULL),
|
||||
m_terrainTexture2X(NULL),
|
||||
m_terrainTexture4X(NULL),
|
||||
m_cullStatus(CULL_STATUS_UNKNOWN),
|
||||
m_texMultiplier(TEX1X)
|
||||
{
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::freeTerrainBuffers
|
||||
//=============================================================================
|
||||
/** Frees the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DTerrainBackground::freeTerrainBuffers(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_vertexTerrain);
|
||||
REF_PTR_RELEASE(m_indexTerrain);
|
||||
m_curNumTerrainVertices=0;
|
||||
m_curNumTerrainIndices=0;
|
||||
m_initialized = false;
|
||||
REF_PTR_RELEASE(m_map);
|
||||
REF_PTR_RELEASE(m_map);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::allocateTerrainBuffers
|
||||
//=============================================================================
|
||||
/** Allocates the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DTerrainBackground::allocateTerrainBuffers(WorldHeightMap *htMap, Int xOrigin, Int yOrigin, Int width)
|
||||
{
|
||||
if (htMap==NULL) return;
|
||||
freeTerrainBuffers(); // in case already allocated. jba [3/24/2003]
|
||||
m_curNumTerrainVertices=0;
|
||||
m_curNumTerrainIndices=0;
|
||||
m_xOrigin = xOrigin;
|
||||
m_yOrigin = yOrigin;
|
||||
m_width = width;
|
||||
m_initialized = true;
|
||||
REF_PTR_SET(m_map, htMap);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::updateCenter
|
||||
//=============================================================================
|
||||
/** Updates the culling status. */
|
||||
//=============================================================================
|
||||
void W3DTerrainBackground::updateCenter(CameraClass *camera)
|
||||
{
|
||||
if (camera->Cull_Box(m_bounds)) {
|
||||
m_cullStatus = CULL_STATUS_INVISIBLE;
|
||||
} else {
|
||||
m_cullStatus = CULL_STATUS_VISIBLE;
|
||||
}
|
||||
|
||||
if (m_cullStatus==CULL_STATUS_INVISIBLE) {
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
m_texMultiplier = TEX1X;
|
||||
return;
|
||||
}
|
||||
Vector3 cameraPos = camera->Get_Position();
|
||||
const Real mipDistance = 310;
|
||||
const Real mipSlop = 40;
|
||||
const Real mip4xDistanceSqr = sqr(mipDistance+mipSlop);
|
||||
const Real mip2xDistanceSqr = sqr(2*mipDistance+mipSlop);
|
||||
const Real mipLODDistanceSqr = sqr(4*mipDistance+mipSlop);
|
||||
Real minDistSqr = 2*mip2xDistanceSqr;
|
||||
Int i, j, k;
|
||||
for (i=-1; i<2; i++) {
|
||||
for (j=-1; j<2; j++) {
|
||||
for (k=-1; k<2; k++) {
|
||||
Vector3 corner = m_bounds.Center;
|
||||
corner.X += m_bounds.Extent.X * i;
|
||||
corner.Y += m_bounds.Extent.Y * j;
|
||||
corner.Z += m_bounds.Extent.Z * k;
|
||||
Real distSqr = (cameraPos-corner).Length2();
|
||||
if (distSqr<minDistSqr) minDistSqr = distSqr;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_texMultiplier = TEX1X;
|
||||
if (minDistSqr<mip4xDistanceSqr) {
|
||||
m_texMultiplier = TEX4X;
|
||||
} else if (minDistSqr<mip2xDistanceSqr) {
|
||||
m_texMultiplier = TEX2X;
|
||||
} else {
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
Int LOD = 0;
|
||||
if (minDistSqr>mipLODDistanceSqr) {
|
||||
LOD = 1;
|
||||
}
|
||||
m_terrainTexture->setLOD(LOD);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::updateCenter
|
||||
//=============================================================================
|
||||
/** Updates the culling status. */
|
||||
//=============================================================================
|
||||
void W3DTerrainBackground::updateTexture(void)
|
||||
{
|
||||
if (m_cullStatus==CULL_STATUS_INVISIBLE) {
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_texMultiplier == TEX4X) {
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
if (m_terrainTexture4X == NULL) {
|
||||
m_terrainTexture4X = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, 4*PIXELS_PER_GRID);
|
||||
m_terrainTexture4X->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_terrainTexture4X->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
}
|
||||
} else if (m_texMultiplier == TEX2X) {
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
if (m_terrainTexture2X == NULL) {
|
||||
m_terrainTexture2X = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, 2*PIXELS_PER_GRID);
|
||||
m_terrainTexture2X->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
m_terrainTexture2X->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
|
||||
}
|
||||
} else {
|
||||
REF_PTR_RELEASE(m_terrainTexture4X);
|
||||
REF_PTR_RELEASE(m_terrainTexture2X);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DTerrainBackground::renderTerrain
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
void W3DTerrainBackground::drawVisiblePolys(RenderInfoClass & rinfo, Bool disableTextures)
|
||||
{
|
||||
#if 1
|
||||
if (m_curNumTerrainIndices == 0) {
|
||||
return;
|
||||
}
|
||||
if (m_cullStatus==CULL_STATUS_INVISIBLE) {
|
||||
return;
|
||||
}
|
||||
// Setup the vertex buffer, shader & texture.
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexTerrain,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexTerrain);
|
||||
if (!disableTextures) {
|
||||
if (m_terrainTexture4X) {
|
||||
DX8Wrapper::Set_Texture(1, m_terrainTexture4X);
|
||||
} else if (m_terrainTexture2X) {
|
||||
DX8Wrapper::Set_Texture(1, m_terrainTexture2X);
|
||||
} else {
|
||||
DX8Wrapper::Set_Texture(1, m_terrainTexture);
|
||||
}
|
||||
}
|
||||
DX8Wrapper::Draw_Triangles( 0, m_curNumTerrainIndices/3, 0, m_curNumTerrainVertices);
|
||||
#else
|
||||
if (m_curNumTerrainIndices == 0) {
|
||||
return;
|
||||
}
|
||||
if (m_cullStatus==CULL_STATUS_INVISIBLE) {
|
||||
return;
|
||||
}
|
||||
// Setup the vertex buffer, shader & texture.
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexTerrain,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexTerrain);
|
||||
if (!disableTextures) {
|
||||
if (m_terrainTexture4X) {
|
||||
DX8Wrapper::Set_Texture(0, m_terrainTexture4X);
|
||||
} else if (m_terrainTexture2X) {
|
||||
DX8Wrapper::Set_Texture(0, m_terrainTexture2X);
|
||||
} else {
|
||||
DX8Wrapper::Set_Texture(0, m_terrainTexture);
|
||||
}
|
||||
}
|
||||
DX8Wrapper::Draw_Triangles( 0, m_curNumTerrainIndices/3, 0, m_curNumTerrainVertices);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,979 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DTerrainTracks.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: RTS3
|
||||
//
|
||||
// File name: W3DTerrainTracks.cpp
|
||||
//
|
||||
// Created: Mark Wilczynski, May 2001
|
||||
//
|
||||
// Desc: Draw track marks on the terrain. Uses a sequence of connected
|
||||
// quads that are oriented to fit the terrain and updated when object
|
||||
// moves.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "W3DDevice/GameClient/W3DTerrainTracks.h"
|
||||
#include "W3DDevice/GameClient/heightmap.h"
|
||||
#include "Common/PerfTimer.h"
|
||||
#include "common/GlobalData.h"
|
||||
#include "common/Debug.h"
|
||||
#include "texture.h"
|
||||
#include "colmath.h"
|
||||
#include "coltest.h"
|
||||
#include "rinfo.h"
|
||||
#include "camera.h"
|
||||
#include "assetmgr.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/Scene.h"
|
||||
#include "GameLogic/TerrainLogic.h"
|
||||
#include "GameLogic/Object.h"
|
||||
#include "GameClient/Drawable.h"
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
#define BRIDGE_OFFSET_FACTOR 0.25f //amount to raise tracks above bridges.
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::~TerrainTracksRenderObjClass
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
TerrainTracksRenderObjClass::~TerrainTracksRenderObjClass(void)
|
||||
{
|
||||
freeTerrainTracksResources();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::TerrainTracksRenderObjClass
|
||||
//=============================================================================
|
||||
/** Constructor. Just nulls out some variables. */
|
||||
//=============================================================================
|
||||
TerrainTracksRenderObjClass::TerrainTracksRenderObjClass(void)
|
||||
{
|
||||
m_stageZeroTexture=NULL;
|
||||
m_lastAnchor=Vector3(0,1,2.25);
|
||||
m_haveAnchor=false;
|
||||
m_haveCap=true;
|
||||
m_topIndex=0;
|
||||
m_bottomIndex=0;
|
||||
m_activeEdgeCount=0;
|
||||
m_totalEdgesAdded=0;
|
||||
m_bound=false;
|
||||
m_ownerDrawable = NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::Get_Obj_Space_Bounding_Sphere
|
||||
//=============================================================================
|
||||
/** WW3D method that returns object bounding sphere used in frustum culling*/
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
||||
{ /// @todo: Add code to cull track marks to screen by constantly updating bounding volumes
|
||||
sphere=m_boundingSphere;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::Get_Obj_Space_Bounding_Box
|
||||
//=============================================================================
|
||||
/** WW3D method that returns object bounding box used in collision detection*/
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
||||
{
|
||||
box=m_boundingBox;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// MirrorRenderObjClass::Class_ID
|
||||
//=============================================================================
|
||||
/** returns the class id, so the scene can tell what kind of render object it has. */
|
||||
//=============================================================================
|
||||
Int TerrainTracksRenderObjClass::Class_ID(void) const
|
||||
{
|
||||
return RenderObjClass::CLASSID_IMAGE3D;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::Clone
|
||||
//=============================================================================
|
||||
/** Not used, but required virtual method. */
|
||||
//=============================================================================
|
||||
RenderObjClass * TerrainTracksRenderObjClass::Clone(void) const
|
||||
{
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::freeTerrainTracksResources
|
||||
//=============================================================================
|
||||
/** Free any W3D resources associated with this object */
|
||||
//=============================================================================
|
||||
Int TerrainTracksRenderObjClass::freeTerrainTracksResources(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_stageZeroTexture);
|
||||
m_haveAnchor=false;
|
||||
m_haveCap=true;
|
||||
m_topIndex=0;
|
||||
m_bottomIndex=0;
|
||||
m_activeEdgeCount=0;
|
||||
m_totalEdgesAdded=0;
|
||||
m_ownerDrawable = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::init
|
||||
//=============================================================================
|
||||
/** Setup size settings and allocate W3D texture */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClass::init( Real width, Real length, const Char *texturename)
|
||||
{
|
||||
freeTerrainTracksResources(); //free old data and ib/vb
|
||||
|
||||
m_boundingSphere.Init(Vector3(0,0,0),400*MAP_XY_FACTOR);
|
||||
m_boundingBox.Center.Set(0.0f, 0.0f, 0.0f);
|
||||
m_boundingBox.Extent.Set(400.0f*MAP_XY_FACTOR, 400.0f*MAP_XY_FACTOR, 1.0f);
|
||||
m_width=width;
|
||||
m_length=length;
|
||||
//no sense culling these things since they have very irregular shape and fade
|
||||
//out over time.
|
||||
Set_Force_Visible(TRUE);
|
||||
m_stageZeroTexture=WW3DAssetManager::Get_Instance()->Get_Texture(texturename);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::addCapEdgeToTrack
|
||||
//=============================================================================
|
||||
/** Cap the current track (adding an feathered edge) so we're ready to resume
|
||||
the track at a new location. Used by objects entering FOW where we need to
|
||||
stop adding edges to the track when they enter the fog boundary but resume
|
||||
elsewhere if they become visible again.
|
||||
*/
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClass::addCapEdgeToTrack(Real x, Real y)
|
||||
{
|
||||
/// @todo: Have object pass its height and orientation so we can remove extra calls.
|
||||
|
||||
if (m_haveCap)
|
||||
{ //we already have a cap or there are no segments to cap
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_activeEdgeCount == 1)
|
||||
{ //if we only have one edge, then it must be the current anchor edge.
|
||||
//since achnors are caps, there is not point in adding another.
|
||||
m_haveCap=TRUE;
|
||||
m_haveAnchor=false; //recreate a new anchor when track resumes.
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 vPos,vZ;
|
||||
Coord3D vZTmp;
|
||||
PathfindLayerEnum objectLayer;
|
||||
Real eHeight;
|
||||
|
||||
if (m_ownerDrawable && (objectLayer=m_ownerDrawable->getObject()->getLayer()) != LAYER_GROUND)
|
||||
eHeight=BRIDGE_OFFSET_FACTOR+TheTerrainLogic->getLayerHeight(x,y,objectLayer,&vZTmp);
|
||||
else
|
||||
eHeight=TheTerrainLogic->getGroundHeight(x,y,&vZTmp);
|
||||
|
||||
vZ.X = vZTmp.x;
|
||||
vZ.Y = vZTmp.y;
|
||||
vZ.Z = vZTmp.z;
|
||||
|
||||
vPos.X=x;
|
||||
vPos.Y=y;
|
||||
vPos.Z=eHeight;
|
||||
|
||||
Vector3 vDir=Vector3(x,y,eHeight)-m_lastAnchor;
|
||||
Int maxEdgeCount=TheTerrainTracksRenderObjClassSystem->m_maxTankTrackEdges;
|
||||
|
||||
//avoid sqrt() by checking distance squared since last track mark
|
||||
if (vDir.Length2() < sqr(m_length))
|
||||
{ //not far enough from anchor to add track
|
||||
//since this is a cap, we'll force the previous segment to transparent
|
||||
Int lastAddedEdge=m_topIndex-1;
|
||||
if (lastAddedEdge < 0)
|
||||
lastAddedEdge = maxEdgeCount-1;
|
||||
m_edges[lastAddedEdge].alpha=0.0f; //force the last added edge to transparent.
|
||||
m_haveCap=TRUE;
|
||||
m_haveAnchor=false; //recreate a new anchor when track resumes.
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_activeEdgeCount >= maxEdgeCount)
|
||||
{ //no more room in buffer so release oldest edge
|
||||
m_bottomIndex++;
|
||||
m_activeEdgeCount--;
|
||||
|
||||
if (m_bottomIndex >= maxEdgeCount)
|
||||
m_bottomIndex=0; //roll buffer back to start
|
||||
}
|
||||
|
||||
if (m_topIndex >= maxEdgeCount)
|
||||
m_topIndex=0; //roll around buffer
|
||||
|
||||
//we traveled far enough from last point.
|
||||
//accept new point
|
||||
vDir.Z=0; //ignore height
|
||||
vDir.Normalize();
|
||||
|
||||
Vector3 vX;
|
||||
|
||||
Vector3::Cross_Product(vDir,vZ,&vX);
|
||||
|
||||
//calculate left end point
|
||||
edgeInfo& topEdge = m_edges[m_topIndex];
|
||||
|
||||
topEdge.endPointPos[0]=vPos-(m_width*0.5f*vX); ///@todo: try getting height at endpoint
|
||||
topEdge.endPointPos[0].Z += 0.2f * MAP_XY_FACTOR; //raise above terrain slightly
|
||||
|
||||
if (m_totalEdgesAdded&1) //every other edge has different set of UV's
|
||||
{
|
||||
topEdge.endPointUV[0].X=0.0f;
|
||||
topEdge.endPointUV[0].Y=0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
topEdge.endPointUV[0].X=0.0f;
|
||||
topEdge.endPointUV[0].Y=1.0f;
|
||||
}
|
||||
|
||||
//calculate right end point
|
||||
topEdge.endPointPos[1]=vPos+(m_width*0.5f*vX); ///@todo: try getting height at endpoint
|
||||
topEdge.endPointPos[1].Z += 0.2f * MAP_XY_FACTOR; //raise above terrain slightly
|
||||
|
||||
if (m_totalEdgesAdded&1) //every other edge has different set of UV's
|
||||
{
|
||||
topEdge.endPointUV[1].X=1.0f;
|
||||
topEdge.endPointUV[1].Y=0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
topEdge.endPointUV[1].X=1.0f;
|
||||
topEdge.endPointUV[1].Y=1.0f;
|
||||
}
|
||||
|
||||
topEdge.timeAdded=WW3D::Get_Sync_Time();
|
||||
topEdge.alpha=0.0f; //fully transparent at cap.
|
||||
m_lastAnchor=vPos;
|
||||
m_activeEdgeCount++;
|
||||
m_totalEdgesAdded++;
|
||||
m_topIndex++; //make space for new edge
|
||||
m_haveCap=TRUE;
|
||||
m_haveAnchor=false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::addEdgeToTrack
|
||||
//=============================================================================
|
||||
/** Try to add an additional segment to track mark. Will do nothing if distance
|
||||
* from last edge is too small. Will overwrite the oldest edge if maximum track
|
||||
* length is reached. Oldest edges should by faded out by that time.
|
||||
*/
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClass::addEdgeToTrack(Real x, Real y)
|
||||
{
|
||||
/// @todo: Have object pass its height and orientation so we can remove extra calls.
|
||||
|
||||
if (!m_haveAnchor)
|
||||
{ //no anchor yet, make this point an anchor.
|
||||
PathfindLayerEnum objectLayer;
|
||||
if (m_ownerDrawable && (objectLayer=m_ownerDrawable->getObject()->getLayer()) != LAYER_GROUND)
|
||||
m_lastAnchor=Vector3(x,y,TheTerrainLogic->getLayerHeight(x,y,objectLayer)+BRIDGE_OFFSET_FACTOR);
|
||||
else
|
||||
m_lastAnchor=Vector3(x,y,TheTerrainLogic->getGroundHeight(x,y));
|
||||
|
||||
m_haveAnchor=true;
|
||||
m_airborne = true;
|
||||
m_haveCap = true; //single segment tracks are always capped because nothing is drawn.
|
||||
return;
|
||||
}
|
||||
|
||||
m_haveCap = false; //have more than 1 segment now so will need to cap if it's interrupted.
|
||||
|
||||
Vector3 vPos,vZ;
|
||||
Coord3D vZTmp;
|
||||
Real eHeight;
|
||||
PathfindLayerEnum objectLayer;
|
||||
|
||||
if (m_ownerDrawable && (objectLayer=m_ownerDrawable->getObject()->getLayer()) != LAYER_GROUND)
|
||||
eHeight=BRIDGE_OFFSET_FACTOR+TheTerrainLogic->getLayerHeight(x,y,objectLayer,&vZTmp);
|
||||
else
|
||||
eHeight=TheTerrainLogic->getGroundHeight(x,y,&vZTmp);
|
||||
|
||||
vZ.X = vZTmp.x;
|
||||
vZ.Y = vZTmp.y;
|
||||
vZ.Z = vZTmp.z;
|
||||
|
||||
vPos.X=x;
|
||||
vPos.Y=y;
|
||||
vPos.Z=eHeight;
|
||||
|
||||
Vector3 vDir=Vector3(x,y,eHeight)-m_lastAnchor;
|
||||
|
||||
//avoid sqrt() by checking distance squared since last track mark
|
||||
if (vDir.Length2() < sqr(m_length))
|
||||
return; //not far enough from anchor to add track
|
||||
|
||||
Int maxEdgeCount=TheTerrainTracksRenderObjClassSystem->m_maxTankTrackEdges;
|
||||
|
||||
if (m_activeEdgeCount >= maxEdgeCount)
|
||||
{ //no more room in buffer so release oldest edge
|
||||
m_bottomIndex++;
|
||||
m_activeEdgeCount--;
|
||||
|
||||
if (m_bottomIndex >= maxEdgeCount)
|
||||
m_bottomIndex=0; //roll buffer back to start
|
||||
}
|
||||
|
||||
if (m_topIndex >= maxEdgeCount)
|
||||
m_topIndex=0; //roll around buffer
|
||||
|
||||
//we traveled far enough from last point.
|
||||
//accept new point
|
||||
vDir.Z=0; //ignore height
|
||||
vDir.Normalize();
|
||||
|
||||
Vector3 vX;
|
||||
|
||||
Vector3::Cross_Product(vDir,vZ,&vX);
|
||||
|
||||
edgeInfo& topEdge = m_edges[m_topIndex];
|
||||
|
||||
//calculate left end point
|
||||
topEdge.endPointPos[0]=vPos-(m_width*0.5f*vX); ///@todo: try getting height at endpoint
|
||||
topEdge.endPointPos[0].Z += 0.2f * MAP_XY_FACTOR; //raise above terrain slightly
|
||||
|
||||
if (m_totalEdgesAdded&1) //every other edge has different set of UV's
|
||||
{
|
||||
topEdge.endPointUV[0].X=0.0f;
|
||||
topEdge.endPointUV[0].Y=0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
topEdge.endPointUV[0].X=0.0f;
|
||||
topEdge.endPointUV[0].Y=1.0f;
|
||||
}
|
||||
|
||||
//calculate right end point
|
||||
topEdge.endPointPos[1]=vPos+(m_width*0.5f*vX); ///@todo: try getting height at endpoint
|
||||
topEdge.endPointPos[1].Z += 0.2f * MAP_XY_FACTOR; //raise above terrain slightly
|
||||
|
||||
if (m_totalEdgesAdded&1) //every other edge has different set of UV's
|
||||
{
|
||||
topEdge.endPointUV[1].X=1.0f;
|
||||
topEdge.endPointUV[1].Y=0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
topEdge.endPointUV[1].X=1.0f;
|
||||
topEdge.endPointUV[1].Y=1.0f;
|
||||
}
|
||||
|
||||
topEdge.timeAdded=WW3D::Get_Sync_Time();
|
||||
topEdge.alpha=1.0f; //fully opaque at start.
|
||||
if (m_airborne || m_activeEdgeCount <= 1) {
|
||||
topEdge.alpha=0.0f; //smooth out track restarts by setting transparent
|
||||
}
|
||||
m_airborne = false;
|
||||
|
||||
m_lastAnchor=vPos;
|
||||
m_activeEdgeCount++;
|
||||
m_totalEdgesAdded++;
|
||||
m_topIndex++; //make space for new edge
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClass::Render
|
||||
//=============================================================================
|
||||
/** Does nothing. Just increments a counter of how many track edges were
|
||||
* requested for rendering this frame. Actual rendering is done in flush().
|
||||
*/
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClass::Render(RenderInfoClass & rinfo)
|
||||
{ ///@todo: After adding track mark visibility tests, add visible marks to another list.
|
||||
if (TheGlobalData->m_makeTrackMarks && m_activeEdgeCount >= 2)
|
||||
TheTerrainTracksRenderObjClassSystem->m_edgesToFlush += m_activeEdgeCount;
|
||||
}
|
||||
|
||||
#define DEFAULT_TRACK_SPACING (MAP_XY_FACTOR * 1.4f)
|
||||
#define DEFAULT_TRACK_WIDTH 4.0f;
|
||||
|
||||
/**Find distance between the "trackfx" bones of the model. This tells us the correct
|
||||
width for the trackmarks.
|
||||
*/
|
||||
static Real computeTrackSpacing(RenderObjClass *renderObj)
|
||||
{
|
||||
Real trackSpacing = DEFAULT_TRACK_SPACING;
|
||||
Int leftTrack;
|
||||
Int rightTrack;
|
||||
|
||||
if ((leftTrack=renderObj->Get_Bone_Index( "TREADFX01" )) != 0 && (rightTrack=renderObj->Get_Bone_Index( "TREADFX02" )) != 0)
|
||||
{ //both bones found, determine distance between them.
|
||||
Vector3 leftPos,rightPos;
|
||||
leftPos=renderObj->Get_Bone_Transform( leftTrack ).Get_Translation();
|
||||
rightPos=renderObj->Get_Bone_Transform( rightTrack ).Get_Translation();
|
||||
rightPos -= leftPos; //get distance between centers of tracks
|
||||
trackSpacing = rightPos.Length() + DEFAULT_TRACK_WIDTH; //add width of each track
|
||||
///@todo: It's assumed that all tank treads have the same width.
|
||||
};
|
||||
|
||||
return trackSpacing;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//TerrainTracksRenderObjClassSystem::bindTrack
|
||||
//=============================================================================
|
||||
/** Grab a track from the free store. If no free tracks exist, return NULL.
|
||||
As long as a track is bound to an object (like a tank) it is ready to accept
|
||||
updates with additional edges. Once it is unbound, it will expire and return
|
||||
to the free store once all tracks have faded out.
|
||||
|
||||
Input: width in world units of each track edge (should probably width of vehicle).
|
||||
length in world units between edges. Shorter lengths produce more edges and
|
||||
smoother curves.
|
||||
texture to use for the tracks - image should be symetrical and include alpha channel.
|
||||
*/
|
||||
//=============================================================================
|
||||
TerrainTracksRenderObjClass *TerrainTracksRenderObjClassSystem::bindTrack( RenderObjClass *renderObject, Real length, const Char *texturename)
|
||||
{
|
||||
TerrainTracksRenderObjClass *mod;
|
||||
|
||||
mod = m_freeModules;
|
||||
if( mod )
|
||||
{
|
||||
// take module off the free list
|
||||
if( mod->m_nextSystem )
|
||||
mod->m_nextSystem->m_prevSystem = mod->m_prevSystem;
|
||||
if( mod->m_prevSystem )
|
||||
mod->m_prevSystem->m_nextSystem = mod->m_nextSystem;
|
||||
else
|
||||
m_freeModules = mod->m_nextSystem;
|
||||
|
||||
// put module on the used list
|
||||
mod->m_prevSystem = NULL;
|
||||
mod->m_nextSystem = m_usedModules;
|
||||
if( m_usedModules )
|
||||
m_usedModules->m_prevSystem = mod;
|
||||
m_usedModules = mod;
|
||||
|
||||
mod->init(computeTrackSpacing(renderObject),length,texturename);
|
||||
mod->m_bound=true;
|
||||
m_TerrainTracksScene->Add_Render_Object( mod);
|
||||
} // end if
|
||||
|
||||
return mod;
|
||||
|
||||
} //end bindTrack
|
||||
|
||||
//=============================================================================
|
||||
//TerrainTracksRenderObjClassSystem::unbindTrack
|
||||
//=============================================================================
|
||||
/** Called when an object (i.e Tank) will not lay down any more tracks and
|
||||
doesn't need this object anymore. The track-laying object will be returned
|
||||
to pool of available tracks as soon as any remaining track edges have faded out.
|
||||
*/
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::unbindTrack( TerrainTracksRenderObjClass *mod )
|
||||
{
|
||||
//this object should return to free store as soon as there is nothing
|
||||
//left to render.
|
||||
mod->m_bound=false;
|
||||
mod->m_ownerDrawable = NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//TerrainTracksRenderObjClassSystem::releaseTrack
|
||||
//=============================================================================
|
||||
/** Returns a track laying object to free store to be used again later.
|
||||
*/
|
||||
void TerrainTracksRenderObjClassSystem::releaseTrack( TerrainTracksRenderObjClass *mod )
|
||||
{
|
||||
if (mod==NULL)
|
||||
return;
|
||||
|
||||
DEBUG_ASSERTCRASH(mod->m_bound == false, ("mod is bound."));
|
||||
|
||||
// remove module from used list
|
||||
if( mod->m_nextSystem )
|
||||
mod->m_nextSystem->m_prevSystem = mod->m_prevSystem;
|
||||
if( mod->m_prevSystem )
|
||||
mod->m_prevSystem->m_nextSystem = mod->m_nextSystem;
|
||||
else
|
||||
m_usedModules = mod->m_nextSystem;
|
||||
|
||||
// add module to free list
|
||||
mod->m_prevSystem = NULL;
|
||||
mod->m_nextSystem = m_freeModules;
|
||||
if( m_freeModules )
|
||||
m_freeModules->m_prevSystem = mod;
|
||||
m_freeModules = mod;
|
||||
mod->freeTerrainTracksResources();
|
||||
m_TerrainTracksScene->Remove_Render_Object(mod);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::TerrainTracksRenderObjClassSystem
|
||||
//=============================================================================
|
||||
/** Constructor. Just nulls out some variables. */
|
||||
//=============================================================================
|
||||
TerrainTracksRenderObjClassSystem::TerrainTracksRenderObjClassSystem()
|
||||
{
|
||||
m_usedModules = NULL;
|
||||
m_freeModules = NULL;
|
||||
m_TerrainTracksScene = NULL;
|
||||
m_edgesToFlush = 0;
|
||||
m_indexBuffer = NULL;
|
||||
m_vertexMaterialClass = NULL;
|
||||
m_vertexBuffer = NULL;
|
||||
|
||||
m_maxTankTrackEdges=TheGlobalData->m_maxTankTrackEdges;
|
||||
m_maxTankTrackOpaqueEdges=TheGlobalData->m_maxTankTrackOpaqueEdges;
|
||||
m_maxTankTrackFadeDelay=TheGlobalData->m_maxTankTrackFadeDelay;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::~TerrainTracksRenderObjClassSystem
|
||||
//=============================================================================
|
||||
/** Destructor. Free all pre-allocated track laying render objects*/
|
||||
//=============================================================================
|
||||
TerrainTracksRenderObjClassSystem::~TerrainTracksRenderObjClassSystem( void )
|
||||
{
|
||||
|
||||
// free all data
|
||||
shutdown();
|
||||
|
||||
m_vertexMaterialClass=NULL;
|
||||
m_TerrainTracksScene=NULL;
|
||||
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::ReAcquireResources
|
||||
//=============================================================================
|
||||
/** (Re)allocates all W3D assets after a reset.. */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::ReAcquireResources(void)
|
||||
{
|
||||
Int i;
|
||||
const Int numModules=TheGlobalData->m_maxTerrainTracks;
|
||||
|
||||
// just for paranoia's sake.
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
REF_PTR_RELEASE(m_vertexBuffer);
|
||||
|
||||
//Create static index buffers. These will index the vertex buffers holding the track segments
|
||||
m_indexBuffer=NEW_REF(DX8IndexBufferClass,((m_maxTankTrackEdges-1)*6));
|
||||
|
||||
// Fill up the IB
|
||||
{
|
||||
DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer);
|
||||
UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
|
||||
|
||||
for (i=0; i<(m_maxTankTrackEdges-1); i++)
|
||||
{
|
||||
ib[3]=ib[0]=i*2;
|
||||
ib[1]=i*2+1;
|
||||
ib[4]=ib[2]=(i+1)*2+1;
|
||||
ib[5]=(i+1)*2;
|
||||
ib+=6; //skip the 6 indices we just filled
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_ASSERTCRASH(numModules*m_maxTankTrackEdges*2 < 65535, ("Too many terrain track edges"));
|
||||
|
||||
m_vertexBuffer=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,numModules*m_maxTankTrackEdges*2,DX8VertexBufferClass::USAGE_DYNAMIC));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::ReleaseResources
|
||||
//=============================================================================
|
||||
/** (Re)allocates all W3D assets after a reset.. */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::ReleaseResources(void)
|
||||
{
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
REF_PTR_RELEASE(m_vertexBuffer);
|
||||
// Note - it is ok to not release the material, as it is a w3d object that
|
||||
// has no dx8 resources. jba.
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::init
|
||||
//=============================================================================
|
||||
/** initialize the system, allocate all the render objects we will need */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::init( SceneClass *TerrainTracksScene )
|
||||
{
|
||||
const Int numModules=TheGlobalData->m_maxTerrainTracks;
|
||||
|
||||
Int i;
|
||||
TerrainTracksRenderObjClass *mod;
|
||||
|
||||
m_TerrainTracksScene=TerrainTracksScene;
|
||||
|
||||
ReAcquireResources();
|
||||
//go with a preset material for now.
|
||||
m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
|
||||
|
||||
//use a multi-texture shader: (text1*diffuse)*text2.
|
||||
m_shaderClass = ShaderClass::_PresetAlphaShader;//_PresetATestSpriteShader;//_PresetOpaqueShader;
|
||||
|
||||
// we cannot initialize a system that is already initialized
|
||||
if( m_freeModules || m_usedModules )
|
||||
{
|
||||
|
||||
// system already online!
|
||||
assert( 0 );
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
// allocate our modules for this system
|
||||
for( i = 0; i < numModules; i++ )
|
||||
{
|
||||
|
||||
mod = NEW_REF( TerrainTracksRenderObjClass, () );
|
||||
|
||||
if( mod == NULL )
|
||||
{
|
||||
|
||||
// unable to allocate modules needed
|
||||
assert( 0 );
|
||||
return;
|
||||
|
||||
} // end if
|
||||
|
||||
mod->m_prevSystem = NULL;
|
||||
mod->m_nextSystem = m_freeModules;
|
||||
if( m_freeModules )
|
||||
m_freeModules->m_prevSystem = mod;
|
||||
m_freeModules = mod;
|
||||
|
||||
} // end for i
|
||||
|
||||
} // end init
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::shutdown
|
||||
//=============================================================================
|
||||
/** Shutdown and free all memory for this system */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::shutdown( void )
|
||||
{
|
||||
TerrainTracksRenderObjClass *nextMod,*mod;
|
||||
|
||||
//release unbound tracks that may still be fading out
|
||||
mod=m_usedModules;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
nextMod=mod->m_nextSystem;
|
||||
|
||||
if (!mod->m_bound)
|
||||
releaseTrack(mod);
|
||||
|
||||
mod = nextMod;
|
||||
} // end while
|
||||
|
||||
|
||||
// free all attached things and used modules
|
||||
assert( m_usedModules == NULL );
|
||||
|
||||
// free all module storage
|
||||
while( m_freeModules )
|
||||
{
|
||||
|
||||
nextMod = m_freeModules->m_nextSystem;
|
||||
REF_PTR_RELEASE (m_freeModules);
|
||||
m_freeModules = nextMod;
|
||||
|
||||
} // end while
|
||||
|
||||
REF_PTR_RELEASE(m_indexBuffer);
|
||||
REF_PTR_RELEASE(m_vertexMaterialClass);
|
||||
REF_PTR_RELEASE(m_vertexBuffer);
|
||||
|
||||
} // end shutdown
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::update
|
||||
//=============================================================================
|
||||
/** Update the state of all active track marks - fade, expire, etc. */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::update()
|
||||
{
|
||||
|
||||
Int iTime=WW3D::Get_Sync_Time();
|
||||
Real iDiff;
|
||||
TerrainTracksRenderObjClass *mod=m_usedModules,*nextMod;
|
||||
|
||||
//first update all the tracks
|
||||
while( mod )
|
||||
{
|
||||
Int i,index;
|
||||
Vector3 *endPoint;
|
||||
Vector2 *endPointUV;
|
||||
|
||||
nextMod = mod->m_nextSystem;
|
||||
|
||||
if (!TheGlobalData->m_makeTrackMarks)
|
||||
mod->m_haveAnchor=false; //force a track restart next time around.
|
||||
|
||||
for (i=0,index=mod->m_bottomIndex; i<mod->m_activeEdgeCount; i++,index++)
|
||||
{
|
||||
if (index >= m_maxTankTrackEdges)
|
||||
index=0;
|
||||
|
||||
endPoint=&mod->m_edges[index].endPointPos[0]; //left endpoint
|
||||
endPointUV=&mod->m_edges[index].endPointUV[0];
|
||||
iDiff=(float)(iTime-mod->m_edges[index].timeAdded);
|
||||
iDiff = 1.0f - iDiff/(Real)m_maxTankTrackFadeDelay;
|
||||
if (iDiff < 0.0)
|
||||
iDiff=0.0f;
|
||||
if (mod->m_edges[index].alpha>0.0f) {
|
||||
mod->m_edges[index].alpha=iDiff;
|
||||
}
|
||||
|
||||
if (iDiff == 0.0f)
|
||||
{ //this edge was invisible, we can remove it
|
||||
mod->m_bottomIndex++;
|
||||
mod->m_activeEdgeCount--;
|
||||
|
||||
if (mod->m_bottomIndex >= m_maxTankTrackEdges)
|
||||
mod->m_bottomIndex=0; //roll buffer back to start
|
||||
}
|
||||
if (mod->m_activeEdgeCount == 0 && !mod->m_bound)
|
||||
releaseTrack(mod);
|
||||
}
|
||||
mod = nextMod;
|
||||
} // end while
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// TerrainTracksRenderObjClassSystem::flush
|
||||
//=============================================================================
|
||||
/** Draw all active track marks for this frame */
|
||||
//=============================================================================
|
||||
void TerrainTracksRenderObjClassSystem::flush()
|
||||
{
|
||||
/** @todo: Optimize system by drawing tracks as triangle strips and use dynamic vertex buffer access.
|
||||
May also try rendering all tracks with one call to W3D/D3D by grouping them by texture.
|
||||
Try improving the fit to vertical surfaces like cliffs.
|
||||
*/
|
||||
|
||||
Int diffuseLight;
|
||||
TerrainTracksRenderObjClass *mod=m_usedModules;
|
||||
if (!mod)
|
||||
return; //nothing to render
|
||||
|
||||
Int trackStartIndex;
|
||||
Real distanceFade;
|
||||
|
||||
if (ShaderClass::Is_Backface_Culling_Inverted())
|
||||
return; //don't render track marks in reflections.
|
||||
|
||||
// adjust shading for time of day.
|
||||
Real shadeR, shadeG, shadeB;
|
||||
shadeR = TheGlobalData->m_terrainAmbient[0].red;
|
||||
shadeG = TheGlobalData->m_terrainAmbient[0].green;
|
||||
shadeB = TheGlobalData->m_terrainAmbient[0].blue;
|
||||
shadeR += TheGlobalData->m_terrainDiffuse[0].red/2;
|
||||
shadeG += TheGlobalData->m_terrainDiffuse[0].green/2;
|
||||
shadeB += TheGlobalData->m_terrainDiffuse[0].blue/2;
|
||||
shadeR*=255.0f;
|
||||
shadeG*=255.0f;
|
||||
shadeB*=255.0f;
|
||||
|
||||
diffuseLight = REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16);
|
||||
Real numFadedEdges=m_maxTankTrackEdges-m_maxTankTrackOpaqueEdges;
|
||||
|
||||
//check if there is anything to draw and fill vertex buffer
|
||||
if (m_edgesToFlush >= 2)
|
||||
{
|
||||
DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexBuffer);
|
||||
VertexFormatXYZDUV1 *verts = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
|
||||
trackStartIndex=0;
|
||||
|
||||
mod=m_usedModules;
|
||||
//Fill our vertex buffer with all the tracks
|
||||
while( mod )
|
||||
{
|
||||
Int i,index;
|
||||
Vector3 *endPoint;
|
||||
Vector2 *endPointUV;
|
||||
|
||||
if (mod->m_activeEdgeCount >= 2 && mod->Is_Really_Visible())
|
||||
{
|
||||
for (i=0,index=mod->m_bottomIndex; i<mod->m_activeEdgeCount; i++,index++)
|
||||
{
|
||||
if (index >= m_maxTankTrackEdges)
|
||||
index=0;
|
||||
|
||||
endPoint=&mod->m_edges[index].endPointPos[0]; //left endpoint
|
||||
endPointUV=&mod->m_edges[index].endPointUV[0];
|
||||
|
||||
distanceFade=1.0f;
|
||||
|
||||
if ((mod->m_activeEdgeCount -1 -i) >= m_maxTankTrackOpaqueEdges)// && i < (MAX_PER_TRACK_EDGE_COUNT-FORCE_FADE_AT_EDGE))
|
||||
{ //we're getting close to the limit on the number of track pieces allowed
|
||||
//so force it to fade out.
|
||||
distanceFade=1.0f-(float)((mod->m_activeEdgeCount -i)-m_maxTankTrackOpaqueEdges)/numFadedEdges;
|
||||
}
|
||||
|
||||
distanceFade *= mod->m_edges[index].alpha; //adjust fade with distance from start of track
|
||||
|
||||
verts->x=endPoint->X;
|
||||
verts->y=endPoint->Y;
|
||||
verts->z=endPoint->Z;
|
||||
|
||||
verts->u1=endPointUV->X;
|
||||
verts->v1=endPointUV->Y;
|
||||
|
||||
//fade the alpha channel with distance
|
||||
verts->diffuse=diffuseLight | ( REAL_TO_INT(distanceFade*255.0f) <<24);
|
||||
verts++;
|
||||
|
||||
endPoint=&mod->m_edges[index].endPointPos[1]; //right endpoint
|
||||
endPointUV=&mod->m_edges[index].endPointUV[1];
|
||||
|
||||
verts->x=endPoint->X;
|
||||
verts->y=endPoint->Y;
|
||||
verts->z=endPoint->Z;
|
||||
|
||||
verts->u1=endPointUV->X;
|
||||
verts->v1=endPointUV->Y; ///@todo: Add diffuse lighting.
|
||||
|
||||
verts->diffuse=diffuseLight | ( REAL_TO_INT(distanceFade*255.0f) <<24);
|
||||
verts++;
|
||||
}//for
|
||||
}// mod has edges to render
|
||||
mod = mod->m_nextSystem;
|
||||
} //while (mod)
|
||||
}//edges to flush
|
||||
|
||||
//draw the filled vertex buffers
|
||||
if (m_edgesToFlush >= 2)
|
||||
{
|
||||
ShaderClass::Invalidate();
|
||||
DX8Wrapper::Set_Material(m_vertexMaterialClass);
|
||||
DX8Wrapper::Set_Shader(m_shaderClass);
|
||||
DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
|
||||
DX8Wrapper::Set_Vertex_Buffer(m_vertexBuffer);
|
||||
|
||||
trackStartIndex=0;
|
||||
mod=m_usedModules;
|
||||
Matrix3D tm(mod->Transform);
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
while (mod)
|
||||
{
|
||||
if (mod->m_activeEdgeCount >= 2 && mod->Is_Really_Visible())
|
||||
{
|
||||
DX8Wrapper::Set_Texture(0,mod->m_stageZeroTexture);
|
||||
DX8Wrapper::Set_Index_Buffer_Index_Offset(trackStartIndex);
|
||||
DX8Wrapper::Draw_Triangles( 0,(mod->m_activeEdgeCount-1)*2, 0, mod->m_activeEdgeCount*2);
|
||||
|
||||
trackStartIndex += mod->m_activeEdgeCount*2;
|
||||
}
|
||||
mod=mod->m_nextSystem;
|
||||
}
|
||||
} //there are some edges to render in pool.
|
||||
|
||||
m_edgesToFlush=0; //reset count for next flush
|
||||
}
|
||||
|
||||
/**Removes all remaining tracks from the rendering system*/
|
||||
void TerrainTracksRenderObjClassSystem::Reset(void)
|
||||
{
|
||||
TerrainTracksRenderObjClass *nextMod,*mod=m_usedModules;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
nextMod=mod->m_nextSystem;
|
||||
|
||||
releaseTrack(mod);
|
||||
|
||||
mod = nextMod;
|
||||
} // end while
|
||||
|
||||
|
||||
// free all attached things and used modules
|
||||
assert( m_usedModules == NULL );
|
||||
m_edgesToFlush=0;
|
||||
}
|
||||
|
||||
/**Clear the treads from each track laying object without freeing the objects.
|
||||
Mostly used when user changed LOD level*/
|
||||
void TerrainTracksRenderObjClassSystem::clearTracks(void)
|
||||
{
|
||||
TerrainTracksRenderObjClass *mod=m_usedModules;
|
||||
|
||||
while(mod)
|
||||
{
|
||||
mod->m_haveAnchor=false;
|
||||
mod->m_haveCap=true;
|
||||
mod->m_topIndex=0;
|
||||
mod->m_bottomIndex=0;
|
||||
mod->m_activeEdgeCount=0;
|
||||
mod->m_totalEdgesAdded=0;
|
||||
|
||||
mod = mod->m_nextSystem;
|
||||
} // end while
|
||||
|
||||
m_edgesToFlush=0;
|
||||
}
|
||||
|
||||
/**Adjust various paremeters which affect the cost of rendering tracks on the map.
|
||||
Parameters are passed via GlobalData*/
|
||||
void TerrainTracksRenderObjClassSystem::setDetail(void)
|
||||
{
|
||||
//Remove all existing track segments from screen.
|
||||
clearTracks();
|
||||
ReleaseResources();
|
||||
|
||||
m_maxTankTrackEdges=TheGlobalData->m_maxTankTrackEdges;
|
||||
m_maxTankTrackOpaqueEdges=TheGlobalData->m_maxTankTrackOpaqueEdges;
|
||||
m_maxTankTrackFadeDelay=TheGlobalData->m_maxTankTrackFadeDelay;
|
||||
|
||||
//We changed the maximum number of visible edges so re-allocate our resources to match.
|
||||
ReAcquireResources();
|
||||
};
|
||||
|
||||
TerrainTracksRenderObjClassSystem *TheTerrainTracksRenderObjClassSystem=NULL; ///< singleton for track drawing system.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Westwood Studios Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2001 - All Rights Reserved
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: Generals
|
||||
//
|
||||
// Module: Video
|
||||
//
|
||||
// File name: W3DDevice/GameClient/W3DVideoBuffer.cpp
|
||||
//
|
||||
// Created: 10/23/01 TR
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "Common/GameMemory.h"
|
||||
#include "WW3D2/texture.h"
|
||||
#include "WW3D2/textureloader.h"
|
||||
#include "W3DDevice/GameClient/W3DVideoBuffer.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Externals
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Types
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Data
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Public Data
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::W3DVideoBuffer
|
||||
//============================================================================
|
||||
|
||||
W3DVideoBuffer::W3DVideoBuffer( VideoBuffer::Type format )
|
||||
: VideoBuffer(format),
|
||||
m_texture(NULL),
|
||||
m_surface(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::SetBuffer
|
||||
//============================================================================
|
||||
|
||||
Bool W3DVideoBuffer::allocate( UnsignedInt width, UnsignedInt height )
|
||||
{
|
||||
free();
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_textureWidth = width;;
|
||||
m_textureHeight = height;;
|
||||
unsigned int temp_depth=1;
|
||||
TextureLoader::Validate_Texture_Size( m_textureWidth, m_textureHeight, temp_depth);
|
||||
|
||||
WW3DFormat w3dFormat = TypeToW3DFormat( m_format );
|
||||
|
||||
if ( w3dFormat == WW3D_FORMAT_UNKNOWN )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_texture = MSGNEW("TextureClass") TextureClass ( m_textureWidth, m_textureHeight, w3dFormat, MIP_LEVELS_1 );
|
||||
|
||||
if ( m_texture == NULL )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( lock() == NULL )
|
||||
{
|
||||
free();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::~W3DVideoBuffer
|
||||
//============================================================================
|
||||
|
||||
W3DVideoBuffer::~W3DVideoBuffer()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::lock
|
||||
//============================================================================
|
||||
|
||||
void* W3DVideoBuffer::lock( void )
|
||||
{
|
||||
void *mem = NULL;
|
||||
|
||||
if ( m_surface != NULL )
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
|
||||
m_surface = m_texture->Get_Surface_Level();
|
||||
|
||||
if ( m_surface )
|
||||
{
|
||||
mem = m_surface->Lock( (Int*) &m_pitch );
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::unlock
|
||||
//============================================================================
|
||||
|
||||
void W3DVideoBuffer::unlock( void )
|
||||
{
|
||||
if ( m_surface != NULL )
|
||||
{
|
||||
m_surface->Unlock();
|
||||
m_surface->Release_Ref();
|
||||
m_surface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::valid
|
||||
//============================================================================
|
||||
|
||||
Bool W3DVideoBuffer::valid( void )
|
||||
{
|
||||
return m_texture != NULL;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::reset
|
||||
//============================================================================
|
||||
|
||||
void W3DVideoBuffer::free( void )
|
||||
{
|
||||
unlock();
|
||||
|
||||
if ( m_texture )
|
||||
{
|
||||
unlock();
|
||||
m_texture->Release_Ref();
|
||||
m_texture = NULL;
|
||||
}
|
||||
m_surface = NULL;
|
||||
|
||||
VideoBuffer::free();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
// W3DVideoBuffer::TypeToW3DFormat
|
||||
//============================================================================
|
||||
|
||||
WW3DFormat W3DVideoBuffer::TypeToW3DFormat( VideoBuffer::Type format )
|
||||
{
|
||||
WW3DFormat w3dFormat = WW3D_FORMAT_UNKNOWN;
|
||||
switch ( format )
|
||||
{
|
||||
case TYPE_X8R8G8B8:
|
||||
w3dFormat = WW3D_FORMAT_X8R8G8B8;
|
||||
break;
|
||||
|
||||
case TYPE_R8G8B8:
|
||||
w3dFormat = WW3D_FORMAT_R8G8B8;
|
||||
break;
|
||||
|
||||
case TYPE_R5G6B5:
|
||||
w3dFormat = WW3D_FORMAT_R5G6B5;
|
||||
break;
|
||||
|
||||
case TYPE_X1R5G5B5:
|
||||
w3dFormat = WW3D_FORMAT_X1R5G5B5;
|
||||
break;
|
||||
}
|
||||
|
||||
return w3dFormat;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// W3DFormatToType
|
||||
//============================================================================
|
||||
|
||||
VideoBuffer::Type W3DVideoBuffer::W3DFormatToType( WW3DFormat w3dFormat )
|
||||
{
|
||||
Type format = TYPE_UNKNOWN;
|
||||
switch ( w3dFormat )
|
||||
{
|
||||
case WW3D_FORMAT_X8R8G8B8:
|
||||
format = VideoBuffer::TYPE_X8R8G8B8;
|
||||
break;
|
||||
case WW3D_FORMAT_R8G8B8:
|
||||
format = VideoBuffer::TYPE_R8G8B8;
|
||||
break;
|
||||
case WW3D_FORMAT_R5G6B5:
|
||||
format = VideoBuffer::TYPE_R5G6B5;
|
||||
break;
|
||||
case WW3D_FORMAT_X1R5G5B5:
|
||||
format = VideoBuffer::TYPE_X1R5G5B5;
|
||||
break;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////// W3DWebBrowser.cpp ///////////////
|
||||
// July 2002 Bryan Cleveland
|
||||
|
||||
#include "W3DDevice/GameClient/W3DWebBrowser.h"
|
||||
#include "WW3D2/Texture.h"
|
||||
#include "WW3D2/TextureLoader.h"
|
||||
#include "WW3D2/SurfaceClass.h"
|
||||
#include "GameClient/Image.h"
|
||||
#include "GameClient/GameWindow.h"
|
||||
#include "vector2i.h"
|
||||
#include <d3dx8.h>
|
||||
#include "WW3D2/dx8wrapper.h"
|
||||
#include "WW3D2/dx8WebBrowser.h"
|
||||
|
||||
W3DWebBrowser::W3DWebBrowser() : WebBrowser() {
|
||||
}
|
||||
|
||||
Bool W3DWebBrowser::createBrowserWindow(char *tag, GameWindow *win)
|
||||
{
|
||||
|
||||
WinInstanceData *winData = win->winGetInstanceData();
|
||||
AsciiString windowName = winData->m_decoratedNameString;
|
||||
|
||||
Int x, y, w, h;
|
||||
|
||||
win->winGetSize(&w, &h);
|
||||
win->winGetScreenPosition(&x, &y);
|
||||
|
||||
WebBrowserURL *url = findURL( AsciiString(tag) );
|
||||
|
||||
if (url == NULL) {
|
||||
DEBUG_LOG(("W3DWebBrowser::createBrowserWindow - couldn't find URL for page %s\n", tag));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CComQIPtr<IDispatch> idisp(m_dispatch);
|
||||
if (m_dispatch == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DX8WebBrowser::CreateBrowser(windowName.str(), url->m_url.str(), x, y, w, h, 0, BROWSEROPTION_SCROLLBARS | BROWSEROPTION_3DBORDER, (LPDISPATCH)this);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void W3DWebBrowser::closeBrowserWindow(GameWindow *win)
|
||||
{
|
||||
DX8WebBrowser::DestroyBrowser(win->winGetInstanceData()->m_decoratedNameString.str());
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: W3DWaypointBuffer.cpp ////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Electronic Arts Pacific.
|
||||
//
|
||||
// Confidential Information
|
||||
// Copyright (C) 2002 - All Rights Reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Project: Command & Conquers: Generals
|
||||
//
|
||||
// File name: W3DWaypointBuffer.cpp
|
||||
//
|
||||
// Created: Kris Morness, October 2002
|
||||
//
|
||||
// Desc: Draw buffer to handle all the waypoints in the scene. Waypoints
|
||||
// are rendered after terrain, after roads & bridges, and after
|
||||
// global fog, but before structures, objects, units, trees, etc.
|
||||
// This way if we have two waypoints at the bottom of a hill but
|
||||
// going through the hill, the line won't get cut off. However,
|
||||
// structures and units on top of paths will render above it. Waypoints
|
||||
// are only shown for selected units while in waypoint plotting mode.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Includes
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "W3DDevice/GameClient/W3DWaypointBuffer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assetmgr.h>
|
||||
#include <texture.h>
|
||||
|
||||
#include "Common/GlobalData.h"
|
||||
#include "Common/RandomValue.h"
|
||||
#include "Common/ThingFactory.h"
|
||||
#include "Common/ThingTemplate.h"
|
||||
|
||||
#include "GameClient/Drawable.h"
|
||||
#include "GameClient/GameClient.h"
|
||||
#include "GameClient/InGameUI.h"
|
||||
|
||||
#include "GameLogic/Object.h"
|
||||
|
||||
#include "GameLogic/Module/AIUpdate.h"
|
||||
|
||||
#include "W3DDevice/GameClient/TerrainTex.h"
|
||||
#include "W3DDevice/GameClient/HeightMap.h"
|
||||
|
||||
#include "WW3D2/Camera.h"
|
||||
#include "WW3D2/DX8Wrapper.h"
|
||||
#include "WW3D2/DX8Renderer.h"
|
||||
#include "WW3D2/Mesh.h"
|
||||
#include "WW3D2/MeshMdl.h"
|
||||
#include "WW3D2/Segline.h"
|
||||
|
||||
|
||||
#define MAX_DISPLAY_NODES 512
|
||||
|
||||
|
||||
|
||||
#ifdef _INTERNAL
|
||||
// for occasional debugging...
|
||||
//#pragma optimize("", off)
|
||||
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DWaypointBuffer::W3DWaypointBuffer
|
||||
//=============================================================================
|
||||
/** Constructor. Sets m_initialized to true if it finds the w3d models it needs
|
||||
for the bibs. */
|
||||
//=============================================================================
|
||||
W3DWaypointBuffer::W3DWaypointBuffer(void)
|
||||
{
|
||||
m_waypointNodeRobj = WW3DAssetManager::Get_Instance()->Create_Render_Obj( "SCMNode" );
|
||||
m_line = new SegmentedLineClass;
|
||||
|
||||
m_texture = WW3DAssetManager::Get_Instance()->Get_Texture( "EXLaser.tga" );
|
||||
|
||||
|
||||
setDefaultLineStyle();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DWaypointBuffer::~W3DWaypointBuffer
|
||||
//=============================================================================
|
||||
/** Destructor. Releases w3d assets. */
|
||||
//=============================================================================
|
||||
W3DWaypointBuffer::~W3DWaypointBuffer(void)
|
||||
{
|
||||
REF_PTR_RELEASE( m_waypointNodeRobj );
|
||||
REF_PTR_RELEASE( m_texture );
|
||||
REF_PTR_RELEASE( m_line );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// W3DWaypointBuffer::freeBibBuffers
|
||||
//=============================================================================
|
||||
/** Frees the index and vertex buffers. */
|
||||
//=============================================================================
|
||||
void W3DWaypointBuffer::freeWaypointBuffers()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void W3DWaypointBuffer::setDefaultLineStyle( void )
|
||||
{
|
||||
if( m_texture )
|
||||
{
|
||||
m_line->Set_Texture( m_texture );
|
||||
}
|
||||
ShaderClass lineShader=ShaderClass::_PresetAdditiveShader;
|
||||
lineShader.Set_Depth_Compare(ShaderClass::PASS_ALWAYS);
|
||||
m_line->Set_Shader( lineShader ); //pick the alpha blending mode you want - see shader.h for others.
|
||||
m_line->Set_Width( 1.5f );
|
||||
m_line->Set_Color( Vector3( 0.25f, 0.5f, 1.0f ) );
|
||||
m_line->Set_Texture_Mapping_Mode( SegLineRendererClass::TILED_TEXTURE_MAP ); //this tiles the texture across the line
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// W3DWaypointBuffer::drawWaypoints
|
||||
//=============================================================================
|
||||
/** Draws the waypoints. Uses camera to cull */
|
||||
//=============================================================================
|
||||
void W3DWaypointBuffer::drawWaypoints(RenderInfoClass &rinfo)
|
||||
{
|
||||
|
||||
if ( ! TheInGameUI )
|
||||
return;
|
||||
|
||||
|
||||
setDefaultLineStyle();
|
||||
|
||||
|
||||
|
||||
if( TheInGameUI->isInWaypointMode() )
|
||||
{
|
||||
//Create a default light environment with no lights and only full ambient.
|
||||
//@todo: Fix later by copying default scene light environement from W3DScene.cpp.
|
||||
LightEnvironmentClass lightEnv;
|
||||
lightEnv.Reset(Vector3(0,0,0), Vector3(1.0f,1.0f,1.0f));
|
||||
lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
|
||||
RenderInfoClass localRinfo(rinfo.Camera);
|
||||
localRinfo.light_environment=&lightEnv;
|
||||
Vector3 points[ MAX_DISPLAY_NODES + 1 ]; //Lines have nodes + 1 points.
|
||||
|
||||
const DrawableList *selected = TheInGameUI->getAllSelectedDrawables();
|
||||
Drawable *draw;
|
||||
for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it )
|
||||
{
|
||||
draw = *it;
|
||||
Object *obj = draw->getObject();
|
||||
Int numPoints = 1;
|
||||
if( obj && ! obj->isKindOf( KINDOF_IGNORED_IN_GUI ))//so mobs and stuff sont make a gazillion lines
|
||||
{
|
||||
AIUpdateInterface *ai = obj->getAI();
|
||||
Int goalSize = ai ? ai->friend_getWaypointGoalPathSize() : 0;
|
||||
Int gpIdx = ai ? ai->friend_getCurrentGoalPathIndex() : 0;
|
||||
if( ai && gpIdx >= 0 && gpIdx < goalSize )
|
||||
{
|
||||
const Coord3D *pos = obj->getPosition();
|
||||
points[ 0 ].Set( Vector3( pos->x, pos->y, pos->z ) );
|
||||
|
||||
for( int i = gpIdx; i < goalSize; i++ )
|
||||
{
|
||||
const Coord3D *waypoint = ai->friend_getGoalPathPosition( i );
|
||||
if( waypoint )
|
||||
{
|
||||
//Render line from previous point to current node.
|
||||
|
||||
if( numPoints < MAX_DISPLAY_NODES + 1 )
|
||||
{
|
||||
points[ numPoints ].Set( Vector3( waypoint->x, waypoint->y, waypoint->z ) );
|
||||
numPoints++;
|
||||
}
|
||||
|
||||
m_waypointNodeRobj->Set_Position(Vector3(waypoint->x,waypoint->y,waypoint->z));
|
||||
WW3D::Render(*m_waypointNodeRobj,localRinfo);
|
||||
}
|
||||
}
|
||||
//Now render the lines in one pass!
|
||||
m_line->Set_Points( numPoints, points );
|
||||
m_line->Render( localRinfo );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // maybe we want to draw rally points, then?
|
||||
{
|
||||
//Create a default light environment with no lights and only full ambient.
|
||||
//@todo: Fix later by copying default scene light environement from W3DScene.cpp.
|
||||
LightEnvironmentClass lightEnv;
|
||||
lightEnv.Reset(Vector3(0,0,0), Vector3(1.0f,1.0f,1.0f));
|
||||
lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
|
||||
RenderInfoClass localRinfo(rinfo.Camera);
|
||||
localRinfo.light_environment=&lightEnv;
|
||||
Vector3 points[ MAX_DISPLAY_NODES + 1 ]; //Lines have nodes + 1 points.
|
||||
|
||||
const DrawableList *selected = TheInGameUI->getAllSelectedDrawables();
|
||||
Drawable *draw;
|
||||
for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it )
|
||||
{
|
||||
draw = *it;
|
||||
Object *obj = draw->getObject();
|
||||
|
||||
Int numPoints = 0;
|
||||
if( obj )
|
||||
{
|
||||
if ( ! obj->isLocallyControlled())
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
// WAIT! before we go browsing the drawable list for buildings that want to draw their rally points
|
||||
// lets test for that very special case of having a listeningoutpost selected, and some enemy drawable moused-over
|
||||
if ( obj->isKindOf( KINDOF_REVEALS_ENEMY_PATHS ) )
|
||||
{
|
||||
|
||||
DrawableID enemyID = TheInGameUI->getMousedOverDrawableID();
|
||||
Drawable *enemyDraw = TheGameClient->findDrawableByID( enemyID );
|
||||
if ( enemyDraw )
|
||||
{
|
||||
Object *enemy = enemyDraw->getObject();
|
||||
if ( enemy )
|
||||
{
|
||||
if ( enemy->getRelationship( obj ) == ENEMIES )
|
||||
{
|
||||
|
||||
Coord3D delta = *obj->getPosition();
|
||||
delta.sub( enemy->getPosition() );
|
||||
if ( delta.length() <= obj->getVisionRange() ) // is listening outpost close enough to do this?
|
||||
{
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
AIUpdateInterface *ai = enemy->getAI();
|
||||
Int goalSize = ai ? ai->friend_getWaypointGoalPathSize() : 0;
|
||||
Int gpIdx = ai ? ai->friend_getCurrentGoalPathIndex() : 0;
|
||||
if( ai )
|
||||
{
|
||||
Bool lineExists = FALSE;
|
||||
|
||||
const Coord3D *pos = enemy->getPosition();
|
||||
points[ numPoints++ ].Set( Vector3( pos->x, pos->y, pos->z ) );
|
||||
|
||||
if ( gpIdx >= 0 && gpIdx < goalSize )// Ooh, the enemy is in waypoint mode
|
||||
{
|
||||
|
||||
for( int i = gpIdx; i < goalSize; i++ )
|
||||
{
|
||||
const Coord3D *waypoint = ai->friend_getGoalPathPosition( i );
|
||||
if( waypoint )
|
||||
{
|
||||
//Render line from previous point to current node.
|
||||
|
||||
if( numPoints < MAX_DISPLAY_NODES + 1 )
|
||||
{
|
||||
points[ numPoints++ ].Set( Vector3( waypoint->x, waypoint->y, waypoint->z ) );
|
||||
}
|
||||
|
||||
m_waypointNodeRobj->Set_Position(Vector3(waypoint->x,waypoint->y,waypoint->z));
|
||||
WW3D::Render(*m_waypointNodeRobj,localRinfo);
|
||||
lineExists = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // then enemy may be moving to a goal position
|
||||
{
|
||||
const Coord3D *destinationPoint = ai->getGoalPosition();
|
||||
if ( destinationPoint->length() > 1.0f )
|
||||
{
|
||||
points[ numPoints++ ].Set( Vector3( destinationPoint->x, destinationPoint->y, destinationPoint->z ) );
|
||||
m_waypointNodeRobj->Set_Position(Vector3(destinationPoint->x,destinationPoint->y,destinationPoint->z));
|
||||
WW3D::Render(*m_waypointNodeRobj,localRinfo);
|
||||
lineExists = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( lineExists )
|
||||
{
|
||||
//Now render the lines in one pass!
|
||||
|
||||
m_line->Set_Color( Vector3( 0.95f, 0.5f, 0.0f ) );
|
||||
m_line->Set_Width( 3.0f );
|
||||
|
||||
m_line->Set_Points( numPoints, points );
|
||||
m_line->Render( localRinfo );
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;// dont even bother with the rest, since this one listening outpost satisfies the single path-line limit
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ExitInterface *exitInterface = obj->getObjectExitInterface();
|
||||
if( exitInterface )
|
||||
{
|
||||
|
||||
Coord3D exitPoint;
|
||||
if ( ! exitInterface->getExitPosition(exitPoint))
|
||||
exitPoint = *obj->getPosition();
|
||||
|
||||
points[ numPoints ].Set( Vector3( exitPoint.x, exitPoint.y, exitPoint.z ) );
|
||||
numPoints++;
|
||||
|
||||
Bool boxWrap = TRUE;
|
||||
Coord3D naturalRallyPoint;
|
||||
if (exitInterface->getNaturalRallyPoint(naturalRallyPoint, FALSE))//FALSE means "without the extra offset"
|
||||
{
|
||||
if( !naturalRallyPoint.equals( exitPoint ) )
|
||||
{
|
||||
points[ numPoints ].Set( Vector3( naturalRallyPoint.x, naturalRallyPoint.y, naturalRallyPoint.z ) );
|
||||
numPoints++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Helipad rally point -- so don't use box wrapping.
|
||||
boxWrap = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
continue; //next drawable
|
||||
|
||||
const Coord3D *rallyPoint = exitInterface->getRallyPoint();
|
||||
if( rallyPoint )
|
||||
{
|
||||
if( boxWrap )
|
||||
{
|
||||
|
||||
//test to se whether the rally point flanks the side of the natural rally point
|
||||
//to do this we find the two corners of the geometry extents that are nearest the natural rally point
|
||||
// these define the natural rally point edge
|
||||
// an intermediate point should be inserted at the corner nearest the rally point
|
||||
const GeometryInfo& geom = obj->getGeometryInfo();
|
||||
const Coord3D *ctr = obj->getPosition();
|
||||
Coord3D NRPDelta;
|
||||
NRPDelta.x = naturalRallyPoint.x - exitPoint.x;
|
||||
NRPDelta.y = naturalRallyPoint.y - exitPoint.y;
|
||||
NRPDelta.z = 0.0f;
|
||||
|
||||
|
||||
//This is a quick idiot test to se whether the rally line needs to wrap the box at all
|
||||
Coord3D wayOutPoint = NRPDelta;
|
||||
wayOutPoint.normalize();
|
||||
wayOutPoint.scale( 99999.9f );
|
||||
Real wayOutLength = wayOutPoint.length();
|
||||
wayOutPoint.add(&naturalRallyPoint);
|
||||
|
||||
|
||||
//if the rallypoint is closer to the wayoutpoint than it is to the natural rally point then we definitely do not wrap
|
||||
Coord3D rallyToWayOutDelta = wayOutPoint;
|
||||
rallyToWayOutDelta.sub(rallyPoint);
|
||||
if ( (100.0f + rallyToWayOutDelta.length()) > wayOutLength)
|
||||
{
|
||||
|
||||
//if we passed the above idiot test, now lets be sure by testing the dotproduct of the rp against the wayoutpoint
|
||||
wayOutPoint.normalize();// a normal shooting straight out the door
|
||||
//next comes the delta between the NRP and the RP
|
||||
Coord3D NRPToRPDelta = naturalRallyPoint;
|
||||
NRPToRPDelta.sub(rallyPoint);
|
||||
NRPToRPDelta.normalize();
|
||||
Real dot = NRPToRPDelta.x * wayOutPoint.x + NRPToRPDelta.y * wayOutPoint.y;
|
||||
if (dot > 0)
|
||||
{
|
||||
|
||||
Real angle = obj->getOrientation();
|
||||
Real c = (Real)cos(angle);
|
||||
Real s = (Real)sin(angle);
|
||||
|
||||
Coord3D NRPToCtrDelta;
|
||||
NRPToCtrDelta.x = naturalRallyPoint.x - ctr->x;
|
||||
NRPToCtrDelta.y = naturalRallyPoint.y - ctr->y;
|
||||
NRPToCtrDelta.x = 0.0f;
|
||||
|
||||
Real exc = geom.getMajorRadius() * c;
|
||||
Real eyc = geom.getMinorRadius() * c;
|
||||
Real exs = geom.getMajorRadius() * s;
|
||||
Real eys = geom.getMinorRadius() * s;
|
||||
|
||||
Coord2D corners[ 4 ];
|
||||
|
||||
corners[0].x = ctr->x - exc - eys;
|
||||
corners[0].y = ctr->y + eyc - exs;
|
||||
corners[1].x = ctr->x + exc - eys;
|
||||
corners[1].y = ctr->y + eyc + exs;
|
||||
corners[2].x = ctr->x + exc + eys;
|
||||
corners[2].y = ctr->y - eyc + exs;
|
||||
corners[3].x = ctr->x - exc + eys;
|
||||
corners[3].y = ctr->y - eyc - exs;
|
||||
|
||||
Coord2D *pNearElbow = NULL;//find the closest corner to the rallyPoint same end as door
|
||||
Coord2D *pFarElbow = NULL; //find the closest corner to the rallypoint away from door
|
||||
Coord2D *nearCandidate = NULL;
|
||||
Coord3D cornerToRPDelta, cornerToExitDelta;
|
||||
cornerToRPDelta.z = 0.0f;
|
||||
cornerToExitDelta.z = 0.0f;
|
||||
Real elbowDistanceNear = 99999.9f;
|
||||
Real elbowDistanceFar = 99999.9f;
|
||||
|
||||
for (UnsignedInt cornerIndex = 0; cornerIndex < 4; ++ cornerIndex)
|
||||
{
|
||||
nearCandidate = &corners[cornerIndex];//for quicker array access
|
||||
cornerToExitDelta.x = exitPoint.x - nearCandidate->x;
|
||||
cornerToExitDelta.y = exitPoint.y - nearCandidate->y;
|
||||
cornerToExitDelta.normalize();
|
||||
|
||||
dot = cornerToExitDelta.x * wayOutPoint.x + cornerToExitDelta.y * wayOutPoint.y;
|
||||
if ( dot < 0.0f )
|
||||
{
|
||||
cornerToRPDelta.x = rallyPoint->x - nearCandidate->x;
|
||||
cornerToRPDelta.y = rallyPoint->y - nearCandidate->y;
|
||||
if (cornerToRPDelta.length() < elbowDistanceNear)
|
||||
{
|
||||
elbowDistanceNear = cornerToRPDelta.length();
|
||||
pNearElbow = nearCandidate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cornerToRPDelta.x = rallyPoint->x - nearCandidate->x;
|
||||
cornerToRPDelta.y = rallyPoint->y - nearCandidate->y;
|
||||
if (cornerToRPDelta.length() < elbowDistanceFar)
|
||||
{
|
||||
elbowDistanceFar = cornerToRPDelta.length();
|
||||
pFarElbow = nearCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (pNearElbow)//did we find a nearest corner?
|
||||
{
|
||||
m_waypointNodeRobj->Set_Position(Vector3(pNearElbow->x,pNearElbow->y,ctr->z));
|
||||
WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
|
||||
points[ numPoints ].Set( Vector3( pNearElbow->x, pNearElbow->y, ctr->z ) );
|
||||
numPoints++;
|
||||
|
||||
|
||||
//and for that matter did we find a far side coner?
|
||||
if (pFarElbow)//did we find a nearest corner?
|
||||
{
|
||||
// but let's test the dot of the first elbow against the rally point to find out
|
||||
//whethet the rally point wraps around this one, too
|
||||
Coord3D firstElbowDelta;
|
||||
firstElbowDelta.x = naturalRallyPoint.x - pNearElbow->x;
|
||||
firstElbowDelta.y = naturalRallyPoint.y - pNearElbow->y;
|
||||
firstElbowDelta.z = 0.0f;
|
||||
firstElbowDelta.normalize();
|
||||
|
||||
Coord3D firstToRPDelta;
|
||||
firstToRPDelta.x = pNearElbow->x - rallyPoint->x;
|
||||
firstToRPDelta.y = pNearElbow->y - rallyPoint->y;
|
||||
firstToRPDelta.z = 0.0f;
|
||||
firstToRPDelta.normalize();
|
||||
|
||||
dot = firstToRPDelta.x * firstElbowDelta.x + firstToRPDelta.y * firstElbowDelta.y;
|
||||
if (dot < 0)// we have a second elbow
|
||||
{
|
||||
m_waypointNodeRobj->Set_Position(Vector3(pFarElbow->x,pFarElbow->y,ctr->z));
|
||||
WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
|
||||
points[ numPoints ].Set( Vector3( pFarElbow->x, pFarElbow->y, ctr->z ) );
|
||||
numPoints++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Finally draw the line out to the RallyPoint
|
||||
points[ numPoints ].Set( Vector3( rallyPoint->x, rallyPoint->y, rallyPoint->z ) );
|
||||
numPoints++;
|
||||
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
m_waypointNodeRobj->Set_Position(Vector3(naturalRallyPoint.x,naturalRallyPoint.y,naturalRallyPoint.z));
|
||||
WW3D::Render(*m_waypointNodeRobj,localRinfo); //The little hockey puck
|
||||
|
||||
|
||||
m_line->Set_Points( numPoints, points );
|
||||
m_line->Render( localRinfo );
|
||||
|
||||
}// end if exit interface
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user