2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
/* A viewport to each player */
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "game/C4Viewport.h"
2009-05-08 13:28:41 +00:00
2016-04-03 18:07:56 +00:00
# include "editor/C4ViewportWindow.h"
# include "editor/C4Console.h"
2016-04-02 17:44:44 +00:00
# include "object/C4Def.h"
2016-04-03 18:07:56 +00:00
# include "object/C4Object.h"
# include "game/C4FullScreen.h"
# include "lib/C4Stat.h"
# include "player/C4Player.h"
# include "object/C4ObjectMenu.h"
# include "gui/C4MouseControl.h"
# include "landscape/C4PXS.h"
# include "gui/C4GameMessage.h"
# include "gui/C4ScriptGuiWindow.h"
# include "graphics/C4GraphicsResource.h"
# include "game/C4GraphicsSystem.h"
# include "landscape/C4Landscape.h"
2016-04-02 15:50:49 +00:00
# include "landscape/C4Sky.h"
2016-04-03 18:07:56 +00:00
# include "player/C4PlayerList.h"
# include "object/C4GameObjects.h"
# include "network/C4Network2.h"
# include "landscape/fow/C4FoWRegion.h"
2009-05-08 13:28:41 +00:00
2010-12-06 20:31:37 +00:00
void C4Viewport : : DropFile ( const char * fileName , float x , float y )
{
2015-01-03 21:51:02 +00:00
Game . DropFile ( fileName , GetViewX ( ) + x / Zoom , GetViewY ( ) + y / Zoom ) ;
2010-12-06 20:31:37 +00:00
}
2009-08-15 18:50:32 +00:00
bool C4Viewport : : UpdateOutputSize ( )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( ! pWindow ) return false ;
2009-05-08 13:28:41 +00:00
// Output size
2011-03-13 19:00:03 +00:00
C4Rect rect ;
2010-09-22 15:11:19 +00:00
2016-01-22 19:05:43 +00:00
# ifdef USE_GTK
2010-09-22 15:11:19 +00:00
GtkAllocation allocation ;
2012-04-08 23:15:30 +00:00
gtk_widget_get_allocation ( GTK_WIDGET ( pWindow - > render_widget ) , & allocation ) ;
2010-09-22 15:11:19 +00:00
2009-05-08 13:28:41 +00:00
// Use only size of drawing area without scrollbars
2011-03-13 19:00:03 +00:00
rect . x = allocation . x ;
rect . y = allocation . y ;
rect . Wdt = allocation . width ;
rect . Hgt = allocation . height ;
2009-05-08 13:28:41 +00:00
# else
2009-08-15 18:50:32 +00:00
if ( ! pWindow - > GetSize ( & rect ) ) return false ;
2009-05-08 13:28:41 +00:00
# endif
2011-03-13 19:00:03 +00:00
OutX = rect . x ; OutY = rect . y ;
ViewWdt = rect . Wdt ; ViewHgt = rect . Hgt ;
2015-01-03 21:51:02 +00:00
ScrollView ( 0 , 0 ) ;
2009-05-08 13:28:41 +00:00
// Scroll bars
ScrollBarsByViewPosition ( ) ;
// Reset menus
2009-08-15 18:50:32 +00:00
ResetMenuPositions = true ;
2009-05-08 13:28:41 +00:00
// update internal GL size
2010-03-06 14:07:30 +00:00
if ( pWindow & & pWindow - > pSurface )
pWindow - > pSurface - > UpdateSize ( ViewWdt , ViewHgt ) ;
2009-05-08 13:28:41 +00:00
// Done
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Viewport : : C4Viewport ( )
2010-03-28 18:58:01 +00:00
{
2015-12-28 17:16:33 +00:00
Player = 0 ;
viewX = viewY = 0 ;
targetViewX = targetViewY = 0 ;
ViewWdt = ViewHgt = 0 ;
BorderLeft = BorderTop = BorderRight = BorderBottom = 0 ;
OutX = OutY = ViewWdt = ViewHgt = 0 ;
DrawX = DrawY = 0 ;
Zoom = 1.0 ;
ZoomTarget = 0.0 ;
ViewportOpenFrame = 0 ;
ZoomLimitMin = ZoomLimitMax = 0 ; // no limit
Next = NULL ;
PlayerLock = true ;
ResetMenuPositions = false ;
viewOffsX = viewOffsY = 0 ;
fIsNoOwnerViewport = false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Viewport : : ~ C4Viewport ( )
2010-03-28 18:58:01 +00:00
{
2015-01-14 17:03:05 +00:00
DisableFoW ( ) ;
2015-12-28 17:24:09 +00:00
if ( pWindow ) { delete pWindow - > pSurface ; pWindow - > Clear ( ) ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : DrawOverlay ( C4TargetFacet & cgo , const ZoomData & GameZoom )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Game . C4S . Head . Film | | ! Game . C4S . Head . Replay )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Player info
C4ST_STARTNEW ( PInfoStat , " C4Viewport::DrawOverlay: Player Info " )
DrawPlayerInfo ( cgo ) ;
C4ST_STOP ( PInfoStat )
C4ST_STARTNEW ( MenuStat , " C4Viewport::DrawOverlay: Menu " )
DrawMenu ( cgo ) ;
C4ST_STOP ( MenuStat )
2010-03-28 18:58:01 +00:00
}
2010-02-23 11:50:14 +00:00
2010-02-23 12:05:13 +00:00
// Control overlays (if not film/replay)
if ( ! Game . C4S . Head . Film | | ! Game . C4S . Head . Replay )
2010-03-28 18:58:01 +00:00
{
2010-02-23 12:05:13 +00:00
// Mouse control
if ( : : MouseControl . IsViewport ( this ) )
2010-03-28 18:58:01 +00:00
{
2010-02-23 12:05:13 +00:00
C4ST_STARTNEW ( MouseStat , " C4Viewport::DrawOverlay: Mouse " )
: : MouseControl . Draw ( cgo , GameZoom ) ;
// Draw GUI-mouse in EM if active
2010-10-29 23:47:50 +00:00
if ( pWindow ) : : pGUI - > RenderMouse ( cgo ) ;
2010-02-23 12:05:13 +00:00
C4ST_STOP ( MouseStat )
2010-02-23 11:50:14 +00:00
}
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-09-26 23:17:36 +00:00
void C4Viewport : : DrawMenu ( C4TargetFacet & cgo0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Get player
2009-06-12 23:09:32 +00:00
C4Player * pPlr = : : Players . Get ( Player ) ;
2009-05-08 13:28:41 +00:00
2011-09-26 23:17:36 +00:00
// for menus, cgo is using GUI-syntax: TargetX/Y marks the drawing offset; x/y/Wdt/Hgt marks the offset rect
C4TargetFacet cgo ; cgo . Set ( cgo0 ) ;
cgo . X = 0 ; cgo . Y = 0 ;
cgo . Wdt = cgo0 . Wdt * cgo0 . Zoom ; cgo . Hgt = cgo0 . Hgt * cgo0 . Zoom ;
cgo . TargetX = float ( cgo0 . X ) ; cgo . TargetY = float ( cgo0 . Y ) ;
cgo . Zoom = 1 ;
2011-10-03 14:30:18 +00:00
pDraw - > SetZoom ( cgo . X , cgo . Y , cgo . Zoom ) ;
2011-09-26 23:17:36 +00:00
2009-05-08 13:28:41 +00:00
// Player eliminated
if ( pPlr & & pPlr - > Eliminated )
2010-03-28 18:58:01 +00:00
{
2011-10-03 14:30:18 +00:00
pDraw - > TextOut ( FormatString ( LoadResStr ( pPlr - > Surrendered ? " IDS_PLR_SURRENDERED " : " IDS_PLR_ELIMINATED " ) , pPlr - > GetName ( ) ) . getData ( ) ,
2011-09-26 23:17:36 +00:00
: : GraphicsResource . FontRegular , 1.0 , cgo . Surface , cgo . TargetX + cgo . Wdt / 2 , cgo . TargetY + 2 * cgo . Hgt / 3 , 0xfaFF0000 , ACenter ) ;
2009-05-08 13:28:41 +00:00
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Player cursor object menu
if ( pPlr & & pPlr - > Cursor & & pPlr - > Cursor - > Menu )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ResetMenuPositions ) pPlr - > Cursor - > Menu - > ResetLocation ( ) ;
// if mouse is dragging, make it transparent to easy construction site drag+drop
bool fDragging = false ;
2009-06-05 15:20:07 +00:00
if ( : : MouseControl . IsDragging ( ) & & : : MouseControl . IsViewport ( this ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fDragging = true ;
2011-10-03 14:30:18 +00:00
pDraw - > ActivateBlitModulation ( 0x4fffffff ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// draw menu
pPlr - > Cursor - > Menu - > Draw ( cgo ) ;
// reset modulation for dragging
2011-10-03 14:30:18 +00:00
if ( fDragging ) pDraw - > DeactivateBlitModulation ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Player menu
if ( pPlr & & pPlr - > Menu . IsActive ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ResetMenuPositions ) pPlr - > Menu . ResetLocation ( ) ;
pPlr - > Menu . Draw ( cgo ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Fullscreen menu
if ( FullScreen . pMenu & & FullScreen . pMenu - > IsActive ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ResetMenuPositions ) FullScreen . pMenu - > ResetLocation ( ) ;
FullScreen . pMenu - > Draw ( cgo ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Flag done
2009-08-15 18:50:32 +00:00
ResetMenuPositions = false ;
2009-05-08 13:28:41 +00:00
2011-09-26 23:17:36 +00:00
// restore Zoom
2011-10-03 14:30:18 +00:00
pDraw - > SetZoom ( cgo0 . X , cgo0 . Y , cgo0 . Zoom ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-01-10 14:50:21 +00:00
void C4Viewport : : Draw ( C4TargetFacet & cgo0 , bool fDrawGame , bool fDrawOverlay )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef USE_CONSOLE
// No drawing in console mode
return ;
# endif
2010-03-06 14:07:30 +00:00
C4TargetFacet cgo ; cgo . Set ( cgo0 ) ;
2009-05-08 13:28:41 +00:00
ZoomData GameZoom ;
GameZoom . X = cgo . X ; GameZoom . Y = cgo . Y ;
2010-09-25 20:52:43 +00:00
GameZoom . Zoom = cgo . Zoom ;
2009-05-08 13:28:41 +00:00
2015-02-02 23:59:46 +00:00
// Draw landscape borders
2015-09-12 22:14:18 +00:00
if ( BorderLeft > 0.0f ) pDraw - > BlitSurfaceTile ( : : GraphicsResource . fctBackground . Surface , cgo . Surface , DrawX , DrawY , BorderLeft , ViewHgt , - DrawX , - DrawY , NULL ) ;
if ( BorderTop > 0.0f ) pDraw - > BlitSurfaceTile ( : : GraphicsResource . fctBackground . Surface , cgo . Surface , DrawX + BorderLeft , DrawY , ViewWdt - BorderLeft - BorderRight , BorderTop , - DrawX - BorderLeft , - DrawY , NULL ) ;
if ( BorderRight > 0.0f ) pDraw - > BlitSurfaceTile ( : : GraphicsResource . fctBackground . Surface , cgo . Surface , DrawX + ViewWdt - BorderRight , DrawY , BorderRight , ViewHgt , - DrawX - ViewWdt + BorderRight , - DrawY , NULL ) ;
if ( BorderBottom > 0.0f ) pDraw - > BlitSurfaceTile ( : : GraphicsResource . fctBackground . Surface , cgo . Surface , DrawX + BorderLeft , DrawY + ViewHgt - BorderBottom , ViewWdt - BorderLeft - BorderRight , BorderBottom , - DrawX - BorderLeft , - DrawY - ViewHgt + BorderBottom , NULL ) ;
2013-09-14 18:04:15 +00:00
2015-01-07 16:29:48 +00:00
// Compute non-bordered viewport area
2015-02-02 23:59:46 +00:00
cgo . X + = BorderLeft ; cgo . Y + = BorderTop ; cgo . Wdt - = ( BorderLeft + BorderRight ) / cgo . Zoom ; cgo . Hgt - = ( BorderTop + BorderBottom ) / cgo . Zoom ;
cgo . TargetX + = BorderLeft / Zoom ; cgo . TargetY + = BorderTop / Zoom ;
2013-09-14 18:04:15 +00:00
// Apply Zoom
2015-02-02 23:59:46 +00:00
GameZoom . X = cgo . X ; GameZoom . Y = cgo . Y ;
2013-09-14 18:04:15 +00:00
pDraw - > SetZoom ( GameZoom ) ;
2015-01-07 16:29:48 +00:00
// Set clipper to integer bounds around floating point viewport region
const FLOAT_RECT clipRect = { DrawX + BorderLeft , DrawX + ViewWdt - BorderRight , DrawY + BorderTop , DrawY + ViewHgt - BorderBottom } ;
const C4Rect & clipRectInt ( clipRect ) ;
pDraw - > SetPrimaryClipper ( clipRectInt . x , clipRectInt . y , clipRectInt . x + clipRectInt . Wdt - 1 , clipRectInt . y + clipRectInt . Hgt - 1 ) ;
2013-09-14 18:04:15 +00:00
2009-10-16 21:07:43 +00:00
last_game_draw_cgo = cgo ;
2009-05-08 13:28:41 +00:00
2016-01-10 14:50:21 +00:00
if ( fDrawGame )
2010-03-28 18:58:01 +00:00
{
2016-01-10 14:50:21 +00:00
// --- activate FoW here ---
2014-12-29 22:08:17 +00:00
2016-01-10 14:50:21 +00:00
// Render FoW only if active for player
C4FoWRegion * pFoW = NULL ;
if ( Player ! = NO_OWNER )
{
C4Player * pPlr = : : Players . Get ( Player ) ;
assert ( pPlr ! = NULL ) ;
2014-12-29 22:08:17 +00:00
2016-01-10 14:50:21 +00:00
if ( pPlr - > fFogOfWar ) pFoW = this - > pFoW . get ( ) ;
}
2012-08-19 18:35:10 +00:00
2016-01-10 14:50:21 +00:00
// Update FoW
if ( pFoW )
{
// Viewport region in landscape coordinates
const FLOAT_RECT vpRect = { cgo . TargetX , cgo . TargetX + cgo . Wdt , cgo . TargetY , cgo . TargetY + cgo . Hgt } ;
// Region in which the light is calculated
// At the moment, just choose integer coordinates to surround the viewport
const C4Rect lightRect ( vpRect ) ;
2016-01-15 13:53:00 +00:00
if ( ! lightRect . Wdt | | ! lightRect . Hgt )
{
// Do not bother initializing FoW on empty region; would cause errors in drawing proc
pFoW = NULL ;
}
else
{
pFoW - > Update ( lightRect , vpRect ) ;
if ( ! pFoW - > Render ( ) )
{
// If FoW init fails, do not set it for further drawing
pFoW = NULL ;
}
}
2016-01-10 14:50:21 +00:00
}
pDraw - > SetFoW ( pFoW ) ;
2009-05-08 13:28:41 +00:00
2016-01-10 14:50:21 +00:00
C4ST_STARTNEW ( SkyStat , " C4Viewport::Draw: Sky " )
2016-04-02 15:50:49 +00:00
: : Landscape . GetSky ( ) . Draw ( cgo ) ;
2016-01-10 14:50:21 +00:00
C4ST_STOP ( SkyStat )
2014-11-06 16:19:41 +00:00
2016-01-10 14:50:21 +00:00
: : Objects . Draw ( cgo , Player , - 2147483647 - 1 /* INT32_MIN */ , 0 ) ;
2009-05-08 13:28:41 +00:00
2016-01-10 14:50:21 +00:00
// Draw Landscape
C4ST_STARTNEW ( LandStat , " C4Viewport::Draw: Landscape " )
: : Landscape . Draw ( cgo , pFoW ) ;
C4ST_STOP ( LandStat )
2009-05-08 13:28:41 +00:00
2016-01-10 14:50:21 +00:00
// draw PXS (unclipped!)
C4ST_STARTNEW ( PXSStat , " C4Viewport::Draw: PXS " )
: : PXS . Draw ( cgo ) ;
C4ST_STOP ( PXSStat )
2009-05-08 13:28:41 +00:00
2016-02-09 19:39:11 +00:00
// Draw objects which are behind the particle plane.
const int particlePlane = 900 ;
C4ST_STARTNEW ( ObjStat , " C4Viewport::Draw: Objects (1) " )
: : Objects . Draw ( cgo , Player , 1 , particlePlane ) ;
2016-01-10 14:50:21 +00:00
C4ST_STOP ( ObjStat )
2009-05-08 13:28:41 +00:00
2016-02-09 19:39:11 +00:00
// Draw global dynamic particles on a specific Plane
// to enable scripters to put objects both behind and in front of particles.
C4ST_STARTNEW ( PartStat , " C4Viewport::Draw: Dynamic Particles " )
2016-01-10 14:50:21 +00:00
: : Particles . DrawGlobalParticles ( cgo ) ;
C4ST_STOP ( PartStat )
2009-05-08 13:28:41 +00:00
2016-02-09 19:39:11 +00:00
// Now the remaining objects in front of the particles (e.g. GUI elements)
C4ST_STARTNEW ( Obj2Stat , " C4Viewport::Draw: Objects (2) " )
: : Objects . Draw ( cgo , Player , particlePlane + 1 , 2147483647 /* INT32_MAX */ ) ;
C4ST_STOP ( Obj2Stat )
2016-01-10 14:50:21 +00:00
// Draw everything else without FoW
pDraw - > SetFoW ( NULL ) ;
}
else
{
pDraw - > DrawBoxDw ( cgo . Surface , cgo . X , cgo . Y , cgo . X + cgo . Wdt , cgo . Y + cgo . Hgt , 0xff000000 ) ;
}
2012-08-19 18:35:10 +00:00
2009-05-08 13:28:41 +00:00
// Draw PathFinder
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowPathfinder ) Game . PathFinder . Draw ( cgo ) ;
2009-05-08 13:28:41 +00:00
// Draw overlay
2015-03-22 08:58:43 +00:00
if ( ! Game . C4S . Head . Film | | ! Game . C4S . Head . Replay ) Game . DrawCrewOverheadText ( cgo , Player ) ;
2009-05-08 13:28:41 +00:00
2012-09-20 11:33:38 +00:00
// Lights overlay
if ( : : GraphicsSystem . ShowLights & & pFoW ) pFoW - > Render ( & cgo ) ;
2011-09-11 20:05:29 +00:00
2009-05-08 13:28:41 +00:00
if ( fDrawOverlay )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Determine zoom of overlay
2011-08-18 17:46:51 +00:00
float fGUIZoom = GetGUIZoom ( ) ;
2009-05-08 13:28:41 +00:00
// now restore complete cgo range for overlay drawing
2011-10-03 14:30:18 +00:00
pDraw - > SetZoom ( DrawX , DrawY , fGUIZoom ) ;
pDraw - > SetPrimaryClipper ( DrawX , DrawY , DrawX + ( ViewWdt - 1 ) , DrawY + ( ViewHgt - 1 ) ) ;
2010-09-25 20:52:43 +00:00
C4TargetFacet gui_cgo ;
gui_cgo . Set ( cgo0 ) ;
2009-05-08 13:28:41 +00:00
2010-09-25 20:52:43 +00:00
gui_cgo . X = DrawX ; gui_cgo . Y = DrawY ; gui_cgo . Zoom = fGUIZoom ;
gui_cgo . Wdt = int ( float ( ViewWdt ) / fGUIZoom ) ; gui_cgo . Hgt = int ( float ( ViewHgt ) / fGUIZoom ) ;
2015-01-03 21:51:02 +00:00
gui_cgo . TargetX = GetViewX ( ) ; gui_cgo . TargetY = GetViewY ( ) ;
2010-03-16 11:10:11 +00:00
2010-09-25 20:52:43 +00:00
last_gui_draw_cgo = gui_cgo ;
2009-10-16 21:07:43 +00:00
2009-05-08 13:28:41 +00:00
// draw custom GUI objects
2010-09-25 20:52:43 +00:00
: : Objects . ForeObjects . DrawIfCategory ( gui_cgo , Player , C4D_Foreground , false ) ;
2009-05-08 13:28:41 +00:00
// Draw overlay
C4ST_STARTNEW ( OvrStat , " C4Viewport::Draw: Overlay " )
2010-09-28 18:16:33 +00:00
if ( Application . isEditor ) Console . EditCursor . Draw ( cgo ) ;
2009-05-08 13:28:41 +00:00
2010-09-25 20:52:43 +00:00
// Game messages
C4ST_STARTNEW ( MsgStat , " C4Viewport::DrawOverlay: Messages " )
2011-10-03 14:30:18 +00:00
pDraw - > SetZoom ( 0 , 0 , 1.0 ) ;
2010-09-25 20:52:43 +00:00
: : Messages . Draw ( gui_cgo , cgo , Player ) ;
C4ST_STOP ( MsgStat )
2009-05-08 13:28:41 +00:00
2013-02-12 19:39:20 +00:00
// ingame menus
2013-05-09 11:28:45 +00:00
C4ST_STARTNEW ( GuiWindowStat , " C4Viewport::DrawOverlay: Menus " )
2013-02-12 19:39:20 +00:00
pDraw - > SetZoom ( 0 , 0 , 1.0 ) ;
2014-10-13 16:48:03 +00:00
: : Game . ScriptGuiRoot - > DrawAll ( gui_cgo , Player ) ;
2013-05-09 11:28:45 +00:00
C4ST_STOP ( GuiWindowStat )
2013-02-12 19:39:20 +00:00
DrawOverlay ( gui_cgo , GameZoom ) ;
2009-05-08 13:28:41 +00:00
// Netstats
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowNetstatus )
2010-09-25 20:52:43 +00:00
: : Network . DrawStatus ( gui_cgo ) ;
2009-05-08 13:28:41 +00:00
C4ST_STOP ( OvrStat )
}
2013-09-14 18:04:15 +00:00
// Remove zoom n clippers
pDraw - > SetZoom ( 0 , 0 , 1.0 ) ;
pDraw - > NoPrimaryClipper ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : BlitOutput ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pWindow )
2010-03-28 18:58:01 +00:00
{
2011-03-13 16:41:42 +00:00
C4Rect rtSrc , rtDst ;
rtSrc . x = DrawX ; rtSrc . y = DrawY ; rtSrc . Wdt = ViewWdt ; rtSrc . Hgt = ViewHgt ;
rtDst . x = OutX ; rtDst . y = OutY ; rtDst . Wdt = ViewWdt ; rtDst . Hgt = ViewHgt ;
2010-03-05 21:15:25 +00:00
pWindow - > pSurface - > PageFlip ( & rtSrc , & rtDst ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : Execute ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Adjust position
2015-12-03 03:11:28 +00:00
AdjustZoomAndPosition ( ) ;
2009-05-08 13:28:41 +00:00
// Current graphics output
C4TargetFacet cgo ;
2015-12-28 17:24:09 +00:00
C4Surface * target = pWindow ? pWindow - > pSurface : FullScreen . pSurface ;
cgo . Set ( target , DrawX , DrawY , float ( ViewWdt ) / Zoom , float ( ViewHgt ) / Zoom , GetViewX ( ) , GetViewY ( ) , Zoom ) ;
pDraw - > PrepareRendering ( target ) ;
2016-01-10 14:50:21 +00:00
// Do not spoil game contents on owner-less viewport
bool draw_game = true ;
if ( Player = = NO_OWNER )
if ( ! : : Application . isEditor & & ! : : Game . DebugMode )
2016-01-16 21:29:23 +00:00
if ( ! : : Network . isEnabled ( ) | | ! : : Network . Clients . GetLocal ( ) | | ! : : Network . Clients . GetLocal ( ) - > isObserver ( ) )
2016-01-10 14:50:21 +00:00
if ( : : Game . PlayerInfos . GetJoinIssuedPlayerCount ( ) > 0 ) // free scrolling allowed if the scenario was started explicitely without players to inspect the landscape
draw_game = false ;
2009-05-08 13:28:41 +00:00
// Draw
2016-01-10 14:50:21 +00:00
Draw ( cgo , draw_game , true ) ;
2009-05-08 13:28:41 +00:00
// Blit output
BlitOutput ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-12-04 16:36:27 +00:00
/* This method is called whenever the viewport size is changed. Thus, its job
is to recalculate the zoom and zoom limits with the new values for ViewWdt
and ViewHgt . */
void C4Viewport : : CalculateZoom ( )
{
2015-12-03 02:24:57 +00:00
// Zoom is only initialized by player or global setting during viewport creation time, because after that
// the player may have changed to another preferred zoom.
// However, viewports may change multiple times during startup (because of NO_OWNER viewport being deleted
// and possible other player joins). So check by frame counter. Zoom changes done in paused mode on the
// player init frame will be lost, but that should not be a problem.
if ( ViewportOpenFrame > = Game . FrameCounter )
2013-12-04 16:36:27 +00:00
InitZoom ( ) ;
C4Player * plr = Players . Get ( Player ) ;
if ( plr )
plr - > ZoomLimitsToViewport ( this ) ;
else
2016-04-02 15:50:49 +00:00
SetZoomLimits ( 0.8 * std : : min < float > ( float ( ViewWdt ) / : : Landscape . GetWidth ( ) , float ( ViewHgt ) / : : Landscape . GetHeight ( ) ) , 8 ) ;
2013-12-04 16:36:27 +00:00
}
2010-09-08 21:49:42 +00:00
void C4Viewport : : InitZoom ( )
{
C4Player * plr = Players . Get ( Player ) ;
if ( plr )
{
2010-12-12 21:38:19 +00:00
plr - > ZoomToViewport ( this , true ) ;
2010-09-08 21:49:42 +00:00
}
else
{
2016-04-02 15:50:49 +00:00
ZoomTarget = std : : max < float > ( float ( ViewWdt ) / : : Landscape . GetWidth ( ) , 1.0f ) ;
2010-09-08 21:49:42 +00:00
Zoom = ZoomTarget ;
}
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : ChangeZoom ( float by_factor )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ZoomTarget * = by_factor ;
2010-09-08 21:49:42 +00:00
if ( ZoomLimitMin & & ZoomTarget < ZoomLimitMin ) ZoomTarget = ZoomLimitMin ;
if ( ZoomLimitMax & & ZoomTarget > ZoomLimitMax ) ZoomTarget = ZoomLimitMax ;
}
void C4Viewport : : SetZoom ( float to_value , bool direct )
{
ZoomTarget = to_value ;
2010-12-13 20:55:43 +00:00
if ( Player ! = NO_OWNER | | ! : : Application . isEditor )
{
if ( ZoomLimitMin & & ZoomTarget < ZoomLimitMin ) ZoomTarget = ZoomLimitMin ;
if ( ZoomLimitMax & & ZoomTarget > ZoomLimitMax ) ZoomTarget = ZoomLimitMax ;
}
2010-09-08 21:49:42 +00:00
// direct: Set zoom without scrolling to it
if ( direct ) Zoom = ZoomTarget ;
}
void C4Viewport : : SetZoomLimits ( float to_min_zoom , float to_max_zoom )
{
ZoomLimitMin = to_min_zoom ;
ZoomLimitMax = to_max_zoom ;
2012-03-19 14:10:12 +00:00
if ( ZoomLimitMax & & ZoomLimitMax < ZoomLimitMin ) ZoomLimitMax = ZoomLimitMin ;
ChangeZoom ( 1 ) ; // Constrains zoom to limit.
2010-09-08 21:49:42 +00:00
}
float C4Viewport : : GetZoomByViewRange ( int32_t size_x , int32_t size_y ) const
{
// set zoom such that both size_x and size_y are guarantueed to fit into the viewport range
// determine whether zoom is to be calculated by x or by y
2010-09-19 15:39:00 +00:00
bool zoom_by_y = false ;
2010-09-08 21:49:42 +00:00
if ( size_x & & size_y )
{
zoom_by_y = ( size_y * ViewWdt > size_x * ViewHgt ) ;
}
else if ( size_y )
{
// no x size passed - zoom by y
zoom_by_y = true ;
}
2010-09-17 12:35:24 +00:00
else
2010-09-08 21:49:42 +00:00
{
// 0/0 size passed - zoom to default
2010-09-17 12:35:24 +00:00
if ( ! size_x )
2015-01-02 00:06:00 +00:00
size_x = C4VP_DefViewRangeX * 2 ;
2010-09-08 21:49:42 +00:00
zoom_by_y = false ;
}
// zoom calculation
if ( zoom_by_y )
return float ( ViewHgt ) / size_y ;
else
return float ( ViewWdt ) / size_x ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-12-06 20:32:27 +00:00
void C4Viewport : : SetZoom ( float zoomValue )
{
Zoom = zoomValue ;
// also set target to prevent zoom from changing back
ZoomTarget = zoomValue ;
}
2015-12-03 03:11:28 +00:00
void C4Viewport : : AdjustZoomAndPosition ( )
2010-03-28 18:58:01 +00:00
{
2015-12-03 03:11:28 +00:00
// Move zoom towards target zoom
2013-12-04 16:36:27 +00:00
if ( ZoomTarget < 0.000001f ) CalculateZoom ( ) ;
2010-09-08 21:49:42 +00:00
// Change Zoom
2010-09-25 20:53:55 +00:00
2015-12-03 03:11:28 +00:00
if ( Zoom ! = ZoomTarget )
2010-04-26 23:32:45 +00:00
{
2015-12-03 03:11:28 +00:00
float DeltaZoom = Zoom / ZoomTarget ;
if ( DeltaZoom < 1 ) DeltaZoom = 1 / DeltaZoom ;
2010-09-08 21:49:42 +00:00
// Minimal Zoom change factor
2015-12-03 03:11:28 +00:00
static const float Z0 = pow ( C4GFX_ZoomStep , 1.0f / 8.0f ) ;
2010-09-08 21:49:42 +00:00
// We change zoom based on (logarithmic) distance of current zoom
// to target zoom. The greater the distance the more we adjust the
// zoom in one frame. There is a minimal zoom change Z0 to make sure
// we reach ZoomTarget in finite time.
2015-12-03 03:11:28 +00:00
float ZoomAdjustFactor = Z0 * pow ( DeltaZoom , 1.0f / 8.0f ) ;
2010-09-08 21:49:42 +00:00
if ( Zoom < ZoomTarget )
2015-11-15 12:53:01 +00:00
Zoom = std : : min ( Zoom * ZoomAdjustFactor , ZoomTarget ) ;
2010-09-08 21:49:42 +00:00
if ( Zoom > ZoomTarget )
2015-11-15 12:53:01 +00:00
Zoom = std : : max ( Zoom / ZoomAdjustFactor , ZoomTarget ) ;
2010-04-26 23:32:45 +00:00
}
2015-12-03 03:11:28 +00:00
// Adjust position
AdjustPosition ( false ) ;
}
void C4Viewport : : AdjustPosition ( bool immediate )
{
if ( ViewWdt = = 0 | | ViewHgt = = 0 )
{
// zero-sized viewport, possibly minimized editor window
// don't do anything then
return ;
}
assert ( Zoom > 0 ) ;
assert ( ZoomTarget > 0 ) ;
float ViewportScrollBorder = fIsNoOwnerViewport ? 0 : float ( C4ViewportScrollBorder ) ;
C4Player * pPlr = : : Players . Get ( Player ) ;
2009-05-08 13:28:41 +00:00
// View position
if ( PlayerLock & & ValidPlr ( Player ) )
2010-03-28 18:58:01 +00:00
{
2015-01-03 21:51:02 +00:00
float scrollRange , extraBoundsX , extraBoundsY ;
scrollRange = extraBoundsX = extraBoundsY = 0 ;
// target view position (landscape coordinates)
float targetCenterViewX = fixtof ( pPlr - > ViewX ) ;
float targetCenterViewY = fixtof ( pPlr - > ViewY ) ;
2013-02-12 19:39:20 +00:00
2010-03-28 18:58:01 +00:00
if ( pPlr - > ViewMode = = C4PVM_Scrolling )
{
2015-01-03 21:51:02 +00:00
extraBoundsX = extraBoundsY = ViewportScrollBorder ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2015-11-15 12:53:01 +00:00
scrollRange = std : : min ( ViewWdt / ( 10 * Zoom ) , ViewHgt / ( 10 * Zoom ) ) ;
2015-01-03 21:51:02 +00:00
2009-05-08 13:28:41 +00:00
// if view is close to border, allow scrolling
2015-11-15 12:53:01 +00:00
if ( targetCenterViewX < ViewportScrollBorder ) extraBoundsX = std : : min < float > ( ViewportScrollBorder - targetCenterViewX , ViewportScrollBorder ) ;
2016-04-02 15:50:49 +00:00
else if ( targetCenterViewX > = : : Landscape . GetWidth ( ) - ViewportScrollBorder ) extraBoundsX = std : : min < float > ( targetCenterViewX - : : Landscape . GetWidth ( ) , 0 ) + ViewportScrollBorder ;
2015-11-15 12:53:01 +00:00
if ( targetCenterViewY < ViewportScrollBorder ) extraBoundsY = std : : min < float > ( ViewportScrollBorder - targetCenterViewY , ViewportScrollBorder ) ;
2016-04-02 15:50:49 +00:00
else if ( targetCenterViewY > = : : Landscape . GetHeight ( ) - ViewportScrollBorder ) extraBoundsY = std : : min < float > ( targetCenterViewY - : : Landscape . GetHeight ( ) , 0 ) + ViewportScrollBorder ;
2010-03-28 18:58:01 +00:00
}
2015-01-03 21:51:02 +00:00
2016-04-02 15:50:49 +00:00
extraBoundsX = std : : max ( extraBoundsX , ( ViewWdt / Zoom - : : Landscape . GetWidth ( ) ) / 2 + 1 ) ;
extraBoundsY = std : : max ( extraBoundsY , ( ViewHgt / Zoom - : : Landscape . GetHeight ( ) ) / 2 + 1 ) ;
2015-01-03 21:51:02 +00:00
2009-05-08 13:28:41 +00:00
// add mouse auto scroll
2015-01-03 21:51:02 +00:00
if ( pPlr - > MouseControl & & : : MouseControl . InitCentered & & Config . Controls . MouseAutoScroll )
2010-02-09 18:04:04 +00:00
{
2015-01-03 21:51:02 +00:00
float strength = Config . Controls . MouseAutoScroll / 100.0f ;
targetCenterViewX + = strength * ( : : MouseControl . VpX - ViewWdt / 2.0f ) / Zoom ;
targetCenterViewY + = strength * ( : : MouseControl . VpY - ViewHgt / 2.0f ) / Zoom ;
2010-02-09 18:04:04 +00:00
}
2015-01-03 21:51:02 +00:00
2009-05-08 13:28:41 +00:00
// scroll range
2015-12-03 03:11:28 +00:00
if ( ! immediate )
{
targetCenterViewX = Clamp ( targetCenterViewX , targetCenterViewX - scrollRange , targetCenterViewX + scrollRange ) ;
targetCenterViewY = Clamp ( targetCenterViewY , targetCenterViewY - scrollRange , targetCenterViewY + scrollRange ) ;
}
2009-05-08 13:28:41 +00:00
// bounds
2016-04-02 15:50:49 +00:00
targetCenterViewX = Clamp ( targetCenterViewX , ViewWdt / Zoom / 2 - extraBoundsX , : : Landscape . GetWidth ( ) - ViewWdt / Zoom / 2 + extraBoundsX ) ;
targetCenterViewY = Clamp ( targetCenterViewY , ViewHgt / Zoom / 2 - extraBoundsY , : : Landscape . GetHeight ( ) - ViewHgt / Zoom / 2 + extraBoundsY ) ;
2015-01-03 21:51:02 +00:00
targetViewX = targetCenterViewX - ViewWdt / Zoom / 2 + viewOffsX ;
targetViewY = targetCenterViewY - ViewHgt / Zoom / 2 + viewOffsY ;
2015-12-03 03:11:28 +00:00
if ( immediate )
{
// immediate scroll
SetViewX ( targetViewX ) ;
SetViewY ( targetViewY ) ;
}
else
{
// smooth scroll
int32_t smooth = Clamp < int32_t > ( Config . General . ScrollSmooth , 1 , 50 ) ;
ScrollView ( ( targetViewX - viewX ) / smooth , ( targetViewY - viewY ) / smooth ) ;
}
2010-03-28 18:58:01 +00:00
}
2015-01-03 21:51:02 +00:00
UpdateBordersX ( ) ;
UpdateBordersY ( ) ;
2009-05-08 13:28:41 +00:00
// NO_OWNER can't scroll
2015-01-03 21:51:02 +00:00
if ( fIsNoOwnerViewport ) { viewOffsX = 0 ; viewOffsY = 0 ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : CenterPosition ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// center viewport position on map
// set center position
2016-04-02 15:50:49 +00:00
SetViewX ( : : Landscape . GetWidth ( ) / 2 + ViewWdt / Zoom / 2 ) ;
SetViewY ( : : Landscape . GetHeight ( ) / 2 + ViewHgt / Zoom / 2 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-03 21:51:02 +00:00
void C4Viewport : : UpdateBordersX ( )
2010-03-28 18:58:01 +00:00
{
2015-11-15 12:53:01 +00:00
BorderLeft = std : : max ( - GetViewX ( ) * Zoom , 0.0f ) ;
2016-04-02 15:50:49 +00:00
BorderRight = std : : max ( ViewWdt - : : Landscape . GetWidth ( ) * Zoom + GetViewX ( ) * Zoom , 0.0f ) ;
2015-01-03 21:51:02 +00:00
}
void C4Viewport : : UpdateBordersY ( )
{
2015-11-15 12:53:01 +00:00
BorderTop = std : : max ( - GetViewY ( ) * Zoom , 0.0f ) ;
2016-04-02 15:50:49 +00:00
BorderBottom = std : : max ( ViewHgt - : : Landscape . GetHeight ( ) * Zoom + GetViewY ( ) * Zoom , 0.0f ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : DrawPlayerInfo ( C4TargetFacet & cgo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Facet ccgo ;
if ( ! ValidPlr ( Player ) ) return ;
// Controls
DrawPlayerStartup ( cgo ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Viewport : : Init ( int32_t iPlayer , bool fSetTempOnly )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Fullscreen viewport initialization
// Set Player
if ( ! ValidPlr ( iPlayer ) ) iPlayer = NO_OWNER ;
Player = iPlayer ;
2015-12-03 02:24:57 +00:00
ViewportOpenFrame = Game . FrameCounter ;
2009-05-08 13:28:41 +00:00
if ( ! fSetTempOnly ) fIsNoOwnerViewport = ( iPlayer = = NO_OWNER ) ;
2012-03-04 21:45:00 +00:00
if ( Application . isEditor )
{
// Console viewport initialization
// Create window
2015-12-28 17:24:09 +00:00
pWindow . reset ( new C4ViewportWindow ( this ) ) ;
2012-03-04 21:45:00 +00:00
if ( ! pWindow - > Init ( Player ) )
return false ;
UpdateOutputSize ( ) ;
// Disable player lock on unowned viewports
if ( ! ValidPlr ( Player ) ) TogglePlayerLock ( ) ;
// Don't call Execute right away since it is not yet guaranteed that
// the Player has set this as its Viewport, and the drawing routines rely
// on that.
}
else
{
// Owned viewport: clear any flash message explaining observer menu
if ( ValidPlr ( iPlayer ) ) : : GraphicsSystem . FlashMessage ( " " ) ;
}
2015-01-14 17:03:05 +00:00
EnableFoW ( ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-14 17:03:05 +00:00
void C4Viewport : : DisableFoW ( )
{
2015-12-28 17:24:09 +00:00
pFoW . reset ( ) ;
2015-01-14 17:03:05 +00:00
}
void C4Viewport : : EnableFoW ( )
{
2016-04-02 15:50:49 +00:00
if ( : : Landscape . HasFoW ( ) & & Player ! = NO_OWNER )
2015-12-28 17:24:09 +00:00
{
2016-04-02 15:50:49 +00:00
pFoW . reset ( new C4FoWRegion ( : : Landscape . GetFoW ( ) , : : Players . Get ( Player ) ) ) ;
2015-12-28 17:24:09 +00:00
}
else
{
DisableFoW ( ) ;
}
2015-01-14 17:03:05 +00:00
}
2009-05-08 13:28:41 +00:00
extern int32_t DrawMessageOffset ;
void C4Viewport : : DrawPlayerStartup ( C4TargetFacet & cgo )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Player * pPlr ;
2009-06-12 23:09:32 +00:00
if ( ! ( pPlr = : : Players . Get ( Player ) ) ) return ;
2009-05-08 13:28:41 +00:00
if ( ! pPlr - > LocalControl | | ! pPlr - > ShowStartup ) return ;
int32_t iNameHgtOff = 0 ;
// Control
2012-01-29 02:13:55 +00:00
// unnecessary with the current control sets
2009-10-14 16:46:22 +00:00
if ( pPlr & & pPlr - > ControlSet )
2010-03-28 18:58:01 +00:00
{
2009-10-14 16:46:22 +00:00
C4Facet controlset_facet = pPlr - > ControlSet - > GetPicture ( ) ;
if ( controlset_facet . Wdt ) controlset_facet . Draw ( cgo . Surface ,
2010-03-28 18:58:01 +00:00
cgo . X + ( cgo . Wdt - controlset_facet . Wdt ) / 2 ,
cgo . Y + cgo . Hgt * 2 / 3 + DrawMessageOffset ,
0 , 0 ) ;
2009-05-08 13:28:41 +00:00
iNameHgtOff = GfxR - > fctKeyboard . Hgt ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Name
2011-10-03 14:30:18 +00:00
pDraw - > TextOut ( pPlr - > GetName ( ) , : : GraphicsResource . FontRegular , 1.0 , cgo . Surface ,
2010-03-28 18:58:01 +00:00
cgo . X + cgo . Wdt / 2 , cgo . Y + cgo . Hgt * 2 / 3 + iNameHgtOff + DrawMessageOffset ,
pPlr - > ColorDw | 0xff000000 , ACenter ) ;
}
2009-05-08 13:28:41 +00:00
2015-01-03 21:51:02 +00:00
void C4Viewport : : ScrollView ( float byX , float byY )
{
SetViewX ( viewX + byX ) ;
SetViewY ( viewY + byY ) ;
}
void C4Viewport : : SetViewX ( float x )
{
viewX = x ;
if ( fIsNoOwnerViewport )
{
2016-04-02 15:50:49 +00:00
if ( : : Landscape . GetWidth ( ) < ViewWdt / Zoom )
2015-01-03 21:51:02 +00:00
{
2016-04-02 15:50:49 +00:00
viewX = : : Landscape . GetWidth ( ) / 2 - ViewWdt / Zoom / 2 ;
2015-01-03 21:51:02 +00:00
}
else
{
2016-04-02 15:50:49 +00:00
viewX = Clamp ( x , 0.0f , : : Landscape . GetWidth ( ) - ViewWdt / Zoom ) ;
2015-01-03 21:51:02 +00:00
}
}
UpdateBordersX ( ) ;
}
void C4Viewport : : SetViewY ( float y )
{
viewY = y ;
if ( fIsNoOwnerViewport )
{
2016-04-02 15:50:49 +00:00
if ( : : Landscape . GetHeight ( ) < ViewHgt / Zoom )
2015-01-03 21:51:02 +00:00
{
2016-04-02 15:50:49 +00:00
viewY = : : Landscape . GetHeight ( ) / 2 - ViewHgt / Zoom / 2 ;
2015-01-03 21:51:02 +00:00
}
else
{
2016-04-02 15:50:49 +00:00
viewY = Clamp ( y , 0.0f , : : Landscape . GetHeight ( ) - ViewHgt / Zoom ) ;
2015-01-03 21:51:02 +00:00
}
}
UpdateBordersY ( ) ;
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : SetOutputSize ( int32_t iDrawX , int32_t iDrawY , int32_t iOutX , int32_t iOutY , int32_t iOutWdt , int32_t iOutHgt )
2010-03-28 18:58:01 +00:00
{
2015-01-03 21:51:02 +00:00
int32_t deltaWidth = ViewWdt - iOutWdt ;
int32_t deltaHeight = ViewHgt - iOutHgt ;
2009-05-08 13:28:41 +00:00
// update output parameters
DrawX = iDrawX ; DrawY = iDrawY ;
OutX = iOutX ; OutY = iOutY ;
ViewWdt = iOutWdt ; ViewHgt = iOutHgt ;
2015-01-03 21:51:02 +00:00
// update view position: Remain centered at previous position
// scrolling the view must be done after setting the new view width and height
ScrollView ( deltaWidth / 2 , deltaHeight / 2 ) ;
2013-12-04 16:36:27 +00:00
CalculateZoom ( ) ;
2009-05-08 13:28:41 +00:00
// Reset menus
2009-08-15 18:50:32 +00:00
ResetMenuPositions = true ;
2009-05-08 13:28:41 +00:00
// player uses mouse control? then clip the cursor
C4Player * pPlr ;
2010-01-25 04:00:59 +00:00
if ( ( pPlr = : : Players . Get ( Player ) ) )
2009-05-08 13:28:41 +00:00
if ( pPlr - > MouseControl )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:20:07 +00:00
: : MouseControl . UpdateClip ( ) ;
2009-05-08 13:28:41 +00:00
// and inform GUI
2010-10-29 23:47:50 +00:00
: : pGUI - > SetPreferredDlgRect ( C4Rect ( iOutX , iOutY , iOutWdt , iOutHgt ) ) ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : ClearPointers ( C4Object * pObj )
2010-03-28 18:58:01 +00:00
{
2012-11-16 16:29:42 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Viewport : : NextPlayer ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Player * pPlr ; int32_t iPlr ;
2009-06-12 23:09:32 +00:00
if ( ! ( pPlr = : : Players . Get ( Player ) ) )
2010-03-28 18:58:01 +00:00
{
2009-06-12 23:09:32 +00:00
if ( ! ( pPlr = : : Players . First ) ) return ;
2010-03-28 18:58:01 +00:00
}
else if ( ! ( pPlr = pPlr - > Next ) )
if ( Game . C4S . Head . Film & & Game . C4S . Head . Replay )
pPlr = : : Players . First ; // cycle to first in film mode only; in network obs mode allow NO_OWNER-view
2009-05-08 13:28:41 +00:00
if ( pPlr ) iPlr = pPlr - > Number ; else iPlr = NO_OWNER ;
if ( iPlr ! = Player ) Init ( iPlr , true ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Viewport : : IsViewportMenu ( class C4Menu * pMenu )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check all associated menus
// Get player
2009-06-12 23:09:32 +00:00
C4Player * pPlr = : : Players . Get ( Player ) ;
2009-05-08 13:28:41 +00:00
// Player eliminated: No menu
if ( pPlr & & pPlr - > Eliminated ) return false ;
// Player cursor object menu
if ( pPlr & & pPlr - > Cursor & & pPlr - > Cursor - > Menu = = pMenu ) return true ;
// Player menu
if ( pPlr & & pPlr - > Menu . IsActive ( ) & & & ( pPlr - > Menu ) = = pMenu ) return true ;
// Fullscreen menu (if active, only one viewport can exist)
if ( FullScreen . pMenu & & FullScreen . pMenu - > IsActive ( ) & & FullScreen . pMenu = = pMenu ) return true ;
// no match
return false ;
2010-03-28 18:58:01 +00:00
}
2010-09-29 01:44:05 +00:00
// C4ViewportList
C4ViewportList Viewports ;
C4ViewportList : : C4ViewportList ( ) :
FirstViewport ( NULL )
{
ViewportArea . Default ( ) ;
}
C4ViewportList : : ~ C4ViewportList ( )
{
}
void C4ViewportList : : Clear ( )
{
C4Viewport * next ;
while ( FirstViewport )
{
next = FirstViewport - > Next ;
delete FirstViewport ;
FirstViewport = next ;
}
FirstViewport = NULL ;
}
void C4ViewportList : : Execute ( bool DrawBackground )
{
// Background redraw
if ( DrawBackground )
DrawFullscreenBackground ( ) ;
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
2010-12-11 18:50:38 +00:00
{
if ( cvp - > GetWindow ( ) )
cvp - > GetWindow ( ) - > RequestUpdate ( ) ;
2010-12-12 14:27:48 +00:00
else
cvp - > Execute ( ) ;
2010-12-11 18:50:38 +00:00
}
2010-09-29 01:44:05 +00:00
}
void C4ViewportList : : DrawFullscreenBackground ( )
{
for ( int i = 0 , iNum = BackgroundAreas . GetCount ( ) ; i < iNum ; + + i )
{
const C4Rect & rc = BackgroundAreas . Get ( i ) ;
2015-09-12 22:14:18 +00:00
pDraw - > BlitSurfaceTile ( : : GraphicsResource . fctBackground . Surface , FullScreen . pSurface , rc . x , rc . y , rc . Wdt , rc . Hgt , - rc . x , - rc . y , NULL ) ;
2010-09-29 01:44:05 +00:00
}
}
bool C4ViewportList : : CloseViewport ( C4Viewport * cvp )
{
if ( ! cvp ) return false ;
// Chop the start of the chain off
if ( FirstViewport = = cvp )
{
FirstViewport = cvp - > Next ;
delete cvp ;
2015-12-13 21:14:55 +00:00
StartSoundEffect ( " UI::CloseViewport " ) ;
2010-09-29 01:44:05 +00:00
}
// Take out of the chain
else for ( C4Viewport * prev = FirstViewport ; prev ; prev = prev - > Next )
{
if ( prev - > Next = = cvp )
{
prev - > Next = cvp - > Next ;
delete cvp ;
2015-12-13 21:14:55 +00:00
StartSoundEffect ( " UI::CloseViewport " ) ;
2010-09-29 01:44:05 +00:00
}
}
// Recalculate viewports
RecalculateViewports ( ) ;
// Done
return true ;
}
2012-03-23 21:53:56 +00:00
# ifdef USE_WIN32_WINDOWS
2010-09-29 01:44:05 +00:00
C4Viewport * C4ViewportList : : GetViewport ( HWND hwnd )
{
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
if ( cvp - > pWindow - > hWindow = = hwnd )
return cvp ;
return NULL ;
}
# endif
bool C4ViewportList : : CreateViewport ( int32_t iPlayer , bool fSilent )
{
// Create and init new viewport, add to viewport list
int32_t iLastCount = GetViewportCount ( ) ;
C4Viewport * nvp = new C4Viewport ;
2012-03-04 21:45:00 +00:00
bool fOkay = nvp - > Init ( iPlayer , false ) ;
2010-09-29 01:44:05 +00:00
if ( ! fOkay ) { delete nvp ; return false ; }
C4Viewport * pLast ;
for ( pLast = FirstViewport ; pLast & & pLast - > Next ; pLast = pLast - > Next ) { }
if ( pLast ) pLast - > Next = nvp ; else FirstViewport = nvp ;
// Recalculate viewports
RecalculateViewports ( ) ;
// Viewports start off at centered position
nvp - > CenterPosition ( ) ;
2015-10-11 01:46:55 +00:00
// Initial player zoom values to viewport (in case they were set early in InitializePlayer, loaded from savegame, etc.)
C4Player * plr = : : Players . Get ( iPlayer ) ;
if ( plr )
{
plr - > ZoomToViewport ( nvp , true , false , false ) ;
plr - > ZoomLimitsToViewport ( nvp ) ;
}
2010-09-29 01:44:05 +00:00
// Action sound
if ( GetViewportCount ( ) ! = iLastCount ) if ( ! fSilent )
2015-12-13 21:14:55 +00:00
StartSoundEffect ( " UI::CloseViewport " ) ;
2010-09-29 01:44:05 +00:00
return true ;
}
2015-01-14 17:03:05 +00:00
void C4ViewportList : : DisableFoW ( )
{
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
cvp - > DisableFoW ( ) ;
}
void C4ViewportList : : EnableFoW ( )
{
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
cvp - > EnableFoW ( ) ;
}
2010-09-29 01:44:05 +00:00
void C4ViewportList : : ClearPointers ( C4Object * pObj )
{
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
cvp - > ClearPointers ( pObj ) ;
}
bool C4ViewportList : : CloseViewport ( int32_t iPlayer , bool fSilent )
{
// Close all matching viewports
int32_t iLastCount = GetViewportCount ( ) ;
C4Viewport * next , * prev = NULL ;
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = next )
{
next = cvp - > Next ;
if ( cvp - > Player = = iPlayer | | ( iPlayer = = NO_OWNER & & cvp - > fIsNoOwnerViewport ) )
{
delete cvp ;
if ( prev ) prev - > Next = next ;
else FirstViewport = next ;
}
else
prev = cvp ;
}
2012-10-13 19:36:14 +00:00
// Anything was done?
if ( GetViewportCount ( ) ! = iLastCount )
{
// Recalculate viewports
RecalculateViewports ( ) ;
// Action sound
2015-12-13 21:14:55 +00:00
if ( ! fSilent ) StartSoundEffect ( " UI::CloseViewport " ) ;
2012-10-13 19:36:14 +00:00
}
2010-09-29 01:44:05 +00:00
return true ;
}
void C4ViewportList : : RecalculateViewports ( )
{
// Fullscreen only
if ( Application . isEditor ) return ;
// Sort viewports
SortViewportsByPlayerControl ( ) ;
// Viewport area
2010-10-17 19:38:56 +00:00
int32_t iBorderTop = 0 ;
2010-09-29 01:44:05 +00:00
if ( Config . Graphics . UpperBoard )
iBorderTop = C4UpperBoardHeight ;
ViewportArea . Set ( FullScreen . pSurface , 0 , iBorderTop , C4GUI : : GetScreenWdt ( ) , C4GUI : : GetScreenHgt ( ) - iBorderTop ) ;
// Redraw flag
: : GraphicsSystem . InvalidateBg ( ) ;
# ifdef _WIN32
// reset mouse clipping
ClipCursor ( NULL ) ;
# else
// StdWindow handles this.
# endif
// reset GUI dlg pos
2010-10-29 23:47:50 +00:00
: : pGUI - > SetPreferredDlgRect ( C4Rect ( ViewportArea . X , ViewportArea . Y , ViewportArea . Wdt , ViewportArea . Hgt ) ) ;
2010-09-29 01:44:05 +00:00
// fullscreen background: First, cover all of screen
BackgroundAreas . Clear ( ) ;
BackgroundAreas . AddRect ( C4Rect ( ViewportArea . X , ViewportArea . Y , ViewportArea . Wdt , ViewportArea . Hgt ) ) ;
// Viewports
C4Viewport * cvp ;
int32_t iViews = 0 ;
for ( cvp = FirstViewport ; cvp ; cvp = cvp - > Next ) iViews + + ;
if ( ! iViews ) return ;
int32_t iViewsH = ( int32_t ) sqrt ( float ( iViews ) ) ;
int32_t iViewsX = iViews / iViewsH ;
int32_t iViewsL = iViews % iViewsH ;
int32_t cViewH , cViewX , ciViewsX ;
int32_t cViewWdt , cViewHgt , cOffWdt , cOffHgt , cOffX , cOffY ;
cvp = FirstViewport ;
for ( cViewH = 0 ; cViewH < iViewsH ; cViewH + + )
{
ciViewsX = iViewsX ; if ( cViewH < iViewsL ) ciViewsX + + ;
for ( cViewX = 0 ; cViewX < ciViewsX ; cViewX + + )
{
cViewWdt = ViewportArea . Wdt / ciViewsX ;
cViewHgt = ViewportArea . Hgt / iViewsH ;
cOffX = ViewportArea . X ;
cOffY = ViewportArea . Y ;
cOffWdt = cOffHgt = 0 ;
if ( ciViewsX * cViewWdt < ViewportArea . Wdt )
cOffX = ( ViewportArea . Wdt - ciViewsX * cViewWdt ) / 2 ;
if ( iViewsH * cViewHgt < ViewportArea . Hgt )
cOffY = ( ViewportArea . Hgt - iViewsH * cViewHgt ) / 2 + ViewportArea . Y ;
if ( Config . Graphics . SplitscreenDividers )
{
if ( cViewX < ciViewsX - 1 ) cOffWdt = 4 ;
if ( cViewH < iViewsH - 1 ) cOffHgt = 4 ;
}
int32_t coViewWdt = cViewWdt - cOffWdt ;
int32_t coViewHgt = cViewHgt - cOffHgt ;
C4Rect rcOut ( cOffX + cViewX * cViewWdt , cOffY + cViewH * cViewHgt , coViewWdt , coViewHgt ) ;
cvp - > SetOutputSize ( rcOut . x , rcOut . y , rcOut . x , rcOut . y , rcOut . Wdt , rcOut . Hgt ) ;
cvp = cvp - > Next ;
// clip down area avaiable for background drawing
BackgroundAreas . ClipByRect ( rcOut ) ;
}
}
2015-08-02 21:19:28 +00:00
// and finally recalculate script menus
if ( : : Game . ScriptGuiRoot )
: : Game . ScriptGuiRoot - > RequestLayoutUpdate ( ) ;
2010-09-29 01:44:05 +00:00
}
int32_t C4ViewportList : : GetViewportCount ( )
{
int32_t iResult = 0 ;
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next ) iResult + + ;
return iResult ;
}
2010-12-12 21:38:19 +00:00
C4Viewport * C4ViewportList : : GetViewport ( int32_t iPlayer , C4Viewport * pPrev )
2010-09-29 01:44:05 +00:00
{
2010-12-12 21:38:19 +00:00
for ( C4Viewport * cvp = pPrev ? pPrev - > Next : FirstViewport ; cvp ; cvp = cvp - > Next )
2010-09-29 01:44:05 +00:00
if ( cvp - > Player = = iPlayer | | ( iPlayer = = NO_OWNER & & cvp - > fIsNoOwnerViewport ) )
return cvp ;
return NULL ;
}
2015-08-28 01:44:23 +00:00
int32_t C4ViewportList : : GetAudibility ( int32_t iX , int32_t iY , int32_t * iPan , int32_t iAudibilityRadius , int32_t * outPlayer )
2010-09-29 01:44:05 +00:00
{
// default audibility radius
if ( ! iAudibilityRadius ) iAudibilityRadius = C4AudibilityRadius ;
// Accumulate audibility by viewports
int32_t iAudible = 0 ; * iPan = 0 ;
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
{
2015-01-03 21:51:02 +00:00
float distanceToCenterOfViewport = Distance ( cvp - > GetViewCenterX ( ) , cvp - > GetViewCenterY ( ) , iX , iY ) ;
2015-08-28 01:44:23 +00:00
int32_t audibility = Clamp < int32_t > ( 100 - 100 * distanceToCenterOfViewport / C4AudibilityRadius , 0 , 100 ) ;
if ( audibility > iAudible )
{
iAudible = audibility ;
if ( outPlayer ) * outPlayer = cvp - > Player ;
}
2015-01-03 21:51:02 +00:00
* iPan + = ( iX - ( cvp - > GetViewCenterX ( ) ) ) / 5 ;
2010-09-29 01:44:05 +00:00
}
2015-02-12 22:05:55 +00:00
* iPan = Clamp < int32_t > ( * iPan , - 100 , 100 ) ;
2010-09-29 01:44:05 +00:00
return iAudible ;
}
void C4ViewportList : : SortViewportsByPlayerControl ( )
{
// Sort
bool fSorted ;
C4Player * pPlr1 , * pPlr2 ;
C4Viewport * pView , * pNext , * pPrev ;
do
{
fSorted = true ;
for ( pPrev = NULL , pView = FirstViewport ; pView & & ( pNext = pView - > Next ) ; pView = pNext )
{
// Get players
pPlr1 = : : Players . Get ( pView - > Player ) ;
pPlr2 = : : Players . Get ( pNext - > Player ) ;
// Swap order
if ( pPlr1 & & pPlr2 & & pPlr1 - > ControlSet & & pPlr2 - > ControlSet & & ( pPlr1 - > ControlSet - > GetLayoutOrder ( ) > pPlr2 - > ControlSet - > GetLayoutOrder ( ) ) )
{
if ( pPrev ) pPrev - > Next = pNext ; else FirstViewport = pNext ;
pView - > Next = pNext - > Next ;
pNext - > Next = pView ;
pPrev = pNext ;
pNext = pView ;
fSorted = false ;
}
// Don't swap
else
{
pPrev = pView ;
}
}
}
while ( ! fSorted ) ;
}
bool C4ViewportList : : ViewportNextPlayer ( )
{
// safety: switch valid?
if ( ( ! Game . C4S . Head . Film | | ! Game . C4S . Head . Replay ) & & ! GetViewport ( NO_OWNER ) ) return false ;
// do switch then
C4Viewport * vp = GetFirstViewport ( ) ;
if ( ! vp ) return false ;
vp - > NextPlayer ( ) ;
return true ;
}
bool C4ViewportList : : FreeScroll ( C4Vec2D vScrollBy )
{
// safety: move valid?
if ( ( ! Game . C4S . Head . Replay | | ! Game . C4S . Head . Film ) & & ! GetViewport ( NO_OWNER ) ) return false ;
C4Viewport * vp = GetFirstViewport ( ) ;
if ( ! vp ) return false ;
// move then (old static code crap...)
static int32_t vp_vx = 0 ; static int32_t vp_vy = 0 ; static int32_t vp_vf = 0 ;
int32_t dx = vScrollBy . x ; int32_t dy = vScrollBy . y ;
if ( Game . FrameCounter - vp_vf < 5 )
{ dx + = vp_vx ; dy + = vp_vy ; }
vp_vx = dx ; vp_vy = dy ; vp_vf = Game . FrameCounter ;
2015-01-03 21:51:02 +00:00
vp - > ScrollView ( dx , dy ) ;
2010-09-29 01:44:05 +00:00
return true ;
}
bool C4ViewportList : : ViewportZoomOut ( )
{
for ( C4Viewport * vp = FirstViewport ; vp ; vp = vp - > Next ) vp - > ChangeZoom ( 1.0f / C4GFX_ZoomStep ) ;
return true ;
}
bool C4ViewportList : : ViewportZoomIn ( )
{
for ( C4Viewport * vp = FirstViewport ; vp ; vp = vp - > Next ) vp - > ChangeZoom ( C4GFX_ZoomStep ) ;
return true ;
}
void C4ViewportList : : MouseMoveToViewport ( int32_t iButton , int32_t iX , int32_t iY , DWORD dwKeyParam )
{
// Pass on to mouse controlled viewport
for ( C4Viewport * cvp = FirstViewport ; cvp ; cvp = cvp - > Next )
if ( : : MouseControl . IsViewport ( cvp ) )
: : MouseControl . Move ( iButton ,
2015-02-12 22:05:55 +00:00
Clamp < int32_t > ( iX - cvp - > OutX , 0 , cvp - > ViewWdt - 1 ) ,
Clamp < int32_t > ( iY - cvp - > OutY , 0 , cvp - > ViewHgt - 1 ) ,
2010-09-29 01:44:05 +00:00
dwKeyParam ) ;
}