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-07-28 01:47:41 +00:00
|
|
|
*
|
2007-05-31 20:28:29 +00:00
|
|
|
* Additional copyright for this file:
|
|
|
|
* Copyright (C) 1994-1998 Revolution Software Ltd.
|
|
|
|
*
|
2003-07-28 01:47:41 +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
|
|
|
|
* 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
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2003-07-28 01:47:41 +00:00
|
|
|
*/
|
|
|
|
|
2007-09-19 08:40:12 +00:00
|
|
|
|
2006-03-29 15:59:37 +00:00
|
|
|
#include "common/endian.h"
|
2005-01-10 22:06:49 +00:00
|
|
|
#include "common/system.h"
|
2005-02-27 16:11:19 +00:00
|
|
|
|
2005-04-27 20:29:19 +00:00
|
|
|
#include "graphics/primitives.h"
|
|
|
|
|
2003-10-28 19:51:30 +00:00
|
|
|
#include "sword2/sword2.h"
|
2005-02-27 16:11:19 +00:00
|
|
|
#include "sword2/defs.h"
|
2006-02-12 19:33:45 +00:00
|
|
|
#include "sword2/screen.h"
|
2005-03-11 15:30:28 +00:00
|
|
|
|
2003-10-04 00:52:27 +00:00
|
|
|
namespace Sword2 {
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2005-02-19 14:02:16 +00:00
|
|
|
#define RENDERAVERAGETOTAL 4
|
2003-10-15 06:40:31 +00:00
|
|
|
|
2005-02-19 14:02:16 +00:00
|
|
|
void Screen::updateRect(Common::Rect *r) {
|
2004-03-28 16:30:50 +00:00
|
|
|
_vm->_system->copyRectToScreen(_buffer + r->top * _screenWide + r->left,
|
2003-10-15 06:40:31 +00:00
|
|
|
_screenWide, r->left, r->top, r->right - r->left,
|
|
|
|
r->bottom - r->top);
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
|
|
|
|
2005-02-19 14:02:16 +00:00
|
|
|
void Screen::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect) {
|
2004-01-09 07:53:08 +00:00
|
|
|
if (!r->intersects(*clipRect))
|
2003-08-17 14:07:16 +00:00
|
|
|
return;
|
|
|
|
|
2003-08-28 06:36:15 +00:00
|
|
|
byte *src = s->data;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2004-01-09 07:53:08 +00:00
|
|
|
if (r->top < clipRect->top) {
|
|
|
|
src -= BLOCKWIDTH * (r->top - clipRect->top);
|
|
|
|
r->top = clipRect->top;
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
2004-01-09 07:53:08 +00:00
|
|
|
if (r->left < clipRect->left) {
|
|
|
|
src -= (r->left - clipRect->left);
|
|
|
|
r->left = clipRect->left;
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
2004-01-09 07:53:08 +00:00
|
|
|
if (r->bottom > clipRect->bottom)
|
|
|
|
r->bottom = clipRect->bottom;
|
|
|
|
if (r->right > clipRect->right)
|
|
|
|
r->right = clipRect->right;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
byte *dst = _buffer + r->top * _screenWide + r->left;
|
2004-07-26 16:41:57 +00:00
|
|
|
int i;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2003-08-28 06:36:15 +00:00
|
|
|
if (s->transparent) {
|
|
|
|
for (i = 0; i < r->bottom - r->top; i++) {
|
2004-07-26 16:41:57 +00:00
|
|
|
for (int j = 0; j < r->right - r->left; j++) {
|
2003-08-28 06:36:15 +00:00
|
|
|
if (src[j])
|
|
|
|
dst[j] = src[j];
|
|
|
|
}
|
|
|
|
src += BLOCKWIDTH;
|
2003-10-15 06:40:31 +00:00
|
|
|
dst += _screenWide;
|
2003-08-28 06:36:15 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < r->bottom - r->top; i++) {
|
|
|
|
memcpy(dst, src, r->right - r->left);
|
|
|
|
src += BLOCKWIDTH;
|
2003-10-15 06:40:31 +00:00
|
|
|
dst += _screenWide;
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
2003-08-19 08:47:09 +00:00
|
|
|
}
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
// There are two different separate functions for scaling the image - one fast
|
|
|
|
// and one good. Or at least that's the theory. I'm sure there are better ways
|
|
|
|
// to scale an image than this. The latter is used at the highest graphics
|
2010-04-17 17:23:30 +00:00
|
|
|
// quality setting. Note that the "good" scaler takes extra parameters so that
|
|
|
|
// it can use the background image when calculating the average pixel value.
|
2003-08-20 21:17:23 +00:00
|
|
|
//
|
2010-04-17 17:23:30 +00:00
|
|
|
// This code isn't quite like the original DrawSprite(), but the result should
|
|
|
|
// be close enough, I hope.
|
2003-08-20 21:17:23 +00:00
|
|
|
|
2005-02-19 14:02:16 +00:00
|
|
|
void Screen::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) {
|
2004-06-06 15:40:31 +00:00
|
|
|
int x, y;
|
2003-08-20 21:17:23 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
for (x = 0; x < dstWidth; x++)
|
|
|
|
_xScale[x] = (x * srcWidth) / dstWidth;
|
2003-08-20 21:17:23 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
for (y = 0; y < dstHeight; y++)
|
|
|
|
_yScale[y] = (y * srcHeight) / dstHeight;
|
2003-08-20 21:17:23 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
for (y = 0; y < dstHeight; y++) {
|
|
|
|
for (x = 0; x < dstWidth; x++) {
|
|
|
|
dst[x] = src[_yScale[y] * srcPitch + _xScale[x]];
|
2003-08-20 21:17:23 +00:00
|
|
|
}
|
2004-06-06 15:40:31 +00:00
|
|
|
dst += dstPitch;
|
2003-08-20 21:17:23 +00:00
|
|
|
}
|
2004-06-06 15:40:31 +00:00
|
|
|
}
|
2003-08-20 21:17:23 +00:00
|
|
|
|
2010-04-17 17:23:30 +00:00
|
|
|
void Screen::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backBuf, int16 bbXPos, int16 bbYPos) {
|
2004-06-06 15:40:31 +00:00
|
|
|
for (int y = 0; y < dstHeight; y++) {
|
|
|
|
for (int x = 0; x < dstWidth; x++) {
|
|
|
|
uint8 c1, c2, c3, c4;
|
2003-08-27 07:17:12 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
uint32 xPos = (x * srcWidth) / dstWidth;
|
|
|
|
uint32 yPos = (y * srcHeight) / dstHeight;
|
|
|
|
uint32 xFrac = dstWidth - (x * srcWidth) % dstWidth;
|
|
|
|
uint32 yFrac = dstHeight - (y * srcHeight) % dstHeight;
|
2003-08-27 07:17:12 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
byte *srcPtr = src + yPos * srcPitch + xPos;
|
2003-08-27 07:17:12 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
bool transparent = true;
|
2003-08-27 07:17:12 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
if (*srcPtr) {
|
|
|
|
c1 = *srcPtr;
|
|
|
|
transparent = false;
|
2010-04-17 17:23:30 +00:00
|
|
|
} else {
|
|
|
|
if (bbXPos + x >= 0 &&
|
|
|
|
bbXPos + x < RENDERWIDE &&
|
|
|
|
bbYPos + y >= MENUDEEP &&
|
|
|
|
bbYPos + y < MENUDEEP + RENDERDEEP) {
|
|
|
|
c1 = *(backBuf + _screenWide * (bbYPos + y) + bbXPos + x);
|
|
|
|
} else {
|
|
|
|
c1 = 0;
|
|
|
|
}
|
|
|
|
}
|
2003-08-27 07:17:12 +00:00
|
|
|
|
2004-06-06 15:40:31 +00:00
|
|
|
if (x < dstWidth - 1) {
|
|
|
|
if (*(srcPtr + 1)) {
|
|
|
|
c2 = *(srcPtr + 1);
|
|
|
|
transparent = false;
|
2010-04-17 17:23:30 +00:00
|
|
|
} else {
|
|
|
|
if (bbXPos + x + 1 >= 0 &&
|
|
|
|
bbXPos + x + 1 < RENDERWIDE &&
|
|
|
|
bbYPos + y >= MENUDEEP &&
|
|
|
|
bbYPos + y + 1 < MENUDEEP + RENDERDEEP) {
|
|
|
|
c2 = *(backBuf + _screenWide * (bbYPos + y) + bbXPos + x + 1);
|
|
|
|
} else {
|
|
|
|
c2 = c1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2004-06-06 15:40:31 +00:00
|
|
|
c2 = c1;
|
2010-04-17 17:23:30 +00:00
|
|
|
}
|
2004-06-06 15:40:31 +00:00
|
|
|
|
|
|
|
if (y < dstHeight - 1) {
|
|
|
|
if (*(srcPtr + srcPitch)) {
|
|
|
|
c3 = *(srcPtr + srcPitch);
|
|
|
|
transparent = false;
|
2010-04-17 17:23:30 +00:00
|
|
|
} else {
|
|
|
|
if (bbXPos + x >= 0 &&
|
|
|
|
bbXPos + x < RENDERWIDE &&
|
|
|
|
bbYPos + y + 1 >= MENUDEEP &&
|
|
|
|
bbYPos + y + 1 < MENUDEEP + RENDERDEEP) {
|
|
|
|
c3 = *(backBuf + _screenWide * (bbYPos + y + 1) + bbXPos);
|
|
|
|
} else {
|
|
|
|
c3 = c1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2004-06-06 15:40:31 +00:00
|
|
|
c3 = c1;
|
2010-04-17 17:23:30 +00:00
|
|
|
}
|
2004-06-06 15:40:31 +00:00
|
|
|
|
|
|
|
if (x < dstWidth - 1 && y < dstHeight - 1) {
|
|
|
|
if (*(srcPtr + srcPitch + 1)) {
|
|
|
|
c4 = *(srcPtr + srcPitch + 1);
|
|
|
|
transparent = false;
|
2010-04-17 17:23:30 +00:00
|
|
|
} else {
|
|
|
|
if (bbXPos + x + 1 >= 0 &&
|
|
|
|
bbXPos + x + 1 < RENDERWIDE &&
|
|
|
|
bbYPos + y + 1 >= MENUDEEP &&
|
|
|
|
bbYPos + y + 1 < MENUDEEP + RENDERDEEP) {
|
|
|
|
c4 = *(backBuf + _screenWide * (bbYPos + y + 1) + bbXPos + x + 1);
|
|
|
|
} else {
|
|
|
|
c4 = c3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2004-06-06 15:40:31 +00:00
|
|
|
c4 = c3;
|
2010-04-17 17:23:30 +00:00
|
|
|
}
|
2004-06-06 15:40:31 +00:00
|
|
|
|
|
|
|
if (!transparent) {
|
2011-02-15 21:52:15 +00:00
|
|
|
uint32 r1 = _palette[c1 * 3 + 0];
|
|
|
|
uint32 g1 = _palette[c1 * 3 + 1];
|
|
|
|
uint32 b1 = _palette[c1 * 3 + 2];
|
2004-06-06 15:40:31 +00:00
|
|
|
|
2011-02-15 21:52:15 +00:00
|
|
|
uint32 r2 = _palette[c2 * 3 + 0];
|
|
|
|
uint32 g2 = _palette[c2 * 3 + 1];
|
|
|
|
uint32 b2 = _palette[c2 * 3 + 2];
|
2004-06-06 15:40:31 +00:00
|
|
|
|
2011-02-15 21:52:15 +00:00
|
|
|
uint32 r3 = _palette[c3 * 3 + 0];
|
|
|
|
uint32 g3 = _palette[c3 * 3 + 1];
|
|
|
|
uint32 b3 = _palette[c3 * 3 + 2];
|
2004-06-06 15:40:31 +00:00
|
|
|
|
2011-02-15 21:52:15 +00:00
|
|
|
uint32 r4 = _palette[c4 * 3 + 0];
|
|
|
|
uint32 g4 = _palette[c4 * 3 + 1];
|
|
|
|
uint32 b4 = _palette[c4 * 3 + 2];
|
2004-06-06 15:40:31 +00:00
|
|
|
|
|
|
|
uint32 r5 = (r1 * xFrac + r2 * (dstWidth - xFrac)) / dstWidth;
|
|
|
|
uint32 g5 = (g1 * xFrac + g2 * (dstWidth - xFrac)) / dstWidth;
|
|
|
|
uint32 b5 = (b1 * xFrac + b2 * (dstWidth - xFrac)) / dstWidth;
|
|
|
|
|
|
|
|
uint32 r6 = (r3 * xFrac + r4 * (dstWidth - xFrac)) / dstWidth;
|
|
|
|
uint32 g6 = (g3 * xFrac + g4 * (dstWidth - xFrac)) / dstWidth;
|
|
|
|
uint32 b6 = (b3 * xFrac + b4 * (dstWidth - xFrac)) / dstWidth;
|
|
|
|
|
|
|
|
uint32 r = (r5 * yFrac + r6 * (dstHeight - yFrac)) / dstHeight;
|
|
|
|
uint32 g = (g5 * yFrac + g6 * (dstHeight - yFrac)) / dstHeight;
|
|
|
|
uint32 b = (b5 * yFrac + b6 * (dstHeight - yFrac)) / dstHeight;
|
|
|
|
|
|
|
|
dst[y * dstWidth + x] = quickMatch(r, g, b);
|
|
|
|
} else
|
|
|
|
dst[y * dstWidth + x] = 0;
|
2003-08-27 07:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
2003-08-20 21:17:23 +00:00
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* Plots a point relative to the top left corner of the screen. This is only
|
|
|
|
* used for debugging.
|
|
|
|
* @param x x-coordinate of the point
|
|
|
|
* @param y y-coordinate of the point
|
2011-04-14 12:12:27 +00:00
|
|
|
* @param color color of the point
|
2003-09-28 14:13:57 +00:00
|
|
|
*/
|
|
|
|
|
2011-04-14 12:12:27 +00:00
|
|
|
void Screen::plotPoint(int x, int y, uint8 color) {
|
2004-07-26 16:41:57 +00:00
|
|
|
byte *buf = _buffer + MENUDEEP * RENDERWIDE;
|
|
|
|
|
|
|
|
x -= _scrollX;
|
|
|
|
y -= _scrollY;
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
if (x >= 0 && x < RENDERWIDE && y >= 0 && y < RENDERDEEP) {
|
2011-04-14 12:12:27 +00:00
|
|
|
buf[y * RENDERWIDE + x] = color;
|
2004-07-26 16:41:57 +00:00
|
|
|
markAsDirty(x, y + MENUDEEP, x, y + MENUDEEP);
|
2004-05-09 13:24:07 +00:00
|
|
|
}
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 12:12:27 +00:00
|
|
|
static void plot(int x, int y, int color, void *data) {
|
2005-05-12 13:12:15 +00:00
|
|
|
Screen *screen = (Screen *)data;
|
2011-04-14 12:12:27 +00:00
|
|
|
screen->plotPoint(x, y, (uint8) color);
|
2005-04-20 14:45:23 +00:00
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* Draws a line from one point to another. This is only used for debugging.
|
|
|
|
* @param x0 x-coordinate of the start point
|
|
|
|
* @param y0 y-coordinate of the start point
|
|
|
|
* @param x1 x-coordinate of the end point
|
|
|
|
* @param y1 y-coordinate of the end point
|
2011-04-14 12:12:27 +00:00
|
|
|
* @param color color of the line
|
2003-09-28 14:13:57 +00:00
|
|
|
*/
|
|
|
|
|
2011-04-14 12:12:27 +00:00
|
|
|
void Screen::drawLine(int x0, int y0, int x1, int y1, uint8 color) {
|
|
|
|
Graphics::drawLine(x0, y0, x1, y1, color, &plot, this);
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* This function tells the driver the size of the background screen for the
|
|
|
|
* current location.
|
|
|
|
* @param w width of the current location
|
|
|
|
* @param h height of the current location
|
|
|
|
*/
|
|
|
|
|
2005-02-19 14:02:16 +00:00
|
|
|
void Screen::setLocationMetrics(uint16 w, uint16 h) {
|
2003-10-15 06:40:31 +00:00
|
|
|
_locationWide = w;
|
|
|
|
_locationDeep = h;
|
2004-01-04 15:11:30 +00:00
|
|
|
setNeedFullRedraw();
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* Draws a parallax layer at the current position determined by the scroll. A
|
|
|
|
* parallax can be either foreground, background or the main screen.
|
|
|
|
*/
|
|
|
|
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
void Screen::renderParallax(byte *ptr, int16 l) {
|
2003-08-17 14:07:16 +00:00
|
|
|
int16 x, y;
|
2009-04-07 19:52:46 +00:00
|
|
|
uint16 xRes, yRes;
|
2003-10-02 17:43:02 +00:00
|
|
|
Common::Rect r;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2009-04-07 19:52:46 +00:00
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Fetch resolution data from parallax
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-04-07 19:52:46 +00:00
|
|
|
if (Sword2Engine::isPsx()) {
|
|
|
|
xRes = READ_LE_UINT16(ptr);
|
|
|
|
yRes = READ_LE_UINT16(ptr + 2) * 2;
|
|
|
|
} else {
|
|
|
|
Parallax p;
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-04-07 19:52:46 +00:00
|
|
|
p.read(ptr);
|
|
|
|
xRes = p.w;
|
|
|
|
yRes = p.h;
|
|
|
|
}
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
if (_locationWide == _screenWide)
|
2003-08-17 14:07:16 +00:00
|
|
|
x = 0;
|
|
|
|
else
|
2009-04-07 19:52:46 +00:00
|
|
|
x = ((int32)((xRes - _screenWide) * _scrollX) / (int32)(_locationWide - _screenWide));
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
if (_locationDeep == _screenDeep - MENUDEEP * 2)
|
2003-08-17 14:07:16 +00:00
|
|
|
y = 0;
|
|
|
|
else
|
2009-04-07 19:52:46 +00:00
|
|
|
y = ((int32)((yRes - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32)(_locationDeep - (_screenDeep - MENUDEEP * 2)));
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2004-01-09 07:53:08 +00:00
|
|
|
Common::Rect clipRect;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
|
|
|
// Leave enough space for the top and bottom menues
|
|
|
|
|
2004-01-09 07:53:08 +00:00
|
|
|
clipRect.left = 0;
|
|
|
|
clipRect.right = _screenWide;
|
|
|
|
clipRect.top = MENUDEEP;
|
|
|
|
clipRect.bottom = _screenDeep - MENUDEEP;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
for (int j = 0; j < _yBlocks[l]; j++) {
|
|
|
|
for (int i = 0; i < _xBlocks[l]; i++) {
|
|
|
|
if (_blockSurfaces[l][i + j * _xBlocks[l]]) {
|
2003-08-17 14:07:16 +00:00
|
|
|
r.left = i * BLOCKWIDTH - x;
|
|
|
|
r.right = r.left + BLOCKWIDTH;
|
2004-07-26 16:41:57 +00:00
|
|
|
r.top = j * BLOCKHEIGHT - y + MENUDEEP;
|
2003-08-17 14:07:16 +00:00
|
|
|
r.bottom = r.top + BLOCKHEIGHT;
|
2004-01-09 07:53:08 +00:00
|
|
|
blitBlockSurface(_blockSurfaces[l][i + j * _xBlocks[l]], &r, &clipRect);
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
_parallaxScrollX = _scrollX - x;
|
|
|
|
_parallaxScrollY = _scrollY - y;
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2003-08-29 06:42:34 +00:00
|
|
|
// Uncomment this when benchmarking the drawing routines.
|
|
|
|
#define LIMIT_FRAME_RATE
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
2011-05-25 15:17:11 +00:00
|
|
|
* Initializes the timers before the render loop is entered.
|
2003-09-28 14:13:57 +00:00
|
|
|
*/
|
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
void Screen::initializeRenderCycle() {
|
2004-09-28 20:19:37 +00:00
|
|
|
_initialTime = _vm->_system->getMillis();
|
2007-01-03 07:36:44 +00:00
|
|
|
_totalTime = _initialTime + (1000 / _vm->getFramesPerSecond());
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* This function should be called when the game engine is ready to start the
|
|
|
|
* render cycle.
|
|
|
|
*/
|
|
|
|
|
2005-05-02 05:41:01 +00:00
|
|
|
void Screen::startRenderCycle() {
|
2003-10-15 06:40:31 +00:00
|
|
|
_scrollXOld = _scrollX;
|
|
|
|
_scrollYOld = _scrollY;
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2004-09-28 20:19:37 +00:00
|
|
|
_startTime = _vm->_system->getMillis();
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
if (_startTime + _renderAverageTime >= _totalTime) {
|
|
|
|
_scrollX = _scrollXTarget;
|
|
|
|
_scrollY = _scrollYTarget;
|
|
|
|
_renderTooSlow = true;
|
2003-08-20 21:17:23 +00:00
|
|
|
} else {
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
_scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime));
|
|
|
|
_scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime));
|
2003-10-15 06:40:31 +00:00
|
|
|
_renderTooSlow = false;
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2004-01-04 15:11:30 +00:00
|
|
|
if (_scrollXOld != _scrollX || _scrollYOld != _scrollY)
|
|
|
|
setNeedFullRedraw();
|
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
_framesPerGameCycle = 0;
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* This function should be called at the end of the render cycle.
|
2005-07-30 21:11:48 +00:00
|
|
|
* @return true if the render cycle is to be terminated,
|
2004-03-15 00:55:44 +00:00
|
|
|
* or false if it should continue
|
2003-09-28 14:13:57 +00:00
|
|
|
*/
|
|
|
|
|
2005-05-02 05:41:01 +00:00
|
|
|
bool Screen::endRenderCycle() {
|
2003-10-15 06:40:31 +00:00
|
|
|
static int32 renderTimeLog[4] = { 60, 60, 60, 60 };
|
|
|
|
static int32 renderCountIndex = 0;
|
2003-07-28 01:47:41 +00:00
|
|
|
int32 time;
|
|
|
|
|
2004-09-28 20:19:37 +00:00
|
|
|
time = _vm->_system->getMillis();
|
2003-10-15 06:40:31 +00:00
|
|
|
renderTimeLog[renderCountIndex] = time - _startTime;
|
|
|
|
_startTime = time;
|
|
|
|
_renderAverageTime = (renderTimeLog[0] + renderTimeLog[1] + renderTimeLog[2] + renderTimeLog[3]) >> 2;
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
_framesPerGameCycle++;
|
2003-07-28 01:47:41 +00:00
|
|
|
|
|
|
|
if (++renderCountIndex == RENDERAVERAGETOTAL)
|
|
|
|
renderCountIndex = 0;
|
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
if (_renderTooSlow) {
|
2011-05-25 15:17:11 +00:00
|
|
|
initializeRenderCycle();
|
2003-10-15 06:40:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_startTime + _renderAverageTime >= _totalTime) {
|
2007-01-03 07:36:44 +00:00
|
|
|
_totalTime += (1000 / _vm->getFramesPerSecond());
|
2003-10-15 06:40:31 +00:00
|
|
|
_initialTime = time;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-08-29 06:42:34 +00:00
|
|
|
#ifdef LIMIT_FRAME_RATE
|
2003-10-15 06:40:31 +00:00
|
|
|
if (_scrollXTarget == _scrollX && _scrollYTarget == _scrollY) {
|
2003-08-29 06:42:34 +00:00
|
|
|
// If we have already reached the scroll target sleep for the
|
|
|
|
// rest of the render cycle.
|
2003-11-16 14:18:29 +00:00
|
|
|
_vm->sleepUntil(_totalTime);
|
2004-09-28 20:19:37 +00:00
|
|
|
_initialTime = _vm->_system->getMillis();
|
2007-01-03 07:36:44 +00:00
|
|
|
_totalTime += (1000 / _vm->getFramesPerSecond());
|
2003-10-15 06:40:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
2003-08-29 06:42:34 +00:00
|
|
|
#endif
|
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
// This is an attempt to ensure that we always reach the scroll target.
|
|
|
|
// Otherwise the game frequently tries to pump out new interpolation
|
|
|
|
// frames without ever getting anywhere.
|
2003-08-29 06:42:34 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
if (ABS(_scrollX - _scrollXTarget) <= 1 && ABS(_scrollY - _scrollYTarget) <= 1) {
|
|
|
|
_scrollX = _scrollXTarget;
|
|
|
|
_scrollY = _scrollYTarget;
|
|
|
|
} else {
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
_scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime));
|
|
|
|
_scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime));
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2004-01-04 15:11:30 +00:00
|
|
|
if (_scrollX != _scrollXOld || _scrollY != _scrollYOld)
|
|
|
|
setNeedFullRedraw();
|
|
|
|
|
2004-01-14 10:58:09 +00:00
|
|
|
#ifdef LIMIT_FRAME_RATE
|
|
|
|
// Give the other threads some breathing space. This apparently helps
|
|
|
|
// against bug #875683, though I was never able to reproduce it for
|
|
|
|
// myself.
|
2004-09-28 20:19:37 +00:00
|
|
|
_vm->_system->delayMillis(10);
|
2004-01-14 10:58:09 +00:00
|
|
|
#endif
|
2004-01-13 10:27:13 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
return false;
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2004-04-07 12:31:32 +00:00
|
|
|
/**
|
|
|
|
* Reset scrolling stuff. This function is called from initBackground()
|
|
|
|
*/
|
|
|
|
|
2005-05-02 05:41:01 +00:00
|
|
|
void Screen::resetRenderEngine() {
|
2004-04-07 12:31:32 +00:00
|
|
|
_parallaxScrollX = 0;
|
|
|
|
_parallaxScrollY = 0;
|
|
|
|
_scrollX = 0;
|
|
|
|
_scrollY = 0;
|
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* This function should be called five times with either the parallax layer
|
|
|
|
* or a NULL pointer in order of background parallax to foreground parallax.
|
|
|
|
*/
|
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
int32 Screen::initializeBackgroundLayer(byte *parallax) {
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
Parallax p;
|
2003-08-17 14:07:16 +00:00
|
|
|
uint16 i, j, k;
|
2004-04-23 07:02:11 +00:00
|
|
|
byte *data;
|
|
|
|
byte *dst;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
debug(2, "initializeBackgroundLayer");
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
assert(_layer < MAXLAYERS);
|
2003-08-17 14:07:16 +00:00
|
|
|
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
if (!parallax) {
|
2003-10-15 06:40:31 +00:00
|
|
|
_layer++;
|
2003-08-17 14:07:16 +00:00
|
|
|
return RD_OK;
|
|
|
|
}
|
|
|
|
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
p.read(parallax);
|
|
|
|
|
|
|
|
_xBlocks[_layer] = (p.w + BLOCKWIDTH - 1) / BLOCKWIDTH;
|
|
|
|
_yBlocks[_layer] = (p.h + BLOCKHEIGHT - 1) / BLOCKHEIGHT;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2005-05-12 13:12:15 +00:00
|
|
|
_blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *));
|
2003-10-15 06:40:31 +00:00
|
|
|
if (!_blockSurfaces[_layer])
|
2003-08-17 14:07:16 +00:00
|
|
|
return RDERR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
// Decode the parallax layer into a large chunk of memory
|
|
|
|
|
2005-05-12 13:12:15 +00:00
|
|
|
byte *memchunk = (byte *)calloc(_xBlocks[_layer] * _yBlocks[_layer], BLOCKWIDTH * BLOCKHEIGHT);
|
2003-08-17 14:07:16 +00:00
|
|
|
if (!memchunk)
|
|
|
|
return RDERR_OUTOFMEMORY;
|
|
|
|
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
for (i = 0; i < p.h; i++) {
|
|
|
|
uint32 p_offset = READ_LE_UINT32(parallax + Parallax::size() + 4 * i);
|
|
|
|
|
|
|
|
if (!p_offset)
|
2003-08-17 14:07:16 +00:00
|
|
|
continue;
|
|
|
|
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
byte *pLine = parallax + p_offset;
|
2004-07-26 16:41:57 +00:00
|
|
|
uint16 packets = READ_LE_UINT16(pLine);
|
|
|
|
uint16 offset = READ_LE_UINT16(pLine + 2);
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
data = pLine + 4;
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
dst = memchunk + i * p.w + offset;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
if (!packets) {
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
memcpy(dst, data, p.w);
|
2003-08-17 14:07:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
bool zeros = false;
|
|
|
|
|
|
|
|
for (j = 0; j < packets; j++) {
|
2003-08-17 14:07:16 +00:00
|
|
|
if (zeros) {
|
|
|
|
dst += *data;
|
2004-07-26 16:41:57 +00:00
|
|
|
offset += *data;
|
2003-08-17 14:07:16 +00:00
|
|
|
data++;
|
2004-07-26 16:41:57 +00:00
|
|
|
zeros = false;
|
|
|
|
} else if (!*data) {
|
2003-08-17 14:07:16 +00:00
|
|
|
data++;
|
2004-07-26 16:41:57 +00:00
|
|
|
zeros = true;
|
2003-08-17 14:07:16 +00:00
|
|
|
} else {
|
2004-07-26 16:41:57 +00:00
|
|
|
uint16 count = *data++;
|
2003-08-17 14:07:16 +00:00
|
|
|
memcpy(dst, data, count);
|
|
|
|
data += count;
|
|
|
|
dst += count;
|
2004-07-26 16:41:57 +00:00
|
|
|
offset += count;
|
|
|
|
zeros = true;
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
// The large memory chunk is now divided into a number of smaller
|
|
|
|
// surfaces. For most parallax layers, we'll end up using less memory
|
|
|
|
// this way, and it will be faster to draw since completely transparent
|
|
|
|
// surfaces are discarded.
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) {
|
2003-08-17 14:07:16 +00:00
|
|
|
bool block_has_data = false;
|
2003-08-28 06:36:15 +00:00
|
|
|
bool block_is_transparent = false;
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
int x = BLOCKWIDTH * (i % _xBlocks[_layer]);
|
|
|
|
int y = BLOCKHEIGHT * (i / _xBlocks[_layer]);
|
2003-08-17 14:07:16 +00:00
|
|
|
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
data = memchunk + p.w * y + x;
|
2003-12-08 07:30:22 +00:00
|
|
|
|
2003-08-17 14:07:16 +00:00
|
|
|
for (j = 0; j < BLOCKHEIGHT; j++) {
|
2003-08-28 06:36:15 +00:00
|
|
|
for (k = 0; k < BLOCKWIDTH; k++) {
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
if (x + k < p.w && y + j < p.h) {
|
|
|
|
if (data[j * p.w + k])
|
2004-07-26 16:41:57 +00:00
|
|
|
block_has_data = true;
|
|
|
|
else
|
|
|
|
block_is_transparent = true;
|
|
|
|
}
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only assign a surface to the block if it contains data.
|
|
|
|
|
|
|
|
if (block_has_data) {
|
2005-05-12 13:12:15 +00:00
|
|
|
_blockSurfaces[_layer][i] = (BlockSurface *)malloc(sizeof(BlockSurface));
|
2003-08-17 14:07:16 +00:00
|
|
|
|
|
|
|
// Copy the data into the surfaces.
|
2003-10-15 06:40:31 +00:00
|
|
|
dst = _blockSurfaces[_layer][i]->data;
|
2003-08-17 14:07:16 +00:00
|
|
|
for (j = 0; j < BLOCKHEIGHT; j++) {
|
|
|
|
memcpy(dst, data, BLOCKWIDTH);
|
Applied my own patch #1341495, in an attempt to fix alignment issues
reported by Crilith.
To elaborate a bit, the engine no longer accesses resource data through
packed structs. Instead it uses memory streams and the READ/WRITE
functions.
If data is mainly read, not written, I have replaced the old struct with a
new one with a read() function to read the whole thing from memory into the
struct's variables, and a write() function to dump the struct's variables
to memory. In fact, most of these write() functions remain unused.
If data is both read and written, I have replaced the struct with a class
with individual get/set functions to replace the old variables. This
manipulates memory directly.
Since I'm fairly sure that these structs are frequently stored as local
variables for a script, all script variables (both local and global) are
stored as little-endian and accessed through the READ/WRITE functions,
rather than being treated as arrays of 32-bit integers.
On a positive note, the functions for doing endian conversion of resources
and save games have been removed, and some general cleanups have been made
to assist in the rewrite.
Initial reports indicate that this patch indeed fixes alignment issues, and
that I have not - surprisingly - broken the game on big-endian platforms.
At least not in any immediately obvious way. And there's still plenty of
time to fix regressions before 0.9.0, too.
svn-id: r19366
2005-10-29 21:24:54 +00:00
|
|
|
data += p.w;
|
2003-08-17 14:07:16 +00:00
|
|
|
dst += BLOCKWIDTH;
|
|
|
|
}
|
2003-08-28 06:36:15 +00:00
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
_blockSurfaces[_layer][i]->transparent = block_is_transparent;
|
2003-08-28 06:36:15 +00:00
|
|
|
|
2003-08-17 14:07:16 +00:00
|
|
|
} else
|
2003-10-15 06:40:31 +00:00
|
|
|
_blockSurfaces[_layer][i] = NULL;
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
2003-09-28 16:27:51 +00:00
|
|
|
|
2003-08-17 14:07:16 +00:00
|
|
|
free(memchunk);
|
2003-10-15 06:40:31 +00:00
|
|
|
_layer++;
|
2003-07-28 01:47:41 +00:00
|
|
|
|
2003-09-28 16:27:51 +00:00
|
|
|
return RD_OK;
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2009-04-07 19:52:46 +00:00
|
|
|
/**
|
|
|
|
* This converts PSX format background data into a format that
|
|
|
|
* can be understood by renderParallax functions.
|
|
|
|
* PSX Backgrounds are divided into tiles of 64x32 (with aspect
|
|
|
|
* ratio correction), while PC backgrounds are in tiles of 64x64.
|
|
|
|
*/
|
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
int32 Screen::initializePsxBackgroundLayer(byte *parallax) {
|
2009-04-07 19:52:46 +00:00
|
|
|
uint16 bgXres, bgYres;
|
|
|
|
uint16 trueXres, stripeNumber, totStripes;
|
|
|
|
uint32 baseAddress, stripePos;
|
|
|
|
uint16 i, j;
|
|
|
|
byte *dst;
|
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
debug(2, "initializePsxBackgroundLayer");
|
2009-04-07 19:52:46 +00:00
|
|
|
|
|
|
|
assert(_layer < MAXLAYERS);
|
|
|
|
|
|
|
|
if (!parallax) {
|
|
|
|
_layer++;
|
|
|
|
return RD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch data from buffer
|
|
|
|
|
|
|
|
bgXres = READ_LE_UINT16(parallax);
|
|
|
|
bgYres = READ_LE_UINT16(parallax + 2) * 2;
|
|
|
|
baseAddress = READ_LE_UINT32(parallax + 4);
|
|
|
|
parallax += 8;
|
|
|
|
|
|
|
|
// Calculate TRUE resolution of background, must be
|
|
|
|
// a multiple of 64
|
|
|
|
|
|
|
|
trueXres = (bgXres % 64) ? ((bgXres/64) + 1) * 64 : bgXres;
|
|
|
|
totStripes = trueXres / 64;
|
|
|
|
|
|
|
|
_xBlocks[_layer] = (bgXres + BLOCKWIDTH - 1) / BLOCKWIDTH;
|
|
|
|
_yBlocks[_layer] = (bgYres + BLOCKHEIGHT - 1) / BLOCKHEIGHT;
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-04-07 19:52:46 +00:00
|
|
|
uint16 remLines = bgYres % 64;
|
|
|
|
|
|
|
|
byte *tileChunk = (byte *)malloc(BLOCKHEIGHT * BLOCKWIDTH);
|
|
|
|
if (!tileChunk)
|
|
|
|
return RDERR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
_blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *));
|
2009-12-09 06:33:00 +00:00
|
|
|
if (!_blockSurfaces[_layer]) {
|
|
|
|
free(tileChunk);
|
2009-04-07 19:52:46 +00:00
|
|
|
return RDERR_OUTOFMEMORY;
|
2009-12-09 06:33:00 +00:00
|
|
|
}
|
2009-04-07 19:52:46 +00:00
|
|
|
|
|
|
|
// Group PSX background (64x32, when stretched vertically) tiles together,
|
|
|
|
// to make them compatible with pc version (composed by 64x64 tiles)
|
|
|
|
|
|
|
|
stripeNumber = 0;
|
|
|
|
stripePos = 0;
|
|
|
|
for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) {
|
|
|
|
bool block_has_data = false;
|
|
|
|
bool block_is_transparent = false;
|
|
|
|
|
|
|
|
int posX = i / _yBlocks[_layer];
|
|
|
|
int posY = i % _yBlocks[_layer];
|
|
|
|
|
|
|
|
uint32 stripeOffset = READ_LE_UINT32(parallax + stripeNumber * 8 + 4) + stripePos - baseAddress;
|
|
|
|
|
|
|
|
memset(tileChunk, 1, BLOCKHEIGHT * BLOCKWIDTH);
|
|
|
|
|
2009-05-24 15:17:42 +00:00
|
|
|
if (!(remLines && posY == _yBlocks[_layer] - 1))
|
2009-04-07 19:52:46 +00:00
|
|
|
remLines = 32;
|
|
|
|
|
2009-09-30 16:16:53 +00:00
|
|
|
for (j = 0; j < remLines; j++) {
|
2009-04-07 19:52:46 +00:00
|
|
|
memcpy(tileChunk + j * BLOCKWIDTH * 2, parallax + stripeOffset + j * BLOCKWIDTH, BLOCKWIDTH);
|
|
|
|
memcpy(tileChunk + j * BLOCKWIDTH * 2 + BLOCKWIDTH, parallax + stripeOffset + j * BLOCKWIDTH, BLOCKWIDTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < BLOCKHEIGHT * BLOCKWIDTH; j++) {
|
|
|
|
if (tileChunk[j])
|
|
|
|
block_has_data = true;
|
|
|
|
else
|
|
|
|
block_is_transparent = true;
|
2009-05-24 15:17:42 +00:00
|
|
|
}
|
2009-04-07 19:52:46 +00:00
|
|
|
|
|
|
|
int tileIndex = totStripes * posY + posX;
|
|
|
|
|
|
|
|
// Only assign a surface to the block if it contains data.
|
|
|
|
|
|
|
|
if (block_has_data) {
|
|
|
|
_blockSurfaces[_layer][tileIndex] = (BlockSurface *)malloc(sizeof(BlockSurface));
|
|
|
|
|
|
|
|
// Copy the data into the surfaces.
|
|
|
|
dst = _blockSurfaces[_layer][tileIndex]->data;
|
|
|
|
memcpy(dst, tileChunk, BLOCKWIDTH * BLOCKHEIGHT);
|
|
|
|
|
|
|
|
_blockSurfaces[_layer][tileIndex]->transparent = block_is_transparent;
|
|
|
|
|
|
|
|
} else
|
|
|
|
_blockSurfaces[_layer][tileIndex] = NULL;
|
|
|
|
|
|
|
|
if (posY == _yBlocks[_layer] - 1) {
|
|
|
|
stripeNumber++;
|
|
|
|
stripePos = 0;
|
|
|
|
} else {
|
|
|
|
stripePos += 0x800;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(tileChunk);
|
|
|
|
_layer++;
|
|
|
|
|
2009-05-24 15:17:42 +00:00
|
|
|
return RD_OK;
|
2009-04-07 19:52:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This converts PSX format parallax data into a format that
|
|
|
|
* can be understood by renderParallax functions.
|
|
|
|
*/
|
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
int32 Screen::initializePsxParallaxLayer(byte *parallax) {
|
2009-04-07 19:52:46 +00:00
|
|
|
uint16 plxXres, plxYres;
|
|
|
|
uint16 xTiles, yTiles;
|
|
|
|
uint16 i, j, k;
|
|
|
|
byte *data;
|
|
|
|
byte *dst;
|
|
|
|
|
2011-05-25 15:17:11 +00:00
|
|
|
debug(2, "initializePsxParallaxLayer");
|
2009-04-07 19:52:46 +00:00
|
|
|
|
|
|
|
assert(_layer < MAXLAYERS);
|
|
|
|
|
|
|
|
if (!parallax) {
|
|
|
|
_layer++;
|
|
|
|
return RD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
plxXres = READ_LE_UINT16(parallax);
|
|
|
|
plxYres = READ_LE_UINT16(parallax + 2);
|
|
|
|
xTiles = READ_LE_UINT16(parallax + 4);
|
|
|
|
yTiles = READ_LE_UINT16(parallax + 6);
|
|
|
|
|
|
|
|
// Beginning of parallax table composed by uint32,
|
|
|
|
// if word is 0, corresponding tile contains no data and must be skipped,
|
|
|
|
// if word is 0x400 tile contains data.
|
|
|
|
parallax += 8;
|
|
|
|
|
|
|
|
// Beginning if tiles data.
|
|
|
|
data = parallax + xTiles * yTiles * 4;
|
|
|
|
|
|
|
|
_xBlocks[_layer] = xTiles;
|
2010-10-15 06:12:23 +00:00
|
|
|
_yBlocks[_layer] = (yTiles / 2) + ((yTiles % 2) ? 1 : 0);
|
|
|
|
bool oddTiles = ((yTiles % 2) ? true : false);
|
2009-04-07 19:52:46 +00:00
|
|
|
|
|
|
|
_blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *));
|
|
|
|
if (!_blockSurfaces[_layer])
|
|
|
|
return RDERR_OUTOFMEMORY;
|
|
|
|
|
|
|
|
// We have to check two tiles for every block in PSX version, if one of those
|
|
|
|
// has data in it, the whole block has data. Also, tiles must be doublelined to
|
|
|
|
// get correct aspect ratio.
|
|
|
|
for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) {
|
|
|
|
bool block_has_data = false;
|
|
|
|
bool block_is_transparent = false;
|
|
|
|
bool firstTilePresent, secondTilePresent;
|
|
|
|
|
|
|
|
int posX = i / _yBlocks[_layer];
|
|
|
|
int posY = i % _yBlocks[_layer];
|
|
|
|
|
|
|
|
if (oddTiles && posY == _yBlocks[_layer] - 1) {
|
|
|
|
firstTilePresent = READ_LE_UINT32(parallax) == 0x400;
|
|
|
|
secondTilePresent = false;
|
|
|
|
parallax += 4;
|
|
|
|
} else {
|
|
|
|
firstTilePresent = READ_LE_UINT32(parallax) == 0x400;
|
|
|
|
secondTilePresent = READ_LE_UINT32(parallax + 4) == 0x400;
|
|
|
|
parallax += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If one of the two grouped tiles has data, then the whole block has data
|
|
|
|
if (firstTilePresent || secondTilePresent) {
|
|
|
|
block_has_data = true;
|
|
|
|
|
|
|
|
// If one of the two grouped blocks is without data, then we also have transparency
|
2009-09-30 16:16:53 +00:00
|
|
|
if (!firstTilePresent || !secondTilePresent)
|
2009-04-07 19:52:46 +00:00
|
|
|
block_is_transparent = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now do a second check to see if we have a partially transparent block
|
|
|
|
if (block_has_data && !block_is_transparent) {
|
|
|
|
byte *block = data;
|
|
|
|
if (firstTilePresent) {
|
|
|
|
for (k = 0; k < 0x400; k++) {
|
2009-09-30 16:16:53 +00:00
|
|
|
if (*(block + k) == 0) {
|
2009-04-07 19:52:46 +00:00
|
|
|
block_is_transparent = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
block += 0x400; // On to next block...
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we didn't find transparency in first block and we have
|
|
|
|
// a second tile, check it
|
2009-05-24 15:17:42 +00:00
|
|
|
if (secondTilePresent && !block_is_transparent) {
|
2009-04-07 19:52:46 +00:00
|
|
|
for (k = 0; k < 0x400; k++) {
|
2009-09-30 16:16:53 +00:00
|
|
|
if (*(block + k) == 0) {
|
2009-04-07 19:52:46 +00:00
|
|
|
block_is_transparent = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int tileIndex = xTiles * posY + posX;
|
|
|
|
|
|
|
|
// Only assign a surface to the block if it contains data.
|
|
|
|
|
|
|
|
if (block_has_data) {
|
|
|
|
_blockSurfaces[_layer][tileIndex] = (BlockSurface *)malloc(sizeof(BlockSurface));
|
|
|
|
memset(_blockSurfaces[_layer][tileIndex], 0, BLOCKHEIGHT * BLOCKWIDTH);
|
|
|
|
|
|
|
|
// Copy the data into the surfaces.
|
|
|
|
dst = _blockSurfaces[_layer][tileIndex]->data;
|
|
|
|
|
|
|
|
if (firstTilePresent) { //There is data in the first tile
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
memcpy(dst, data, BLOCKWIDTH);
|
|
|
|
dst += BLOCKWIDTH;
|
|
|
|
memcpy(dst, data, BLOCKWIDTH);
|
|
|
|
dst += BLOCKWIDTH;
|
|
|
|
data += BLOCKWIDTH;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dst += 0x800;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (secondTilePresent) {
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
memcpy(dst, data, BLOCKWIDTH);
|
|
|
|
dst += BLOCKWIDTH;
|
|
|
|
memcpy(dst, data, BLOCKWIDTH);
|
|
|
|
dst += BLOCKWIDTH;
|
|
|
|
data += BLOCKWIDTH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_blockSurfaces[_layer][tileIndex]->transparent = block_is_transparent;
|
|
|
|
} else
|
|
|
|
_blockSurfaces[_layer][tileIndex] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
_layer++;
|
|
|
|
|
|
|
|
return RD_OK;
|
|
|
|
}
|
|
|
|
|
2003-09-28 14:13:57 +00:00
|
|
|
/**
|
|
|
|
* Should be called once after leaving the room to free up memory.
|
|
|
|
*/
|
|
|
|
|
2005-05-02 05:41:01 +00:00
|
|
|
void Screen::closeBackgroundLayer() {
|
2003-08-20 21:17:23 +00:00
|
|
|
debug(2, "CloseBackgroundLayer");
|
2003-08-17 14:07:16 +00:00
|
|
|
|
2009-04-07 19:52:46 +00:00
|
|
|
if (Sword2Engine::isPsx())
|
|
|
|
flushPsxScrCache();
|
|
|
|
|
2004-07-26 16:41:57 +00:00
|
|
|
for (int i = 0; i < MAXLAYERS; i++) {
|
|
|
|
if (_blockSurfaces[i]) {
|
|
|
|
for (int j = 0; j < _xBlocks[i] * _yBlocks[i]; j++)
|
|
|
|
if (_blockSurfaces[i][j])
|
|
|
|
free(_blockSurfaces[i][j]);
|
|
|
|
free(_blockSurfaces[i]);
|
|
|
|
_blockSurfaces[i] = NULL;
|
2003-08-17 14:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-15 06:40:31 +00:00
|
|
|
_layer = 0;
|
2003-07-28 01:47:41 +00:00
|
|
|
}
|
2003-10-04 00:52:27 +00:00
|
|
|
|
|
|
|
} // End of namespace Sword2
|