2010-02-02 16:25:35 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
2014-02-18 02:34:24 +01:00
*
2010-02-02 16:25:35 +00:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2014-02-18 02:34:24 +01:00
*
2010-02-02 16:25:35 +00:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
2011-04-24 11:34:27 +03:00
# include "common/algorithm.h"
2016-02-21 17:21:48 +01:00
# include "common/config-manager.h"
2011-04-24 11:34:27 +03:00
# include "common/events.h"
# include "common/keyboard.h"
2016-01-02 15:32:38 +02:00
# include "common/list.h"
2011-04-24 11:34:27 +03:00
# include "common/str.h"
# include "common/system.h"
# include "common/textconsole.h"
# include "engines/engine.h"
2016-07-28 14:49:13 -05:00
# include "engines/util.h"
2012-08-16 13:30:32 -04:00
# include "graphics/palette.h"
2011-04-24 11:34:27 +03:00
# include "graphics/surface.h"
2010-02-02 16:25:35 +00:00
# include "sci/sci.h"
2012-05-21 01:29:30 +03:00
# include "sci/console.h"
2017-01-09 22:57:41 -06:00
# include "sci/event.h"
2016-11-27 10:53:06 -06:00
# include "sci/engine/features.h"
2010-06-23 15:23:37 +00:00
# include "sci/engine/kernel.h"
2010-02-02 16:25:35 +00:00
# include "sci/engine/state.h"
# include "sci/engine/selector.h"
# include "sci/engine/vm.h"
# include "sci/graphics/cache.h"
2011-10-19 20:27:43 +03:00
# include "sci/graphics/compare.h"
2016-07-31 13:41:05 -05:00
# include "sci/graphics/cursor32.h"
2010-02-03 01:36:53 +00:00
# include "sci/graphics/font.h"
2016-07-03 17:57:58 -05:00
# include "sci/graphics/frameout.h"
2017-07-03 20:12:39 -05:00
# include "sci/graphics/helpers.h"
2010-02-04 17:57:44 +00:00
# include "sci/graphics/paint32.h"
2016-01-06 20:00:28 -06:00
# include "sci/graphics/palette32.h"
2016-01-18 00:12:47 -06:00
# include "sci/graphics/plane32.h"
2016-06-25 14:19:47 -05:00
# include "sci/graphics/remap32.h"
2016-07-03 17:57:58 -05:00
# include "sci/graphics/screen.h"
2016-01-18 00:12:47 -06:00
# include "sci/graphics/screen_item32.h"
2016-06-25 14:19:47 -05:00
# include "sci/graphics/text32.h"
2010-02-02 16:25:35 +00:00
# include "sci/graphics/frameout.h"
2016-07-25 11:06:27 -05:00
# include "sci/graphics/transitions32.h"
2016-07-03 17:57:58 -05:00
# include "sci/graphics/video32.h"
2010-02-02 16:25:35 +00:00
namespace Sci {
2016-08-19 11:53:04 -05:00
GfxFrameout : : GfxFrameout ( SegManager * segMan , GfxPalette32 * palette , GfxTransitions32 * transitions , GfxCursor32 * cursor ) :
2016-09-09 16:17:41 -05:00
_isHiRes ( gameIsHiRes ( ) ) ,
2016-01-18 00:12:47 -06:00
_palette ( palette ) ,
2016-07-31 13:41:05 -05:00
_cursor ( cursor ) ,
2016-02-18 21:09:15 -06:00
_segMan ( segMan ) ,
2016-07-25 11:06:27 -05:00
_transitions ( transitions ) ,
2016-07-01 19:47:15 -05:00
_throttleState ( 0 ) ,
2016-02-18 21:09:15 -06:00
_remapOccurred ( false ) ,
_overdrawThreshold ( 0 ) ,
2017-07-22 23:26:39 -05:00
_throttleKernelFrameOut ( true ) ,
2017-05-22 18:40:52 -05:00
_palMorphIsOn ( false ) ,
_lastScreenUpdateTick ( 0 ) {
2016-01-18 00:12:47 -06:00
2016-07-28 14:49:13 -05:00
if ( g_sci - > getGameId ( ) = = GID_PHANTASMAGORIA ) {
_currentBuffer = Buffer ( 630 , 450 , nullptr ) ;
} else if ( _isHiRes ) {
_currentBuffer = Buffer ( 640 , 480 , nullptr ) ;
} else {
_currentBuffer = Buffer ( 320 , 200 , nullptr ) ;
}
_currentBuffer . setPixels ( calloc ( 1 , _currentBuffer . screenWidth * _currentBuffer . screenHeight ) ) ;
_screenRect = Common : : Rect ( _currentBuffer . screenWidth , _currentBuffer . screenHeight ) ;
initGraphics ( _currentBuffer . screenWidth , _currentBuffer . screenHeight , _isHiRes ) ;
2016-03-18 18:49:10 -05:00
switch ( g_sci - > getGameId ( ) ) {
2016-07-11 13:02:05 -05:00
case GID_HOYLE5 :
2016-03-18 18:49:10 -05:00
case GID_LIGHTHOUSE :
case GID_LSL7 :
case GID_PHANTASMAGORIA2 :
case GID_TORIN :
case GID_RAMA :
_currentBuffer . scriptWidth = 640 ;
_currentBuffer . scriptHeight = 480 ;
break ;
2017-01-08 19:34:24 -06:00
case GID_GK2 :
2017-01-09 11:39:43 -06:00
case GID_PQSWAT :
2017-01-08 19:34:24 -06:00
if ( ! g_sci - > isDemo ( ) ) {
_currentBuffer . scriptWidth = 640 ;
_currentBuffer . scriptHeight = 480 ;
}
break ;
2016-03-18 18:49:10 -05:00
default :
// default script width for other games is 320x200
break ;
}
2010-02-02 16:25:35 +00:00
}
GfxFrameout : : ~ GfxFrameout ( ) {
2012-01-15 18:35:33 +02:00
clear ( ) ;
2016-03-06 16:40:23 -06:00
CelObj : : deinit ( ) ;
free ( _currentBuffer . getPixels ( ) ) ;
2010-02-02 16:25:35 +00:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : run ( ) {
CelObj : : init ( ) ;
Plane : : init ( ) ;
ScreenItem : : init ( ) ;
2017-01-22 19:01:02 -06:00
GfxText32 : : init ( ) ;
2016-01-18 00:12:47 -06:00
// NOTE: This happens in SCI::InitPlane in the actual engine,
// and is a background fill plane to ensure hidden planes
// (planes with a priority of -1) are never drawn
2016-02-18 00:07:28 -06:00
Plane * initPlane = new Plane ( Common : : Rect ( _currentBuffer . scriptWidth , _currentBuffer . scriptHeight ) ) ;
2016-01-18 00:12:47 -06:00
initPlane - > _priority = 0 ;
_planes . add ( initPlane ) ;
}
2011-02-14 22:38:12 -05:00
void GfxFrameout : : clear ( ) {
_planes . clear ( ) ;
2016-02-21 01:44:28 +01:00
_visiblePlanes . clear ( ) ;
2016-01-18 00:12:47 -06:00
_showList . clear ( ) ;
}
2016-09-09 16:17:41 -05:00
bool GfxFrameout : : gameIsHiRes ( ) const {
// QFG4 is always low resolution
if ( g_sci - > getGameId ( ) = = GID_QFG4 ) {
return false ;
}
2017-05-05 23:24:20 -05:00
// PQ4 DOS floppy is low resolution only
if ( g_sci - > getGameId ( ) = = GID_PQ4 & & ! g_sci - > isCD ( ) ) {
return false ;
}
2016-09-09 16:17:41 -05:00
// GK1 DOS floppy is low resolution only, but GK1 Mac floppy is high
// resolution only
if ( g_sci - > getGameId ( ) = = GID_GK1 & &
! g_sci - > isCD ( ) & &
g_sci - > getPlatform ( ) ! = Common : : kPlatformMacintosh ) {
return false ;
}
// All other games are either high resolution by default, or have a
// user-defined toggle
return ConfMan . getBool ( " enable_high_resolution_graphics " ) ;
}
2016-01-18 00:12:47 -06:00
# pragma mark -
# pragma mark Screen items
2016-07-02 19:11:46 -05:00
void GfxFrameout : : addScreenItem ( ScreenItem & screenItem ) const {
Plane * plane = _planes . findByObject ( screenItem . _plane ) ;
if ( plane = = nullptr ) {
error ( " GfxFrameout::addScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x " , PRINT_REG ( screenItem . _plane ) , PRINT_REG ( screenItem . _object ) ) ;
}
plane - > _screenItemList . add ( & screenItem ) ;
}
void GfxFrameout : : updateScreenItem ( ScreenItem & screenItem ) const {
// TODO: In SCI3+ this will need to go through Plane
// Plane *plane = _planes.findByObject(screenItem._plane);
// if (plane == nullptr) {
// error("GfxFrameout::updateScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
// }
screenItem . update ( ) ;
}
void GfxFrameout : : deleteScreenItem ( ScreenItem & screenItem ) {
Plane * plane = _planes . findByObject ( screenItem . _plane ) ;
if ( plane = = nullptr ) {
error ( " GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x " , PRINT_REG ( screenItem . _plane ) , PRINT_REG ( screenItem . _object ) ) ;
}
if ( plane - > _screenItemList . findByObject ( screenItem . _object ) = = nullptr ) {
error ( " GfxFrameout::deleteScreenItem: Screen item %04x:%04x not found in plane %04x:%04x " , PRINT_REG ( screenItem . _object ) , PRINT_REG ( screenItem . _plane ) ) ;
}
deleteScreenItem ( screenItem , * plane ) ;
}
void GfxFrameout : : deleteScreenItem ( ScreenItem & screenItem , Plane & plane ) {
if ( screenItem . _created = = 0 ) {
screenItem . _created = 0 ;
screenItem . _updated = 0 ;
screenItem . _deleted = getScreenCount ( ) ;
2016-06-18 20:48:10 -05:00
} else {
2016-07-02 19:11:46 -05:00
plane . _screenItemList . erase ( & screenItem ) ;
plane . _screenItemList . pack ( ) ;
2016-06-18 20:48:10 -05:00
}
}
2016-07-02 19:11:46 -05:00
void GfxFrameout : : deleteScreenItem ( ScreenItem & screenItem , const reg_t planeObject ) {
2016-06-18 20:48:10 -05:00
Plane * plane = _planes . findByObject ( planeObject ) ;
2016-07-02 19:11:46 -05:00
if ( plane = = nullptr ) {
error ( " GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x " , PRINT_REG ( planeObject ) , PRINT_REG ( screenItem . _object ) ) ;
}
deleteScreenItem ( screenItem , * plane ) ;
2016-06-18 20:48:10 -05:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelAddScreenItem ( const reg_t object ) {
const reg_t planeObject = readSelector ( _segMan , object , SELECTOR ( plane ) ) ;
_segMan - > getObject ( object ) - > setInfoSelectorFlag ( kInfoFlagViewInserted ) ;
Plane * plane = _planes . findByObject ( planeObject ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kAddScreenItem: Plane %04x:%04x not found for screen item %04x:%04x " , PRINT_REG ( planeObject ) , PRINT_REG ( object ) ) ;
2016-01-18 00:12:47 -06:00
}
ScreenItem * screenItem = plane - > _screenItemList . findByObject ( object ) ;
if ( screenItem ! = nullptr ) {
screenItem - > update ( object ) ;
2012-06-07 11:26:32 +03:00
} else {
2016-01-18 00:12:47 -06:00
screenItem = new ScreenItem ( object ) ;
plane - > _screenItemList . add ( screenItem ) ;
2012-06-07 11:26:32 +03:00
}
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelUpdateScreenItem ( const reg_t object ) {
const reg_t magnifierObject = readSelector ( _segMan , object , SELECTOR ( magnifier ) ) ;
if ( magnifierObject . isNull ( ) ) {
const reg_t planeObject = readSelector ( _segMan , object , SELECTOR ( plane ) ) ;
Plane * plane = _planes . findByObject ( planeObject ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kUpdateScreenItem: Plane %04x:%04x not found for screen item %04x:%04x " , PRINT_REG ( planeObject ) , PRINT_REG ( object ) ) ;
2016-01-18 00:12:47 -06:00
}
2012-06-07 11:26:32 +03:00
2016-01-18 00:12:47 -06:00
ScreenItem * screenItem = plane - > _screenItemList . findByObject ( object ) ;
if ( screenItem = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kUpdateScreenItem: Screen item %04x:%04x not found in plane %04x:%04x " , PRINT_REG ( object ) , PRINT_REG ( planeObject ) ) ;
2016-01-18 00:12:47 -06:00
}
2010-09-19 14:50:28 +00:00
2016-01-18 00:12:47 -06:00
screenItem - > update ( object ) ;
} else {
2016-03-07 17:27:38 -06:00
error ( " Magnifier view is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks! " ) ;
2016-01-18 00:12:47 -06:00
}
}
2010-09-19 14:50:28 +00:00
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelDeleteScreenItem ( const reg_t object ) {
_segMan - > getObject ( object ) - > clearInfoSelectorFlag ( kInfoFlagViewInserted ) ;
2012-09-26 04:17:31 +02:00
2016-01-18 00:12:47 -06:00
const reg_t planeObject = readSelector ( _segMan , object , SELECTOR ( plane ) ) ;
Plane * plane = _planes . findByObject ( planeObject ) ;
if ( plane = = nullptr ) {
return ;
}
2011-10-14 13:51:59 +03:00
2016-01-18 00:12:47 -06:00
ScreenItem * screenItem = plane - > _screenItemList . findByObject ( object ) ;
if ( screenItem = = nullptr ) {
return ;
}
2010-09-19 14:50:28 +00:00
2016-07-02 19:11:46 -05:00
deleteScreenItem ( * screenItem , * plane ) ;
2016-01-18 00:12:47 -06:00
}
2010-09-19 14:50:28 +00:00
2016-01-18 00:12:47 -06:00
# pragma mark -
# pragma mark Planes
2010-10-23 19:23:07 +00:00
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelAddPlane ( const reg_t object ) {
Plane * plane = _planes . findByObject ( object ) ;
if ( plane ! = nullptr ) {
plane - > update ( object ) ;
updatePlane ( * plane ) ;
} else {
plane = new Plane ( object ) ;
2017-09-18 22:13:44 -05:00
addPlane ( plane ) ;
2016-01-18 00:12:47 -06:00
}
}
2010-10-23 19:23:07 +00:00
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelUpdatePlane ( const reg_t object ) {
Plane * plane = _planes . findByObject ( object ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kUpdatePlane: Plane %04x:%04x not found " , PRINT_REG ( object ) ) ;
2010-07-24 16:47:12 +00:00
}
2016-01-18 00:12:47 -06:00
plane - > update ( object ) ;
updatePlane ( * plane ) ;
2010-02-02 16:25:35 +00:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelDeletePlane ( const reg_t object ) {
Plane * plane = _planes . findByObject ( object ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kDeletePlane: Plane %04x:%04x not found " , PRINT_REG ( object ) ) ;
2016-01-18 00:12:47 -06:00
}
2012-01-14 14:22:23 +02:00
2016-01-18 00:12:47 -06:00
if ( plane - > _created ) {
// NOTE: The original engine calls some `AbortPlane` function that
// just ends up doing this anyway so we skip the extra indirection
_planes . erase ( plane ) ;
} else {
plane - > _created = 0 ;
plane - > _deleted = g_sci - > _gfxFrameout - > getScreenCount ( ) ;
}
}
2010-07-25 19:56:44 +00:00
2016-03-05 23:56:38 -06:00
void GfxFrameout : : deletePlane ( Plane & planeToFind ) {
Plane * plane = _planes . findByObject ( planeToFind . _object ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " deletePlane: Plane %04x:%04x not found " , PRINT_REG ( planeToFind . _object ) ) ;
2016-03-05 23:56:38 -06:00
}
if ( plane - > _created ) {
_planes . erase ( plane ) ;
} else {
plane - > _created = 0 ;
plane - > _moved = 0 ;
plane - > _deleted = getScreenCount ( ) ;
}
}
2016-03-10 15:48:48 -06:00
void GfxFrameout : : kernelMovePlaneItems ( const reg_t object , const int16 deltaX , const int16 deltaY , const bool scrollPics ) {
Plane * plane = _planes . findByObject ( object ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kMovePlaneItems: Plane %04x:%04x not found " , PRINT_REG ( object ) ) ;
2016-03-10 15:48:48 -06:00
}
plane - > scrollScreenItems ( deltaX , deltaY , scrollPics ) ;
for ( ScreenItemList : : iterator it = plane - > _screenItemList . begin ( ) ; it ! = plane - > _screenItemList . end ( ) ; + + it ) {
ScreenItem & screenItem = * * it ;
// If object is a number, the screen item from the
// engine, not a script, and should be ignored
if ( screenItem . _object . isNumber ( ) ) {
continue ;
}
if ( deltaX ! = 0 ) {
writeSelectorValue ( _segMan , screenItem . _object , SELECTOR ( x ) , readSelectorValue ( _segMan , screenItem . _object , SELECTOR ( x ) ) + deltaX ) ;
}
if ( deltaY ! = 0 ) {
writeSelectorValue ( _segMan , screenItem . _object , SELECTOR ( y ) , readSelectorValue ( _segMan , screenItem . _object , SELECTOR ( y ) ) + deltaY ) ;
}
}
}
2016-01-18 00:12:47 -06:00
int16 GfxFrameout : : kernelGetHighPlanePri ( ) {
return _planes . getTopSciPlanePriority ( ) ;
}
2012-06-22 09:31:51 +03:00
2017-09-18 22:13:44 -05:00
void GfxFrameout : : addPlane ( Plane * plane ) {
// In SSCI, if a plane with the same object ID already existed, this call
// would cancel deletion and update an already-existing plane, but callers
// expect the passed plane object to become memory-managed by GfxFrameout,
// so doing what SSCI did would end up leaking the Plane objects
if ( _planes . findByObject ( plane - > _object ) ! = nullptr ) {
error ( " Plane %04x:%04x already exists " , PRINT_REG ( plane - > _object ) ) ;
2010-02-02 16:25:35 +00:00
}
2017-09-18 22:13:44 -05:00
plane - > clipScreenRect ( _screenRect ) ;
_planes . add ( plane ) ;
2010-02-02 16:25:35 +00:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : updatePlane ( Plane & plane ) {
// NOTE: This assertion comes from SCI engine code.
assert ( _planes . findByObject ( plane . _object ) = = & plane ) ;
2012-06-09 12:12:44 +03:00
2016-01-18 00:12:47 -06:00
Plane * visiblePlane = _visiblePlanes . findByObject ( plane . _object ) ;
plane . sync ( visiblePlane , _screenRect ) ;
// NOTE: updateScreenRect was originally called a second time here,
// but it is already called at the end of the Plane::Update call
// in the original engine anyway.
_planes . sort ( ) ;
2010-07-26 14:41:19 +00:00
}
2016-01-18 00:12:47 -06:00
# pragma mark -
# pragma mark Pics
2012-01-15 18:35:33 +02:00
2016-07-25 13:40:51 -05:00
void GfxFrameout : : kernelAddPicAt ( const reg_t planeObject , const GuiResourceId pictureId , const int16 x , const int16 y , const bool mirrorX , const bool deleteDuplicate ) {
2016-01-18 00:12:47 -06:00
Plane * plane = _planes . findByObject ( planeObject ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kAddPicAt: Plane %04x:%04x not found " , PRINT_REG ( planeObject ) ) ;
2010-07-26 14:41:19 +00:00
}
2016-07-25 13:40:51 -05:00
plane - > addPic ( pictureId , Common : : Point ( x , y ) , mirrorX , deleteDuplicate ) ;
2010-07-26 14:41:19 +00:00
}
2016-01-18 00:12:47 -06:00
# pragma mark -
# pragma mark Rendering
2016-06-30 13:24:46 -05:00
void GfxFrameout : : frameOut ( const bool shouldShowBits , const Common : : Rect & eraseRect ) {
2017-07-03 15:26:24 -05:00
updateMousePositionForRendering ( ) ;
2017-01-09 22:57:41 -06:00
2016-07-03 17:57:58 -05:00
RobotDecoder & robotPlayer = g_sci - > _video32 - > getRobotPlayer ( ) ;
const bool robotIsActive = robotPlayer . getStatus ( ) ! = RobotDecoder : : kRobotStatusUninitialized ;
if ( robotIsActive ) {
robotPlayer . doRobot ( ) ;
}
2016-01-18 00:12:47 -06:00
// NOTE: The original engine allocated these as static arrays of 100
// pointers to ScreenItemList / RectList
ScreenItemListList screenItemLists ;
EraseListList eraseLists ;
screenItemLists . resize ( _planes . size ( ) ) ;
eraseLists . resize ( _planes . size ( ) ) ;
2016-03-11 07:54:45 +02:00
if ( g_sci - > _gfxRemap32 - > getRemapCount ( ) > 0 & & _remapOccurred ) {
2016-03-15 21:05:01 +02:00
remapMarkRedraw ( ) ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:24:46 -05:00
calcLists ( screenItemLists , eraseLists , eraseRect ) ;
2016-01-18 00:12:47 -06:00
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
list - > sort ( ) ;
}
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
for ( DrawList : : iterator drawItem = list - > begin ( ) ; drawItem ! = list - > end ( ) ; + + drawItem ) {
( * drawItem ) - > screenItem - > getCelObj ( ) . submitPalette ( ) ;
2012-06-09 15:36:36 +03:00
}
}
2016-01-18 00:12:47 -06:00
_remapOccurred = _palette - > updateForFrame ( ) ;
for ( PlaneList : : size_type i = 0 ; i < _planes . size ( ) ; + + i ) {
drawEraseList ( eraseLists [ i ] , * _planes [ i ] ) ;
drawScreenItemList ( screenItemLists [ i ] ) ;
}
2016-07-03 17:57:58 -05:00
if ( robotIsActive ) {
robotPlayer . frameAlmostVisible ( ) ;
}
2016-01-18 00:12:47 -06:00
2017-05-06 00:00:04 -05:00
_palette - > updateHardware ( ) ;
2016-01-18 00:12:47 -06:00
if ( shouldShowBits ) {
showBits ( ) ;
}
2016-07-03 17:57:58 -05:00
if ( robotIsActive ) {
robotPlayer . frameNowVisible ( ) ;
}
2012-06-09 15:36:36 +03:00
}
2016-07-25 11:06:27 -05:00
void GfxFrameout : : palMorphFrameOut ( const int8 * styleRanges , PlaneShowStyle * showStyle ) {
2017-07-03 15:26:24 -05:00
updateMousePositionForRendering ( ) ;
2016-07-25 11:06:27 -05:00
Palette sourcePalette ( _palette - > getNextPalette ( ) ) ;
alterVmap ( sourcePalette , sourcePalette , - 1 , styleRanges ) ;
2016-09-26 19:28:51 -05:00
int16 prevRoom = g_sci - > getEngineState ( ) - > variables [ VAR_GLOBAL ] [ kGlobalVarPreviousRoomNo ] . toSint16 ( ) ;
2016-07-25 11:06:27 -05:00
2016-07-28 14:49:13 -05:00
Common : : Rect rect ( _currentBuffer . screenWidth , _currentBuffer . screenHeight ) ;
2016-07-25 11:06:27 -05:00
_showList . add ( rect ) ;
showBits ( ) ;
// NOTE: The original engine allocated these as static arrays of 100
// pointers to ScreenItemList / RectList
ScreenItemListList screenItemLists ;
EraseListList eraseLists ;
screenItemLists . resize ( _planes . size ( ) ) ;
eraseLists . resize ( _planes . size ( ) ) ;
if ( g_sci - > _gfxRemap32 - > getRemapCount ( ) > 0 & & _remapOccurred ) {
remapMarkRedraw ( ) ;
}
calcLists ( screenItemLists , eraseLists ) ;
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
list - > sort ( ) ;
}
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
for ( DrawList : : iterator drawItem = list - > begin ( ) ; drawItem ! = list - > end ( ) ; + + drawItem ) {
( * drawItem ) - > screenItem - > getCelObj ( ) . submitPalette ( ) ;
}
}
_remapOccurred = _palette - > updateForFrame ( ) ;
for ( PlaneList : : size_type i = 0 ; i < _planes . size ( ) ; + + i ) {
drawEraseList ( eraseLists [ i ] , * _planes [ i ] ) ;
drawScreenItemList ( screenItemLists [ i ] ) ;
}
Palette nextPalette ( _palette - > getNextPalette ( ) ) ;
if ( prevRoom < 1000 ) {
for ( int i = 0 ; i < ARRAYSIZE ( sourcePalette . colors ) ; + + i ) {
if ( styleRanges [ i ] = = - 1 | | styleRanges [ i ] = = 0 ) {
sourcePalette . colors [ i ] = nextPalette . colors [ i ] ;
sourcePalette . colors [ i ] . used = true ;
}
}
} else {
for ( int i = 0 ; i < ARRAYSIZE ( sourcePalette . colors ) ; + + i ) {
if ( styleRanges [ i ] = = - 1 | | validZeroStyle ( styleRanges [ i ] , i ) ) {
sourcePalette . colors [ i ] = nextPalette . colors [ i ] ;
sourcePalette . colors [ i ] . used = true ;
}
}
}
_palette - > submit ( sourcePalette ) ;
_palette - > updateFFrame ( ) ;
_palette - > updateHardware ( ) ;
alterVmap ( nextPalette , sourcePalette , 1 , _transitions - > _styleRanges ) ;
if ( showStyle & & showStyle - > type ! = kShowStyleMorph ) {
_transitions - > processEffects ( * showStyle ) ;
} else {
showBits ( ) ;
}
for ( PlaneList : : iterator plane = _planes . begin ( ) ; plane ! = _planes . end ( ) ; + + plane ) {
( * plane ) - > _redrawAllCount = getScreenCount ( ) ;
}
if ( g_sci - > _gfxRemap32 - > getRemapCount ( ) > 0 & & _remapOccurred ) {
remapMarkRedraw ( ) ;
}
calcLists ( screenItemLists , eraseLists ) ;
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
list - > sort ( ) ;
}
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
for ( DrawList : : iterator drawItem = list - > begin ( ) ; drawItem ! = list - > end ( ) ; + + drawItem ) {
( * drawItem ) - > screenItem - > getCelObj ( ) . submitPalette ( ) ;
}
}
_remapOccurred = _palette - > updateForFrame ( ) ;
for ( PlaneList : : size_type i = 0 ; i < _planes . size ( ) ; + + i ) {
drawEraseList ( eraseLists [ i ] , * _planes [ i ] ) ;
drawScreenItemList ( screenItemLists [ i ] ) ;
}
_palette - > submit ( nextPalette ) ;
_palette - > updateFFrame ( ) ;
2017-05-06 00:00:04 -05:00
_palette - > updateHardware ( ) ;
2016-07-25 11:06:27 -05:00
showBits ( ) ;
}
2017-07-03 20:12:39 -05:00
void GfxFrameout : : directFrameOut ( const Common : : Rect & showRect ) {
updateMousePositionForRendering ( ) ;
_showList . add ( showRect ) ;
showBits ( ) ;
}
2016-01-18 00:12:47 -06:00
2017-07-03 20:12:39 -05:00
# ifdef USE_RGB_COLOR
void GfxFrameout : : resetHardware ( ) {
updateMousePositionForRendering ( ) ;
_showList . add ( Common : : Rect ( getCurrentBuffer ( ) . screenWidth , getCurrentBuffer ( ) . screenHeight ) ) ;
g_system - > getPaletteManager ( ) - > setPalette ( _palette - > getHardwarePalette ( ) , 0 , 256 ) ;
showBits ( ) ;
2016-01-18 00:12:47 -06:00
}
2017-07-03 20:12:39 -05:00
# endif
2016-01-18 00:12:47 -06:00
2016-06-30 13:50:10 -05:00
/**
* Determines the parts of ` middleRect ` that aren ' t overlapped
* by ` showRect ` , optimised for contiguous memory writes .
* Returns - 1 if ` middleRect ` and ` showRect ` have no intersection .
* Returns number of returned parts ( in ` outRects ` ) otherwise .
* ( In particular , this returns 0 if ` middleRect ` is contained
* in ` other ` . )
*
* ` middleRect ` is modified directly to extend into the upper
* and lower rects .
*/
int splitRectsForRender ( Common : : Rect & middleRect , const Common : : Rect & showRect , Common : : Rect ( & outRects ) [ 2 ] ) {
if ( ! middleRect . intersects ( showRect ) ) {
return - 1 ;
}
const int16 minLeft = MIN ( middleRect . left , showRect . left ) ;
const int16 maxRight = MAX ( middleRect . right , showRect . right ) ;
int16 upperLeft , upperTop , upperRight , upperMaxTop ;
if ( middleRect . top < showRect . top ) {
upperLeft = middleRect . left ;
upperTop = middleRect . top ;
upperRight = middleRect . right ;
upperMaxTop = showRect . top ;
}
else {
upperLeft = showRect . left ;
upperTop = showRect . top ;
upperRight = showRect . right ;
upperMaxTop = middleRect . top ;
}
int16 lowerLeft , lowerRight , lowerBottom , lowerMinBottom ;
if ( middleRect . bottom > showRect . bottom ) {
lowerLeft = middleRect . left ;
lowerRight = middleRect . right ;
lowerBottom = middleRect . bottom ;
lowerMinBottom = showRect . bottom ;
} else {
lowerLeft = showRect . left ;
lowerRight = showRect . right ;
lowerBottom = showRect . bottom ;
lowerMinBottom = middleRect . bottom ;
}
int splitCount = 0 ;
middleRect . left = minLeft ;
middleRect . top = upperMaxTop ;
middleRect . right = maxRight ;
middleRect . bottom = lowerMinBottom ;
if ( upperTop ! = upperMaxTop ) {
Common : : Rect & upperRect = outRects [ 0 ] ;
upperRect . left = upperLeft ;
upperRect . top = upperTop ;
upperRect . right = upperRight ;
upperRect . bottom = upperMaxTop ;
// Merge upper rect into middle rect if possible
if ( upperRect . left = = middleRect . left & & upperRect . right = = middleRect . right ) {
middleRect . top = upperRect . top ;
} else {
+ + splitCount ;
}
}
if ( lowerBottom ! = lowerMinBottom ) {
Common : : Rect & lowerRect = outRects [ splitCount ] ;
lowerRect . left = lowerLeft ;
lowerRect . top = lowerMinBottom ;
lowerRect . right = lowerRight ;
lowerRect . bottom = lowerBottom ;
// Merge lower rect into middle rect if possible
if ( lowerRect . left = = middleRect . left & & lowerRect . right = = middleRect . right ) {
middleRect . bottom = lowerRect . bottom ;
} else {
+ + splitCount ;
}
}
assert ( splitCount < = 2 ) ;
return splitCount ;
}
2016-01-18 00:12:47 -06:00
2016-06-30 13:24:46 -05:00
// NOTE: The third rectangle parameter is only ever given a non-empty rect
// by VMD code, via `frameOut`
void GfxFrameout : : calcLists ( ScreenItemListList & drawLists , EraseListList & eraseLists , const Common : : Rect & eraseRect ) {
2016-06-30 13:50:10 -05:00
RectList eraseList ;
Common : : Rect outRects [ 4 ] ;
2016-01-18 00:12:47 -06:00
int deletedPlaneCount = 0 ;
2016-06-30 13:50:10 -05:00
bool addedToEraseList = false ;
2016-01-18 00:12:47 -06:00
bool foundTransparentPlane = false ;
2016-06-30 13:24:46 -05:00
if ( ! eraseRect . isEmpty ( ) ) {
addedToEraseList = true ;
2016-06-30 13:50:10 -05:00
eraseList . add ( eraseRect ) ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:50:10 -05:00
PlaneList : : size_type planeCount = _planes . size ( ) ;
2016-07-01 15:54:52 -05:00
for ( PlaneList : : size_type outerPlaneIndex = 0 ; outerPlaneIndex < planeCount ; + + outerPlaneIndex ) {
2016-06-30 13:50:10 -05:00
const Plane * outerPlane = _planes [ outerPlaneIndex ] ;
const Plane * visiblePlane = _visiblePlanes . findByObject ( outerPlane - > _object ) ;
2016-01-18 00:12:47 -06:00
2016-06-27 20:58:22 -05:00
// NOTE: SSCI only ever checks for kPlaneTypeTransparent here, even
// though kPlaneTypeTransparentPicture is also a transparent plane
2016-01-18 00:12:47 -06:00
if ( outerPlane - > _type = = kPlaneTypeTransparent ) {
foundTransparentPlane = true ;
}
2012-07-05 13:42:00 +03:00
2016-01-18 00:12:47 -06:00
if ( outerPlane - > _deleted ) {
2016-06-30 13:50:10 -05:00
if ( visiblePlane ! = nullptr & & ! visiblePlane - > _screenRect . isEmpty ( ) ) {
eraseList . add ( visiblePlane - > _screenRect ) ;
addedToEraseList = true ;
2016-01-18 00:12:47 -06:00
}
+ + deletedPlaneCount ;
2016-06-30 13:50:10 -05:00
} else if ( visiblePlane ! = nullptr & & outerPlane - > _moved ) {
// _moved will be decremented in the final loop through the planes,
// at the end of this function
{
const int splitCount = splitRects ( visiblePlane - > _screenRect , outerPlane - > _screenRect , outRects ) ;
if ( splitCount ) {
if ( splitCount = = - 1 & & ! visiblePlane - > _screenRect . isEmpty ( ) ) {
eraseList . add ( visiblePlane - > _screenRect ) ;
2016-01-18 00:12:47 -06:00
} else {
2016-06-30 13:50:10 -05:00
for ( int i = 0 ; i < splitCount ; + + i ) {
eraseList . add ( outRects [ i ] ) ;
2016-01-18 00:12:47 -06:00
}
}
2016-06-30 13:50:10 -05:00
addedToEraseList = true ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:50:10 -05:00
}
2016-01-18 00:12:47 -06:00
2016-06-30 13:50:10 -05:00
if ( ! outerPlane - > _redrawAllCount ) {
const int splitCount = splitRects ( outerPlane - > _screenRect , visiblePlane - > _screenRect , outRects ) ;
if ( splitCount ) {
for ( int i = 0 ; i < splitCount ; + + i ) {
eraseList . add ( outRects [ i ] ) ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:50:10 -05:00
addedToEraseList = true ;
2012-06-09 15:36:36 +03:00
}
}
}
2016-06-30 13:50:10 -05:00
if ( addedToEraseList ) {
2016-07-01 15:54:52 -05:00
for ( RectList : : size_type rectIndex = 0 ; rectIndex < eraseList . size ( ) ; + + rectIndex ) {
2016-06-30 13:50:10 -05:00
const Common : : Rect & rect = * eraseList [ rectIndex ] ;
for ( int innerPlaneIndex = planeCount - 1 ; innerPlaneIndex > = 0 ; - - innerPlaneIndex ) {
const Plane & innerPlane = * _planes [ innerPlaneIndex ] ;
if (
! innerPlane . _deleted & &
innerPlane . _type ! = kPlaneTypeTransparent & &
innerPlane . _screenRect . intersects ( rect )
) {
if ( ! innerPlane . _redrawAllCount ) {
eraseLists [ innerPlaneIndex ] . add ( innerPlane . _screenRect . findIntersectingRect ( rect ) ) ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:50:10 -05:00
const int splitCount = splitRects ( rect , innerPlane . _screenRect , outRects ) ;
2016-01-18 00:12:47 -06:00
for ( int i = 0 ; i < splitCount ; + + i ) {
2016-06-30 13:50:10 -05:00
eraseList . add ( outRects [ i ] ) ;
2016-01-18 00:12:47 -06:00
}
2012-07-05 13:42:00 +03:00
2016-06-30 13:50:10 -05:00
eraseList . erase_at ( rectIndex ) ;
2016-01-18 00:12:47 -06:00
break ;
}
2012-06-09 15:36:36 +03:00
}
}
2016-01-18 00:12:47 -06:00
2016-06-30 13:50:10 -05:00
eraseList . pack ( ) ;
2012-06-09 15:36:36 +03:00
}
}
2016-01-18 00:12:47 -06:00
// clean up deleted planes
if ( deletedPlaneCount ) {
for ( int planeIndex = planeCount - 1 ; planeIndex > = 0 ; - - planeIndex ) {
Plane * plane = _planes [ planeIndex ] ;
if ( plane - > _deleted ) {
- - plane - > _deleted ;
if ( plane - > _deleted < = 0 ) {
2016-06-30 13:50:10 -05:00
const int visiblePlaneIndex = _visiblePlanes . findIndexByObject ( plane - > _object ) ;
if ( visiblePlaneIndex ! = - 1 ) {
_visiblePlanes . remove_at ( visiblePlaneIndex ) ;
2016-01-18 00:12:47 -06:00
}
2013-01-11 00:45:10 +02:00
2016-01-18 00:12:47 -06:00
_planes . remove_at ( planeIndex ) ;
eraseLists . remove_at ( planeIndex ) ;
drawLists . remove_at ( planeIndex ) ;
}
2013-01-11 00:45:10 +02:00
2016-01-18 00:12:47 -06:00
if ( - - deletedPlaneCount < = 0 ) {
break ;
}
}
}
}
2013-01-11 00:45:10 +02:00
2016-06-30 13:50:10 -05:00
// Some planes may have been deleted, so re-retrieve count
2016-01-18 00:12:47 -06:00
planeCount = _planes . size ( ) ;
2016-06-30 13:50:10 -05:00
for ( PlaneList : : size_type outerIndex = 0 ; outerIndex < planeCount ; + + outerIndex ) {
2016-01-18 00:12:47 -06:00
// "outer" just refers to the outer loop
2016-06-30 13:50:10 -05:00
Plane & outerPlane = * _planes [ outerIndex ] ;
if ( outerPlane . _priorityChanged ) {
- - outerPlane . _priorityChanged ;
2016-01-18 00:12:47 -06:00
2016-06-30 13:50:10 -05:00
const Plane * visibleOuterPlane = _visiblePlanes . findByObject ( outerPlane . _object ) ;
2016-05-30 08:33:38 -05:00
if ( visibleOuterPlane = = nullptr ) {
2016-06-30 13:50:10 -05:00
warning ( " calcLists could not find visible plane for %04x:%04x " , PRINT_REG ( outerPlane . _object ) ) ;
2016-05-30 08:33:38 -05:00
continue ;
}
2016-01-18 00:12:47 -06:00
2016-06-30 13:50:10 -05:00
eraseList . add ( outerPlane . _screenRect . findIntersectingRect ( visibleOuterPlane - > _screenRect ) ) ;
2016-01-18 00:12:47 -06:00
2016-07-01 15:54:52 -05:00
for ( int innerIndex = ( int ) planeCount - 1 ; innerIndex > = 0 ; - - innerIndex ) {
2016-01-18 00:12:47 -06:00
// "inner" just refers to the inner loop
2016-06-30 13:50:10 -05:00
const Plane & innerPlane = * _planes [ innerIndex ] ;
const Plane * visibleInnerPlane = _visiblePlanes . findByObject ( innerPlane . _object ) ;
2016-01-18 00:12:47 -06:00
2016-06-30 13:50:10 -05:00
const RectList : : size_type rectCount = eraseList . size ( ) ;
for ( RectList : : size_type rectIndex = 0 ; rectIndex < rectCount ; + + rectIndex ) {
const int splitCount = splitRects ( * eraseList [ rectIndex ] , innerPlane . _screenRect , outRects ) ;
2016-01-18 00:12:47 -06:00
if ( splitCount = = 0 ) {
2016-05-30 08:33:38 -05:00
if ( visibleInnerPlane ! = nullptr ) {
2016-01-18 00:12:47 -06:00
// same priority, or relative priority between inner/outer changed
2016-06-30 13:50:10 -05:00
if ( ( visibleOuterPlane - > _priority - visibleInnerPlane - > _priority ) * ( outerPlane . _priority - innerPlane . _priority ) < = 0 ) {
if ( outerPlane . _priority < = innerPlane . _priority ) {
eraseLists [ innerIndex ] . add ( * eraseList [ rectIndex ] ) ;
2016-01-18 00:12:47 -06:00
} else {
2016-06-30 13:50:10 -05:00
eraseLists [ outerIndex ] . add ( * eraseList [ rectIndex ] ) ;
2016-01-18 00:12:47 -06:00
}
}
}
2016-06-30 13:50:10 -05:00
eraseList . erase_at ( rectIndex ) ;
2016-01-18 00:12:47 -06:00
} else if ( splitCount ! = - 1 ) {
for ( int i = 0 ; i < splitCount ; + + i ) {
2016-06-30 13:50:10 -05:00
eraseList . add ( outRects [ i ] ) ;
2016-01-18 00:12:47 -06:00
}
2016-05-30 08:33:38 -05:00
if ( visibleInnerPlane ! = nullptr ) {
2016-01-18 00:12:47 -06:00
// same priority, or relative priority between inner/outer changed
2016-06-30 13:50:10 -05:00
if ( ( visibleOuterPlane - > _priority - visibleInnerPlane - > _priority ) * ( outerPlane . _priority - innerPlane . _priority ) < = 0 ) {
* eraseList [ rectIndex ] = outerPlane . _screenRect . findIntersectingRect ( innerPlane . _screenRect ) ;
if ( outerPlane . _priority < = innerPlane . _priority ) {
eraseLists [ innerIndex ] . add ( * eraseList [ rectIndex ] ) ;
} else {
eraseLists [ outerIndex ] . add ( * eraseList [ rectIndex ] ) ;
2016-01-18 00:12:47 -06:00
}
}
}
2016-06-30 13:50:10 -05:00
eraseList . erase_at ( rectIndex ) ;
2016-01-18 00:12:47 -06:00
}
}
2016-06-30 13:50:10 -05:00
eraseList . pack ( ) ;
2016-01-18 00:12:47 -06:00
}
}
}
2013-01-11 00:45:10 +02:00
2016-06-30 13:50:10 -05:00
for ( PlaneList : : size_type planeIndex = 0 ; planeIndex < planeCount ; + + planeIndex ) {
Plane & plane = * _planes [ planeIndex ] ;
Plane * visiblePlane = _visiblePlanes . findByObject ( plane . _object ) ;
2013-01-11 00:45:10 +02:00
2016-06-30 13:50:10 -05:00
if ( ! plane . _screenRect . isEmpty ( ) ) {
if ( plane . _redrawAllCount ) {
plane . redrawAll ( visiblePlane , _planes , drawLists [ planeIndex ] , eraseLists [ planeIndex ] ) ;
} else {
if ( visiblePlane = = nullptr ) {
error ( " Missing visible plane for source plane %04x:%04x " , PRINT_REG ( plane . _object ) ) ;
}
2013-01-11 00:45:10 +02:00
2016-06-30 13:50:10 -05:00
plane . calcLists ( * visiblePlane , _planes , drawLists [ planeIndex ] , eraseLists [ planeIndex ] ) ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:50:10 -05:00
} else {
plane . decrementScreenItemArrayCounts ( visiblePlane , false ) ;
}
2013-01-11 00:45:10 +02:00
2016-06-30 13:50:10 -05:00
if ( plane . _moved ) {
// the work for handling moved/resized planes was already done
// earlier in the function, we are just cleaning up now
- - plane . _moved ;
2016-01-18 00:12:47 -06:00
}
2016-06-30 13:50:10 -05:00
if ( plane . _created ) {
_visiblePlanes . add ( new Plane ( plane ) ) ;
- - plane . _created ;
} else if ( plane . _updated ) {
2016-10-10 09:27:49 -05:00
if ( visiblePlane = = nullptr ) {
error ( " [GfxFrameout::calcLists]: Attempt to update nonexistent visible plane " ) ;
}
2016-06-30 13:50:10 -05:00
* visiblePlane = plane ;
- - plane . _updated ;
2016-01-18 00:12:47 -06:00
}
2012-07-04 02:17:27 +03:00
}
2010-10-23 19:23:07 +00:00
2016-06-27 20:58:22 -05:00
// NOTE: SSCI only looks for kPlaneTypeTransparent, not
// kPlaneTypeTransparentPicture
2016-01-18 00:12:47 -06:00
if ( foundTransparentPlane ) {
2016-06-30 13:50:10 -05:00
for ( PlaneList : : size_type planeIndex = 0 ; planeIndex < planeCount ; + + planeIndex ) {
for ( PlaneList : : size_type i = planeIndex + 1 ; i < planeCount ; + + i ) {
2016-01-18 00:12:47 -06:00
if ( _planes [ i ] - > _type = = kPlaneTypeTransparent ) {
_planes [ i ] - > filterUpEraseRects ( drawLists [ i ] , eraseLists [ planeIndex ] ) ;
}
}
if ( _planes [ planeIndex ] - > _type = = kPlaneTypeTransparent ) {
2016-07-01 15:54:52 -05:00
for ( int i = ( int ) planeIndex - 1 ; i > = 0 ; - - i ) {
2016-01-18 00:12:47 -06:00
_planes [ i ] - > filterDownEraseRects ( drawLists [ i ] , eraseLists [ i ] , eraseLists [ planeIndex ] ) ;
}
if ( eraseLists [ planeIndex ] . size ( ) > 0 ) {
error ( " Transparent plane's erase list not absorbed " ) ;
}
}
2010-10-23 19:23:07 +00:00
2016-06-30 13:50:10 -05:00
for ( PlaneList : : size_type i = planeIndex + 1 ; i < planeCount ; + + i ) {
2016-01-18 00:12:47 -06:00
if ( _planes [ i ] - > _type = = kPlaneTypeTransparent ) {
_planes [ i ] - > filterUpDrawRects ( drawLists [ i ] , drawLists [ planeIndex ] ) ;
}
}
}
}
2010-02-02 16:25:35 +00:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : drawEraseList ( const RectList & eraseList , const Plane & plane ) {
if ( plane . _type ! = kPlaneTypeColored ) {
2010-10-23 19:23:07 +00:00
return ;
2012-07-04 02:17:27 +03:00
}
2010-10-23 19:23:07 +00:00
2016-06-30 13:50:10 -05:00
const RectList : : size_type eraseListSize = eraseList . size ( ) ;
for ( RectList : : size_type i = 0 ; i < eraseListSize ; + + i ) {
mergeToShowList ( * eraseList [ i ] , _showList , _overdrawThreshold ) ;
_currentBuffer . fillRect ( * eraseList [ i ] , plane . _back ) ;
2016-01-18 00:12:47 -06:00
}
}
void GfxFrameout : : drawScreenItemList ( const DrawList & screenItemList ) {
2016-06-30 13:50:10 -05:00
const DrawList : : size_type drawListSize = screenItemList . size ( ) ;
for ( DrawList : : size_type i = 0 ; i < drawListSize ; + + i ) {
const DrawItem & drawItem = * screenItemList [ i ] ;
2016-01-18 00:12:47 -06:00
mergeToShowList ( drawItem . rect , _showList , _overdrawThreshold ) ;
2016-06-30 13:50:10 -05:00
const ScreenItem & screenItem = * drawItem . screenItem ;
2016-01-18 00:12:47 -06:00
// TODO: Remove
2016-03-05 23:56:38 -06:00
// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), PRINT_RECT(drawItem.rect));
2016-01-18 00:12:47 -06:00
CelObj & celObj = * screenItem . _celObj ;
celObj . draw ( _currentBuffer , screenItem , drawItem . rect , screenItem . _mirrorX ^ celObj . _mirrorX ) ;
}
}
2011-10-12 02:43:08 +03:00
2016-01-18 00:12:47 -06:00
void GfxFrameout : : mergeToShowList ( const Common : : Rect & drawRect , RectList & showList , const int overdrawThreshold ) {
2016-06-30 13:50:10 -05:00
RectList mergeList ;
Common : : Rect merged ;
mergeList . add ( drawRect ) ;
for ( RectList : : size_type i = 0 ; i < mergeList . size ( ) ; + + i ) {
bool didMerge = false ;
const Common : : Rect & r1 = * mergeList [ i ] ;
if ( ! r1 . isEmpty ( ) ) {
for ( RectList : : size_type j = 0 ; j < showList . size ( ) ; + + j ) {
const Common : : Rect & r2 = * showList [ j ] ;
if ( ! r2 . isEmpty ( ) ) {
merged = r1 ;
merged . extend ( r2 ) ;
int difference = merged . width ( ) * merged . height ( ) ;
difference - = r1 . width ( ) * r1 . height ( ) ;
difference - = r2 . width ( ) * r2 . height ( ) ;
if ( r1 . intersects ( r2 ) ) {
const Common : : Rect overlap = r1 . findIntersectingRect ( r2 ) ;
difference + = overlap . width ( ) * overlap . height ( ) ;
}
if ( difference < = overdrawThreshold ) {
mergeList . erase_at ( i ) ;
showList . erase_at ( j ) ;
mergeList . add ( merged ) ;
didMerge = true ;
break ;
} else {
Common : : Rect outRects [ 2 ] ;
int splitCount = splitRectsForRender ( * mergeList [ i ] , * showList [ j ] , outRects ) ;
if ( splitCount ! = - 1 ) {
mergeList . add ( * mergeList [ i ] ) ;
mergeList . erase_at ( i ) ;
showList . erase_at ( j ) ;
didMerge = true ;
while ( splitCount - - ) {
mergeList . add ( outRects [ splitCount ] ) ;
}
break ;
}
}
}
2016-01-18 00:12:47 -06:00
}
2013-01-13 17:28:09 +02:00
2016-06-30 13:50:10 -05:00
if ( didMerge ) {
showList . pack ( ) ;
}
}
2013-01-11 00:45:10 +02:00
}
2012-05-14 02:30:15 +03:00
2016-06-30 13:50:10 -05:00
mergeList . pack ( ) ;
for ( RectList : : size_type i = 0 ; i < mergeList . size ( ) ; + + i ) {
showList . add ( * mergeList [ i ] ) ;
}
2010-09-19 14:50:28 +00:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : showBits ( ) {
2016-07-31 13:41:05 -05:00
if ( ! _showList . size ( ) ) {
2017-05-22 18:40:52 -05:00
updateScreen ( ) ;
2016-07-31 13:41:05 -05:00
return ;
}
2016-01-18 00:12:47 -06:00
for ( RectList : : const_iterator rect = _showList . begin ( ) ; rect ! = _showList . end ( ) ; + + rect ) {
Common : : Rect rounded ( * * rect ) ;
// NOTE: SCI engine used BR-inclusive rects so used slightly
// different masking here to ensure that the width of rects
// was always even.
rounded . left & = ~ 1 ;
rounded . right = ( rounded . right + 1 ) & ~ 1 ;
2016-07-31 13:41:05 -05:00
_cursor - > gonnaPaint ( rounded ) ;
2010-06-20 17:17:46 +00:00
}
2016-07-31 13:41:05 -05:00
_cursor - > paintStarting ( ) ;
2016-01-18 00:12:47 -06:00
for ( RectList : : const_iterator rect = _showList . begin ( ) ; rect ! = _showList . end ( ) ; + + rect ) {
Common : : Rect rounded ( * * rect ) ;
// NOTE: SCI engine used BR-inclusive rects so used slightly
// different masking here to ensure that the width of rects
// was always even.
rounded . left & = ~ 1 ;
rounded . right = ( rounded . right + 1 ) & ~ 1 ;
byte * sourceBuffer = ( byte * ) _currentBuffer . getPixels ( ) + rounded . top * _currentBuffer . screenWidth + rounded . left ;
2017-01-12 12:41:27 -06:00
// Sometimes screen items (especially from SCI2.1early transitions, like
// in the asteroids minigame in PQ4) generate zero-dimension show
// rectangles. In SSCI, zero-dimension rectangles are OK (they just
// result in no copy), but OSystem::copyRectToScreen will assert on
// them, so we need to check for zero-dimensions rectangles and ignore
// them explicitly
2016-07-26 19:56:12 -05:00
if ( rounded . width ( ) = = 0 | | rounded . height ( ) = = 0 ) {
continue ;
}
2017-07-03 20:12:39 -05:00
# ifdef USE_RGB_COLOR
if ( g_system - > getScreenFormat ( ) ! = _currentBuffer . format ) {
// This happens (at least) when playing a video in Shivers with
// HQ video on & subtitles on
Graphics : : Surface * screenSurface = _currentBuffer . getSubArea ( rounded ) . convertTo ( g_system - > getScreenFormat ( ) , _palette - > getHardwarePalette ( ) ) ;
assert ( screenSurface ) ;
g_system - > copyRectToScreen ( screenSurface - > getPixels ( ) , screenSurface - > pitch , rounded . left , rounded . top , screenSurface - > w , screenSurface - > h ) ;
screenSurface - > free ( ) ;
delete screenSurface ;
} else {
# else
{
# endif
g_system - > copyRectToScreen ( sourceBuffer , _currentBuffer . screenWidth , rounded . left , rounded . top , rounded . width ( ) , rounded . height ( ) ) ;
}
2016-01-18 00:12:47 -06:00
}
2016-07-31 13:41:05 -05:00
_cursor - > donePainting ( ) ;
2016-01-18 00:12:47 -06:00
_showList . clear ( ) ;
2017-05-22 18:40:52 -05:00
updateScreen ( ) ;
2010-06-20 17:17:46 +00:00
}
2010-06-14 16:58:15 +00:00
2016-01-18 00:12:47 -06:00
void GfxFrameout : : alterVmap ( const Palette & palette1 , const Palette & palette2 , const int8 style , const int8 * const styleRanges ) {
uint8 clut [ 256 ] ;
for ( int paletteIndex = 0 ; paletteIndex < ARRAYSIZE ( palette1 . colors ) ; + + paletteIndex ) {
int outerR = palette1 . colors [ paletteIndex ] . r ;
int outerG = palette1 . colors [ paletteIndex ] . g ;
int outerB = palette1 . colors [ paletteIndex ] . b ;
if ( styleRanges [ paletteIndex ] = = style ) {
int minDiff = 262140 ;
2016-05-28 11:02:40 -05:00
int minDiffIndex = paletteIndex ;
2016-01-18 00:12:47 -06:00
for ( int i = 0 ; i < 236 ; + + i ) {
if ( styleRanges [ i ] ! = style ) {
int r = palette1 . colors [ i ] . r ;
int g = palette1 . colors [ i ] . g ;
int b = palette1 . colors [ i ] . b ;
int diffSquared = ( outerR - r ) * ( outerR - r ) + ( outerG - g ) * ( outerG - g ) + ( outerB - b ) * ( outerB - b ) ;
if ( diffSquared < minDiff ) {
minDiff = diffSquared ;
minDiffIndex = i ;
}
}
}
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
clut [ paletteIndex ] = minDiffIndex ;
}
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
if ( style = = 1 & & styleRanges [ paletteIndex ] = = 0 ) {
int minDiff = 262140 ;
2016-05-28 11:02:40 -05:00
int minDiffIndex = paletteIndex ;
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
for ( int i = 0 ; i < 236 ; + + i ) {
int r = palette2 . colors [ i ] . r ;
int g = palette2 . colors [ i ] . g ;
int b = palette2 . colors [ i ] . b ;
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
int diffSquared = ( outerR - r ) * ( outerR - r ) + ( outerG - g ) * ( outerG - g ) + ( outerB - b ) * ( outerB - b ) ;
if ( diffSquared < minDiff ) {
minDiff = diffSquared ;
minDiffIndex = i ;
}
2011-02-07 12:24:09 +00:00
}
2016-01-18 00:12:47 -06:00
clut [ paletteIndex ] = minDiffIndex ;
2011-11-17 22:08:36 +02:00
}
2016-01-18 00:12:47 -06:00
}
2011-02-07 12:24:09 +00:00
2016-01-18 00:12:47 -06:00
byte * pixels = ( byte * ) _currentBuffer . getPixels ( ) ;
for ( int pixelIndex = 0 , numPixels = _currentBuffer . screenWidth * _currentBuffer . screenHeight ; pixelIndex < numPixels ; + + pixelIndex ) {
byte currentValue = pixels [ pixelIndex ] ;
int8 styleRangeValue = styleRanges [ currentValue ] ;
if ( styleRangeValue = = - 1 & & styleRangeValue = = style ) {
currentValue = pixels [ pixelIndex ] = clut [ currentValue ] ;
2016-03-18 09:10:10 -05:00
// NOTE: In original engine this assignment happens outside of the
// condition, but if the branch is not followed the value is just
// going to be the same as it was before
styleRangeValue = styleRanges [ currentValue ] ;
2011-11-17 22:08:36 +02:00
}
2016-01-18 00:12:47 -06:00
if (
( styleRangeValue = = 1 & & styleRangeValue = = style ) | |
( styleRangeValue = = 0 & & style = = 1 )
) {
pixels [ pixelIndex ] = clut [ currentValue ] ;
}
2011-11-17 22:08:36 +02:00
}
}
2017-05-22 18:40:52 -05:00
void GfxFrameout : : updateScreen ( const int delta ) {
// using OSystem::getMillis instead of Sci::getTickCount because these
// values need to be monotonically increasing for the duration of the
// GfxFrameout object or else the screen will stop updating
const uint32 now = g_system - > getMillis ( ) * 60 / 1000 ;
if ( now < = _lastScreenUpdateTick + delta ) {
return ;
}
_lastScreenUpdateTick = now ;
g_system - > updateScreen ( ) ;
g_sci - > getSciDebugger ( ) - > onFrame ( ) ;
}
2016-03-02 14:02:15 -06:00
void GfxFrameout : : kernelFrameOut ( const bool shouldShowBits ) {
2016-07-25 11:06:27 -05:00
if ( _transitions - > hasShowStyles ( ) ) {
_transitions - > processShowStyles ( ) ;
2016-01-18 00:12:47 -06:00
} else if ( _palMorphIsOn ) {
2016-07-25 11:06:27 -05:00
palMorphFrameOut ( _transitions - > _styleRanges , nullptr ) ;
2016-01-18 00:12:47 -06:00
_palMorphIsOn = false ;
} else {
2016-07-25 11:06:27 -05:00
if ( _transitions - > hasScrolls ( ) ) {
_transitions - > processScrolls ( ) ;
}
2012-05-21 01:29:30 +03:00
2016-03-02 14:02:15 -06:00
frameOut ( shouldShowBits ) ;
2016-01-18 00:12:47 -06:00
}
2016-06-14 17:43:57 -05:00
2017-07-22 23:26:39 -05:00
if ( _throttleKernelFrameOut ) {
throttle ( ) ;
}
2016-07-02 19:11:59 -05:00
}
void GfxFrameout : : throttle ( ) {
2017-05-04 22:42:32 -05:00
uint8 throttleTime ;
if ( _throttleState = = 2 ) {
throttleTime = 16 ;
_throttleState = 0 ;
} else {
throttleTime = 17 ;
+ + _throttleState ;
2016-06-14 17:43:57 -05:00
}
2017-05-04 22:42:32 -05:00
g_sci - > getEngineState ( ) - > speedThrottler ( throttleTime ) ;
g_sci - > getEngineState ( ) - > _throttleTrigger = true ;
2016-01-18 00:12:47 -06:00
}
2012-05-21 01:29:30 +03:00
2016-08-02 09:49:04 -05:00
void GfxFrameout : : shakeScreen ( int16 numShakes , const ShakeDirection direction ) {
if ( direction & kShakeHorizontal ) {
// Used by QFG4 room 750
warning ( " TODO: Horizontal shake not implemented " ) ;
return ;
}
while ( numShakes - - ) {
2017-09-03 13:42:27 -05:00
if ( g_engine - > shouldQuit ( ) ) {
break ;
}
2016-08-02 09:49:04 -05:00
if ( direction & kShakeVertical ) {
g_system - > setShakePos ( _isHiRes ? 8 : 4 ) ;
}
2017-05-22 18:40:52 -05:00
updateScreen ( ) ;
2016-08-02 09:49:04 -05:00
g_sci - > getEngineState ( ) - > wait ( 3 ) ;
if ( direction & kShakeVertical ) {
g_system - > setShakePos ( 0 ) ;
}
2017-05-22 18:40:52 -05:00
updateScreen ( ) ;
2016-08-02 09:49:04 -05:00
g_sci - > getEngineState ( ) - > wait ( 3 ) ;
}
}
2016-03-08 10:27:15 -06:00
# pragma mark -
# pragma mark Mouse cursor
2016-02-20 05:38:22 +01:00
2016-03-08 10:27:15 -06:00
reg_t GfxFrameout : : kernelIsOnMe ( const reg_t object , const Common : : Point & position , bool checkPixel ) const {
2016-03-18 13:08:37 -05:00
const reg_t planeObject = readSelector ( _segMan , object , SELECTOR ( plane ) ) ;
2016-03-08 10:27:15 -06:00
Plane * plane = _visiblePlanes . findByObject ( planeObject ) ;
if ( plane = = nullptr ) {
return make_reg ( 0 , 0 ) ;
2016-02-20 05:38:22 +01:00
}
2016-03-08 10:27:15 -06:00
ScreenItem * screenItem = plane - > _screenItemList . findByObject ( object ) ;
if ( screenItem = = nullptr ) {
return make_reg ( 0 , 0 ) ;
2016-02-20 05:38:22 +01:00
}
2016-03-18 13:08:37 -05:00
// NOTE: The original engine passed a copy of the ScreenItem into isOnMe
// as a hack around the fact that the screen items in `_visiblePlanes`
// did not have their `_celObj` pointers cleared when their CelInfo was
// updated by `Plane::decrementScreenItemArrayCounts`. We handle this
// this more intelligently by clearing `_celObj` in the copy assignment
// operator, which is only ever called by `decrementScreenItemArrayCounts`
// anyway.
2016-03-08 10:27:15 -06:00
return make_reg ( 0 , isOnMe ( * screenItem , * plane , position , checkPixel ) ) ;
2016-02-20 15:46:12 +01:00
}
2016-03-08 10:27:15 -06:00
bool GfxFrameout : : isOnMe ( const ScreenItem & screenItem , const Plane & plane , const Common : : Point & position , const bool checkPixel ) const {
2016-02-20 05:38:22 +01:00
2016-03-08 10:27:15 -06:00
Common : : Point scaledPosition ( position ) ;
mulru ( scaledPosition , Ratio ( _currentBuffer . screenWidth , _currentBuffer . scriptWidth ) , Ratio ( _currentBuffer . screenHeight , _currentBuffer . scriptHeight ) ) ;
scaledPosition . x + = plane . _planeRect . left ;
scaledPosition . y + = plane . _planeRect . top ;
2016-02-20 05:38:22 +01:00
2016-03-08 10:27:15 -06:00
if ( ! screenItem . _screenRect . contains ( scaledPosition ) ) {
return false ;
2016-02-20 05:38:22 +01:00
}
2016-03-08 10:27:15 -06:00
if ( checkPixel ) {
CelObj & celObj = screenItem . getCelObj ( ) ;
2016-02-20 05:38:22 +01:00
2016-03-08 10:27:15 -06:00
bool mirrorX = screenItem . _mirrorX ^ celObj . _mirrorX ;
2016-02-20 05:38:22 +01:00
2016-03-08 10:27:15 -06:00
scaledPosition . x - = screenItem . _scaledPosition . x ;
scaledPosition . y - = screenItem . _scaledPosition . y ;
2016-02-20 05:38:22 +01:00
2017-09-30 00:03:05 -05:00
if ( getSciVersion ( ) < SCI_VERSION_2_1_LATE ) {
SCI32: Fix bad text rendering in RAMA
In SCI3, Sierra removed the ability of the main renderer to
automatically scale CelObjs with different source resolutions.
Instead, in SCI3, all CelObjs are treated as having the same
resolution as the screen (i.e. 640x480).
In all SCI3 games other than RAMA, keeping the code paths for
resolution-dependent scaling is not a problem because all the
assets and game code are correctly designed to use the same
640x480 resolution throughout. RAMA, on the other hand, was
written with the text subsystem set to a resolution of 630x450
(Phant1's screen resolution), and in SSCI, resolution-dependent
scaling code was not removed from the *text* subsystem. As a
result, RAMA's game scripts rely on the slightly larger scaled
dimensions coming out of the text system when determining the size
of screen items for rendering, and then also rely on the main
renderer ignoring the 630x450 resolution baked into the bitmaps
generated by the text subsystem when drawing them to the screen.
2017-09-29 14:57:22 -05:00
mulru ( scaledPosition , Ratio ( celObj . _xResolution , _currentBuffer . screenWidth ) , Ratio ( celObj . _yResolution , _currentBuffer . screenHeight ) ) ;
}
2016-02-20 05:38:22 +01:00
2016-03-08 10:27:15 -06:00
if ( screenItem . _scale . signal ! = kScaleSignalNone & & screenItem . _scale . x & & screenItem . _scale . y ) {
scaledPosition . x = scaledPosition . x * 128 / screenItem . _scale . x ;
scaledPosition . y = scaledPosition . y * 128 / screenItem . _scale . y ;
2016-02-20 05:38:22 +01:00
}
2017-06-17 14:17:16 -05:00
// TODO/HACK: When clicking at the very bottom edge of a scaled cel, it
// is possible that the calculated `scaledPosition` ends up one pixel
// outside of the bounds of the cel. It is not known yet whether this is
// a bug that also existed in SSCI (and so garbage memory would be read
// there), or if there is actually an error in our scaling of
// `ScreenItem::_screenRect` and/or `scaledPosition`. For now, just do
// an extra bounds check and return so games don't crash when a user
// clicks an unlucky point. Later, double-check the disassembly and
// either confirm this is a suitable fix (because SSCI just read bad
// memory) or fix the actual broken thing and remove this workaround.
if ( scaledPosition . x < 0 | |
scaledPosition . y < 0 | |
scaledPosition . x > = celObj . _width | |
scaledPosition . y > = celObj . _height ) {
return false ;
}
2016-03-08 10:27:15 -06:00
uint8 pixel = celObj . readPixel ( scaledPosition . x , scaledPosition . y , mirrorX ) ;
2016-10-09 10:52:08 -05:00
return pixel ! = celObj . _skipColor ;
2016-02-20 05:38:22 +01:00
}
2016-03-08 10:27:15 -06:00
return true ;
2016-02-20 05:38:22 +01:00
}
2017-07-09 17:25:17 +02:00
bool GfxFrameout : : getNowSeenRect ( const reg_t screenItemObject , Common : : Rect & result ) const {
2016-03-10 14:05:27 -06:00
const reg_t planeObject = readSelector ( _segMan , screenItemObject , SELECTOR ( plane ) ) ;
2017-07-09 17:25:17 +02:00
const Plane * plane = _planes . findByObject ( planeObject ) ;
2016-03-10 14:05:27 -06:00
if ( plane = = nullptr ) {
2017-07-09 17:25:17 +02:00
error ( " getNowSeenRect: Plane %04x:%04x not found for screen item %04x:%04x " , PRINT_REG ( planeObject ) , PRINT_REG ( screenItemObject ) ) ;
2016-03-10 14:05:27 -06:00
}
2017-07-09 17:25:17 +02:00
const ScreenItem * screenItem = plane - > _screenItemList . findByObject ( screenItemObject ) ;
2016-03-10 14:05:27 -06:00
if ( screenItem = = nullptr ) {
2017-07-09 17:25:17 +02:00
// NOTE: MGDX is assumed to use the older getNowSeenRect since it was
// released before SQ6, but this has not been verified since it cannot
// be disassembled at the moment (Phar Lap Windows-only release)
// (See also kSetNowSeen32)
if ( getSciVersion ( ) < = SCI_VERSION_2_1_EARLY | |
g_sci - > getGameId ( ) = = GID_SQ6 | |
g_sci - > getGameId ( ) = = GID_MOTHERGOOSEHIRES ) {
error ( " getNowSeenRect: Unable to find screen item %04x:%04x " , PRINT_REG ( screenItemObject ) ) ;
}
warning ( " getNowSeenRect: Unable to find screen item %04x:%04x " , PRINT_REG ( screenItemObject ) ) ;
2016-07-31 15:19:48 -05:00
return false ;
2016-03-10 14:05:27 -06:00
}
2017-07-09 17:25:17 +02:00
result = screenItem - > getNowSeenRect ( * plane ) ;
return true ;
}
bool GfxFrameout : : kernelSetNowSeen ( const reg_t screenItemObject ) const {
Common : : Rect nsrect ;
bool found = getNowSeenRect ( screenItemObject , nsrect ) ;
if ( ! found )
return false ;
2016-11-27 10:53:06 -06:00
if ( g_sci - > _features - > usesAlternateSelectors ( ) ) {
2017-07-09 17:25:17 +02:00
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( left ) , nsrect . left ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( top ) , nsrect . top ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( right ) , nsrect . right - 1 ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( bottom ) , nsrect . bottom - 1 ) ;
2016-11-27 10:53:06 -06:00
} else {
2017-07-09 17:25:17 +02:00
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsLeft ) , nsrect . left ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsTop ) , nsrect . top ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsRight ) , nsrect . right - 1 ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsBottom ) , nsrect . bottom - 1 ) ;
2016-11-27 10:53:06 -06:00
}
2016-07-31 15:19:48 -05:00
return true ;
2016-03-10 14:05:27 -06:00
}
2017-07-09 17:25:17 +02:00
int16 GfxFrameout : : kernelObjectIntersect ( const reg_t object1 , const reg_t object2 ) const {
Common : : Rect nsrect1 , nsrect2 ;
bool found1 = getNowSeenRect ( object1 , nsrect1 ) ;
bool found2 = getNowSeenRect ( object2 , nsrect2 ) ;
// If both objects were not found, SSCI would probably return an
// intersection area of 1 since SSCI's invalid/uninitialized rect has an
// area of 1. We (mostly) ignore that corner case here.
if ( ! found1 & & ! found2 )
warning ( " Both objects not found in kObjectIntersect " ) ;
// If one object was not found, SSCI would use its invalid/uninitialized
// rect for it, which is at coordinates 0x89ABCDEF. This can't intersect
// valid rects, so we return 0.
if ( ! found1 | | ! found2 )
return 0 ;
const Common : : Rect intersection = nsrect1 . findIntersectingRect ( nsrect2 ) ;
return intersection . width ( ) * intersection . height ( ) ;
}
2016-03-15 21:05:01 +02:00
void GfxFrameout : : remapMarkRedraw ( ) {
for ( PlaneList : : const_iterator it = _planes . begin ( ) ; it ! = _planes . end ( ) ; + + it ) {
Plane * p = * it ;
p - > remapMarkRedraw ( ) ;
}
}
2016-01-18 00:12:47 -06:00
# pragma mark -
# pragma mark Debugging
2012-05-21 01:29:30 +03:00
2016-01-18 00:12:47 -06:00
void GfxFrameout : : printPlaneListInternal ( Console * con , const PlaneList & planeList ) const {
for ( PlaneList : : const_iterator it = planeList . begin ( ) ; it ! = planeList . end ( ) ; + + it ) {
Plane * p = * it ;
p - > printDebugInfo ( con ) ;
2012-05-21 01:29:30 +03:00
}
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : printPlaneList ( Console * con ) const {
printPlaneListInternal ( con , _planes ) ;
}
void GfxFrameout : : printVisiblePlaneList ( Console * con ) const {
printPlaneListInternal ( con , _visiblePlanes ) ;
}
2012-09-26 04:17:31 +02:00
2016-03-07 16:41:57 -06:00
void GfxFrameout : : printPlaneItemListInternal ( Console * con , const ScreenItemList & screenItemList ) const {
ScreenItemList : : size_type i = 0 ;
for ( ScreenItemList : : const_iterator sit = screenItemList . begin ( ) ; sit ! = screenItemList . end ( ) ; sit + + ) {
ScreenItem * screenItem = * sit ;
con - > debugPrintf ( " %2d: " , i + + ) ;
screenItem - > printDebugInfo ( con ) ;
}
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : printPlaneItemList ( Console * con , const reg_t planeObject ) const {
Plane * p = _planes . findByObject ( planeObject ) ;
2012-05-21 01:29:30 +03:00
2016-01-18 00:12:47 -06:00
if ( p = = nullptr ) {
con - > debugPrintf ( " Plane does not exist " ) ;
return ;
}
2016-03-07 16:41:57 -06:00
printPlaneItemListInternal ( con , p - > _screenItemList ) ;
}
void GfxFrameout : : printVisiblePlaneItemList ( Console * con , const reg_t planeObject ) const {
Plane * p = _visiblePlanes . findByObject ( planeObject ) ;
if ( p = = nullptr ) {
con - > debugPrintf ( " Plane does not exist " ) ;
return ;
2012-05-21 01:29:30 +03:00
}
2016-03-07 16:41:57 -06:00
printPlaneItemListInternal ( con , p - > _screenItemList ) ;
2012-05-21 01:29:30 +03:00
}
2011-10-28 22:18:10 +03:00
} // End of namespace Sci