/* ** Command & Conquer Generals(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 . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // RadiusDecal.cpp /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #define DEFINE_SHADOW_NAMES #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/Xfer.h" #include "GameClient/RadiusDecal.h" #include "GameClient/Shadow.h" #include "GameLogic/GameLogic.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif // ------------------------------------------------------------------------------------------------ RadiusDecalTemplate::RadiusDecalTemplate() : m_shadowType(SHADOW_ALPHA_DECAL), m_minOpacity(1.0f), m_maxOpacity(1.0f), m_opacityThrobTime(LOGICFRAMES_PER_SECOND), m_color(0), m_onlyVisibleToOwningPlayer(true), m_name(AsciiString::TheEmptyString) // Added By Sadullah Nader for Init purposes { } // ------------------------------------------------------------------------------------------------ void RadiusDecalTemplate::createRadiusDecal(const Coord3D& pos, Real radius, const Player* owningPlayer, RadiusDecal& result) const { result.clear(); if (owningPlayer == NULL) { DEBUG_CRASH(("You MUST specify a non-NULL owningPlayer to createRadiusDecal. (srj)\n")); return; } if (m_name.isEmpty() || radius <= 0.0f) return; // it is now considered nonEmpty, regardless of the state of m_decal, etc result.m_empty = false; if (!m_onlyVisibleToOwningPlayer || owningPlayer->getPlayerIndex() == ThePlayerList->getLocalPlayer()->getPlayerIndex()) { Shadow::ShadowTypeInfo decalInfo; decalInfo.allowUpdates = FALSE; // shadow texture will never update decalInfo.allowWorldAlign = TRUE; // shadow image will wrap around world objects decalInfo.m_type = m_shadowType; strcpy(decalInfo.m_ShadowName, m_name.str()); // name of your texture decalInfo.m_sizeX = radius*2; // world space dimensions decalInfo.m_sizeY = radius*2; // world space dimensions result.m_decal = TheProjectedShadowManager->addDecal(&decalInfo); if (result.m_decal) { result.m_decal->setAngle(0.0f); result.m_decal->setColor(m_color == 0 ? owningPlayer->getPlayerColor() : m_color); result.m_decal->setPosition(pos.x, pos.y, pos.z); result.m_template = this; } else { DEBUG_CRASH(("Unable to add decal %s\n",decalInfo.m_ShadowName)); } } } // ------------------------------------------------------------------------------------------------ void RadiusDecalTemplate::xferRadiusDecalTemplate( Xfer *xfer ) { // version XferVersion currentVersion = 1; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); xfer->xferAsciiString(&m_name); xfer->xferUser(&m_shadowType, sizeof(m_shadowType)); xfer->xferReal(&m_minOpacity); xfer->xferReal(&m_maxOpacity); xfer->xferUnsignedInt(&m_opacityThrobTime); xfer->xferColor(&m_color); xfer->xferBool(&m_onlyVisibleToOwningPlayer); } // ------------------------------------------------------------------------------------------------ /*static*/ void RadiusDecalTemplate::parseRadiusDecalTemplate(INI* ini, void *instance, void * store, const void* /*userData*/) { static const FieldParse dataFieldParse[] = { { "Texture", INI::parseAsciiString, NULL, offsetof( RadiusDecalTemplate, m_name ) }, { "Style", INI::parseBitString32, TheShadowNames, offsetof( RadiusDecalTemplate, m_shadowType ) }, { "OpacityMin", INI::parsePercentToReal, NULL, offsetof( RadiusDecalTemplate, m_minOpacity ) }, { "OpacityMax", INI::parsePercentToReal, NULL, offsetof( RadiusDecalTemplate, m_maxOpacity) }, { "OpacityThrobTime", INI::parseDurationUnsignedInt,NULL, offsetof( RadiusDecalTemplate, m_opacityThrobTime ) }, { "Color", INI::parseColorInt, NULL, offsetof( RadiusDecalTemplate, m_color ) }, { "OnlyVisibleToOwningPlayer", INI::parseBool, NULL, offsetof( RadiusDecalTemplate, m_onlyVisibleToOwningPlayer ) }, { 0, 0, 0, 0 } }; ini->initFromINI(store, dataFieldParse); } // ------------------------------------------------------------------------------------------------ RadiusDecal::RadiusDecal() : m_template(NULL), m_decal(NULL), m_empty(true) { } // ------------------------------------------------------------------------------------------------ RadiusDecal::RadiusDecal(const RadiusDecal& that) : m_template(NULL), m_decal(NULL), m_empty(true) { DEBUG_CRASH(("not fully implemented")); } // ------------------------------------------------------------------------------------------------ RadiusDecal& RadiusDecal::operator=(const RadiusDecal& that) { if (this != &that) { m_template = NULL; if (m_decal) m_decal->release(); m_decal = NULL; m_empty = true; DEBUG_CRASH(("not fully implemented")); } return *this; } // ------------------------------------------------------------------------------------------------ void RadiusDecal::xferRadiusDecal( Xfer *xfer ) { /// @todo implement me if (xfer->getXferMode() == XFER_LOAD) { clear(); } } // ------------------------------------------------------------------------------------------------ void RadiusDecal::clear() { m_template = NULL; if (m_decal) { m_decal->release(); } m_decal = NULL; m_empty = true; } // ------------------------------------------------------------------------------------------------ RadiusDecal::~RadiusDecal() { clear(); } // ------------------------------------------------------------------------------------------------ void RadiusDecal::update() { if (m_decal && m_template) { UnsignedInt now = TheGameLogic->getFrame(); Real theta = (2*PI) * (Real)(now % m_template->m_opacityThrobTime) / (Real)m_template->m_opacityThrobTime; Real percent = 0.5f * (Sin(theta) + 1.0f); Int opac; if( TheGameLogic->getDrawIconUI() ) { opac = REAL_TO_INT((m_template->m_minOpacity + percent * (m_template->m_maxOpacity - m_template->m_minOpacity)) * 255.0f); } else { //Scripts turned this off, so don't show them! opac = 0; } m_decal->setOpacity(opac); } } void RadiusDecal::setOpacity( Real o ) { if (m_decal) { m_decal->setOpacity(REAL_TO_INT(255.0f * o)); } } // ------------------------------------------------------------------------------------------------ void RadiusDecal::setPosition(const Coord3D& pos) { if (m_decal) { m_decal->setPosition(pos.x, pos.y, pos.z); //world space position of center of decal } }