2007-05-30 21:56:52 +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 .
2003-12-16 02:10:15 +00:00
*
* 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 .
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2008-01-05 12:45:14 +00:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2003-12-16 02:10:15 +00:00
* GNU General Public License for more details .
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2005-10-18 01:30:26 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2003-12-16 02:10:15 +00:00
*
2006-02-11 10:01:01 +00:00
* $ URL $
* $ Id $
2003-12-16 02:10:15 +00:00
*
*/
2007-09-19 08:40:12 +00:00
2005-06-24 15:23:51 +00:00
# include "common/system.h"
2004-10-21 12:37:13 +00:00
# include "common/util.h"
2006-03-29 15:59:37 +00:00
2004-10-21 12:37:13 +00:00
# include "sword1/screen.h"
# include "sword1/logic.h"
# include "sword1/sworddefs.h"
# include "sword1/text.h"
# include "sword1/resman.h"
# include "sword1/objectman.h"
# include "sword1/menu.h"
2009-02-28 10:46:33 +00:00
# include "sword1/swordres.h"
2004-10-21 12:37:13 +00:00
# include "sword1/sword1.h"
2003-12-16 02:10:15 +00:00
2004-01-11 15:47:41 +00:00
namespace Sword1 {
2003-12-16 02:10:15 +00:00
# define SCROLL_FRACTION 16
# define MAX_SCROLL_DISTANCE 8
# define FADE_UP 1
# define FADE_DOWN -1
2004-01-11 15:47:41 +00:00
Screen : : Screen ( OSystem * system , ResMan * pResMan , ObjectMan * pObjMan ) {
2003-12-16 02:10:15 +00:00
_system = system ;
_resMan = pResMan ;
_objMan = pObjMan ;
_screenBuf = _screenGrid = NULL ;
_backLength = _foreLength = _sortLength = 0 ;
_fadingStep = 0 ;
2004-11-09 04:06:10 +00:00
_currentScreen = 0xFFFF ;
2009-02-15 22:33:18 +00:00
_updatePalette = false ;
2009-03-16 23:10:50 +00:00
_psxCache . decodedBackground = NULL ;
_psxCache . extPlxCache = NULL ;
2004-11-09 04:06:10 +00:00
}
2009-11-02 21:54:57 +00:00
Screen : : ~ Screen ( ) {
2009-02-16 06:11:37 +00:00
free ( _screenBuf ) ;
free ( _screenGrid ) ;
2004-11-09 04:06:10 +00:00
if ( _currentScreen ! = 0xFFFF )
quitScreen ( ) ;
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
void Screen : : clearScreen ( ) {
2006-08-26 11:34:35 +00:00
if ( _screenBuf ) {
_fullRefresh = true ;
memset ( _screenBuf , 0 , _scrnSizeX * _scrnSizeY ) ;
2009-02-15 21:20:21 +00:00
_system - > fillScreen ( 0 ) ;
2006-08-26 11:34:35 +00:00
}
}
2004-01-11 15:47:41 +00:00
void Screen : : useTextManager ( Text * pTextMan ) {
2003-12-16 02:10:15 +00:00
_textMan = pTextMan ;
}
2004-01-11 15:47:41 +00:00
int32 Screen : : inRange ( int32 a , int32 b , int32 c ) { // return b(!) so that: a <= b <= c
2003-12-16 02:10:15 +00:00
return ( a > b ) ? ( a ) : ( ( b < c ) ? b : c ) ;
}
2004-01-11 15:47:41 +00:00
void Screen : : setScrolling ( int16 offsetX , int16 offsetY ) {
offsetX = inRange ( 0 , offsetX , Logic : : _scriptVars [ MAX_SCROLL_OFFSET_X ] ) ;
offsetY = inRange ( 0 , offsetY , Logic : : _scriptVars [ MAX_SCROLL_OFFSET_Y ] ) ;
2003-12-16 02:10:15 +00:00
2004-01-11 15:47:41 +00:00
if ( Logic : : _scriptVars [ SCROLL_FLAG ] = = 2 ) { // first time on this screen - need absolute scroll immediately!
_oldScrollX = Logic : : _scriptVars [ SCROLL_OFFSET_X ] = ( uint32 ) offsetX ;
_oldScrollY = Logic : : _scriptVars [ SCROLL_OFFSET_Y ] = ( uint32 ) offsetY ;
Logic : : _scriptVars [ SCROLL_FLAG ] = 1 ;
2003-12-16 02:10:15 +00:00
_fullRefresh = true ;
2004-01-11 15:47:41 +00:00
} else if ( Logic : : _scriptVars [ SCROLL_FLAG ] = = 1 ) {
2004-03-01 08:04:10 +00:00
// Because parallax layers may be drawn on the old scroll offset, we
// want a full refresh not only when the scroll offset changes, but
// also on the frame where they become the same.
if ( _oldScrollX ! = Logic : : _scriptVars [ SCROLL_OFFSET_X ] | | _oldScrollY ! = Logic : : _scriptVars [ SCROLL_OFFSET_Y ] )
_fullRefresh = true ;
2004-01-11 15:47:41 +00:00
_oldScrollX = Logic : : _scriptVars [ SCROLL_OFFSET_X ] ;
_oldScrollY = Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ;
2004-12-09 21:32:02 +00:00
int dx = offsetX - Logic : : _scriptVars [ SCROLL_OFFSET_X ] ;
int dy = offsetY - Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ;
2005-11-08 10:21:02 +00:00
int scrlDistX = inRange ( - MAX_SCROLL_DISTANCE , ( ( ( SCROLL_FRACTION - 1 ) + ABS ( dx ) ) / SCROLL_FRACTION ) * ( ( dx > 0 ) ? 1 : - 1 ) , MAX_SCROLL_DISTANCE ) ;
int scrlDistY = inRange ( - MAX_SCROLL_DISTANCE , ( ( ( SCROLL_FRACTION - 1 ) + ABS ( dy ) ) / SCROLL_FRACTION ) * ( ( dy > 0 ) ? 1 : - 1 ) , MAX_SCROLL_DISTANCE ) ;
2004-12-09 21:32:02 +00:00
if ( ( scrlDistX ! = 0 ) | | ( scrlDistY ! = 0 ) )
2003-12-21 17:45:15 +00:00
_fullRefresh = true ;
2004-12-09 21:32:02 +00:00
Logic : : _scriptVars [ SCROLL_OFFSET_X ] = inRange ( 0 , Logic : : _scriptVars [ SCROLL_OFFSET_X ] + scrlDistX , Logic : : _scriptVars [ MAX_SCROLL_OFFSET_X ] ) ;
Logic : : _scriptVars [ SCROLL_OFFSET_Y ] = inRange ( 0 , Logic : : _scriptVars [ SCROLL_OFFSET_Y ] + scrlDistY , Logic : : _scriptVars [ MAX_SCROLL_OFFSET_Y ] ) ;
2005-11-04 15:40:54 +00:00
} else {
// SCROLL_FLAG == 0, this usually means that the screen is smaller than 640x400 and doesn't need scrolling at all
// however, it can also mean that the gamescript overwrote the scrolling flag to take care of scrolling directly,
// (see bug report #1345130) so we ignore the offset arguments in this case
Logic : : _scriptVars [ SCROLL_OFFSET_X ] = inRange ( 0 , Logic : : _scriptVars [ SCROLL_OFFSET_X ] , Logic : : _scriptVars [ MAX_SCROLL_OFFSET_X ] ) ;
Logic : : _scriptVars [ SCROLL_OFFSET_Y ] = inRange ( 0 , Logic : : _scriptVars [ SCROLL_OFFSET_Y ] , Logic : : _scriptVars [ MAX_SCROLL_OFFSET_Y ] ) ;
if ( ( Logic : : _scriptVars [ SCROLL_OFFSET_X ] ! = _oldScrollX ) | | ( Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ! = _oldScrollY ) ) {
_fullRefresh = true ;
_oldScrollX = Logic : : _scriptVars [ SCROLL_OFFSET_X ] ;
_oldScrollY = Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ;
}
2003-12-16 02:10:15 +00:00
}
}
2009-11-02 21:54:57 +00:00
void Screen : : fadeDownPalette ( ) {
2003-12-17 07:33:00 +00:00
if ( ! _isBlack ) { // don't fade down twice
_fadingStep = 15 ;
_fadingDirection = FADE_DOWN ;
}
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
void Screen : : fadeUpPalette ( ) {
2003-12-28 23:24:03 +00:00
_fadingStep = 1 ;
2003-12-16 02:10:15 +00:00
_fadingDirection = FADE_UP ;
}
2004-01-11 15:47:41 +00:00
void Screen : : fnSetPalette ( uint8 start , uint16 length , uint32 id , bool fadeUp ) {
2003-12-17 01:47:47 +00:00
uint8 * palData = ( uint8 * ) _resMan - > openFetchRes ( id ) ;
if ( start = = 0 ) // force color 0 to black
palData [ 0 ] = palData [ 1 ] = palData [ 2 ] = 0 ;
2007-09-19 08:40:12 +00:00
2009-02-28 10:46:33 +00:00
if ( SwordEngine : : isMac ( ) ) { // see bug #1701058
2007-05-26 16:17:31 +00:00
if ( start ! = 0 & & start + length = = 256 ) // and force color 255 to black as well
palData [ ( length - 1 ) * 3 + 0 ] = palData [ ( length - 1 ) * 3 + 1 ] = palData [ ( length - 1 ) * 3 + 2 ] = 0 ;
}
2003-12-17 01:47:47 +00:00
for ( uint32 cnt = 0 ; cnt < length ; cnt + + ) {
_targetPalette [ ( start + cnt ) * 4 + 0 ] = palData [ cnt * 3 + 0 ] < < 2 ;
_targetPalette [ ( start + cnt ) * 4 + 1 ] = palData [ cnt * 3 + 1 ] < < 2 ;
_targetPalette [ ( start + cnt ) * 4 + 2 ] = palData [ cnt * 3 + 2 ] < < 2 ;
}
_resMan - > resClose ( id ) ;
2003-12-17 07:33:00 +00:00
_isBlack = false ;
2003-12-17 01:47:47 +00:00
if ( fadeUp ) {
_fadingStep = 1 ;
2003-12-17 07:33:00 +00:00
_fadingDirection = FADE_UP ;
2003-12-20 20:20:53 +00:00
memset ( _currentPalette , 0 , 256 * 4 ) ;
2004-02-28 12:58:13 +00:00
_system - > setPalette ( _currentPalette , 0 , 256 ) ;
2003-12-17 01:47:47 +00:00
} else
2004-02-28 12:58:13 +00:00
_system - > setPalette ( _targetPalette + 4 * start , start , length ) ;
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
void Screen : : fullRefresh ( ) {
2004-01-04 05:21:22 +00:00
_fullRefresh = true ;
2004-02-28 12:58:13 +00:00
_system - > setPalette ( _targetPalette , 0 , 256 ) ;
2003-12-22 01:20:47 +00:00
}
2009-11-02 21:54:57 +00:00
bool Screen : : stillFading ( ) {
2003-12-22 23:38:23 +00:00
return ( _fadingStep ! = 0 ) ;
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
bool Screen : : showScrollFrame ( ) {
2009-02-15 22:33:18 +00:00
if ( ( ! _fullRefresh ) | | Logic : : _scriptVars [ NEW_PALETTE ] | | _updatePalette )
2004-01-07 19:08:59 +00:00
return false ; // don't draw an additional frame if we aren't scrolling or have to change the palette
2004-01-11 15:47:41 +00:00
if ( ( _oldScrollX = = Logic : : _scriptVars [ SCROLL_OFFSET_X ] ) & &
( _oldScrollY = = Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ) )
2004-01-07 19:08:59 +00:00
return false ; // check again if we *really* are scrolling.
2004-01-11 15:47:41 +00:00
uint16 avgScrlX = ( uint16 ) ( _oldScrollX + Logic : : _scriptVars [ SCROLL_OFFSET_X ] ) / 2 ;
uint16 avgScrlY = ( uint16 ) ( _oldScrollY + Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ) / 2 ;
2004-01-07 19:08:59 +00:00
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( _screenBuf + avgScrlY * _scrnSizeX + avgScrlX , _scrnSizeX , 0 , 40 , SCREEN_WIDTH , SCREEN_DEPTH ) ;
2004-02-28 12:58:13 +00:00
_system - > updateScreen ( ) ;
2004-01-07 19:08:59 +00:00
return true ;
}
2009-11-02 21:54:57 +00:00
void Screen : : updateScreen ( ) {
2004-01-11 15:47:41 +00:00
if ( Logic : : _scriptVars [ NEW_PALETTE ] ) {
2003-12-16 02:10:15 +00:00
_fadingStep = 1 ;
_fadingDirection = FADE_UP ;
2009-02-15 22:33:18 +00:00
_updatePalette = true ;
2004-01-11 15:47:41 +00:00
Logic : : _scriptVars [ NEW_PALETTE ] = 0 ;
2003-12-16 02:10:15 +00:00
}
2009-02-15 22:33:18 +00:00
if ( _updatePalette ) {
fnSetPalette ( 0 , 184 , _roomDefTable [ _currentScreen ] . palettes [ 0 ] , false ) ;
fnSetPalette ( 184 , 72 , _roomDefTable [ _currentScreen ] . palettes [ 1 ] , false ) ;
_updatePalette = false ;
}
2003-12-16 02:10:15 +00:00
if ( _fadingStep ) {
fadePalette ( ) ;
2004-02-28 12:58:13 +00:00
_system - > setPalette ( _currentPalette , 0 , 256 ) ;
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
uint16 scrlX = ( uint16 ) Logic : : _scriptVars [ SCROLL_OFFSET_X ] ;
uint16 scrlY = ( uint16 ) Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ;
2003-12-16 02:10:15 +00:00
if ( _fullRefresh ) {
_fullRefresh = false ;
uint16 copyWidth = SCREEN_WIDTH ;
uint16 copyHeight = SCREEN_DEPTH ;
if ( scrlX + copyWidth > _scrnSizeX )
copyWidth = _scrnSizeX - scrlX ;
if ( scrlY + copyHeight > _scrnSizeY )
copyHeight = _scrnSizeY - scrlY ;
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( _screenBuf + scrlY * _scrnSizeX + scrlX , _scrnSizeX , 0 , 40 , copyWidth , copyHeight ) ;
2003-12-16 02:10:15 +00:00
} else {
// partial screen update only. The screen coordinates probably won't fit to the
// grid holding the informations on which blocks have to be updated.
// as the grid will be X pixel higher and Y pixel more to the left, this can be cured
// by first checking the top border, then the left column and then the remaining (aligned) part.
uint8 * gridPos = _screenGrid + ( scrlX / SCRNGRID_X ) + ( scrlY / SCRNGRID_Y ) * _gridSizeX ;
uint8 * scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX ;
uint8 diffX = ( uint8 ) ( scrlX % SCRNGRID_X ) ;
uint8 diffY = ( uint8 ) ( scrlY % SCRNGRID_Y ) ;
uint16 gridW = SCREEN_WIDTH / SCRNGRID_X ;
uint16 gridH = SCREEN_DEPTH / SCRNGRID_Y ;
if ( diffY ) {
2004-01-03 12:29:21 +00:00
diffY = SCRNGRID_Y - diffY ;
2003-12-16 02:10:15 +00:00
uint16 cpWidth = 0 ;
2005-07-30 21:11:48 +00:00
for ( uint16 cntx = 0 ; cntx < gridW ; cntx + + )
2004-01-03 12:29:21 +00:00
if ( gridPos [ cntx ] ) {
gridPos [ cntx ] > > = 1 ;
2003-12-16 02:10:15 +00:00
cpWidth + + ;
} else if ( cpWidth ) {
int16 xPos = ( cntx - cpWidth ) * SCRNGRID_X - diffX ;
if ( xPos < 0 )
xPos = 0 ;
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( scrnBuf + xPos , _scrnSizeX , xPos , 40 , cpWidth * SCRNGRID_X , diffY ) ;
2003-12-16 02:10:15 +00:00
cpWidth = 0 ;
}
if ( cpWidth ) {
int16 xPos = ( gridW - cpWidth ) * SCRNGRID_X - diffX ;
if ( xPos < 0 )
xPos = 0 ;
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( scrnBuf + xPos , _scrnSizeX , xPos , 40 , SCREEN_WIDTH - xPos , diffY ) ;
2003-12-16 02:10:15 +00:00
}
2004-01-03 12:29:21 +00:00
scrlY + = diffY ;
}
// okay, y scrolling is compensated. check x now.
gridPos = _screenGrid + ( scrlX / SCRNGRID_X ) + ( scrlY / SCRNGRID_Y ) * _gridSizeX ;
scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX ;
2003-12-16 02:10:15 +00:00
if ( diffX ) {
2004-01-03 12:29:21 +00:00
diffX = SCRNGRID_X - diffX ;
2003-12-16 02:10:15 +00:00
uint16 cpHeight = 0 ;
2004-01-03 12:29:21 +00:00
for ( uint16 cnty = 0 ; cnty < gridH ; cnty + + ) {
if ( * gridPos ) {
* gridPos > > = 1 ;
2003-12-16 02:10:15 +00:00
cpHeight + + ;
} else if ( cpHeight ) {
uint16 yPos = ( cnty - cpHeight ) * SCRNGRID_Y ;
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( scrnBuf + yPos * _scrnSizeX , _scrnSizeX , 0 , yPos + diffY + 40 , diffX , cpHeight * SCRNGRID_Y ) ;
2004-01-03 12:29:21 +00:00
cpHeight = 0 ;
2003-12-16 02:10:15 +00:00
}
2004-01-03 12:29:21 +00:00
gridPos + = _gridSizeX ;
}
2003-12-16 02:10:15 +00:00
if ( cpHeight ) {
uint16 yPos = ( gridH - cpHeight ) * SCRNGRID_Y ;
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( scrnBuf + yPos * _scrnSizeX , _scrnSizeX , 0 , yPos + diffY + 40 , diffX , SCREEN_DEPTH - ( yPos + diffY ) ) ;
2004-01-03 12:29:21 +00:00
}
scrlX + = diffX ;
}
// x scroll is compensated, too. check the rest of the screen, now.
2003-12-16 02:10:15 +00:00
scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX ;
2004-01-03 12:29:21 +00:00
gridPos = _screenGrid + ( scrlX / SCRNGRID_X ) + ( scrlY / SCRNGRID_Y ) * _gridSizeX ;
2003-12-16 02:10:15 +00:00
for ( uint16 cnty = 0 ; cnty < gridH ; cnty + + ) {
uint16 cpWidth = 0 ;
uint16 cpHeight = SCRNGRID_Y ;
if ( cnty = = gridH - 1 )
2004-01-04 17:40:51 +00:00
cpHeight = SCRNGRID_Y - diffY ;
2003-12-16 02:10:15 +00:00
for ( uint16 cntx = 0 ; cntx < gridW ; cntx + + )
2004-01-03 12:29:21 +00:00
if ( gridPos [ cntx ] ) {
gridPos [ cntx ] > > = 1 ;
2003-12-16 02:10:15 +00:00
cpWidth + + ;
} else if ( cpWidth ) {
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( scrnBuf + ( cntx - cpWidth ) * SCRNGRID_X , _scrnSizeX , ( cntx - cpWidth ) * SCRNGRID_X + diffX , cnty * SCRNGRID_Y + diffY + 40 , cpWidth * SCRNGRID_X , cpHeight ) ;
2004-01-03 12:29:21 +00:00
cpWidth = 0 ;
2003-12-16 02:10:15 +00:00
}
if ( cpWidth ) {
uint16 xPos = ( gridW - cpWidth ) * SCRNGRID_X ;
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( scrnBuf + xPos , _scrnSizeX , xPos + diffX , cnty * SCRNGRID_Y + diffY + 40 , SCREEN_WIDTH - ( xPos + diffX ) , cpHeight ) ;
2003-12-16 02:10:15 +00:00
}
gridPos + = _gridSizeX ;
scrnBuf + = _scrnSizeX * SCRNGRID_Y ;
}
}
2004-02-28 12:58:13 +00:00
_system - > updateScreen ( ) ;
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : newScreen ( uint32 screen ) {
2003-12-23 00:59:18 +00:00
uint8 cnt ;
2003-12-16 02:10:15 +00:00
// set sizes and scrolling, initialize/load screengrid, force screen refresh
_currentScreen = screen ;
_scrnSizeX = _roomDefTable [ screen ] . sizeX ;
_scrnSizeY = _roomDefTable [ screen ] . sizeY ;
_gridSizeX = _scrnSizeX / SCRNGRID_X ;
_gridSizeY = _scrnSizeY / SCRNGRID_Y ;
if ( ( _scrnSizeX % SCRNGRID_X ) | | ( _scrnSizeY % SCRNGRID_Y ) )
error ( " Illegal screensize: %d: %d/%d " , screen , _scrnSizeX , _scrnSizeY ) ;
if ( ( _scrnSizeX > SCREEN_WIDTH ) | | ( _scrnSizeY > SCREEN_DEPTH ) ) {
2004-01-11 15:47:41 +00:00
Logic : : _scriptVars [ SCROLL_FLAG ] = 2 ;
Logic : : _scriptVars [ MAX_SCROLL_OFFSET_X ] = _scrnSizeX - SCREEN_WIDTH ;
Logic : : _scriptVars [ MAX_SCROLL_OFFSET_Y ] = _scrnSizeY - SCREEN_DEPTH ;
2003-12-16 02:10:15 +00:00
} else {
2004-01-11 15:47:41 +00:00
Logic : : _scriptVars [ SCROLL_FLAG ] = 0 ;
Logic : : _scriptVars [ MAX_SCROLL_OFFSET_X ] = 0 ;
Logic : : _scriptVars [ MAX_SCROLL_OFFSET_Y ] = 0 ;
2003-12-16 02:10:15 +00:00
}
2005-11-04 15:40:54 +00:00
Logic : : _scriptVars [ SCROLL_OFFSET_X ] = 0 ;
Logic : : _scriptVars [ SCROLL_OFFSET_Y ] = 0 ;
2010-01-03 19:37:43 +00:00
free ( _screenBuf ) ;
free ( _screenGrid ) ;
2009-03-16 23:10:50 +00:00
if ( SwordEngine : : isPsx ( ) )
flushPsxCache ( ) ;
2003-12-16 02:10:15 +00:00
_screenBuf = ( uint8 * ) malloc ( _scrnSizeX * _scrnSizeY ) ;
_screenGrid = ( uint8 * ) malloc ( _gridSizeX * _gridSizeY ) ;
2004-01-03 12:29:21 +00:00
memset ( _screenGrid , 0 , _gridSizeX * _gridSizeY ) ;
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _roomDefTable [ _currentScreen ] . totalLayers ; cnt + + ) {
2003-12-17 01:47:47 +00:00
// open and lock all resources, will be closed in quitScreen()
2003-12-16 02:10:15 +00:00
_layerBlocks [ cnt ] = ( uint8 * ) _resMan - > openFetchRes ( _roomDefTable [ _currentScreen ] . layers [ cnt ] ) ;
2003-12-16 19:31:12 +00:00
if ( cnt > 0 )
_layerBlocks [ cnt ] + = sizeof ( Header ) ;
2003-12-16 02:10:15 +00:00
}
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _roomDefTable [ _currentScreen ] . totalLayers - 1 ; cnt + + ) {
2003-12-16 02:10:15 +00:00
// there's no grid for the background layer, so it's totalLayers - 1
_layerGrid [ cnt ] = ( uint16 * ) _resMan - > openFetchRes ( _roomDefTable [ _currentScreen ] . grids [ cnt ] ) ;
2008-01-28 00:14:17 +00:00
_layerGrid [ cnt ] + = 14 ;
2003-12-16 02:10:15 +00:00
}
_parallax [ 0 ] = _parallax [ 1 ] = NULL ;
if ( _roomDefTable [ _currentScreen ] . parallax [ 0 ] )
_parallax [ 0 ] = ( uint8 * ) _resMan - > openFetchRes ( _roomDefTable [ _currentScreen ] . parallax [ 0 ] ) ;
if ( _roomDefTable [ _currentScreen ] . parallax [ 1 ] )
_parallax [ 1 ] = ( uint8 * ) _resMan - > openFetchRes ( _roomDefTable [ _currentScreen ] . parallax [ 1 ] ) ;
2009-02-15 22:33:18 +00:00
_updatePalette = true ;
2004-01-03 12:29:21 +00:00
_fullRefresh = true ;
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
void Screen : : quitScreen ( ) {
2003-12-23 00:59:18 +00:00
uint8 cnt ;
2009-05-24 15:17:42 +00:00
if ( SwordEngine : : isPsx ( ) )
2009-03-16 23:10:50 +00:00
flushPsxCache ( ) ;
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _roomDefTable [ _currentScreen ] . totalLayers ; cnt + + )
2003-12-16 02:10:15 +00:00
_resMan - > resClose ( _roomDefTable [ _currentScreen ] . layers [ cnt ] ) ;
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _roomDefTable [ _currentScreen ] . totalLayers - 1 ; cnt + + )
2003-12-16 02:10:15 +00:00
_resMan - > resClose ( _roomDefTable [ _currentScreen ] . grids [ cnt ] ) ;
if ( _roomDefTable [ _currentScreen ] . parallax [ 0 ] )
_resMan - > resClose ( _roomDefTable [ _currentScreen ] . parallax [ 0 ] ) ;
if ( _roomDefTable [ _currentScreen ] . parallax [ 1 ] )
_resMan - > resClose ( _roomDefTable [ _currentScreen ] . parallax [ 1 ] ) ;
2004-11-09 04:06:10 +00:00
_currentScreen = 0xFFFF ;
2003-12-16 02:10:15 +00:00
}
2009-11-02 21:54:57 +00:00
void Screen : : draw ( ) {
2003-12-23 00:59:18 +00:00
uint8 cnt ;
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
debug ( 8 , " Screen::draw() -> _currentScreen %u " , _currentScreen ) ;
2009-05-24 15:17:42 +00:00
2003-12-21 17:34:44 +00:00
if ( _currentScreen = = 54 ) {
// rm54 has a BACKGROUND parallax layer in parallax[0]
2009-02-28 10:46:33 +00:00
if ( _parallax [ 0 ] & & ! SwordEngine : : isPsx ( ) ) //Avoid drawing this parallax on PSX edition, it gets occluded by background
2003-12-21 17:34:44 +00:00
renderParallax ( _parallax [ 0 ] ) ;
uint8 * src = _layerBlocks [ 0 ] ;
uint8 * dest = _screenBuf ;
2009-02-28 10:46:33 +00:00
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) ) {
2009-03-17 07:46:04 +00:00
if ( ! _psxCache . decodedBackground )
_psxCache . decodedBackground = psxShrinkedBackgroundToIndexed ( _layerBlocks [ 0 ] , _scrnSizeX , _scrnSizeY ) ;
2009-03-17 08:03:29 +00:00
memcpy ( _screenBuf , _psxCache . decodedBackground , _scrnSizeX * _scrnSizeY ) ;
} else {
uint16 scrnScrlY = MIN ( ( uint32 ) _oldScrollY , Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ) ;
uint16 scrnHeight = SCREEN_DEPTH + ABS ( ( int32 ) _oldScrollY - ( int32 ) Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ) ;
2009-03-17 08:22:51 +00:00
src + = scrnScrlY * _scrnSizeX ;
dest + = scrnScrlY * _scrnSizeX ;
2009-03-17 08:03:29 +00:00
// In this background to create transparency we have to iterate through all pixels, avoid checking those out of screen
for ( uint16 cnty = scrnScrlY ; ( cnty < _scrnSizeY ) & & ( cnty < scrnHeight + scrnScrlY ) ; cnty + + )
for ( uint16 cntx = 0 ; cntx < _scrnSizeX ; cntx + + ) {
2009-03-17 08:22:51 +00:00
if ( * src )
2009-03-17 08:03:29 +00:00
if ( ! ( SwordEngine : : isMac ( ) ) | | * src ! = 255 ) // see bug #1701058
2009-03-17 08:22:51 +00:00
* dest = * src ;
src + + ;
dest + + ;
2009-03-17 08:03:29 +00:00
}
}
2004-12-10 15:13:10 +00:00
2009-02-28 10:46:33 +00:00
} else if ( ! ( SwordEngine : : isPsx ( ) ) ) {
2003-12-21 17:34:44 +00:00
memcpy ( _screenBuf , _layerBlocks [ 0 ] , _scrnSizeX * _scrnSizeY ) ;
2009-02-28 10:46:33 +00:00
} else { //We are using PSX version
2009-09-30 16:16:53 +00:00
if ( _currentScreen = = 45 | | _currentScreen = = 55 | |
2009-03-16 23:10:50 +00:00
_currentScreen = = 57 | | _currentScreen = = 63 | | _currentScreen = = 71 ) { // Width shrinked backgrounds
2009-05-24 15:17:42 +00:00
if ( ! _psxCache . decodedBackground )
2009-03-16 23:10:50 +00:00
_psxCache . decodedBackground = psxShrinkedBackgroundToIndexed ( _layerBlocks [ 0 ] , _scrnSizeX , _scrnSizeY ) ;
} else {
if ( ! _psxCache . decodedBackground )
_psxCache . decodedBackground = psxBackgroundToIndexed ( _layerBlocks [ 0 ] , _scrnSizeX , _scrnSizeY ) ;
}
memcpy ( _screenBuf , _psxCache . decodedBackground , _scrnSizeX * _scrnSizeY ) ;
2009-02-28 10:46:33 +00:00
}
2003-12-16 02:10:15 +00:00
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _backLength ; cnt + + )
2003-12-16 02:10:15 +00:00
processImage ( _backList [ cnt ] ) ;
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _sortLength - 1 ; cnt + + )
2003-12-16 02:10:15 +00:00
for ( uint8 sCnt = 0 ; sCnt < _sortLength - 1 ; sCnt + + )
if ( _sortList [ sCnt ] . y > _sortList [ sCnt + 1 ] . y ) {
2003-12-19 14:16:31 +00:00
SWAP ( _sortList [ sCnt ] , _sortList [ sCnt + 1 ] ) ;
2003-12-16 02:10:15 +00:00
}
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _sortLength ; cnt + + )
2003-12-16 02:10:15 +00:00
processImage ( _sortList [ cnt ] . id ) ;
if ( ( _currentScreen ! = 54 ) & & _parallax [ 0 ] )
renderParallax ( _parallax [ 0 ] ) ; // screens other than 54 have FOREGROUND parallax layer in parallax[0]
if ( _parallax [ 1 ] )
renderParallax ( _parallax [ 1 ] ) ;
2009-05-24 15:17:42 +00:00
// PSX version has parallax layer for this room in an external file (TRAIN.PLX)
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) & & _currentScreen = = 63 ) {
2009-03-16 22:25:37 +00:00
// FIXME: this should be handled in a cleaner way...
2009-03-16 23:10:50 +00:00
if ( ! _psxCache . extPlxCache ) {
2009-05-24 15:17:42 +00:00
Common : : File parallax ;
2009-03-16 22:25:37 +00:00
parallax . open ( " TRAIN.PLX " ) ;
2009-03-16 23:10:50 +00:00
_psxCache . extPlxCache = ( uint8 * ) malloc ( parallax . size ( ) ) ;
parallax . read ( _psxCache . extPlxCache , parallax . size ( ) ) ;
2009-03-16 22:25:37 +00:00
parallax . close ( ) ;
}
2009-03-16 23:10:50 +00:00
renderParallax ( _psxCache . extPlxCache ) ;
2009-02-28 10:46:33 +00:00
}
2003-12-23 00:59:18 +00:00
for ( cnt = 0 ; cnt < _foreLength ; cnt + + )
2003-12-16 02:10:15 +00:00
processImage ( _foreList [ cnt ] ) ;
_backLength = _sortLength = _foreLength = 0 ;
}
2004-01-11 15:47:41 +00:00
void Screen : : processImage ( uint32 id ) {
Object * compact ;
2003-12-16 02:10:15 +00:00
FrameHeader * frameHead ;
int scale ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
compact = _objMan - > fetchObject ( id ) ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
if ( compact - > o_type = = TYPE_TEXT )
frameHead = _textMan - > giveSpriteData ( ( uint8 ) compact - > o_target ) ;
else
frameHead = _resMan - > fetchFrame ( _resMan - > openFetchRes ( compact - > o_resource ) , compact - > o_frame ) ;
2005-07-30 21:11:48 +00:00
2003-12-16 02:10:15 +00:00
uint8 * sprData = ( ( uint8 * ) frameHead ) + sizeof ( FrameHeader ) ;
uint16 spriteX = compact - > o_anim_x ;
uint16 spriteY = compact - > o_anim_y ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
if ( compact - > o_status & STAT_SHRINK ) {
scale = ( compact - > o_scale_a * compact - > o_ycoord + compact - > o_scale_b ) / 256 ;
2006-11-12 19:05:51 +00:00
spriteX + = ( ( int16 ) _resMan - > readUint16 ( & frameHead - > offsetX ) * scale ) / 256 ;
spriteY + = ( ( int16 ) _resMan - > readUint16 ( & frameHead - > offsetY ) * scale ) / 256 ;
2003-12-16 02:10:15 +00:00
} else {
scale = 256 ;
2006-11-12 19:05:51 +00:00
spriteX + = ( int16 ) _resMan - > readUint16 ( & frameHead - > offsetX ) ;
spriteY + = ( int16 ) _resMan - > readUint16 ( & frameHead - > offsetY ) ;
2003-12-16 02:10:15 +00:00
}
uint8 * tonyBuf = NULL ;
2009-02-28 10:46:33 +00:00
uint8 * hifBuf = NULL ;
if ( SwordEngine : : isPsx ( ) & & compact - > o_type ! = TYPE_TEXT ) { // PSX sprites are compressed with HIF
hifBuf = ( uint8 * ) malloc ( _resMan - > readUint16 ( & frameHead - > width ) * _resMan - > readUint16 ( & frameHead - > height ) / 2 ) ;
memset ( hifBuf , 0x00 , ( _resMan - > readUint16 ( & frameHead - > width ) * _resMan - > readUint16 ( & frameHead - > height ) / 2 ) ) ;
decompressHIF ( sprData , hifBuf ) ;
sprData = hifBuf ;
} else if ( frameHead - > runTimeComp [ 3 ] = = ' 7 ' ) { // RLE7 encoded?
2006-11-12 19:05:51 +00:00
decompressRLE7 ( sprData , _resMan - > readUint32 ( & frameHead - > compSize ) , _rleBuffer ) ;
2003-12-16 02:10:15 +00:00
sprData = _rleBuffer ;
} else if ( frameHead - > runTimeComp [ 3 ] = = ' 0 ' ) { // RLE0 encoded?
2006-11-12 19:05:51 +00:00
decompressRLE0 ( sprData , _resMan - > readUint32 ( & frameHead - > compSize ) , _rleBuffer ) ;
2003-12-16 02:10:15 +00:00
sprData = _rleBuffer ;
} else if ( frameHead - > runTimeComp [ 1 ] = = ' I ' ) { // new type
2006-11-12 19:05:51 +00:00
tonyBuf = ( uint8 * ) malloc ( _resMan - > readUint16 ( & frameHead - > width ) * _resMan - > readUint16 ( & frameHead - > height ) ) ;
decompressTony ( sprData , _resMan - > readUint32 ( & frameHead - > compSize ) , tonyBuf ) ;
2003-12-16 02:10:15 +00:00
sprData = tonyBuf ;
}
uint16 sprSizeX , sprSizeY ;
if ( compact - > o_status & STAT_SHRINK ) {
2009-02-28 10:46:33 +00:00
memset ( _shrinkBuffer , 0 , SHRINK_BUFFER_SIZE ) ; //Clean shrink buffer to avoid corruption
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) & & ( compact - > o_resource ! = GEORGE_MEGA ) ) { //PSX Height shrinked sprites
2009-02-28 10:46:33 +00:00
sprSizeX = ( scale * _resMan - > readUint16 ( & frameHead - > width ) ) / 256 ;
sprSizeY = ( scale * ( _resMan - > readUint16 ( & frameHead - > height ) ) ) / 256 / 2 ;
fastShrink ( sprData , _resMan - > readUint16 ( & frameHead - > width ) , ( _resMan - > readUint16 ( & frameHead - > height ) ) / 2 , scale , _shrinkBuffer ) ;
} else if ( SwordEngine : : isPsx ( ) ) { //PSX width/height shrinked sprites
sprSizeX = ( scale * _resMan - > readUint16 ( & frameHead - > width ) ) / 256 / 2 ;
sprSizeY = ( scale * _resMan - > readUint16 ( & frameHead - > height ) ) / 256 / 2 ;
fastShrink ( sprData , _resMan - > readUint16 ( & frameHead - > width ) / 2 , _resMan - > readUint16 ( & frameHead - > height ) / 2 , scale , _shrinkBuffer ) ;
} else {
sprSizeX = ( scale * _resMan - > readUint16 ( & frameHead - > width ) ) / 256 ;
sprSizeY = ( scale * _resMan - > readUint16 ( & frameHead - > height ) ) / 256 ;
fastShrink ( sprData , _resMan - > readUint16 ( & frameHead - > width ) , _resMan - > readUint16 ( & frameHead - > height ) , scale , _shrinkBuffer ) ;
}
2003-12-16 02:10:15 +00:00
sprData = _shrinkBuffer ;
} else {
2006-11-12 19:05:51 +00:00
sprSizeX = _resMan - > readUint16 ( & frameHead - > width ) ;
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) ) { //PSX sprites are half height
2009-02-28 10:46:33 +00:00
sprSizeY = _resMan - > readUint16 ( & frameHead - > height ) / 2 ;
} else
sprSizeY = ( _resMan - > readUint16 ( & frameHead - > height ) ) ;
2003-12-16 02:10:15 +00:00
}
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
if ( ! ( compact - > o_status & STAT_OVERRIDE ) ) {
//mouse size linked to exact size & coordinates of sprite box - shrink friendly
2006-11-12 19:05:51 +00:00
if ( _resMan - > readUint16 ( & frameHead - > offsetX ) | | _resMan - > readUint16 ( & frameHead - > offsetY ) ) {
2003-12-16 02:10:15 +00:00
//for megas the mouse area is reduced to account for sprite not
//filling the box size is reduced to 1/2 width, 4/5 height
compact - > o_mouse_x1 = spriteX + sprSizeX / 4 ;
compact - > o_mouse_x2 = spriteX + ( 3 * sprSizeX ) / 4 ;
compact - > o_mouse_y1 = spriteY + sprSizeY / 10 ;
compact - > o_mouse_y2 = spriteY + ( 9 * sprSizeY ) / 10 ;
} else {
compact - > o_mouse_x1 = spriteX ;
compact - > o_mouse_x2 = spriteX + sprSizeX ;
compact - > o_mouse_y1 = spriteY ;
compact - > o_mouse_y2 = spriteY + sprSizeY ;
}
}
2009-02-28 10:46:33 +00:00
2003-12-16 02:10:15 +00:00
uint16 sprPitch = sprSizeX ;
uint16 incr ;
spriteClipAndSet ( & spriteX , & spriteY , & sprSizeX , & sprSizeY , & incr ) ;
2009-02-28 10:46:33 +00:00
2003-12-16 02:10:15 +00:00
if ( ( sprSizeX > 0 ) & & ( sprSizeY > 0 ) ) {
2009-09-30 16:16:53 +00:00
if ( ( ! ( SwordEngine : : isPsx ( ) ) | | ( compact - > o_type = = TYPE_TEXT )
2009-03-30 12:11:22 +00:00
| | ( compact - > o_resource = = LVSFLY ) | | ( ! ( compact - > o_resource = = GEORGE_MEGA ) & & ( sprSizeX < 260 ) ) ) )
2009-02-28 10:46:33 +00:00
drawSprite ( sprData + incr , spriteX , spriteY , sprSizeX , sprSizeY , sprPitch ) ;
else if ( ( ( sprSizeX > = 260 ) & & ( sprSizeX < 450 ) ) | | ( ( compact - > o_resource = = GMWRITH ) & & ( sprSizeX < 515 ) ) // a psx shrinked sprite (1/2 width)
| | ( ( compact - > o_resource = = GMPOWER ) & & ( sprSizeX < 515 ) ) ) // some needs to be hardcoded, headers don't give useful infos
drawPsxHalfShrinkedSprite ( sprData + incr , spriteX , spriteY , sprSizeX / 2 , sprSizeY , sprPitch / 2 ) ;
else if ( sprSizeX > = 450 ) // A PSX double shrinked sprite (1/3 width)
drawPsxFullShrinkedSprite ( sprData + incr , spriteX , spriteY , sprSizeX / 3 , sprSizeY , sprPitch / 3 ) ;
else // This is for psx half shrinked, walking george and remaining sprites
drawPsxHalfShrinkedSprite ( sprData + incr , spriteX , spriteY , sprSizeX , sprSizeY , sprPitch ) ;
if ( ! ( compact - > o_status & STAT_FORE ) & & ! ( SwordEngine : : isPsx ( ) & & ( compact - > o_resource = = MOUBUSY ) ) ) // Check fixes moue sprite being masked by layer, happens only on psx
2003-12-16 02:10:15 +00:00
verticalMask ( spriteX , spriteY , sprSizeX , sprSizeY ) ;
}
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
if ( compact - > o_type ! = TYPE_TEXT )
_resMan - > resClose ( compact - > o_resource ) ;
2009-05-24 15:17:42 +00:00
2010-01-03 19:37:43 +00:00
free ( tonyBuf ) ;
free ( hifBuf ) ;
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : verticalMask ( uint16 x , uint16 y , uint16 bWidth , uint16 bHeight ) {
2003-12-16 02:10:15 +00:00
if ( _roomDefTable [ _currentScreen ] . totalLayers < = 1 )
return ;
2003-12-20 15:26:44 +00:00
2009-02-28 10:46:33 +00:00
if ( SwordEngine : : isPsx ( ) ) { // PSX sprites are vertical shrinked, and some width shrinked
bHeight * = 2 ;
bWidth * = 2 ;
}
2009-05-24 15:17:42 +00:00
2003-12-20 15:26:44 +00:00
bWidth = ( bWidth + ( x & ( SCRNGRID_X - 1 ) ) + ( SCRNGRID_X - 1 ) ) / SCRNGRID_X ;
bHeight = ( bHeight + ( y & ( SCRNGRID_Y - 1 ) ) + ( SCRNGRID_Y - 1 ) ) / SCRNGRID_Y ;
2003-12-16 02:10:15 +00:00
x / = SCRNGRID_X ;
y / = SCRNGRID_Y ;
if ( x + bWidth > _gridSizeX )
bWidth = _gridSizeX - x ;
if ( y + bHeight > _gridSizeY )
bHeight = _gridSizeY - y ;
2003-12-16 19:31:12 +00:00
uint16 gridY = y + SCREEN_TOP_EDGE / SCRNGRID_Y ; // imaginary screen on top
2003-12-22 11:51:27 +00:00
gridY + = bHeight - 1 ; // we start from the bottom edge
2003-12-16 19:31:12 +00:00
uint16 gridX = x + SCREEN_LEFT_EDGE / SCRNGRID_X ; // imaginary screen left
uint16 lGridSizeX = _gridSizeX + 2 * ( SCREEN_LEFT_EDGE / SCRNGRID_X ) ; // width of the grid for the imaginary screen
2003-12-16 02:10:15 +00:00
for ( uint16 blkx = 0 ; blkx < bWidth ; blkx + + ) {
2004-05-02 13:54:05 +00:00
// A sprite can be masked by several layers at the same time,
// so we have to check them all. See bug #917427.
for ( int16 level = _roomDefTable [ _currentScreen ] . totalLayers - 2 ; level > = 0 ; level - - ) {
if ( _layerGrid [ level ] [ gridX + blkx + gridY * lGridSizeX ] ) {
uint16 * grid = _layerGrid [ level ] + gridX + blkx + gridY * lGridSizeX ;
for ( int16 blky = bHeight - 1 ; blky > = 0 ; blky - - ) {
if ( * grid ) {
2009-02-28 10:46:33 +00:00
uint8 * blkData ;
if ( SwordEngine : : isPsx ( ) )
blkData = _layerBlocks [ level + 1 ] + ( _resMan - > readUint16 ( grid ) - 1 ) * 64 ; //PSX layers are half height too...
else
blkData = _layerBlocks [ level + 1 ] + ( _resMan - > readUint16 ( grid ) - 1 ) * 128 ;
2004-05-02 13:54:05 +00:00
blitBlockClear ( x + blkx , y + blky , blkData ) ;
2005-07-30 21:11:48 +00:00
} else
2004-05-02 13:54:05 +00:00
break ;
grid - = lGridSizeX ;
}
2003-12-16 02:10:15 +00:00
}
}
}
}
2004-01-11 15:47:41 +00:00
void Screen : : blitBlockClear ( uint16 x , uint16 y , uint8 * data ) {
2003-12-16 02:10:15 +00:00
uint8 * dest = _screenBuf + ( y * SCRNGRID_Y ) * _scrnSizeX + ( x * SCRNGRID_X ) ;
2009-02-28 10:46:33 +00:00
for ( uint8 cnty = 0 ; cnty < ( SwordEngine : : isPsx ( ) ? SCRNGRID_Y / 2 : SCRNGRID_Y ) ; cnty + + ) {
2003-12-16 02:10:15 +00:00
for ( uint8 cntx = 0 ; cntx < SCRNGRID_X ; cntx + + )
if ( data [ cntx ] )
dest [ cntx ] = data [ cntx ] ;
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
if ( SwordEngine : : isPsx ( ) ) {
dest + = _scrnSizeX ;
for ( uint8 cntx = 0 ; cntx < SCRNGRID_X ; cntx + + )
if ( data [ cntx ] )
dest [ cntx ] = data [ cntx ] ;
2009-05-24 15:17:42 +00:00
}
2003-12-16 02:10:15 +00:00
data + = SCRNGRID_X ;
dest + = _scrnSizeX ;
}
}
2004-01-11 15:47:41 +00:00
void Screen : : renderParallax ( uint8 * data ) {
2004-01-09 05:11:10 +00:00
uint16 paraScrlX , paraScrlY ;
uint16 scrnScrlX , scrnScrlY ;
uint16 scrnWidth , scrnHeight ;
2009-02-28 10:46:33 +00:00
uint16 paraSizeX , paraSizeY ;
ParallaxHeader * header = NULL ;
uint32 * lineIndexes = NULL ;
2009-03-02 10:59:14 +00:00
if ( SwordEngine : : isPsx ( ) ) //Parallax headers are different in PSX version
fetchPsxParallaxSize ( data , & paraSizeX , & paraSizeY ) ;
else {
2009-02-28 10:46:33 +00:00
header = ( ParallaxHeader * ) data ;
lineIndexes = ( uint32 * ) ( data + sizeof ( ParallaxHeader ) ) ;
paraSizeX = _resMan - > getUint16 ( header - > sizeX ) ;
paraSizeY = _resMan - > getUint16 ( header - > sizeY ) ;
}
assert ( ( paraSizeX > = SCREEN_WIDTH ) & & ( paraSizeY > = SCREEN_DEPTH ) ) ;
2004-01-09 05:11:10 +00:00
// we have to render more than the visible screen part for displaying scroll frames
2004-01-11 15:47:41 +00:00
scrnScrlX = MIN ( ( uint32 ) _oldScrollX , Logic : : _scriptVars [ SCROLL_OFFSET_X ] ) ;
scrnWidth = SCREEN_WIDTH + ABS ( ( int32 ) _oldScrollX - ( int32 ) Logic : : _scriptVars [ SCROLL_OFFSET_X ] ) ;
scrnScrlY = MIN ( ( uint32 ) _oldScrollY , Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ) ;
scrnHeight = SCREEN_DEPTH + ABS ( ( int32 ) _oldScrollY - ( int32 ) Logic : : _scriptVars [ SCROLL_OFFSET_Y ] ) ;
2003-12-20 13:43:40 +00:00
2009-02-28 10:46:33 +00:00
2003-12-20 13:43:40 +00:00
if ( _scrnSizeX ! = SCREEN_WIDTH ) {
2009-02-28 10:46:33 +00:00
double scrlfx = ( paraSizeX - SCREEN_WIDTH ) / ( ( double ) ( _scrnSizeX - SCREEN_WIDTH ) ) ;
2004-01-09 05:11:10 +00:00
paraScrlX = ( uint16 ) ( scrnScrlX * scrlfx ) ;
2003-12-20 13:43:40 +00:00
} else
2004-01-09 05:11:10 +00:00
paraScrlX = 0 ;
2003-12-20 13:43:40 +00:00
if ( _scrnSizeY ! = SCREEN_DEPTH ) {
2009-02-28 10:46:33 +00:00
double scrlfy = ( paraSizeY - SCREEN_DEPTH ) / ( ( double ) ( _scrnSizeY - SCREEN_DEPTH ) ) ;
2004-01-09 05:11:10 +00:00
paraScrlY = ( uint16 ) ( scrnScrlY * scrlfy ) ;
2003-12-20 13:43:40 +00:00
} else
2004-01-09 05:11:10 +00:00
paraScrlY = 0 ;
2004-12-10 15:13:10 +00:00
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) )
2009-03-02 10:59:14 +00:00
drawPsxParallax ( data , paraScrlX , scrnScrlX , scrnWidth ) ;
2009-02-28 10:46:33 +00:00
else
for ( uint16 cnty = 0 ; cnty < scrnHeight ; cnty + + ) {
uint8 * src = data + _resMan - > readUint32 ( lineIndexes + cnty + paraScrlY ) ;
uint8 * dest = _screenBuf + scrnScrlX + ( cnty + scrnScrlY ) * _scrnSizeX ;
uint16 remain = paraScrlX ;
uint16 xPos = 0 ;
while ( remain ) { // skip past the first part of the parallax to get to the right scrolling position
uint8 doSkip = * src + + ;
if ( doSkip < = remain )
remain - = doSkip ;
else {
xPos = doSkip - remain ;
dest + = xPos ;
remain = 0 ;
}
uint8 doCopy = * src + + ;
if ( doCopy < = remain ) {
remain - = doCopy ;
src + = doCopy ;
} else {
uint16 remCopy = doCopy - remain ;
memcpy ( dest , src + remain , remCopy ) ;
dest + = remCopy ;
2003-12-16 02:10:15 +00:00
src + = doCopy ;
2009-02-28 10:46:33 +00:00
xPos = remCopy ;
remain = 0 ;
}
}
while ( xPos < scrnWidth ) {
if ( uint8 skip = * src + + ) {
dest + = skip ;
xPos + = skip ;
}
if ( xPos < scrnWidth ) {
if ( uint8 doCopy = * src + + ) {
if ( xPos + doCopy > scrnWidth )
doCopy = scrnWidth - xPos ;
memcpy ( dest , src , doCopy ) ;
dest + = doCopy ;
xPos + = doCopy ;
src + = doCopy ;
}
2003-12-16 02:10:15 +00:00
}
}
}
}
2004-01-11 15:47:41 +00:00
void Screen : : drawSprite ( uint8 * sprData , uint16 sprX , uint16 sprY , uint16 sprWidth , uint16 sprHeight , uint16 sprPitch ) {
2003-12-16 02:10:15 +00:00
uint8 * dest = _screenBuf + ( sprY * _scrnSizeX ) + sprX ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
for ( uint16 cnty = 0 ; cnty < sprHeight ; cnty + + ) {
for ( uint16 cntx = 0 ; cntx < sprWidth ; cntx + + )
if ( sprData [ cntx ] )
dest [ cntx ] = sprData [ cntx ] ;
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
if ( SwordEngine : : isPsx ( ) ) { //On PSX version we need to double horizontal lines
2009-05-24 15:17:42 +00:00
dest + = _scrnSizeX ;
2009-02-28 10:46:33 +00:00
for ( uint16 cntx = 0 ; cntx < sprWidth ; cntx + + )
if ( sprData [ cntx ] )
dest [ cntx ] = sprData [ cntx ] ;
}
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
sprData + = sprPitch ;
dest + = _scrnSizeX ;
}
}
// Used to draw psx sprites which are 1/2 of original width
void Screen : : drawPsxHalfShrinkedSprite ( uint8 * sprData , uint16 sprX , uint16 sprY , uint16 sprWidth , uint16 sprHeight , uint16 sprPitch ) {
uint8 * dest = _screenBuf + ( sprY * _scrnSizeX ) + sprX ;
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
for ( uint16 cnty = 0 ; cnty < sprHeight ; cnty + + ) {
for ( uint16 cntx = 0 ; cntx < sprWidth ; cntx + + )
if ( sprData [ cntx ] ) {
dest [ cntx * 2 ] = sprData [ cntx ] ; //In these sprites we need to double vetical lines too...
dest [ cntx * 2 + 1 ] = sprData [ cntx ] ;
}
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
dest + = _scrnSizeX ;
for ( uint16 cntx = 0 ; cntx < sprWidth ; cntx + + )
if ( sprData [ cntx ] ) {
dest [ cntx * 2 ] = sprData [ cntx ] ;
dest [ cntx * 2 + 1 ] = sprData [ cntx ] ;
}
sprData + = sprPitch ;
2009-05-24 15:17:42 +00:00
dest + = _scrnSizeX ;
2009-02-28 10:46:33 +00:00
}
}
// Used to draw psx sprites which are 1/3 of original width
void Screen : : drawPsxFullShrinkedSprite ( uint8 * sprData , uint16 sprX , uint16 sprY , uint16 sprWidth , uint16 sprHeight , uint16 sprPitch ) {
uint8 * dest = _screenBuf + ( sprY * _scrnSizeX ) + sprX ;
for ( uint16 cnty = 0 ; cnty < sprHeight ; cnty + + ) {
for ( uint16 cntx = 0 ; cntx < sprWidth ; cntx + + )
if ( sprData [ cntx ] ) {
dest [ cntx * 3 ] = sprData [ cntx ] ; //In these sprites we need to double vertical lines too...
dest [ cntx * 3 + 1 ] = sprData [ cntx ] ;
dest [ cntx * 3 + 2 ] = sprData [ cntx ] ;
}
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
dest + = _scrnSizeX ;
for ( uint16 cntx = 0 ; cntx < sprWidth ; cntx + + )
if ( sprData [ cntx ] ) {
dest [ cntx * 3 ] = sprData [ cntx ] ;
dest [ cntx * 3 + 1 ] = sprData [ cntx ] ;
dest [ cntx * 3 + 2 ] = sprData [ cntx ] ;
}
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
sprData + = sprPitch ;
dest + = _scrnSizeX ;
}
}
// nearest neighbor filter:
2004-01-11 15:47:41 +00:00
void Screen : : fastShrink ( uint8 * src , uint32 width , uint32 height , uint32 scale , uint8 * dest ) {
2003-12-16 02:10:15 +00:00
uint32 resHeight = ( height * scale ) > > 8 ;
uint32 resWidth = ( width * scale ) > > 8 ;
uint32 step = 0x10000 / scale ;
uint8 columnTab [ 160 ] ;
uint32 res = step > > 1 ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
for ( uint16 cnt = 0 ; cnt < resWidth ; cnt + + ) {
columnTab [ cnt ] = ( uint8 ) ( res > > 8 ) ;
res + = step ;
}
uint32 newRow = step > > 1 ;
uint32 oldRow = 0 ;
2003-12-19 14:07:12 +00:00
uint8 * destPos = dest ;
2003-12-23 00:59:18 +00:00
uint16 lnCnt ;
for ( lnCnt = 0 ; lnCnt < resHeight ; lnCnt + + ) {
2003-12-16 02:10:15 +00:00
while ( oldRow < ( newRow > > 8 ) ) {
oldRow + + ;
src + = width ;
}
for ( uint16 colCnt = 0 ; colCnt < resWidth ; colCnt + + ) {
* destPos + + = src [ columnTab [ colCnt ] ] ;
}
newRow + = step ;
}
// scaled, now stipple shadows if there are any
2003-12-23 00:59:18 +00:00
for ( lnCnt = 0 ; lnCnt < resHeight ; lnCnt + + ) {
2003-12-16 02:10:15 +00:00
uint16 xCnt = lnCnt & 1 ;
destPos = dest + lnCnt * resWidth + ( lnCnt & 1 ) ;
while ( xCnt < resWidth ) {
if ( * destPos = = 200 )
* destPos = 0 ;
destPos + = 2 ;
xCnt + = 2 ;
}
}
}
2004-01-11 15:47:41 +00:00
void Screen : : addToGraphicList ( uint8 listId , uint32 objId ) {
2003-12-16 02:10:15 +00:00
if ( listId = = 0 ) {
2005-11-08 11:24:46 +00:00
assert ( _foreLength < MAX_FORE ) ;
2003-12-16 02:10:15 +00:00
_foreList [ _foreLength + + ] = objId ;
}
if ( listId = = 1 ) {
2005-11-08 11:24:46 +00:00
assert ( _sortLength < MAX_SORT ) ;
2004-01-11 15:47:41 +00:00
Object * cpt = _objMan - > fetchObject ( objId ) ;
2003-12-16 02:10:15 +00:00
_sortList [ _sortLength ] . id = objId ;
_sortList [ _sortLength ] . y = cpt - > o_anim_y ; // gives feet coords if boxed mega, otherwise top of sprite box
if ( ! ( cpt - > o_status & STAT_SHRINK ) ) { // not a boxed mega using shrinking
Header * frameRaw = ( Header * ) _resMan - > openFetchRes ( cpt - > o_resource ) ;
FrameHeader * frameHead = _resMan - > fetchFrame ( frameRaw , cpt - > o_frame ) ;
2006-11-12 19:05:51 +00:00
_sortList [ _sortLength ] . y + = _resMan - > readUint16 ( & frameHead - > height ) - 1 ; // now pointing to base of sprite
2003-12-16 02:10:15 +00:00
_resMan - > resClose ( cpt - > o_resource ) ;
}
_sortLength + + ;
}
if ( listId = = 2 ) {
2005-11-08 11:24:46 +00:00
assert ( _backLength < MAX_BACK ) ;
2003-12-16 02:10:15 +00:00
_backList [ _backLength + + ] = objId ;
}
}
2009-03-02 11:12:41 +00:00
uint8 * Screen : : psxBackgroundToIndexed ( uint8 * psxBackground , uint32 bakXres , uint32 bakYres ) {
2009-02-28 10:46:33 +00:00
uint32 xresInTiles = bakXres / 16 ;
uint32 yresInTiles = ( ( bakYres / 2 ) % 16 ) ? ( bakYres / 32 ) + 1 : ( bakYres / 32 ) ;
uint32 totTiles = xresInTiles * yresInTiles ;
uint32 tileYpos = 0 ; //tile position in a virtual xresInTiles * yresInTiles grid
uint32 tileXpos = 0 ;
uint32 tag = READ_LE_UINT32 ( psxBackground ) ;
uint8 * decomp_tile = ( uint8 * ) malloc ( 16 * 16 ) ; //Tiles are always 16 * 16
2009-03-02 11:30:23 +00:00
uint8 * fullres_buffer = ( uint8 * ) malloc ( bakXres * yresInTiles * 32 ) ;
2009-03-17 09:21:14 +00:00
memset ( fullres_buffer , 0 , bakXres * yresInTiles * 32 ) ;
2009-02-28 10:46:33 +00:00
bool isCompressed = ( tag = = 0x434F4D50 ) ;
psxBackground + = 4 ; //We skip the id tag
for ( uint32 currentTile = 0 ; currentTile < totTiles ; currentTile + + ) {
2009-05-24 15:17:42 +00:00
uint32 tileOffset = READ_LE_UINT32 ( psxBackground + 4 * currentTile ) ;
2009-09-30 16:16:53 +00:00
if ( isCompressed )
2009-02-28 10:46:33 +00:00
decompressHIF ( psxBackground + tileOffset - 4 , decomp_tile ) ; //Decompress the tile into decomp_tile
else
memcpy ( decomp_tile , psxBackground + tileOffset - 4 , 16 * 16 ) ;
if ( currentTile > 0 & & ! ( currentTile % xresInTiles ) ) { //Finished a line of tiles, going down
tileYpos + + ;
tileXpos = 0 ;
2009-05-24 15:17:42 +00:00
}
2009-03-02 13:46:50 +00:00
for ( byte tileLine = 0 ; tileLine < 16 ; tileLine + + ) { // Copy data to destination buffer
2009-05-24 15:17:42 +00:00
memcpy ( fullres_buffer + tileLine * bakXres * 2 + tileXpos * 16 + tileYpos * bakXres * 16 * 2 , decomp_tile + tileLine * 16 , 16 ) ;
2009-03-02 11:30:23 +00:00
memcpy ( fullres_buffer + tileLine * bakXres * 2 + bakXres + tileXpos * 16 + tileYpos * bakXres * 16 * 2 , decomp_tile + tileLine * 16 , 16 ) ;
}
2009-02-28 10:46:33 +00:00
tileXpos + + ;
}
free ( decomp_tile ) ;
return fullres_buffer ;
}
// needed because some psx backgrounds are half width and half height
2009-03-02 11:12:41 +00:00
uint8 * Screen : : psxShrinkedBackgroundToIndexed ( uint8 * psxBackground , uint32 bakXres , uint32 bakYres ) {
2009-02-28 10:46:33 +00:00
uint32 xresInTiles = ( bakXres / 2 ) % 16 ? ( bakXres / 32 ) + 1 : ( bakXres / 32 ) ;
uint32 yresInTiles = ( bakYres / 2 ) % 16 ? ( bakYres / 32 ) + 1 : ( bakYres / 32 ) ;
uint32 totTiles = xresInTiles * yresInTiles ;
uint32 tileYpos = 0 ; //tile position in a virtual xresInTiles * yresInTiles grid
uint32 tileXpos = 0 ;
uint32 dataBegin = READ_LE_UINT32 ( psxBackground + 4 ) ;
uint8 * decomp_tile = ( uint8 * ) malloc ( 16 * 16 ) ; //Tiles are always 16 * 16
2009-03-02 13:46:50 +00:00
uint8 * fullres_buffer = ( uint8 * ) malloc ( bakXres * ( yresInTiles + 1 ) * 32 ) ;
2009-03-17 09:21:14 +00:00
memset ( fullres_buffer , 0 , bakXres * ( yresInTiles + 1 ) * 32 ) ;
2009-02-28 10:46:33 +00:00
bool isCompressed = ( READ_LE_UINT32 ( psxBackground ) = = MKID_BE ( ' COMP ' ) ) ;
totTiles - = xresInTiles ;
psxBackground + = 4 ; //We skip the id tag
uint32 currentTile ;
for ( currentTile = 0 ; currentTile < totTiles ; currentTile + + ) {
2009-05-24 15:17:42 +00:00
uint32 tileOffset = READ_LE_UINT32 ( psxBackground + 4 * currentTile ) ;
2009-09-30 16:16:53 +00:00
if ( isCompressed )
2009-02-28 10:46:33 +00:00
decompressHIF ( psxBackground + tileOffset - 4 , decomp_tile ) ; //Decompress the tile into decomp_tile
else
memcpy ( decomp_tile , psxBackground + tileOffset - 4 , 16 * 16 ) ;
if ( currentTile > 0 & & ! ( currentTile % xresInTiles ) ) { //Finished a line of tiles, going down
tileYpos + + ;
tileXpos = 0 ;
2009-05-24 15:17:42 +00:00
}
2009-03-02 13:46:50 +00:00
for ( byte tileLine = 0 ; tileLine < 16 ; tileLine + + ) {
uint8 * dest = fullres_buffer + tileLine * bakXres * 2 + tileXpos * 32 + tileYpos * bakXres * 16 * 2 ;
for ( byte tileColumn = 0 ; tileColumn < 16 ; tileColumn + + ) {
uint8 pixData = * ( decomp_tile + tileColumn + tileLine * 16 ) ;
* ( dest + tileColumn * 2 ) = pixData ;
* ( dest + tileColumn * 2 + 1 ) = pixData ;
}
dest + = bakXres ;
for ( byte tileColumn = 0 ; tileColumn < 16 ; tileColumn + + ) {
uint8 pixData = * ( decomp_tile + tileColumn + tileLine * 16 ) ;
* ( dest + tileColumn * 2 ) = pixData ;
* ( dest + tileColumn * 2 + 1 ) = pixData ;
}
2009-02-28 10:46:33 +00:00
}
2009-03-02 13:46:50 +00:00
tileXpos + + ;
2009-02-28 10:46:33 +00:00
}
//Calculate number of remaining tiles
uint32 remainingTiles = ( dataBegin - ( currentTile * 4 + 4 ) ) / 4 ;
2009-03-02 13:46:50 +00:00
// Last line of tiles is full width!
2009-02-28 10:46:33 +00:00
uint32 tileHeight = ( remainingTiles = = xresInTiles * 2 ) ? 16 : 8 ;
tileXpos = 0 ;
for ( ; currentTile < totTiles + remainingTiles ; currentTile + + ) {
2009-05-24 15:17:42 +00:00
uint32 tileOffset = READ_LE_UINT32 ( psxBackground + 4 * currentTile ) ;
2009-02-28 10:46:33 +00:00
2009-09-30 16:16:53 +00:00
if ( isCompressed )
2009-02-28 10:46:33 +00:00
decompressHIF ( psxBackground + tileOffset - 4 , decomp_tile ) ; //Decompress the tile into decomp_tile
else
memcpy ( decomp_tile , psxBackground + tileOffset - 4 , 256 ) ;
2009-03-02 13:46:50 +00:00
for ( byte tileLine = 0 ; tileLine < tileHeight ; tileLine + + ) { // Write the decoded tiles into last lines of background
2009-05-24 15:17:42 +00:00
memcpy ( fullres_buffer + tileXpos * 16 + ( tileLine + ( yresInTiles - 1 ) * 16 ) * bakXres * 2 , decomp_tile + tileLine * 16 , 16 ) ;
2009-03-02 13:46:50 +00:00
memcpy ( fullres_buffer + tileXpos * 16 + ( tileLine + ( yresInTiles - 1 ) * 16 ) * bakXres * 2 + bakXres , decomp_tile + tileLine * 16 , 16 ) ;
}
2009-02-28 10:46:33 +00:00
tileXpos + + ;
}
free ( decomp_tile ) ;
return fullres_buffer ;
}
2009-03-02 10:59:14 +00:00
void Screen : : fetchPsxParallaxSize ( uint8 * psxParallax , uint16 * paraSizeX , uint16 * paraSizeY ) {
2009-02-28 10:46:33 +00:00
uint16 xresInTiles = READ_LE_UINT16 ( psxParallax + 10 ) ;
uint16 yresInTiles = READ_LE_UINT16 ( psxParallax + 12 ) ;
2009-03-02 10:59:14 +00:00
* paraSizeX = xresInTiles * 16 ;
* paraSizeY = yresInTiles * 32 ; // Vertical resolution needs to be doubled
}
2009-02-28 10:46:33 +00:00
2009-03-02 10:59:14 +00:00
void Screen : : drawPsxParallax ( uint8 * psxParallax , uint16 paraScrlX , uint16 scrnScrlX , uint16 scrnWidth ) {
uint16 totTiles = READ_LE_UINT16 ( psxParallax + 14 ) ; // Total tiles
2009-02-28 10:46:33 +00:00
2009-03-02 10:59:14 +00:00
uint16 skipRow = paraScrlX / 16 ; // Rows of tiles we have to skip
uint8 leftPixelSkip = paraScrlX % 16 ; // Pixel columns we have to skip while drawing the first row
2009-02-28 10:46:33 +00:00
2009-03-02 10:59:14 +00:00
uint8 * plxPos = psxParallax + 16 ; // Pointer to tile position header section
uint8 * plxOff = psxParallax + 16 + totTiles * 2 ; // Pointer to tile relative offsets section
uint8 * plxData = psxParallax + 16 + totTiles * 2 + totTiles * 4 ; //Pointer to beginning of tiles data section
2009-02-28 10:46:33 +00:00
2009-03-02 10:59:14 +00:00
uint8 * tile_buffer = ( uint8 * ) malloc ( 16 * 16 ) ; // Buffer for 16x16 pix tile
2009-02-28 10:46:33 +00:00
2009-03-02 10:59:14 +00:00
/* For parallax rendering we should check both horizontal and vertical scrolling,
* but in PSX edition of the game , the only vertical scrolling parallax is disabled .
* So , in this function i ' ll only check for horizontal scrolling .
*/
for ( uint16 currentTile = 0 ; currentTile < totTiles - 1 ; currentTile + + ) {
uint8 tileXpos = * ( plxPos + 2 * currentTile ) ; // Fetch tile X and Y position in the grid
uint8 tileYpos = * ( plxPos + 2 * currentTile + 1 ) * 2 ;
int32 tileBegin = ( tileXpos * 16 ) - paraScrlX ;
tileBegin = ( tileBegin < 0 ) ? 0 : tileBegin ;
uint16 currentLine = ( tileYpos * 16 ) ; //Current line of the image we are drawing upon, used to avoid going out of screen
2009-05-24 15:17:42 +00:00
2009-03-02 10:59:14 +00:00
if ( tileXpos > = skipRow ) { // Tiles not needed in the screen buffer are not uncompressed
uint32 tileOffset = READ_LE_UINT32 ( plxOff + 4 * currentTile ) ;
2009-05-24 15:17:42 +00:00
uint16 rightScreenLimit = _scrnSizeX - scrnScrlX ; // Do not write over and beyond this limit, lest we get memory corruption
2009-03-02 10:59:14 +00:00
uint8 * dest = _screenBuf + ( tileYpos * 16 * _scrnSizeX ) + tileBegin + scrnScrlX ;
uint8 * src = tile_buffer ;
decompressHIF ( plxData + tileOffset , tile_buffer ) ; // Decompress the tile
if ( tileXpos ! = skipRow ) { // This tile will surely be drawn fully in the buffer
for ( byte tileLine = 0 ; ( tileLine < 16 ) & & ( currentLine < SCREEN_DEPTH ) ; tileLine + + ) { // Check that we are not going outside the bottom screen part
2009-05-24 15:17:42 +00:00
for ( byte tileColumn = 0 ; ( tileColumn < 16 ) & & ( tileBegin + tileColumn ) < rightScreenLimit ; tileColumn + + )
if ( * ( src + tileColumn ) ) * ( dest + tileColumn ) = * ( src + tileColumn ) ;
dest + = _scrnSizeX ;
2009-03-02 10:59:14 +00:00
currentLine + + ;
if ( currentLine < SCREEN_DEPTH ) {
2009-05-24 15:17:42 +00:00
for ( byte tileColumn = 0 ; ( tileColumn < 16 ) & & ( tileBegin + tileColumn ) < rightScreenLimit ; tileColumn + + )
if ( * ( src + tileColumn ) ) * ( dest + tileColumn ) = * ( src + tileColumn ) ;
dest + = _scrnSizeX ;
2009-03-02 10:59:14 +00:00
currentLine + + ;
}
src + = 16 ; // get to next line of decoded tile
}
} else { // This tile may be drawn only partially
src + = leftPixelSkip ; //Skip hidden pixels
for ( byte tileLine = 0 ; ( tileLine < 16 ) & & ( currentLine < SCREEN_DEPTH ) ; tileLine + + ) {
2009-05-24 15:17:42 +00:00
for ( byte tileColumn = 0 ; tileColumn < ( 16 - leftPixelSkip ) ; tileColumn + + )
if ( * ( src + tileColumn ) ) * ( dest + tileColumn ) = * ( src + tileColumn ) ;
dest + = _scrnSizeX ;
2009-03-02 10:59:14 +00:00
currentLine + + ;
if ( currentLine < SCREEN_DEPTH ) {
2009-05-24 15:17:42 +00:00
for ( byte tileColumn = 0 ; tileColumn < ( 16 - leftPixelSkip ) ; tileColumn + + )
if ( * ( src + tileColumn ) ) * ( dest + tileColumn ) = * ( src + tileColumn ) ;
dest + = _scrnSizeX ;
2009-03-02 10:59:14 +00:00
currentLine + + ;
}
src + = 16 ;
}
}
}
}
2009-02-28 10:46:33 +00:00
2009-03-02 10:59:14 +00:00
free ( tile_buffer ) ;
2009-02-28 10:46:33 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : decompressTony ( uint8 * src , uint32 compSize , uint8 * dest ) {
2003-12-16 02:10:15 +00:00
uint8 * endOfData = src + compSize ;
while ( src < endOfData ) {
uint8 numFlat = * src + + ;
if ( numFlat ) {
memset ( dest , * src , numFlat ) ;
src + + ;
dest + = numFlat ;
}
if ( src < endOfData ) {
uint8 numNoFlat = * src + + ;
memcpy ( dest , src , numNoFlat ) ;
src + = numNoFlat ;
dest + = numNoFlat ;
}
}
}
2004-01-11 15:47:41 +00:00
void Screen : : decompressRLE7 ( uint8 * src , uint32 compSize , uint8 * dest ) {
2003-12-16 02:10:15 +00:00
uint8 * compBufEnd = src + compSize ;
while ( src < compBufEnd ) {
uint8 code = * src + + ;
if ( ( code > 127 ) | | ( code = = 0 ) )
* dest + + = code ;
else {
code + + ;
memset ( dest , * src + + , code ) ;
dest + = code ;
}
}
}
2004-01-11 15:47:41 +00:00
void Screen : : decompressRLE0 ( uint8 * src , uint32 compSize , uint8 * dest ) {
2003-12-16 02:10:15 +00:00
uint8 * srcBufEnd = src + compSize ;
while ( src < srcBufEnd ) {
uint8 color = * src + + ;
if ( color ) {
2004-01-03 12:29:21 +00:00
* dest + + = color ;
2003-12-16 02:10:15 +00:00
} else {
uint8 skip = * src + + ;
2004-01-03 12:29:21 +00:00
memset ( dest , 0 , skip ) ;
dest + = skip ;
2003-12-16 02:10:15 +00:00
}
}
}
2009-02-28 10:46:33 +00:00
void Screen : : decompressHIF ( uint8 * src , uint8 * dest ) {
for ( ; ; ) { //Main loop
byte control_byte = * src + + ;
uint32 byte_count = 0 ;
while ( byte_count < 8 ) {
if ( control_byte & 0x80 ) {
uint16 info_word = READ_BE_UINT16 ( src ) ; //Read the info word
src + = 2 ;
if ( info_word = = 0xFFFF ) return ; //Got 0xFFFF code, finished.
2009-05-24 15:17:42 +00:00
int32 repeat_count = ( info_word > > 12 ) + 2 ; //How many time data needs to be refetched
2009-09-30 16:16:53 +00:00
while ( repeat_count > = 0 ) {
2009-05-24 15:17:42 +00:00
uint8 * old_data_src = dest - ( ( info_word & 0xFFF ) + 1 ) ;
2009-02-28 10:46:33 +00:00
* dest + + = * old_data_src ;
repeat_count - - ;
}
} else
* dest + + = * src + + ;
byte_count + + ;
control_byte < < = 1 ; //Shifting left the control code one bit
}
}
}
2009-11-02 21:54:57 +00:00
void Screen : : flushPsxCache ( ) {
2009-03-16 23:10:50 +00:00
if ( _psxCache . decodedBackground ) {
free ( _psxCache . decodedBackground ) ;
_psxCache . decodedBackground = NULL ;
}
if ( _psxCache . extPlxCache ) {
free ( _psxCache . extPlxCache ) ;
_psxCache . extPlxCache = NULL ;
}
}
2009-11-02 21:54:57 +00:00
void Screen : : fadePalette ( ) {
2003-12-16 02:10:15 +00:00
if ( _fadingStep = = 16 )
memcpy ( _currentPalette , _targetPalette , 256 * 4 ) ;
2004-01-07 19:08:59 +00:00
else if ( ( _fadingStep = = 1 ) & & ( _fadingDirection = = FADE_DOWN ) ) {
memset ( _currentPalette , 0 , 4 * 256 ) ;
} else
2003-12-16 02:10:15 +00:00
for ( uint16 cnt = 0 ; cnt < 256 * 4 ; cnt + + )
_currentPalette [ cnt ] = ( _targetPalette [ cnt ] * _fadingStep ) > > 4 ;
_fadingStep + = _fadingDirection ;
2003-12-17 07:33:00 +00:00
if ( _fadingStep = = 17 ) {
2003-12-16 02:10:15 +00:00
_fadingStep = 0 ;
2003-12-17 07:33:00 +00:00
_isBlack = false ;
} else if ( _fadingStep = = 0 )
_isBlack = true ;
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : fnSetParallax ( uint32 screen , uint32 resId ) {
2003-12-16 02:10:15 +00:00
_roomDefTable [ screen ] . parallax [ 0 ] = resId ;
}
2004-01-11 15:47:41 +00:00
void Screen : : spriteClipAndSet ( uint16 * pSprX , uint16 * pSprY , uint16 * pSprWidth , uint16 * pSprHeight , uint16 * incr ) {
2003-12-16 02:10:15 +00:00
int16 sprX = * pSprX - SCREEN_LEFT_EDGE ;
int16 sprY = * pSprY - SCREEN_TOP_EDGE ;
int16 sprW = * pSprWidth ;
int16 sprH = * pSprHeight ;
2005-07-30 21:11:48 +00:00
2003-12-16 02:10:15 +00:00
if ( sprY < 0 ) {
* incr = ( uint16 ) ( ( - sprY ) * sprW ) ;
sprH + = sprY ;
sprY = 0 ;
} else
* incr = 0 ;
if ( sprX < 0 ) {
* incr - = sprX ;
sprW + = sprX ;
sprX = 0 ;
}
2005-07-30 21:11:48 +00:00
2003-12-16 02:10:15 +00:00
if ( sprY + sprH > _scrnSizeY )
sprH = _scrnSizeY - sprY ;
if ( sprX + sprW > _scrnSizeX )
sprW = _scrnSizeX - sprX ;
2003-12-19 14:07:12 +00:00
2003-12-16 02:10:15 +00:00
if ( sprH < 0 )
* pSprHeight = 0 ;
else
* pSprHeight = ( uint16 ) sprH ;
if ( sprW < 0 )
* pSprWidth = 0 ;
else
* pSprWidth = ( uint16 ) sprW ;
2009-05-24 15:17:42 +00:00
2003-12-16 02:10:15 +00:00
* pSprX = ( uint16 ) sprX ;
* pSprY = ( uint16 ) sprY ;
2004-01-03 10:49:08 +00:00
2004-02-22 16:31:32 +00:00
if ( * pSprWidth & & * pSprHeight ) {
2005-11-08 11:24:46 +00:00
// sprite will be drawn, so mark it in the grid buffer
2004-01-03 12:29:21 +00:00
uint16 gridH = ( * pSprHeight + ( sprY & ( SCRNGRID_Y - 1 ) ) + ( SCRNGRID_Y - 1 ) ) / SCRNGRID_Y ;
uint16 gridW = ( * pSprWidth + ( sprX & ( SCRNGRID_X - 1 ) ) + ( SCRNGRID_X - 1 ) ) / SCRNGRID_X ;
2009-05-24 15:17:42 +00:00
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) ) {
2009-02-28 10:46:33 +00:00
gridH * = 2 ; // This will correct the PSX sprite being cut at half height
gridW * = 2 ; // and masking problems when sprites are stretched in width
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
uint16 bottomSprPos = ( * pSprY + ( * pSprHeight ) * 2 ) ; //Position of bottom line of sprite
if ( bottomSprPos > _scrnSizeY ) { //Check that resized psx sprite isn't drawn outside of screen boundaries
uint16 outScreen = bottomSprPos - _scrnSizeY ;
* pSprHeight - = ( outScreen % 2 ) ? ( outScreen + 1 ) / 2 : outScreen / 2 ;
}
2009-05-24 15:17:42 +00:00
}
2009-02-28 10:46:33 +00:00
2004-01-03 10:49:08 +00:00
uint16 gridX = sprX / SCRNGRID_X ;
uint16 gridY = sprY / SCRNGRID_Y ;
uint8 * gridBuf = _screenGrid + gridX + gridY * _gridSizeX ;
if ( gridX + gridW > _gridSizeX )
gridW = _gridSizeX - gridX ;
if ( gridY + gridH > _gridSizeY )
gridH = _gridSizeY - gridY ;
for ( uint16 cnty = 0 ; cnty < gridH ; cnty + + ) {
for ( uint16 cntx = 0 ; cntx < gridW ; cntx + + )
2004-01-03 12:29:21 +00:00
gridBuf [ cntx ] = 2 ;
2004-01-03 10:49:08 +00:00
gridBuf + = _gridSizeX ;
}
2003-12-16 02:10:15 +00:00
}
}
2004-01-11 15:47:41 +00:00
void Screen : : fnFlash ( uint8 color ) {
warning ( " stub: Screen::fnFlash(%d) " , color ) ;
2003-12-17 01:47:47 +00:00
}
2004-01-11 15:47:41 +00:00
// ------------------- Menu screen interface ---------------------------
2003-12-17 01:47:47 +00:00
2004-01-11 15:47:41 +00:00
void Screen : : showFrame ( uint16 x , uint16 y , uint32 resId , uint32 frameNo , const byte * fadeMask , int8 fadeStatus ) {
2003-12-21 17:55:40 +00:00
uint8 frame [ 40 * 40 ] ;
int i , j ;
2009-09-30 16:16:53 +00:00
if ( SwordEngine : : isPsx ( ) )
2009-05-24 15:17:42 +00:00
memset ( frame , 0 , sizeof ( frame ) ) ; // PSX top menu is black
2009-02-28 10:46:33 +00:00
else
memset ( frame , 199 , sizeof ( frame ) ) ; // Dark gray background
2003-12-21 17:55:40 +00:00
if ( resId ! = 0xffffffff ) {
FrameHeader * frameHead = _resMan - > fetchFrame ( _resMan - > openFetchRes ( resId ) , frameNo ) ;
uint8 * frameData = ( ( uint8 * ) frameHead ) + sizeof ( FrameHeader ) ;
2009-02-28 10:46:33 +00:00
if ( SwordEngine : : isPsx ( ) ) { //We need to decompress PSX frames
uint8 * frameBufferPSX = ( uint8 * ) malloc ( _resMan - > getUint16 ( frameHead - > width ) * _resMan - > getUint16 ( frameHead - > height ) / 2 ) ;
decompressHIF ( frameData , frameBufferPSX ) ;
for ( i = 0 ; i < _resMan - > getUint16 ( frameHead - > height ) / 2 ; i + + ) {
for ( j = 0 ; j < _resMan - > getUint16 ( frameHead - > width ) ; j + + ) {
uint8 data = frameBufferPSX [ i * _resMan - > getUint16 ( frameHead - > width ) + j ] ;
frame [ ( i * 2 + 4 ) * 40 + j + 2 ] = data ;
frame [ ( i * 2 + 1 + 4 ) * 40 + j + 2 ] = data ; //Linedoubling the sprite
}
2003-12-21 17:55:40 +00:00
}
2009-05-24 15:17:42 +00:00
2009-02-28 10:46:33 +00:00
free ( frameBufferPSX ) ;
} else {
2009-05-24 15:17:42 +00:00
for ( i = 0 ; i < _resMan - > getUint16 ( frameHead - > height ) ; i + + )
for ( j = 0 ; j < _resMan - > getUint16 ( frameHead - > height ) ; j + + )
2009-02-28 10:46:33 +00:00
frame [ ( i + 4 ) * 40 + j + 2 ] = frameData [ i * _resMan - > getUint16 ( frameHead - > width ) + j ] ;
2003-12-21 17:55:40 +00:00
}
_resMan - > resClose ( resId ) ;
}
if ( fadeMask ) {
for ( i = 0 ; i < 40 ; i + + ) {
for ( j = 0 ; j < 40 ; j + + ) {
if ( fadeMask [ ( ( i % 8 ) * 8 ) + ( j % 8 ) ] > = fadeStatus )
frame [ i * 40 + j ] = 0 ;
}
}
}
2004-03-28 16:30:50 +00:00
_system - > copyRectToScreen ( frame , 40 , x , y , 40 , 40 ) ;
2003-12-16 02:10:15 +00:00
}
// ------------------- router debugging code --------------------------------
2004-01-11 15:47:41 +00:00
void Screen : : vline ( uint16 x , uint16 y1 , uint16 y2 ) {
2003-12-16 02:10:15 +00:00
for ( uint16 cnty = y1 ; cnty < = y2 ; cnty + + )
_screenBuf [ x + _scrnSizeX * cnty ] = 0 ;
}
2004-01-11 15:47:41 +00:00
void Screen : : hline ( uint16 x1 , uint16 x2 , uint16 y ) {
2003-12-19 14:07:12 +00:00
for ( uint16 cntx = x1 ; cntx < = x2 ; cntx + + )
2003-12-16 02:10:15 +00:00
_screenBuf [ y * _scrnSizeX + cntx ] = 0 ;
}
2004-01-11 15:47:41 +00:00
void Screen : : bsubline_1 ( uint16 x1 , uint16 y1 , uint16 x2 , uint16 y2 ) {
2003-12-16 02:10:15 +00:00
int x , y , ddx , ddy , e ;
2003-12-19 14:16:31 +00:00
ddx = ABS ( x2 - x1 ) ;
ddy = ABS ( y2 - y1 ) < < 1 ;
2003-12-19 14:07:12 +00:00
e = ddx - ddy ;
ddx < < = 1 ;
if ( x1 > x2 ) {
2003-12-16 02:10:15 +00:00
uint16 tmp ;
tmp = x1 ; x1 = x2 ; x2 = tmp ;
tmp = y1 ; y1 = y2 ; y2 = tmp ;
2003-12-19 14:07:12 +00:00
}
for ( x = x1 , y = y1 ; x < = x2 ; x + + ) {
2003-12-16 02:10:15 +00:00
_screenBuf [ y * _scrnSizeX + x ] = 0 ;
if ( e < 0 ) {
2003-12-19 14:07:12 +00:00
y + + ;
e + = ddx - ddy ;
2003-12-16 02:10:15 +00:00
} else {
2003-12-19 14:07:12 +00:00
e - = ddy ;
2003-12-16 02:10:15 +00:00
}
2003-12-19 14:07:12 +00:00
}
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : bsubline_2 ( uint16 x1 , uint16 y1 , uint16 x2 , uint16 y2 ) {
2003-12-16 02:10:15 +00:00
int x , y , ddx , ddy , e ;
2003-12-19 14:16:31 +00:00
ddx = ABS ( x2 - x1 ) < < 1 ;
ddy = ABS ( y2 - y1 ) ;
2003-12-19 14:07:12 +00:00
e = ddy - ddx ;
ddy < < = 1 ;
if ( y1 > y2 ) {
2003-12-16 02:10:15 +00:00
uint16 tmp ;
tmp = x1 ; x1 = x2 ; x2 = tmp ;
tmp = y1 ; y1 = y2 ; y2 = tmp ;
2003-12-19 14:07:12 +00:00
}
for ( y = y1 , x = x1 ; y < = y2 ; y + + ) {
2003-12-16 02:10:15 +00:00
_screenBuf [ y * _scrnSizeX + x ] = 0 ;
if ( e < 0 ) {
x + + ;
e + = ddy - ddx ;
} else {
e - = ddx ;
}
2003-12-19 14:07:12 +00:00
}
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : bsubline_3 ( uint16 x1 , uint16 y1 , uint16 x2 , uint16 y2 ) {
2003-12-16 02:10:15 +00:00
int x , y , ddx , ddy , e ;
2003-12-19 14:16:31 +00:00
ddx = ABS ( x1 - x2 ) < < 1 ;
ddy = ABS ( y2 - y1 ) ;
2003-12-19 14:07:12 +00:00
e = ddy - ddx ;
ddy < < = 1 ;
if ( y1 > y2 ) {
2003-12-16 02:10:15 +00:00
uint16 tmp ;
tmp = x1 ; x1 = x2 ; x2 = tmp ;
tmp = y1 ; y1 = y2 ; y2 = tmp ;
2003-12-19 14:07:12 +00:00
}
2003-12-16 02:10:15 +00:00
2003-12-19 14:07:12 +00:00
for ( y = y1 , x = x1 ; y < = y2 ; y + + ) {
2003-12-16 02:10:15 +00:00
_screenBuf [ y * _scrnSizeX + x ] = 0 ;
if ( e < 0 ) {
x - - ;
2003-12-19 14:07:12 +00:00
e + = ddy - ddx ;
2003-12-16 02:10:15 +00:00
} else {
e - = ddx ;
}
2003-12-19 14:07:12 +00:00
}
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : bsubline_4 ( uint16 x1 , uint16 y1 , uint16 x2 , uint16 y2 ) {
2003-12-16 02:10:15 +00:00
int x , y , ddx , ddy , e ;
2003-12-19 14:16:31 +00:00
ddy = ABS ( y2 - y1 ) < < 1 ;
ddx = ABS ( x1 - x2 ) ;
2003-12-19 14:07:12 +00:00
e = ddx - ddy ;
ddx < < = 1 ;
if ( x1 > x2 ) {
2003-12-16 02:10:15 +00:00
uint16 tmp ;
tmp = x1 ; x1 = x2 ; x2 = tmp ;
tmp = y1 ; y1 = y2 ; y2 = tmp ;
2003-12-19 14:07:12 +00:00
}
for ( x = x1 , y = y1 ; x < = x2 ; x + + ) {
2003-12-16 02:10:15 +00:00
_screenBuf [ y * _scrnSizeX + x ] = 0 ;
if ( e < 0 ) {
2003-12-19 14:07:12 +00:00
y - - ;
e + = ddx - ddy ;
2003-12-16 02:10:15 +00:00
} else {
2003-12-19 14:07:12 +00:00
e - = ddy ;
2003-12-16 02:10:15 +00:00
}
2003-12-19 14:07:12 +00:00
}
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
void Screen : : drawLine ( uint16 x1 , uint16 y1 , uint16 x2 , uint16 y2 ) {
2003-12-16 02:10:15 +00:00
if ( ( x1 = = x2 ) & & ( y1 = = y2 ) ) {
_screenBuf [ x1 + y1 * _scrnSizeX ] = 0 ;
}
2003-12-19 14:07:12 +00:00
if ( x1 = = x2 ) {
2003-12-16 06:37:12 +00:00
vline ( x1 , MIN ( y1 , y2 ) , MAX ( y1 , y2 ) ) ;
2003-12-16 02:10:15 +00:00
return ;
2003-12-19 14:07:12 +00:00
}
if ( y1 = = y2 ) {
2003-12-16 06:37:12 +00:00
hline ( MIN ( x1 , x2 ) , MAX ( x1 , x2 ) , y1 ) ;
2003-12-16 02:10:15 +00:00
return ;
2003-12-19 14:07:12 +00:00
}
float k = float ( y2 - y1 ) / float ( x2 - x1 ) ;
2003-12-16 02:10:15 +00:00
2003-12-19 14:07:12 +00:00
if ( ( k > = 0 ) & & ( k < = 1 ) ) {
2003-12-16 02:10:15 +00:00
bsubline_1 ( x1 , y1 , x2 , y2 ) ;
2003-12-19 14:07:12 +00:00
} else if ( k > 1 ) {
2003-12-16 02:10:15 +00:00
bsubline_2 ( x1 , y1 , x2 , y2 ) ;
2003-12-19 14:07:12 +00:00
} else if ( ( k < 0 ) & & ( k > = - 1 ) ) {
2003-12-16 02:10:15 +00:00
bsubline_4 ( x1 , y1 , x2 , y2 ) ;
2003-12-19 14:07:12 +00:00
} else {
2003-12-16 02:10:15 +00:00
bsubline_3 ( x1 , y1 , x2 , y2 ) ;
2003-12-19 14:07:12 +00:00
}
2003-12-16 02:10:15 +00:00
}
2004-01-11 15:47:41 +00:00
} // End of namespace Sword1