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"
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"
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"
2010-02-06 19:35:51 +00:00
# include "sci/graphics/coordadjuster.h"
2011-10-19 20:27:43 +03:00
# include "sci/graphics/compare.h"
2010-02-03 01:36:53 +00:00
# include "sci/graphics/font.h"
2010-02-02 16:25:35 +00:00
# include "sci/graphics/screen.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-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"
2011-02-07 12:24:09 +00:00
# include "sci/video/robot_decoder.h"
2010-02-02 16:25:35 +00:00
namespace Sci {
2016-01-18 00:12:47 -06:00
static int dissolveSequences [ 2 ] [ 20 ] = {
/* SCI2.1early- */ { 3 , 6 , 12 , 20 , 48 , 96 , 184 , 272 , 576 , 1280 , 3232 , 6912 , 13568 , 24576 , 46080 } ,
/* SCI2.1mid+ */ { 0 , 0 , 3 , 6 , 12 , 20 , 48 , 96 , 184 , 272 , 576 , 1280 , 3232 , 6912 , 13568 , 24576 , 46080 , 73728 , 132096 , 466944 }
} ;
static int16 divisionsDefaults [ 2 ] [ 16 ] = {
/* SCI2.1early- */ { 1 , 20 , 20 , 20 , 20 , 20 , 20 , 20 , 20 , 20 , 20 , 40 , 40 , 101 , 101 } ,
/* SCI2.1mid+ */ { 1 , 20 , 20 , 20 , 20 , 10 , 10 , 10 , 10 , 20 , 20 , 6 , 10 , 101 , 101 , 2 }
} ;
static int16 unknownCDefaults [ 2 ] [ 16 ] = {
/* SCI2.1early- */ { 0 , 1 , 1 , 2 , 2 , 3 , 3 , 4 , 4 , 5 , 5 , 0 , 0 , 0 , 0 } ,
/* SCI2.1mid+ */ { 0 , 2 , 2 , 3 , 3 , 4 , 4 , 5 , 5 , 6 , 6 , 0 , 0 , 7 , 7 , 0 }
2012-06-09 12:12:44 +03:00
} ;
2016-06-20 20:40:43 -05:00
GfxFrameout : : GfxFrameout ( SegManager * segMan , ResourceManager * resMan , GfxCoordAdjuster * coordAdjuster , GfxScreen * screen , GfxPalette32 * palette ) :
2016-02-18 21:09:15 -06:00
_isHiRes ( false ) ,
2016-01-18 00:12:47 -06:00
_palette ( palette ) ,
2016-02-18 21:09:15 -06:00
_resMan ( resMan ) ,
_screen ( screen ) ,
_segMan ( segMan ) ,
2016-06-14 17:43:57 -05:00
_benchmarkingFinished ( false ) ,
_throttleFrameOut ( true ) ,
2016-01-18 00:12:47 -06:00
_showStyles ( nullptr ) ,
// TODO: Stop using _gfxScreen
2016-02-19 16:57:21 +01:00
_currentBuffer ( screen - > getDisplayWidth ( ) , screen - > getDisplayHeight ( ) , nullptr ) ,
2016-02-18 21:09:15 -06:00
_remapOccurred ( false ) ,
_frameNowVisible ( false ) ,
2016-02-19 16:57:21 +01:00
_screenRect ( screen - > getDisplayWidth ( ) , screen - > getDisplayHeight ( ) ) ,
2016-02-18 21:09:15 -06:00
_overdrawThreshold ( 0 ) ,
_palMorphIsOn ( false ) {
2016-01-18 00:12:47 -06:00
2016-02-19 16:57:21 +01:00
_currentBuffer . setPixels ( calloc ( 1 , screen - > getDisplayWidth ( ) * screen - > getDisplayHeight ( ) ) ) ;
2016-01-18 00:12:47 -06:00
for ( int i = 0 ; i < 236 ; i + = 2 ) {
_styleRanges [ i ] = 0 ;
_styleRanges [ i + 1 ] = - 1 ;
}
for ( int i = 236 ; i < ARRAYSIZE ( _styleRanges ) ; + + i ) {
_styleRanges [ i ] = 0 ;
}
2016-01-20 20:06:45 -06:00
// TODO: Make hires detection work uniformly across all SCI engine
// versions (this flag is normally passed by SCI::MakeGraphicsMgr
2016-01-18 00:12:47 -06:00
// to the GraphicsMgr constructor depending upon video configuration,
// so should be handled upstream based on game configuration instead
// of here)
2016-01-20 20:06:45 -06:00
if ( getSciVersion ( ) > = SCI_VERSION_2_1_EARLY & & _resMan - > detectHires ( ) ) {
_isHiRes = true ;
}
2016-01-18 00:12:47 -06:00
if ( getSciVersion ( ) < SCI_VERSION_2_1_MIDDLE ) {
_dissolveSequenceSeeds = dissolveSequences [ 0 ] ;
_defaultDivisions = divisionsDefaults [ 0 ] ;
_defaultUnknownC = unknownCDefaults [ 0 ] ;
} else {
_dissolveSequenceSeeds = dissolveSequences [ 1 ] ;
_defaultDivisions = divisionsDefaults [ 1 ] ;
_defaultUnknownC = unknownCDefaults [ 1 ] ;
}
2016-03-18 18:49:10 -05:00
switch ( g_sci - > getGameId ( ) ) {
case GID_GK2 :
case GID_LIGHTHOUSE :
case GID_LSL7 :
case GID_PHANTASMAGORIA2 :
case GID_PQSWAT :
case GID_TORIN :
case GID_RAMA :
_currentBuffer . scriptWidth = 640 ;
_currentBuffer . scriptHeight = 480 ;
break ;
default :
// default script width for other games is 320x200
break ;
}
2016-01-18 00:12:47 -06:00
// TODO: Nothing in the renderer really uses this. Currently,
// the cursor renderer does, and kLocalToGlobal/kGlobalToLocal
// do, but in the real engine (1) the cursor is handled in
// frameOut, and (2) functions do a very simple lookup of the
// plane and arithmetic with the plane's gameRect. In
// principle, CoordAdjuster could be reused for
// convertGameRectToPlaneRect, but it is not super clear yet
// what the benefit would be to do that.
_coordAdjuster = ( GfxCoordAdjuster32 * ) coordAdjuster ;
// TODO: Script resolution is hard-coded per game;
// also this must be set or else the engine will crash
_coordAdjuster - > setScriptsResolution ( _currentBuffer . scriptWidth , _currentBuffer . scriptHeight ) ;
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 ( ) ;
// 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 ) ;
}
2016-02-21 17:21:48 +01:00
// SCI32 actually did not clear anything at all it seems on restore. The scripts actually cleared up
// planes + screen items right before restoring. And after restoring they sync'd its internal planes list
// as well.
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-02-21 17:21:48 +01:00
// This is what Game::restore does, only needed when our ScummVM dialogs are patched in
// It actually does one pass before actual restore deleting screen items + planes
// And after restore it does another pass adding screen items + planes.
2016-02-21 17:30:25 +01:00
// Attention: at least Space Quest 6's option plane seems to stay in memory right from the start and is not re-created.
2016-02-21 17:21:48 +01:00
void GfxFrameout : : syncWithScripts ( bool addElements ) {
EngineState * engineState = g_sci - > getEngineState ( ) ;
SegManager * segMan = engineState - > _segMan ;
// In case original save/restore dialogs are active, don't do anything
if ( ConfMan . getBool ( " originalsaveload " ) )
return ;
// Get planes list object
reg_t planesListObject = engineState - > variables [ VAR_GLOBAL ] [ 10 ] ;
reg_t planesListElements = readSelector ( segMan , planesListObject , SELECTOR ( elements ) ) ;
List * planesList = segMan - > lookupList ( planesListElements ) ;
reg_t planesNodeObject = planesList - > first ;
// Go through all elements of planes::elements
while ( ! planesNodeObject . isNull ( ) ) {
Node * planesNode = segMan - > lookupNode ( planesNodeObject ) ;
reg_t planeObject = planesNode - > value ;
if ( addElements ) {
// Add this plane object
kernelAddPlane ( planeObject ) ;
}
reg_t planeCastsObject = readSelector ( segMan , planeObject , SELECTOR ( casts ) ) ;
reg_t setListElements = readSelector ( segMan , planeCastsObject , SELECTOR ( elements ) ) ;
// Now go through all elements of plane::casts::elements
List * planeCastsList = segMan - > lookupList ( setListElements ) ;
reg_t planeCastsNodeObject = planeCastsList - > first ;
while ( ! planeCastsNodeObject . isNull ( ) ) {
Node * castsNode = segMan - > lookupNode ( planeCastsNodeObject ) ;
2016-02-21 20:56:00 +01:00
reg_t castsObject = castsNode - > value ;
2016-02-21 17:21:48 +01:00
2016-02-21 20:56:00 +01:00
reg_t castsListElements = readSelector ( segMan , castsObject , SELECTOR ( elements ) ) ;
2016-02-21 17:21:48 +01:00
2016-02-21 20:56:00 +01:00
List * castsList = segMan - > lookupList ( castsListElements ) ;
reg_t castNodeObject = castsList - > first ;
2016-02-21 17:21:48 +01:00
while ( ! castNodeObject . isNull ( ) ) {
Node * castNode = segMan - > lookupNode ( castNodeObject ) ;
reg_t castObject = castNode - > value ;
// read selector "-info-" of this object
// TODO: Seems to have been changed for SCI3
2016-02-21 20:32:42 +01:00
// Do NOT use getInfoSelector in here. SCI3 games did not use infoToa, but an actual selector.
// Maybe that selector is just a straight copy, but it needs to get verified/checked.
2016-02-21 17:21:48 +01:00
uint16 castInfoSelector = readSelectorValue ( segMan , castObject , SELECTOR ( _info_ ) ) ;
if ( castInfoSelector & kInfoFlagViewInserted ) {
if ( addElements ) {
// Flag set, so add this screen item
kernelAddScreenItem ( castObject ) ;
} else {
// Flag set, so delete this screen item
kernelDeleteScreenItem ( castObject ) ;
}
}
castNodeObject = castNode - > succ ;
}
planeCastsNodeObject = castsNode - > succ ;
}
if ( ! addElements ) {
// Delete this plane object
kernelDeletePlane ( planeObject ) ;
}
planesNodeObject = planesNode - > succ ;
}
}
2016-06-26 10:52:17 -05:00
# pragma mark -
# pragma mark Benchmarking
bool GfxFrameout : : checkForFred ( const reg_t object ) {
const int16 viewId = readSelectorValue ( _segMan , object , SELECTOR ( view ) ) ;
const SciGameId gameId = g_sci - > getGameId ( ) ;
if ( gameId = = GID_QFG4 & & viewId = = 9999 ) {
return true ;
}
if ( gameId ! = GID_QFG4 & & viewId = = - 556 ) {
return true ;
}
if ( Common : : String ( _segMan - > getObjectName ( object ) ) = = " fred " ) {
return true ;
}
return false ;
}
2016-01-18 00:12:47 -06:00
# pragma mark -
# pragma mark Screen items
2016-06-18 20:48:10 -05:00
void GfxFrameout : : deleteScreenItem ( ScreenItem * screenItem , Plane * plane ) {
if ( screenItem - > _created = = 0 ) {
screenItem - > _created = 0 ;
screenItem - > _updated = 0 ;
screenItem - > _deleted = getScreenCount ( ) ;
} else {
plane - > _screenItemList . erase ( screenItem ) ;
plane - > _screenItemList . pack ( ) ;
}
}
void GfxFrameout : : deleteScreenItem ( ScreenItem * screenItem , const reg_t planeObject ) {
Plane * plane = _planes . findByObject ( planeObject ) ;
deleteScreenItem ( screenItem , plane ) ;
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelAddScreenItem ( const reg_t object ) {
2016-06-14 17:43:57 -05:00
// The "fred" object is used to test graphics performance;
// it is impacted by framerate throttling, so disable the
// throttling when this item is on the screen for the
// performance check to pass.
2016-06-26 10:52:17 -05:00
if ( ! _benchmarkingFinished & & _throttleFrameOut & & checkForFred ( object ) ) {
2016-06-14 17:43:57 -05:00
_throttleFrameOut = false ;
}
2016-01-18 00:12:47 -06:00
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 ) {
2016-06-14 17:43:57 -05:00
// The "fred" object is used to test graphics performance;
// it is impacted by framerate throttling, so disable the
// throttling when this item is on the screen for the
// performance check to pass.
2016-06-26 10:52:17 -05:00
if ( ! _benchmarkingFinished & & checkForFred ( object ) ) {
2016-06-14 17:43:57 -05:00
_benchmarkingFinished = true ;
_throttleFrameOut = true ;
}
2016-01-18 00:12:47 -06:00
_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-06-18 20:48:10 -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 ) ;
addPlane ( * plane ) ;
}
}
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
2016-01-18 00:12:47 -06:00
void GfxFrameout : : addPlane ( Plane & plane ) {
if ( _planes . findByObject ( plane . _object ) = = nullptr ) {
plane . clipScreenRect ( _screenRect ) ;
_planes . add ( & plane ) ;
} else {
plane . _deleted = 0 ;
if ( plane . _created = = 0 ) {
plane . _moved = g_sci - > _gfxFrameout - > getScreenCount ( ) ;
2010-02-02 16:25:35 +00:00
}
2016-01-18 00:12:47 -06:00
_planes . sort ( ) ;
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-01-18 00:12:47 -06:00
void GfxFrameout : : kernelAddPicAt ( const reg_t planeObject , const GuiResourceId pictureId , const int16 x , const int16 y , const bool mirrorX ) {
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-01-18 00:12:47 -06:00
plane - > addPic ( pictureId , Common : : Point ( x , y ) , mirrorX ) ;
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 ) {
2016-01-18 00:12:47 -06:00
// TODO: Robot
// if (_robot != nullptr) {
// _robot.doRobot();
// }
// 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 ( ) ;
// NOTE: SCI engine set this to false on each loop through the
// planelist iterator below. Since that is a waste, we only set
// it once.
_frameNowVisible = false ;
for ( PlaneList : : size_type i = 0 ; i < _planes . size ( ) ; + + i ) {
drawEraseList ( eraseLists [ i ] , * _planes [ i ] ) ;
drawScreenItemList ( screenItemLists [ i ] ) ;
}
// TODO: Robot
// if (_robot != nullptr) {
// _robot->frameAlmostVisible();
// }
_palette - > updateHardware ( ) ;
if ( shouldShowBits ) {
showBits ( ) ;
}
_frameNowVisible = true ;
// TODO: Robot
// if (_robot != nullptr) {
// robot->frameNowVisible();
// }
2012-06-09 15:36:36 +03:00
}
2016-06-30 13:50:10 -05:00
/**
* Determines the parts of ` r ` that aren ' t overlapped by ` other ` .
* Returns - 1 if ` r ` and ` other ` have no intersection .
* Returns number of returned parts ( in ` outRects ` ) otherwise .
* ( In particular , this returns 0 if ` r ` is contained in ` other ` . )
*/
2016-01-18 00:12:47 -06:00
int splitRects ( Common : : Rect r , const Common : : Rect & other , Common : : Rect ( & outRects ) [ 4 ] ) {
if ( ! r . intersects ( other ) ) {
return - 1 ;
}
2016-06-30 13:50:10 -05:00
int splitCount = 0 ;
2016-01-18 00:12:47 -06:00
if ( r . top < other . top ) {
2016-06-30 13:50:10 -05:00
Common : : Rect & t = outRects [ splitCount + + ] ;
2016-01-18 00:12:47 -06:00
t = r ;
t . bottom = other . top ;
r . top = other . top ;
}
if ( r . bottom > other . bottom ) {
2016-06-30 13:50:10 -05:00
Common : : Rect & t = outRects [ splitCount + + ] ;
2016-01-18 00:12:47 -06:00
t = r ;
t . top = other . bottom ;
r . bottom = other . bottom ;
}
if ( r . left < other . left ) {
2016-06-30 13:50:10 -05:00
Common : : Rect & t = outRects [ splitCount + + ] ;
2016-01-18 00:12:47 -06:00
t = r ;
t . right = other . left ;
r . left = other . left ;
}
if ( r . right > other . right ) {
2016-06-30 13:50:10 -05:00
Common : : Rect & t = outRects [ splitCount + + ] ;
2016-01-18 00:12:47 -06:00
t = r ;
t . left = other . right ;
}
2016-06-30 13:50:10 -05:00
return splitCount ;
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-01-18 00:12:47 -06:00
for ( int 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
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 ) {
for ( int rectIndex = 0 ; rectIndex < eraseList . size ( ) ; + + rectIndex ) {
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-06-30 13:50:10 -05:00
for ( PlaneList : : size_type innerIndex = 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 ) {
* 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-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-06-30 13:50:10 -05:00
for ( PlaneList : : size_type i = 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 : : palMorphFrameOut ( const int8 * styleRanges , const ShowStyleEntry * showStyle ) {
2016-06-25 14:19:47 -05:00
Palette sourcePalette ( _palette - > getNextPalette ( ) ) ;
2016-01-18 00:12:47 -06:00
alterVmap ( sourcePalette , sourcePalette , - 1 , styleRanges ) ;
2011-10-12 02:43:08 +03:00
2016-03-16 01:05:02 +02:00
int16 prevRoom = g_sci - > getEngineState ( ) - > variables [ VAR_GLOBAL ] [ 12 ] . toSint16 ( ) ;
2011-10-12 02:43:08 +03:00
2016-01-18 00:12:47 -06:00
Common : : Rect rect ( _screen - > getDisplayWidth ( ) , _screen - > getDisplayHeight ( ) ) ;
_showList . add ( rect ) ;
showBits ( ) ;
2012-01-14 14:22:23 +02:00
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-03-11 07:54:45 +02:00
}
2016-01-18 00:12:47 -06:00
2016-06-30 13:24:46 -05:00
calcLists ( screenItemLists , eraseLists ) ;
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-01-15 18:35:33 +02:00
}
2016-01-18 00:12:47 -06:00
}
2012-09-26 04:17:31 +02:00
2016-01-18 00:12:47 -06:00
_remapOccurred = _palette - > updateForFrame ( ) ;
_frameNowVisible = false ;
for ( PlaneList : : size_type i = 0 ; i < _planes . size ( ) ; + + i ) {
drawEraseList ( eraseLists [ i ] , * _planes [ i ] ) ;
drawScreenItemList ( screenItemLists [ i ] ) ;
}
2016-06-25 14:19:47 -05:00
Palette nextPalette ( _palette - > getNextPalette ( ) ) ;
2016-01-18 00:12:47 -06:00
2016-03-16 01:05:02 +02:00
if ( prevRoom < 1000 ) {
2016-01-18 00:12:47 -06:00
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 ) {
2016-06-30 13:50:10 -05:00
// TODO: Limiting range 72 to 103 is NOT present in every game
2016-01-18 00:12:47 -06:00
if ( styleRanges [ i ] = = - 1 | | ( styleRanges [ i ] = = 0 & & i > 71 & & i < 104 ) ) {
sourcePalette . colors [ i ] = nextPalette . colors [ i ] ;
sourcePalette . colors [ i ] . used = true ;
}
2012-01-15 18:35:33 +02:00
}
2012-01-14 14:22:23 +02:00
}
2016-01-18 00:12:47 -06:00
_palette - > submit ( sourcePalette ) ;
_palette - > updateFFrame ( ) ;
_palette - > updateHardware ( ) ;
alterVmap ( nextPalette , sourcePalette , 1 , _styleRanges ) ;
2016-02-20 23:28:00 +02:00
if ( showStyle & & showStyle - > type ! = kShowStyleUnknown ) {
2016-01-18 00:12:47 -06:00
// TODO: SCI2.1mid transition effects
// processEffects();
2016-03-17 10:22:15 -05:00
warning ( " Transition %d not implemented! " , showStyle - > type ) ;
2016-01-18 00:12:47 -06:00
} else {
showBits ( ) ;
2010-02-02 16:25:35 +00:00
}
2011-10-12 02:43:08 +03:00
2016-01-18 00:12:47 -06:00
_frameNowVisible = true ;
2010-02-02 16:25:35 +00:00
2016-01-18 00:12:47 -06:00
for ( PlaneList : : iterator plane = _planes . begin ( ) ; plane ! = _planes . end ( ) ; + + plane ) {
2016-03-17 09:54:40 -05:00
( * plane ) - > _redrawAllCount = getScreenCount ( ) ;
2016-01-18 00:12:47 -06:00
}
2010-02-02 16:25:35 +00:00
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-03-11 07:54:45 +02:00
}
2010-07-25 20:41:23 +00:00
2016-06-30 13:24:46 -05:00
calcLists ( screenItemLists , eraseLists ) ;
2016-01-18 00:12:47 -06:00
for ( ScreenItemListList : : iterator list = screenItemLists . begin ( ) ; list ! = screenItemLists . end ( ) ; + + list ) {
list - > sort ( ) ;
2010-07-24 18:06:49 +00:00
}
2010-02-02 16:25:35 +00:00
2016-01-18 00:12:47 -06:00
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 ( ) ;
// NOTE: During this second loop, `_frameNowVisible = false` is
// inside the next loop in SCI2.1mid
_frameNowVisible = false ;
for ( PlaneList : : size_type i = 0 ; i < _planes . size ( ) ; + + i ) {
drawEraseList ( eraseLists [ i ] , * _planes [ i ] ) ;
drawScreenItemList ( screenItemLists [ i ] ) ;
}
2010-02-02 16:25:35 +00:00
2016-01-18 00:12:47 -06:00
_palette - > submit ( nextPalette ) ;
_palette - > updateFFrame ( ) ;
_palette - > updateHardware ( ) ;
showBits ( ) ;
2010-06-14 16:58:15 +00:00
2016-01-18 00:12:47 -06:00
_frameNowVisible = true ;
2010-06-20 17:17:46 +00:00
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : showBits ( ) {
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 ;
// TODO:
// _cursor->GonnaPaint(rounded);
2010-06-20 17:17:46 +00:00
}
2016-01-18 00:12:47 -06:00
// TODO:
// _cursor->PaintStarting();
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 ;
g_system - > copyRectToScreen ( sourceBuffer , _currentBuffer . screenWidth , rounded . left , rounded . top , rounded . width ( ) , rounded . height ( ) ) ;
}
// TODO:
// _cursor->DonePainting();
_showList . clear ( ) ;
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
// NOTE: This is currBuffer->ptr in SCI engine
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
}
}
2016-01-18 00:12:47 -06:00
void GfxFrameout : : kernelSetPalStyleRange ( const uint8 fromColor , const uint8 toColor ) {
if ( toColor > fromColor ) {
return ;
}
for ( int i = fromColor ; i < toColor ; + + i ) {
_styleRanges [ i ] = 0 ;
}
}
inline ShowStyleEntry * GfxFrameout : : findShowStyleForPlane ( const reg_t planeObj ) const {
ShowStyleEntry * entry = _showStyles ;
while ( entry ! = nullptr ) {
if ( entry - > plane = = planeObj ) {
break ;
2011-11-17 22:08:36 +02:00
}
2016-01-18 00:12:47 -06:00
entry = entry - > next ;
2011-11-17 22:08:36 +02:00
}
2016-01-18 00:12:47 -06:00
return entry ;
}
inline ShowStyleEntry * GfxFrameout : : deleteShowStyleInternal ( ShowStyleEntry * const showStyle ) {
ShowStyleEntry * lastEntry = nullptr ;
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
for ( ShowStyleEntry * testEntry = _showStyles ; testEntry ! = nullptr ; testEntry = testEntry - > next ) {
if ( testEntry = = showStyle ) {
break ;
}
lastEntry = testEntry ;
}
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
if ( lastEntry = = nullptr ) {
_showStyles = showStyle - > next ;
lastEntry = _showStyles ;
} else {
lastEntry - > next = showStyle - > next ;
}
2011-11-17 22:08:36 +02:00
2016-03-17 10:22:15 -05:00
delete [ ] showStyle - > fadeColorRanges ;
2016-01-18 00:12:47 -06:00
delete showStyle ;
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
// TODO: Verify that this is the correct entry to return
// for the loop in processShowStyles to work correctly
return lastEntry ;
2011-11-17 22:08:36 +02:00
}
2016-01-18 00:12:47 -06:00
// TODO: 10-argument version is only in SCI3; argc checks are currently wrong for this version
// and need to be fixed in future
// TODO: SQ6 does not use 'priority' (exists since SCI2) or 'blackScreen' (exists since SCI3);
// check to see if other versions use or if they are just always ignored
2016-03-16 21:57:36 -05:00
void GfxFrameout : : kernelSetShowStyle ( const uint16 argc , const reg_t planeObj , const ShowStyleType type , const int16 seconds , const int16 back , const int16 priority , const int16 animate , const int16 frameOutNow , reg_t pFadeArray , int16 divisions , const int16 blackScreen ) {
2016-01-18 00:12:47 -06:00
bool hasDivisions = false ;
bool hasFadeArray = false ;
2016-03-16 21:57:36 -05:00
// KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
// for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
// put `divisions` where `pFadeArray` is supposed to be
if ( getSciVersion ( ) = = SCI_VERSION_2_1_MIDDLE & & g_sci - > getGameId ( ) = = GID_KQ7 ) {
hasDivisions = argc > 7 ;
hasFadeArray = false ;
divisions = argc > 7 ? pFadeArray . toSint16 ( ) : - 1 ;
pFadeArray = NULL_REG ;
} else if ( getSciVersion ( ) < SCI_VERSION_2_1_MIDDLE ) {
2016-01-18 00:12:47 -06:00
hasDivisions = argc > 7 ;
hasFadeArray = false ;
} else if ( getSciVersion ( ) < SCI_VERSION_3 ) {
hasDivisions = argc > 8 ;
hasFadeArray = argc > 7 ;
} else {
hasDivisions = argc > 9 ;
hasFadeArray = argc > 8 ;
}
2011-02-07 12:24:09 +00:00
2016-01-18 00:12:47 -06:00
bool isFadeUp ;
int16 color ;
if ( back ! = - 1 ) {
isFadeUp = false ;
color = back ;
} else {
isFadeUp = true ;
color = 0 ;
}
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
if ( ( getSciVersion ( ) < SCI_VERSION_2_1_MIDDLE & & type = = 15 ) | | type > 15 ) {
error ( " Illegal show style %d for plane %04x:%04x " , type , PRINT_REG ( planeObj ) ) ;
}
Plane * plane = _planes . findByObject ( planeObj ) ;
if ( plane = = nullptr ) {
error ( " Plane %04x:%04x is not present in active planes list " , PRINT_REG ( planeObj ) ) ;
}
bool createNewEntry = true ;
ShowStyleEntry * entry = findShowStyleForPlane ( planeObj ) ;
if ( entry ! = nullptr ) {
2016-03-17 10:22:15 -05:00
// TODO: SCI2.1early has different criteria for show style reuse
2016-01-18 00:12:47 -06:00
bool useExisting = true ;
if ( useExisting ) {
useExisting = entry - > divisions = = ( hasDivisions ? divisions : _defaultDivisions [ type ] ) & & entry - > unknownC = = _defaultUnknownC [ type ] ;
}
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
if ( useExisting ) {
createNewEntry = false ;
isFadeUp = true ;
entry - > currentStep = 0 ;
2011-11-17 22:08:36 +02:00
} else {
2016-01-18 00:12:47 -06:00
isFadeUp = true ;
color = entry - > color ;
deleteShowStyleInternal ( entry /*, true*/ ) ;
entry = nullptr ;
2011-11-17 22:08:36 +02:00
}
}
2016-01-18 00:12:47 -06:00
if ( type > 0 ) {
if ( createNewEntry ) {
entry = new ShowStyleEntry ;
// NOTE: SCI2.1 engine tests if allocation returned a null pointer
// but then only avoids setting currentStep if this is so. Since
// this is a nonsensical approach, we do not do that here
entry - > currentStep = 0 ;
entry - > unknownC = _defaultUnknownC [ type ] ;
entry - > processed = false ;
entry - > divisions = hasDivisions ? divisions : _defaultDivisions [ type ] ;
entry - > plane = planeObj ;
2016-03-17 10:22:15 -05:00
entry - > fadeColorRanges = nullptr ;
if ( hasFadeArray ) {
// NOTE: SCI2.1mid engine does no check to verify that an array is
// successfully retrieved, and SegMan will cause a fatal error
// if we try to use a memory segment that is not an array
SciArray < reg_t > * table = _segMan - > lookupArray ( pFadeArray ) ;
uint32 rangeCount = table - > getSize ( ) ;
entry - > fadeColorRangesCount = rangeCount ;
// NOTE: SCI engine code always allocates memory even if the range
// table has no entries, but this does not really make sense, so
// we avoid the allocation call in this case
if ( rangeCount > 0 ) {
entry - > fadeColorRanges = new uint16 [ rangeCount ] ;
for ( size_t i = 0 ; i < rangeCount ; + + i ) {
entry - > fadeColorRanges [ i ] = table - > getValue ( i ) . toUint16 ( ) ;
2016-01-18 00:12:47 -06:00
}
}
2016-03-17 10:22:15 -05:00
} else {
entry - > fadeColorRangesCount = 0 ;
2016-01-18 00:12:47 -06:00
}
}
// NOTE: The original engine had no nullptr check and would just crash
// if it got to here
if ( entry = = nullptr ) {
error ( " Cannot edit non-existing ShowStyle entry " ) ;
}
entry - > fadeUp = isFadeUp ;
entry - > color = color ;
entry - > nextTick = g_sci - > getTickCount ( ) ;
entry - > type = type ;
entry - > animate = animate ;
entry - > delay = ( seconds * 60 + entry - > divisions - 1 ) / entry - > divisions ;
if ( entry - > delay = = 0 ) {
if ( entry - > fadeColorRanges ! = nullptr ) {
delete [ ] entry - > fadeColorRanges ;
}
delete entry ;
error ( " ShowStyle has no duration " ) ;
}
if ( frameOutNow ) {
Common : : Rect frameOutRect ( 0 , 0 ) ;
frameOut ( false , frameOutRect ) ;
}
if ( createNewEntry ) {
2016-03-17 10:22:15 -05:00
// TODO: Implement SCI2.1early and SCI3
2016-01-18 00:12:47 -06:00
entry - > next = _showStyles ;
_showStyles = entry ;
2011-02-07 12:24:09 +00:00
}
2011-11-17 22:08:36 +02:00
}
2016-01-18 00:12:47 -06:00
}
2011-11-17 22:08:36 +02:00
2016-01-18 00:12:47 -06:00
// NOTE: Different version of SCI engine support different show styles
// SCI2 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12, 13, 14
// SCI2.1 implements 0, 1/2/3/4/5/6/7/8/9/10/11/12/15, 13, 14
// SCI3 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12/15, 13, 14
// TODO: Sierra code needs to be replaced with code that uses the
// computed entry->delay property instead of just counting divisors,
// as the latter is machine-speed-dependent and leads to wrong
// transition speeds
void GfxFrameout : : processShowStyles ( ) {
uint32 now = g_sci - > getTickCount ( ) ;
bool continueProcessing ;
// TODO: Change to bool? Engine uses inc to set the value to true,
// but there does not seem to be any reason to actually count how
// many times it was set
int doFrameOut ;
do {
continueProcessing = false ;
doFrameOut = 0 ;
ShowStyleEntry * showStyle = _showStyles ;
while ( showStyle ! = nullptr ) {
bool retval = false ;
if ( ! showStyle - > animate ) {
+ + doFrameOut ;
}
if ( showStyle - > nextTick < now | | ! showStyle - > animate ) {
// TODO: Different versions of SCI use different processors!
// This is the SQ6/KQ7/SCI2.1mid table.
switch ( showStyle - > type ) {
case kShowStyleNone : {
retval = processShowStyleNone ( showStyle ) ;
break ;
}
case kShowStyleHShutterOut :
case kShowStyleVShutterOut :
case kShowStyleWipeLeft :
case kShowStyleWipeUp :
case kShowStyleIrisOut :
case kShowStyleHShutterIn :
case kShowStyleVShutterIn :
case kShowStyleWipeRight :
case kShowStyleWipeDown :
case kShowStyleIrisIn :
case kShowStyle11 :
case kShowStyle12 :
case kShowStyleUnknown : {
2016-03-17 10:22:15 -05:00
retval = processShowStyleMorph ( showStyle ) ;
2016-01-18 00:12:47 -06:00
break ;
}
case kShowStyleFadeOut : {
retval = processShowStyleFade ( - 1 , showStyle ) ;
break ;
}
case kShowStyleFadeIn : {
retval = processShowStyleFade ( 1 , showStyle ) ;
break ;
}
}
}
2016-01-06 20:03:27 -06:00
2016-01-18 00:12:47 -06:00
if ( ! retval ) {
continueProcessing = true ;
2016-01-06 20:03:27 -06:00
}
2016-01-18 00:12:47 -06:00
if ( retval & & showStyle - > processed ) {
showStyle = deleteShowStyleInternal ( showStyle ) ;
} else {
showStyle = showStyle - > next ;
2016-01-06 20:03:27 -06:00
}
}
2016-01-18 00:12:47 -06:00
if ( doFrameOut ) {
2016-03-02 13:57:12 -06:00
frameOut ( true ) ;
// TODO: Transitions without the “animate” flag are too
// fast, but the throttle value is arbitrary. Someone on
// real hardware probably needs to test what the actual
// speed of these transitions should be
EngineState * state = g_sci - > getEngineState ( ) ;
state - > speedThrottler ( 33 ) ;
state - > _throttleTrigger = true ;
2016-01-18 00:12:47 -06:00
}
} while ( continueProcessing & & doFrameOut ) ;
}
bool GfxFrameout : : processShowStyleNone ( ShowStyleEntry * const showStyle ) {
if ( showStyle - > fadeUp ) {
_palette - > setFade ( 100 , 0 , 255 ) ;
} else {
_palette - > setFade ( 0 , 0 , 255 ) ;
2016-01-06 20:03:27 -06:00
}
2016-01-18 00:12:47 -06:00
showStyle - > processed = true ;
return true ;
}
2016-01-06 20:03:27 -06:00
2016-01-18 00:12:47 -06:00
bool GfxFrameout : : processShowStyleMorph ( ShowStyleEntry * const showStyle ) {
palMorphFrameOut ( _styleRanges , showStyle ) ;
showStyle - > processed = true ;
return true ;
}
2016-01-06 20:03:27 -06:00
2016-01-18 00:12:47 -06:00
// TODO: Normalise use of 'entry' vs 'showStyle'
bool GfxFrameout : : processShowStyleFade ( const int direction , ShowStyleEntry * const showStyle ) {
bool unchanged = true ;
if ( showStyle - > currentStep < showStyle - > divisions ) {
int percent ;
if ( direction < = 0 ) {
percent = showStyle - > divisions - showStyle - > currentStep - 1 ;
} else {
percent = showStyle - > currentStep ;
2016-01-06 20:03:27 -06:00
}
2016-01-18 00:12:47 -06:00
percent * = 100 ;
percent / = showStyle - > divisions - 1 ;
2016-01-06 20:03:27 -06:00
2016-01-18 00:12:47 -06:00
if ( showStyle - > fadeColorRangesCount > 0 ) {
for ( int i = 0 , len = showStyle - > fadeColorRangesCount ; i < len ; i + = 2 ) {
_palette - > setFade ( percent , showStyle - > fadeColorRanges [ i ] , showStyle - > fadeColorRanges [ i + 1 ] ) ;
}
} else {
_palette - > setFade ( percent , 0 , 255 ) ;
}
2016-01-06 20:03:27 -06:00
2016-01-18 00:12:47 -06:00
+ + showStyle - > currentStep ;
showStyle - > nextTick + = showStyle - > delay ;
unchanged = false ;
2016-01-06 20:03:27 -06:00
}
2016-01-18 00:12:47 -06:00
if ( showStyle - > currentStep > = showStyle - > divisions & & unchanged ) {
if ( direction > 0 ) {
showStyle - > processed = true ;
}
2016-01-06 20:03:27 -06:00
2016-01-18 00:12:47 -06:00
return true ;
2016-01-06 20:03:27 -06:00
}
2016-01-18 00:12:47 -06:00
return false ;
}
2016-03-02 14:02:15 -06:00
void GfxFrameout : : kernelFrameOut ( const bool shouldShowBits ) {
2016-01-18 00:12:47 -06:00
if ( _showStyles ! = nullptr ) {
processShowStyles ( ) ;
} else if ( _palMorphIsOn ) {
palMorphFrameOut ( _styleRanges , nullptr ) ;
_palMorphIsOn = false ;
} else {
// TODO: Window scroll
2016-03-17 09:55:29 -05:00
// if (g_PlaneScroll) {
// processScrolls();
2016-01-18 00:12:47 -06:00
// }
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
if ( _throttleFrameOut ) {
g_sci - > getEngineState ( ) - > speedThrottler ( 16 ) ;
g_sci - > getEngineState ( ) - > _throttleTrigger = true ;
}
2016-01-18 00:12:47 -06:00
}
2012-05-21 01:29:30 +03:00
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
2016-03-08 10:27:15 -06:00
mulru ( scaledPosition , Ratio ( celObj . _scaledWidth , _currentBuffer . screenWidth ) , Ratio ( celObj . _scaledHeight , _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
}
2016-03-08 10:27:15 -06:00
uint8 pixel = celObj . readPixel ( scaledPosition . x , scaledPosition . y , mirrorX ) ;
return pixel ! = celObj . _transparentColor ;
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
}
2016-03-10 14:05:27 -06:00
void GfxFrameout : : kernelSetNowSeen ( const reg_t screenItemObject ) const {
const reg_t planeObject = readSelector ( _segMan , screenItemObject , SELECTOR ( plane ) ) ;
Plane * plane = _planes . findByObject ( planeObject ) ;
if ( plane = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kSetNowSeen: Plane %04x:%04x not found for screen item %04x:%04x " , PRINT_REG ( planeObject ) , PRINT_REG ( screenItemObject ) ) ;
2016-03-10 14:05:27 -06:00
}
ScreenItem * screenItem = plane - > _screenItemList . findByObject ( screenItemObject ) ;
if ( screenItem = = nullptr ) {
2016-03-10 17:31:51 -06:00
error ( " kSetNowSeen: Screen item %04x:%04x not found in plane %04x:%04x " , PRINT_REG ( screenItemObject ) , PRINT_REG ( planeObject ) ) ;
2016-03-10 14:05:27 -06:00
}
Common : : Rect result = screenItem - > getNowSeenRect ( * plane ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsLeft ) , result . left ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsTop ) , result . top ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsRight ) , result . right - 1 ) ;
writeSelectorValue ( _segMan , screenItemObject , SELECTOR ( nsBottom ) , result . bottom - 1 ) ;
}
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