diff options
Diffstat (limited to 'sword2/render.cpp')
| -rw-r--r-- | sword2/render.cpp | 584 |
1 files changed, 0 insertions, 584 deletions
diff --git a/sword2/render.cpp b/sword2/render.cpp deleted file mode 100644 index da60ecd6d9..0000000000 --- a/sword2/render.cpp +++ /dev/null @@ -1,584 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 The ScummVM project - * - * 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. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" - -#include "graphics/primitives.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/build_display.h" - -#ifdef BACKEND_8BIT -#include "sword2/animation.h" -#endif - -namespace Sword2 { - -#define MILLISECSPERCYCLE 83 -#define RENDERAVERAGETOTAL 4 - -void Screen::updateRect(Common::Rect *r) { - _vm->_system->copyRectToScreen(_buffer + r->top * _screenWide + r->left, - _screenWide, r->left, r->top, r->right - r->left, - r->bottom - r->top); -} - -void Screen::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect) { - if (!r->intersects(*clipRect)) - return; - - byte *src = s->data; - - if (r->top < clipRect->top) { - src -= BLOCKWIDTH * (r->top - clipRect->top); - r->top = clipRect->top; - } - if (r->left < clipRect->left) { - src -= (r->left - clipRect->left); - r->left = clipRect->left; - } - if (r->bottom > clipRect->bottom) - r->bottom = clipRect->bottom; - if (r->right > clipRect->right) - r->right = clipRect->right; - - byte *dst = _buffer + r->top * _screenWide + r->left; - int i; - - if (s->transparent) { - for (i = 0; i < r->bottom - r->top; i++) { - for (int j = 0; j < r->right - r->left; j++) { - if (src[j]) - dst[j] = src[j]; - } - src += BLOCKWIDTH; - dst += _screenWide; - } - } else { - for (i = 0; i < r->bottom - r->top; i++) { - memcpy(dst, src, r->right - r->left); - src += BLOCKWIDTH; - dst += _screenWide; - } - } -} - -// 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 -// quality setting. Note that the "good" scaler takes an extra parameter, a -// pointer to the area of the screen where the sprite will be drawn. -// -// This code isn't quite like the original DrawSprite(), but should be close -// enough. - -void Screen::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) { - int x, y; - - for (x = 0; x < dstWidth; x++) - _xScale[x] = (x * srcWidth) / dstWidth; - - for (y = 0; y < dstHeight; y++) - _yScale[y] = (y * srcHeight) / dstHeight; - - for (y = 0; y < dstHeight; y++) { - for (x = 0; x < dstWidth; x++) { - dst[x] = src[_yScale[y] * srcPitch + _xScale[x]]; - } - dst += dstPitch; - } -} - -void Screen::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) { - for (int y = 0; y < dstHeight; y++) { - for (int x = 0; x < dstWidth; x++) { - uint8 c1, c2, c3, c4; - - uint32 xPos = (x * srcWidth) / dstWidth; - uint32 yPos = (y * srcHeight) / dstHeight; - uint32 xFrac = dstWidth - (x * srcWidth) % dstWidth; - uint32 yFrac = dstHeight - (y * srcHeight) % dstHeight; - - byte *srcPtr = src + yPos * srcPitch + xPos; - byte *backPtr = backbuf + y * _screenWide + x; - - bool transparent = true; - - if (*srcPtr) { - c1 = *srcPtr; - transparent = false; - } else - c1 = *backPtr; - - if (x < dstWidth - 1) { - if (*(srcPtr + 1)) { - c2 = *(srcPtr + 1); - transparent = false; - } else - c2 = *(backPtr + 1); - } else - c2 = c1; - - if (y < dstHeight - 1) { - if (*(srcPtr + srcPitch)) { - c3 = *(srcPtr + srcPitch); - transparent = false; - } else - c3 = *(backPtr + _screenWide); - } else - c3 = c1; - - if (x < dstWidth - 1 && y < dstHeight - 1) { - if (*(srcPtr + srcPitch + 1)) { - c4 = *(srcPtr + srcPitch + 1); - transparent = false; - } else - c4 = *(backPtr + _screenWide + 1); - } else - c4 = c3; - - if (!transparent) { - uint32 r1 = _palette[c1 * 4 + 0]; - uint32 g1 = _palette[c1 * 4 + 1]; - uint32 b1 = _palette[c1 * 4 + 2]; - - uint32 r2 = _palette[c2 * 4 + 0]; - uint32 g2 = _palette[c2 * 4 + 1]; - uint32 b2 = _palette[c2 * 4 + 2]; - - uint32 r3 = _palette[c3 * 4 + 0]; - uint32 g3 = _palette[c3 * 4 + 1]; - uint32 b3 = _palette[c3 * 4 + 2]; - - uint32 r4 = _palette[c4 * 4 + 0]; - uint32 g4 = _palette[c4 * 4 + 1]; - uint32 b4 = _palette[c4 * 4 + 2]; - - 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; - } - } -} - -/** - * 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 - * @param colour colour of the point - */ - -void Screen::plotPoint(int x, int y, uint8 colour) { - byte *buf = _buffer + MENUDEEP * RENDERWIDE; - - x -= _scrollX; - y -= _scrollY; - - if (x >= 0 && x < RENDERWIDE && y >= 0 && y < RENDERDEEP) { - buf[y * RENDERWIDE + x] = colour; - markAsDirty(x, y + MENUDEEP, x, y + MENUDEEP); - } -} - -static void plot(int x, int y, int colour, void *data) { - Screen *screen = (Screen *)data; - screen->plotPoint(x, y, (uint8) colour); -} - -/** - * 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 - * @param colour colour of the line - */ - -void Screen::drawLine(int x0, int y0, int x1, int y1, uint8 colour) { - Graphics::drawLine(x0, y0, x1, y1, colour, &plot, this); -} - -/** - * 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 - */ - -void Screen::setLocationMetrics(uint16 w, uint16 h) { - _locationWide = w; - _locationDeep = h; - setNeedFullRedraw(); -} - -/** - * Draws a parallax layer at the current position determined by the scroll. A - * parallax can be either foreground, background or the main screen. - */ - -void Screen::renderParallax(byte *ptr, int16 l) { - Parallax p; - int16 x, y; - Common::Rect r; - - p.read(ptr); - - if (_locationWide == _screenWide) - x = 0; - else - x = ((int32)((p.w - _screenWide) * _scrollX) / (int32)(_locationWide - _screenWide)); - - if (_locationDeep == _screenDeep - MENUDEEP * 2) - y = 0; - else - y = ((int32)((p.h - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32)(_locationDeep - (_screenDeep - MENUDEEP * 2))); - - Common::Rect clipRect; - - // Leave enough space for the top and bottom menues - - clipRect.left = 0; - clipRect.right = _screenWide; - clipRect.top = MENUDEEP; - clipRect.bottom = _screenDeep - MENUDEEP; - - for (int j = 0; j < _yBlocks[l]; j++) { - for (int i = 0; i < _xBlocks[l]; i++) { - if (_blockSurfaces[l][i + j * _xBlocks[l]]) { - r.left = i * BLOCKWIDTH - x; - r.right = r.left + BLOCKWIDTH; - r.top = j * BLOCKHEIGHT - y + MENUDEEP; - r.bottom = r.top + BLOCKHEIGHT; - blitBlockSurface(_blockSurfaces[l][i + j * _xBlocks[l]], &r, &clipRect); - } - } - } - - _parallaxScrollX = _scrollX - x; - _parallaxScrollY = _scrollY - y; -} - -// Uncomment this when benchmarking the drawing routines. -#define LIMIT_FRAME_RATE - -/** - * Initialises the timers before the render loop is entered. - */ - -void Screen::initialiseRenderCycle() { - _initialTime = _vm->_system->getMillis(); - _totalTime = _initialTime + MILLISECSPERCYCLE; -} - -/** - * This function should be called when the game engine is ready to start the - * render cycle. - */ - -void Screen::startRenderCycle() { - _scrollXOld = _scrollX; - _scrollYOld = _scrollY; - - _startTime = _vm->_system->getMillis(); - - if (_startTime + _renderAverageTime >= _totalTime) { - _scrollX = _scrollXTarget; - _scrollY = _scrollYTarget; - _renderTooSlow = true; - } else { - _scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _renderTooSlow = false; - } - - if (_scrollXOld != _scrollX || _scrollYOld != _scrollY) - setNeedFullRedraw(); - - _framesPerGameCycle = 0; -} - -/** - * This function should be called at the end of the render cycle. - * @return true if the render cycle is to be terminated, - * or false if it should continue - */ - -bool Screen::endRenderCycle() { - static int32 renderTimeLog[4] = { 60, 60, 60, 60 }; - static int32 renderCountIndex = 0; - int32 time; - - time = _vm->_system->getMillis(); - renderTimeLog[renderCountIndex] = time - _startTime; - _startTime = time; - _renderAverageTime = (renderTimeLog[0] + renderTimeLog[1] + renderTimeLog[2] + renderTimeLog[3]) >> 2; - - _framesPerGameCycle++; - - if (++renderCountIndex == RENDERAVERAGETOTAL) - renderCountIndex = 0; - - if (_renderTooSlow) { - initialiseRenderCycle(); - return true; - } - - if (_startTime + _renderAverageTime >= _totalTime) { - _totalTime += MILLISECSPERCYCLE; - _initialTime = time; - return true; - } - -#ifdef LIMIT_FRAME_RATE - if (_scrollXTarget == _scrollX && _scrollYTarget == _scrollY) { - // If we have already reached the scroll target sleep for the - // rest of the render cycle. - _vm->sleepUntil(_totalTime); - _initialTime = _vm->_system->getMillis(); - _totalTime += MILLISECSPERCYCLE; - return true; - } -#endif - - // 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. - - if (ABS(_scrollX - _scrollXTarget) <= 1 && ABS(_scrollY - _scrollYTarget) <= 1) { - _scrollX = _scrollXTarget; - _scrollY = _scrollYTarget; - } else { - _scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - } - - if (_scrollX != _scrollXOld || _scrollY != _scrollYOld) - setNeedFullRedraw(); - -#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. - _vm->_system->delayMillis(10); -#endif - - return false; -} - -/** - * Reset scrolling stuff. This function is called from initBackground() - */ - -void Screen::resetRenderEngine() { - _parallaxScrollX = 0; - _parallaxScrollY = 0; - _scrollX = 0; - _scrollY = 0; -} - -/** - * This function should be called five times with either the parallax layer - * or a NULL pointer in order of background parallax to foreground parallax. - */ - -int32 Screen::initialiseBackgroundLayer(byte *parallax) { - Parallax p; - uint16 i, j, k; - byte *data; - byte *dst; - - debug(2, "initialiseBackgroundLayer"); - - assert(_layer < MAXLAYERS); - - if (!parallax) { - _layer++; - return RD_OK; - } - - p.read(parallax); - - _xBlocks[_layer] = (p.w + BLOCKWIDTH - 1) / BLOCKWIDTH; - _yBlocks[_layer] = (p.h + BLOCKHEIGHT - 1) / BLOCKHEIGHT; - - _blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *)); - if (!_blockSurfaces[_layer]) - return RDERR_OUTOFMEMORY; - - // Decode the parallax layer into a large chunk of memory - - byte *memchunk = (byte *)calloc(_xBlocks[_layer] * _yBlocks[_layer], BLOCKWIDTH * BLOCKHEIGHT); - if (!memchunk) - return RDERR_OUTOFMEMORY; - - for (i = 0; i < p.h; i++) { - uint32 p_offset = READ_LE_UINT32(parallax + Parallax::size() + 4 * i); - - if (!p_offset) - continue; - - byte *pLine = parallax + p_offset; - uint16 packets = READ_LE_UINT16(pLine); - uint16 offset = READ_LE_UINT16(pLine + 2); - - data = pLine + 4; - dst = memchunk + i * p.w + offset; - - if (!packets) { - memcpy(dst, data, p.w); - continue; - } - - bool zeros = false; - - for (j = 0; j < packets; j++) { - if (zeros) { - dst += *data; - offset += *data; - data++; - zeros = false; - } else if (!*data) { - data++; - zeros = true; - } else { - uint16 count = *data++; - memcpy(dst, data, count); - data += count; - dst += count; - offset += count; - zeros = true; - } - } - } - - // 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. - - for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) { - bool block_has_data = false; - bool block_is_transparent = false; - - int x = BLOCKWIDTH * (i % _xBlocks[_layer]); - int y = BLOCKHEIGHT * (i / _xBlocks[_layer]); - - data = memchunk + p.w * y + x; - - for (j = 0; j < BLOCKHEIGHT; j++) { - for (k = 0; k < BLOCKWIDTH; k++) { - if (x + k < p.w && y + j < p.h) { - if (data[j * p.w + k]) - block_has_data = true; - else - block_is_transparent = true; - } - } - } - - // Only assign a surface to the block if it contains data. - - if (block_has_data) { - _blockSurfaces[_layer][i] = (BlockSurface *)malloc(sizeof(BlockSurface)); - - // Copy the data into the surfaces. - dst = _blockSurfaces[_layer][i]->data; - for (j = 0; j < BLOCKHEIGHT; j++) { - memcpy(dst, data, BLOCKWIDTH); - data += p.w; - dst += BLOCKWIDTH; - } - - _blockSurfaces[_layer][i]->transparent = block_is_transparent; - - } else - _blockSurfaces[_layer][i] = NULL; - } - - free(memchunk); - _layer++; - - return RD_OK; -} - -/** - * Should be called once after leaving the room to free up memory. - */ - -void Screen::closeBackgroundLayer() { - debug(2, "CloseBackgroundLayer"); - - 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; - } - } - - _layer = 0; -} - -#ifdef BACKEND_8BIT -void Screen::plotYUV(byte *lut, int width, int height, byte *const *dat) { - byte *buf = _buffer + ((480 - height) / 2) * RENDERWIDE + (640 - width) / 2; - - int x, y; - - int ypos = 0; - int cpos = 0; - int linepos = 0; - - for (y = 0; y < height; y += 2) { - for (x = 0; x < width; x += 2) { - int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * (BITDEPTH + 1)) + ((dat[1][cpos] + ROUNDADD) >> SHIFT)) * (BITDEPTH + 1); - cpos++; - - buf[linepos ] = lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)]; - buf[RENDERWIDE + linepos++] = lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)]; - buf[linepos ] = lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)]; - buf[RENDERWIDE + linepos++] = lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)]; - } - linepos += (2 * RENDERWIDE - width); - ypos += width; - } -} -#endif - - -} // End of namespace Sword2 |
