patch #790060 SWORD2: Initial graphics work from erik very nice indeed :)

svn-id: r9737
This commit is contained in:
Jonathan Gray 2003-08-17 14:07:16 +00:00
parent d343ef10b3
commit 48ceff0545
6 changed files with 330 additions and 30 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -281,9 +281,8 @@ void Sword2State::go()
Zdebug("CALLING: InitialiseDisplay");
// rv = InitialiseDisplay(640, 480, 8, RD_FULLSCREEN);
_system->init_size(640, 480);
rv = RD_OK;
rv = InitialiseDisplay(640, 480, 8, RD_FULLSCREEN);
Zdebug("RETURNED with rv = %.8x", rv);
if (rv != RD_OK)