aboutsummaryrefslogtreecommitdiff
path: root/sword2/driver
diff options
context:
space:
mode:
authorJonathan Gray2003-08-17 14:07:16 +0000
committerJonathan Gray2003-08-17 14:07:16 +0000
commit48ceff05456579fc2c93a04a2f6540520b3d8458 (patch)
tree92a04e35f4727a63c30b6b90f17c9555b4ce81d1 /sword2/driver
parentd343ef10b3b5b4ca75feb2ab1ddbab19ecca9d8b (diff)
downloadscummvm-rg350-48ceff05456579fc2c93a04a2f6540520b3d8458.tar.gz
scummvm-rg350-48ceff05456579fc2c93a04a2f6540520b3d8458.tar.bz2
scummvm-rg350-48ceff05456579fc2c93a04a2f6540520b3d8458.zip
patch #790060 SWORD2: Initial graphics work from erik very nice indeed :)
svn-id: r9737
Diffstat (limited to 'sword2/driver')
-rw-r--r--sword2/driver/d_draw.cpp20
-rw-r--r--sword2/driver/d_draw.h4
-rw-r--r--sword2/driver/driver96.h28
-rw-r--r--sword2/driver/palette.cpp15
-rw-r--r--sword2/driver/render.cpp290
5 files changed, 329 insertions, 28 deletions
diff --git a/sword2/driver/d_draw.cpp b/sword2/driver/d_draw.cpp
index 8971a79174..0c4891e427 100644
--- a/sword2/driver/d_draw.cpp
+++ b/sword2/driver/d_draw.cpp
@@ -45,6 +45,8 @@
#define MILLISECSPERCYCLE 83
+// Surface *lpPrimarySurface;
+Surface *lpBackBuffer;
/*
LPDIRECTDRAW7 m_pDD;
@@ -234,6 +236,12 @@ int32 RestoreDisplay(void)
int32 InitialiseDisplay(int16 width, int16 height, int16 colourDepth, int32 windowType)
{
+ screenWide = width;
+ screenDeep = height;
+
+// lpPrimarySurface = new Surface(width, height);
+ lpBackBuffer = new Surface(width, height);
+
/*
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
@@ -715,7 +723,11 @@ int32 GetRenderType(void)
int32 FlipScreens(void)
{
- warning("stub FlipScreens");
+ // I think this function can be removed. We render to lpBackBuffer,
+ // and the backend acts as the primary buffer.
+
+ debug(0, "FlipScreens");
+
/*
HRESULT hr;
BOOL vbl;
@@ -825,7 +837,9 @@ int32 WaitForVbl(void)
int32 EraseBackBuffer( void )
{
- warning("stub EraseBackBuffer");
+ debug(0, "EraseBackBuffer");
+ lpBackBuffer->clear();
+
/*
DDBLTFX ddbltfx;
HRESULT hr;
@@ -1224,7 +1238,7 @@ void GetDrawStatus(_drvDrawStatus *s)
// s->lpDraw = lpDraw;
// s->lpDD2 = lpDD2;
// s->lpPrimarySurface = lpPrimarySurface;
-// s->lpBackBuffer = lpBackBuffer;
+ s->lpBackBuffer = lpBackBuffer;
// s->lpPalette = lpPalette;
s->screenDeep = screenDeep;
s->screenWide = screenWide;
diff --git a/sword2/driver/d_draw.h b/sword2/driver/d_draw.h
index cc2ed6532f..3c6adad86d 100644
--- a/sword2/driver/d_draw.h
+++ b/sword2/driver/d_draw.h
@@ -78,8 +78,8 @@ extern "C" {
extern uint8 *lpPalette; // palette
-extern uint8 *lpBackBuffer; // back surface
-extern uint8 *lpPrimarySurface; // DirectDraw front buffer.
+extern Surface *lpBackBuffer; // back surface
+// extern Surface *lpPrimarySurface; // DirectDraw front buffer.
extern uint8 *lpDD2; // DirectDraw2 object
extern BOOL bFullScreen; // Defines whether the app is running in full screen mode or not.
//extern DDCOLORKEY blackColorKey; // transparent pixel for color key blitting.
diff --git a/sword2/driver/driver96.h b/sword2/driver/driver96.h
index 9904fd14f2..476ed1245e 100644
--- a/sword2/driver/driver96.h
+++ b/sword2/driver/driver96.h
@@ -1053,6 +1053,7 @@
#include "common/scummsys.h"
#include "common/engine.h" // for warning()
#include "common/system.h"
+#include "common/rect.h"
//#include "ddraw.h"
//#include "dsound.h"
@@ -1254,6 +1255,29 @@ typedef int BOOL;
#define TRUE 1
#define FALSE 0
+// FIXME: Temporary (?) surface class to replace LPDIRECTDRAWSURFACE for now.
+
+class Surface {
+public:
+ uint16 _width, _height;
+ uint16 _pitch;
+ byte *_pixels;
+
+ Surface(uint width, uint height) {
+ _width = width;
+ _height = height;
+ _pixels = (byte *) calloc(_width, _height);
+ };
+
+ ~Surface() {
+ free(_pixels);
+ };
+
+ void clear();
+ void blit(Surface *s, ScummVM::Rect *r);
+ void blit(Surface *s, ScummVM::Rect *r, ScummVM::Rect *clip_rect);
+};
+
//
// Structure definitions
// ---------------------
@@ -1351,8 +1375,8 @@ typedef struct
// HWND hwnd;
// LPDIRECTDRAW lpDraw;
// LPDIRECTDRAW2 lpDD2;
-// LPDIRECTDRAWSURFACE lpPrimarySurface;
-// LPDIRECTDRAWSURFACE lpBackBuffer;
+// Surface *lpPrimarySurface;
+ Surface *lpBackBuffer;
// LPDIRECTDRAWPALETTE lpPalette;
int16 screenDeep;
int16 screenWide;
diff --git a/sword2/driver/palette.cpp b/sword2/driver/palette.cpp
index f832a5481e..c9d6cf6cb2 100644
--- a/sword2/driver/palette.cpp
+++ b/sword2/driver/palette.cpp
@@ -318,7 +318,20 @@ __inline uint8 QuickMatch(uint8 r, uint8 g, uint8 b)
int32 SetPalette(int16 startEntry, int16 noEntries, uint8 *colourTable, uint8 fadeNow)
{
- warning("stub SetPalette( %d, %d, %d )", startEntry, noEntries, fadeNow);
+ debug(0, "SetPalette(%d, %d, %d)", startEntry, noEntries, fadeNow);
+
+ StackLock lock(g_sword2->_paletteMutex);
+
+ if (noEntries == 0) {
+ RestorePalette();
+ return RD_OK;
+ }
+
+ // FIXME: Handle the fadeNow parameter
+
+ memcpy(&palCopy[startEntry][0], colourTable, noEntries * 4);
+ g_sword2->_system->set_palette((byte *) palCopy, startEntry, noEntries);
+
/*
int32 hr;
diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp
index c4065a2692..9e56a3bee0 100644
--- a/sword2/driver/render.cpp
+++ b/sword2/driver/render.cpp
@@ -208,6 +208,7 @@
#include "_mouse.h"
#include "render.h"
#include "menu.h"
+#include "../sword2.h"
@@ -248,7 +249,7 @@ static int16 scrollxTarget;
static int16 scrollyTarget;
static int16 scrollxOld;
static int16 scrollyOld;
-//static uint16 layer = 0;
+static uint16 layer = 0;
@@ -275,14 +276,90 @@ int32 renderTooSlow;
uint8 xblocks[MAXLAYERS];
uint8 yblocks[MAXLAYERS];
uint8 restoreLayer[MAXLAYERS];
-//LPDIRECTDRAWSURFACE *blockSurfaces[MAXLAYERS] = {0,0,0,0,0};
+// Each layer is composed by several sub-blocks
+
+Surface **blockSurfaces[MAXLAYERS] = { 0, 0, 0, 0, 0 };
+
+
+
+void Surface::clear() {
+ memset(_pixels, 0, _width * _height);
+ g_sword2->_system->copy_rect(_pixels, _width, 0, 0, _width, _height);
+}
+
+void Surface::blit(Surface *s, ScummVM::Rect *r) {
+ ScummVM::Rect clip_rect;
+
+ clip_rect.left = 0;
+ clip_rect.top = 0;
+ clip_rect.right = 640;
+ clip_rect.bottom = 480;
+
+ blit(s, r, &clip_rect);
+}
+
+void Surface::blit(Surface *s, ScummVM::Rect *r, ScummVM::Rect *clip_rect) {
+ if (r->top > clip_rect->bottom || r->left > clip_rect->right || r->bottom <= clip_rect->top || r->right <= clip_rect->left)
+ return;
+
+ byte *src = s->_pixels;
+
+ if (r->top < clip_rect->top) {
+ src -= s->_width * (r->top - clip_rect->top);
+ r->top = clip_rect->top;
+ }
+ if (r->left < clip_rect->left) {
+ src -= (r->left - clip_rect->left);
+ r->left = clip_rect->left;
+ }
+ if (r->bottom > clip_rect->bottom)
+ r->bottom = clip_rect->bottom;
+ if (r->right > clip_rect->right)
+ r->right = clip_rect->right;
+
+ byte *dst = _pixels + r->top * _width + r->left;
+ int i, j;
+
+ // FIXME: We first render the data to the back buffer, and then copy
+ // it to the backend. Since the same area will probably be copied
+ // several times, as each new parallax layer is rendered, this may be
+ // a bit inefficient.
+
+ for (i = 0; i < r->bottom - r->top; i++) {
+ for (j = 0; j < r->right - r->left; j++) {
+ if (src[j])
+ dst[j] = src[j];
+ }
+ src += s->_width;
+ dst += _width;
+ }
+
+ g_sword2->_system->copy_rect(_pixels + r->top * _width + r->left, _width, r->left, r->top, r->right - r->left, r->bottom - r->top);
+}
int32 RestoreBackgroundLayer(_parallax *p, int16 l)
{
- warning("stub RestoreBackgroundLayer %d", l);
+ int16 oldLayer = layer;
+ int16 i;
+
+ debug(0, "RestoreBackgroundLayer %d", l);
+
+ layer = l;
+ if (blockSurfaces[l]) {
+ for (i = 0; i < xblocks[l] * yblocks[l]; i++)
+ if (blockSurfaces[l][i])
+ delete blockSurfaces[l][i];
+
+ free(blockSurfaces[l]);
+ blockSurfaces[l] = NULL;
+ }
+ RestoreSurfaces();
+ InitialiseBackgroundLayer(p);
+ layer = oldLayer;
+
/*
int16 oldLayer = layer;
int16 i;
@@ -605,10 +682,47 @@ int32 SetLocationMetrics(uint16 w, uint16 h)
-int32 RenderParallax(_parallax *p, int16 layer)
+int32 RenderParallax(_parallax *p, int16 l) {
+ int16 x, y;
+ int16 i, j;
+ ScummVM::Rect r;
+
+ debug(0, "RenderParallax %d", l);
+
+ 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)));
+
+ ScummVM::Rect clip_rect;
+
+ // Leave enough space for the top and bottom menues
+
+ clip_rect.left = 0;
+ clip_rect.right = 640;
+ clip_rect.top = 40;
+ clip_rect.bottom = 440;
+
+ for (j = 0; j < yblocks[l]; j++) {
+ for (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 + 40;
+ r.bottom = r.top + BLOCKHEIGHT;
+ lpBackBuffer->blit(blockSurfaces[l][i + j * xblocks[l]], &r, &clip_rect);
+ }
+ }
+ }
+
+ parallaxScrollx = scrollx - x;
+ parallaxScrolly = scrolly - y;
-{
- warning("stub RenderParallax %d", layer);
/*
#if PROFILING == 1
@@ -619,7 +733,7 @@ int32 RenderParallax(_parallax *p, int16 layer)
#endif
- if ((renderCaps & RDBLTFX_ALLHARDWARE) || ((renderCaps & RDBLTFX_FGPARALLAX) && (layer > 2)))
+ if ((renderCaps & RDBLTFX_ALLHARDWARE) || ((renderCaps & RDBLTFX_FGPARALLAX) && (l > 2)))
{
int16 x, y;
@@ -628,10 +742,10 @@ int32 RenderParallax(_parallax *p, int16 layer)
HRESULT hr = 0;
RECT r, rd;
- if (restoreLayer[layer])
+ if (restoreLayer[l])
{
- RestoreBackgroundLayer(p, layer);
- restoreLayer[layer] = 0;
+ RestoreBackgroundLayer(p, l);
+ restoreLayer[l] = 0;
}
if (locationWide == screenWide)
@@ -648,12 +762,12 @@ int32 RenderParallax(_parallax *p, int16 layer)
while (TRUE)
{
j = 0;
- while (j < yblocks[layer])
+ while (j < yblocks[l])
{
i = 0;
- while (i < xblocks[layer])
+ while (i < xblocks[l])
{
- if (*(blockSurfaces[layer] + i + j * xblocks[layer]))
+ if (*(blockSurfaces[l] + i + j * xblocks[l]))
{
r.left = i * BLOCKWIDTH - x;
r.right = r.left + BLOCKWIDTH;
@@ -684,7 +798,7 @@ int32 RenderParallax(_parallax *p, int16 layer)
rd.bottom = BLOCKHEIGHT - (r.bottom - 440);
r.bottom = 440;
}
- hr = IDirectDrawSurface2_Blt(lpBackBuffer, &r, *(blockSurfaces[layer] + i + j * xblocks[layer]), &rd, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &r, *(blockSurfaces[l] + i + j * xblocks[l]), &rd, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
if (hr == DDERR_INVALIDRECT)
hr = 0;
if (hr)
@@ -707,7 +821,7 @@ int32 RenderParallax(_parallax *p, int16 layer)
if (++restoreSurfaces == 4)
return(RDERR_RESTORELAYERS);
else
- RestoreBackgroundLayer(p, layer);
+ RestoreBackgroundLayer(p, l);
}
else
return(RD_OK);
@@ -996,7 +1110,14 @@ int32 SetScrollTarget(int16 sx, int16 sy)
int32 CopyScreenBuffer(void)
{
- warning("stub CopyScreenBuffer");
+ debug(0, "CopyScreenBuffer");
+
+ // FIXME: The backend should keep track of dirty rects, but I have a
+ // feeling each one may be drawn several times, so we may have do add
+ // our own handling of them instead.
+
+ g_sword2->_system->update_screen();
+
/*
uint8 *dst, *src;
@@ -1065,10 +1186,126 @@ int32 CopyScreenBuffer(void)
-int32 InitialiseBackgroundLayer(_parallax *p)
+int32 InitialiseBackgroundLayer(_parallax *p) {
+ uint8 *memchunk;
+ uint32 *quaddata;
+ uint8 zeros;
+ uint16 count;
+ uint16 i, j, k;
+ uint16 x;
+ uint8 *data;
+ uint8 *dst;
+ _parallaxLine *line;
+
+ debug(0, "InitialiseBackgroundLayer");
+
+ // This function is called to re-initialise the layers if they have
+ // been lost. We know this if the layers have already been assigned.
+
+ // TODO: Can layers still be lost, or is that a DirectDraw-ism?
+
+ if (layer == MAXLAYERS)
+ CloseBackgroundLayer();
+
+ if (!p) {
+ layer++;
+ return RD_OK;
+ }
+
+ xblocks[layer] = (p->w + BLOCKWIDTH - 1) >> BLOCKWBITS;
+ yblocks[layer] = (p->h + BLOCKHEIGHT - 1) >> BLOCKHBITS;
+
+ blockSurfaces[layer] = (Surface **) calloc(xblocks[layer] * yblocks[layer], sizeof(Surface *));
+ if (!blockSurfaces[layer])
+ return RDERR_OUTOFMEMORY;
+
+ // Decode the parallax layer into a large chunk of memory
+
+ memchunk = (uint8 *) malloc(xblocks[layer] * BLOCKWIDTH * yblocks[layer] * BLOCKHEIGHT);
+ if (!memchunk)
+ return RDERR_OUTOFMEMORY;
+
+ // We clear not the entire memory chunk, but enough of it to store
+ // the entire parallax layer.
+
+ memset(memchunk, 0, p->w * p->h);
+
+ for (i = 0; i < p->h; i++) {
+ if (p->offset[i] == 0)
+ continue;
+
+ line = (_parallaxLine *) ((uint8 *) p + p->offset[i]);
+ data = (uint8 *) line + sizeof(_parallaxLine);
+ x = line->offset;
+
+ dst = memchunk + i * p->w + x;
+
+ zeros = 0;
+ if (line->packets == 0) {
+ memcpy(dst, data, p->w);
+ continue;
+ }
+
+ for (j = 0; j < line->packets; j++) {
+ if (zeros) {
+ dst += *data;
+ x += *data;
+ data++;
+ zeros = 0;
+ } else if (*data == 0) {
+ data++;
+ zeros = 1;
+ } else {
+ count = *data++;
+ memcpy(dst, data, count);
+ data += count;
+ dst += count;
+ x += count;
+ zeros = 1;
+ }
+ }
+ }
+
+ // Now create the surfaces!
+
+ for (i = 0; i < xblocks[layer] * yblocks[layer]; i++) {
+ bool block_has_data = false;
+
+ data = memchunk + (p->w * BLOCKHEIGHT * (i / xblocks[layer])) + BLOCKWIDTH * (i % xblocks[layer]);
+
+ quaddata = (uint32 *) data;
+
+ for (j = 0; j < BLOCKHEIGHT; j++) {
+ for (k = 0; k < BLOCKWIDTH / 4; k++) {
+ if (*quaddata) {
+ block_has_data = true;
+ goto bailout;
+ }
+ quaddata++;
+ }
+ quaddata += ((p->w - BLOCKWIDTH) / 4);
+ }
+
+bailout:
+
+ // Only assign a surface to the block if it contains data.
+
+ if (block_has_data) {
+ blockSurfaces[layer][i] = new Surface(BLOCKWIDTH, BLOCKHEIGHT);
+
+ // Copy the data into the surfaces.
+ dst = blockSurfaces[layer][i]->_pixels;
+ for (j = 0; j < BLOCKHEIGHT; j++) {
+ memcpy(dst, data, BLOCKWIDTH);
+ data += p->w;
+ dst += BLOCKWIDTH;
+ }
+ } else
+ blockSurfaces[layer][i] = NULL;
+ }
+ free(memchunk);
+ layer++;
-{
- warning("stub InitialiseBackgroundLayer");
/*
uint8 *memchunk;
uint32 *quaddata;
@@ -1252,7 +1489,20 @@ int32 InitialiseBackgroundLayer(_parallax *p)
int32 CloseBackgroundLayer(void)
{
- warning("stub CloseBackgroundLayer");
+ debug(0, "CloseBackgroundLayer");
+
+ int16 i, j;
+
+ for (j = 0; j < MAXLAYERS; j++) {
+ if (blockSurfaces[j]) {
+ for (i = 0; i < xblocks[j] * yblocks[j]; i++)
+ if (blockSurfaces[j][i])
+ delete blockSurfaces[j][i];
+ free(blockSurfaces[j]);
+ }
+ }
+
+ layer = 0;
/*
int16 i, j;