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:
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user