2013-07-24 11:13:57 -05: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 .
* 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 .
* 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 .
*
*/
# include "common/scummsys.h"
2013-07-29 10:59:09 -05:00
# include "graphics/colormasks.h"
2013-07-24 11:13:57 -05:00
2013-07-28 21:37:32 -05:00
# include "zvision/render_table.h"
2013-07-29 15:03:08 -05:00
# include "zvision/vector2.h"
2013-07-24 11:13:57 -05:00
namespace ZVision {
2013-07-30 14:25:31 -05:00
RenderTable : : RenderTable ( uint numColumns , uint numRows )
2013-07-24 11:13:57 -05:00
: _numRows ( numRows ) ,
2013-07-26 12:26:30 -05:00
_numColumns ( numColumns ) ,
2013-07-30 02:35:49 +03:00
_renderState ( FLAT ) {
2013-07-24 11:13:57 -05:00
assert ( numRows ! = 0 & & numColumns ! = 0 ) ;
2013-07-29 15:03:08 -05:00
_internalBuffer = new Vector2 [ numRows * numColumns ] ;
2013-07-24 11:13:57 -05:00
}
RenderTable : : ~ RenderTable ( ) {
delete [ ] _internalBuffer ;
}
void RenderTable : : setRenderState ( RenderState newState ) {
_renderState = newState ;
switch ( newState ) {
case PANORAMA :
2013-07-29 15:23:25 -05:00
_panoramaOptions . fieldOfView = 27.0f ;
2013-07-28 21:38:53 -05:00
_panoramaOptions . linearScale = 0.55f ;
2013-07-29 21:53:24 -05:00
_panoramaOptions . reverse = false ;
2013-07-24 11:13:57 -05:00
break ;
case TILT :
2013-07-29 15:08:03 -05:00
2013-07-24 11:13:57 -05:00
break ;
case FLAT :
// Intentionally left empty
break ;
}
}
2013-08-14 10:36:52 -05:00
const Common : : Point RenderTable : : convertWarpedCoordToFlatCoord ( const Common : : Point & point ) {
2013-08-14 10:43:37 -05:00
// If we're outside the range of the RenderTable, no warping is happening. Return the maximum image coords
if ( point . x > = _numColumns | | point . y > = _numRows ) {
int16 x = CLIP < int16 > ( point . x , 0 , _numColumns ) ;
int16 y = CLIP < int16 > ( point . y , 0 , _numRows ) ;
return Common : : Point ( x , y ) ;
}
2013-08-11 13:44:23 -05:00
uint32 index = point . y * _numColumns + point . x ;
Common : : Point newPoint ( point ) ;
newPoint . x + = _internalBuffer [ index ] . x ;
newPoint . y + = _internalBuffer [ index ] . y ;
return newPoint ;
}
2013-07-29 10:59:09 -05:00
uint16 mixTwoRGB ( uint16 colorOne , uint16 colorTwo , float percentColorOne ) {
assert ( percentColorOne < 1.0f ) ;
float rOne = float ( ( colorOne & Graphics : : ColorMasks < 555 > : : kRedMask ) > > Graphics : : ColorMasks < 555 > : : kRedShift ) ;
float rTwo = float ( ( colorTwo & Graphics : : ColorMasks < 555 > : : kRedMask ) > > Graphics : : ColorMasks < 555 > : : kRedShift ) ;
float gOne = float ( ( colorOne & Graphics : : ColorMasks < 555 > : : kGreenMask ) > > Graphics : : ColorMasks < 555 > : : kGreenShift ) ;
float gTwo = float ( ( colorTwo & Graphics : : ColorMasks < 555 > : : kGreenMask ) > > Graphics : : ColorMasks < 555 > : : kGreenShift ) ;
float bOne = float ( ( colorOne & Graphics : : ColorMasks < 555 > : : kBlueMask ) > > Graphics : : ColorMasks < 555 > : : kBlueShift ) ;
float bTwo = float ( ( colorTwo & Graphics : : ColorMasks < 555 > : : kBlueMask ) > > Graphics : : ColorMasks < 555 > : : kBlueShift ) ;
float rFinal = rOne * percentColorOne + rTwo * ( 1.0f - percentColorOne ) ;
float gFinal = gOne * percentColorOne + gTwo * ( 1.0f - percentColorOne ) ;
float bFinal = bOne * percentColorOne + bTwo * ( 1.0f - percentColorOne ) ;
uint16 returnColor = ( byte ( rFinal + 0.5f ) < < Graphics : : ColorMasks < 555 > : : kRedShift ) |
( byte ( gFinal + 0.5f ) < < Graphics : : ColorMasks < 555 > : : kGreenShift ) |
( byte ( bFinal + 0.5f ) < < Graphics : : ColorMasks < 555 > : : kBlueShift ) ;
return returnColor ;
}
2013-08-17 09:46:18 -05:00
void RenderTable : : mutateImage ( uint16 * sourceBuffer , uint16 * destBuffer , int16 imageWidth , int16 imageHeight , int16 destinationX , int16 destinationY , const Common : : Rect & subRect , bool wrap , bool isTransposed ) {
for ( int16 y = subRect . top ; y < subRect . bottom ; y + + ) {
2013-08-17 11:36:42 -05:00
int16 normalizedY = y - subRect . top ;
int32 internalColumnIndex = ( normalizedY + destinationY ) * _numColumns ;
int32 destColumnIndex = normalizedY * _numColumns ;
2013-07-28 21:37:32 -05:00
2013-08-17 09:46:18 -05:00
for ( int16 x = subRect . left ; x < subRect . right ; x + + ) {
2013-08-17 11:36:42 -05:00
int16 normalizedX = x - subRect . left ;
2013-07-28 21:37:32 -05:00
2013-08-17 11:36:42 -05:00
int32 index = internalColumnIndex + normalizedX + destinationX ;
2013-07-28 21:37:32 -05:00
2013-08-17 09:46:18 -05:00
// RenderTable only stores offsets from the original coordinates
2013-08-17 11:36:42 -05:00
int16 sourceYIndex = y + _internalBuffer [ index ] . y ;
int16 sourceXIndex = x + _internalBuffer [ index ] . x ;
2013-08-17 09:46:18 -05:00
if ( wrap ) {
2013-08-17 20:34:44 -05:00
while ( sourceXIndex > = imageWidth ) {
2013-08-17 09:46:18 -05:00
sourceXIndex - = imageWidth ;
2013-08-17 20:34:44 -05:00
}
while ( sourceXIndex < 0 ) {
2013-08-17 09:46:18 -05:00
sourceXIndex + = imageWidth ;
}
2013-08-17 20:34:44 -05:00
while ( sourceYIndex > = imageHeight ) {
2013-08-17 09:46:18 -05:00
sourceYIndex - = imageHeight ;
2013-08-17 20:34:44 -05:00
}
while ( sourceYIndex < 0 ) {
2013-08-17 09:46:18 -05:00
sourceYIndex + = imageHeight ;
}
} else {
// Clamp the yIndex to the size of the image
2013-08-17 11:36:42 -05:00
sourceYIndex = CLIP < int32 > ( sourceYIndex , 0 , imageHeight - 1 ) ;
2013-08-17 09:46:18 -05:00
// Clamp the xIndex to the size of the image
2013-08-17 11:36:42 -05:00
sourceXIndex = CLIP < int32 > ( sourceXIndex , 0 , imageWidth - 1 ) ;
2013-08-17 09:46:18 -05:00
}
if ( isTransposed ) {
destBuffer [ destColumnIndex + normalizedX ] = sourceBuffer [ sourceXIndex * imageHeight + sourceYIndex ] ;
} else {
destBuffer [ destColumnIndex + normalizedX ] = sourceBuffer [ sourceYIndex * imageWidth + sourceXIndex ] ;
}
2013-07-26 12:26:30 -05:00
}
}
}
2013-07-29 15:08:03 -05:00
void RenderTable : : generateRenderTable ( ) {
switch ( _renderState ) {
case ZVision : : RenderTable : : PANORAMA :
generatePanoramaLookupTable ( ) ;
break ;
case ZVision : : RenderTable : : TILT :
generateTiltLookupTable ( ) ;
break ;
case ZVision : : RenderTable : : FLAT :
// Intentionally left empty
break ;
}
}
2013-07-24 11:13:57 -05:00
void RenderTable : : generatePanoramaLookupTable ( ) {
memset ( _internalBuffer , 0 , _numRows * _numColumns * sizeof ( uint16 ) ) ;
float halfWidth = ( float ) _numColumns / 2.0f ;
float halfHeight = ( float ) _numRows / 2.0f ;
2013-08-14 18:05:13 -05:00
float fovInRadians = ( _panoramaOptions . fieldOfView * M_PI / 180.0f ) ;
float cylinderRadius = halfHeight / tan ( fovInRadians ) ;
2013-07-24 11:13:57 -05:00
2013-07-26 12:26:30 -05:00
// TODO: Change the algorithm to write a whole row at a time instead of a whole column at a time. AKA: for(y) { for(x) {}} instead of for(x) { for(y) {}}
2013-07-30 14:25:31 -05:00
for ( uint x = 0 ; x < _numColumns ; x + + ) {
2013-07-24 11:13:57 -05:00
// Add an offset of 0.01 to overcome zero tan/atan issue (vertical line on half of screen)
2013-08-14 18:05:13 -05:00
// Alpha represents the horizontal angle between the viewer at the center of a cylinder and x
float alpha = atan ( ( ( float ) x - halfWidth + 0.01f ) / cylinderRadius ) ;
2013-07-24 11:13:57 -05:00
2013-08-14 18:05:13 -05:00
// To get x in cylinder coordinates, we just need to calculate the arc length
// We also scale it by _panoramaOptions.linearScale
int32 xInCylinderCoords = int32 ( floor ( ( cylinderRadius * _panoramaOptions . linearScale * alpha ) + halfWidth ) ) ;
float cosAlpha = cos ( alpha ) ;
2013-07-24 11:13:57 -05:00
2013-07-30 14:25:31 -05:00
for ( uint y = 0 ; y < _numRows ; y + + ) {
2013-08-14 18:05:13 -05:00
// To calculate y in cylinder coordinates, we can do similar triangles comparison,
// comparing the triangle from the center to the screen and from the center to the edge of the cylinder
int32 yInCylinderCoords = int32 ( floor ( halfHeight + ( ( float ) y - halfHeight ) * cosAlpha ) ) ;
2013-07-24 11:13:57 -05:00
2013-07-26 12:26:30 -05:00
uint32 index = y * _numColumns + x ;
2013-08-14 18:05:13 -05:00
// Only store the (x,y) offsets instead of the absolute positions
_internalBuffer [ index ] . x = xInCylinderCoords - x ;
_internalBuffer [ index ] . y = yInCylinderCoords - y ;
2013-07-24 11:13:57 -05:00
}
}
}
void RenderTable : : generateTiltLookupTable ( ) {
2013-08-11 13:44:23 -05:00
for ( uint x = 0 ; x < _numColumns ; x + + ) {
for ( uint y = 0 ; y < _numRows ; y + + ) {
uint32 index = y * _numColumns + x ;
2013-07-29 15:22:14 -05:00
2013-08-11 13:44:23 -05:00
_internalBuffer [ index ] . x = 0 ;
_internalBuffer [ index ] . y = 0 ;
}
}
2013-07-29 15:22:14 -05:00
}
2013-07-29 15:20:51 -05:00
void RenderTable : : setPanoramaFoV ( float fov ) {
assert ( fov > 0.0f ) ;
2013-07-24 11:13:57 -05:00
2013-07-29 15:20:51 -05:00
_panoramaOptions . fieldOfView = fov ;
}
void RenderTable : : setPanoramaScale ( float scale ) {
assert ( scale > 0.0f ) ;
_panoramaOptions . linearScale = scale ;
2013-07-24 11:13:57 -05:00
}
2013-07-29 21:53:24 -05:00
void RenderTable : : setPanoramaReverse ( bool reverse ) {
_panoramaOptions . reverse = reverse ;
}
2013-07-29 21:45:53 -05:00
void RenderTable : : setTiltFoV ( float fov ) {
assert ( fov > 0.0f ) ;
_tiltOptions . fieldOfView = fov ;
}
void RenderTable : : setTiltScale ( float scale ) {
assert ( scale > 0.0f ) ;
_tiltOptions . linearScale = scale ;
}
2013-07-29 21:53:24 -05:00
void RenderTable : : setTiltReverse ( bool reverse ) {
_tiltOptions . reverse = reverse ;
}
2013-07-24 11:13:57 -05:00
} // End of namespace ZVision