Skip to content
23 changes: 15 additions & 8 deletions Core/GameEngine/Include/GameClient/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 PlaneClass::IntersectionResType 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; }
Expand Down Expand Up @@ -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 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
Expand Down Expand Up @@ -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 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 {}
Expand Down
24 changes: 14 additions & 10 deletions Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3898,9 +3898,11 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage
if( TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove )
{
// 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;

GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION );
newMsg->appendLocationArgument(pos);
newMsg->appendIntegerArgument(GUARDMODE_NORMAL);

Expand All @@ -3918,8 +3920,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.
Expand All @@ -3930,9 +3930,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)
Expand Down Expand Up @@ -3969,9 +3971,11 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage
if( !TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove )
{
// 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;
Comment thread
stephanmeesters marked this conversation as resolved.

GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION );
newMsg->appendLocationArgument(pos);
newMsg->appendIntegerArgument(GUARDMODE_NORMAL);

Expand All @@ -3985,8 +3989,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.
Expand All @@ -3997,7 +3999,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
Expand All @@ -4012,6 +4015,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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ static CommandStatus doFireWeaponCommand( const CommandButton *command, const IC
Coord3D world;

// translate the mouse location into world coords
TheTacticalView->screenToTerrain( mouse, &world );
if( !TheTacticalView->screenToTerrain( mouse, &world ) )
return COMMAND_COMPLETE;

// create the message and append arguments
msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON_AT_LOCATION );
Expand All @@ -153,8 +154,6 @@ static CommandStatus doFireWeaponCommand( const CommandButton *command, const IC
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 ) )
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );
Expand All @@ -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 );
Expand Down Expand Up @@ -414,12 +417,13 @@ 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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 );
Expand All @@ -176,7 +179,11 @@ 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 && !TheTacticalView->screenToTerrain( &anchorEnd, &worldEnd ) )
break;

Object *builderObj = TheGameLogic->findObjectByID( TheInGameUI->getPendingPlaceSourceObjectID() );

Expand Down Expand Up @@ -217,7 +224,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 |
Expand All @@ -244,7 +251,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.
Expand All @@ -268,15 +275,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() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
}
}

Expand Down
51 changes: 33 additions & 18 deletions Core/GameEngine/Source/GameClient/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
PlaneClass::IntersectionResType 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 PlaneClass::NO_INTERSECTION;

ICoord2D screenTopLeft;
ICoord2D screenTopRight;
Expand All @@ -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;

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( individualResults[i] == PlaneClass::NO_INTERSECTION )
{
combinedResult = PlaneClass::NO_INTERSECTION;
break;
}
if( individualResults[i] == PlaneClass::OUTSIDE_LINE )
{
combinedResult = PlaneClass::OUTSIDE_LINE;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should break here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No because NO_INTERSECTION will take precedence over OUTSIDE_LINE

}
}

return combinedResult;
}

// ------------------------------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override;

CameraClass *get3DCamera() const { return m_3DCamera; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ class WorldHeightMap : public RefCountClass,
Int getXExtent() {return m_width;} ///<number of vertices in x
Int getYExtent() {return m_height;} ///<number of vertices in y

Region2D getDrawRegion2D();

Int getDrawOrgX() {return m_drawOriginX;}
Int getDrawOrgY() {return m_drawOriginY;}

Expand Down
Loading
Loading