From e2eff57b0dd5285d05effe2eee1417fdd58c2882 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 10:28:06 +0200 Subject: [PATCH 1/7] bugfix(view): Fix view ray casting behavior for mouse picks, drawable occlusion and radar box --- Core/GameEngine/Include/GameClient/View.h | 23 ++-- .../GameClient/MessageStream/CommandXlat.cpp | 18 +-- .../MessageStream/GUICommandTranslator.cpp | 50 ++++---- .../MessageStream/PlaceEventTranslator.cpp | 26 ++-- .../MessageStream/SelectionXlat.cpp | 8 +- Core/GameEngine/Source/GameClient/View.cpp | 51 +++++--- .../Include/W3DDevice/GameClient/W3DView.h | 4 +- .../W3DDevice/GameClient/WorldHeightMap.h | 2 + .../W3DDevice/Common/System/W3DRadar.cpp | 52 ++++---- .../W3DDevice/GameClient/BaseHeightMap.cpp | 2 +- .../W3DDevice/GameClient/W3DShaderManager.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DView.cpp | 111 +++++++++++------- .../GameClient/Water/W3DWaterTracks.cpp | 96 ++++++++------- .../W3DDevice/GameClient/WorldHeightMap.cpp | 17 +++ Core/Libraries/Include/Lib/BaseType.h | 8 ++ Core/Libraries/Source/WWVegas/WWMath/plane.h | 17 ++- .../W3DDevice/GameClient/W3DDisplay.cpp | 13 +- 17 files changed, 301 insertions(+), 199 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index d1952d403ea..53c01d8aa64 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -33,7 +33,9 @@ #include "Common/GameType.h" #include "Common/Snapshot.h" #include "Lib/BaseType.h" +#include "WW3D2/camera.h" #include "WW3D2/coltype.h" ///< we don't generally do this, but we need the W3D collision types +#include "WWMath/plane.h" #include "WWMath/wwmath.h" #define DEFAULT_VIEW_WIDTH 640 @@ -120,11 +122,12 @@ class View : public Snapshot Bool (*callback)( Drawable *draw, void *userData ), void *userData ) = 0; - /** project the 4 corners of this view into the world and return each point as a parameter, - the world points are at the requested Z */ - virtual void getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + /// Project the 4 corners of this view into the world and return each point as a parameter, + /// the world points are at the requested Z. Returns whether all corner view rays intersect + /// with the Z plane. + virtual PlaneIntersectionType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ); + Real z, ViewportClass viewPort = ViewportClass() ); virtual void setWidth( Int width ) { m_width = width; } virtual Int getWidth() { return m_width; } @@ -238,8 +241,12 @@ class View : public Snapshot Bool worldToScreen( const Coord3D *w, ICoord2D *s ) { return worldToScreenTriReturn( w, s ) == WTS_INSIDE_FRUSTUM; } ///< Transform world coordinate "w" into screen coordinate "s" virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) = 0; ///< Like worldToScreen(), but with a more informative return value - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) = 0; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) = 0; ///< transform screen point to world point at the specified world Z value + + /// Transform screen point to the viewed world position on the 3D terrain. Returns true when intersection exists. + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) = 0; + + /// Transform screen point to the viewed world position at the specified world Z height. Returns the type of the intersection. + virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) = 0; virtual void getLocation ( ViewLocation *location ); ///< write the view's current location in to the view location object virtual void setLocation ( const ViewLocation *location ); ///< set the view's current location from to the view location object @@ -403,8 +410,8 @@ class ViewDummy : public View { return WTS_INVALID; } - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {} - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {} + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } + virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override { return PlaneIntersectionType_None; } virtual void drawView() override {} virtual void updateView() override {} virtual void stepView() override {} diff --git a/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp index fa0d78a384f..6c6cfdebfab 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp @@ -3900,7 +3900,8 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage // create the message and append arguments for a guard location GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if (!TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos )) + break; newMsg->appendLocationArgument(pos); newMsg->appendIntegerArgument(GUARDMODE_NORMAL); @@ -3918,8 +3919,6 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage if (TheGlobalData->m_useAlternateMouse && TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp)) { - Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); - // NOTE: RIGHT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. // If we see this msg, no object was clicked on, therefore clicked on ground. // Issue move command to all currently selected objects. @@ -3930,9 +3929,11 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage // translate from screen coordinates to terrain coords Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if (!TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos )) + break; const CommandButton *command = TheInGameUI->getGUICommand(); + Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); Bool controllable = TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); if (isPoint && controllable) @@ -3971,7 +3972,8 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage // create the message and append arguments for a guard location GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if (!TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos )) + break; newMsg->appendLocationArgument(pos); newMsg->appendIntegerArgument(GUARDMODE_NORMAL); @@ -3985,8 +3987,6 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage } case GameMessage::MSG_MOUSE_LEFT_CLICK: { - Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); - // NOTE: LEFT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. // If we see this msg, no object was clicked on, therefore clicked on ground. // Issue move command to all currently selected objects. @@ -3997,7 +3997,8 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage // translate from screen coordinates to terrain coords Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if( !TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ) ) + break; const CommandButton *command = TheInGameUI->getGUICommand(); // maintain this as the list of GUI button initiated commands that fire with left click in alt mouse mode @@ -4012,6 +4013,7 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage if ((TheGlobalData->m_useAlternateMouse) && (! isFiringGUICommand)) break; + Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); Bool controllable = TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); if (isPoint && controllable) diff --git a/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp b/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp index d37d7f51dec..dbaf9d29c23 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp @@ -141,20 +141,19 @@ static CommandStatus doFireWeaponCommand( const CommandButton *command, const IC Coord3D world; // translate the mouse location into world coords - TheTacticalView->screenToTerrain( mouse, &world ); - - // create the message and append arguments - msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON_AT_LOCATION ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - msg->appendLocationArgument( world ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - - //Also append the object ID (incase weapon doesn't like obstacles on land). - Object *target = validUnderCursor( mouse, command, PICK_TYPE_SELECTABLE ); - ObjectID targetID = target ? target->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - + if (TheTacticalView->screenToTerrain( mouse, &world )) + { + // create the message and append arguments + msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON_AT_LOCATION ); + msg->appendIntegerArgument( command->getWeaponSlot() ); + msg->appendLocationArgument( world ); + msg->appendIntegerArgument( command->getMaxShotsToFire() ); + //Also append the object ID (incase weapon doesn't like obstacles on land). + Object *target = validUnderCursor( mouse, command, PICK_TYPE_SELECTABLE ); + ObjectID targetID = target ? target->getID() : INVALID_ID; + msg->appendObjectIDArgument( targetID ); + } } else if( BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) { @@ -233,7 +232,8 @@ static CommandStatus doGuardCommand( const CommandButton *command, GuardMode gua if (BitIsSet( command->getOptions(), NEED_TARGET_POS )) { // translate the mouse location into world coords - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; } else { @@ -277,7 +277,8 @@ static CommandStatus doAttackMoveCommand( const CommandButton *command, const IC // convert mouse point to world coords Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // send the message to set the rally point GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_ATTACKMOVETO ); @@ -316,7 +317,8 @@ static CommandStatus doSetRallyPointCommand( const CommandButton *command, const // convert mouse point to world coords Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // send the message to set the rally point GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SET_RALLY_POINT ); @@ -339,7 +341,8 @@ static CommandStatus doPlaceBeacon( const CommandButton *command, const ICoord2D // convert mouse point to world coords Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // send the message to set the rally point GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_PLACE_BEACON ); @@ -414,14 +417,15 @@ GameMessageDisposition GUICommandTranslator::translateGameMessage(const GameMess if (BitIsSet(command->getOptions(), NEED_TARGET_POS)) { Coord3D worldPos; - TheTacticalView->screenToTerrain(&mouse, &worldPos); - - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_EVACUATE); - msg->appendLocationArgument(worldPos); + if( TheTacticalView->screenToTerrain(&mouse, &worldPos) ) + { + GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_EVACUATE); + msg->appendLocationArgument(worldPos); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_EVACUATE ); + pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_EVACUATE ); - commandStatus = COMMAND_COMPLETE; + commandStatus = COMMAND_COMPLETE; + } } break; diff --git a/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp b/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp index 0d6999bbd98..78ac92adcf3 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp @@ -80,7 +80,11 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess Coord3D world; // translate mouse position to world position - TheTacticalView->screenToTerrain( &mouse, &world ); + if( !TheTacticalView->screenToTerrain( &mouse, &world ) ) + { + TheInGameUI->placeBuildAvailable( nullptr, nullptr ); + break; + } // // placing things causes a dozer to go over and build it ... get the dozer in question @@ -163,8 +167,7 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess if (build && TheInGameUI->isPlacementAnchored()) { GameMessage *placeMsg; -// Player *player = ThePlayerList->getLocalPlayer(); - Coord3D world; + Coord3D worldStart, worldEnd; Real angle; ICoord2D anchorStart, anchorEnd; Bool isLineBuild = TheBuildAssistant->isLineBuildTemplate( build ); @@ -176,7 +179,12 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess TheInGameUI->getPlacementPoints( &anchorStart, &anchorEnd ); // translate the screen position of start to world target location - TheTacticalView->screenToTerrain( &anchorStart, &world ); + if( !TheTacticalView->screenToTerrain( &anchorStart, &worldStart ) ) + break; + + if( isLineBuild ) + if( !TheTacticalView->screenToTerrain( &anchorEnd, &worldEnd ) ) + break; Object *builderObj = TheGameLogic->findObjectByID( TheInGameUI->getPendingPlaceSourceObjectID() ); @@ -217,7 +225,7 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess // check to see if this is a legal location to build something at LegalBuildCode lbc; - lbc = TheBuildAssistant->isLocationLegalToBuild( &world, + lbc = TheBuildAssistant->isLocationLegalToBuild( &worldStart, build, angle, BuildAssistant::USE_QUICK_PATHFIND | @@ -244,7 +252,7 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess //dozer/worker. placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION ); placeMsg->appendIntegerArgument( commandButton->getSpecialPowerTemplate()->getID() ); //The ID of the special power template. - placeMsg->appendLocationArgument( world ); //Position of special to be fired. + placeMsg->appendLocationArgument( worldStart ); //Position of special to be fired. placeMsg->appendRealArgument( angle ); //Angle of special to be fired. placeMsg->appendObjectIDArgument( INVALID_ID ); //There is no object in the way. placeMsg->appendIntegerArgument( commandButton->getOptions() ); //Command button options. @@ -268,15 +276,11 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DOZER_CONSTRUCT ); placeMsg->appendIntegerArgument(build->getTemplateID()); - placeMsg->appendLocationArgument(world); + placeMsg->appendLocationArgument(worldStart); placeMsg->appendRealArgument(angle); if( isLineBuild ) { - Coord3D worldEnd; - - TheTacticalView->screenToTerrain( &anchorEnd, &worldEnd ); placeMsg->appendLocationArgument( worldEnd ); - } pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), placeMsg->getType() ); diff --git a/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp index caca08f832a..7bacb8d956a 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp @@ -450,9 +450,11 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa { Coord3D position; - TheTacticalView->screenToTerrain( &pixel, &position ); - mouseoverMessage = TheMessageStream->appendMessage( GameMessage::MSG_MOUSEOVER_LOCATION_HINT ); - mouseoverMessage->appendLocationArgument( position ); + if( TheTacticalView->screenToTerrain( &pixel, &position ) ) + { + mouseoverMessage = TheMessageStream->appendMessage( GameMessage::MSG_MOUSEOVER_LOCATION_HINT ); + mouseoverMessage->appendLocationArgument( position ); + } } } diff --git a/Core/GameEngine/Source/GameClient/View.cpp b/Core/GameEngine/Source/GameClient/View.cpp index 19f69015daf..5fd35b013be 100644 --- a/Core/GameEngine/Source/GameClient/View.cpp +++ b/Core/GameEngine/Source/GameClient/View.cpp @@ -243,13 +243,12 @@ Bool View::isUserControlLocked() const /** project the 4 corners of this view into the world and return each point as a parameter, the world points are at the requested Z */ //------------------------------------------------------------------------------------------------- -void View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, +PlaneIntersectionType View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ) + Real z, ViewportClass viewPort ) { - // sanity if( topLeft == nullptr || topRight == nullptr || bottomRight == nullptr || bottomLeft == nullptr) - return; + return PlaneIntersectionType_None; ICoord2D screenTopLeft; ICoord2D screenTopRight; @@ -262,20 +261,36 @@ void View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, // setup the screen coords for the 4 corners of the viewable display getOrigin( &origin.x, &origin.y ); - screenTopLeft.x = origin.x; - screenTopLeft.y = origin.y; - screenTopRight.x = origin.x + viewWidth; - screenTopRight.y = origin.y; - screenBottomRight.x = origin.x + viewWidth; - screenBottomRight.y = origin.y + viewHeight; - screenBottomLeft.x = origin.x; - screenBottomLeft.y = origin.y + viewHeight; - - // project - screenToWorldAtZ( &screenTopLeft, topLeft, z ); - screenToWorldAtZ( &screenTopRight, topRight, z ); - screenToWorldAtZ( &screenBottomRight, bottomRight, z ); - screenToWorldAtZ( &screenBottomLeft, bottomLeft, z ); + screenTopLeft.x = origin.x + viewWidth * viewPort.Min.X; + screenTopLeft.y = origin.y + viewHeight * viewPort.Min.Y; + screenTopRight.x = origin.x + viewWidth * viewPort.Max.X; + screenTopRight.y = origin.y + viewHeight * viewPort.Min.Y; + screenBottomRight.x = origin.x + viewWidth * viewPort.Max.X; + screenBottomRight.y = origin.y + viewHeight * viewPort.Max.Y; + screenBottomLeft.x = origin.x + viewWidth * viewPort.Min.X; + screenBottomLeft.y = origin.y + viewHeight * viewPort.Max.Y; + + PlaneIntersectionType result = PlaneIntersectionType_InsideSegment; + PlaneIntersectionType insersectionType[4]; + insersectionType[0] = screenToWorldAtZ( &screenTopLeft, topLeft, z ); + insersectionType[1] = screenToWorldAtZ( &screenTopRight, topRight, z ); + insersectionType[2] = screenToWorldAtZ( &screenBottomRight, bottomRight, z ); + insersectionType[3] = screenToWorldAtZ( &screenBottomLeft, bottomLeft, z ); + + for( Int i = 0; i < 4; ++i ) + { + if( insersectionType[i] == PlaneIntersectionType_None ) + { + result = PlaneIntersectionType_None; + break; + } + if( insersectionType[i] == PlaneIntersectionType_OutsideLine ) + { + result = PlaneIntersectionType_OutsideLine; + } + } + + return result; } // ------------------------------------------------------------------------------------------------ diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h index 88ff0dce7ae..5e4170849f3 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h @@ -218,8 +218,8 @@ class W3DView : public View, public SubsystemInterface virtual void setFieldOfView( Real angle ) override; ///< Set the horizontal field of view angle virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override; ///< Transform world coordinate "w" into screen coordinate "s" - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override; ///< transform screen point to world point at the specified world Z value + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override; + virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override; CameraClass *get3DCamera() const { return m_3DCamera; } diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h index a0ba2d832a9..5cfdcf6cc22 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h @@ -247,6 +247,8 @@ class WorldHeightMap : public RefCountClass, Int getXExtent() {return m_width;} ///getScreenCornerWorldPointsAtZ( &world[ 0 ], - &world[ 1 ], - &world[ 2 ], - &world[ 3 ], - getTerrainAverageZ() ); + if( TheTacticalView->getScreenCornerWorldPointsAtZ(&world[0], &world[1], &world[2], &world[3], getTerrainAverageZ()) == PlaneIntersectionType_None ) + return; // convert each of the 4 points in the world to radar cell positions for( i = 0; i < 4; i++ ) @@ -221,8 +221,6 @@ void W3DRadar::reconstructViewBox() } - m_reconstructViewBox = FALSE; - } //------------------------------------------------------------------------------------------------- @@ -282,8 +280,8 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) ICoord2D ulScreen; ICoord2D ulRadar; Coord3D ulWorld; - ICoord2D ulStart = { 0, 0 }; - ICoord2D start, end; + ICoord2D ulPixel; + ICoord2D pixelStart, pixelEnd; ICoord2D clipStart, clipEnd; Real lineWidth = 1.0f; Color topColor = GameMakeColor( 225, 225, 0, 255 ); @@ -304,7 +302,8 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) // convert top left of screen into world position TheTacticalView->getOrigin( &ulScreen.x, &ulScreen.y ); - TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ); + if( TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ) == PlaneIntersectionType_None ) + return; // convert world to radar coords ulRadar.x = ulWorld.x / (m_mapExtent.width() / RADAR_CELL_WIDTH); @@ -315,7 +314,7 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) // into position on the radar for where the radar is drawn and the size of the // area that the radar is drawn in // - radarToPixel( &ulRadar, &ulStart, pixelX, pixelY, width, height ); + radarToPixel( &ulRadar, &ulPixel, pixelX, pixelY, width, height ); // // using our view box offset array, convert each of those radar cell offset points @@ -327,36 +326,36 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) ICoord2D radar; // top line - start = ulStart; + pixelStart = ulPixel; radar.x = ulRadar.x + m_viewBox[ 1 ].x; radar.y = ulRadar.y + m_viewBox[ 1 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + radarToPixel( &radar, &pixelEnd, pixelX, pixelY, width, height ); + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, topColor ); // right line - start = end; + pixelStart = pixelEnd; radar.x += m_viewBox[ 2 ].x; radar.y += m_viewBox[ 2 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + radarToPixel( &radar, &pixelEnd, pixelX, pixelY, width, height ); + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, topColor, bottomColor ); // bottom line - start = end; + pixelStart = pixelEnd; radar.x += m_viewBox[ 3 ].x; radar.y += m_viewBox[ 3 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + radarToPixel( &radar, &pixelEnd, pixelX, pixelY, width, height ); + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, bottomColor ); // left line - start = end; - end = ulStart; - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + pixelStart = pixelEnd; + pixelEnd = ulPixel; + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, bottomColor, topColor ); @@ -870,10 +869,7 @@ W3DRadar::W3DRadar() for( Int i = 0; i < 4; i++ ) { - - m_viewBox[ i ].x = 0; - m_viewBox[ i ].y = 0; - + m_viewBox[ i ].zero(); } } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp index 64ac668122b..89e810dcbce 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp @@ -1381,7 +1381,7 @@ Bool BaseHeightMapRenderObjClass::getMaximumVisibleBox(const FrustumClass &frust ClippedCorners[0]=frustum.Corners[0]; for (Int i=0; i<4; i++) { ClippedCorners[i]=frustum.Corners[i]; - if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction)) + if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction) == PlaneIntersectionType_InsideSegment) { //edge intersects the terrain ClippedCorners[i+4]=frustum.Corners[i]+(frustum.Corners[i+4]-frustum.Corners[i])*clipFraction; } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 9e05f36e0f8..f9d26be6e1b 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1423,7 +1423,7 @@ Int MaskTextureShader::set(Int pass) D3DXMatrixInverse(&inv, &det, &curView); D3DXMATRIX scale,offset,offsetTextureCenter; - Coord3D centerPos; + Coord3D centerPos(0,0,0); //Find center of projection (this should be returned from some other filter, etc. but //for now assume terrain location at center of screen. diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index c029fa4880a..538377541f1 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -92,8 +92,6 @@ #include "WW3D2/dx8renderer.h" #include "WW3D2/light.h" -#include "WW3D2/camera.h" -#include "WW3D2/coltype.h" #include "WW3D2/predlod.h" #include "WW3D2/ww3d.h" @@ -659,7 +657,7 @@ void W3DView::getPickRay(const ICoord2D *screen, Vector3 *rayStart, Vector3 *ray m_3DCamera->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_3DCamera->Get_Depth(); //adjust length to reach far clip plane + *rayEnd *= sqr(m_3DCamera->Get_Depth()); //adjust length to reach far clip plane and beyond *rayEnd += *rayStart; //get point on far clip plane along ray from camera. } @@ -779,28 +777,18 @@ void W3DView::updateCameraClipPlanes(const Matrix3D &transform) const Vector3 camPos = transform.Get_Translation(); const Vector3 camDir = -transform.Get_Z_Vector(); - const Int loX = heightMap->getDrawOrgX() - heightMap->getBorderSize(); - const Int loY = heightMap->getDrawOrgY() - heightMap->getBorderSize(); - const Int hiX = loX + heightMap->getDrawWidth(); - const Int hiY = loY + heightMap->getDrawHeight(); - - // Convert to world coordinates - const Real minX = loX * MAP_XY_FACTOR; - const Real minY = loY * MAP_XY_FACTOR; - const Real maxX = hiX * MAP_XY_FACTOR; - const Real maxY = hiY * MAP_XY_FACTOR; - + const Region2D region = heightMap->getDrawRegion2D(); const Real minZ = TheTerrainRenderObject->getMinHeight(); // Bounding sphere Vector3 center; - center.X = (minX + maxX) * 0.5f; - center.Y = (minY + maxY) * 0.5f; + center.X = (region.lo.x + region.hi.x) * 0.5f; + center.Y = (region.lo.y + region.hi.y) * 0.5f; center.Z = minZ - 1.0f; // -1 to avoid Z clipping when looking straight down // Half extents - const Real dx = (maxX - minX) * 0.5f; - const Real dy = (maxY - minY) * 0.5f; + const Real dx = (region.hi.x - region.lo.x) * 0.5f; + const Real dy = (region.hi.y - region.lo.y) * 0.5f; // Project center const Vector3 v = center - camPos; @@ -1709,9 +1697,14 @@ void W3DView::update() //------------------------------------------------------------------------------------------------- /** Find region which contains all drawables in 3D space. */ +// TheSuperHackers @fix Now gives back a proper region on low camera pitch by falling back to +// the drawn terrain area or map extents. //------------------------------------------------------------------------------------------------- void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion) { + Region3D mapExtent; + TheTerrainLogic->getExtent( &mapExtent ); + // // get the 4 points in 3D space of the 4 corners of the view, we will use a z = 0.0f // value so that we can get everything ... even stuff below the terrain @@ -1720,18 +1713,29 @@ void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion) // \ / // 4---3 Coord3D box[ 4 ]; - getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f ); - - // - // take those 4 corners projected into the world and create an axis aligned bounding - // box, we will use this box to iterate the drawables in 3D space - // - axisAlignedRegion.setFromPointsNoZ(box, ARRAY_SIZE(box)); + if( getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f ) == PlaneIntersectionType_InsideSegment ) + { + // + // take those 4 corners projected into the world and create an axis aligned bounding + // box, we will use this box to iterate the drawables in 3D space + // + axisAlignedRegion.setFromPointsNoZ(box, ARRAY_SIZE(box)); + } + else + { + if( WorldHeightMap *heightMap = TheTerrainRenderObject->getMap() ) + { + const Region2D region = heightMap->getDrawRegion2D(); + axisAlignedRegion.set(region); + } + else + { + axisAlignedRegion = mapExtent; + } + } // low and high regions will be based of the extent of the map - Region3D mapExtent; - Real safeValue = 999999; - TheTerrainLogic->getExtent( &mapExtent ); + constexpr const Real safeValue = 999999; axisAlignedRegion.lo.z = mapExtent.lo.z - safeValue; axisAlignedRegion.hi.z = mapExtent.hi.z + safeValue; @@ -2527,12 +2531,13 @@ Drawable *W3DView::pickDrawable( const ICoord2D *screen, Bool forceAttack, PickT //------------------------------------------------------------------------------------------------- /** convert a pixel (x,y) to a location in the world on the terrain. Screen coordinates assumed in absolute values relative to full display resolution. */ +// TheSuperHackers @fix Now returns whether a terrain intersection exists to let callers handle the +// failure condition. //------------------------------------------------------------------------------------------------- -void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) +Bool W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) { - // sanity if( screen == nullptr || world == nullptr || TheTerrainRenderObject == nullptr ) - return; + return false; if (m_cameraHasMovedSinceRequest) { m_locationRequests.clear(); @@ -2543,13 +2548,12 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) m_locationRequests.erase(m_locationRequests.begin(), m_locationRequests.begin() + 10); } - - // We insert them at the end for speed (no copies needed), but using the princ of locality, we should + // We insert them at the end for speed (no copies needed), but using the principle of locality, we should // start searching where we most recently inserted for (int i = m_locationRequests.size() - 1; i >= 0; --i) { if (m_locationRequests[i].first.x == screen->x && m_locationRequests[i].first.y == screen->y) { (*world) = m_locationRequests[i].second; - return; + return true; } } @@ -2557,6 +2561,7 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) LineSegClass lineseg; CastResultStruct result; Vector3 intersection(0,0,0); + Bool hasIntersection = false; getPickRay(screen,&rayStart,&rayEnd); @@ -2564,11 +2569,11 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) RayCollisionTestClass raytest(lineseg,&result); + // Get the point of intersection according to W3D if( TheTerrainRenderObject->Cast_Ray(raytest) ) { - // get the point of intersection according to W3D intersection = result.ContactPoint; - + hasIntersection = true; } // Pick bridges. @@ -2576,8 +2581,12 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) Drawable *bridge = TheTerrainLogic->pickBridge(rayStart, rayEnd, &bridgePt); if (bridge && bridgePt.Z > intersection.Z) { intersection = bridgePt; + hasIntersection = true; } + if (!hasIntersection) + return false; + world->x = intersection.X; world->y = intersection.Y; world->z = intersection.Z; @@ -2587,6 +2596,7 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) req.second = (*world); m_locationRequests.push_back(req); // Insert this request at the end, requires no extra copies + return true; } //------------------------------------------------------------------------------------------------- @@ -2612,9 +2622,9 @@ void W3DView::lookAt( const Coord3D *o ) m_3DCamera->Un_Project(rayEnd,Vector2(0.0f,0.0f)); //get world space point rayEnd -= rayStart; //vector camera to world space point rayEnd.Normalize(); //make unit vector - rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane - rayStart.Set(pos.x, pos.y, pos.z); + rayEnd *= sqr(m_3DCamera->Get_Depth()); //adjust length to reach far clip plane and beyond rayEnd += rayStart; //get point on far clip plane along ray from camera. + rayStart.Set(pos.x, pos.y, pos.z); lineseg.Set(rayStart,rayEnd); RayCollisionTestClass raytest(lineseg,&result); @@ -3638,16 +3648,31 @@ void W3DView::shake( const Coord3D *epicenter, CameraShakeType shakeType ) //------------------------------------------------------------------------------------------------- /** Transform the screen pixel coord passed in, to a world coordinate at the specified z value */ +// TheSuperHackers @fix Now returns whether a Z plane intersection exists to let callers handle the +// failure condition. //------------------------------------------------------------------------------------------------- -void W3DView::screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) +PlaneIntersectionType W3DView::screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) { Vector3 rayStart, rayEnd; - getPickRay( s, &rayStart, &rayEnd ); - w->x = Vector3::Find_X_At_Z( z, rayStart, rayEnd ); - w->y = Vector3::Find_Y_At_Z( z, rayStart, rayEnd ); - w->z = z; + getPickRay( screen, &rayStart, &rayEnd ); + + PlaneClass plane; + plane.N = Vector3(0, 0, 1); + plane.D = z; + float t; + PlaneIntersectionType intersectionType = plane.Compute_Intersection(rayStart, rayEnd, &t); + + if (intersectionType != PlaneIntersectionType_None) + { + Vector3 intersectPos; + intersectPos = rayStart + (rayEnd-rayStart) * t; + world->x = intersectPos.X; + world->y = intersectPos.Y; + world->z = z; + } + return intersectionType; } void W3DView::cameraEnableSlaveMode(const AsciiString & objectName, const AsciiString & boneName) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp index c39c264c924..27983d5b823 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp @@ -1162,49 +1162,53 @@ void TestWaterUpdate() { if (!haveStart) { mouseAnchor=screenPoint; - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointStart); - haveStart=1; - UnicodeString string; - string.format(L"Added Start"); - TheInGameUI->message(string); + if (TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointStart)) + { + haveStart=1; + UnicodeString string; + string.format(L"Added Start"); + TheInGameUI->message(string); + } } else { endPoint=screenPoint; - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd); - haveEnd=1; - //Have enough info to add a wave now - track=TheWaterTracksRenderSystem->bindTrack(currentWaveType); - if (track) - {// track->init(1.5f*MAP_XY_FACTOR,Vector2(terrainPointStart.x,terrainPointStart.y),Vector2(terrainPointEnd.x,terrainPointEnd.y),"wave256.tga"); - //Generate valid input for the 2 points - Vector2 startPoint(terrainPointStart.x,terrainPointStart.y); - Vector2 endPoint(terrainPointEnd.x,terrainPointEnd.y); - Vector2 midPoint = endPoint - startPoint; - Vector2 m_perpDir = midPoint; - m_perpDir.Rotate(1.57079632679f); //get vector perpendicular to wave motion. - m_perpDir.Normalize(); - midPoint = startPoint + (midPoint)*0.5f; - Vector2 dirMidPoint = midPoint + m_perpDir; - - track->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,0); - - if (waveTypeInfo[currentWaveType].m_secondWaveTimeOffset) - { - //Add a second track slightly behind this one - track2=TheWaterTracksRenderSystem->bindTrack(currentWaveType); - if (track2) + if (TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd)) + { + haveEnd=1; + //Have enough info to add a wave now + track=TheWaterTracksRenderSystem->bindTrack(currentWaveType); + if (track) + {// track->init(1.5f*MAP_XY_FACTOR,Vector2(terrainPointStart.x,terrainPointStart.y),Vector2(terrainPointEnd.x,terrainPointEnd.y),"wave256.tga"); + //Generate valid input for the 2 points + Vector2 startPoint(terrainPointStart.x,terrainPointStart.y); + Vector2 endPoint(terrainPointEnd.x,terrainPointEnd.y); + Vector2 midPoint = endPoint - startPoint; + Vector2 m_perpDir = midPoint; + m_perpDir.Rotate(1.57079632679f); //get vector perpendicular to wave motion. + m_perpDir.Normalize(); + midPoint = startPoint + (midPoint)*0.5f; + Vector2 dirMidPoint = midPoint + m_perpDir; + + track->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,0); + + if (waveTypeInfo[currentWaveType].m_secondWaveTimeOffset) { - track2->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,waveTypeInfo[currentWaveType].m_secondWaveTimeOffset); + //Add a second track slightly behind this one + track2=TheWaterTracksRenderSystem->bindTrack(currentWaveType); + if (track2) + { + track2->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,waveTypeInfo[currentWaveType].m_secondWaveTimeOffset); + } } - } - UnicodeString string; - string.format(L"Added End"); - TheInGameUI->message(string); + UnicodeString string; + string.format(L"Added End"); + TheInGameUI->message(string); + } + haveStart=0; //reset for next segment + haveEnd=0; } - haveStart=0; //reset for next segment - haveEnd=0; } addPointReset=0; } @@ -1285,21 +1289,23 @@ void TestWaterUpdate() // View *tacticalView = TheDisplay->getFirstView(); // tacticalView->worldToScreen( &m_moveHint[i].pos, &pos ); - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd); - //Check if point is within correct distance of start - Real xdiff=terrainPointEnd.x - terrainPointStart.x; - Real ydiff=terrainPointEnd.y - terrainPointStart.y; - if (sqrt (xdiff * xdiff + ydiff * ydiff) <= waveTypeInfo[currentWaveType].m_finalWidth) - { TheDisplay->drawLine(mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y,1,0xffccccff); - DX8Wrapper::Invalidate_Cached_Render_States(); - ShaderClass::Invalidate(); - } + if (TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd)) + { + //Check if point is within correct distance of start + Real xdiff=terrainPointEnd.x - terrainPointStart.x; + Real ydiff=terrainPointEnd.y - terrainPointStart.y; + if (sqrt (xdiff * xdiff + ydiff * ydiff) <= waveTypeInfo[currentWaveType].m_finalWidth) + { TheDisplay->drawLine(mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y,1,0xffccccff); + DX8Wrapper::Invalidate_Cached_Render_States(); + ShaderClass::Invalidate(); + } - pauseWaves=TRUE; + pauseWaves=TRUE; // char buffer[64]; // sprintf(buffer,"\n%d,%d,%d,%d",mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y); // OutputDebugString (buffer); + } } } } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp index 5deb1994be3..cff40a8d32c 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp @@ -2200,6 +2200,23 @@ TerrainTextureClass *WorldHeightMap::getFlatTexture(Int xCell, Int yCell, Int ce return newTexture; } +Region2D WorldHeightMap::getDrawRegion2D() +{ + // Get region in heightmap space + const Int loX = getDrawOrgX() - getBorderSize(); + const Int loY = getDrawOrgY() - getBorderSize(); + const Int hiX = loX + getDrawWidth(); + const Int hiY = loY + getDrawHeight(); + + // Convert to world space + Region2D region; + region.lo.x = loX * MAP_XY_FACTOR; + region.lo.y = loY * MAP_XY_FACTOR; + region.hi.x = hiX * MAP_XY_FACTOR; + region.hi.y = hiY * MAP_XY_FACTOR; + + return region; +} WorldHeightMap::DrawArea WorldHeightMap::createDrawArea(Int xOrg, Int yOrg) { diff --git a/Core/Libraries/Include/Lib/BaseType.h b/Core/Libraries/Include/Lib/BaseType.h index 2cb718c9e27..285f85cd90c 100644 --- a/Core/Libraries/Include/Lib/BaseType.h +++ b/Core/Libraries/Include/Lib/BaseType.h @@ -542,6 +542,14 @@ struct Region3D return lo.is(value) && hi.is(value); } + void set(const Region2D ®ion) + { + lo.x = region.lo.x; + lo.y = region.lo.y; + hi.x = region.hi.x; + hi.y = region.hi.y; + } + void setFromPointsNoZ(const Coord3D* points, Int count) { lo.x = points[0].x; diff --git a/Core/Libraries/Source/WWVegas/WWMath/plane.h b/Core/Libraries/Source/WWVegas/WWMath/plane.h index eb3630595da..d21a4ca5830 100644 --- a/Core/Libraries/Source/WWVegas/WWMath/plane.h +++ b/Core/Libraries/Source/WWVegas/WWMath/plane.h @@ -53,6 +53,13 @@ ** sign of the D value is inverted. */ +enum PlaneIntersectionType CPP_11(: int) +{ + PlaneIntersectionType_None = 0, // No intersection when the line is parallel to the plane + PlaneIntersectionType_InsideSegment = 1, // The segment INSIDE point A and B intersects the plane + PlaneIntersectionType_OutsideLine = 2, // The infinite line OUTSIDE point A and B intersects the plane +}; + class PlaneClass { public: @@ -81,7 +88,7 @@ class PlaneClass inline void Set(const Vector3 & normal,const Vector3 & point); inline void Set(const Vector3 & point1,const Vector3 & point2,const Vector3 & point3); - bool Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const; + PlaneIntersectionType Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const; bool In_Front(const Vector3 & point) const; bool In_Front(const SphereClass & sphere) const; bool In_Front_Or_Intersecting(const SphereClass & sphere) const; @@ -148,7 +155,7 @@ inline void PlaneClass::Set(const Vector3 & point1, const Vector3 & point2, cons } } -inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const +inline PlaneIntersectionType PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const { float num,den; den = Vector3::Dot_Product(N,p1-p0); @@ -157,7 +164,7 @@ inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & ** If the denominator is zero, the ray is parallel to the plane */ if (den == 0.0f) { - return false; + return PlaneIntersectionType_None; } num = -(Vector3::Dot_Product(N,p0) - D); @@ -169,10 +176,10 @@ inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & ** the plane but the segment does not */ if ((*set_t < 0.0f) || (*set_t > 1.0f)) { - return false; + return PlaneIntersectionType_OutsideLine; } - return true; + return PlaneIntersectionType_InsideSegment; } inline bool PlaneClass::In_Front(const Vector3 & point) const diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 7d083f3393e..91541e588d0 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1453,9 +1453,16 @@ void W3DDisplay::gatherDebugStats() //display the x and y mouse coordinates const MouseIO *mouseIO = TheMouse->getMouseStatus(); Coord3D worldPos; - TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos); - unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", mouseIO->pos.x, mouseIO->pos.y, - worldPos.x, worldPos.y, worldPos.z); + if( TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos) ) + { + unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", + mouseIO->pos.x, mouseIO->pos.y, worldPos.x, worldPos.y, worldPos.z); + } + else + { + unibuffer.format( L"Mouse position: screen: (%d, %d), world: none", + mouseIO->pos.x, mouseIO->pos.y); + } m_displayStrings[MousePosition]->setText( unibuffer ); //display the number of particles in the world and being displayed on screen From 51dc4b6f2d45cc98a6e53eb4e1651a6da5e80343 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 11:30:37 +0200 Subject: [PATCH 2/7] Fix MaskTextureShader::set --- .../Source/W3DDevice/GameClient/W3DShaderManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index f9d26be6e1b..31668207670 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1423,7 +1423,8 @@ Int MaskTextureShader::set(Int pass) D3DXMatrixInverse(&inv, &det, &curView); D3DXMATRIX scale,offset,offsetTextureCenter; - Coord3D centerPos(0,0,0); + Coord3D centerPos; + centerPos.zero(); //Find center of projection (this should be returned from some other filter, etc. but //for now assume terrain location at center of screen. From a2d22f5f35011f88cbab936debb71097c1d1b359 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 11:40:57 +0200 Subject: [PATCH 3/7] Fix wbview3d --- GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index 3480dc29baf..b22424bd266 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -175,11 +175,11 @@ class PlaceholderView : public View Bool (*callback)( Drawable *draw, void *userData ), void *userData ) override {return 0;}; virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override { return WTS_INVALID; }; ///< Transform world coordinate "w" into screen coordinate "s" - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {}; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {}; ///< transform screen point to world point at the specified world Z value - virtual void getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } + virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override { return PlaneIntersectionType_None; } + virtual PlaneIntersectionType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ) override {}; + Real z, ViewportClass viewPort = ViewportClass() ) override { return PlaneIntersectionType_None; } virtual void drawView() override {}; ///< Render the world visible in this view. virtual void updateView() override {}; ///< Render the world visible in this view. From 0c2c466dd7f990ba51d76607a2c76dcae5d530fb Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 11:47:17 +0200 Subject: [PATCH 4/7] Move IntersectionResType into PlaneClass --- Core/GameEngine/Include/GameClient/View.h | 6 ++--- Core/GameEngine/Source/GameClient/View.cpp | 26 +++++++++---------- .../Include/W3DDevice/GameClient/W3DView.h | 2 +- .../W3DDevice/Common/System/W3DRadar.cpp | 4 +-- .../W3DDevice/GameClient/BaseHeightMap.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DView.cpp | 8 +++--- Core/Libraries/Source/WWVegas/WWMath/plane.h | 24 ++++++++--------- .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 6 ++--- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 53c01d8aa64..ccc33949f64 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -125,7 +125,7 @@ class View : public Snapshot /// Project the 4 corners of this view into the world and return each point as a parameter, /// the world points are at the requested Z. Returns whether all corner view rays intersect /// with the Z plane. - virtual PlaneIntersectionType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + virtual PlaneClass::IntersectionResType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, Real z, ViewportClass viewPort = ViewportClass() ); @@ -246,7 +246,7 @@ class View : public Snapshot virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) = 0; /// Transform screen point to the viewed world position at the specified world Z height. Returns the type of the intersection. - virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) = 0; + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) = 0; virtual void getLocation ( ViewLocation *location ); ///< write the view's current location in to the view location object virtual void setLocation ( const ViewLocation *location ); ///< set the view's current location from to the view location object @@ -411,7 +411,7 @@ class ViewDummy : public View return WTS_INVALID; } virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } - virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override { return PlaneIntersectionType_None; } + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override { return PlaneClass::NO_INTERSECTION; } virtual void drawView() override {} virtual void updateView() override {} virtual void stepView() override {} diff --git a/Core/GameEngine/Source/GameClient/View.cpp b/Core/GameEngine/Source/GameClient/View.cpp index 5fd35b013be..8a8886a31c8 100644 --- a/Core/GameEngine/Source/GameClient/View.cpp +++ b/Core/GameEngine/Source/GameClient/View.cpp @@ -243,12 +243,12 @@ Bool View::isUserControlLocked() const /** project the 4 corners of this view into the world and return each point as a parameter, the world points are at the requested Z */ //------------------------------------------------------------------------------------------------- -PlaneIntersectionType View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, +PlaneClass::IntersectionResType View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, Real z, ViewportClass viewPort ) { if( topLeft == nullptr || topRight == nullptr || bottomRight == nullptr || bottomLeft == nullptr) - return PlaneIntersectionType_None; + return PlaneClass::NO_INTERSECTION; ICoord2D screenTopLeft; ICoord2D screenTopRight; @@ -270,27 +270,27 @@ PlaneIntersectionType View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coo screenBottomLeft.x = origin.x + viewWidth * viewPort.Min.X; screenBottomLeft.y = origin.y + viewHeight * viewPort.Max.Y; - PlaneIntersectionType result = PlaneIntersectionType_InsideSegment; - PlaneIntersectionType insersectionType[4]; - insersectionType[0] = screenToWorldAtZ( &screenTopLeft, topLeft, z ); - insersectionType[1] = screenToWorldAtZ( &screenTopRight, topRight, z ); - insersectionType[2] = screenToWorldAtZ( &screenBottomRight, bottomRight, z ); - insersectionType[3] = screenToWorldAtZ( &screenBottomLeft, bottomLeft, z ); + PlaneClass::IntersectionResType combinedResult = PlaneClass::INSIDE_SEGMENT; + PlaneClass::IntersectionResType individualResults[4]; + individualResults[0] = screenToWorldAtZ( &screenTopLeft, topLeft, z ); + individualResults[1] = screenToWorldAtZ( &screenTopRight, topRight, z ); + individualResults[2] = screenToWorldAtZ( &screenBottomRight, bottomRight, z ); + individualResults[3] = screenToWorldAtZ( &screenBottomLeft, bottomLeft, z ); for( Int i = 0; i < 4; ++i ) { - if( insersectionType[i] == PlaneIntersectionType_None ) + if( individualResults[i] == PlaneClass::NO_INTERSECTION ) { - result = PlaneIntersectionType_None; + combinedResult = PlaneClass::NO_INTERSECTION; break; } - if( insersectionType[i] == PlaneIntersectionType_OutsideLine ) + if( individualResults[i] == PlaneClass::OUTSIDE_LINE ) { - result = PlaneIntersectionType_OutsideLine; + combinedResult = PlaneClass::OUTSIDE_LINE; } } - return result; + return combinedResult; } // ------------------------------------------------------------------------------------------------ diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h index 5e4170849f3..e84b8f7b42f 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h @@ -219,7 +219,7 @@ class W3DView : public View, public SubsystemInterface virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override; ///< Transform world coordinate "w" into screen coordinate "s" virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override; - virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override; + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override; CameraClass *get3DCamera() const { return m_3DCamera; } diff --git a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index 6c45e94ed02..056af0d6b9b 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -189,7 +189,7 @@ void W3DRadar::reconstructViewBox() // 1-------2 // \ / // 4---3 - if( TheTacticalView->getScreenCornerWorldPointsAtZ(&world[0], &world[1], &world[2], &world[3], getTerrainAverageZ()) == PlaneIntersectionType_None ) + if( TheTacticalView->getScreenCornerWorldPointsAtZ(&world[0], &world[1], &world[2], &world[3], getTerrainAverageZ()) == PlaneClass::NO_INTERSECTION ) return; // convert each of the 4 points in the world to radar cell positions @@ -302,7 +302,7 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) // convert top left of screen into world position TheTacticalView->getOrigin( &ulScreen.x, &ulScreen.y ); - if( TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ) == PlaneIntersectionType_None ) + if( TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ) == PlaneClass::NO_INTERSECTION ) return; // convert world to radar coords diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp index 89e810dcbce..0103ca60685 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp @@ -1381,7 +1381,7 @@ Bool BaseHeightMapRenderObjClass::getMaximumVisibleBox(const FrustumClass &frust ClippedCorners[0]=frustum.Corners[0]; for (Int i=0; i<4; i++) { ClippedCorners[i]=frustum.Corners[i]; - if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction) == PlaneIntersectionType_InsideSegment) + if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction) == PlaneClass::INSIDE_SEGMENT) { //edge intersects the terrain ClippedCorners[i+4]=frustum.Corners[i]+(frustum.Corners[i+4]-frustum.Corners[i])*clipFraction; } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 538377541f1..6f7c163d193 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -1713,7 +1713,7 @@ void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion) // \ / // 4---3 Coord3D box[ 4 ]; - if( getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f ) == PlaneIntersectionType_InsideSegment ) + if( getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f ) == PlaneClass::INSIDE_SEGMENT ) { // // take those 4 corners projected into the world and create an axis aligned bounding @@ -3651,7 +3651,7 @@ void W3DView::shake( const Coord3D *epicenter, CameraShakeType shakeType ) // TheSuperHackers @fix Now returns whether a Z plane intersection exists to let callers handle the // failure condition. //------------------------------------------------------------------------------------------------- -PlaneIntersectionType W3DView::screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) +PlaneClass::IntersectionResType W3DView::screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) { Vector3 rayStart, rayEnd; @@ -3661,9 +3661,9 @@ PlaneIntersectionType W3DView::screenToWorldAtZ( const ICoord2D *screen, Coord3D plane.N = Vector3(0, 0, 1); plane.D = z; float t; - PlaneIntersectionType intersectionType = plane.Compute_Intersection(rayStart, rayEnd, &t); + PlaneClass::IntersectionResType intersectionType = plane.Compute_Intersection(rayStart, rayEnd, &t); - if (intersectionType != PlaneIntersectionType_None) + if (intersectionType != PlaneClass::NO_INTERSECTION) { Vector3 intersectPos; intersectPos = rayStart + (rayEnd-rayStart) * t; diff --git a/Core/Libraries/Source/WWVegas/WWMath/plane.h b/Core/Libraries/Source/WWVegas/WWMath/plane.h index d21a4ca5830..f2f6cf3e969 100644 --- a/Core/Libraries/Source/WWVegas/WWMath/plane.h +++ b/Core/Libraries/Source/WWVegas/WWMath/plane.h @@ -53,19 +53,19 @@ ** sign of the D value is inverted. */ -enum PlaneIntersectionType CPP_11(: int) -{ - PlaneIntersectionType_None = 0, // No intersection when the line is parallel to the plane - PlaneIntersectionType_InsideSegment = 1, // The segment INSIDE point A and B intersects the plane - PlaneIntersectionType_OutsideLine = 2, // The infinite line OUTSIDE point A and B intersects the plane -}; - class PlaneClass { public: enum { FRONT = 0, BACK, ON }; + enum IntersectionResType + { + NO_INTERSECTION = 0, // No intersection when the line is parallel to the plane + INSIDE_SEGMENT = 1, // The segment INSIDE point A and B intersects the plane + OUTSIDE_LINE = 2, // The infinite line OUTSIDE point A and B intersects the plane + }; + Vector3 N; // Normal of the plane float D; // Distance along the normal from the origin @@ -88,7 +88,7 @@ class PlaneClass inline void Set(const Vector3 & normal,const Vector3 & point); inline void Set(const Vector3 & point1,const Vector3 & point2,const Vector3 & point3); - PlaneIntersectionType Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const; + PlaneClass::IntersectionResType Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const; bool In_Front(const Vector3 & point) const; bool In_Front(const SphereClass & sphere) const; bool In_Front_Or_Intersecting(const SphereClass & sphere) const; @@ -155,7 +155,7 @@ inline void PlaneClass::Set(const Vector3 & point1, const Vector3 & point2, cons } } -inline PlaneIntersectionType PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const +inline PlaneClass::IntersectionResType PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const { float num,den; den = Vector3::Dot_Product(N,p1-p0); @@ -164,7 +164,7 @@ inline PlaneIntersectionType PlaneClass::Compute_Intersection(const Vector3 & p0 ** If the denominator is zero, the ray is parallel to the plane */ if (den == 0.0f) { - return PlaneIntersectionType_None; + return PlaneClass::NO_INTERSECTION; } num = -(Vector3::Dot_Product(N,p0) - D); @@ -176,10 +176,10 @@ inline PlaneIntersectionType PlaneClass::Compute_Intersection(const Vector3 & p0 ** the plane but the segment does not */ if ((*set_t < 0.0f) || (*set_t > 1.0f)) { - return PlaneIntersectionType_OutsideLine; + return PlaneClass::OUTSIDE_LINE; } - return PlaneIntersectionType_InsideSegment; + return PlaneClass::INSIDE_SEGMENT; } inline bool PlaneClass::In_Front(const Vector3 & point) const diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index b22424bd266..e1e654da19b 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -176,10 +176,10 @@ class PlaceholderView : public View void *userData ) override {return 0;}; virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override { return WTS_INVALID; }; ///< Transform world coordinate "w" into screen coordinate "s" virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } - virtual PlaneIntersectionType screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override { return PlaneIntersectionType_None; } - virtual PlaneIntersectionType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override { return PlaneClass::NO_INTERSECTION; } + virtual PlaneClass::IntersectionResType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z, ViewportClass viewPort = ViewportClass() ) override { return PlaneIntersectionType_None; } + Real z, ViewportClass viewPort = ViewportClass() ) override { return PlaneClass::NO_INTERSECTION; } virtual void drawView() override {}; ///< Render the world visible in this view. virtual void updateView() override {}; ///< Render the world visible in this view. From aa8919651229e4ed0dff1a6305389bcb8cee0e98 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 11:51:14 +0200 Subject: [PATCH 5/7] Move pauseWaves=TRUE --- .../Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp index 27983d5b823..ea8ebe4c081 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp @@ -1300,12 +1300,12 @@ void TestWaterUpdate() ShaderClass::Invalidate(); } - pauseWaves=TRUE; - // char buffer[64]; // sprintf(buffer,"\n%d,%d,%d,%d",mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y); // OutputDebugString (buffer); } + + pauseWaves=TRUE; } } } From 8efdbdb77b5f6271989f4bd22ba01f828709e974 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 11:59:15 +0200 Subject: [PATCH 6/7] Clarify Region3D::setXY --- .../Source/W3DDevice/GameClient/W3DView.cpp | 4 ++-- Core/Libraries/Include/Lib/BaseType.h | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 6f7c163d193..ed70dcfefec 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -1719,14 +1719,14 @@ void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion) // take those 4 corners projected into the world and create an axis aligned bounding // box, we will use this box to iterate the drawables in 3D space // - axisAlignedRegion.setFromPointsNoZ(box, ARRAY_SIZE(box)); + axisAlignedRegion.setXYFromPoints(box, ARRAY_SIZE(box)); } else { if( WorldHeightMap *heightMap = TheTerrainRenderObject->getMap() ) { const Region2D region = heightMap->getDrawRegion2D(); - axisAlignedRegion.set(region); + axisAlignedRegion.setXY(region); } else { diff --git a/Core/Libraries/Include/Lib/BaseType.h b/Core/Libraries/Include/Lib/BaseType.h index 285f85cd90c..297af0b9332 100644 --- a/Core/Libraries/Include/Lib/BaseType.h +++ b/Core/Libraries/Include/Lib/BaseType.h @@ -542,7 +542,8 @@ struct Region3D return lo.is(value) && hi.is(value); } - void set(const Region2D ®ion) + // Set XY from a 2D region and leave Z unchanged. + void setXY(const Region2D ®ion) { lo.x = region.lo.x; lo.y = region.lo.y; @@ -550,7 +551,8 @@ struct Region3D hi.y = region.hi.y; } - void setFromPointsNoZ(const Coord3D* points, Int count) + // Set XY from any amount of points and leave Z unchanged. + void setXYFromPoints(const Coord3D* points, Int count) { lo.x = points[0].x; lo.y = points[0].y; From 0db89beacd7618b421c9714e0a0f1730b74a96c5 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:54:52 +0200 Subject: [PATCH 7/7] Move rayStart.Set back --- Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index ed70dcfefec..3f684ea7597 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -2623,8 +2623,8 @@ void W3DView::lookAt( const Coord3D *o ) rayEnd -= rayStart; //vector camera to world space point rayEnd.Normalize(); //make unit vector rayEnd *= sqr(m_3DCamera->Get_Depth()); //adjust length to reach far clip plane and beyond - rayEnd += rayStart; //get point on far clip plane along ray from camera. rayStart.Set(pos.x, pos.y, pos.z); + rayEnd += rayStart; //get point on far clip plane along ray from camera. lineseg.Set(rayStart,rayEnd); RayCollisionTestClass raytest(lineseg,&result);