aboutsummaryrefslogtreecommitdiff
path: root/sword2
diff options
context:
space:
mode:
authorJonathan Gray2003-07-28 01:47:41 +0000
committerJonathan Gray2003-07-28 01:47:41 +0000
commitdc6aa9912c73e1e03c32b6b214c5fbc46aa1eb57 (patch)
tree5c6bb0d5236aa9d5102d1cd7d6821fd3848086f8 /sword2
parentf020d28b5e9297f93d5bedae62885b380c23f517 (diff)
downloadscummvm-rg350-dc6aa9912c73e1e03c32b6b214c5fbc46aa1eb57.tar.gz
scummvm-rg350-dc6aa9912c73e1e03c32b6b214c5fbc46aa1eb57.tar.bz2
scummvm-rg350-dc6aa9912c73e1e03c32b6b214c5fbc46aa1eb57.zip
bs2 driver
svn-id: r9212
Diffstat (limited to 'sword2')
-rw-r--r--sword2/driver/.cvsignore1
-rw-r--r--sword2/driver/_console.cpp165
-rw-r--r--sword2/driver/_console.h47
-rw-r--r--sword2/driver/_mouse.cpp618
-rw-r--r--sword2/driver/_mouse.h54
-rw-r--r--sword2/driver/d_draw.cpp1274
-rw-r--r--sword2/driver/d_draw.h96
-rw-r--r--sword2/driver/d_sound.cpp3095
-rw-r--r--sword2/driver/d_sound.h43
-rw-r--r--sword2/driver/ddutil.h159
-rw-r--r--sword2/driver/driver96.h1665
-rw-r--r--sword2/driver/keyboard.cpp129
-rw-r--r--sword2/driver/keyboard.h46
-rw-r--r--sword2/driver/language.cpp134
-rw-r--r--sword2/driver/menu.cpp570
-rw-r--r--sword2/driver/menu.h47
-rw-r--r--sword2/driver/misc.cpp62
-rw-r--r--sword2/driver/palette.cpp482
-rw-r--r--sword2/driver/palette.h66
-rw-r--r--sword2/driver/rdwin.cpp627
-rw-r--r--sword2/driver/rdwin.h56
-rw-r--r--sword2/driver/render.cpp1283
-rw-r--r--sword2/driver/render.h93
-rw-r--r--sword2/driver/sprite.cpp3240
24 files changed, 14052 insertions, 0 deletions
diff --git a/sword2/driver/.cvsignore b/sword2/driver/.cvsignore
new file mode 100644
index 0000000000..39a06683b7
--- /dev/null
+++ b/sword2/driver/.cvsignore
@@ -0,0 +1 @@
+.deps
diff --git a/sword2/driver/_console.cpp b/sword2/driver/_console.cpp
new file mode 100644
index 0000000000..fe9bb69cd1
--- /dev/null
+++ b/sword2/driver/_console.cpp
@@ -0,0 +1,165 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : console.c
+// Created : 19th September 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the code which controls and displays
+// the console/debugging window.
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 20-Sep-96 PRP Inital console code. Currently draws the
+// background of the console window. Tex
+//
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// int32 OpenConsole(void)
+//
+// Displays the console window and directs keyboard input to it.
+//
+// --------------------------------------------------------------------------
+//
+// int32 CloseConsole(void)
+//
+// Removes the console from the display.
+//
+//=============================================================================
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+
+#include "d_draw.h"
+
+
+
+uint8 consoleStatus = 0; // 1 - console display
+static uint16 consoley = 0;
+static uint32 consoleSize;
+static uint8 *consoleSprite = NULL;
+
+
+
+// --------------------------------------------------------------------------
+// Called before the screens are flipped, so that the console can be drawn
+// over the screen if necessary.
+// --------------------------------------------------------------------------
+void DisplayConsole(void)
+
+{
+ warning("stub DisplayConsole");
+/*
+ uint8 *src, *dst;
+ uint8 i;
+// DDSURFACEDESC ddDescription;
+// HRESULT hr;
+
+
+ if (consoleStatus)
+ {
+
+ ddDescription.dwSize = sizeof(ddDescription);
+
+ hr = IDirectDrawSurface_Lock(lpBackBuffer, NULL, &ddDescription, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ RestoreSurfaces();
+ hr = IDirectDrawSurface_Lock(lpBackBuffer, NULL, &ddDescription, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ }
+
+ if (hr == DD_OK)
+ {
+
+ dst = (uint8 *) ddDescription.lpSurface + (screenDeep - consoley) * ddDescription.lPitch;
+ src = (uint8 *) consoleSprite;
+
+ for (i=0; i<consoley; i++)
+ {
+ memcpy(dst, src, screenWide);
+ src += screenWide;
+ dst += ddDescription.lPitch;
+ }
+ IDirectDrawSurface_Unlock(lpBackBuffer, ddDescription.lpSurface);
+ }
+ }
+ */
+}
+
+
+
+
+int32 OpenConsole(void)
+
+{
+ warning("stub OpenConsole");
+/*
+ if (consoleStatus)
+ return(RDERR_ALREADYOPEN);
+
+ if (consoleSprite == NULL)
+ {
+ consoley = screenDeep >> 2;
+ consoleSize = screenWide * consoley;
+ consoleSprite = (uint8 *) malloc(consoleSize);
+ }
+
+ if (consoleSprite == NULL)
+ return(RDERR_OUTOFMEMORY);
+
+ memset(consoleSprite, 0, consoleSize);
+*/
+ consoleStatus = 1;
+
+ return(RD_OK);
+
+}
+
+
+
+
+int32 CloseConsole(void)
+
+{
+
+ if (!consoleStatus)
+ return(RDERR_ALREADYCLOSED);
+
+ free(consoleSprite);
+ consoleSprite = NULL;
+
+ consoleStatus = 0;
+
+ return(RD_OK);
+
+}
+
diff --git a/sword2/driver/_console.h b/sword2/driver/_console.h
new file mode 100644
index 0000000000..8907a00164
--- /dev/null
+++ b/sword2/driver/_console.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : console.h
+// Created : 19th September 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 20-Sep-96 PRP Internal driver interface to the console
+// functions and data.
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the console.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//=============================================================================
+
+
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+
+
+extern void DisplayConsole(void);
+
+
+#endif
diff --git a/sword2/driver/_mouse.cpp b/sword2/driver/_mouse.cpp
new file mode 100644
index 0000000000..da2627a3f1
--- /dev/null
+++ b/sword2/driver/_mouse.cpp
@@ -0,0 +1,618 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : mouse.c
+// Created : 17th September 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the interface to the mouse..
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 18-Sep-96 PRP Initial mouse functions. Simple logging of
+// previous 16 mouse events implemented. Mouse
+// drawing is currently hard coded, but animations
+// will be definable at a later date.
+//
+// 1.1 03-Oct-96 PRP Changed the mouse position so that mouse y of
+// zero is the top left corner of the screen, and
+// not the top left corner of the top menubar.
+// Also, removed the x and y position from the
+// mouse log. And changed the MouseEvent function
+// so that it returns a pointer to _mouseEvent
+//
+// 1.2 04-Oct-96 PRP Put direct path in for ddraw.h
+//
+// 1.3 31-Oct-96 PRP Added code to draw the proper type of mouse
+// sprite, which comprises of the internal
+// function DrawMouse and globally available
+// AnimateMouse and SetMouseAnim.
+//
+// 1.4 15-Nov-96 PRP Definition of menubar size is now obtained
+// from menu.h
+//
+// 1.5 18-Nov-96 PRP Changed the direct draw interface to
+// IDirectDraw2.
+//
+// 1.6 25-Nov-96 PRP Added functionality to set the luggage
+// sprite.
+//
+// 1.7 06-Jan-97 PRP Changed the width and height of sprites
+// to be signed.
+//
+// 1.8 14-Jan-97 JEL Reset mouse frame when new animation starts.
+//
+// 1.9 27-Jan-97 PRP Changed the mouse drawing routines to utilize
+// directDraw surfaces and transparency blitting.
+//
+// 1.10 10-Feb-97 PRP Changed the directDraw error reporting so that
+// it works properly. Also, created the mouse
+// sprite depending upon whether the hardware can
+// blt or not.
+//
+// 1.11 19-Mar-97 PRP Fixed a bug which was causing the mouse sprite
+// to be freed up each frame and therefore
+// decompressed and re-loaded each frame.
+//
+// 1.12 20-Mar-97 PRP Added a function to reset the render code when
+// the control panel is entered.
+//
+// 1.13 09-Apr-97 PRP Made the mouse animation wrap back to the
+// seventh frame.
+//
+// 1.14 10-Apr-97 PRP Added parameter to define whether mouse flashes
+// or not.
+//
+// 1.15 23-Jul-97 JEL Added CheckForMouseEvents() to return no. of events outstanding
+//
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// _mouseEvent *MouseEvent(void)
+//
+// The address of a _mouseEvent pointer is passed in. If there is a mouse
+// event in the queue, a the value of the mouse event pointer is set to the
+// address of the event, otherwise, the mouse event pointer is set to NULL.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetMouseAnim(uint8 *ma, int32 size)
+//
+// A pointer to a valid mouse animation is passed in, along with the size of
+// the header plus sprite data. Remember to check that the function has
+// successfully completed, as memory allocation is required.
+// Pass NULL in to clear the mouse sprite.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetLuggageAnim(uint8 *ma, int32 size)
+//
+// A pointer to a valid luggage animation is passed in, along with the size of
+// the header plus sprite data. Remember to check that the function has
+// successfully completed, as memory allocation is required.
+// Pass NULL in to clear the luggage sprite. Luggage sprites are of the same
+// format as mouse sprites.
+//
+// --------------------------------------------------------------------------
+//
+// int32 AnimateMouse(void)
+//
+// This function animates the current mouse pointer. If no pointer is
+// currently defined, an error code is returned.
+//
+//=============================================================================
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+
+#include "d_draw.h"
+#include "render.h"
+#include "menu.h"
+
+
+
+#define MAX_MOUSE_EVENTS 16
+#define MOUSEFLASHFRAME 6
+
+
+typedef struct
+{
+ uint8 runTimeComp; // type of runtime compression used for the frame data
+ uint8 noAnimFrames; // number of frames in the anim
+ int8 xHotSpot;
+ int8 yHotSpot;
+ uint8 mousew;
+ uint8 mouseh;
+} _mouseAnim;
+
+
+int16 mousex;
+int16 mousey;
+
+static uint8 mouseBacklog = 0;
+static uint8 mouseLogPos = 0;
+static uint8 mouseFrame;
+static uint8 luggageFrame = 0;
+static uint8 *mouseSprite = NULL;
+static _mouseAnim *mouseAnim = NULL;
+static _mouseAnim *luggageAnim = NULL;
+static _mouseEvent mouseLog[MAX_MOUSE_EVENTS];
+static int32 *mouseOffsets;
+static int32 *luggageOffset;
+//static LPDIRECTDRAWSURFACE *mouseSurfaces;
+//static LPDIRECTDRAWSURFACE luggageSurface = NULL;
+
+
+
+
+
+
+
+void ResetRenderEngine(void)
+
+{
+
+ memset(myScreenBuffer, 0, RENDERWIDE * RENDERDEEP);
+ parallaxScrollx = 0;
+ parallaxScrolly = 0;
+ scrollx = 0;
+ scrolly = 0;
+
+}
+
+
+
+
+// --------------------------------------------------------------------------
+// Logs the mouse button event passed in buttons. The button events are
+// defined as RD_LEFTBUTTONDOWN, RD_LEFTBUTTONUP, RD_RIGHTBUTTONDOWN and
+// RD_RIGHTBUTTONUP.
+// --------------------------------------------------------------------------
+void LogMouseEvent(uint16 buttons)
+
+{
+
+ _mouseEvent *me;
+
+
+ if (mouseBacklog == MAX_MOUSE_EVENTS-1) // We need to leave the one which is
+ { // the current event alone!
+ return;
+ }
+
+ me = &mouseLog[(mouseBacklog + mouseLogPos) % MAX_MOUSE_EVENTS];
+ me->buttons = buttons;
+ mouseBacklog += 1;
+
+}
+
+
+
+
+
+
+int32 DecompressMouse(uint8 *decomp, uint8 *comp, int32 size)
+
+{
+
+ int32 i = 0;
+
+ while (i < size)
+ {
+ if (*comp > 183)
+ {
+ *decomp++ = *comp++;
+ i += 1;
+ }
+ else
+ {
+ memset(decomp, 0, *comp);
+ decomp += *comp;
+ i += *comp++;
+ }
+ }
+ return(RD_OK);
+}
+
+
+
+// --------------------------------------------------------------------------
+// Draws the mouse sprite to the back buffer.
+// --------------------------------------------------------------------------
+int32 DrawMouse(void)
+
+{
+ warning("stub DrawMouse");
+/*
+ uint8 *src, *dst;
+ int16 i;
+ int16 xoff=0, yoff=0;
+ uint8 *decompSprite;
+ DDSURFACEDESC ddsd;
+ HRESULT hr;
+ RECT rs, rd;
+
+
+
+ if (luggageAnim)
+ {
+
+ if (luggageSurface == NULL)
+ {
+ // Create the luggage surface.
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ if (dxHalCaps & RDCAPS_SRCBLTCKEY)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+
+ ddsd.dwWidth = luggageAnim->mousew;
+ ddsd.dwHeight = luggageAnim->mouseh;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &luggageSurface, NULL);
+ if (hr != DD_OK)
+ {
+ if (hr == DDERR_OUTOFVIDEOMEMORY)
+ {
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &luggageSurface, NULL);
+ }
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create mouse surface", hr);
+ return(hr);
+ }
+ }
+ // Set the surface blt source colour key
+ hr = IDirectDrawSurface2_SetColorKey(luggageSurface, DDCKEY_SRCBLT, &blackColorKey);
+
+ // Copy the data into the surfaces.
+ decompSprite = (uint8 *) malloc(luggageAnim->mousew * luggageAnim->mouseh);
+ if (decompSprite == NULL)
+ return(RDERR_OUTOFMEMORY);
+// DecompressMouse(decompSprite, (uint8 *) luggageAnim + *mouseOffsets, luggageAnim->mousew * luggageAnim->mouseh);
+ DecompressMouse(decompSprite, (uint8 *) luggageAnim + *luggageOffset, luggageAnim->mousew * luggageAnim->mouseh);
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ hr = IDirectDrawSurface2_Lock(luggageSurface, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ IDirectDrawSurface2_Restore(luggageSurface);
+ hr = IDirectDrawSurface2_Lock(luggageSurface, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to lock luggage surface", hr);
+ return(hr);
+ }
+ }
+ dst = ddsd.lpSurface;
+ src = decompSprite;
+ for (i=0; i<luggageAnim->mouseh; i++)
+ {
+ memcpy(dst, src, luggageAnim->mousew);
+ dst += ddsd.lPitch;
+ src += luggageAnim->mousew;
+ }
+ IDirectDrawSurface2_Unlock(luggageSurface, ddsd.lpSurface);
+ free(decompSprite);
+ }
+
+
+ rd.top = mousey + MENUDEEP - luggageAnim->yHotSpot;
+ rd.bottom = rd.top + luggageAnim->mouseh;
+ rd.left = mousex - luggageAnim->xHotSpot;
+ rd.right = rd.left + luggageAnim->mousew;
+
+ rs.left = 0;
+ rs.right = luggageAnim->mousew;
+ rs.top = 0;
+ rs.bottom = luggageAnim->mouseh;
+
+ if (rd.left < 0)
+ {
+ rs.left = 0 - rd.left;
+ rd.left = 0;
+ }
+ if (rd.top < 0)
+ {
+ rs.top = 0 - rd.top;
+ rd.top = 0;
+ }
+ if (rd.right > RENDERWIDE)
+ {
+ rs.right -= (rd.right - RENDERWIDE);
+ rd.right = RENDERWIDE;
+ }
+ if (rd.bottom > ALIGNRENDERDEEP)
+ {
+ rs.bottom -= (rd.bottom - ALIGNRENDERDEEP);
+ rd.bottom = ALIGNRENDERDEEP;
+ }
+
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &rd, luggageSurface, &rs, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
+ if (hr = DDERR_SURFACELOST)
+ {
+ IDirectDrawSurface2_Release(luggageSurface);
+ luggageSurface = NULL;
+ }
+
+ }
+
+ if (mouseAnim == NULL)
+ {
+ return(RD_OK);
+ }
+
+
+ // Decompress the mouse sprite onto the directDraw surface, if it is not
+ // there already.
+ if (*(mouseSurfaces + mouseFrame) == NULL)
+ {
+
+ // Create the mouse surface.
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ if (dxHalCaps & RDCAPS_SRCBLTCKEY)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+
+ ddsd.dwWidth = mouseAnim->mousew;
+ ddsd.dwHeight = mouseAnim->mouseh;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, mouseSurfaces + mouseFrame, NULL);
+ if (hr != DD_OK)
+ {
+ if (hr == DDERR_OUTOFVIDEOMEMORY)
+ {
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, mouseSurfaces + mouseFrame, NULL);
+ }
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create mouse surface", hr);
+ return(hr);
+ }
+ }
+ // Set the surface blt source colour key
+ hr = IDirectDrawSurface2_SetColorKey(*(mouseSurfaces + mouseFrame), DDCKEY_SRCBLT, &blackColorKey);
+
+ // Copy the data into the surfaces.
+ decompSprite = (uint8 *) malloc(mouseAnim->mousew * mouseAnim->mouseh);
+ if (decompSprite == NULL)
+ return(RDERR_OUTOFMEMORY);
+ DecompressMouse(decompSprite, mouseSprite, mouseAnim->mousew * mouseAnim->mouseh);
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ hr = IDirectDrawSurface2_Lock(*(mouseSurfaces + mouseFrame), NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ IDirectDrawSurface2_Restore(*(mouseSurfaces + mouseFrame));
+ hr = IDirectDrawSurface2_Lock(*(mouseSurfaces + mouseFrame), NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot lock mouse surface", hr);
+ return(hr);
+ }
+ }
+ dst = ddsd.lpSurface;
+ src = decompSprite;
+ for (i=0; i<mouseAnim->mouseh; i++)
+ {
+ memcpy(dst, src, mouseAnim->mousew);
+ dst += ddsd.lPitch;
+ src += mouseAnim->mousew;
+ }
+ IDirectDrawSurface2_Unlock(*(mouseSurfaces + mouseFrame), ddsd.lpSurface);
+ free(decompSprite);
+ }
+
+
+ rd.top = mousey + MENUDEEP - mouseAnim->yHotSpot;
+ rd.bottom = rd.top + mouseAnim->mouseh;
+ rd.left = mousex - mouseAnim->xHotSpot;
+ rd.right = rd.left + mouseAnim->mousew;
+
+ rs.left = 0;
+ rs.right = mouseAnim->mousew;
+ rs.top = 0;
+ rs.bottom = mouseAnim->mouseh;
+
+ if (rd.left < 0)
+ {
+ rs.left = 0 - rd.left;
+ rd.left = 0;
+ }
+ if (rd.top < 0)
+ {
+ rs.top = 0 - rd.top;
+ rd.top = 0;
+ }
+ if (rd.right > RENDERWIDE)
+ {
+ rs.right -= (rd.right - RENDERWIDE);
+ rd.right = RENDERWIDE;
+ }
+ if (rd.bottom > ALIGNRENDERDEEP)
+ {
+ rs.bottom -= (rd.bottom - ALIGNRENDERDEEP);
+ rd.bottom = ALIGNRENDERDEEP;
+ }
+
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &rd, *(mouseSurfaces + mouseFrame), &rs, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
+ if (hr == DDERR_SURFACELOST)
+ {
+ IDirectDrawSurface2_Release(*(mouseSurfaces + mouseFrame));
+ *(mouseSurfaces + mouseFrame) = NULL;
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+
+_mouseEvent *MouseEvent(void)
+
+{
+ _mouseEvent *me;
+
+ if (mouseBacklog)
+ {
+ me = &mouseLog[mouseLogPos];
+ if (++mouseLogPos == MAX_MOUSE_EVENTS)
+ {
+ mouseLogPos = 0;
+ }
+ mouseBacklog -= 1;
+ return(me);
+ }
+
+ return(NULL);
+
+}
+
+
+uint8 CheckForMouseEvents(void) // (James23july97)
+{
+ return (mouseBacklog); // return the number of mouse events waiting
+}
+
+
+int32 AnimateMouse(void)
+
+{
+ if (mouseAnim)
+ {
+ if (++mouseFrame == mouseAnim->noAnimFrames)
+ {
+ mouseFrame = MOUSEFLASHFRAME;
+ }
+ mouseSprite = (uint8 *) mouseAnim + *(mouseOffsets+mouseFrame);
+ }
+ else
+ {
+ return(RDERR_UNKNOWN);
+ }
+
+ return(RD_OK);
+
+}
+
+
+
+int32 SetMouseAnim(uint8 *ma, int32 size, int32 mouseFlash)
+
+{
+ warning("stub SetMouseAnim( %d, %d )", size, mouseFlash);
+/*
+ int32 i;
+
+ if (mouseAnim)
+ {
+ for (i=0; i<mouseAnim->noAnimFrames; i++)
+ {
+ if (*(mouseSurfaces + i))
+ {
+ IDirectDrawSurface2_Release(*(mouseSurfaces + i));
+ *(mouseSurfaces + i) = NULL;
+ }
+ }
+
+ free(mouseAnim);
+ mouseAnim = NULL;
+ free(mouseSurfaces);
+ mouseSurfaces = NULL;
+ }
+
+ if (ma)
+ {
+ if (mouseFlash == RDMOUSE_FLASH)
+ mouseFrame = 0;
+ else
+ mouseFrame = MOUSEFLASHFRAME;
+ mouseAnim = malloc(size);
+ if (mouseAnim == NULL)
+ {
+ return(RDERR_OUTOFMEMORY);
+ }
+ else
+ {
+ memcpy((uint8 *) mouseAnim, ma, size);
+ mouseOffsets = (int32 *) ((uint8 *) mouseAnim + sizeof(_mouseAnim));
+ AnimateMouse();
+ mouseSurfaces = (LPDIRECTDRAWSURFACE *) malloc(mouseAnim->noAnimFrames * sizeof(LPDIRECTDRAWSURFACE));
+ if (mouseSurfaces == NULL)
+ return(RDERR_OUTOFMEMORY);
+ memset(mouseSurfaces, 0, sizeof(LPDIRECTDRAWSURFACE) * mouseAnim->noAnimFrames);
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 SetLuggageAnim(uint8 *ma, int32 size)
+
+{
+ warning("stub SetLugggeAnim");
+/*
+
+ if (luggageAnim)
+ {
+ free(luggageAnim);
+ luggageAnim = NULL;
+ }
+
+ if (ma)
+ {
+ luggageAnim = malloc(size);
+ if (luggageAnim == NULL)
+ {
+ return(RDERR_OUTOFMEMORY);
+ }
+ else
+ {
+ memcpy((uint8 *) luggageAnim, ma, size);
+ luggageOffset = (int32 *) ((uint8 *) luggageAnim + sizeof(_mouseAnim));
+ AnimateMouse();
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
diff --git a/sword2/driver/_mouse.h b/sword2/driver/_mouse.h
new file mode 100644
index 0000000000..290f5caf34
--- /dev/null
+++ b/sword2/driver/_mouse.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : mouse.h
+// Created : 18th September 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 18-Sep-96 PRP Internal driver interface to the mouse driver
+// functions and data.
+//
+// 1.1 03-Oct-96 PRP Changed the definition of mousex and y so that
+// negative values are allowed.
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the mouse.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef MOUSE_H
+#define MOUSE_H
+
+
+extern int16 mousex; // Mouse x coordinate
+extern int16 mousey; // Mouse y coordinate
+
+extern void LogMouseEvent(uint16 buttons); // Adds a mouse event to the log
+extern int32 DrawMouse(void); // Renders the mouse onto the back buffer.
+
+
+#endif
diff --git a/sword2/driver/d_draw.cpp b/sword2/driver/d_draw.cpp
new file mode 100644
index 0000000000..30baabeb2d
--- /dev/null
+++ b/sword2/driver/d_draw.cpp
@@ -0,0 +1,1274 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+//#include <mmsystem.h>
+#include <stdio.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+#include "rdwin.h"
+#include "_mouse.h"
+#include "d_draw.h"
+#include "palette.h"
+
+//#include "ddutil.h"
+//CDisplay *g_pDisplay = NULL;
+
+
+
+
+
+#define SCREENYOFFSET 40
+
+#define MILLISECSPERCYCLE 83
+
+
+
+/*
+LPDIRECTDRAW7 m_pDD;
+
+
+static LPDIRECTDRAW lpDraw; // DirectDraw object
+LPDIRECTDRAW2 lpDD2; // DirectDraw2 object
+LPDIRECTDRAWSURFACE lpPrimarySurface; // DirectDraw primary surface
+LPDIRECTDRAWSURFACE lpBackBuffer; // DirectDraw back surface
+LPDIRECTDRAWPALETTE lpPalette = NULL; // DirectDraw palette
+
+static PALETTEENTRY AppPalette[256]; // Application wide logical palette
+*/
+
+
+// Game screen metrics
+int16 screenDeep;
+int16 screenWide;
+
+
+// Set to 1 if vertical blank status cannot be checked.
+static BOOL noVbl = 0;
+BOOL bFullScreen = 0;
+
+
+
+// Scroll variables. scrollx and scrolly hold the current scroll position,
+// and scrollxTarget and scrollyTarget are the target position for the end
+// of the game cycle.
+
+int16 scrollx;
+int16 scrolly;
+static int16 scrollxTarget;
+static int16 scrollyTarget;
+static int16 scrollxOld;
+static int16 scrollyOld;
+static int16 failCount = 0;
+//static DDCAPS driverCaps;
+
+int32 renderCaps = 0;
+int32 dxHalCaps = 0;
+int32 dxHelCaps = 0;
+//DDCOLORKEY blackColorKey;
+
+
+static int32 platformIsNT = 0;
+
+
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+
+
+void FatalDirectDrawError(char *str, int32 code, char *filename, int32 line)
+{
+
+ char string[256];
+
+ RestoreDisplay();
+
+ sprintf(string, "FATAL: %s - code 0x%.8x - file %s - line %d", str, code, filename, line);
+ //MessageBox(hwnd, string, "DDraw error", MB_OK);
+ warning("%s", string);
+
+}
+
+
+
+
+//----------------------------------------------------------------------------------------------------------------
+
+
+
+int32 PlotDots(int16 x, int16 y, int16 count)
+
+{
+
+ int16 i;
+ uint8 *dst;
+
+ warning("stub PlotDots( %d, %d, %d )", x, y, count);
+/*
+ DDSURFACEDESC ddDescription;
+ HRESULT hr;
+
+ ddDescription.dwSize = sizeof(ddDescription);
+
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddDescription, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ RestoreSurfaces();
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddDescription, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ }
+
+ if (hr == DD_OK)
+ {
+
+ dst = (uint8 *) ddDescription.lpSurface + y * ddDescription.lPitch + x;
+
+ for (i=0; i<=count; i++)
+ {
+ *dst = 184;
+ dst += 2;
+ }
+ dst = (uint8 *) ddDescription.lpSurface + (y+1) * ddDescription.lPitch + x;
+ for (i=0; i<=count/10; i++)
+ {
+ *dst = 184;
+ dst += 20;
+ }
+ IDirectDrawSurface2_Unlock(lpBackBuffer, ddDescription.lpSurface);
+ }
+*/
+ return(RD_OK);
+
+}
+//----------------------------------------------------------------------------------------------------------------
+
+
+
+void RestoreSurfaces(void)
+
+{
+ warning("stub RestoreSurfaces");
+/*
+ IDirectDrawSurface2_Restore(lpPrimarySurface);
+ IDirectDrawSurface2_Restore(lpBackBuffer);
+*/
+}
+
+//----------------------------------------------------------------------------------------------------------------
+
+/*
+static PALETTEENTRY *CreateAppPalette(PALETTEENTRY *pe)
+{
+
+ HDC screen_dc;
+
+// Fill the palette with system colours
+ screen_dc = GetDC(NULL);
+ GetSystemPaletteEntries(screen_dc, 0, 256, pe);
+ ReleaseDC(NULL, screen_dc);
+
+ return pe;
+
+}
+*/
+
+
+//----------------------------------------------------------------------------------------------------------------
+
+int32 RestoreDisplay(void)
+
+{
+ warning("stub RestoreDisplay");
+/*
+ if( lpDraw != NULL )
+ {
+ if( lpPrimarySurface != NULL )
+ {
+ IDirectDrawSurface2_Release(lpPrimarySurface);
+ lpPrimarySurface = NULL;
+ }
+ if( lpPalette != NULL )
+ {
+ IDirectDrawPalette_Release(lpPalette);
+ lpPalette = NULL;
+ }
+ if (lpDD2 != NULL)
+ {
+ IDirectDraw2_Release(lpDD2);
+ lpDD2 = NULL;
+ }
+
+ IDirectDraw_Release(lpDraw);
+ lpDraw = NULL;
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+
+int32 InitialiseDisplay(int16 width, int16 height, int16 colourDepth, int32 windowType)
+{
+/*
+ DDSURFACEDESC ddsd;
+ DDSCAPS ddscaps;
+ HRESULT hr;
+ DDCAPS helCaps;
+ LARGE_INTEGER timerFrequency;
+ int32 capsError = 0;
+
+
+ OSVERSIONINFO VersionInfo;
+ VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ if (GetVersionEx(&VersionInfo))
+ {
+
+ switch (VersionInfo.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32s :
+ case VER_PLATFORM_WIN32_WINDOWS :
+ break;
+ case VER_PLATFORM_WIN32_NT :
+ platformIsNT = 1;
+ break;
+ }
+ }
+
+
+ if (windowType == RD_FULLSCREEN)
+ bFullScreen = TRUE;
+ else
+ bFullScreen = FALSE;
+
+ // Colour depths of 8 bits only are currently supported
+ if (colourDepth != 8)
+ {
+ return(RDERR_COLOURDEPTH);
+ }
+
+ screenWide = width;
+ screenDeep = height;
+
+ // Create the directDraw object
+ hr = DirectDrawCreate(NULL, &lpDraw, NULL);
+// hr=DirectDrawCreateEx( NULL, (VOID**)&m_pDD, IID_IDirectDraw7, NULL );
+
+
+ if ( hr != DD_OK )
+ {
+// Zdebug(" DirectDrawCreate failed!");
+
+ DirectDrawError("DirectDraw unavailable", hr);
+ return(hr);
+ }
+
+
+ // Get exclusive mode
+ if (bFullScreen)
+ {
+
+// hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ hr = IDirectDraw2_SetCooperativeLevel(lpDraw, hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Exclusive mode unavailable", hr);
+ return(hr);
+ }
+
+ // TONY TEMP
+
+
+ hr = IDirectDraw2_QueryInterface(lpDraw, &IID_IDirectDraw2, (LPVOID *) &lpDD2);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("DirectDraw2 unavailable", hr);
+ return(hr);
+ }
+
+ // Set up the display mode which has been requested
+// hr = lpDD2->lpVtbl->SetDisplayMode(lpDD2, width, height, colourDepth, 0, 0);
+ hr = IDirectDraw2_SetDisplayMode(lpDD2, width, height, colourDepth, 0, 0);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to set display mode", hr);
+ return(hr);
+ }
+
+ // Set up the primary surface descriptor
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+ ddsd.dwBackBufferCount = 1;
+
+ // Create the primary surface
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &lpPrimarySurface, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create primary surface", hr);
+ return(hr);
+ }
+
+ // Create the back buffer as a page flipping surface
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+ hr = IDirectDrawSurface2_GetAttachedSurface(lpPrimarySurface, &ddscaps, &lpBackBuffer);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to attach back buffer", hr);
+ return(hr);
+ }
+
+ EraseBackBuffer();
+ FlipScreens();
+ EraseBackBuffer();
+ FlipScreens();
+
+ // Create a palette object
+ hr = IDirectDraw2_CreatePalette(lpDD2, DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE,
+ CreateAppPalette(AppPalette), &lpPalette, NULL);
+ if (hr != DD_OK )
+ {
+ DirectDrawError("Cannot create 8-bit palette", hr);
+ return(hr);
+ }
+
+ // Set our palette object active
+ hr = IDirectDrawSurface2_SetPalette(lpPrimarySurface, lpPalette);
+ if (hr != DD_OK )
+ {
+ DirectDrawError("Unable to set palette", hr);
+ return(hr);
+ }
+
+ }
+ else
+ {
+ RECT rcWork;
+ RECT rc;
+ HDC hdc;
+ DWORD dwStyle;
+ uint32 GameBPP;
+
+
+
+ hr = IDirectDraw_SetCooperativeLevel(lpDraw, hwnd, DDSCL_NORMAL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot set normal cooperative level", hr);
+ return(hr);
+ }
+
+
+
+ hr = IDirectDraw_QueryInterface(lpDraw, &IID_IDirectDraw2, (LPVOID *) &lpDD2);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("DirectDraw2 unavailable", hr);
+ return(hr);
+ }
+
+ //
+ // when in windows we should use the current mode
+ //
+ hdc = GetDC(NULL);
+ GameBPP = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
+ ReleaseDC(NULL, hdc);
+
+ if ((GameBPP != 8) && (GameBPP != 16))
+ {
+ MessageBox(hwnd, "Cannot execute in high colour mode - going to full screen", "Broken Sword II", MB_OK);
+ return(RDERR_GOFULLSCREEN);
+ }
+ else if (GameBPP != 8)
+ {
+ if (MessageBox(hwnd, "Your display is not in 256 colour mode. Would you like to go to full screen mode (better performance)", "Broken Sword II", MB_YESNO) == IDYES)
+ {
+ return(RDERR_GOFULLSCREEN);
+ }
+ }
+
+ //
+ // if we are still a WS_POPUP window we should convert to a
+ // normal app window so we look like a windows app.
+ //
+ dwStyle = GetWindowStyle(hwnd);
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong(hwnd, GWL_STYLE, dwStyle);
+
+// if (bStretch)
+// SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);
+// else
+// SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);
+ SetRect(&rc, 0, 0, 640, 480);
+
+ AdjustWindowRectEx(&rc,
+ GetWindowStyle(hwnd),
+ GetMenu(hwnd) != NULL,
+ GetWindowExStyle(hwnd));
+
+ SetWindowPos(hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+ SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+
+ //
+ // make sure our window does not hang outside of the work area
+ // this will make people who have the tray on the top or left
+ // happy.
+ //
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
+ GetWindowRect(hwnd, &rc);
+ if (rc.left < rcWork.left) rc.left = rcWork.left;
+ if (rc.top < rcWork.top) rc.top = rcWork.top;
+ SetWindowPos(hwnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+
+
+
+ // Set up the primary surface descriptor
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ // Create the primary surface
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &lpPrimarySurface, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create primary surface", hr);
+ return(hr);
+ }
+
+ // Create the back buffer as a page flipping surface
+ memset( &ddsd, 0, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
+
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwHeight = 480;
+ ddsd.dwWidth = 640;
+
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &lpBackBuffer, NULL );
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot attach back buffer", hr);
+ return(hr);
+ }
+
+ // DDClear();
+
+ if (IDirectDrawSurface2_GetDC(lpPrimarySurface, &hdc) == DD_OK)
+ {
+ char *szMsg = "Broken Sword II is loading.......please wait.";
+ SetTextColor(hdc, RGB(255,255,255));
+ SetBkMode(hdc, TRANSPARENT);
+ TextOut(hdc, rcWindow.left, rcWindow.top, szMsg, lstrlen(szMsg));
+ IDirectDrawSurface2_ReleaseDC(lpPrimarySurface, hdc);
+ }
+
+ // Create a palette object - only if we have a palette!
+ if (GameBPP == 8)
+ {
+ hr = IDirectDraw2_CreatePalette(lpDD2, DDPCAPS_8BIT, CreateAppPalette(AppPalette), &lpPalette, NULL);
+ if (hr != DD_OK )
+ {
+ DirectDrawError("Cannot create 8-bit palette", hr);
+ return(hr);
+ }
+
+ hr = IDirectDrawSurface2_SetPalette(lpPrimarySurface, lpPalette);
+ if (hr != DD_OK )
+ {
+ DirectDrawError("Cannot set palette", hr);
+ return(hr);
+ }
+ }
+ }
+
+ // Set my capability bits.
+ memset(&driverCaps, 0, sizeof(DDCAPS));
+ memset(&helCaps, 0, sizeof(DDCAPS));
+ driverCaps.dwSize = sizeof(DDCAPS);
+ helCaps.dwSize = sizeof(DDCAPS);
+ hr = IDirectDraw2_GetCaps(lpDD2, &driverCaps, &helCaps);
+ if (hr != DD_OK)
+ {
+ driverCaps.dwSize = sizeof(DDCAPS_DX3);
+ helCaps.dwSize = sizeof(DDCAPS_DX3);
+ hr = IDirectDraw2_GetCaps(lpDD2, &driverCaps, &helCaps);
+ if (hr != DD_OK)
+ {
+ MessageBox(hwnd, "Cannot get hardware capabilities. Software emulation only. Re-install DirectX!", "DDraw error", MB_OK);
+ capsError = 1;
+ }
+ }
+
+ blackColorKey.dwColorSpaceLowValue = 0;
+ blackColorKey.dwColorSpaceHighValue = 0;
+
+ if (capsError)
+ {
+ helCaps.dwCaps = DDCAPS_BLT + DDCAPS_BLTSTRETCH + DDCAPS_COLORKEY;
+ helCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT;
+ dxHelCaps += RDCAPS_BLTSTRETCH;
+ dxHelCaps += RDCAPS_SRCBLTCKEY;
+ renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_ARITHMETICSTRETCH | RDBLTFX_EDGEBLEND |
+ RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_GRADEDALPHA;
+ }
+ else
+ {
+ if ((helCaps.dwCaps & DDCAPS_BLT == 0) ||
+ (helCaps.dwCaps & DDCAPS_BLTSTRETCH == 0) ||
+ (helCaps.dwCaps & DDCAPS_COLORKEY == 0) ||
+ (helCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT == 0))
+ {
+ RestoreDisplay();
+ return(RDERR_NOEMULATION);
+ }
+
+// if (driverCaps.dwCaps & DDCAPS_BLTSTRETCH)
+// {
+// if (driverCaps.dwFXCaps & (DDFXCAPS_BLTSHRINKX + DDFXCAPS_BLTSHRINKY + DDFXCAPS_BLTSTRETCHX + DDFXCAPS_BLTSTRETCHY) ==
+// DDFXCAPS_BLTSHRINKX + DDFXCAPS_BLTSHRINKY + DDFXCAPS_BLTSTRETCHX + DDFXCAPS_BLTSTRETCHY)
+// dxHalCaps += RDCAPS_BLTSTRETCH;
+// else if (helCaps.dwCaps & DDCAPS_BLTSTRETCH)
+// dxHelCaps += RDCAPS_BLTSTRETCH;
+// else
+// return RDERR_DDRAWNOEMULATION;
+// }
+// else if (helCaps.dwCaps & DDCAPS_BLTSTRETCH)
+// dxHelCaps += RDCAPS_BLTSTRETCH;
+// else
+// return(RDERR_DDRAWNOEMULATION);
+
+ if (helCaps.dwCaps & DDCAPS_BLTSTRETCH)
+ dxHelCaps += RDCAPS_BLTSTRETCH;
+ else
+ return(RDERR_DDRAWNOEMULATION);
+
+ if ((driverCaps.dwCaps & DDCAPS_BLT) && (driverCaps.dwCaps & DDCAPS_COLORKEY) && (driverCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
+ dxHalCaps += RDCAPS_SRCBLTCKEY;
+ else if ((helCaps.dwCaps & DDCAPS_BLT) && (helCaps.dwCaps & DDCAPS_COLORKEY) && (helCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
+ dxHelCaps += RDCAPS_SRCBLTCKEY;
+ else
+ return(RDERR_DDRAWNOEMULATION);
+
+
+
+ // Do computer speed testing here to set bits. - this is the path we go through:
+ //
+ // if (Can everything be done in hardware?)
+ // renderCaps = RDBLTFX_ALLHARDWARE;
+ // else
+ // if (Everything fast enough in software)
+ // turn everything on in software
+ // else
+ // Turn blending off
+ // if (can everything but blending be done in hardware?)
+ // renderCaps = RDBLTFX_ALLHARDWARE
+ // else
+ // if (everything but blending fast enough in software)
+ // Do everything but blending in software
+ // else
+ // Turn off sprite effects
+ // endif
+ // endif
+ // endif
+ // endif
+
+
+
+
+ if ((driverCaps.dwCaps & DDCAPS_BLT) && (driverCaps.dwCaps & DDCAPS_COLORKEY) && (driverCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT)
+ && (driverCaps.dwCaps & DDSCAPS_ALPHA) && (driverCaps.dwAlphaBltConstBitDepths))
+ renderCaps = RDBLTFX_ALLHARDWARE | RDBLTFX_GRADEDALPHA | RDBLTFX_FLATALPHA;
+ else if ((driverCaps.dwCaps & DDCAPS_BLT) && (driverCaps.dwCaps & DDCAPS_COLORKEY) && (driverCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
+ renderCaps = RDBLTFX_ALLHARDWARE;
+ else
+ renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_ARITHMETICSTRETCH | RDBLTFX_EDGEBLEND |
+ RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_GRADEDALPHA;
+
+ if (QueryPerformanceFrequency(&timerFrequency) == TRUE)
+ if (timerFrequency.QuadPart > 700000)
+ renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_ARITHMETICSTRETCH | RDBLTFX_EDGEBLEND |
+ RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_GRADEDALPHA;
+
+ // if ((driverCaps.dwCaps & DDCAPS_BLT) && (driverCaps.dwCaps & DDCAPS_COLORKEY) && (driverCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
+ // renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_ARITHMETICSTRETCH | RDBLTFX_EDGEBLEND |
+ // RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_GRADEDALPHA | RDBLTFX_FGPARALLAX;
+ // else
+ // renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_ARITHMETICSTRETCH | RDBLTFX_EDGEBLEND |
+ // RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_GRADEDALPHA;
+
+ // renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_ALLHARDWARE;
+ }
+*/
+ return(RD_OK);
+
+}
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------------------------------
+
+
+
+int32 RenderHard(void)
+{
+ warning("stub RenderHard");
+/*
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ return(RDERR_ALREADYON);
+ if ((driverCaps.dwCaps & DDCAPS_BLT) && (driverCaps.dwCaps & DDCAPS_COLORKEY) && (driverCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
+ renderCaps = RDBLTFX_ALLHARDWARE;
+ else
+ return(RDERR_NOHARDWARE);
+
+*/
+ return(RD_OK);
+}
+
+int32 RenderSoft(void)
+{
+ warning("stub RenderSoft");
+/*
+ if (!(renderCaps & RDBLTFX_ALLHARDWARE))
+ return(RDERR_ALREADYON);
+ renderCaps = RDBLTFX_MOUSEBLT | RDBLTFX_ARITHMETICSTRETCH | RDBLTFX_EDGEBLEND |
+ RDBLTFX_SHADOWBLEND | RDBLTFX_FLATALPHA | RDBLTFX_GRADEDALPHA;
+*/
+ return(RD_OK);
+}
+
+int32 SetBltFx(void)
+{
+ renderCaps |= RDBLTFX_EDGEBLEND + RDBLTFX_ARITHMETICSTRETCH;
+ return(RD_OK);
+}
+
+int32 ClearBltFx(void)
+{
+ renderCaps &= (0xffffffff - RDBLTFX_EDGEBLEND - RDBLTFX_ARITHMETICSTRETCH);
+ return(RD_OK);
+}
+
+int32 ClearShadowFx(void)
+{
+ renderCaps &= (0xffffffff - RDBLTFX_SHADOWBLEND);
+ return(RD_OK);
+}
+
+int32 SetShadowFx(void)
+{
+ renderCaps |= RDBLTFX_SHADOWBLEND;
+ return RD_OK;
+}
+
+int32 GetRenderType(void)
+{
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ {
+ return (0);
+ }
+ else
+ {
+ if (renderCaps & (RDBLTFX_EDGEBLEND + RDBLTFX_ARITHMETICSTRETCH))
+ return (3);
+ else
+ {
+ if (renderCaps & RDBLTFX_SHADOWBLEND)
+ return(2);
+ else
+ return (1);
+ }
+ }
+}
+
+int32 FlipScreens(void)
+
+{
+ warning("stub FlipScreens");
+/*
+ HRESULT hr;
+ BOOL vbl;
+ int32 startTime;
+
+ DrawMouse();
+
+ if (bFullScreen)
+ {
+ startTime = timeGetTime();
+
+ while(TRUE)
+ {
+ if (!noVbl)
+ {
+ hr = IDirectDraw2_GetVerticalBlankStatus(lpDD2, &vbl);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Vertical blank status unavailable", hr);
+ }
+ }
+
+ if (vbl || noVbl)
+ {
+ hr = IDirectDrawSurface2_Flip(lpPrimarySurface, NULL, 0);
+ if (hr == DD_OK)
+ {
+ break;
+ }
+
+ if (hr == DDERR_SURFACELOST)
+ {
+ if (gotTheFocus)
+ {
+ hr = IDirectDrawSurface2_Restore(lpPrimarySurface);
+
+ if(hr != DD_OK)
+ {
+ if (++failCount == 32)
+ return(RDERR_CANNOTFLIP);
+ }
+ }
+
+ }
+ else
+ failCount = 0;
+
+ if(hr != DDERR_WASSTILLDRAWING)
+ {
+ break;
+ }
+ }
+ if (timeGetTime() - startTime > 20)
+ {
+ noVbl = 1;
+ }
+ }
+ }
+ else
+ {
+
+ hr = IDirectDrawSurface2_Blt(lpPrimarySurface, &rcWindow, lpBackBuffer, NULL, DDBLT_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ return(RDERR_UNKNOWN);
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+
+int32 WaitForVbl(void)
+{
+ warning("stub WaitForVbl");
+/*
+ BOOL vbl;
+ HRESULT hr;
+ uint32 counter = 0;
+
+
+ while(1)
+ {
+ hr = IDirectDraw2_GetVerticalBlankStatus(lpDD2, &vbl);
+
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot get vertical blank status", hr);
+ return(hr);
+ }
+
+ if (vbl || noVbl)
+ break;
+
+ if (++counter == 250000)
+ noVbl = 1;
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+
+
+int32 EraseBackBuffer( void )
+{
+ warning("stub EraseBackBuffer");
+/*
+ DDBLTFX ddbltfx;
+ HRESULT hr;
+ RECT r = {0, 0, screenWide, screenDeep};
+
+
+ // Erase the background
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = 0;
+
+ while( 1 )
+ {
+
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &r, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+
+ if (hr == DDERR_SURFACELOST)
+ {
+
+ RestoreSurfaces();
+
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &r, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+
+ if (hr != DD_OK)
+ {
+ if (++failCount == 32)
+ {
+ DirectDrawError("Cannot render back buffer", hr);
+ return(hr);
+ }
+ else
+ {
+ failCount = 0;
+ return(RD_OK);
+ }
+ }
+
+ }
+
+ if (hr == DD_OK)
+ {
+ break;
+ }
+
+ if (hr != DDERR_WASSTILLDRAWING)
+ {
+ DirectDrawError("Cannot render back buffer", hr);
+ return(hr);
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+
+
+int32 SaveScreenShot(uint8 *buffer, uint8 *palette)
+{
+
+ static uint16 pcxCount = 0;
+ int virtualWidth;
+ int pix;
+ int keyPix;
+ int line;
+ int i;
+ int runLength;
+ char filename[80];
+ unsigned char ch;
+ unsigned char *pcxData;
+ unsigned char pal[256*3];
+ FILE *fp;
+ _pcxHeader pcxHead;
+
+ sprintf(filename, "snap%.4d.pcx", pcxCount);
+
+ fp = fopen(filename, "wb");
+ if (fp == NULL)
+ {
+ sprintf(filename, "c:\\snap%.4d.pcx", pcxCount);
+ fp = fopen(filename, "wb");
+ if (fp == NULL)
+ {
+ return(0);
+ }
+ }
+ pcxCount += 1;
+
+ // Set up and write the header
+ pcxHead.manufacturer = 0x0a;
+ pcxHead.version = 5;
+ pcxHead.encoding = 1;
+ pcxHead.bitsPerPixel = 8;
+ pcxHead.xmin = 0;
+ pcxHead.ymin = 0;
+ pcxHead.xmax = 639;
+ pcxHead.ymax = 479;
+ pcxHead.hres = 72;
+ pcxHead.vres = 72;
+ pcxHead.reserved = 0;
+ pcxHead.colourPlanes = 1;
+ pcxHead.bytesPerLine = 640;
+ pcxHead.paletteType = 1;
+ fwrite(&pcxHead , sizeof(pcxHead), 1, fp);
+
+ // The simplest job is to write out the entire file as a series of single units
+
+ virtualWidth = 640;
+// char *pcxDataBase = buffer; //GetBitMap() + (GetHeight()-1)* virtualWidth ;
+ for (line = 0 ; line < 480; line++)
+ {
+ pcxData = (unsigned char *)buffer; //pcxDataBase;
+
+ // Look to compress this line of 'width' pixels
+ pix = 0;
+ while (pix < 640)
+ { // Look for some run length coding
+ keyPix = pcxData[pix++];
+ runLength = 1;
+ while ( (pix < 640) && (keyPix == pcxData[pix]) )
+ { runLength++;
+ pix++;
+ }
+ while (runLength > 1)
+ { // We have a run length bit. Runs are a maximum of 0x3f
+ int lRun = runLength > 0x3f ? 0x3f : runLength;
+ runLength -= lRun;
+ lRun |= 0xc0;
+ ch = (unsigned char) lRun;
+ fwrite(&ch, 1, 1, fp);
+ ch = (unsigned char) keyPix;
+ fwrite(&ch, 1, 1, fp);
+// fFile.WriteChar(lRun);
+// fFile.WriteChar(keyPix);
+ }
+ if (runLength)
+ { // Single pixel. If its <= 0x3f it goes straight in, otherwise it is a single run length
+ if (keyPix < 0xc0)
+ {
+ ch = (unsigned char) keyPix;
+ fwrite(&ch, 1, 1, fp);
+// fFile.WriteChar(keyPix);
+ }
+ else
+ {
+ ch = 0xc1;
+ fwrite(&ch, 1, 1, fp);
+ ch = (unsigned char) keyPix;
+ fwrite(&ch, 1, 1, fp);
+// fFile.WriteChar(0xc1);
+// fFile.WriteChar(keyPix);
+ }
+ }
+ }
+// pcxDataBase -= virtualWidth;
+ buffer += virtualWidth;
+ }
+
+ // Convert and write out the palette
+// StringClass sPal(768);
+// unsigned char *pal = palette;
+// for (int count = 0 ; count < 256 ; count++)
+// { *(pal++) = bmi.bmiColors[count].rgbRed;
+// *(pal++) = bmi.bmiColors[count].rgbGreen;
+// *(pal++) = bmi.bmiColors[count].rgbBlue;
+// }
+ ch = 0x0c;
+ fwrite(&ch, 1, 1, fp);
+
+ for (i=0; i<256*3; i++)
+ {
+ pal[i] = *((unsigned char *) palette + i);
+ }
+
+// fFile.WriteChar(0x0c);
+ fwrite(pal, 256*3, 1, fp);
+// if (fFile.Write(sPal , 768)!=768)
+// return(-1);
+ fclose(fp);
+
+ return(1);
+
+}
+
+
+
+
+
+
+int32 GrabScreenShot(void)
+
+{
+ warning("stub GrabScreenShot");
+/*
+ uint8 *screenGrabBuffer;
+ uint8 *palette;
+ DDSURFACEDESC ddsd;
+ HRESULT hr;
+ int32 i;
+
+
+ screenGrabBuffer = (uint8 *) malloc(screenWide * screenDeep);
+ if (screenGrabBuffer == NULL)
+ return(RDERR_OUTOFMEMORY);
+
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ hr = IDirectDrawSurface2_Lock(lpPrimarySurface, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ free(screenGrabBuffer);
+ return(RDERR_LOCKFAILED);
+ }
+
+ for (i=0; i<screenDeep; i++)
+ {
+ memcpy(screenGrabBuffer + i * screenWide, (uint8 *) ddsd.lpSurface + ddsd.lPitch * i, screenWide);
+ }
+ IDirectDrawSurface2_Unlock(lpPrimarySurface, ddsd.lpSurface);
+
+
+ palette = (uint8 *) malloc(256 * 3);
+ if (palette == NULL)
+ {
+ free(screenGrabBuffer);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ for (i=0; i<256; i++)
+ {
+ palette[i*3] = palCopy[i][0];
+ palette[i*3+1] = palCopy[i][1];
+ palette[i*3+2] = palCopy[i][2];
+ }
+
+ hr = SaveScreenShot(screenGrabBuffer,palette);
+
+
+ free(palette);
+ free(screenGrabBuffer);
+*/
+ return(RD_OK);
+}
+
+
+
+int32 NextSmackerFrame(void)
+{
+ warning("stub NextSmackerFrame");
+ return(RD_OK);
+}
+
+
+uint32 textSurface = 0;
+
+void OpenTextObject(_movieTextObject *obj)
+{
+ CreateSurface(obj->textSprite, &textSurface);
+}
+
+void CloseTextObject(_movieTextObject *obj)
+{
+ DeleteSurface(textSurface);
+ textSurface = 0;
+}
+
+void DrawTextObject(_movieTextObject *obj)
+{
+ warning("stub DrawTextObject");
+/*
+ HRESULT hr;
+ RECT rd, rs;
+ LPDIRECTDRAWSURFACE dds;
+ _spriteInfo *s = obj->textSprite;
+ char myString[256];
+
+
+ dds = (LPDIRECTDRAWSURFACE) textSurface;
+
+ // Set startx and starty for the screen buffer ADDED THIS!
+ if (s->type & RDSPR_DISPLAYALIGN)
+ rd.top = s->y;
+ else
+ rd.top = s->y - scrolly;
+
+ if (s->type & RDSPR_DISPLAYALIGN)
+ rd.left = s->x;
+ else
+ rd.left = s->x - scrollx;
+
+ rs.left = 0;
+ rs.right = s->w;
+ rs.top = 0;
+ rs.bottom = s->h;
+ if (s->scale & 0xff)
+ {
+ rd.right = rd.left + s->scaledWidth;
+ rd.bottom = rd.top + s->scaledHeight;
+ // Do clipping
+ if (rd.top < 40)
+ {
+ rs.top = (40 - rd.top) * 256 / s->scale;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440)
+ {
+ rs.bottom -= ((rd.bottom - 440) * 256 / s->scale);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0)
+ {
+ rs.left = (0 - rd.left) * 256 / s->scale;
+ rd.left = 0;
+ }
+ if (rd.right > 640)
+ {
+ rs.right -= ((rd.right - 640) * 256 / s->scale);
+ rd.right = 640;
+ }
+ }
+ else
+ {
+ rd.right = rd.left + s->w;
+ rd.bottom = rd.top + s->h;
+
+ // Do clipping
+ if (rd.top < 40)
+ {
+ rs.top = 40 - rd.top;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440)
+ {
+ rs.bottom -= (rd.bottom - 440);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0)
+ {
+ rs.left = 0 - rd.left;
+ rd.left = 0;
+ }
+ if (rd.right > 640)
+ {
+ rs.right -= (rd.right - 640);
+ rd.right = 640;
+ }
+ }
+
+ if (s->type & RDSPR_TRANS)
+ {
+ hr = IDirectDrawSurface2_Blt(lpPrimarySurface, &rd, dds, &rs, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
+ if (hr)
+ {
+ if (hr == DDERR_SURFACELOST)
+ hr = RDERR_SURFACELOST;
+ else if (dxHalCaps & RDCAPS_BLTSTRETCH)
+ dxHalCaps -= RDCAPS_BLTSTRETCH;
+ else
+ {
+ sprintf(myString, "Cannot print smacker text x%d y%d w%d h%d s%d t%d\n", s->x, s->y, s->w, s->h, s->scale, s->type);
+ DirectDrawError(myString, hr);
+ }
+ }
+ }
+ else
+ {
+ hr = IDirectDrawSurface2_Blt(lpPrimarySurface, &rd, dds, &rs, DDBLT_WAIT, NULL);
+ if (hr)
+ {
+ if (hr == DDERR_SURFACELOST)
+ hr = RDERR_SURFACELOST;
+ else
+ {
+ sprintf(myString, "Cannot print smacker text x%d y%d w%d h%d s%d t%d\n", s->x, s->y, s->w, s->h, s->scale, s->type);
+ DirectDrawError(myString, hr);
+ }
+ }
+ }
+*/
+}
+
+
+extern uint8 musicMuted;
+
+int32 PlaySmacker(char *filename, _movieTextObject *text[], uint8 *musicOut)
+{
+ warning("stub PlaySmacker %s", filename);
+ return(RD_OK);
+
+}
+
+
+
+void GetDrawStatus(_drvDrawStatus *s)
+{
+// s->hwnd = hwnd;
+// s->lpDraw = lpDraw;
+// s->lpDD2 = lpDD2;
+// s->lpPrimarySurface = lpPrimarySurface;
+// s->lpBackBuffer = lpBackBuffer;
+// s->lpPalette = lpPalette;
+ s->screenDeep = screenDeep;
+ s->screenWide = screenWide;
+ s->scrollx = scrollx;
+ s->scrolly = scrolly;
+ s->scrollxTarget = scrollxTarget;
+ s->scrollyTarget = scrollyTarget;
+ s->scrollxOld = scrollxOld;
+ s->scrollyOld = scrollyOld;
+ s->failCount = failCount;
+ s->renderCaps = renderCaps;
+ s->dxHalCaps = dxHalCaps;
+ s->dxHelCaps = dxHelCaps;
+ s->noVbl = noVbl;
+ s->bFullScreen = bFullScreen;
+
+// memcpy(&s->driverCaps, &driverCaps, sizeof(DDCAPS));
+// memset(&blackColorKey, 0, sizeof(DDCOLORKEY));
+}
+
+
+
+void SetDrawStatus(_drvDrawStatus *s)
+{
+// hwnd = s->hwnd;
+// lpDraw = s->lpDraw;
+// lpDD2 = s->lpDD2;
+// lpPrimarySurface= s->lpPrimarySurface;
+// lpBackBuffer = s->lpBackBuffer;
+// lpPalette = s->lpPalette;
+ screenDeep = s->screenDeep;
+ screenWide = s->screenWide;
+ scrollx = s->scrollx;
+ scrolly = s->scrolly;
+ scrollxTarget = s->scrollxTarget;
+ scrollyTarget = s->scrollyTarget;
+ scrollxOld = s->scrollxOld;
+ scrollyOld = s->scrollyOld;
+ failCount = s->failCount;
+// renderCaps = s->renderCaps;
+ dxHalCaps = s->dxHalCaps;
+ dxHelCaps = s->dxHelCaps;
+ noVbl = s->noVbl;
+ bFullScreen = s->bFullScreen;
+
+// memcpy(&driverCaps, &s->driverCaps, sizeof(DDCAPS));
+// memset(&blackColorKey, 0, sizeof(DDCOLORKEY));
+}
diff --git a/sword2/driver/d_draw.h b/sword2/driver/d_draw.h
new file mode 100644
index 0000000000..0c4302bfaa
--- /dev/null
+++ b/sword2/driver/d_draw.h
@@ -0,0 +1,96 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : d_draw.h
+// Created : 22nd August 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 16-Sep-96 PRP Interface to the DirectDraw driver functions
+// and data.
+//
+// 1.1 19-Sep-96 PRP Increased scope of directDraw data, such as
+// the back buffer object, so that mouse.c can
+// have access to the screen.
+//
+// 1.2 25-Sep-96 PRP Made scrollx and scrolly available to all
+// driver code.
+//
+// 1.3 26-Sep-96 PRP Moved scroll stuff to render.h for clarity.
+//
+// 1.4 07-Nov-96 PRP Made bFullScreen available to all driver code.
+//
+// 1.5 18-Nov-96 PRP Added reference to lpDD2 object.
+//
+// 1.6 24-Jan-97 PRP Added hardware capability bits and defines.
+//
+// 1.7 06-Mar-97 PRP Changed capability bits, and changed the
+// direct draw error reporting call. Added
+// function to grab screen shot.
+//
+// 1.8 16-Jun-97 PSJ Made globall externable to c++.
+//
+// 1.9 27-Jun-97 PRP Moving the definition of GrabScreenShot to
+// driver96.h for external access.
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the d_draw.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef D_DRAW_H
+#define D_DRAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#include "ddraw.h"
+
+// Bits defining hardware and emulation capabilities.
+#define RDCAPS_BLTSTRETCH 1
+#define RDCAPS_SRCBLTCKEY 2
+#define DirectDrawError(f, g) FatalDirectDrawError(f, g, __FILE__, __LINE__)
+
+
+extern uint8 *lpPalette; // palette
+extern uint8 *lpBackBuffer; // back surface
+extern uint8 *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.
+extern uint8 blackColorKey; // transparent pixel for color key blitting.
+extern int32 dxHalCaps; // Hardware capabilities.
+extern int32 dxHelCaps; // Emulation capabilities.
+
+extern void FatalDirectDrawError(char *str, int32 dderr, char *file, int32 line);
+extern void RestoreSurfaces(void); // Restores direct draw surfaces.
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/sword2/driver/d_sound.cpp b/sword2/driver/d_sound.cpp
new file mode 100644
index 0000000000..d3ec3200ae
--- /dev/null
+++ b/sword2/driver/d_sound.cpp
@@ -0,0 +1,3095 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : d_sound.c
+// Created : 3rd December 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the driver interface to direct sound.
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 03-Dec-96 PRP The sound buffer can be created, with the
+// format defined by the game engine, and speech
+// can be played.
+//
+// 1.1 05-Dec-96 PRP Sound effects now done.
+//
+// 1.2 19-Dec-96 PRP Added volume and pan to speech and sound
+// effects. Also, added type to sound effects
+// so that they can be looped. Implemented
+// a CloseAllFx function which will clear out
+// all sound effects.
+//
+// 1.3 20-Dec-96 PRP Fixed a bug in the function which clears
+// spot effects when they have finished playing.
+//
+// 1.4 02-Jan-97 PRP Fixed a bug in ClearAllFx which was trying
+// to close the speech.
+//
+// 1.5 08-Apr-97 PRP Added ... to the
+// InitialiseSound function.
+//
+// 1.6 09-Apr-97 PRP Added functions to steam music from CD.
+//
+// 1.7 29-May-97 PSJ Added functions to save and restore the state
+// of the sound drivers.
+//
+// 1.8 04-Jun-97 PRP Added bodge to PlayFx routine which registers
+// a sound effect to remove itself from the list
+// if it is the tune to leave a sequence.
+//
+// 1.9 06-Jun-97 PSJ Expanded volTable from 17 to 241 entries.
+// Added an fx and a speech master volume level.
+// Added SetFxVolume and GetFxVolume for fx master
+// volume. Added SetSpeechVolume and GetSpeechVolume
+// for speech master volume.
+//
+// 1.10 09-Jun-97 PSJ Added SetMusicVolume and GetMusicVolume.
+//
+// 1.11 09-Jun-97 PSJ Fixed bug in SetSpeechVolume.
+//
+// 1.12 10-Jun-97 PSJ Added MuteMusic, MuteSpeech, MuteFx, IsMusicMute,
+// IsFxMute and IsSpeechMute.
+//
+// 1.13 12-Jun-97 PSJ Added PlayCompSpeech to play compressed speech
+// from a speech cluster.
+//
+// 1.14 19-Jun-97 PSJ Added StreamCompMusic and UpdateCompSampleStreaming
+// to play compressed music from a music cluster.
+// Added StopMusic to fade out any music playing.
+//
+// 1.15 24-Jun-97 PSJ Changed PlayCompSpeech to physically check for
+// playing samples rather than using the assuming the
+// speechStatus flag is correct.
+//
+// 1.16 24-Jun-97 PSJ Fixed bug it SetSpeechVolume.
+//
+// 1.17 26-Jun-97 PSJ Added AmISpeaking() for lip syncing.
+//
+// 1.18 26-Jun-97 PSJ Tweaked the nose of the dread, killer AmISpeaking
+// function.
+//
+// 1.19 26-Jun-97 PSJ Added PauseSpeech and UnpauseSpeech.
+//
+// 1.20 26-Jun-97 PSJ Fixed a bug in the muteSpeech routine.
+//
+// 1.21 26-Jun-97 PSJ Fixed a bug in the AmISpeaking routine.
+//
+// 1.22 26-Jun-97 PSJ PlayCompSpeech loads and pauses the speech
+// ready to be played by UnpauseSpeech.
+//
+// 1.23 01-Jul-97 PSJ Fixed GetSpeechStatus to work when speech is paused
+//
+// 1.24 03-Jul-97 PSJ Stopped PlayCompSpeech clicking at the end of samples.
+//
+// 1.25 10-Jul-97 PSJ Reduced music volume by 1/4 when playing speech
+//
+// 1.26 10-Jul-97 PSJ GetMusicVolume return safeMusicVol if it is set.
+//
+// 1.27 15-Jul-97 PRP Added functions to pause and unpause the sound effects.
+//
+// 1.28 15-Jul-97 PRP Fixed PauseFx
+//
+// 1.29 16-Jul-97 PSJ Added GetCompSpeechSize and PreFetchCompSpeech
+//
+// 1.30 16-Jul-97 PRP Fixed setting of sound fx volume.
+//
+// 1.31 18-Jul-97 PRP Added speech expansion to get samples to sound the same.
+//
+// 1.32 18-Jul-97 PRP Hopefully fixed expansion algorithm.
+//
+// 1.33 18-Jul-97 JEL Fixed UnpauseFx()
+//
+// 1.34 18-Jul-97 JEL Fixed PlayCompSpeech()
+//
+// 1.35 18-Jul-97 JEL Removed speech volume enhancing (now to be done in speech compressor)
+//
+// 1.36 21-Jul-97 PRP Added new type of sound effect which is the music lead in.
+// Also, added function to pause the sound effects
+// just for sequences.
+//
+// 1.37 21-Jul-97 PRP Modified ClearAllFx so that it doesn't kick out
+// lead in and lead out music for smacker sequences.
+//
+// 1.38 21-Jul-97 PRP Tried to fix the bug where the second lead in
+// music will not play due to a duplicate id.
+//
+// 1.39 21-Jul-97 PRP Finally fixed the bug to kick out lead in music
+// fx when they have finished.
+//
+// 1.40 25-Jul-97 JEL Fixed crashing when music paused & unpaused repeatedly
+//
+// 1.41 28-Jul-97 PRP Checked to see if fx are looping as well as playing!
+//
+// 1.42 30-Jul-97 PSJ Added Music dipping.
+//
+// 1.43 30-Jul-97 PSJ Added MusicTimeRemaining.
+//
+// 1.44 31-Jul-97 PSJ Adjusted MusicTimeRemaining to include music left in buffer.
+//
+// 1.45 06-Aug-97 PSJ Updated Get and Set scroll SoundStatus.
+//
+// 1.46 12-Aug-97 PSJ Added ReverseStereo(void)
+//
+// 1.47 13-Aug-97 PSJ Updated DipMusic so it fades up after speech has finished.
+//
+// 1.48 13-Aug-97 PRP Added IsFxOpen().
+//
+// 1.49 15-Aug-97 PRP Added SetFxVolumePan().
+//
+// 1.50 15-Aug-97 PRP Added SetFxIdVolume()
+//
+// 1.51 15-Aug-97 PSJ Fixed bug in PlayCompMusic();
+//
+// 1.52 19-Aug-97 JEL Fixed bug in MusicTimeRemaining()
+//
+// WE'VE SCREWED UP THE NUMBERING!
+//
+// 1.59 19-Aug-97 JEL Fixed bug in MusicTimeRemaining(), ;)
+//
+// 1.60 19-Aug-97 PSJ Updated DipMusic so it fades music a bit more.
+//
+// 1.61 21-Aug-97 PSJ Updated StreamCompMusic so if both streams are in use,
+// the fading stream is stopped and the new tune started.
+//
+// 1.62 21-Aug-97 PSJ Updated StreamCompMusic so if the music is unmuted,
+// the last tune is restarted if it was looping.
+//
+// 1.63 22-Aug-97 PSJ Update PlayFx to handle smacker leadouts.
+//
+// 1.64 27-Aug-97 PSJ Update PlayFx to record an fx's local volume,
+// So SetFxVolume can update playing fx's with the
+// correct volume.
+//
+// 1.65 27-Aug-97 PSJ Stopped CloseFX from closing invalid fx's.
+//
+// 1.66 01-Sep-97 PRP Cleared the fxPaused flag when closing fx.
+//
+// 1.67 01-Sep-97 PRP Fixed the fact that SetFxVolume was still
+// being done even if the fx were muted.
+//
+// 1.68 01-Sep-97 PRP Set zero sound to -10000
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// int32 InitialiseSound(uint16 freq, uint16 channels, uint16 bitDepth)
+//
+// This function initialises DirectSound by specifying the parameters of the
+// primary buffer.
+//
+// Freq is the sample rate - 44100, 22050 or 11025
+// Channels should be 1 for mono, 2 for stereo
+// BitDepth should be either 8 or 16 bits per sample.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlaySpeech(uint8 *data, uint8 vol, int8 pan)
+//
+// This function plays the wav file passed into it as speech. An error occurs
+// if speech is already playing, or directSound comes accross problems. The
+// volume is 0 for zero volume and 16 for maximum volume. The pan position
+// is -16 for full left, 0 for central and 16 for full right.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlayCompSpeech(const char *filename, uint32 id, uint8 vol, int8 pan)
+//
+// This function loads, decompresses and plays the wav 'id' from the cluster
+// 'filename'. An error occurs if speech is already playing, or directSound
+// comes accross problems. 'volume' can be from 0 to 16. 'pan' can be from
+// -16 (full left) to 16 (full right).
+// id is the text line id used to reference the speech within the speech
+// cluster.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StopSpeech(void)
+//
+// Stops the speech from playing.
+//
+// --------------------------------------------------------------------------
+//
+// int32 GetSpeechStatus(void)
+//
+// Returns either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED
+//
+// --------------------------------------------------------------------------
+//
+// int32 AmISpeaking(void)
+//
+// Returns either RDSE_QUIET or RDSE_SPEAKING
+//
+// --------------------------------------------------------------------------
+//
+// int32 PauseSpeech(void)
+//
+// Stops the speech dead in it's tracks.
+//
+// --------------------------------------------------------------------------
+//
+// int32 UnpauseSpeech(void)
+//
+// Re-starts the speech from where it was stopped.
+//
+// --------------------------------------------------------------------------
+//
+// int32 OpenFx(int32 id, uint8 *data)
+//
+// This function opens a sound effect ready for playing. A unique id should
+// be passed in so that each effect can be referenced individually.
+//
+// WARNING: Zero is not a valid ID.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlayFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type)
+//
+// This function plays a sound effect. If the effect has already been opened
+// then *data should be NULL, and the sound effect will simply be obtained
+// from the id passed in. If the effect has not been opened, then the wav
+// data should be passed in data. The sound effect will be closed when it
+// has finished playing.
+//
+// The volume can be between 0 (minimum) and 16 (maximum). The pan defines
+// the left/right balance of the sample. -16 is full left, and 16 is full
+// right with 0 in the middle. The sample type can be either RDSE_FXSPOT, or
+// RDSE_FXLOOP.
+//
+// WARNING: Zero is not a valid ID
+//
+// --------------------------------------------------------------------------
+//
+// int32 CloseFx(int32 id)
+//
+// This function closes a sound effect which has been previously opened for
+// playing. Sound effects must be closed when they are finished with,
+// otherwise you will run out of sound effect buffers.
+//
+// --------------------------------------------------------------------------
+//
+// int32 ClearAllFx(void)
+//
+// This function clears all of the sound effects which are currently open or
+// playing, irrespective of type.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StreamMusic(uint8 *filename, int32 loopFlag)
+//
+// Streams music from the file defined by filename. The loopFlag should
+// be set to RDSE_FXLOOP if the music is to loop back to the start.
+// Otherwise, it should be RDSE_FXSPOT.
+// The return value must be checked for any problems.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StreamCompMusic(uint8 *filename, uint32 id, int32 loopFlag)
+//
+// Streams music 'id' from the cluster file 'filename'. The loopFlag should
+// be set to RDSE_FXLOOP if the music is to loop back to the start.
+// Otherwise, it should be RDSE_FXSPOT.
+// The return value must be checked for any problems.
+//
+// StreamCompMusic should not be used inconjunction with StreamMusic.
+//
+// --------------------------------------------------------------------------
+//
+// void StopMusic(void)
+//
+// Fades out and stops the music.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PauseMusic(void)
+//
+// Stops the music dead in it's tracks.
+//
+// --------------------------------------------------------------------------
+//
+// int32 UnpauseMusic(void)
+//
+// Re-starts the music from where it was stopped.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 MusicTimeRemaining(void)
+//
+// Returns the time left for the current tune.
+//
+// ----------------------------------------------------------------------------
+//
+// int32 ReverseStereo(void)
+//
+// This function reverse the pan table, thus reversing the stereo.
+//
+//=============================================================================
+
+
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+#include <stdio.h>
+
+#include "driver96.h"
+#include "rdwin.h" // for hwnd.
+
+// Decompression macros
+#define MakeCompressedByte(shift,sign,amplitude) (((shift)<<4) + ((sign)<<3) + (amplitude))
+#define GetCompressedShift(byte) ((byte)>>4)
+#define GetCompressedSign(byte) (((byte)>>3) & 1)
+#define GetCompressedAmplitude(byte) ((byte) & 7)
+#define GetdAPower(dA,power) for (power = 15;power>0 && !((dA) & (1<<power)); power--)
+
+int32 panTable[33] = {
+ -10000,
+ -1500, -1400, -1300, -1200,
+ -1100, -1000, -900, -800,
+ -700, -600, -500, -400,
+ -300, -200, -100, 0,
+ 100, 200, 300, 400,
+ 500, 600, 700, 800,
+ 900, 1000, 1100, 1200,
+ 1300, 1400, 1500, 10000
+};
+
+int32 volTable[241] = {
+
+-10000, -3925, -3852, -3781, -3710, -3642, -3574, -3508, -3443, -3379, -3316, -3255, -3194, -3135, -3077, -3020, -2964, -2909, -2855, -2802, -2750, -2699, -2649, -2600, -2551, -2504, -2458, -2412, -2367, -2323, -2280, -2238, -2197, -2156, -2116, -2077, -2038, -2000, -1963, -1927, -1891, -1856, -1821, -1788, -1755, -1722, -1690, -1659, -1628, -1598, -1568, -1539, -1510, -1482, -1455, -1428, -1401, -1375, -1350, -1325,
+-1300, -1290, -1279, -1269, -1259, -1249, -1239, -1229, -1219, -1209, -1199, -1190, -1180, -1171, -1161, -1152, -1142, -1133, -1124, -1115, -1106, -1097, -1088, -1080, -1071, -1062, -1054, -1045, -1037, -1028, -1020, -1012, -1004, -996, -988, -980, -972, -964, -956, -949, -941, -933, -926, -918, -911, -904, -896, -889, -882, -875, -868, -861, -854, -847, -840, -833, -827, -820, -813, -807,
+-800, -791, -782, -773, -764, -755, -747, -738, -730, -721, -713, -705, -697, -689, -681, -673, -665, -658, -650, -643, -635, -628, -621, -613, -606, -599, -593, -586, -579, -572, -566, -559, -553, -546, -540, -534, -528, -522, -516, -510, -504, -498, -492, -487, -481, -476, -470, -465, -459, -454, -449, -444, -439, -434, -429, -424, -419, -414, -409, -404,
+-400, -362, -328, -297, -269, -244, -221, -200, -181, -164, -148, -134, -122, -110, -100, -90, -82, -74, -67, -61, -55, -50, -45, -41, -37, -33, -30, -27, -25, -22, -20, -18, -16, -15, -13, -12, -11, -10, -9, -8, -7, -6, -6, -5, -5, -4, -4, -3, -3, -3, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0
+
+};
+
+/*
+LPDIRECTSOUND lpDS;
+LPDIRECTSOUNDBUFFER dsbPrimary;
+LPDIRECTSOUNDBUFFER dsbSpeech;
+LPDIRECTSOUNDBUFFER dsbFx[MAXFX];
+*/
+
+int32 fxId[MAXFX];
+uint8 fxCached[MAXFX];
+uint8 fxiPaused[MAXFX];
+uint8 fxLooped[MAXFX];
+uint8 fxVolume[MAXFX];
+
+uint8 soundOn = 0;
+uint8 speechStatus = 0;
+uint8 fxPaused = 0;
+uint8 speechPaused = 0;
+uint8 speechVol = 14;
+uint8 fxVol = 14;
+uint8 speechMuted = 0;
+uint8 fxMuted = 0;
+uint8 compressedMusic = 0;
+
+int16 musStreaming[MAXMUS];
+int16 musicPaused[MAXMUS];
+int16 musCounter[MAXMUS];
+int16 musFading[MAXMUS];
+int16 musLooping[MAXMUS];
+//DSBUFFERDESC dsbdMus[MAXMUS];
+//LPDIRECTSOUNDBUFFER lpDsbMus[MAXMUS];
+FILE *fpMus[MAXMUS];
+//PCMWAVEFORMAT wfMus[MAXMUS];
+int32 streamCursor[MAXMUS];
+char musFilename[MAXMUS][256];
+int32 musFilePos[MAXMUS];
+int32 musEnd[MAXMUS];
+int16 musLastSample[MAXMUS];
+uint32 musId[MAXMUS];
+uint32 volMusic[2] = {16, 16};
+uint8 musicMuted = 0;
+int32 musicVolTable[17] = {
+ -10000,
+ -5000, -3000, -2500, -2250,
+ -2000, -1750, -1500, -1250,
+ -1000, -750, -500, -350,
+ -200, -100, -50, 0
+};
+
+
+
+void UpdateSampleStreaming(void);
+void UpdateCompSampleStreaming(void);
+int32 DipMusic(void);
+
+
+#define SPEECH_EXPANSION
+
+#ifdef SPEECH_EXPANSION
+
+int16 ExpandSpeech(int16 sample)
+// This code is executed to expand the speech samples to make them sound
+// louder, without losing the quality of the sample
+{
+ double x, xsquared, result;
+ double expansionFactor = 2.5;
+
+ x = (double) sample;
+ xsquared = sample * sample;
+
+ if (x < 0.0)
+ {
+ result = expansionFactor * x + (expansionFactor - 1.0) * xsquared / 32768.0;
+ if (result < -32767.0)
+ result = -32767.0;
+ }
+ else
+ {
+ result = expansionFactor * x + (1.0 - expansionFactor) * xsquared / 32768.0;
+ if (result > 32767.0)
+ result = 32767.0;
+ }
+
+ return (int16) result;
+
+}
+#endif
+
+
+// --------------------------------------------------------------------------
+// This function reverse the pan table, thus reversing the stereo.
+// --------------------------------------------------------------------------
+int32 ReverseStereo(void)
+{
+ int32 i,j;
+
+ for (i = 0; i<16; i++)
+ {
+ j = panTable[i];
+ panTable[i] = panTable[32-i];
+ panTable[32-i] = j;
+ }
+
+ return (RD_OK);
+}
+
+
+
+// --------------------------------------------------------------------------
+// This function returns the index of the sound effect with the ID passed in.
+// --------------------------------------------------------------------------
+int32 GetFxIndex(int32 id)
+
+{
+
+ int32 i = 0;
+
+ while (i < MAXFX)
+ {
+ if (fxId[i] == id)
+ break;
+ i++;
+ }
+
+ return(i);
+
+}
+
+
+int32 IsFxOpen(int32 id)
+{
+
+ int32 i = 0;
+
+ while (i < MAXFX)
+ {
+ if (fxId[i] == id)
+ break;
+ i++;
+ }
+
+ if (i == MAXFX)
+ return 1;
+ else
+ return 0;
+
+}
+
+
+// --------------------------------------------------------------------------
+// This function checks the status of all current sound effects, and clears
+// out the ones which are no longer required in a buffer. It is called on
+// a slow timer from rdwin.c
+// --------------------------------------------------------------------------
+void FxServer(void)
+
+{
+ warning("stub FxServer");
+/*
+ int32 i;
+ int32 status;
+
+
+ if (!soundOn)
+ return;
+
+ if (musicPaused[0] + musicPaused[1] == 0)
+ {
+ if (compressedMusic == 1)
+ UpdateCompSampleStreaming();
+ else if (compressedMusic == 2)
+ UpdateSampleStreaming();
+ }
+
+ if (fxPaused)
+ {
+ for (i=0; i<MAXFX; i++)
+ {
+ if ((fxId[i] == 0xfffffffe) || (fxId[i] == 0xffffffff))
+ {
+ IDirectSoundBuffer_GetStatus(dsbFx[i], &status);
+ if (!(status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING)))
+ {
+ if (fxCached[i] == RDSE_FXTOCLEAR)
+ {
+ IDirectSoundBuffer_Release(dsbFx[i]);
+ fxId[i] = 0;
+ }
+ }
+ }
+ }
+ return;
+ }
+
+
+ for (i=0; i<MAXFX; i++)
+ {
+ if (fxId[i])
+ {
+ IDirectSoundBuffer_GetStatus(dsbFx[i], &status);
+ if (!(status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING)))
+ {
+ if (fxCached[i] == RDSE_FXTOCLEAR)
+ {
+ IDirectSoundBuffer_Release(dsbFx[i]);
+ fxId[i] = 0;
+ }
+ }
+ }
+ }
+*/
+}
+
+
+
+
+
+int32 InitialiseSound(uint16 freq, uint16 channels, uint16 bitDepth)
+
+{
+ warning("stub InitaliseSound( %d, %d, %d )", freq, channels, bitDepth);
+/*
+ int32 i;
+ HRESULT hrz;
+ DSBUFFERDESC dsbd;
+ WAVEFORMATEX pf;
+
+
+ hrz = DirectSoundCreate(NULL, &lpDS, NULL);
+ if (hrz != DS_OK)
+ return(RDERR_DSOUNDCREATE);
+
+ hrz = IDirectSound_SetCooperativeLevel(lpDS, hwnd, DSSCL_EXCLUSIVE);
+ if (hrz != DS_OK)
+ {
+ IDirectSound_Release(lpDS);
+ return(RDERR_DSOUNDCOOPERATE);
+ }
+
+
+ memset(&dsbd, 0, sizeof(DSBUFFERDESC));
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.lpwfxFormat = NULL;
+ hrz = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &dsbPrimary, NULL);
+ if (hrz != DS_OK)
+ {
+ IDirectSound_Release(lpDS);
+ return(RDERR_DSOUNDPBUFFER);
+ }
+
+ memset(&pf, 0, sizeof(WAVEFORMATEX));
+
+ pf.wFormatTag = WAVE_FORMAT_PCM;
+
+ pf.nSamplesPerSec = freq;
+
+ pf.nChannels = channels;
+
+ pf.wBitsPerSample = bitDepth;
+ pf.nBlockAlign = pf.wBitsPerSample * pf.nChannels >> 3;
+ pf.nAvgBytesPerSec = pf.nBlockAlign * pf.nSamplesPerSec;
+ pf.cbSize = 0;
+ hrz = IDirectSoundBuffer_SetFormat(dsbPrimary, (LPWAVEFORMATEX) &pf);
+ if (hrz != DS_OK)
+ {
+ // We have not been able to set the primary format to the format requested!!!
+ // But carry on anyway, the mixer will just have to work harder :)
+ }
+
+ // Clear the fx id's
+ for (i=0; i<MAXFX; i++)
+ fxId[i] = 0;
+
+ soundOn = 1;
+
+ //----------------------------------
+ // New initialisers (James19aug97)
+
+ memset (fxId, 0, MAXFX*sizeof(int32));
+ memset (fxCached, 0, MAXFX*sizeof(uint8));
+ memset (fxiPaused, 0, MAXFX*sizeof(uint8));
+ memset (fxLooped, 0, MAXFX*sizeof(uint8));
+
+ memset (musStreaming, 0, MAXFX*sizeof(int16));
+ memset (musicPaused, 0, MAXFX*sizeof(int16));
+ memset (musCounter, 0, MAXFX*sizeof(int16));
+ memset (musFading, 0, MAXFX*sizeof(int16));
+
+ memset (musLooping, 0, MAXFX*sizeof(int16));
+ memset (fpMus, 0, MAXFX*sizeof(FILE*));
+
+ memset (streamCursor, 0, MAXFX*sizeof(int32));
+ memset (musFilePos, 0, MAXFX*sizeof(int32));
+ memset (musEnd, 0, MAXFX*sizeof(int32));
+ memset (musLastSample, 0, MAXFX*sizeof(int16));
+ memset (musId, 0, MAXFX*sizeof(uint32));
+*/
+ return(RD_OK);
+
+}
+
+
+int32 PlaySpeech(uint8 *data, uint8 vol, int8 pan)
+
+{
+ warning("stub PlaySpeech");
+/*
+ uint32 dwBytes1, dwBytes2;
+ int32 i;
+ uint32 *data32;
+ void *lpv1, *lpv2;
+ _wavHeader *wav;
+ HRESULT hr;
+ DSBUFFERDESC dsbd;
+ PCMWAVEFORMAT wf;
+
+
+ wav = (_wavHeader *) data;
+
+ if (soundOn)
+ {
+ if (speechStatus)
+ return(RDERR_SPEECHPLAYING);
+
+ memset(&wf, 0, sizeof(PCMWAVEFORMAT));
+ wf.wf.wFormatTag = WAVE_FORMAT_PCM;
+ wf.wf.nChannels = wav->channels;
+ wf.wf.nSamplesPerSec = wav->samplesPerSec;
+ wf.wBitsPerSample = 8 * wav->blockAlign / (wav->samplesPerSec * wav->channels);
+ wf.wf.nBlockAlign = wf.wf.nChannels * wf.wBitsPerSample / 8;
+ wf.wf.nAvgBytesPerSec = wf.wf.nSamplesPerSec * wf.wf.nBlockAlign;
+
+ memset(&dsbd, 0, sizeof(DSBUFFERDESC));
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ // dsbd.dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbd.lpwfxFormat = (LPWAVEFORMATEX) &wf;
+
+ // Set the sample size - search for the size of the data.
+ i = 0;
+ while (i<100)
+ {
+ if (*data == 'd')
+ {
+ data32 = (int32 *) data;
+ if (*data32 == 'atad')
+ break;
+ }
+ i += 1;
+ data++;
+ }
+ if (i == 100)
+ return(RDERR_INVALIDWAV);
+
+ dsbd.dwBufferBytes = *(data32 + 1);
+
+ // Create the speech sample buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &dsbSpeech, NULL);
+ if (hr != DS_OK)
+ return(RDERR_CREATESOUNDBUFFER);
+
+ // Lock the speech buffer, ready to fill it with data
+ hr = IDirectSoundBuffer_Lock(dsbSpeech, 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(dsbSpeech);
+ hr = IDirectSoundBuffer_Lock(dsbSpeech, 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+ // Fill the speech buffer with data
+ memcpy((uint8 *) lpv1, (uint8 *) (data32 + 2), dwBytes1);
+
+ if (dwBytes1 != dsbd.dwBufferBytes)
+ {
+ memcpy((uint8 *) lpv1 + dwBytes1, (uint8 *) (data32 + 2) + dwBytes1, dwBytes2);
+ }
+
+ // Unlock the buffer now that we've filled it
+ IDirectSoundBuffer_Unlock(dsbSpeech, lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // Modify the volume according to the master volume
+ if (speechMuted)
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[vol*speechVol]);
+
+ IDirectSoundBuffer_SetPan(dsbSpeech, panTable[pan+16]);
+
+ // Start the speech playing
+ IDirectSoundBuffer_Play(dsbSpeech, 0, 0, 0);
+ speechStatus = 1;
+
+ }
+ else
+ {
+ IDirectSoundBuffer_Release(dsbSpeech);
+ return(RDERR_LOCKSPEECHBUFFER);
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 AmISpeaking()
+{
+ warning("stub AmISpeaking");
+/*
+ int32 len;
+// int32 status;
+ int32 readCursor, writeCursor;
+ int32 dwBytes1, dwBytes2;
+ int16 *sample;
+ int32 count = 0;
+ LPVOID lpv1, lpv2;
+ HRESULT hr;
+
+#define POSITIVE_THRESHOLD 350
+#define NEGATIVE_THRESHOLD -350
+ if ((!speechMuted) && (!speechPaused) && (dsbSpeech))
+ {
+ if (IDirectSoundBuffer_GetCurrentPosition(dsbSpeech, &readCursor, &writeCursor) != DS_OK)
+ {
+ return (RDSE_SPEAKING);
+ }
+
+ len = 44100 / 12;
+
+ hr = IDirectSoundBuffer_Lock(dsbSpeech, readCursor, len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ if (hr == DS_OK)
+ {
+ for (sample = (int16*)lpv1; sample<(int16*)((int8*)lpv1+dwBytes1); sample+= 90) // 20 samples
+ if (*sample>POSITIVE_THRESHOLD || *sample<NEGATIVE_THRESHOLD)
+ count++;
+
+ IDirectSoundBuffer_Unlock(dsbSpeech,lpv1,dwBytes1,lpv2,dwBytes2);
+
+ if (count>5) // 25% of the samples
+ return (RDSE_SPEAKING);
+ }
+ return (RDSE_QUIET);
+ }
+ return (RDSE_SPEAKING);
+*/
+ return RDSE_QUIET;
+}
+
+
+int32 GetCompSpeechSize(const char *filename, uint32 speechid)
+{
+ int32 i;
+ uint32 speechIndex[2];
+ FILE *fp;
+
+ // Open the speech cluster and find the data offset & size
+ fp = fopen(filename, "rb");
+ if (fp == NULL)
+ return(0);
+
+ if (fseek(fp, (++speechid)*8, SEEK_SET))
+ {
+ fclose(fp);
+ return (0);
+ }
+
+ if (fread(speechIndex, sizeof(uint32), 2, fp) != 2)
+ {
+ fclose(fp);
+ return (0);
+ }
+
+ if (!speechIndex[0] || !speechIndex[1])
+ {
+ fclose(fp);
+ return (0);
+ }
+
+ fclose(fp);
+
+ i = (speechIndex[1]-1)*2 + sizeof(_wavHeader) + 8;
+
+ return(i);
+}
+
+
+int32 PreFetchCompSpeech(const char *filename, uint32 speechid, uint8 *waveMem)
+{
+ uint32 i;
+ uint16 *data16;
+ uint8 *data8;
+ uint32 speechIndex[2];
+ _wavHeader *pwf = (_wavHeader *) waveMem;
+ FILE *fp;
+
+ // Open the speech cluster and find the data offset & size
+ fp = fopen(filename, "rb");
+ if (fp == NULL)
+ return(RDERR_INVALIDFILENAME);
+
+ if (fseek(fp, (++speechid)*8, SEEK_SET))
+ {
+ fclose(fp);
+ return (RDERR_READERROR);
+ }
+
+ if (fread(speechIndex, sizeof(uint32), 2, fp) != 2)
+ {
+ fclose(fp);
+ return (RDERR_READERROR);
+ }
+
+ if (!speechIndex[0] || !speechIndex[1])
+ {
+ fclose(fp);
+ return (RDERR_INVALIDID);
+ }
+
+ data16 = (uint16*)(waveMem + sizeof(_wavHeader));
+
+ memset(pwf, 0, sizeof(_wavHeader));
+
+ *((uint32*)pwf->riff) = 'FFIR';
+ *((uint32*)pwf->wavID) = 'EVAW';
+ *((uint32*)pwf->format) = ' tmf';
+
+ pwf->formatLen = 0x00000010;
+ pwf->formatTag = 0x0001;
+ pwf->channels = 0x0001;
+ pwf->samplesPerSec = 0x5622;
+ pwf->avgBytesPerSec = 0x0000;
+ pwf->blockAlign = 0xAC44;
+ pwf->unknown1 = 0x0000;
+ pwf->unknown2 = 0x0002;
+ pwf->bitsPerSample = 0x0010;
+
+ *((uint32*)data16) = 'atad';
+
+ data16 += 2;
+
+ *((uint32*)data16) = (speechIndex[1]-1)*2;
+
+ data16 += 2;
+
+ pwf->fileLength = (speechIndex[1]-1)*2 + sizeof(_wavHeader) + 8;
+
+
+ // Calculate position in buffer to load compressed sound into
+ data8 = (uint8*)data16 + (speechIndex[1]-1);
+
+ if (fseek(fp, speechIndex[0], SEEK_SET))
+ {
+ fclose(fp);
+ return (RDERR_INVALIDID);
+ }
+
+ if (fread(data8, sizeof(uint8), speechIndex[1], fp) != speechIndex[1])
+ {
+ fclose(fp);
+ return (RDERR_INVALIDID);
+ }
+
+ fclose(fp);
+
+ data16[0] = *((int16*)data8); // Starting Value
+ i=1;
+
+ while (i<(speechIndex[1]-1))
+ {
+ if (GetCompressedSign(data8[i+1]))
+ data16[i] = data16[i-1] - (GetCompressedAmplitude(data8[i+1])<<GetCompressedShift(data8[i+1]));
+ else
+ data16[i] = data16[i-1] + (GetCompressedAmplitude(data8[i+1])<<GetCompressedShift(data8[i+1]));
+ i++;
+ }
+
+ return(RD_OK);
+}
+
+
+int32 PlayCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan)
+{
+ warning("stub PlayCompSpeech( %s, %d, %d, %d )", filename, speechid, vol, pan);
+/*
+ uint32 dwBytes1, dwBytes2;
+ uint32 i;
+ uint16 *data16;
+ uint8 *data8;
+ uint32 speechIndex[2];
+ void *lpv1, *lpv2;
+ HRESULT hr;
+ DSBUFFERDESC dsbd;
+ PCMWAVEFORMAT wf;
+ FILE *fp;
+
+ if (!speechMuted)
+ {
+ if (GetSpeechStatus() == RDERR_SPEECHPLAYING)
+ return RDERR_SPEECHPLAYING;
+
+ memset(&wf, 0, sizeof(PCMWAVEFORMAT));
+ wf.wf.wFormatTag = WAVE_FORMAT_PCM;
+ wf.wf.nChannels = 1;
+ wf.wf.nSamplesPerSec = 22050;
+ wf.wBitsPerSample = 16;
+ wf.wf.nBlockAlign = 2;
+ wf.wf.nAvgBytesPerSec = 44100;
+
+ memset(&dsbd, 0, sizeof(DSBUFFERDESC));
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+// dsbd.dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbd.lpwfxFormat = (LPWAVEFORMATEX) &wf;
+
+ // Open the speech cluster and find the data offset & size
+ fp = fopen(filename, "rb");
+ if (fp == NULL)
+ return(RDERR_INVALIDFILENAME);
+
+ if (fseek(fp, (++speechid)*8, SEEK_SET))
+ {
+ fclose(fp);
+ return (RDERR_READERROR);
+ }
+
+ if (fread(speechIndex, sizeof(uint32), 2, fp) != 2)
+ {
+ fclose(fp);
+ return (RDERR_READERROR);
+ }
+
+ if (speechIndex[0]==0 || speechIndex[1]==0)
+ {
+ fclose(fp);
+ return (RDERR_INVALIDID);
+ }
+
+
+ dsbd.dwBufferBytes = (speechIndex[1]-1)*2;
+
+ // Create tempory buffer for compressed speech
+ if ((data8 = malloc(speechIndex[1])) == NULL)
+ {
+ fclose(fp);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ if (fseek(fp, speechIndex[0], SEEK_SET))
+ {
+ fclose(fp);
+ free(data8);
+ return (RDERR_INVALIDID);
+ }
+
+ if (fread(data8, sizeof(uint8), speechIndex[1], fp) != speechIndex[1])
+ {
+ fclose(fp);
+ free(data8);
+ return (RDERR_INVALIDID);
+ }
+
+ fclose(fp);
+
+ // Create the speech sample buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &dsbSpeech, NULL);
+ if (hr != DS_OK)
+ {
+ free(data8);
+ return(RDERR_CREATESOUNDBUFFER);
+ }
+
+ // Lock the speech buffer, ready to fill it with data
+ hr = IDirectSoundBuffer_Lock(dsbSpeech, 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(dsbSpeech);
+ hr = IDirectSoundBuffer_Lock(dsbSpeech, 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+ // decompress data into speech buffer.
+ data16 = (uint16*)lpv1;
+
+ data16[0] = *((int16*)data8); // Starting Value
+ i=1;
+
+ while (i<dwBytes1/2)
+ {
+ if (GetCompressedSign(data8[i+1]))
+ data16[i] = data16[i-1] - (GetCompressedAmplitude(data8[i+1])<<GetCompressedShift(data8[i+1]));
+ else
+ data16[i] = data16[i-1] + (GetCompressedAmplitude(data8[i+1])<<GetCompressedShift(data8[i+1]));
+
+
+ i++;
+ }
+
+ if (dwBytes1 != dsbd.dwBufferBytes)
+ {
+ while (i<(dwBytes1+dwBytes2)/2)
+ {
+ if (GetCompressedSign(data8[i+1]))
+ data16[i] = data16[i-1] - (GetCompressedAmplitude(data8[i+1])<<GetCompressedShift(data8[i+1]));
+ else
+ data16[i] = data16[i-1] + (GetCompressedAmplitude(data8[i+1])<<GetCompressedShift(data8[i+1]));
+
+
+ i++;
+ }
+ }
+
+ free(data8);
+
+ // Unlock the buffer now that we've filled it
+ IDirectSoundBuffer_Unlock(dsbSpeech, lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // Modify the volume according to the master volume
+ if (speechMuted)
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[vol*speechVol]);
+
+ IDirectSoundBuffer_SetPan(dsbSpeech, panTable[pan+16]);
+
+ // Start the speech playing
+ speechPaused = 1;
+// IDirectSoundBuffer_Play(dsbSpeech, 0, 0, 0);
+ speechStatus = 1;
+ }
+ else
+ {
+ IDirectSoundBuffer_Release(dsbSpeech);
+ free(data8);
+ return(RDERR_LOCKSPEECHBUFFER);
+ }
+ }
+
+ DipMusic();
+*/
+ return(RD_OK);
+}
+
+
+int32 StopSpeech(void)
+
+{
+ warning("stub StopSpeech");
+/*
+ int32 status;
+
+
+ if (!soundOn)
+ return(RD_OK);
+
+ if (speechStatus)
+ {
+ IDirectSoundBuffer_GetStatus(dsbSpeech, &status);
+ if (status & DSBSTATUS_PLAYING)
+ {
+ IDirectSoundBuffer_Stop(dsbSpeech);
+// SetMusicVolume(GetMusicVolume());
+ }
+
+ IDirectSoundBuffer_Release(dsbSpeech);
+ dsbSpeech = 0;
+ speechStatus = 0;
+ return(RD_OK);
+ }
+*/
+ return(RDERR_SPEECHNOTPLAYING);
+
+}
+
+
+
+int32 GetSpeechStatus(void)
+{
+ warning("stub GetSpeechStatus");
+/*
+ int32 status;
+
+
+ if ((!soundOn) || (!speechStatus))
+ return(RDSE_SAMPLEFINISHED);
+
+ if (speechPaused)
+ return(RDSE_SAMPLEPLAYING);
+
+ IDirectSoundBuffer_GetStatus(dsbSpeech, &status);
+ if (!(status & DSBSTATUS_PLAYING))
+ {
+ speechStatus = 0;
+ IDirectSoundBuffer_Release(dsbSpeech);
+ dsbSpeech = 0;
+// SetMusicVolume(GetMusicVolume());
+ return(RDSE_SAMPLEFINISHED);
+ }
+ return(RDSE_SAMPLEPLAYING);
+*/
+ return RDSE_SAMPLEFINISHED;
+
+}
+
+
+void SetSpeechVolume(uint8 volume)
+{
+ warning("stub SetSpeechVolume");
+/*
+ speechVol = volume;
+ if (dsbSpeech && !speechMuted && GetSpeechStatus() == RDSE_SAMPLEPLAYING)
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[16*speechVol]);
+*/
+}
+
+
+uint8 GetSpeechVolume()
+{
+ return speechVol;
+}
+
+
+void MuteSpeech(uint8 mute)
+{
+ warning("stub MuteSpeech( %d )", mute);
+/*
+ speechMuted = mute;
+
+ if (GetSpeechStatus() == RDSE_SAMPLEPLAYING)
+ {
+ if (mute)
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[16*speechVol]);
+ }
+*/
+}
+
+
+uint8 IsSpeechMute(void)
+{
+ return (speechMuted);
+}
+
+
+int32 PauseSpeech(void)
+{
+ warning("PauseSpeech");
+/*
+ if (GetSpeechStatus() == RDSE_SAMPLEPLAYING)
+ {
+ speechPaused = 1;
+ return (IDirectSoundBuffer_Stop(dsbSpeech));
+ }
+*/
+ return(RD_OK);
+}
+
+int32 UnpauseSpeech(void)
+{
+ warning("UnpauseSpeech");
+/*
+ if (speechPaused)
+ {
+ speechPaused = 0;
+ return (IDirectSoundBuffer_Play(dsbSpeech, 0, 0, 0));
+ }
+*/
+ return(RD_OK);
+}
+
+
+int32 OpenFx(int32 id, uint8 *data)
+
+{
+ warning("stub OpenFx( %d )", id);
+/*
+ uint32 dwBytes1, dwBytes2;
+ int32 i, fxi;
+ uint32 *data32;
+ void *lpv1, *lpv2;
+ _wavHeader *wav;
+ HRESULT hr;
+ DSBUFFERDESC dsbd;
+ PCMWAVEFORMAT wf;
+
+
+ wav = (_wavHeader *) data;
+
+ if (soundOn)
+ {
+
+ // Check for a valid id.
+ if (id == 0)
+ return(RDERR_INVALIDID);
+
+ // Check that the fx is not already open
+ for (i=0; i<MAXFX; i++)
+ if (fxId[i] == id)
+ return(RDERR_FXALREADYOPEN);
+
+ // Now choose a free slot for the fx
+ fxi = 0;
+ while (fxi<MAXFX)
+ {
+ if (fxId[fxi] == 0)
+ break;
+ fxi++;
+ }
+
+ if (fxi == MAXFX)
+ return(RDERR_NOFREEBUFFERS);
+
+ memset(&wf, 0, sizeof(PCMWAVEFORMAT));
+ wf.wf.wFormatTag = WAVE_FORMAT_PCM;
+ wf.wf.nChannels = wav->channels;
+ wf.wf.nSamplesPerSec = wav->samplesPerSec;
+ wf.wBitsPerSample = 8 * wav->blockAlign / (wav->samplesPerSec * wav->channels);
+ wf.wf.nBlockAlign = wf.wf.nChannels * wf.wBitsPerSample / 8;
+ wf.wf.nAvgBytesPerSec = wf.wf.nSamplesPerSec * wf.wf.nBlockAlign;
+
+ memset(&dsbd, 0, sizeof(DSBUFFERDESC));
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+// dsbd.dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbd.lpwfxFormat = (LPWAVEFORMATEX) &wf;
+
+ // Set the sample size - search for the size of the data.
+ i = 0;
+ while (i<100)
+ {
+ if (*data == 'd')
+ {
+ data32 = (int32 *) data;
+ if (*data32 == 'atad')
+ break;
+ }
+ i += 1;
+ data++;
+ }
+ if (i == 100)
+ return(RDERR_INVALIDWAV);
+
+ dsbd.dwBufferBytes = *(data32 + 1);
+
+ // Create the speech sample buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &dsbFx[fxi], NULL);
+ if (hr != DS_OK)
+ return(RDERR_CREATESOUNDBUFFER);
+
+ // Lock the speech buffer, ready to fill it with data
+ hr = IDirectSoundBuffer_Lock(dsbFx[fxi], 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(dsbFx[fxi]);
+ hr = IDirectSoundBuffer_Lock(dsbFx[fxi], 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+ // Fill the speech buffer with data
+ memcpy((uint8 *) lpv1, (uint8 *) (data32 + 2), dwBytes1);
+
+ if (dwBytes1 != dsbd.dwBufferBytes)
+ {
+ memcpy((uint8 *) lpv1 + dwBytes1, (uint8 *) (data32 + 2) + dwBytes1, dwBytes2);
+ }
+
+ // Unlock the buffer now that we've filled it
+ IDirectSoundBuffer_Unlock(dsbFx[fxi], lpv1, dwBytes1, lpv2, dwBytes2);
+
+ }
+ else
+ {
+ IDirectSoundBuffer_Release(dsbFx[fxi]);
+ return(RDERR_LOCKSPEECHBUFFER);
+ }
+
+ fxId[fxi] = id;
+ fxCached[fxi] = RDSE_FXCACHED;
+
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 PlayFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type)
+
+{
+ warning("stub PlayFx( %d, %d, %d, %d )", id, vol, pan, type);
+/*
+ int32 i, loop;
+ HRESULT hr;
+
+ if (type == RDSE_FXLOOP)
+ loop = DSBPLAY_LOOPING;
+ else
+ loop = 0;
+
+ if (soundOn)
+ {
+ if (data == NULL)
+ {
+ if (type == RDSE_FXLEADOUT)
+ {
+ id = 0xffffffff;
+ i = GetFxIndex(id);
+ if (i == MAXFX)
+ return(RDERR_FXNOTOPEN);
+
+ fxLooped[i] = 0;
+
+ // Start the sound effect playing
+ if (musicMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbFx[i], musicVolTable[volMusic[0]]);
+ IDirectSoundBuffer_SetPan(dsbFx[i], 0);
+ IDirectSoundBuffer_Play(dsbFx[i], 0, 0, 0);
+
+ fxCached[i] = RDSE_FXTOCLEAR;
+ }
+ else
+ {
+ i = GetFxIndex(id);
+ if (i == MAXFX)
+ return(RDERR_FXNOTOPEN);
+
+ fxLooped[i] = loop;
+ fxVolume[i] = vol;
+
+ // Start the sound effect playing
+ if (fxMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]);
+ IDirectSoundBuffer_SetPan(dsbFx[i], panTable[pan+16]);
+
+ IDirectSoundBuffer_Play(dsbFx[i], 0, 0, loop);
+ if (id == 0xffffffff)
+ fxCached[i] = RDSE_FXTOCLEAR;
+ }
+ }
+ else
+ {
+ if (type == RDSE_FXLEADIN)
+ {
+ id = 0xfffffffe;
+ hr = OpenFx(id, data);
+ if (hr != RD_OK)
+ return hr;
+ i = GetFxIndex(id);
+ if (i == MAXFX)
+ return RDERR_FXFUCKED;
+ fxCached[i] = RDSE_FXTOCLEAR;
+ if (musicMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbFx[i], musicVolTable[volMusic[0]]);
+ IDirectSoundBuffer_SetPan(dsbFx[i], 0);
+ IDirectSoundBuffer_Play(dsbFx[i], 0, 0, 0);
+ }
+ else
+ {
+ hr = OpenFx(id, data);
+ if (hr != RD_OK)
+ return(hr);
+
+ i = GetFxIndex(id);
+ if (i == MAXFX)
+ return(RDERR_FXFUCKED);
+
+ fxCached[i] = RDSE_FXTOCLEAR;
+ fxLooped[i] = loop;
+ fxVolume[i] = vol;
+
+ // Start the sound effect playing
+ if (fxMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]);
+ IDirectSoundBuffer_SetPan(dsbFx[i], panTable[pan+16]);
+ IDirectSoundBuffer_Play(dsbFx[i], 0, 0, loop);
+ }
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 SetFxVolumePan(int32 id, uint8 vol, int8 pan)
+{
+ warning("stub SetFxVolumePan( %d, %d, %d )", id, vol, pan);
+/*
+ int32 i = GetFxIndex(id);
+ if (i == MAXFX)
+ return RDERR_FXNOTOPEN;
+
+ fxVolume[i] = vol;
+ if (!fxMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]);
+ IDirectSoundBuffer_SetPan(dsbFx[i], panTable[pan+16]);
+*/
+ return RD_OK;
+}
+
+int32 SetFxIdVolume(int32 id, uint8 vol)
+{
+ warning("stub SetFxIdVolume( %d, %d )", id, vol);
+/*
+ int32 i = GetFxIndex(id);
+ if (i == MAXFX)
+ return RDERR_FXNOTOPEN;
+
+ fxVolume[i] = vol;
+ if (!fxMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]);
+*/
+ return RD_OK;
+}
+
+
+
+int32 ClearAllFx(void)
+
+{
+ warning("stub ClearAllFx");
+/*
+ int32 status;
+ int32 i;
+
+
+ if (!soundOn)
+ return(RD_OK);
+
+ i = 0;
+ while (i < MAXFX)
+ {
+ if ((fxId[i]) && (fxId[i] != 0xfffffffe) && (fxId[i] != 0xffffffff))
+ {
+ IDirectSoundBuffer_GetStatus(dsbFx[i], &status);
+ if (status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING))
+ {
+ IDirectSoundBuffer_Stop(dsbFx[i]);
+ }
+ IDirectSoundBuffer_Release(dsbFx[i]);
+ fxId[i] = 0;
+ fxiPaused[i] = 0;
+ }
+ i++;
+ }
+
+*/
+ return(RD_OK);
+
+}
+
+
+int32 CloseFx(int32 id)
+
+{
+ warning("stub CloseFx( %d )", id);
+/*
+ int32 i;
+ int32 status;
+
+
+ if (!soundOn)
+ return(RD_OK);
+
+ i = GetFxIndex(id);
+ if (i<MAXFX)
+ {
+ IDirectSoundBuffer_GetStatus(dsbFx[i], &status);
+ if (status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING))
+ {
+ IDirectSoundBuffer_Stop(dsbFx[i]);
+ }
+
+ IDirectSoundBuffer_Release(dsbFx[i]);
+ fxId[i] = 0;
+ fxiPaused[i] = 0;
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 PauseFx(void)
+
+{
+ warning("stub PauseFx");
+/*
+ int32 i;
+ int32 status;
+
+ if (!fxPaused)
+ {
+ for (i=0; i<MAXFX; i++)
+ {
+ if (fxId[i])
+ {
+ IDirectSoundBuffer_GetStatus(dsbFx[i], &status);
+ if (status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING))
+ {
+ fxiPaused[i] = 1;
+ if (IDirectSoundBuffer_Stop(dsbFx[i]) != RD_OK)
+ return(RDERR_FXFUCKED);
+ }
+ }
+ else
+ {
+ fxiPaused[i] = 0;
+ }
+ }
+ fxPaused = 1;
+ }
+*/
+ return (RD_OK);
+
+}
+
+
+int32 PauseFxForSequence(void)
+
+{
+ warning("stub PauseFxForSequence");
+/*
+ int32 i;
+ int32 status;
+
+ if (!fxPaused)
+ {
+ for (i=0; i<MAXFX; i++)
+ {
+ if ((fxId[i]) && (fxId[i] != 0xfffffffe))
+ {
+ IDirectSoundBuffer_GetStatus(dsbFx[i], &status);
+ if (status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING))
+ {
+ fxiPaused[i] = 1;
+ IDirectSoundBuffer_Stop(dsbFx[i]);
+ }
+ }
+ else
+ {
+ fxiPaused[i] = 0;
+ }
+ }
+ fxPaused = 1;
+ }
+*/
+ return (RD_OK);
+
+}
+
+
+
+int32 UnpauseFx(void)
+
+{
+ warning("stub UnpauseFx");
+/*
+ int32 i;
+
+ if (fxPaused)
+ {
+ for (i=0; i<MAXFX; i++)
+ {
+ if (fxiPaused[i] && fxId[i])
+ {
+ if (IDirectSoundBuffer_Play(dsbFx[i], 0, 0, fxLooped[i]) != RD_OK)
+ return(RDERR_FXFUCKED);
+ }
+ }
+ fxPaused = 0;
+ }
+*/
+ return (RD_OK);
+}
+
+
+
+uint8 GetFxVolume()
+{
+ return fxVol;
+}
+
+
+void SetFxVolume(uint8 volume)
+{
+ warning("stub SetFxVolume( %d )", volume);
+/*
+ int32 fxi;
+ fxVol = volume;
+
+ // Now update the volume of any fxs playing
+ for (fxi = 0; fxi<MAXFX; fxi++)
+ {
+ if (fxId[fxi] && !fxMuted)
+ IDirectSoundBuffer_SetVolume(dsbFx[fxi], volTable[fxVolume[fxi]*fxVol]);
+ }
+*/
+}
+
+
+void MuteFx(uint8 mute)
+{
+ warning("stub MuteFx( %d )");
+/*
+ int32 fxi;
+
+ fxMuted = mute;
+
+ // Now update the volume of any fxs playing
+ for (fxi = 0; fxi<MAXFX; fxi++)
+ {
+ if (fxId[fxi])
+ {
+ if (mute)
+ IDirectSoundBuffer_SetVolume(dsbFx[fxi], volTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(dsbFx[fxi], volTable[fxVolume[fxi]*fxVol]);
+ }
+ }
+*/
+}
+
+uint8 IsFxMute(void)
+{
+ return (fxMuted);
+}
+
+
+
+
+static void StartMusicFadeDown(int i)
+
+{
+
+// IDirectSoundBuffer_Stop(lpDsbMus[i]);
+// IDirectSoundBuffer_Release(lpDsbMus[i]);
+ musFading[i] = -16;
+// musStreaming[i] = 0;
+ fclose(fpMus[i]);
+
+}
+
+
+int32 StreamMusic(uint8 *filename, int32 looping)
+
+{
+ warning("stub StreamMusic( %s, %d )", filename, looping);
+/*
+
+ HRESULT hr;
+ LPVOID lpv1, lpv2;
+ DWORD dwBytes1, dwBytes2;
+ int32 i;
+ int32 v0, v1;
+ int32 bytes;
+ _wavHeader head;
+
+ // Do not allow compressed and uncompressed music to be streamed at the same time.
+ if (compressedMusic == 1)
+ return (RDERR_FXFUCKED);
+
+ compressedMusic = 2;
+
+
+ if (musStreaming[0] + musStreaming[1] == 0)
+ {
+
+ i = 0;
+
+ fpMus[i] = fopen(filename, "rb");
+ if (fpMus[i] == NULL)
+ return(RDERR_INVALIDFILENAME);
+
+ fread(&head, sizeof(_wavHeader), 1, fpMus[i]);
+ streamCursor[i] = 0;
+ musLooping[i] = looping;
+
+
+ memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT));
+ wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM;
+ wfMus[i].wf.nChannels = head.channels;
+ wfMus[i].wf.nSamplesPerSec = head.samplesPerSec;
+ wfMus[i].wBitsPerSample = 8 * head.blockAlign / (head.samplesPerSec * head.channels);
+ wfMus[i].wf.nBlockAlign = wfMus[i].wf.nChannels * wfMus[i].wBitsPerSample / 8;
+ wfMus[i].wf.nAvgBytesPerSec = wfMus[i].wf.nSamplesPerSec * wfMus[i].wf.nBlockAlign;
+
+
+ // Reset the sample format and size
+ memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC));
+ dsbdMus[i].dwSize = sizeof(DSBUFFERDESC);
+// dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbdMus[i].dwBufferBytes = 3 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds
+ dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i];
+
+ // Create the sound effect sample buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL);
+ if (hr == DS_OK)
+ {
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(lpDsbMus[i]);
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+
+ // Fill the speech buffer with data
+ bytes = fread(lpv1, 1, dwBytes1, fpMus[i]);
+// memcpy((uint8 *) lpv1, (uint8 *) wavData + sizeof(wavHeader), dwBytes1);
+
+ // Unlock the buffer now that we've filled it
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // Modify the volume according to the master volume and music mute state
+ if (musicMuted)
+ v0 = v1 = 0;
+ else
+ {
+ v0 = volMusic[0];
+ v1 = volMusic[1];
+ }
+
+ if (v0 > v1)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]);
+ }
+ else
+ {
+ if (v1 > v0)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]);
+ }
+ else
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], 0);
+ }
+ }
+
+
+ // Start the sound effect playing
+ IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING);
+
+ musStreaming[i] = 1;
+ musCounter[i] = 250;
+ strcpy(musFilename[i], filename);
+
+ // and exit the function.
+ }
+ else
+ {
+// Pdebug("Failed to lock sound buffer upon creation - (%d)", hr & 0x0000ffff);
+// DirectSoundDebug("Error - ", hr);
+ fclose(fpMus[i]);
+ return(RDERR_LOCKFAILED);
+ }
+ }
+ else
+ {
+// Pdebug("Failed to create sound buffer - (%d)", hr & 0x0000ffff);
+// Pdebug("Error - ", hr);
+ fclose(fpMus[i]);
+ return(RDERR_CREATESOUNDBUFFER);
+ }
+ }
+ else if (musStreaming[0] + musStreaming[1] == 1)
+ {
+
+ i = musStreaming[0];
+ musLooping[i] = looping;
+
+ if (!musFading[1-i])
+ StartMusicFadeDown(1 - i);
+
+ fpMus[i] = fopen(filename, "rb");
+ if (fpMus[i] == NULL)
+ return(RDERR_INVALIDFILENAME);
+
+ fread(&head, sizeof(_wavHeader), 1, fpMus[i]);
+ streamCursor[i] = 0;
+
+
+ memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT));
+ wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM;
+ wfMus[i].wf.nChannels = head.channels;
+ wfMus[i].wf.nSamplesPerSec = head.samplesPerSec;
+ wfMus[i].wBitsPerSample = 8 * head.blockAlign / (head.samplesPerSec * head.channels);
+ wfMus[i].wf.nBlockAlign = wfMus[i].wf.nChannels * wfMus[i].wBitsPerSample / 8;
+ wfMus[i].wf.nAvgBytesPerSec = wfMus[i].wf.nSamplesPerSec * wfMus[i].wf.nBlockAlign;
+
+
+ // Reset the sample format and size
+ memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC));
+ dsbdMus[i].dwSize = sizeof(DSBUFFERDESC);
+// dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbdMus[i].dwBufferBytes = 6 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds
+ dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i];
+
+ // Create the sound effect sample buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL);
+ if (hr == DS_OK)
+ {
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(lpDsbMus[i]);
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+
+ // Fill the speech buffer with data
+ bytes = fread(lpv1, 1, dwBytes1, fpMus[i]);
+// Pdebug("Read %d bytes\n", bytes);
+// memcpy((uint8 *) lpv1, (uint8 *) wavData + sizeof(_wavHeader), dwBytes1);
+
+ // Unlock the buffer now that we've filled it
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // Modify the volume according to the master volume and music mute state
+ if (musicMuted)
+ v0 = v1 = 0;
+ else
+ {
+ v0 = volMusic[0];
+ v1 = volMusic[1];
+ }
+
+
+ if (v0 > v1)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]);
+ }
+ else
+ {
+ if (v1 > v0)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]);
+ }
+ else
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], 0);
+ }
+ }
+
+
+ // Start the sound effect playing
+ IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING);
+
+ musStreaming[i] = 1;
+ musCounter[i] = 250;
+ strcpy(musFilename[i], filename);
+
+ }
+ else
+ {
+// Pdebug("Failed to lock sound buffer upon creation - (%d)", hr & 0x0000ffff);
+// DirectSoundDebug("Error - ", hr);
+ fclose(fpMus[i]);
+ return(RDERR_LOCKFAILED);
+ }
+ }
+ else
+ {
+// Pdebug("Failed to create sound buffer - (%d)", hr & 0x0000ffff);
+// Pdebug("Error - ", hr);
+ fclose(fpMus[i]);
+ return(RDERR_CREATESOUNDBUFFER);
+ }
+
+ }
+*/
+ return(RD_OK);
+}
+
+
+void UpdateSampleStreaming(void)
+
+{
+ warning("stub UpdateSampleStreaming");
+/*
+
+ int32 i;
+ int32 v0, v1;
+ int32 readLen;
+ int32 len;
+ int32 readCursor, writeCursor;
+ int32 dwBytes1, dwBytes2;
+ LPVOID lpv1, lpv2;
+ HRESULT hr;
+
+
+ for (i=0; i<MAXMUS; i++)
+ {
+ if (musStreaming[i])
+ {
+ if (musFading[i])
+ {
+ if (musFading[i] < 0)
+ {
+ if (++musFading[i] == 0)
+ {
+ IDirectSoundBuffer_Stop(lpDsbMus[i]);
+ IDirectSoundBuffer_Release(lpDsbMus[i]);
+ musStreaming[i] = 0;
+ }
+ else
+ {
+ // Modify the volume according to the master volume and music mute state
+ if (musicMuted)
+ v0 = v1 = 0;
+ else
+ {
+ v0 = (volMusic[0] * (0 - musFading[i]) / 16);
+ v1 = (volMusic[1] * (0 - musFading[i]) / 16);
+ }
+
+ if (v0 > v1)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]);
+ }
+ else
+ {
+ if (v1 > v0)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]);
+ }
+ else
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], 0);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+
+ if (IDirectSoundBuffer_GetCurrentPosition(lpDsbMus[i], &readCursor, &writeCursor) != DS_OK)
+ {
+// Pdebug ("Stopping sample %d cos cant get position", i);
+ IDirectSoundBuffer_Stop(lpDsbMus[i]);
+ }
+
+
+ len = readCursor - streamCursor[i];
+ if (len < 0)
+ {
+ len += dsbdMus[i].dwBufferBytes;
+ }
+ if (len > 0)
+ {
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(lpDsbMus[i]);
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+ streamCursor[i] += len;
+ if (streamCursor[i] >= (int32) dsbdMus[i].dwBufferBytes)
+ streamCursor[i] -= dsbdMus[i].dwBufferBytes;
+
+ if (len > dwBytes1)
+ {
+ readLen = fread(lpv1, 1, dwBytes1, fpMus[i]);
+ if (readLen == dwBytes1)
+ {
+ readLen = fread(lpv2, 1, dwBytes2, fpMus[i]);
+ if (readLen != dwBytes2)
+ {
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+ StartMusicFadeDown(i);
+ if (musLooping[i])
+ {
+ StreamMusic(musFilename[i], musLooping[i]);
+ }
+ }
+ else
+ {
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+ }
+ }
+ else
+ {
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+ StartMusicFadeDown(i);
+ if (musLooping[i])
+ {
+ StreamMusic(musFilename[i], musLooping[i]);
+ }
+ }
+ }
+ else
+ {
+ readLen = fread(lpv1, 1, len, fpMus[i]);
+ if (readLen != len)
+ {
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+ StartMusicFadeDown(i);
+ if (musLooping[i])
+ {
+ StreamMusic(musFilename[i], musLooping[i]);
+ }
+ }
+ else
+ {
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+ }
+ }
+ }
+// else
+// {
+// DirectSoundDebug("Failed to lock sound buffer to write bytes", hr);
+// Pdebug("Stream cursor %d", streamCursor[i]);
+// Pdebug("len %d", len);
+// }
+ }
+ //}
+ }
+ }
+ }
+*/
+}
+
+
+
+int32 StreamCompMusic(const char *filename, uint32 musicId, int32 looping)
+{
+ warning("stub StreamCompMusic( %s, %d, %d )", filename, musicId, looping);
+/*
+ HRESULT hr;
+ LPVOID lpv1, lpv2;
+ DWORD dwBytes1, dwBytes2;
+ uint32 i,j;
+ int32 v0, v1;
+ uint16 *data16;
+ uint8 *data8;
+
+ // Do not allow compressed and uncompressed music to be streamed at the same time.
+ if (compressedMusic == 2)
+ return (RDERR_FXFUCKED);
+
+ compressedMusic = 1;
+
+ if (musStreaming[0] + musStreaming[1] == 0) // No music streaming at present.
+ {
+ i = 0;
+
+ musLooping[i] = looping; // Save looping info
+ strcpy(musFilename[i], filename); // And tune id's
+ musId[i] = musicId;
+
+ if (IsMusicMute()) // Don't start streaming if the volume is off.
+ return (RD_OK);
+
+ if (!fpMus[0])
+ fpMus[0] = fopen(filename, "rb"); // Always use fpMus[0] (all music in one cluster) musFilePos[i] for different pieces of music.
+ if (fpMus[0] == NULL)
+ return(RDERR_INVALIDFILENAME);
+
+ if (fseek(fpMus[0], (musicId+1)*8, SEEK_SET)) // Seek to music index
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_READERROR);
+ }
+
+ if (fread(&musFilePos[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music index
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_READERROR);
+ }
+
+ if (fread(&musEnd[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music length
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_READERROR);
+ }
+
+ if (!musEnd[i] || !musFilePos[i]) // Check that music is valid (has length & offset)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_INVALIDID);
+ }
+
+ musEnd[i] += musFilePos[i]; // Calculate the file position of the end of the music
+
+ streamCursor[i] = 0; // Reset streaming cursor and store looping flag
+
+ memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT)); // Set up wave format (no headers in cluster)
+ wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM;
+ wfMus[i].wf.nChannels = 1;
+ wfMus[i].wf.nSamplesPerSec = 22050;
+ wfMus[i].wBitsPerSample = 16;
+ wfMus[i].wf.nBlockAlign = 2;
+ wfMus[i].wf.nAvgBytesPerSec = 44100;
+
+ // Reset the sample format and size
+ memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC));
+ dsbdMus[i].dwSize = sizeof(DSBUFFERDESC);
+// dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbdMus[i].dwBufferBytes = 3 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds
+ dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i];
+
+ // Create a temporary buffer
+ if ((data8 = malloc(dsbdMus[i].dwBufferBytes/2)) == NULL) // Allocate a compressed data buffer
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // Seek to start of the compressed music
+ if (fseek(fpMus[0], musFilePos[i], SEEK_SET))
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ free(data8);
+ return (RDERR_INVALIDID);
+ }
+
+ // Read the compressed data in to the buffer
+ if (fread(data8, sizeof(uint8), dsbdMus[i].dwBufferBytes/2, fpMus[0]) != dsbdMus[i].dwBufferBytes/2)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ free(data8);
+ return (RDERR_INVALIDID);
+ }
+
+ // Store the current position in the file for future streaming
+ musFilePos[i] = ftell(fpMus[0]);
+
+ // Create the music buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL);
+ if (hr == DS_OK)
+ {
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(lpDsbMus[i]);
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+ // decompress the music into the music buffer.
+ data16 = (uint16*)lpv1;
+
+ data16[0] = *((int16*)data8); // First sample value
+ j=1;
+
+ while (j<(dwBytes1/2)-1)
+ {
+ if (GetCompressedSign(data8[j+1]))
+ data16[j] = data16[j-1] - (GetCompressedAmplitude(data8[j+1])<<GetCompressedShift(data8[j+1]));
+ else
+ data16[j] = data16[j-1] + (GetCompressedAmplitude(data8[j+1])<<GetCompressedShift(data8[j+1]));
+ j++;
+ }
+
+ // Never need to fill lpv2 because we started at the begining of the sound buffer
+
+ // Store the value of the last sample ready for next batch of decompression
+ musLastSample[i] = data16[j-1];
+
+ // Free the decompression buffer and unlock the buffer now that we've filled it
+ free(data8);
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // Modify the volume according to the master volume and music mute state
+ if (musicMuted)
+ v0 = v1 = 0;
+ else
+ {
+ v0 = volMusic[0];
+ v1 = volMusic[1];
+ }
+
+ if (v0 > v1)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]);
+ }
+ else
+ {
+ if (v1 > v0)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]);
+ }
+ else
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], 0);
+ }
+ }
+
+
+ // Start the sound effect playing
+ IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING);
+
+ // Recorder some last variables
+ musStreaming[i] = 1;
+ musCounter[i] = 250;
+
+ // and exit the function.
+ }
+ else
+ {
+ // Opps Failed to lock the sound buffer
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return(RDERR_LOCKFAILED);
+ }
+ }
+ else
+ {
+ // Opps Failed to create the sound buffer
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return(RDERR_CREATESOUNDBUFFER);
+ }
+ }
+ else
+ {
+ if (musStreaming[0] + musStreaming[1] == 2) // Both streams in use, try to find a fading stream
+ {
+ if (musFading[0])
+ i = 0;
+ else
+ i = 1;
+
+ musFading[i] = 0;
+ IDirectSoundBuffer_Stop(lpDsbMus[i]);
+ IDirectSoundBuffer_Release(lpDsbMus[i]);
+ musStreaming[i] = 0;
+ }
+
+ if (musStreaming[0] + musStreaming[1] == 1) // Some music is already streaming
+ {
+ i = musStreaming[0]; // Set i to the free channel
+
+ musLooping[i] = looping; // Save looping info
+ strcpy(musFilename[i], filename); // And tune id's
+ musId[i] = musicId;
+
+ if (IsMusicMute()) // Don't start streaming if the volume is off.
+ return (RD_OK);
+
+ if (!fpMus[0])
+ fpMus[0] = fopen(filename, "rb"); // Always use fpMus[0] (all music in one cluster) musFilePos[i] for different pieces of music.
+ if (fpMus[0] == NULL)
+ return(RDERR_INVALIDFILENAME);
+
+
+ if (!musFading[1-i]) // Start other music stream fading out
+ musFading[1 - i] = -16;
+
+ streamCursor[i] = 0; // Reset the streaming cursor for this sample
+
+ if (fseek(fpMus[0], (musicId+1)*8, SEEK_SET)) // Seek to music index
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_READERROR);
+ }
+
+ if (fread(&musFilePos[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music index
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_READERROR);
+ }
+
+ if (fread(&musEnd[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music length
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_READERROR);
+ }
+
+ if (!musEnd[i] || !musFilePos[i]) // Check that music is valid (has length & offset)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return (RDERR_INVALIDID);
+ }
+
+ musEnd[i] += musFilePos[i]; // Calculate the file position of the end of the music
+
+ memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT)); // Set up the music format info
+ wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM;
+ wfMus[i].wf.nChannels = 1;
+ wfMus[i].wf.nSamplesPerSec = 22050;
+ wfMus[i].wBitsPerSample = 16;
+ wfMus[i].wf.nBlockAlign = 2;
+ wfMus[i].wf.nAvgBytesPerSec = 44100;
+
+ // Reset the sample format and size
+ memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC));
+ dsbdMus[i].dwSize = sizeof(DSBUFFERDESC);
+// dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT;
+ dsbdMus[i].dwBufferBytes = 3 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds
+ dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i];
+
+ // Allocate a compressed data buffer
+ if ((data8 = malloc(dsbdMus[i].dwBufferBytes/2)) == NULL)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // Seek to start of the compressed music
+ if (fseek(fpMus[0], musFilePos[i], SEEK_SET))
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ free(data8);
+ return (RDERR_INVALIDID);
+ }
+
+ // Read the compressed data in to the buffer
+ if (fread(data8, sizeof(uint8), dsbdMus[i].dwBufferBytes/2, fpMus[0]) != dsbdMus[i].dwBufferBytes/2)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ free(data8);
+ return (RDERR_INVALIDID);
+ }
+
+ // Store the current position in the file for future streaming
+ musFilePos[i] = ftell(fpMus[0]);
+
+ // Create the sound effect sample buffer
+ hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL);
+ if (hr == DS_OK)
+ {
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(lpDsbMus[i]);
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+
+ // decompress the music into the music buffer.
+ data16 = (uint16*)lpv1;
+
+ data16[0] = *((int16*)data8); // First sample value
+ j=1;
+
+ while (j<(dwBytes1/2)-1)
+ {
+ if (GetCompressedSign(data8[j+1]))
+ data16[j] = data16[j-1] - (GetCompressedAmplitude(data8[j+1])<<GetCompressedShift(data8[j+1]));
+ else
+ data16[j] = data16[j-1] + (GetCompressedAmplitude(data8[j+1])<<GetCompressedShift(data8[j+1]));
+ j++;
+ }
+
+ // Never need to fill lpv2 because we started at the begining of the sound buffer
+
+ // Store the value of the last sample ready for next batch of decompression
+ musLastSample[i] = data16[j-1];
+
+ // Free the compressiong buffer and unlock the buffer now that we've filled it
+ free(data8);
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // Modify the volume according to the master volume and music mute state
+ if (musicMuted)
+ v0 = v1 = 0;
+ else
+ {
+ v0 = volMusic[0];
+ v1 = volMusic[1];
+ }
+
+
+ if (v0 > v1)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]);
+ }
+ else
+ {
+ if (v1 > v0)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]);
+ }
+ else
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], 0);
+ }
+ }
+
+
+ // Start the sound effect playing
+ IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING);
+
+ // Record the last variables for streaming and looping
+ musStreaming[i] = 1;
+ musCounter[i] = 250;
+ }
+ else
+ {
+ // Opps failed to lock the sound buffer
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return(RDERR_LOCKFAILED);
+ }
+ }
+ else
+ {
+ // Opps failed to create the sound buffer
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ return(RDERR_CREATESOUNDBUFFER);
+ }
+ }
+ }
+*/
+ return(RD_OK);
+}
+
+
+void UpdateCompSampleStreaming(void)
+{
+ warning("stub UpdateCompSampleStreaming");
+/*
+
+ uint32 i,j,k;
+ int32 v0, v1;
+ int32 len;
+ int32 readCursor, writeCursor;
+ int32 dwBytes1, dwBytes2;
+ LPVOID lpv1, lpv2;
+ HRESULT hr;
+ uint16 *data16;
+ uint8 *data8;
+ int fade;
+
+
+ for (i=0; i<MAXMUS; i++)
+ {
+ if (musStreaming[i])
+ {
+ if (musFading[i])
+ {
+ if (musFading[i] < 0)
+ {
+ if (++musFading[i] == 0)
+ {
+ IDirectSoundBuffer_Stop(lpDsbMus[i]);
+ IDirectSoundBuffer_Release(lpDsbMus[i]);
+ musStreaming[i] = 0;
+ musLooping[i] = 0;
+ }
+ else
+ {
+ // Modify the volume according to the master volume and music mute state
+ if (musicMuted)
+ v0 = v1 = 0;
+ else
+ {
+ v0 = (volMusic[0] * (0 - musFading[i]) / 16);
+ v1 = (volMusic[1] * (0 - musFading[i]) / 16);
+ }
+
+ if (v0 > v1)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]);
+ }
+ else
+ {
+ if (v1 > v0)
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]);
+ }
+ else
+ {
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]);
+ IDirectSoundBuffer_SetPan(lpDsbMus[i], 0);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (IDirectSoundBuffer_GetCurrentPosition(lpDsbMus[i], &readCursor, &writeCursor) != DS_OK)
+ {
+ // Failed to get read and write positions
+ IDirectSoundBuffer_Stop(lpDsbMus[i]);
+ }
+
+
+ // Caluculate the amount of data to load into the sound buffer
+ len = readCursor - streamCursor[i];
+ if (len < 0)
+ {
+ len += dsbdMus[i].dwBufferBytes; // Wrap around !
+ }
+
+ // Reduce length if it requires reading past the end of the music
+ if (musFilePos[i]+len >= musEnd[i])
+ {
+ len = musEnd[i] - musFilePos[i];
+ fade = 1; // End of music reaced so we'll need to fade and repeat
+ }
+ else
+ fade = 0;
+
+ if (len > 0)
+ {
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ if (hr == DSERR_BUFFERLOST)
+ {
+ IDirectSoundBuffer_Restore(lpDsbMus[i]);
+ hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0);
+ }
+
+ if (hr == DS_OK)
+ {
+ streamCursor[i] += len;
+ if (streamCursor[i] >= (int32) dsbdMus[i].dwBufferBytes)
+ streamCursor[i] -= dsbdMus[i].dwBufferBytes;
+
+ // Allocate a compressed data buffer
+ if ((data8 = malloc(len/2)) == NULL)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ musFading[i] = -16;
+ }
+
+ // Seek to update position of compressed music when neccassary (probably never occurs)
+ if (ftell(fpMus[0]) != musFilePos[i])
+ fseek(fpMus[0], musFilePos[i], SEEK_SET);
+
+ // Read the compressed data in to the buffer
+ if (fread(data8, sizeof(uint8), len/2, fpMus[0]) != (size_t)len/2)
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ free(data8);
+ musFading[i] = -16;
+ return;
+ }
+
+ // Update the current position in the file for future streaming
+ musFilePos[i] = ftell(fpMus[0]);
+
+ // decompress the music into the music buffer.
+ data16 = (uint16*)lpv1;
+
+ // Decompress the first byte using the last decompressed sample
+ if (GetCompressedSign(data8[0]))
+ data16[0] = musLastSample[i] - (GetCompressedAmplitude(data8[0])<<GetCompressedShift(data8[0]));
+ else
+ data16[0] = musLastSample[i] + (GetCompressedAmplitude(data8[0])<<GetCompressedShift(data8[0]));
+
+ j = 1;
+
+ // Decompress the rest of lpv1
+ while (j<(uint32)dwBytes1/2)
+ {
+ if (GetCompressedSign(data8[j]))
+ data16[j] = data16[j-1] - (GetCompressedAmplitude(data8[j])<<GetCompressedShift(data8[j]));
+ else
+ data16[j] = data16[j-1] + (GetCompressedAmplitude(data8[j])<<GetCompressedShift(data8[j]));
+ j++;
+ }
+
+ // Store the value of the last sample ready for next batch of decompression
+ musLastSample[i] = data16[j-1];
+
+ if (dwBytes1 < len) // The buffer has wrapped so we need to decompress to lpv2 as well
+ {
+ data16 = (uint16*)lpv2;
+
+ // Decompress first sample int lpv2 from lastsample in lpv1
+ if (GetCompressedSign(data8[j]))
+ data16[0] = musLastSample[i] - (GetCompressedAmplitude(data8[j])<<GetCompressedShift(data8[j]));
+ else
+ data16[0] = musLastSample[i] + (GetCompressedAmplitude(data8[j])<<GetCompressedShift(data8[j]));
+
+ j++;
+ k = 1;
+
+ // Decompress the rest of lpv2
+ while (k<(uint32)dwBytes2/2)
+ {
+ if (GetCompressedSign(data8[j]))
+ data16[k] = data16[k-1] - (GetCompressedAmplitude(data8[j])<<GetCompressedShift(data8[j]));
+ else
+ data16[k] = data16[k-1] + (GetCompressedAmplitude(data8[j])<<GetCompressedShift(data8[j]));
+ j++;
+ k++;
+ }
+
+ // Store the value of the last sample ready for next batch of decompression
+ musLastSample[i] = data16[k-1];
+ }
+
+ // Free the compressed data buffer and unlock the sound buffer.
+ free(data8);
+ IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2);
+
+ // End of the music so we need to start fading and start the music again
+ if (fade)
+ {
+ musFading[i] = -16; // Fade the old music
+
+ // Close the music cluster if it's open
+ if (fpMus[0])
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ }
+
+ // Loop if neccassary
+ if (musLooping[i])
+ StreamCompMusic(musFilename[i], musId[i], musLooping[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+ DipMusic();
+*/
+}
+
+int32 DipMusic()
+{
+ warning("stub DipMusic");
+/*
+ int32 len;
+ int32 readCursor, writeCursor;
+ int32 dwBytes1, dwBytes2;
+ int16 *sample;
+ int32 total = 0;
+ int32 i;
+ int32 status;
+ LPVOID lpv1, lpv2;
+ HRESULT hr = DS_OK;
+ LPDIRECTSOUNDBUFFER dsbMusic = NULL;
+
+ int32 currentMusicVol = musicVolTable[volMusic[0]];
+ int32 minMusicVol;
+
+ // Find which music buffer is currently playing
+ for (i = 0; i<MAXMUS && !dsbMusic; i++)
+ {
+ if (musStreaming[i] && musFading[i] == 0)
+ dsbMusic = lpDsbMus[i];
+ }
+
+ if ((!musicMuted) && dsbMusic && (!speechMuted) && (volMusic[0]>2))
+ {
+ minMusicVol = musicVolTable[volMusic[0] - 3];
+
+ if (speechStatus)
+ {
+ IDirectSoundBuffer_GetStatus(dsbSpeech, &status);
+ if ((hr = IDirectSoundBuffer_GetCurrentPosition(dsbMusic, &readCursor, &writeCursor)) != DS_OK)
+ return hr;
+
+ len = 44100 / 12 ;// 12th of a second
+
+ if ((hr = IDirectSoundBuffer_Lock(dsbMusic, readCursor, len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0)) != DS_OK)
+ return hr;
+
+ for (i = 0, sample = (int16*)lpv1; sample<(int16*)((int8*)lpv1+dwBytes1); sample+= 30, i++) // 60 samples
+ {
+ if (*sample>0)
+ total += *sample;
+ else
+ total -= *sample;
+ }
+
+ total /= i;
+
+ total = minMusicVol + ( ( (currentMusicVol - minMusicVol) * total ) / 8000);
+
+ if (total > currentMusicVol)
+ total = currentMusicVol;
+
+ IDirectSoundBuffer_SetVolume(dsbMusic, total);
+
+ IDirectSoundBuffer_Unlock(dsbMusic,lpv1,dwBytes1,lpv2,dwBytes2);
+ }
+ else
+ {
+ IDirectSoundBuffer_GetVolume(dsbMusic, &total);
+ total += 50;
+ if (total > currentMusicVol)
+ total = currentMusicVol;
+
+ IDirectSoundBuffer_SetVolume(dsbMusic, total);
+ }
+ }
+
+ return (hr);
+*/
+ return RD_OK;
+}
+
+int32 MusicTimeRemaining()
+{
+ warning("stub MusicTimeRemaaining");
+/*
+ int32 writeCursor;
+ int32 i;
+ int32 readCursor;
+
+ for (i=0; i<MAXMUS && !musStreaming[i]; i++)
+ {
+ // this is meant to be empty! (James19aug97)
+ }
+
+ if (i == MAXMUS)
+ return 0;
+
+
+ if ((IDirectSoundBuffer_GetCurrentPosition(lpDsbMus[i], &readCursor, &writeCursor)) != DS_OK)
+ return 0;
+
+ return (((132300-readCursor)/2 + (musEnd[i] - musFilePos[i])) / 22050);
+*/
+ return 0;
+}
+
+
+
+void StopMusic(void)
+{
+ int32 i;
+
+ switch (compressedMusic)
+ {
+ case 1: // compressed music streaming
+ for (i = 0; i<MAXMUS; i++)
+ {
+ if (musStreaming[i])
+ musFading[i] = -16;
+ else
+ // If the music is muted, make sure the tune doesn't restart.
+ musLooping[i] = 0;
+ }
+
+ if (fpMus[0])
+ {
+ fclose(fpMus[0]);
+ fpMus[0] = 0;
+ }
+ break;
+ case 2:
+ for (i = 0; i<MAXMUS; i++)
+ {
+ if (musStreaming[i])
+ StartMusicFadeDown(i);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+int32 PauseMusic(void)
+{
+ warning("stub PauseMusic");
+/*
+ int32 i;
+
+ if (soundOn)
+ {
+ for (i=0; i<2; i++)
+ {
+ if (musStreaming[i])
+ {
+ musicPaused[i] = TRUE;
+
+ if (IDirectSoundBuffer_Stop(lpDsbMus[i]) != RD_OK)
+ return(RDERR_FXFUCKED);
+ }
+ else
+ {
+ musicPaused[i] = FALSE;
+ }
+ }
+ }
+*/
+ return(RD_OK);
+}
+
+int32 UnpauseMusic(void)
+{
+ warning("stub UnpauseMusic");
+/*
+
+ int32 i;
+
+ if (soundOn)
+ {
+ for (i=0; i<2; i++)
+ {
+ if (musicPaused[i])
+ {
+ if (IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING) != RD_OK)
+ return(RDERR_FXFUCKED);
+
+ musicPaused[i] = FALSE;
+ }
+ }
+ }
+*/
+ return(RD_OK);
+}
+
+
+void SetMusicVolume(uint8 volume)
+{
+ warning("stub SetMusicVolume( %d )", volume);
+/*
+ int32 i;
+ for (i = 0; i<MAXMUS; i++)
+ {
+ volMusic[i] = volume;
+ if (musStreaming[i] && !musFading[i] && !musicMuted)
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[volume]);
+ }
+*/
+}
+
+
+uint8 GetMusicVolume()
+{
+ return volMusic[0];
+}
+
+
+void MuteMusic(uint8 mute)
+{
+ warning("stub MuteMusic( %d )", mute);
+/*
+ int32 i;
+
+ musicMuted = mute;
+
+ for (i = 0; i<MAXMUS; i++)
+ {
+ if (!mute)
+ {
+ if (!musStreaming[i] && musLooping[i])
+ StreamCompMusic(musFilename[i], musId[i], musLooping[i]);
+ }
+
+ if (musStreaming[i] && !musFading[i])
+ {
+ if (mute)
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[0]);
+ else
+ IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[volMusic[i]]);
+ }
+ }
+*/
+}
+
+
+uint8 IsMusicMute(void)
+{
+ return (musicMuted);
+}
+
+
+
+void GetSoundStatus(_drvSoundStatus *s)
+{
+ int i;
+
+// s->hwnd = hwnd;
+// s->lpDS = lpDS;
+// s->dsbPrimary = dsbPrimary;
+// s->dsbSpeech = dsbSpeech;
+ s->soundOn = soundOn;
+ s->speechStatus = speechStatus;
+ s->fxPaused = fxPaused;
+ s->speechPaused = speechPaused;
+ s->speechVol = speechVol;
+ s->fxVol = fxVol;
+ s->speechMuted = speechMuted;
+ s->fxMuted = fxMuted;
+ s->compressedMusic = compressedMusic;
+ s->musicMuted = musicMuted;
+
+ memcpy(s->fxId, fxId, sizeof(int32) * MAXFX);
+ memcpy(s->fxCached, fxCached, sizeof(uint8) * MAXFX);
+// memcpy(s->dsbFx, dsbFx, sizeof(LPDIRECTSOUNDBUFFER) * MAXFX);
+ memcpy(s->fxiPaused, fxiPaused, sizeof(uint8) * MAXFX);
+ memcpy(s->fxLooped, fxLooped, sizeof(uint8) * MAXFX);
+ memcpy(s->musStreaming, musStreaming, sizeof(int16) * MAXMUS);
+ memcpy(s->musicPaused, musicPaused, sizeof(int16) * MAXMUS);
+ memcpy(s->musCounter, musCounter, sizeof(int16) * MAXMUS);
+ memcpy(s->musFading, musFading, sizeof(int16) * MAXMUS);
+ memcpy(s->musLooping, musLooping, sizeof(int16) * MAXMUS);
+ memcpy(s->musLastSample,musLastSample, sizeof(int16) * MAXMUS);
+ memcpy(s->streamCursor, streamCursor, sizeof(int32) * MAXMUS);
+ memcpy(s->musFilePos, musFilePos, sizeof(int32) * MAXMUS);
+ memcpy(s->musEnd, musEnd, sizeof(int32) * MAXMUS);
+ memcpy(s->musId, musId, sizeof(uint32) * MAXMUS);
+ memcpy(s->volMusic, volMusic, sizeof(uint32) * 2);
+// memcpy(s->dsbdMus, dsbdMus, sizeof(DSBUFFERDESC) * MAXMUS);
+// memcpy(s->lpDsbMus, lpDsbMus, sizeof(LPDIRECTSOUNDBUFFER) * MAXMUS);
+ memcpy(s->fpMus, fpMus, sizeof(FILE*) * MAXMUS);
+// memcpy(s->wfMus, wfMus, sizeof(PCMWAVEFORMAT) * MAXMUS);
+
+ for (i = 0; i<MAXMUS; i++)
+ memcpy(s->musFilename[i], musFilename[i], sizeof(char) * 256);
+}
+
+
+void SetSoundStatus(_drvSoundStatus *s)
+{
+ int i;
+
+// hwnd = s->hwnd;
+// lpDS = s->lpDS;
+// dsbPrimary = s->dsbPrimary;
+// dsbSpeech = s->dsbSpeech;
+ soundOn = s->soundOn;
+ speechStatus = s->speechStatus;
+ fxPaused = s->fxPaused;
+ speechPaused = s->speechPaused;
+ speechVol = s->speechVol;
+ fxVol = s->fxVol;
+ speechMuted = s->speechMuted;
+ fxMuted = s->fxMuted;
+ compressedMusic = s->compressedMusic;
+ musicMuted = s->musicMuted;
+
+ memcpy(fxId, s->fxId, sizeof(int32) * MAXFX);
+ memcpy(fxCached, s->fxCached, sizeof(uint8) * MAXFX);
+// memcpy(dsbFx, s->dsbFx, sizeof(LPDIRECTSOUNDBUFFER) * MAXFX);
+ memcpy(fxiPaused, s->fxiPaused, sizeof(uint8) * MAXFX);
+ memcpy(fxLooped, s->fxLooped, sizeof(uint8) * MAXFX);
+ memcpy(musStreaming, s->musStreaming, sizeof(int16) * MAXMUS);
+ memcpy(musicPaused, s->musicPaused, sizeof(int16) * MAXMUS);
+ memcpy(musCounter, s->musCounter, sizeof(int16) * MAXMUS);
+ memcpy(musFading, s->musFading, sizeof(int16) * MAXMUS);
+ memcpy(musLooping, s->musLooping, sizeof(int16) * MAXMUS);
+ memcpy(musLastSample,s->musLastSample, sizeof(int16) * MAXMUS);
+ memcpy(streamCursor, s->streamCursor, sizeof(int32) * MAXMUS);
+ memcpy(musFilePos, s->musFilePos, sizeof(int32) * MAXMUS);
+ memcpy(musEnd, s->musEnd, sizeof(int32) * MAXMUS);
+ memcpy(musId, s->musId, sizeof(uint32) * MAXMUS);
+ memcpy(volMusic, s->volMusic, sizeof(uint32) * 2);
+// memcpy(dsbdMus, s->dsbdMus, sizeof(DSBUFFERDESC) * MAXMUS);
+// memcpy(lpDsbMus, s->lpDsbMus, sizeof(LPDIRECTSOUNDBUFFER) * MAXMUS);
+// memcpy(fpMus, s->fpMus, sizeof(FILE*) * MAXMUS);
+// memcpy(wfMus, s->wfMus, sizeof(PCMWAVEFORMAT) * MAXMUS);
+
+ for (i = 0; i<MAXMUS; i++)
+ memcpy(musFilename[i], s->musFilename[i], sizeof(char) * 256);
+}
+
diff --git a/sword2/driver/d_sound.h b/sword2/driver/d_sound.h
new file mode 100644
index 0000000000..5281cf01c9
--- /dev/null
+++ b/sword2/driver/d_sound.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : d_sound.h
+// Created : 5th December 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 05-Dec-96 PRP Interface to the DirectSound driver functions
+//
+// Summary : This include file defines links to all data which is
+// defined in the d_sound.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef D_SOUND_H
+#define D_SOUND_H
+
+extern void FxServer(void);
+
+#endif
diff --git a/sword2/driver/ddutil.h b/sword2/driver/ddutil.h
new file mode 100644
index 0000000000..f6976eca15
--- /dev/null
+++ b/sword2/driver/ddutil.h
@@ -0,0 +1,159 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-2001 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLeft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/sword2/driver/driver96.h b/sword2/driver/driver96.h
new file mode 100644
index 0000000000..87c40c3fbd
--- /dev/null
+++ b/sword2/driver/driver96.h
@@ -0,0 +1,1665 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : driver96.h
+// Created : 6th August 1996
+// By : P.R.Porter
+//
+// Summary : This include file defines all interfaces to the Revolution
+// driver96 system. All game code which requires driver
+// functions should simlply include this file.
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 12-Sep-96 PRP Initial drivers include file - with utypes.h!
+//
+// 1.1 17-Sep-96 PRP screenWide and screenDeep made available to the
+// game engine.
+//
+// 1.2 18-Sep-96 PRP Mouse functions added. The _mouseEvent struct
+// is made visible to the game engine, and the
+// function prototype for getting a mouse event
+// from the queue has been added. Also, filename
+// in macro for driver error reporting is fixed.
+//
+// 1.3 19-Sep-96 PRP Interface to keyboard functions added. Also,
+// removed references to bool which is not
+// allowed by the cpp compiler.
+//
+// 1.4 19-Sep-96 PRP Fix definition of MouseEvent() and make the
+// rderror variable static.
+//
+// 1.5 20-Sep-96 PRP Added interface to console functions.
+//
+// 1.6 23-Sep-96 PRP Removed console functions from drivers!
+//
+// 1.7 25-Sep-96 PRP Added interface to sprite drawing functions.
+// RenderScreen changed so that the drawing offset
+// is not passed in. This is now calculated from
+// SetScrollTarget, and the number of frames we
+// are going to render in the next game cycle.
+//
+// 1.8 26-Sep-96 PRP Moved the screen drawing and scrolling code
+// to render.c for clarity. Changed the mouse
+// coordinates to be relative to the top left
+// corner of the game screen and removed the mouse
+// position from the log.
+//
+// 1.9 09-Oct-96 PRP Defined SOFTWARE_SCREEN_BUFFER in here so that
+// all of the drivers can use it, and the game
+// engine will know what's going on!
+//
+// 1.10 28-Oct-96 PRP DrawSprite has changed. There are now flags to
+// describe whether the sprite is compressed,
+// transparent or displayed from the top left
+// corner of the screen as opposed to the top left
+// corner of the background.
+//
+// 1.11 29-Oct-96 PRP Naming of RDSPR_DISPLAYALIGN fixed in header!
+//
+// 1.12 01-Nov-96 PRP Added compression type, RDSPR_SPRITECOMPRESSION,
+// and increased the size of the parameter passed
+// to DrawSprite so up to eight compression types
+// can be defined.
+// Added functions to mouse.c for animating mouse
+// pointers. Interface to functions put in here..
+//
+// 1.13 07-Nov-96 PRP Added RDERR_GOFULLSCREEN as a return error for
+// creating the primary surface on a screen
+// which is not in 8bpp mode. Also, made it so
+// sprite drawing is passed a structure with
+// all of the sprite parameters in, rather than
+// the individual values passed.
+// When setting up the screen display/resolution
+// you should now specify whether you want the
+// game to run in full screen mode or in a window.
+//
+// 1.14 15-Nov-96 PRP Added menubar code into drivers.
+//
+// 1.15 21-Nov-96 PRP Changed the interface to the DrawLine function.
+//
+// 1.16 25-Nov-96 PRP Added a function to set the Luggage animation.
+//
+// 1.17 25-Nov-96 PRP Added functions to palette.c which create
+// match tables, and match rgb values to palette
+// indeces - and new error messages
+//
+// 1.18 26-Nov-96 PRP Added error - RDERR_INVALIDSCALING which will
+// be used when sprites are drawn with a scaling
+// value outside of the range 0 .. s .. 512
+//
+// 1.19 29-Nov-96 PRP Added timing information to be referenced by
+// the game engine. Also implemented palette
+// fading with new functions added!
+//
+// 1.20 03-Dec-96 PRP Sound driver functions added. It is now
+// possible to play speech.
+//
+// 1.21 05-Dec-96 PRP SetPalette changed so that the palette can
+// be realized immediately or later when fading
+// is called.
+//
+// 1.22 05-Dec-96 PRP Added sound driver functions for dealing with
+// sound fx.
+//
+// 1.23 09-Dec-96 PRP Changed the UpdatePaletteMatchTable to take
+// a pointer rather than a filename.
+//
+// 1.24 19-Dec-96 PRP Changed the sound system functions to add
+// volume and pan position. Also, added a flag
+// to the fx player for looping.
+//
+// 1.25 27-Jan-97 PRP Changed the call to render parallax, to define
+// which layer is to be rendered. Also, added
+// the RDBLTFX_ equates for how the rendering
+// engine works. There are new functions to
+// initialise and close the background layers
+// which need to be called at the start and end
+// of a room.
+//
+// 1.26 10-Feb-97 PRP Changed the direct draw error reporting calls,
+// and added new return error codes.
+//
+// 1.27 11-Feb-97 PRP Added the blending value into the spriteInfo
+// structure.
+//
+// 1.28 12-Feb-97 PRP Added set and clear blt effects functions.
+//
+// 1.29 06-Mar-97 PRP Added error return code RDERR_LOCKFAILED for
+// failing to lock the front buffer when trying
+// to write a screen shot. Also, added definition
+// of _pcxHeader.
+//
+// 1.30 17-Mar-97 PRP Added RDFADE_BLACK as a return value for the
+// GetPaletteStatus() function.
+//
+// 1.31 18-Mar-97 PRP Added InitialiseRenderCycle() to be called
+// before the rendering loop is entered. This
+// resets the timers.
+//
+// 1.32 20-Mar-97 PRP Added reference to ResetRenderEngine() to be
+// called upon entry to the control panel.
+//
+// 1.33 24-Mar-97 PRP Added sprite drawing functions for hardware
+// utilisation.
+//
+// 1.34 24-Mar-97 PRP Added return code RDERR_SURFACELOST
+//
+// 1.35 01-Apr-97 PRP Added new sprite type RDSPR_RLE256FAST
+//
+// 1.36 04-Apr-97 PRP Changed the prototype for InitialiseWindow.
+//
+// 1.37 07-Apr-97 PRP Added function prototypes and error values
+// for the switching between the hardware and
+// software renderers.
+//
+// 1.38 07-Apr-97 PRP Added function prototypes and error values
+// for the shadow masking engine.
+//
+// 1.39 08-Apr-97 PRP Added reference to PlaySmacker()
+//
+// 1.40 09-Apr-97 PRP Added references to the functions which play music
+// streaming it from the CD.
+//
+// 1.41 10-Apr-97 PRP Added defines for mouse flashing or not. Also
+// changed function call to SetMouseAnim to
+// include this parameter.
+//
+// 1.42 11-Apr-97 PRP EraseSoftwareScreenBuffer added.
+//
+// 1.43 11-Apr-97 JEL In render.c changed EraseSoftwareRenderBuffer to EraseSoftwareScreenBuffer
+//
+// 1.44 11-Apr-97 CJR Added palCopy definition for use in game engine.
+//
+// 1.45 22-Apr-97 PRP Added decompression error return value.
+//
+// 1.46 28-Apr-97 PSJ Added members to _wavHeader structure.
+//
+// 1.47 21-May-97 PRP Added the _movieTextObject data structure. This will
+// be used in the call to PlaySmacker to define if there is any
+// text to be displayed and when.
+//
+// 1.48 21-May-97 PRP Fixed the pointer to the text sprite within the movie
+// text object structure.
+//
+// 1.49 22-May-97 JEL Fixed PlaySmacker for a movieTextObject parameter of NULL
+//
+// 1.50 29-May-97 PSJ Added the _drvStatus data structure. This will allow the
+// state of all the drivers globals to be passed between dlls,
+// exectuables and threads.
+//
+// 1.51 29-May-97 PSJ Added the _drvSoundStatus data structure and move _drvStatus to _drvDrawStatus.
+// This will allow the state of the drivers drawing globals and audio globals to
+// be passed between dlls, exectuables and threads.
+// Also included ddraw.h dsound.h and mmsystem.h in this file.
+//
+// 1.52 29-May-97 PRP Added reference to the DisableQuitKey function,
+// which removes the ability to press control-Q to quit
+// the game.
+//
+// 1.53 04-Jun-97 PRP Changed the funtion call to PlaySmacker. Now includes
+// a wav to lead out at the end of the smack file.
+//
+// 1.55 06-Jun-97 PSJ Added GetFxVolume and SetFxVolume for fx master volume control.
+// Added GetSpeechVolume and SetSpeechVolume for speech master volume.
+//
+// 1.56 09-Jun-97 PSJ Added GetMusicVolume and SetMusicVolume.
+//
+// 1.57 10-Jun-97 PSJ Added MuteMusic, MuteFx, MuteSpeech, IsMusicMute, IsFxMute and Is SpeechMute
+//
+// 1.58 12-Jun-97 PSJ Added PlayCompSpeech to load and play a compressed wave.
+//
+// 1.59 12-Jun-97 PSJ Added GetRenderType to return the type of rendering
+// currently being used.
+//
+// 1.60 13-Jun-97 PRP Added functions to set and clear shadow mask status.
+//
+// 1.61 26-Jun-97 PSJ Added AmISpeaking to check for lip syncing spots in the speech.
+// Also added RDSE_QUIET and RDSE_SPEAKING as return values.
+//
+// 1.62 26-Jun-97 PSJ Added PauseSpeech and UnpauseSpeech.
+//
+// 1.63 26-Jun-97 PRP Added DimPalette.
+//
+// 1.64 27-Jun-97 PRP Moved definition of GrabScreenShot in from
+// d_draw.h
+//
+// 1.65 15-Jul-97 PRP Added functions to pause and unpause speech.
+//
+// 1.66 16-Jul-97 PRP Added a speech pointer to the movieTextObject structure.
+//
+// 1.67 16-Jul-97 PSJ Added GetCompSpeechSize and PreFetchSpeech
+//
+// 1.68 21-Jul-97 PRP Added new FX type for sequence lead in and new function
+// to pause sound effects apart from the lead in music.
+//
+// 1.73 22-Jul-97 PRP Added define to ensure DirectX 3.0 functionality used
+// under DirectX 5.0 drivers :)
+//
+// 1.74 23-Jul-97 JEL Added CheckForMouseEvents() to return no. of events outstanding
+//
+// 1.75 30-Jul-97 PSJ Added MusicTimeRemaining() to return time left for current tune.
+//
+// 1.77 06-Aug-97 PSJ Updated Get and Set scroll SoundStatus.
+//
+// 1.78 07-Aug-97 PSJ Added SetWindowName to set the name of the window.
+//
+// 1.79 12-Aug-97 PSJ Added ReverseStereo.
+//
+// 1.80 13-Aug-97 PRP Added CloseMenuImmediately.
+//
+// 1.81 13-Aug-97 PSJ Added GetKeyStatus
+//
+// 1.82 13-Aug-97 PRP Added IsFxOpen.
+//
+// 1.83 15-Aug-97 PRP SetFxVolumePan added to update a sample on the fly.
+//
+// 1.84 15-Aug-97 PRP SetFxIdVolume added.
+//
+// 1.85 22-Aug-97 PSJ Added type RDSE_LEADOUT
+//
+// Functions
+// ---------
+//
+// ---------------------------------------------------------------------------
+// ------------------------------- d_draw.c ----------------------------------
+// ---------------------------------------------------------------------------
+//
+// int32 InitialiseDisplay(int32 width, int32 height, int32 colourDepth, int32 windowType)
+//
+// Initialises the directDraw display with the sizes and colour depths passed
+// in. The windowType is either RD_FULLSCREEN or RD_WINDOWED depending upon
+// whether the app is to run in a window or not. If RD_WINDOWED is selected,
+// the runction may returnRDERR_GOFULLSCREEN which implies that the window
+// size and colour depth requested is not compatible with the current
+// settings.
+// If the required display cannot be set up, then an error code is
+// returned, otherwise zero.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 ResetDisplay(void)
+//
+// Closes down the directDraw sub-system and resets the display back to it's
+// original size. Returns an RD code.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 FlipScreens(void)
+//
+// Waits for the vertical retrace and then flips the front and back buffers.
+// If a vertical retrace flag is unavailable, it flips immediately. Returns
+// an RD code.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 EraseBackBuffer(void)
+//
+// Fills the back buffer with palette colour zero. Returns an RD code.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 WaitForVbl(void)
+//
+// This function returns when the video hardware is in vertical retrace.
+//
+// ---------------------------------------------------------------------------
+//
+// void InterpretDirectDrawError(int32 error)
+//
+// This function is passed the pointer to a direct draw error code, and
+// translates this into a revolution driver error code. It also reports the
+// error.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 SetBltFx(void)
+//
+// Sets the edge blend and arithmetic stretching effects.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 ClearBltFx(void)
+//
+// Clears the edge blend and arithmetic stretching effects.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 RenderHard(void);
+//
+// Turns on the hardware renderer. Returns an error if the
+// hardware is not capable of rendering.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 RenderSoft(void);
+//
+// Turns on the software renderer. Returns an error if it
+// is already on.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 GetRenderType(void)
+//
+// Returns the type of rendering currently being used.
+// 0 = H/W rendering, 1 = S/W Rendering + BltFxOFF, 2 = S/W Rendering + BltFxON
+//
+// ---------------------------------------------------------------------------
+//
+// int32 PlaySmacker(char *filename)
+//
+// Plays the smacker file, filename.
+//
+// ---------------------------------------------------------------------------
+//
+// void GetDrawStatus(_drvStatus *s)
+//
+// Retrieves the value of the driver's drawing globals and stores them in s.
+//
+// ---------------------------------------------------------------------------
+//
+// void SetDrawStatus(_drvStatus *s)
+//
+// Set the value of the driver's drawing globals from s.
+//
+// --------------------------- rdwin.c ---------------------------------------
+// ---------------------------------------------------------------------------
+//
+// int32 InitialiseWindow(HWND hWnd)
+//
+// Creates a window! This must be the first operation in creating the
+// Windows 95 version.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 ServiceWindows(void)
+//
+// This function should be called at a high rate ( > 20 per second) to service
+// windows and the interfaces it provides.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 CloseAppWindow(void)
+//
+// Removes all windows hooks from the application.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 ReportDriverError(int32 error)
+//
+// Creates a message box and displays the error code passed to it, as well as
+// the filename and line that the function was called from
+//
+// ---------------------------------------------------------------------------
+//
+// int32 ReportFatalError(uint8 *error)
+//
+// Creates a message box and displays the error string passed in, as well as
+// the filename and line that the function was called from
+//
+// ---------------------------------------------------------------------------
+//
+// void SetWindowName(const char *windowName)
+//
+// Set the window name to windowName and stores this name in gameName for future
+// use.
+//
+// ---------------------------------------------------------------------------
+// --------------------------------- language.c ------------------------------
+// ---------------------------------------------------------------------------
+//
+// int32 GetLanguageVersion(uint8 *version)
+//
+// This function modifies the 'version' passed in to be the current language.
+// The first time this function is called, it gets the language from the
+// version.inf file distributed on the game CD. It returns an RD error code
+// if this file cannot be opened, or the version cannot be obtained from it.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 SetLanguageVersion(uint8 version)
+//
+// This function is useful for debugging. It sets the version to the one
+// passed in.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 GetGameName(uint8 *name);
+//
+// Fills the string pointed to by name with the title of the game, depending
+// upon what the current language version is.
+//
+// --------------------------------------------------------------------------
+// ------------------------------- palette.c --------------------------------
+// --------------------------------------------------------------------------
+//
+// void SetPalette(int32 startEntry, int32 noEntries, uint8 *colourTable, uint8 setNow)
+//
+// Sets the palette from position startEntry for noEntries, to the data
+// pointed to by colourTable. To set the palette immediately pass
+// RDPAL_INSTANT. If you want to fade later, pass RDPAL_FADE.
+//
+// --------------------------------------------------------------------------
+//
+// int32 UpdatePaletteMatchTable(uint8 *data)
+//
+// Uses the current palCopy to create a table of palette indeces which will
+// be searched later for a quick palette match - only if NULL is passed in
+// as the data. If a pointer to valid data is passed in, the palette match
+// table is copied from that data.
+//
+// --------------------------------------------------------------------------
+//
+// uint8 QuickMatch(uint8 r, uint8 g, uint8 b)
+//
+// Returns the palette index of the closest matching colour in the palette
+// to these RGB values.
+//
+// --------------------------------------------------------------------------
+//
+// int32 FadeUp(float time)
+//
+// Fades the palette up from black to the current palette in time.
+//
+// --------------------------------------------------------------------------
+//
+// int32 FadeDown(float time)
+//
+// Fades the palette down to black from the current palette in time.
+//
+// --------------------------------------------------------------------------
+//
+// uint8 GetFadeStatus(void)
+//
+// Returns the fade status which can be one of RDFADE_UP, RDFADE_DOWN or
+// RDFADE_NONE.
+//
+//
+// --------------------------------------------------------------------------
+// -------------------------------- mouse.c ---------------------------------
+// --------------------------------------------------------------------------
+//
+// _mouseEvent *MouseEvent(void)
+//
+// If there is a mouse event in the queue, a valid pointer is returned.
+// Otherwise, NULL.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetMouseAnim(uint8 *ma, int32 size, int32 mouseFlash)
+//
+// A pointer to a valid mouse animation is passed in, along with the size of
+// the header plus sprite data. Remember to check that the function has
+// successfully completed, as memory allocation is required. When the mouse
+// animation has been set, the mouse sprite does not need to be kept in the
+// memory manager.
+// Pass NULL in to clear the mouse sprite.
+// mouseFlash should be either RDMOUSE_FLASH or RDMOUSE_NOFLASH
+// defining whether to pulse the mouse or not.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetLuggageAnim(uint8 *la, int32 size)
+//
+// A pointer to a valid luggage animation is passed in, along with the size of
+// the header plus sprite data. Remember to check that the function has
+// successfully completed, as memory allocation is required.
+// Pass NULL in to clear the luggage sprite. Luggage sprites are of the same
+// format as mouse sprites.
+//
+// --------------------------------------------------------------------------
+//
+// int32 AnimateMouse(void)
+//
+// This function animates the current mouse pointer. If no pointer is
+// currently defined, an error code is returned.
+//
+//
+// --------------------------------------------------------------------------
+// ------------------------------ keyboard.c --------------------------------
+// --------------------------------------------------------------------------
+//
+// BOOL KeyWaiting(void)
+//
+// This function returns TRUE if there is an unprocessed key waiting in the
+// queue, FALSE otherwise.
+//
+// --------------------------------------------------------------------------
+//
+// int32 ReadKey(char *key)
+//
+// Sets the value of key passed in to the current waiting key. If there is
+// no key waiting, an error code is returned.
+//
+//
+// --------------------------------------------------------------------------
+//
+// void GetKeyStatus(_drvKeyStatus *)
+//
+// Retrieves the address of the keyboard buffer bits.
+//
+// --------------------------------------------------------------------------
+// ------------------------------- sprite.c ---------------------------------
+// --------------------------------------------------------------------------
+//
+// int32 DrawSprite(_spriteInfo *s)
+//
+// Draws a sprite onto the screen of the type defined in the _spriteInfo
+// structure. The _spriteInfo structure consists of the following elements:
+//
+// int16 x; // coords for top-left of sprite
+// int16 y;
+// uint16 w; // dimensions of sprite (before scaling)
+// uint16 h;
+// uint16 scale; // scale at which to draw, given in 256ths
+// ['0' or '256' MEANS DON'T SCALE]
+// uint16 scaledWidth; // new dimensions
+// uint16 scaledHeight; //
+// uint16 blend // blending value.
+// uint16 type; // combination of the bits below
+// uint8 *data; // pointer to the sprite data
+// uint8 *colourTable; // pointer to 16-byte colour table - only
+// applicable to 16-col compression type
+//
+// WARNING: Sprites will only be drawn onto the background. Sprites will not
+// appear over the menubar areas. The mouse and menu drawing is treated
+// as a special case.
+//
+// The type of the sprite can be any of the following:
+//
+// if (RDSPR_TRANS)
+// The sprite has a transparent colour zero
+// if (RDSPR_NOCOMPRESSION)
+// The sprite data must not be compressed (slow to draw)
+// The RDSPR_DISPLAYALIGN bit may be set to draw the sprite
+// at coordinates relative to the top left corner of the
+// monitor.
+// else
+// Compression must be set as one of the following:
+// RDSPR_RLE16
+// RDSPR_RLE256
+// RDSPR_LAYERCOMPRESSION
+// else
+// The sprite has an opaque colour zero
+// RDSPR_NOCOMPRESSION must be set!
+// RDSPR_DISPLAYALIGN may be set to align the coordinates of the sprite
+// to the top left corner of the monitor.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 CreateSurface(_spriteInfo *s, uint32 *surface)
+//
+// Creates a sprite surface in video memory (if possible) and returns it's
+// handle in surface.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 DrawSurface(_spriteInfo *s, uint32 surface)
+//
+// Draws the sprite surface created earlier. If the surface has been lost,
+// it is recreated.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 DeleteSurface(uint32 surface)
+//
+// Deletes a surface from video memory.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 OpenLightMask(_spriteInfo *s)
+//
+// Opens the light masking sprite for a room.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 CloseLightMask(void)
+//
+// Closes the light masking sprite for a room.
+//
+// --------------------------------------------------------------------------
+// ------------------------------- render.c ---------------------------------
+// --------------------------------------------------------------------------
+//
+// int32 RenderParallax(_parallax *p)
+//
+// Draws a parallax layer at the current position determined by the scroll.
+// A parallax can be either foreground, background or the main screen.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 CopyScreenBuffer(void)
+//
+// Copies the screen buffer to screen memory. This function should be called
+// when the drawing should be done to the back buffer. It only does this
+// when we are using a software screen buffer.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 SetScrollTarget(int16 sx, int16 sy)
+//
+// Sets the scroll target position for the end of the game cycle. The drivers
+// will then automatically scroll as many times as it can to reach this
+// position in the allotted time.
+//
+// --------------------------------------------------------------------------
+//
+// int32 InitialiseRenderCycle(void)
+//
+// Initialises the timers before the render loop is entered.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StartRenderCycle(void)
+//
+// This function should be called when the game engine is ready to start
+// the render cycle.
+//
+// --------------------------------------------------------------------------
+//
+// int32 EndRenderCycle(BOOL *end)
+//
+// This function should be called at the end of the render cycle. If the
+// render cycle is to be terminated, the function sets *end to 1. Otherwise,
+// the render cycle should continue.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetLocationMetrics(uint16 w, uint16 h)
+//
+// This function tells the drivers the size of the background screen for the
+// current location.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlotPoint(uint16 x, uint16 y, uint8 colour)
+//
+// Plots the point x,y in relation to the top left corner of the background.
+//
+// --------------------------------------------------------------------------
+//
+// int32 DrawLine(int16 x1, int16 y1, int16 x2, int16 y2, uint8 colour)
+//
+// Draws a line from the point x1,y1 to x2,y2 of the specified colour.
+//
+// --------------------------------------------------------------------------
+//
+// int32 InitialiseBackgroundLayer(_parallax *p)
+//
+// 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 CloseBackgroundLayer(void)
+//
+// Should be called once after leaving a room to free up video memory.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlotDots(int16 x, int16 y, int16 count)
+//
+// Plots 'count' dots at the position x,y.
+//
+// --------------------------------------------------------------------------
+//
+// int32 EraseSoftwareScreenBuffer(void)
+//
+// Clears the memory used for the software screen buffer. This should
+// not be called every cycle because it takes time and is not necessary.
+// However, it should be called between levels and such.
+//
+// --------------------------------------------------------------------------
+// ---------------------------- menu.c --------------------------------------
+// --------------------------------------------------------------------------
+//
+// int32 ProcessMenu(void)
+//
+// This function should be called regularly to process the menuber system.
+// The rate at which this function is called will dictate how smooth the menu
+// system is. The menu cannot be drawn at a higher rate than the system
+// vbl rate.
+//
+// --------------------------------------------------------------------------
+//
+// int32 ShowMenu(uint8 menu)
+//
+// This function brings the menu in to view. The choice of top or bottom menu
+// is defined by the parameter menu being either RDMENU_TOP or RDMENU_BOTTOM.
+// An error code is returned if the menu is already shown.
+//
+// --------------------------------------------------------------------------
+//
+// int32 HideMenu(uint8 menu)
+//
+// This function hides the menu defined by the parameter menu. If the menu is
+// already hidden, an error code is returned.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetMenuIcon(uint8 menu, uint8 pocket, uint8 *icon)
+//
+// This function sets a menubar icon to that passed in. If icon is NULL, the
+// pocket is cleared, otherwise, that icon is placed into pocket. The menu is
+// either RDMENU_TOP or RDMENU_BOTTOM. Valid error codes include
+// RDERR_INVALIDPOCKET if the pocket number does not exist. Initially, there
+// are 15 pockets.
+//
+// --------------------------------------------------------------------------
+//
+// uint8 GetMenuStatus(uint8 menu)
+//
+// This function returns the status of the menu passed in menu. Return values
+// are RDMENU_OPENING, RDMENU_CLOSING, RDMENU_HIDDEN and RDMENU_SHOWN.
+//
+//
+//
+// --------------------------------------------------------------------------
+// --------------------------- d_sound.c ------------------------------------
+// --------------------------------------------------------------------------
+//
+// int32 InitialiseSound(uint16 freq, uint16 channels, uint16 bitDepth)
+//
+// This function initialises DirectSound by specifying the parameters of the
+// primary buffer.
+//
+// Freq is the sample rate - 44100, 22050 or 11025
+// Channels should be 1 for mono, 2 for stereo
+// BitDepth should be either 8 or 16 bits per sample.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlaySpeech(uint8 *data, uint8 vol, int8 pan)
+//
+// This function plays the wav file passed into it as speech. An error occurs
+// if speech is already playing, or directSound comes accross problems.
+// volume can be from 0 to 16.
+// pan can be from -16 (full left) to 16 (full right).
+//
+// --------------------------------------------------------------------------
+//
+// int32 PreFetchCompSpeech(const char *filename, uint32 speechid, uint8 *wave)
+//
+// This function loads and decompresses speech sample 'speechid' from the
+// cluster 'filename' into 'wave'. 'wave' should contain the address of
+// preallocated memory large enough for speech to fit into
+// (see GetCompSpeechSize).
+//
+// --------------------------------------------------------------------------
+//
+// int32 GetCompSpeechSize(const char *filename, uint32 speechid);
+//
+// This function returns the size that speech sample 'speechid' from cluster
+// 'filename' will be after it has been decompressed and had a wav header
+// added. Returns 0 for any error.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlayCompSpeech(const char *filename, uint32 id, uint8 vol, int8 pan)
+//
+// This function loads, decompresses and plays the wav 'id' from the cluster
+// 'filename'. An error occurs if speech is already playing, or directSound
+// comes accross problems. 'volume' can be from 0 to 16. 'pan' can be from
+// -16 (full left) to 16 (full right).
+// id is the text line id used to reference the speech within the speech
+// cluster.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StopSpeech(void)
+//
+// Stops the speech from playing.
+//
+// --------------------------------------------------------------------------
+//
+// int32 GetSpeechStatus(void)
+//
+// Returns either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED
+//
+// --------------------------------------------------------------------------
+//
+// int32 AmISpeaking(void)
+//
+// Returns either RDSE_QUIET or RDSE_SPEAKING
+//
+// --------------------------------------------------------------------------
+//
+// int32 PauseSpeech(void)
+//
+// Stops the speech dead in it's tracks.
+//
+// --------------------------------------------------------------------------
+//
+// int32 UnpauseSpeech(void)
+//
+// Re-starts the speech from where it was stopped.
+//
+// --------------------------------------------------------------------------
+//
+// int32 OpenFx(int32 id, uint8 *data)
+//
+// This function opens a sound effect ready for playing. A unique id should
+// be passed in so that each effect can be referenced individually.
+//
+// WARNING: Zero is not a valid ID.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlayFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type)
+//
+// This function plays a sound effect. If the effect has already been opened
+// then *data should be NULL, and the sound effect will simply be obtained
+// from the id passed in. If the effect has not been opened, then the wav
+// data should be passed in data. The sound effect will be closed when it
+// has finished playing.
+// volume can be from 0 to 16.
+// pan can be from -16 (full left) to 16 (full right).
+// type is either RDSE_FXSPOT or RDSE_FXLOOP
+//
+// WARNING: Zero is not a valid ID
+//
+// --------------------------------------------------------------------------
+//
+// int32 CloseFx(int32 id)
+//
+// This function closes a sound effect which has been previously opened for
+// playing. Sound effects must be closed when they are finished with,
+// otherwise you will run out of sound effect buffers.
+//
+// --------------------------------------------------------------------------
+//
+// int32 ClearAllFx(void)
+//
+// This function clears all of the sound effects which are currently open or
+// playing, irrespective of type.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StreamMusic(uint8 *filename, int32 loopFlag)
+//
+// Streams music from the file defined by filename. The loopFlag should
+// be set to RDSE_FXLOOP if the music is to loop back to the start.
+// Otherwise, it should be RDSE_FXSPOT.
+// The return value must be checked for any problems.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StreamCompMusic(uint8 *filename, uint32 id, int32 loopFlag)
+//
+// Streams music 'id' from the cluster file 'filename'. The loopFlag should
+// be set to RDSE_FXLOOP if the music is to loop back to the start.
+// Otherwise, it should be RDSE_FXSPOT.
+// The return value must be checked for any problems.
+//
+// StreamCompMusic should not be used inconjunction with StreamMusic.
+//
+// --------------------------------------------------------------------------
+//
+// void StopMusic(void)
+//
+// Fades out and stops the music.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PauseMusic(void)
+//
+// Stops the music dead in it's tracks.
+//
+// --------------------------------------------------------------------------
+//
+// int32 UnpauseMusic(void)
+//
+// Re-starts the music from where it was stopped.
+//
+// ---------------------------------------------------------------------------
+//
+// void GetSoundStatus(_drvStatus *s)
+//
+// Retrieves the value of the driver's audio globals and stores them in s.
+//
+// ---------------------------------------------------------------------------
+//
+// void SetSoundStatus(_drvStatus *s)
+//
+// Set the value of the driver's audio globals from s.
+//
+// ---------------------------------------------------------------------------
+//
+// void SetMusicVolume(uint8 vol)
+//
+// Set the volume of any future as well as playing (but not fading) music to
+// vol. vol is in the range of 0 to 16 with 0 being silent.
+//
+// ---------------------------------------------------------------------------
+//
+// uint8 GetMusicVolume(void)
+//
+// Returns the volume setting for music.
+//
+// ---------------------------------------------------------------------------
+//
+// void SetFxVolume(uint8 vol)
+//
+// Set the master volume of all fx' to vol. The fx' still have there own
+// volume setting as well as the master volume. vol is in the range 0 to 14
+// with 0 being silent.
+//
+// ---------------------------------------------------------------------------
+//
+// uint8 GetFxVolume(void)
+//
+// Returns the master volume setting for fx'.
+//
+// ---------------------------------------------------------------------------
+//
+// void SetSpeechVolume(uint8 vol)
+//
+// Set the volume of any future as well as playing speech samples to vol.
+// vol is in the range of 0 to 14 with 0 being silent.
+//
+// ---------------------------------------------------------------------------
+//
+// uint8 GetSpeechVolume(void)
+//
+// Returns the volume setting for speech.
+//
+// ---------------------------------------------------------------------------
+//
+// void MuteMusic(uint8 mute)
+//
+// If mute is 0, the music volume is restored to the last set master level.
+// otherwise the music is muted (volume 0).
+//
+// ---------------------------------------------------------------------------
+//
+// void MuteFx(uint8 mute)
+//
+// See MuteMusic(uint8).
+//
+// ---------------------------------------------------------------------------
+//
+// void MuteSpeech(uint8 mute)
+//
+// See MuteMusic(uint8).
+//
+// ---------------------------------------------------------------------------
+//
+// uint8 IsMusicMute(void)
+//
+// Returns the music's mute state, 1 if mute, 0 if not mute.
+//
+// ---------------------------------------------------------------------------
+//
+// uint8 IsFxMute(void)
+//
+// See IsMusicMute().
+//
+// ---------------------------------------------------------------------------
+//
+// uint8 IsMusicMute(void)
+//
+// See IsMusicMute().
+//
+// ---------------------------------------------------------------------------
+//
+// int32 MusicTimeRemaining(void)
+//
+// Returns the time left for the current tune.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 ReverseStereo(void)
+//
+// Returns the time left for the current tune.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 SetFxVolumePan(int32 id, uint8 vol, uint8 pan)
+//
+// Sets the volume and pan of the sample which is currently playing (id)
+//
+//=============================================================================
+
+#ifndef DRIVER96_H
+#define DRIVER96_H
+
+//#define DIRECTDRAW_VERSION 0x0300
+
+//#include <windows.h>
+//#include <windowsx.h>
+#include <limits.h>
+//#include <mmsystem.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "scummsys.h"
+#include "engine.h" // for warning()
+#include "system.h"
+#include "file.h"
+//#include "ddraw.h"
+//#include "dsound.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+//
+// Defines
+// -------
+//
+
+// defines specific to windows headers...
+#ifndef _MSC_VER
+
+#define SEM_FAILCRITICALERRORS 1
+#define FILE_ATTRIBUTE_NORMAL 0x80
+#define _MAX_PATH 260
+
+#endif
+
+//Generic error codes
+#define RD_OK 0x00000000
+#define RDERR_UNKNOWN 0x00000001
+#define RDERR_INVALIDPOINTER 0x00000002
+#define RDERR_OUTOFMEMORY 0x00000003
+#define RDERR_INVALIDFILENAME 0x00000004
+#define RDERR_READERROR 0x00000005
+#define RDERR_WRITEERROR 0x00000006
+#define RDERR_NOEMULATION 0x00000007
+#define RDERR_LOCKFAILED 0x00000008
+
+//Drawing error codes
+#define RDERR_VIDEOMODE 0x00010000
+#define RDERR_COLOURDEPTH 0x00010001
+#define RDERR_CANNOTFLIP 0x00010002
+#define RDERR_RESTORELAYERS 0x00010003
+#define RDERR_DDRAWNOEMULATION 0X00010004
+#define RDERR_NOHARDWARE 0x00010005
+#define RDERR_ALREADYON 0x00010006
+#define RDERR_DECOMPRESSION 0x00010007
+
+//Operating system error codes
+#define RDERR_CREATEWINDOW 0x00020000
+#define RDERR_APPCLOSED 0x00020001
+#define RDERR_GOFULLSCREEN 0x00020002
+
+//Language and version error codes
+#define RDERR_OPENVERSIONFILE 0x00030000
+#define RDERR_INVALIDVERSION 0x00030001
+
+//Keyboard error codes
+#define RDERR_NOKEYWAITING 0x00040000
+
+//Sprite drawing error codes
+#define RDERR_NOCLIPPING 0x00050000
+#define RDERR_NOTIMPLEMENTED 0x00050001
+#define RDERR_UNKNOWNTYPE 0x00050002
+#define RDERR_INVALIDSCALING 0x00050003
+#define RDERR_SURFACELOST 0x00050004
+#define RDERR_NOTCLOSED 0x00050005
+#define RDERR_NOTOPEN 0x00050006
+#define RDERR_ALREADYCLOSED 0x00050007 // added for _console.cpp by khalek
+
+//Menubar error codes
+#define RDERR_INVALIDMENU 0x00060000
+#define RDERR_INVALIDPOCKET 0x00060001
+#define RDERR_INVALIDCOMMAND 0x00060002
+
+//Palette fading error codes
+#define RDERR_FADEINCOMPLETE 0x00070000
+
+//Sound engine error codes
+#define RDERR_DSOUNDCREATE 0x00080000
+#define RDERR_DSOUNDCOOPERATE 0x00080001
+#define RDERR_DSOUNDPBUFFER 0x00080002
+#define RDERR_PRIMARYFORMAT 0x00080003
+#define RDERR_SPEECHPLAYING 0x00080004
+#define RDERR_SPEECHNOTPLAYING 0x00080005
+#define RDERR_INVALIDWAV 0x00080006
+#define RDERR_CREATESOUNDBUFFER 0x00080007
+#define RDERR_LOCKSPEECHBUFFER 0x00080008
+#define RDERR_FXALREADYOPEN 0x00080009
+#define RDERR_NOFREEBUFFERS 0x0008000A
+#define RDERR_FXNOTOPEN 0x0008000B
+#define RDERR_FXFUCKED 0x0008000C
+#define RDERR_INVALIDID 0x0008000D
+
+
+
+
+// Language codes
+#define ENGLISH 0x00
+#define AMERICAN 0x01
+#define GERMAN 0x02
+#define FRENCH 0x03
+#define SPANISH 0x04
+#define ITIALIAN 0x05
+#define JAPANESE 0x06
+#define SLOVAK 0x07
+
+// Key codes
+#define RDKEY_ESCAPE 27
+
+
+// Mouse button defines
+#define RD_LEFTBUTTONDOWN 0x01
+#define RD_LEFTBUTTONUP 0x02
+#define RD_RIGHTBUTTONDOWN 0x04
+#define RD_RIGHTBUTTONUP 0x08
+
+
+//Sprite defines
+#define RDSPR_TRANS 0x0001
+#define RDSPR_BLEND 0x0004
+#define RDSPR_FLIP 0x0008
+#define RDSPR_SHADOW 0x0010
+#define RDSPR_DISPLAYALIGN 0x0020
+#define RDSPR_NOCOMPRESSION 0x0040
+#define RDSPR_EDGEBLEND 0x0080
+//This is the high byte part of the sprite type which defines what type of
+// compression is used, as long as RDSPR_NOCOMPRESSION is not defined.
+#define RDSPR_RLE16 0x0000
+#define RDSPR_RLE256 0x0100
+#define RDSPR_RLE256FAST 0x0200
+
+
+//Rendering defines
+#define RD_SOFTWARESCREENBUFFER 0x01
+
+
+//Windows defines
+#define RD_FULLSCREEN 0x01000000
+#define RD_WINDOWED 0x01000001
+
+
+//Fading defines
+#define RDFADE_NONE 0x00
+#define RDFADE_UP 0x01
+#define RDFADE_DOWN 0x02
+#define RDFADE_BLACK 0x03
+
+//Mouse defines
+#define RDMOUSE_NOFLASH 0x00
+#define RDMOUSE_FLASH 0x01
+
+//Menubar defines.
+#define RDMENU_TOP 0x00
+#define RDMENU_BOTTOM 0x01
+
+#define RDMENU_HIDDEN 0x00
+#define RDMENU_SHOWN 0x01
+#define RDMENU_OPENING 0x02
+#define RDMENU_CLOSING 0x03
+
+#define RDMENU_ICONWIDE 35
+#define RDMENU_ICONDEEP 30
+#define RDMENU_ICONSTART 24
+#define RDMENU_ICONSPACING 5
+#define RDMENU_MAXPOCKETS 15
+#define RDMENU_MENUDEEP 40
+
+#define RDSE_SAMPLEFINISHED 0
+#define RDSE_SAMPLEPLAYING 1
+#define RDSE_FXTOCLEAR 0
+#define RDSE_FXCACHED 1
+#define RDSE_FXSPOT 0
+#define RDSE_FXLOOP 1
+#define RDSE_FXLEADIN 2
+#define RDSE_FXLEADOUT 3
+#define RDSE_QUIET 1
+#define RDSE_SPEAKING 0
+
+
+#define RDPAL_FADE 0
+#define RDPAL_INSTANT 1
+
+//Blitting FX defines
+#define RDBLTFX_MOUSEBLT 0x01
+#define RDBLTFX_FGPARALLAX 0x02
+#define RDBLTFX_ARITHMETICSTRETCH 0x04
+#define RDBLTFX_EDGEBLEND 0x08
+#define RDBLTFX_SHADOWBLEND 0x10
+#define RDBLTFX_FLATALPHA 0x20
+#define RDBLTFX_GRADEDALPHA 0x40
+#define RDBLTFX_ALLHARDWARE 0x80
+
+// Max number of sound fx
+#define MAXFX 16
+#define MAXMUS 2
+
+// Key buffer size
+#define MAX_KEY_BUFFER 32
+
+typedef int BOOL;
+#define TRUE 1
+#define FALSE 0
+typedef uint32 DWORD;
+
+typedef long int LARGE_INTEGER;
+
+//
+// Structure definitions
+// ---------------------
+//
+
+typedef struct
+{
+ uint16 buttons;
+} _mouseEvent;
+
+typedef struct
+{
+ uint16 w;
+ uint16 h;
+ uint32 offset[2]; // 2 is arbitrary
+} _parallax;
+
+// The _spriteInfo structure is used to tell the driver96 code what attributes
+// are linked to a sprite for drawing. These include position, scaling and
+// compression.
+typedef struct
+{
+ int16 x; // coords for top-left of sprite
+ int16 y;
+ uint16 w; // dimensions of sprite (before scaling)
+ uint16 h;
+ uint16 scale; // scale at which to draw, given in 256ths ['0' or '256' MEANS DON'T SCALE]
+ uint16 scaledWidth; // new dimensions (we calc these for the mouse area, so may as well pass to you to save time)
+ uint16 scaledHeight; //
+ uint16 type; // mask containing 'RDSPR_' bits specifying compression type, flip, transparency, etc
+ uint16 blend; // holds the blending values.
+ uint8 *data; // pointer to the sprite data
+ uint8 *colourTable; // pointer to 16-byte colour table, only applicable to 16-col compression type
+} _spriteInfo;
+
+
+// This is the format of a .WAV file. Somewhere after this header is the string
+// 'DATA' followed by an int32 size which is the size of the data. Following
+// the size of the data is the data itself.
+typedef struct
+{
+ char riff[4];
+ uint32 fileLength;
+ char wavID[4];
+ char format[4];
+ uint32 formatLen;
+ uint16 formatTag;
+ uint16 channels;
+ uint16 samplesPerSec;
+ uint16 avgBytesPerSec;
+ uint16 blockAlign;
+ uint16 unknown1;
+ uint16 unknown2;
+ uint16 bitsPerSample;
+} _wavHeader;
+
+
+// This is the structure which is passed to the sequence player.
+// It includes the smack to play, and any text lines which are
+// to be displayed over the top of the sequence.
+
+typedef struct
+{
+ uint16 startFrame;
+ uint16 endFrame;
+ _spriteInfo *textSprite;
+ _wavHeader *speech;
+} _movieTextObject;
+
+
+
+typedef struct
+{ uint8 manufacturer;
+ uint8 version;
+ uint8 encoding;
+ uint8 bitsPerPixel;
+ int16 xmin,ymin;
+ int16 xmax,ymax;
+ int16 hres;
+ int16 vres;
+ char palette[48];
+ char reserved;
+ uint8 colourPlanes;
+ int16 bytesPerLine;
+ int16 paletteType;
+ char filler[58];
+} _pcxHeader;
+
+
+// This is the structure which is used to set and
+// retrieve the direct draw drivers global variables.
+
+typedef struct
+{
+// HWND hwnd;
+// LPDIRECTDRAW lpDraw;
+// LPDIRECTDRAW2 lpDD2;
+// LPDIRECTDRAWSURFACE lpPrimarySurface;
+// LPDIRECTDRAWSURFACE lpBackBuffer;
+// LPDIRECTDRAWPALETTE lpPalette;
+ int16 screenDeep;
+ int16 screenWide;
+ int16 scrollx;
+ int16 scrolly;
+ int16 scrollxTarget;
+ int16 scrollyTarget;
+ int16 scrollxOld;
+ int16 scrollyOld;
+ int16 failCount;
+ int32 renderCaps;
+ int32 dxHalCaps;
+ int32 dxHelCaps;
+ BOOL noVbl;
+ BOOL bFullScreen;
+// DDCAPS driverCaps;
+// DDCOLORKEY blackColorKey;
+} _drvDrawStatus;
+
+
+
+// This is the structure which is used to set and
+// retrieve the direct sound drivers global variables.
+
+typedef struct
+{
+// HWND hwnd;
+// LPDIRECTSOUND lpDS;
+// LPDIRECTSOUNDBUFFER dsbPrimary;
+// LPDIRECTSOUNDBUFFER dsbSpeech;
+// LPDIRECTSOUNDBUFFER dsbFx[MAXFX];
+ int32 fxId[MAXFX];
+ uint8 fxCached[MAXFX];
+ uint8 soundOn;
+ uint8 speechStatus;
+ uint8 fxPaused;
+ char musFilename[MAXMUS][256];
+ uint8 speechPaused;
+ uint8 speechVol;
+ uint8 fxVol;
+ uint8 speechMuted;
+ uint8 fxMuted;
+ uint8 musicMuted;
+ uint8 compressedMusic;
+ uint8 fxiPaused[MAXFX];
+ uint8 fxLooped[MAXFX];
+ int16 musStreaming[MAXMUS];
+ int16 musicPaused[MAXMUS];
+ int16 musCounter[MAXMUS];
+ int16 musFading[MAXMUS];
+ int16 musLooping[MAXMUS];
+ int16 musLastSample[MAXMUS];
+ int32 streamCursor[MAXMUS];
+ int32 musFilePos[MAXMUS];
+ int32 musEnd[MAXMUS];
+ uint32 musId[MAXMUS];
+// DSBUFFERDESC dsbdMus[MAXMUS];
+// LPDIRECTSOUNDBUFFER lpDsbMus[MAXMUS];
+ FILE *fpMus[MAXMUS];
+// PCMWAVEFORMAT wfMus[MAXMUS];
+ uint32 volMusic[2];
+} _drvSoundStatus;
+
+// This is the structure which is used to retrieve
+// the keyboard driver bits.
+
+typedef struct
+{
+ uint8 *pBacklog;
+ uint8 *pPointer;
+ char *pBuffer;
+} _drvKeyStatus;
+
+
+// should probably remove this struct as it just replaces a windows struct...
+typedef struct {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORD dwTotalPhys;
+ DWORD dwAvailPhys;
+ DWORD dwTotalPageFile;
+ DWORD dwAvailPageFile;
+ DWORD dwTotalVirtual;
+ DWORD dwAvailVirtual;
+} GCC_PACK MEMORYSTATUS;
+
+//
+// Function Prototypes
+// -------------------
+//
+
+//-----------------------------------------------------------------------------
+// Display functions - from d_draw.c
+//-----------------------------------------------------------------------------
+extern int32 InitialiseDisplay(int16 width, int16 height, int16 colourDepth, int32 windowType);
+extern int32 RestoreDisplay(void);
+extern int32 FlipScreens(void);
+extern int32 WaitForVbl(void);
+extern int32 EraseBackBuffer(void);
+extern int32 SetBltFx(void);
+extern int32 ClearBltFx(void);
+extern int32 ClearShadowFx(void);
+extern int32 SetShadowFx(void);
+extern int32 RenderHard(void);
+extern int32 RenderSoft(void);
+extern int32 GetRenderType(void);
+extern int32 PlaySmacker(char *filename, _movieTextObject *textObjects[], uint8 *musicOut);
+extern void GetDrawStatus(_drvDrawStatus *s);
+extern void SetDrawStatus(_drvDrawStatus *s);
+extern int32 GrabScreenShot(void);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Windows OS functions - from rdwin.c
+//-----------------------------------------------------------------------------
+//extern int32 InitialiseWindow(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, char *gameName);
+extern int32 CloseAppWindow(void);
+extern int32 ServiceWindows(void);
+extern int32 _ReportDriverError(int32 error, uint8 *filename, uint32 line);
+extern int32 _ReportFatalError(uint8 *error, uint8 *filename, uint32 line);
+extern int32 DisableQuitKey(void);
+extern void SetWindowName(const char *windowName);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Language functions - from language.c
+//-----------------------------------------------------------------------------
+extern int32 GetLanguageVersion(uint8 *version);
+extern int32 SetLanguageVersion(uint8 version);
+extern int32 GetGameName(uint8 *name);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Palette functions - from palette.c
+//-----------------------------------------------------------------------------
+extern int32 SetPalette(int16 startEntry, int16 noEntries, uint8 *palette, uint8 setNow);
+extern int32 UpdatePaletteMatchTable(uint8 *data);
+extern uint8 QuickMatch(uint8 r, uint8 g, uint8 b);
+extern int32 FadeUp(float time);
+extern int32 FadeDown(float time);
+extern uint8 GetFadeStatus(void);
+extern int32 DimPalette(void);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Mouse functions - from mouse.c
+//-----------------------------------------------------------------------------
+extern _mouseEvent *MouseEvent(void);
+extern int32 SetMouseAnim(uint8 *ma, int32 size, int32 mouseFlash);
+extern int32 SetLuggageAnim(uint8 *la, int32 size);
+extern int32 AnimateMouse(void);
+uint8 CheckForMouseEvents(void); // (James23july97)
+extern void ResetRenderEngine(void);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Keyboard functions - from keyboard.c
+//-----------------------------------------------------------------------------
+extern BOOL KeyWaiting(void);
+extern int32 ReadKey(char *key);
+extern void GetKeyStatus(_drvKeyStatus *s);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Sprite functions - from sprite.c
+//-----------------------------------------------------------------------------
+extern int32 DrawSprite(_spriteInfo *s);
+extern int32 CreateSurface(_spriteInfo *s, uint32 *surface);
+extern int32 DrawSurface(_spriteInfo *s, uint32 surface);
+extern int32 DeleteSurface(uint32 surface);
+extern int32 OpenLightMask(_spriteInfo *s);
+extern int32 CloseLightMask(void);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Screen drawing and scrolling function - from render.c
+//-----------------------------------------------------------------------------
+extern int32 SetScrollTarget(int16 sx, int16 sy);
+extern int32 InitialiseRenderCycle(void);
+extern int32 StartRenderCycle(void);
+extern int32 EndRenderCycle(BOOL *end);
+extern int32 RenderParallax(_parallax *p, int16 layer);
+extern int32 SetLocationMetrics(uint16 w, uint16 h);
+extern int32 CopyScreenBuffer(void);
+extern int32 PlotPoint(uint16 x, uint16 y, uint8 colour);
+extern int32 DrawLine(int16 x1, int16 y1, int16 x2, int16 y2, uint8 colour);
+extern int32 InitialiseBackgroundLayer(_parallax *p);
+extern int32 CloseBackgroundLayer(void);
+extern int32 PlotDots(int16 x, int16 y, int16 count);
+extern int32 EraseSoftwareScreenBuffer(void);
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Menubar control and drawing functions - from menu.c
+//-----------------------------------------------------------------------------
+extern int32 ProcessMenu(void);
+extern int32 ShowMenu(uint8 menu);
+extern int32 HideMenu(uint8 menu);
+extern int32 SetMenuIcon(uint8 menu, uint8 pocket, uint8 *icon);
+extern uint8 GetMenuStatus(uint8 menu);
+extern int32 CloseMenuImmediately(void);
+
+
+//-----------------------------------------------------------------------------
+// Sound driver functions - from d_sound.c
+//-----------------------------------------------------------------------------
+extern int32 InitialiseSound(uint16 freq, uint16 channels, uint16 bitDepth);
+extern int32 PlaySpeech(uint8 *data, uint8 vol, int8 pan);
+extern int32 PlayCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan);
+extern int32 PreFetchCompSpeech(const char *filename, uint32 speechid, uint8 *waveMem);
+extern int32 GetCompSpeechSize(const char *filename, uint32 speechid);
+extern int32 AmISpeaking();
+extern int32 StopSpeech(void);
+extern int32 GetSpeechStatus(void);
+extern int32 PauseSpeech(void);
+extern int32 UnpauseSpeech(void);
+extern int32 OpenFx(int32 id, uint8 *data);
+extern int32 PlayFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type);
+extern int32 CloseFx(int32 id);
+extern int32 ClearAllFx(void);
+extern int32 PauseFx(void);
+extern int32 PauseFxForSequence(void);
+extern int32 UnpauseFx(void);
+extern int32 PauseMusic(void);
+extern int32 UnpauseMusic(void);
+extern int32 StreamMusic(uint8 *filename, int32 looping);
+extern int32 StreamCompMusic(const char *filename,uint32 musicId, int32 looping);
+extern int32 MusicTimeRemaining();
+extern int32 ReverseStereo(void);
+extern uint8 GetFxVolume(void);
+extern uint8 GetSpeechVolume(void);
+extern uint8 GetMusicVolume(void);
+extern uint8 IsMusicMute(void);
+extern uint8 IsFxMute(void);
+extern uint8 IsSpeechMute(void);
+extern void StopMusic(void);
+extern void GetSoundStatus(_drvSoundStatus *s);
+extern void SetSoundStatus(_drvSoundStatus *s);
+extern void SetFxVolume(uint8 vol);
+extern void SetSpeechVolume(uint8 vol);
+extern void SetMusicVolume(uint8 vol);
+extern void MuteMusic(uint8 mute);
+extern void MuteFx(uint8 mute);
+extern void MuteSpeech(uint8 mute);
+extern int32 IsFxOpen(int32 id);
+extern int32 SetFxVolumePan(int32 id, uint8 vol, int8 pan);
+extern int32 SetFxIdVolume(int32 id, uint8 vol);
+
+
+//-----------------------------------------------------------------------------
+// Misc functions - from misc.cpp
+//-----------------------------------------------------------------------------
+extern uint32 timeGetTime(void);
+extern void VirtualUnlock(uint8 *free_memman, uint32 total_free_memory);
+extern void GlobalMemoryStatus(MEMORYSTATUS *memo);
+extern void SetFileAttributes(char *file, uint32 atrib);
+extern void DeleteFile(char *file);
+extern void GetCurrentDirectory(uint32 max, char* path);
+extern int32 GetVolumeInformation(char *cdPath, char *sCDName, uint32 maxPath, uint8 *, DWORD *dwMaxCompLength, DWORD *dwFSFlags, uint8 *, uint32 a);
+extern void _mkdir(const char *pathname);
+extern void GetModuleFileName(void *module, char *destStr, uint32 maxLen);
+
+//-----------------------------------------------------------------------------
+//Macro for calling error handler with source filename and line.
+//-----------------------------------------------------------------------------
+#define ReportDriverError(f) _ReportDriverError(f, (uint8 *) __FILE__, (uint32) __LINE__)
+#define ReportFatalError(f) _ReportFatalError(f, (uint8 *) __FILE__, (uint32) __LINE__)
+//-----------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+// Macro for reporting a non-fatal driver error
+//-----------------------------------------------------------------------------
+#ifdef _DEBUG
+static int32 rderror;
+#define Driver(f) \
+ if (rderror = f) \
+ ReportDriverError(rderror)
+#else
+#define Driver(f) f
+#endif
+//-----------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+extern BOOL gotTheFocus; // set if the game is currently displayed
+extern int16 screenWide; // Width of the screen display
+extern int16 screenDeep; // Height of the screen display
+extern int16 mousex; // Mouse screen x coordinate
+extern int16 mousey; // Mouse screen y coordinate
+extern int32 renderCaps; // Flags which determine how to render the scene.
+extern uint8 palCopy[256][4]; // Current palette.
+//-----------------------------------------------------------------------------
+
+extern LARGE_INTEGER myTimers[10][2];
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/sword2/driver/keyboard.cpp b/sword2/driver/keyboard.cpp
new file mode 100644
index 0000000000..6f9d51c997
--- /dev/null
+++ b/sword2/driver/keyboard.cpp
@@ -0,0 +1,129 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : keyboard.c
+// Created : 19th September 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the interface to the keyboard
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 19-Sep-96 PRP Keyboard functions. Simple logging of
+// previous 32 keys pressed.
+//
+// 1.1 19-Sep-96 PRP Fixed bug, ReadKey did not return RD_OK.
+//
+// 1.2 13-Aug-97 PSJ Added GetKeyStatus
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// BOOL KeyWaiting(void)
+//
+// This function returns TRUE if there is an unprocessed key waiting in the
+// queue, FALSE otherwise.
+//
+// --------------------------------------------------------------------------
+//
+// int32 ReadKey(char *key)
+//
+// Sets the value of key passed in to the current waiting key. If there is
+// no key waiting, an error code is returned.
+//
+// --------------------------------------------------------------------------
+//
+// void GetKeyStatus(_drvKeyStatus *s)
+//
+// Retrieves the status of the keyboard handler.
+//
+//=============================================================================
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+
+#include "driver96.h"
+
+#define MAX_KEY_BUFFER 23
+
+uint8 keyBacklog = 0; // The number of key presses waiting to be processed.
+uint8 keyPointer = 0; // Index of the next key to read from the buffer.
+char keyBuffer[MAX_KEY_BUFFER]; // The keyboard buffer
+
+
+
+void WriteKey(char key)
+{
+ if (keyBuffer && keyBacklog < MAX_KEY_BUFFER)
+ {
+ keyBuffer[(keyPointer + keyBacklog) % MAX_KEY_BUFFER] = key;
+ keyBacklog += 1;
+ }
+}
+
+
+
+BOOL KeyWaiting(void)
+
+{
+
+ if (keyBacklog)
+ return(TRUE);
+ else
+ return(FALSE);
+
+}
+
+
+
+int32 ReadKey(char *key)
+
+{
+ if (!keyBacklog)
+ return(RDERR_NOKEYWAITING);
+
+ if (key == NULL)
+ return(RDERR_INVALIDPOINTER);
+
+ *key = keyBuffer[keyPointer++];
+ if (keyPointer == MAX_KEY_BUFFER)
+ keyPointer = 0;
+
+ keyBacklog -= 1;
+
+ return(RD_OK);
+
+}
+
+void GetKeyStatus(_drvKeyStatus *s)
+
+{
+ // Flush key buffer
+ s->pBacklog = &keyBacklog;
+ s->pPointer = &keyPointer;
+ s->pBuffer = keyBuffer;
+}
+
diff --git a/sword2/driver/keyboard.h b/sword2/driver/keyboard.h
new file mode 100644
index 0000000000..56bfad7333
--- /dev/null
+++ b/sword2/driver/keyboard.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : keyboard.h
+// Created : 19th September 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 19-Sep-96 PRP Internal driver interface to the keyboard driver
+// functions and data.
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the keyboard.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef KEYBOARD_H
+#define KEYBOARD_H
+
+
+void WriteKey(char key); // Adds a keypress to the buffer
+
+#endif
diff --git a/sword2/driver/language.cpp b/sword2/driver/language.cpp
new file mode 100644
index 0000000000..b20eb1508c
--- /dev/null
+++ b/sword2/driver/language.cpp
@@ -0,0 +1,134 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : language.c
+// Created : 20th August 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the functions which govern which language
+// version is current.
+//
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 16-Sep-96 PRP Initial language version control functions.
+// Many of the functions are currently stubs, and
+// this will be addressed shortly.
+//
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// int32 GetLanguageVersion(uint8 *version)
+//
+// This function modifies the 'version' passed in to be the current language.
+// The first time this function is called, it gets the language from the
+// version.inf file distributed on the game CD. It returns an RD error code
+// if this file cannot be opened, or the version cannot be obtained from it.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 SetLanguageVersion(uint8 version)
+//
+// This function is useful for debugging. It sets the version to the one
+// passed in.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 GetGameName(uint8 *name);
+//
+// Fills the string pointed to by name with the title of the game, depending
+// upon what the current language version is.
+//
+//=============================================================================
+
+
+#include "driver96.h"
+
+
+
+uint8 languageVersion = ENGLISH;
+
+static uint8 versionFromFile = 0;
+
+
+
+
+int32 GetLanguageVersion(uint8 *version)
+
+{
+
+ if (versionFromFile)
+ {
+ *version = languageVersion;
+ }
+ else
+ {
+ versionFromFile = 1;
+ languageVersion = AMERICAN;
+ return(RDERR_OPENVERSIONFILE);
+ }
+ return(RD_OK);
+
+}
+
+
+int32 SetLanguageVersion(uint8 version)
+
+{
+
+ languageVersion = version;
+ return(RD_OK);
+
+}
+
+
+int32 GetGameName(uint8 *name)
+
+{
+
+ uint8 version;
+ int32 rv;
+
+
+ rv = GetLanguageVersion(&version);
+
+ switch(version)
+ {
+ case ENGLISH:
+ strcpy((char *)name, "Broken Sword II");
+ break;
+ case AMERICAN:
+ strcpy((char *)name, "Circle of Blood II");
+ break;
+ case GERMAN:
+ strcpy((char *)name, "Baphomet's Fluch II");
+ break;
+ default:
+ strcpy((char *)name, "Some game or other, part 86");
+ return(RDERR_INVALIDVERSION);
+ }
+
+ return(rv);
+
+}
diff --git a/sword2/driver/menu.cpp b/sword2/driver/menu.cpp
new file mode 100644
index 0000000000..564e302375
--- /dev/null
+++ b/sword2/driver/menu.cpp
@@ -0,0 +1,570 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : menu.c
+// Created : 14th November 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the code for the driver96 menu system.
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 15-Nov-96 PRP Initial Menu functions.
+//
+// 1.1 20-Nov-96 PRP Fixed the displaying of the bottom menu.
+//
+// 1.2 08-Nov-96 PRP Made the speed of the menubar dependent upon
+// the number of icons displayed.
+//
+// 1.3 24-Jan-97 PRP Changed the creation of menu icon sprite
+// surfaces depending upon whether the hardware
+// can stretch blit or not. Also, made it so
+// that the full size icon sprite is not stretch
+// blitted.
+//
+// 1.4 10-Feb-97 PRP Changed the creation of menu icon sprite
+// surfaces as the capability bits for the drivers
+// have been changed. Also, changed the error
+// reporting code (for directDraw) so that it
+// works.
+//
+// 1.5 04-Mar-97 PRP Tried to fix bug where running out of video
+// memory creating menubar icon surfaces.
+//
+// 1.6 16-Apr-97 PRP Got rid of bug where task switching causes
+// failure of icon draw.
+//
+// 1.7 23-Jul-97 PRP Checked error value of stretched blit.
+//
+// 1.8 13-Aug-97 PRP Added CloseMenuImmediately.
+//
+// 1.9 13-Aug-97 PRP Fixed spelling of above
+//
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// int32 ProcessMenu(void)
+//
+// This function should be called regularly to process the menuber system.
+// The rate at which this function is called will dictate how smooth the menu
+// system is. The menu cannot be drawn at a higher rate than the system
+// vbl rate.
+//
+// --------------------------------------------------------------------------
+//
+// int32 ShowMenu(uint8 menu)
+//
+// This function brings the menu in to view. The choice of top or bottom menu
+// is defined by the parameter menu being either RDMENU_TOP or RDMENU_BOTTOM.
+// An error code is returned if the menu is already shown.
+//
+// --------------------------------------------------------------------------
+//
+// int32 HideMenu(uint8 menu)
+//
+// This function hides the menu defined by the parameter menu. If the menu is
+// already hidden, an error code is returned.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetMenuIcon(uint8 menu, uint8 pocket, uint8 *icon)
+//
+// This function sets a menubar icon to that passed in. If icon is NULL, the
+// pocket is cleared, otherwise, that icon is placed into pocket. The menu is
+// either RDMENU_TOP or RDMENU_BOTTOM. Valid error codes include
+// RDERR_INVALIDPOCKET if the pocket number does not exist. Initially, there
+// are 15 pockets.
+//
+// --------------------------------------------------------------------------
+//
+// uint8 GetMenuStatus(uint8 menu)
+//
+// This function returns the status of the menu passed in menu. Return values
+// are RDMENU_OPENING, RDMENU_CLOSING, RDMENU_HIDDEN and RDMENU_SHOWN.
+//
+//=============================================================================
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+//#include <mmsystem.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+#include "menu.h"
+#include "d_draw.h"
+#include "render.h"
+
+
+#define MENUDEEP 40
+#define MAXMENUANIMS 8
+
+
+
+static uint8 menuStatus[2] =
+{
+ RDMENU_HIDDEN, RDMENU_HIDDEN
+};
+
+static uint8 *icons[2][RDMENU_MAXPOCKETS] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/*
+static LPDIRECTDRAWSURFACE lpIconSurface[2][RDMENU_MAXPOCKETS] =
+{
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+*/
+
+static uint8 pocketStatus[2][RDMENU_MAXPOCKETS] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static uint8 menuCounter[2];
+static uint8 lastIcon[2];
+static uint8 iconCount = 0;
+
+
+
+
+int32 CreateIconSurface(uint8 menu, uint8 pocket)
+
+{
+ warning("stub CreatIconSurface( %d, %d )", menu, pocket);
+/*
+
+ HRESULT hr;
+ DDSURFACEDESC ddsd;
+
+
+ // Set up the direct draw surface for the icon.
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ if (dxHalCaps & RDCAPS_BLTSTRETCH)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+
+ ddsd.dwWidth = RDMENU_ICONWIDE;
+ ddsd.dwHeight = RDMENU_ICONDEEP;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &lpIconSurface[menu][pocket], NULL);
+ if ((dxHalCaps & RDCAPS_BLTSTRETCH) && (hr == DDERR_OUTOFVIDEOMEMORY))
+ {
+ ddsd.ddsCaps.dwCaps &= (0xffffffff - DDSCAPS_VIDEOMEMORY);
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &lpIconSurface[menu][pocket], NULL);
+ }
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to create icon surface", hr);
+ return(hr);
+ }
+*/
+ return(RD_OK);
+}
+
+
+
+int32 LoadIconSurface(int32 menu, int32 pocket)
+
+{
+ warning("stub LoadIconSurface( %d, %d )");
+/*
+
+ uint8 *src, *dst;
+ int32 i;
+ HRESULT hr;
+ DDSURFACEDESC ddsd;
+
+
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+
+ hr = IDirectDrawSurface2_Lock(lpIconSurface[menu][pocket], NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ IDirectDrawSurface2_Restore(lpIconSurface[menu][pocket]);
+ hr = IDirectDrawSurface2_Lock(lpIconSurface[menu][pocket], NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to lock icon surface", hr);
+ return(hr);
+ }
+ }
+
+ src = icons[menu][pocket];
+ dst = ddsd.lpSurface;
+ for (i=0; i<RDMENU_ICONDEEP; i++)
+ {
+ memcpy(dst, src, RDMENU_ICONWIDE);
+ src += RDMENU_ICONWIDE;
+ dst += ddsd.lPitch;
+ }
+
+ IDirectDrawSurface2_Unlock(lpIconSurface[menu][pocket], ddsd.lpSurface);
+*/
+ return(RD_OK);
+
+}
+
+
+
+
+int32 ProcessMenu(void)
+
+{
+ warning("stub ProcessMenu");
+/*
+
+ uint8 menu;
+ uint8 i;
+ uint8 complete;
+ uint8 frameCount;
+// uint8 *src, *dst;
+ int32 curx, xoff;
+ int32 cury, yoff;
+ HRESULT hr;
+ RECT r;
+ int32 delta;
+ static int32 lastTime = 0;
+
+ if (lastTime == 0)
+ {
+ lastTime = timeGetTime();
+ frameCount = 1;
+ }
+ else
+ {
+ delta = timeGetTime() - lastTime;
+ if (delta > 250)
+ {
+ lastTime += delta;
+ delta = 250;
+ frameCount = 1;
+ }
+ else
+ {
+ frameCount = (uint8) ((iconCount+8) * delta / 750);
+ lastTime += frameCount * 750 / (iconCount + 8);
+ }
+
+ }
+
+
+
+ while (frameCount-- > 0)
+ {
+ for (menu = RDMENU_TOP; menu <= RDMENU_BOTTOM; menu++)
+ {
+ if (menuStatus[menu] == RDMENU_OPENING)
+ {
+ // The menu is opening, so process it here
+ complete = 1;
+
+ // Propagate the animation from the first icon.
+ for (i=RDMENU_MAXPOCKETS-1; i>0; i--)
+ {
+ pocketStatus[menu][i] = pocketStatus[menu][i-1];
+ if (pocketStatus[menu][i] != MAXMENUANIMS)
+ {
+ complete = 0;
+ }
+ }
+ if (pocketStatus[menu][i] != MAXMENUANIMS)
+ complete = 0;
+
+ // ... and animate the first icon
+ if (pocketStatus[menu][0] != MAXMENUANIMS)
+ pocketStatus[menu][0] += 1;
+
+ // Check to see if the menu is fully open
+ if (complete)
+ {
+ menuStatus[menu] = RDMENU_SHOWN;
+ }
+ }
+ else if (menuStatus[menu] == RDMENU_CLOSING)
+ {
+ // The menu is closing, so process it here
+ complete = 1;
+
+ // Propagate the animation from the first icon.
+ for (i=RDMENU_MAXPOCKETS-1; i>0; i--)
+ {
+ pocketStatus[menu][i] = pocketStatus[menu][i-1];
+ if (pocketStatus[menu][i] != 0)
+ {
+ complete = 0;
+ }
+ }
+ if (pocketStatus[menu][i] != 0)
+ complete = 0;
+
+ // ... and animate the first icon
+ if (pocketStatus[menu][0] != 0)
+ pocketStatus[menu][0] -= 1;
+
+ // Check to see if the menu is fully open
+ if (complete)
+ {
+ menuStatus[menu] = RDMENU_HIDDEN;
+ }
+ }
+ }
+
+ }
+
+ // Does the menu need to be drawn?
+ for (menu = RDMENU_TOP; menu <= RDMENU_BOTTOM; menu++)
+ {
+ if (menuStatus[menu] != RDMENU_HIDDEN)
+ {
+ // Draw the menu here.
+ curx = RDMENU_ICONSTART + RDMENU_ICONWIDE / 2;
+ cury = (MENUDEEP / 2) + (RENDERDEEP + MENUDEEP) * menu;
+
+ for (i=0; i<RDMENU_MAXPOCKETS; i++)
+ {
+ if (lpIconSurface[menu][i])
+ {
+ if (pocketStatus[menu][i] == MAXMENUANIMS)
+ {
+ xoff = (RDMENU_ICONWIDE / 2);
+ r.left = curx - xoff;
+ r.right = r.left + RDMENU_ICONWIDE;
+ yoff = (RDMENU_ICONDEEP / 2);
+ r.top = cury - yoff;
+ r.bottom = r.top + RDMENU_ICONDEEP;
+ }
+ else
+ {
+ xoff = (RDMENU_ICONWIDE / 2) * pocketStatus[menu][i] / MAXMENUANIMS;
+ r.left = curx - xoff;
+ r.right = curx + xoff;
+ yoff = (RDMENU_ICONDEEP / 2) * pocketStatus[menu][i] / MAXMENUANIMS;
+ r.top = cury - yoff;
+ r.bottom = cury + yoff;
+ }
+
+ if ((xoff != 0) && (yoff != 0))
+ {
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &r, lpIconSurface[menu][i], NULL, DDBLT_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ switch (hr)
+ {
+ case DDERR_GENERIC :
+ hr = 0;
+ break;
+ case DDERR_INVALIDCLIPLIST :
+ hr = 0;
+ break;
+ case DDERR_INVALIDOBJECT :
+ hr = 0;
+ break;
+ case DDERR_INVALIDPARAMS :
+ hr = 0;
+ break;
+ case DDERR_INVALIDRECT :
+ hr = 0;
+ break;
+ case DDERR_NOALPHAHW :
+ hr = 0;
+ break;
+ case DDERR_NOBLTHW :
+ hr = 0;
+ break;
+ case DDERR_NOCLIPLIST :
+ hr = 0;
+ break;
+ case DDERR_NODDROPSHW :
+ hr = 0;
+ break;
+ case DDERR_NOMIRRORHW :
+ hr = 0;
+ break;
+ case DDERR_NORASTEROPHW :
+ hr = 0;
+ break;
+ case DDERR_NOROTATIONHW :
+ hr = 0;
+ break;
+ case DDERR_NOSTRETCHHW :
+ hr = 0;
+ break;
+ case DDERR_NOZBUFFERHW :
+ hr = 0;
+ break;
+ case DDERR_SURFACEBUSY :
+ hr = 0;
+ break;
+ case DDERR_SURFACELOST :
+ hr = 0;
+ break;
+ case DDERR_UNSUPPORTED :
+ hr = 0;
+ break;
+ default: //shit
+ hr = 0;
+ break;
+ }
+ // if (hr == DDERR_INVALIDOBJECT)
+ // {
+ CreateIconSurface(menu, i);
+ LoadIconSurface(menu, i);
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &r, lpIconSurface[menu][i], NULL, DDBLT_WAIT, NULL);
+ // }
+ if (hr != DD_OK)
+ {
+ if (hr != DDERR_SURFACELOST)
+ {
+ DirectDrawError("Unable to blt icon", hr);
+ return(hr);
+ }
+ }
+ }
+ }
+ }
+ curx += (RDMENU_ICONSPACING + RDMENU_ICONWIDE);
+ }
+ }
+ }
+*/
+}
+
+
+int32 ShowMenu(uint8 menu)
+
+{
+
+ // Check for invalid menu parameter
+ if (menu > RDMENU_BOTTOM)
+ return(RDERR_INVALIDMENU);
+
+ // Check that the menu is not currently shown, or in the process of being shown.
+ if ((menuStatus[menu] == RDMENU_SHOWN) || (menuStatus[menu] == RDMENU_OPENING))
+ return(RDERR_INVALIDCOMMAND);
+
+ menuStatus[menu] = RDMENU_OPENING;
+
+}
+
+
+int32 HideMenu(uint8 menu)
+
+{
+
+ // Check for invalid menu parameter
+ if (menu > RDMENU_BOTTOM)
+ return(RDERR_INVALIDMENU);
+
+ // Check that the menu is not currently hidden, or in the process of being hidden.
+ if ((menuStatus[menu] == RDMENU_HIDDEN) || (menuStatus[menu] == RDMENU_CLOSING))
+ return(RDERR_INVALIDCOMMAND);
+
+ menuStatus[menu] = RDMENU_CLOSING;
+
+}
+
+
+int32 CloseMenuImmediately(void)
+{
+ menuStatus[0] = RDMENU_HIDDEN;
+ menuStatus[1] = RDMENU_HIDDEN;
+ memset(pocketStatus, 0, sizeof(uint8) * 2 * RDMENU_MAXPOCKETS);
+ return (RD_OK);
+}
+
+int32 SetMenuIcon(uint8 menu, uint8 pocket, uint8 *icon)
+
+{
+ warning("stub SetMenuIcon( %d, %d )", menu, pocket);
+/*
+
+ HRESULT hr;
+
+
+ // Check for invalid menu parameter.
+ if (menu > RDMENU_BOTTOM)
+ return(RDERR_INVALIDMENU);
+
+ // Check for invalid pocket parameter
+ if (pocket >= RDMENU_MAXPOCKETS)
+ return(RDERR_INVALIDPOCKET);
+
+ // If there is an icon in the requested menu/pocket, clear it out.
+ if (icons[menu][pocket])
+ {
+ iconCount--;
+ free(icons[menu][pocket]);
+ icons[menu][pocket] = NULL;
+ IDirectDrawSurface2_Release(lpIconSurface[menu][pocket]);
+ lpIconSurface[menu][pocket] = NULL;
+ }
+
+ // Only put the icon in the pocket if it is not NULL
+ if (icon != NULL)
+ {
+ iconCount++;
+ icons[menu][pocket] = (uint8 *) malloc(RDMENU_ICONWIDE * RDMENU_ICONDEEP);
+ if (icons[menu][pocket] == NULL)
+ return(RDERR_OUTOFMEMORY);
+ memcpy(icons[menu][pocket], icon, RDMENU_ICONWIDE * RDMENU_ICONDEEP);
+
+ hr = CreateIconSurface(menu, pocket);
+ if (hr != DD_OK)
+ return(hr);
+
+ hr = LoadIconSurface(menu, pocket);
+ if (hr != RD_OK)
+ return(hr);
+ }
+*/
+}
+
+
+uint8 GetMenuStatus(uint8 menu)
+
+{
+
+ if (menu > RDMENU_BOTTOM)
+ return(RDMENU_HIDDEN);
+
+ return(menuStatus[menu]);
+
+}
+
+
+
diff --git a/sword2/driver/menu.h b/sword2/driver/menu.h
new file mode 100644
index 0000000000..de0830030e
--- /dev/null
+++ b/sword2/driver/menu.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : menu.h
+// Created : 15th November 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 15-Nov-96 PRP Internal driver interface to the menu driver
+// functions and data.
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the menu.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef MENU_H
+#define MENU_H
+
+
+#define MENUDEEP 40
+
+#endif
+
diff --git a/sword2/driver/misc.cpp b/sword2/driver/misc.cpp
new file mode 100644
index 0000000000..ce7ea76020
--- /dev/null
+++ b/sword2/driver/misc.cpp
@@ -0,0 +1,62 @@
+/* Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+#include "driver96.h"
+#include "../sword2.h"
+
+uint32 timeGetTime(void) {
+ return g_bs2->_syst->get_msecs();
+}
+
+void VirtualUnlock(uint8 *free_memman, uint32 total_free_memory) {
+ warning("stub VirtualUnlock");
+}
+
+void GlobalMemoryStatus(MEMORYSTATUS *memo) {
+ warning("stub GlobalMemoryStatus");
+ memo->dwTotalPhys = 16000*1024; // hard code 16mb for now
+}
+
+void SetFileAttributes(char *file, uint32 atrib) {
+ warning("stub SetFileAttributes");
+}
+
+void DeleteFile(char *file) {
+ warning("stub DeleteFile");
+}
+
+void GetCurrentDirectory(uint32 max, char* path) {
+ warning("stub GetCurrentDirectory");
+}
+
+int32 GetVolumeInformation(char *cdPath, char *sCDName, uint32 maxPath, uint8 *, DWORD *dwMaxCompLength, DWORD *dwFSFlags, uint8 *, uint32 a) {
+ warning("stub GetVolumeInformation %s", cdPath);
+ strcpy(sCDName, CD1_LABEL);
+ return 1;
+}
+
+// FIXME wrap different platform specific mkdir calls and actually do something
+void _mkdir(const char *pathname) {
+ warning("stub _mkdir %s", pathname);
+}
+
+void GetModuleFileName(void *module, char *destStr, uint32 maxLen) {
+ warning("stub GetModuleFileName");
+}
+
diff --git a/sword2/driver/palette.cpp b/sword2/driver/palette.cpp
new file mode 100644
index 0000000000..5847cfff6b
--- /dev/null
+++ b/sword2/driver/palette.cpp
@@ -0,0 +1,482 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : palette.c
+// Created : 22nd August 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the palette functions and the interface
+// to the directDraw palette.
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 16-Sep-96 PRP Currently holds the palette setting code. Will
+// be modified so that the calling functions have
+// to use the correct palette format, and the
+// fading code will be added.
+//
+// 1.1 17-Sep-96 PRP Removed utypes.h from include list.
+//
+// 1.2 03-Oct-96 PRP Changed the palette format to RGBA 0-255.
+//
+// 1.3 04-Oct-96 PRP No changes
+//
+// 1.4 04-Oct-96 PRP Put direct path in for ddraw.h
+//
+// 1.5 08-Nov-96 PRP Created a drivers copy of the palette so that
+// it can be restored at any time without the
+// game engine having to worry about things.
+// Currently, there is different code for setting
+// the palette in full screen and windowed mode
+// until I can get windowed mode working.
+//
+// 1.6 09-Nov-96 PRP More work to get the palette to work propery
+// in windowed mode.
+//
+// 1.7 22-Nov-96 PRP Made the whole of the palette available to
+// the rest of the driver96 code.
+//
+// 1.8 25-Nov-96 PRP Added a function to create a palette match
+// table from the current palette.
+//
+// 1.9 29-Nov-96 PRP Made the QuickMatch function __inline for
+// speed - but didn't work. Added functions
+// to fade the palette up and down.
+//
+// 1.10 05-Dec-96 PRP Added a flag to SetPalette so that the palette
+// can be set immediately or later by the fade.
+//
+// 1.11 06-Dec-96 JEL fadeStatus now initialised to 0
+//
+// 1.12 09-Dec-96 PRP Function UpdatePaletteMatchTable() changed so
+// that the data can be part of another file.
+//
+// 1.13 10-Feb-97 PRP Changed the direct draw error reporting calls.
+//
+// 1.14 11-Feb-97 PRP Suspended the fade server if the direct draw
+// palette object does not exist.
+//
+// 1.15 17-Mar-97 PRP Added RDFADE_BLACK as a return value so the
+// engine knows the state of the palette when
+// there is no fade.
+//
+// 1.16 17-Mar-97 PRP Fixed driver bug which caused FadeUp to fail
+// becuase of the introduction of RDFADE_BLACK.
+//
+// 1.17 26-Jun-97 PRP Added a function to darken the palette for pausing.
+//
+// 1.18 26-Jun-97 PRP Forgot to return a value.
+//
+// 1.19 26-Jun-97 PRP Forgot to set the palette - DOH!
+//
+// 1.20 26-Jun-97 PRP Fixed undefined symbols bugs.
+//
+// 1.21 09-Jul-97 JEL Fixed palette dimming - to unsigned rather than signed RGB values!
+//
+// 1.22 26-Jun-97 JEL SetPalette now always sets colour 0 to black so doesn't need setting to black from game engine
+//
+// 1.23 10-Jul-97 JEL Nothing changed but new version had to be booked in anyway.
+//
+// 1.24 10-Jul-97 JEL SetPalette doesn't do that any more (see above)!
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// void SetPalette(int32 startEntry, int32 noEntries, uint8 *colourTable)
+//
+// Sets the palette from position startEntry for noEntries, to the data
+// pointed to by colourTable.
+//
+// --------------------------------------------------------------------------
+//
+// void UpdatePaletteMatchTable(uint8 *data)
+//
+// Uses the current palCopy to create a table of palette indeces which will
+// be searched later for a quick palette match, if data is NULL. Otherwise
+// it uses the table passed in.
+//
+// --------------------------------------------------------------------------
+//
+// uint8 QuickMatch(uint8 r, uint8 g, uint8 b)
+//
+// Returns the palette index of the closest matching colour in the palette
+// to these RGB values.
+//
+// --------------------------------------------------------------------------
+//
+// int32 FadeUp(float time)
+//
+// Fades the palette up from black to the current palette in time.
+//
+// --------------------------------------------------------------------------
+//
+// int32 FadeDown(float time)
+//
+// Fades the palette down to black from the current palette in time.
+//
+// --------------------------------------------------------------------------
+//
+// uint8 GetFadeStatus(void)
+//
+// Returns the fade status which can be one of RDFADE_UP, RDFADE_DOWN or
+// RDFADE_NONE.
+//
+//=============================================================================
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+#include <stdio.h>
+//#include <mmsystem.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+#include "d_draw.h"
+
+#define PALTABLESIZE 64*64*64
+
+
+uint8 palCopy[256][4];
+uint8 fadePalette[256][4];
+
+uint8 paletteMatch[PALTABLESIZE];
+
+uint8 fadeStatus=0;
+
+static int32 fadeStartTime;
+static int32 fadeTotalTime;
+
+
+// --------------------------------------------------------------------------
+// int32 RestorePalette(void)
+//
+// This function restores the palette, and should be called whenever the
+// screen mode changes, or something like that.
+// --------------------------------------------------------------------------
+int32 RestorePalette(void)
+
+{
+ warning("stub RestorePalette");
+/*
+ int32 hr;
+
+
+ if (bFullScreen)
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 0, 256, (LPPALETTEENTRY) &palCopy[0][0]);
+ else
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 10, 236, (LPPALETTEENTRY) &palCopy[10][0]);
+
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to restore palette", hr);
+ return(hr);
+ }
+
+*/
+ return(RD_OK);
+
+}
+
+
+uint8 GetMatch(uint8 r, uint8 g, uint8 b)
+
+{
+
+ int32 diff;
+ int32 min;
+ int16 diffred, diffgreen, diffblue;
+ int16 i;
+ uint8 minIndex;
+
+
+ diffred = palCopy[0][0] - r;
+ diffgreen = palCopy[0][1] - g;
+ diffblue = palCopy[0][2] - b;
+
+ diff = diffred * diffred + diffgreen * diffgreen + diffblue * diffblue;
+ min = diff;
+ minIndex = 0;
+ if (diff > 0)
+ {
+ i = 1;
+ while (i < 256)
+ {
+ diffred = palCopy[i][0] - r;
+ diffgreen = palCopy[i][1] - g;
+ diffblue = palCopy[i][2] - b;
+
+ diff = diffred * diffred + diffgreen * diffgreen + diffblue * diffblue;
+ if (diff < min)
+ {
+ min = diff;
+ minIndex = (uint8) i;
+ if (min == 0)
+ break;
+ }
+ i += 1;
+ }
+ }
+
+ // Here, minIndex is the index of the matchpalette which is closest.
+ return(minIndex);
+
+}
+
+
+
+int32 UpdatePaletteMatchTable(uint8 *data)
+
+{
+
+ if (data == NULL)
+
+ // Create palette match table
+ {
+ FILE *fp;
+ int16 red, green, blue;
+ uint8 *p;
+
+ p = &paletteMatch[0];
+ for (red = 0; red < 256; red += 4)
+ {
+ for (green = 0; green < 256; green += 4)
+ {
+ for (blue = 0; blue < 256; blue += 4)
+ {
+ *p++ = GetMatch((uint8) red, (uint8) green, (uint8) blue);
+ }
+ }
+ }
+
+ // Write out palette match table
+ fp = fopen("r11.rgb", "wb");
+ if (fp == NULL)
+ return(RDERR_INVALIDFILENAME);
+ if (fwrite(paletteMatch, 1, 64*64*64, fp) != 64*64*64)
+ return(RDERR_WRITEERROR);
+ fclose(fp);
+ }
+ else
+ // Read table from file
+ {
+
+ memcpy(paletteMatch, data, PALTABLESIZE);
+
+/*
+ FILE *fp;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL)
+ return(RDERR_INVALIDFILENAME);
+ if (fread(paletteMatch, 1, 64*64*64, fp) != 64*64*64)
+ return(RDERR_READERROR);
+ fclose(fp);
+ return(RD_OK);
+*/
+ }
+ return(RD_OK);
+
+}
+
+
+
+__inline uint8 QuickMatch(uint8 r, uint8 g, uint8 b)
+
+{
+ return(paletteMatch[((int32) (r >> 2) << 12) + ((int32) (g >> 2) << 6) + (b >> 2)]);
+}
+
+
+
+
+int32 SetPalette(int16 startEntry, int16 noEntries, uint8 *colourTable, uint8 fadeNow)
+
+{
+ warning("stub SetPalette( %d, %d, %d )", startEntry, noEntries, fadeNow);
+/*
+
+ int32 hr;
+
+ if (noEntries == 0)
+ {
+ RestorePalette();
+ return(RD_OK);
+ }
+
+
+ memcpy(&palCopy[startEntry][0], colourTable, noEntries * 4);
+
+ if ((lpPalette) && (fadeNow == RDPAL_INSTANT))
+ {
+ if (bFullScreen)
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, startEntry, noEntries, (LPPALETTEENTRY) &palCopy[startEntry][0]);
+ else
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 10, 236, (LPPALETTEENTRY) &palCopy[10][0]);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Unable to set palette entries", hr);
+ return(hr);
+ }
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 DimPalette(void)
+{
+ warning("stub DimpPalette");
+/*
+ uint8 *p;
+ uint32 i;
+
+ p = (uint8*) &palCopy[0][0];
+ for (i=0; i<256*4; i++)
+ {
+ *p++ /= 2;
+ }
+ if (lpPalette)
+ IDirectDrawPalette_SetEntries(lpPalette, 0, 0, 256, (LPPALETTEENTRY) &palCopy[0][0]);
+*/
+ return RD_OK;
+
+}
+
+
+
+int32 FadeUp(float time)
+
+{
+
+ if ((fadeStatus != RDFADE_BLACK) && (fadeStatus != RDFADE_NONE))
+ return(RDERR_FADEINCOMPLETE);
+
+ fadeTotalTime = (int32) (time * 1000);
+ fadeStatus = RDFADE_UP;
+ fadeStartTime = timeGetTime();
+
+}
+
+
+int32 FadeDown(float time)
+
+{
+
+ if ((fadeStatus != RDFADE_BLACK) && (fadeStatus != RDFADE_NONE))
+ return(RDERR_FADEINCOMPLETE);
+
+ fadeTotalTime = (int32) (time * 1000);
+ fadeStatus = RDFADE_DOWN;
+ fadeStartTime = timeGetTime();
+
+}
+
+
+uint8 GetFadeStatus(void)
+{
+ return(fadeStatus);
+}
+
+
+void FadeServer(void)
+
+{
+ warning("stub FadeServer");
+/*
+ int32 currentTime;
+ int16 fadeMultiplier;
+ int16 i;
+ HRESULT hr;
+
+
+ if (lpPalette == NULL)
+ return;
+
+ if (fadeStatus)
+ {
+ if (fadeStatus == RDFADE_UP)
+ {
+ currentTime = timeGetTime();
+ if (currentTime >= fadeStartTime + fadeTotalTime)
+ {
+ fadeStatus = RDFADE_NONE;
+ if (bFullScreen)
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 0, 256, (LPPALETTEENTRY) &palCopy[0][0]);
+ else
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 10, 236, (LPPALETTEENTRY) &palCopy[10][0]);
+ }
+ else
+ {
+ fadeMultiplier = (int16) (((int32) (currentTime - fadeStartTime) * 256) / fadeTotalTime);
+ for (i=0; i<256; i++)
+ {
+ fadePalette[i][0] = (palCopy[i][0] * fadeMultiplier) >> 8;
+ fadePalette[i][1] = (palCopy[i][1] * fadeMultiplier) >> 8;
+ fadePalette[i][2] = (palCopy[i][2] * fadeMultiplier) >> 8;
+ }
+ if (bFullScreen)
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 0, 256, (LPPALETTEENTRY) &fadePalette[0][0]);
+ else
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 10, 236, (LPPALETTEENTRY) &fadePalette[10][0]);
+ }
+ }
+ else if (fadeStatus == RDFADE_DOWN)
+ {
+ currentTime = timeGetTime();
+ if (currentTime >= fadeStartTime + fadeTotalTime)
+ {
+ for (i=0; i<256; i++)
+ {
+ fadePalette[i][0] = 0;
+ fadePalette[i][1] = 0;
+ fadePalette[i][2] = 0;
+ }
+ fadeStatus = RDFADE_BLACK;
+ if (bFullScreen)
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 0, 256, (LPPALETTEENTRY) &fadePalette[0][0]);
+ else
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 10, 236, (LPPALETTEENTRY) &fadePalette[10][0]);
+ }
+ else
+ {
+ fadeMultiplier = (int16) (((int32) (fadeTotalTime - (currentTime - fadeStartTime)) * 256) / fadeTotalTime);
+ for (i=0; i<256; i++)
+ {
+ fadePalette[i][0] = (palCopy[i][0] * fadeMultiplier) >> 8;
+ fadePalette[i][1] = (palCopy[i][1] * fadeMultiplier) >> 8;
+ fadePalette[i][2] = (palCopy[i][2] * fadeMultiplier) >> 8;
+ }
+ if (bFullScreen)
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 0, 256, (LPPALETTEENTRY) &fadePalette[0][0]);
+ else
+ hr = IDirectDrawPalette_SetEntries(lpPalette, 0, 10, 236, (LPPALETTEENTRY) &fadePalette[10][0]);
+ }
+ }
+ }
+*/
+}
+
diff --git a/sword2/driver/palette.h b/sword2/driver/palette.h
new file mode 100644
index 0000000000..3e26bd89a2
--- /dev/null
+++ b/sword2/driver/palette.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : palette.h
+// Created : 8th November 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 08-Nov-96 PRP Internal driver interface to the palette
+// functions and data.
+//
+// 1.1 11-Nov-96 PRP Added internal driver reference for
+// RestorePalette which should be called by the
+// windows message handler whenever the window
+// has been minimised/maximised.
+//
+// 1.2 22-Nov-96 PRP Made the palette available to the rest of the
+// driver96 library.
+//
+// 1.3 29-Nov-96 PRP Made paletteMatch table available to other
+// parts of the driver library. Also, made the
+// FadeServer available for the windows module
+// to have access.
+//
+// 1.4 11-Apr-97 CJR Moved palCopy to driver96.h for use in the
+// game engine.
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the palette.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef PALETTE_H
+#define PALETTE_H
+
+extern uint8 paletteMatch[64*64*64];
+
+extern int32 RestorePalette(void);
+extern void FadeServer(void);
+
+
+#endif
+
diff --git a/sword2/driver/rdwin.cpp b/sword2/driver/rdwin.cpp
new file mode 100644
index 0000000000..f945b3ca14
--- /dev/null
+++ b/sword2/driver/rdwin.cpp
@@ -0,0 +1,627 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+#include <stdio.h>
+
+#include "common/stdafx.h"
+#include "engine.h"
+
+#include "driver96.h"
+
+#include "_mouse.h"
+#include "keyboard.h"
+#include "rdwin.h"
+#include "d_draw.h"
+#include "palette.h"
+#include "render.h"
+#include "menu.h"
+#include "d_sound.h"
+#include "../sword2.h"
+
+
+#define MENUDEEP 40 // Temporary, until menu.h is written!
+
+
+
+static BOOL bMouseVisible = FALSE;
+static BOOL controlKey = FALSE;
+static BOOL altKey = FALSE;
+static BOOL wasScreenSaverActive = FALSE;
+static BOOL myAppClosed = FALSE;
+static BOOL controlQDisabled = FALSE;
+static uint8 gameName[80];
+
+
+//BOOL gotTheFocus = FALSE;
+//assume we always have focus for the time being - khalek
+BOOL gotTheFocus = TRUE;
+//HWND hwnd;
+//RECT rcWindow;
+
+
+
+//-----------------------------------------------------------------------------
+
+void Zdebug(char *format,...) {
+#ifdef __PALM_OS__
+ char buf[256]; // 1024 is too big overflow the stack
+#else
+ char buf[1024];
+#endif
+ va_list va;
+
+ va_start(va, format);
+ vsprintf(buf, format, va);
+ va_end(va);
+
+#ifdef __GP32__ //ph0x FIXME: implement fprint?
+ printf("ZDEBUG: %s\n", buf);
+#else
+ fprintf(stderr, "ZDEBUG: %s!\n", buf);
+#endif
+#if defined( USE_WINDBG )
+ strcat(buf, "\n");
+#if defined( _WIN32_WCE )
+ TCHAR buf_unicode[1024];
+ MultiByteToWideChar(CP_ACP, 0, buf, strlen(buf) + 1, buf_unicode, sizeof(buf_unicode));
+ OutputDebugString(buf_unicode);
+#else
+ OutputDebugString(buf);
+#endif
+#endif
+}
+
+/*
+void Zdebug(char *format,...) //Tony's special debug logging file March96
+{
+ warning("stub Zdebug");
+// Write a printf type string to a debug file
+
+ va_list arg_ptr; // Variable argument pointer
+ FILE * debug_filep=0; // Debug file pointer
+ static int first_debug = 1; // Flag for first time this is used
+
+ va_start(arg_ptr,format);
+
+ if (first_debug) //First time round delete any previous debug file
+ {
+ unlink("debug.txt");
+ first_debug = 0;
+ }
+
+ debug_filep = fopen("debug.txt","a+t");
+
+ if (debug_filep != NULL) // if it could be opened
+ {
+ vfprintf(debug_filep, format, arg_ptr);
+ fprintf(debug_filep,"\n");
+
+ fclose(debug_filep);
+ }
+}
+*/
+//-----------------------------------------------------------------------------
+
+/*
+void Message(LPSTR fmt, ...)
+{
+ char buff[256];
+ va_list va;
+
+
+ va_start(va, fmt);
+
+ //
+ // format message with header
+ //
+ lstrcpy( buff, "DRIVER96:" );
+ wvsprintf( &buff[lstrlen(buff)], fmt, va );
+ lstrcat( buff, "\r\n" );
+
+ //
+ // To the debugger
+ //
+ OutputDebugString( buff );
+
+}
+*/
+
+//-----------------------------------------------------------------------------
+// OSystem Event Handler. Full of cross platform goodness and 99% fat free!
+//-----------------------------------------------------------------------------
+void BS2State::parseEvents() {
+ OSystem::Event event;
+
+ while (_system->poll_event(&event)) {
+ switch(event.event_code) {
+
+ case OSystem::EVENT_KEYDOWN:
+ Zdebug("key %d", event.kbd.keycode);
+
+ if (event.kbd.flags==OSystem::KBD_CTRL) {
+ if (event.kbd.keycode == 'w')
+ GrabScreenShot();
+ }
+ WriteKey(event.kbd.keycode);
+
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ mousex = event.mouse.x;
+ mousey = event.mouse.y;
+ _syst->set_mouse_pos(event.mouse.x, event.mouse.y);
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ LogMouseEvent(RD_LEFTBUTTONDOWN);
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ LogMouseEvent(RD_RIGHTBUTTONDOWN);
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ LogMouseEvent(RD_LEFTBUTTONUP);
+ break;
+ case OSystem::EVENT_RBUTTONUP:
+ LogMouseEvent(RD_RIGHTBUTTONUP);
+ break;
+ case OSystem::EVENT_QUIT:
+ Close_game();
+ RestoreDisplay();
+ CloseAppWindow();
+ break;
+ default:
+ break;
+ }
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Windows Message Handler. All keyboard and mouse input is handled here.
+//-----------------------------------------------------------------------------
+/*
+long FAR PASCAL WindowsMessageHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+
+ switch( message )
+ {
+
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 25:
+ FadeServer();
+ return(0);
+ case 1:
+ FxServer();
+ return(0);
+ }
+ break;
+
+
+ case WM_CLOSE:
+ Zdebug("WM_CLOSE");
+ break;
+
+ case WM_SIZE:
+ case WM_MOVE:
+ if (IsIconic(hwnd))
+ {
+ Message("minimising");
+// PauseGame();
+ }
+
+ if (bFullScreen)
+ {
+ SetRect(&rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
+ }
+ else
+ {
+ GetClientRect(hwnd, &rcWindow);
+ ClientToScreen(hwnd, (LPPOINT)&rcWindow);
+ ClientToScreen(hwnd, (LPPOINT)&rcWindow+1);
+ }
+ Message("WINDOW RECT: [%d,%d,%d,%d]", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
+ if (bFullScreen)
+ {
+ SetCapture(hwnd);
+ }
+ else
+ {
+ ReleaseCapture();
+ }
+// SetCursor(NULL);
+// ShowCursor(FALSE);
+ break;
+
+
+
+ case WM_ACTIVATEAPP:
+ gotTheFocus = wParam;
+ if (gotTheFocus)
+ {
+ Message("Got the focus");
+ bMouseVisible = FALSE;
+ Message("Mouse invisible");
+ ShowCursor(FALSE);
+ }
+ else
+ {
+ if (bMouseVisible == FALSE)
+ ShowCursor(TRUE);
+ Message("Lost the focus");
+ bMouseVisible = TRUE;
+ Message("Mouse visible");
+ }
+ break;
+
+
+ case WM_SYSKEYUP:
+ switch( wParam )
+ {
+
+// int32 rv;
+
+ // handle ALT+ENTER (fullscreen)
+ case VK_RETURN:
+ break;
+ }
+ break;
+
+
+ case WM_DISPLAYCHANGE:
+ break;
+
+ case WM_CREATE:
+ SystemParametersInfo(SPI_GETSCREENSAVEACTIVE , 0 , &wasScreenSaverActive , 0);
+ if (wasScreenSaverActive)
+ {
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE , FALSE , 0 , 0 );
+ }
+ break;
+
+
+ case WM_QUERYNEWPALETTE:
+ //
+ // we are getting the palette focus, select our palette
+ //
+ if (!bFullScreen && lpPalette && lpPrimarySurface)
+ {
+ int32 hr;
+
+ hr = IDirectDrawSurface_SetPalette(lpPrimarySurface, lpPalette);
+ if (hr == DDERR_SURFACELOST)
+ {
+ IDirectDrawSurface_Restore(lpPrimarySurface);
+
+ hr= IDirectDrawSurface_SetPalette(lpPrimarySurface, lpPalette);
+ if(hr == DDERR_SURFACELOST)
+ {
+ Message("Failed to restore palette after second try");
+ }
+ }
+
+ //
+ // Restore normal title if palette is ours
+ //
+ if(hr == DD_OK)
+ {
+ SetWindowText(hwnd, gameName);
+ }
+ }
+ break;
+
+ case WM_PALETTECHANGED:
+ //
+ // if another app changed the palette we dont have full control
+ // of the palette. NOTE this only applies for FoxBear in a window
+ // when we are fullscreen we get all the palette all of the time.
+ //
+ if ((HWND)wParam != hwnd)
+ {
+ if( !bFullScreen )
+ {
+ Message("Lost palette but continuing");
+ }
+ }
+ break;
+
+
+// case WM_SETCURSOR:
+// if (bMouseVisible)
+// SetCursor(LoadCursor(NULL, IDC_ARROW));
+// else
+// SetCursor(NULL);
+// return TRUE;
+// break;
+
+ case WM_CHAR:
+ if (lParam & (1 << 30))
+ return(0);
+ WriteKey((char) (wParam & 0xff));
+ return(0);
+
+ case WM_KEYDOWN:
+
+ Zdebug("key %d", wParam);
+
+ switch( wParam )
+ {
+ case VK_CONTROL:
+ controlKey = TRUE;
+ break;
+
+// case VK_ALT:
+// altKey = TRUE;
+// break;
+
+ case 'W':
+ if (controlKey)
+ GrabScreenShot();
+ return 0;
+
+ case 'Q':
+ if (controlKey && !controlQDisabled)
+ DestroyWindow( hWnd );
+ return 0;
+
+ case 'F4':
+ DestroyWindow( hWnd );
+ return 0;
+
+ }
+ break;
+
+
+ case WM_KEYUP:
+ switch(wParam)
+ {
+ case VK_CONTROL:
+ controlKey = FALSE;
+ break;
+
+// case VK_ALT:
+// altKey = FALSE;
+// break;
+
+ }
+ break;
+
+
+ case WM_DESTROY:
+ Zdebug("*destroy*");
+
+ if (wasScreenSaverActive)
+ SystemParametersInfo(SPI_SETSCREENSAVEACTIVE , TRUE , 0 , 0 );
+ PostQuitMessage( 0 );
+ break;
+
+
+ case WM_MOUSEMOVE:
+ mousex = lParam & 0xffff;
+
+ if (bFullScreen)
+ {
+ mousey = (uint16) (lParam >> 16) - MENUDEEP;
+ }
+ else
+ {
+ mousey = (uint16) (lParam >> 16) - MENUDEEP;
+
+ if (mousex < 0)
+ mousex = 0;
+ if (mousex >= RENDERWIDE)
+ mousex = RENDERWIDE-1;
+ }
+
+ if (mousey < -MENUDEEP)
+ mousey = -MENUDEEP;
+ if (mousey >= RENDERDEEP + MENUDEEP)
+ mousey = RENDERDEEP + MENUDEEP - 1;
+
+ return(0);
+
+ case WM_LBUTTONDOWN:
+ LogMouseEvent(RD_LEFTBUTTONDOWN);
+ return(0);
+
+ case WM_LBUTTONUP:
+ LogMouseEvent(RD_LEFTBUTTONUP);
+ return(0);
+
+ case WM_RBUTTONDOWN:
+ LogMouseEvent(RD_RIGHTBUTTONDOWN);
+ return(0);
+
+ case WM_RBUTTONUP:
+ LogMouseEvent(RD_RIGHTBUTTONUP);
+ return(0);
+
+ case WM_LBUTTONDBLCLK:
+ LogMouseEvent(RD_LEFTBUTTONDOWN);
+ return(0);
+
+ case WM_RBUTTONDBLCLK:
+ LogMouseEvent(RD_RIGHTBUTTONDOWN);
+
+
+ case WM_SYSCOMMAND:
+ if (gotTheFocus)
+ return(0);
+
+
+
+
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+
+}
+*/
+
+
+/*
+int32 InitialiseWindow(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, char *gameName)
+
+{
+
+ WNDCLASS wc;
+// uint32 err;
+
+
+// hPrevInstance = hPrevInstance;
+ wc.style = CS_DBLCLKS;
+ wc.lpfnWndProc = WindowsMessageHandler;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon( hInstance, "resourc1"); //IDI_APPLICATION );
+ wc.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wc.hbrBackground = GetStockObject(BLACK_BRUSH);
+
+ wc.lpszMenuName = gameName;
+ wc.lpszClassName = gameName;
+
+ RegisterClass( &wc );
+
+ // Create a window
+ hwnd = CreateWindowEx(WS_EX_APPWINDOW, gameName, gameName, WS_VISIBLE | WS_SYSMENU | WS_POPUP, 0, 0,
+ GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ),
+ NULL, NULL, hInstance, NULL );
+
+ if(!hwnd)
+ {
+ MessageBox(hwnd, "Failed to create window", gameName, MB_OK );
+ DestroyWindow(hwnd);
+ return(RDERR_CREATEWINDOW);
+ }
+
+// ShowWindow(hwnd, nCmdShow);
+ UpdateWindow(hwnd);
+ SetFocus(hwnd);
+
+ SetTimer(hwnd, 25, 1000 / 25, NULL);
+ SetTimer(hwnd, 1, 100, NULL);
+
+ return(RD_OK);
+
+}
+*/
+
+
+int32 CloseAppWindow(void)
+
+{
+ warning("stub CloseAppWindow");
+/*
+ DestroyWindow(hwnd);
+*/
+ // just quit for now
+ g_bs2->_syst->quit();
+ return(RD_OK);
+
+}
+
+
+
+int32 ServiceWindows(void)
+
+{
+ g_bs2->parseEvents();
+// warning("stub ServiceWindows"); // too noisy
+/*
+ MSG msg;
+
+ if (myAppClosed)
+ return(RDERR_APPCLOSED);
+
+ while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if (!GetMessage(&msg, NULL, 0, 0))
+ {
+ myAppClosed = TRUE;
+ return(RDERR_APPCLOSED);
+ }
+
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+
+
+int32 _ReportDriverError(int32 error, uint8 *filename, uint32 line)
+
+{
+ warning("stub _ReportDriverError 0x%.8x file: %s, line: %d ", error, (char *) filename, line);
+/*
+
+ char errorText[128];
+ char name[80];
+
+
+ GetGameName(name);
+ sprintf(errorText, "Fatal error in %s, line %u! Code 0x%.8x", filename, line, error);
+ MessageBox(hwnd, errorText, name, MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE);
+*/
+ return(RD_OK);
+
+}
+
+
+
+int32 _ReportFatalError(uint8 *error, uint8 *filename, uint32 line)
+
+{
+
+ warning("stub _ReportFatalError");
+ char errorText[500];
+ char name[80];
+
+
+ GetGameName((uint8 *)name);
+ sprintf(errorText, "FATAL ERROR - GAME TERMINATED\n%s", error);
+ //MessageBox(hwnd, errorText, name, MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE);
+ warning("%s", errorText);
+
+ return(RD_OK);
+
+}
+
+
+int32 DisableQuitKey(void)
+{
+ controlQDisabled = TRUE;
+ return(RD_OK);
+}
+
+void SetWindowName(const char *windowName)
+{
+ warning("stub SetWindowName( %s )", windowName);
+// SetWindowText(hwnd,windowName);
+// strcpy(gameName,windowName);
+}
diff --git a/sword2/driver/rdwin.h b/sword2/driver/rdwin.h
new file mode 100644
index 0000000000..e176f9a40b
--- /dev/null
+++ b/sword2/driver/rdwin.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : rdwin.h
+// Created : 20th August 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 16-Sep-96 PRP Driver interface to the rdwin functions/data
+//
+// 1.1 07-Nov-96 PRP Added debug windows message handler, and RECT
+// defining the size of the current window.
+//
+// 1.2 04-Apr-97 PRP Oops - no changes
+//
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the rdwin.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef RDWIN_H
+#define RDWIN_H
+
+/*
+extern HWND hwnd; // handle to the current window
+extern RECT rcWindow; // size of the current window.
+
+extern void Message(LPSTR fmt, ...);
+*/
+
+
+#endif
diff --git a/sword2/driver/render.cpp b/sword2/driver/render.cpp
new file mode 100644
index 0000000000..589a86e2ab
--- /dev/null
+++ b/sword2/driver/render.cpp
@@ -0,0 +1,1283 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : render.c
+// Created : 26th September 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the functions which deal with rendering
+// the background and parallax layers, and controlling the
+// speed of the scroll (number of frames)
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 26-Sep-96 PRP The functions have been moved here from d_draw
+// because this is a more sensible place for them.
+//
+// 1.1 04-Oct-96 PRP Added direct path to ddraw.h
+//
+// 1.2 09-Oct-96 PRP Moved SOFTWARE_SCREEN_BUFFER into driver96.h,
+// and renamed to RD_SOFTWARESCREENBUFFER.
+//
+// 1.3 23-Oct-96 PRP Moved definition of _parallaxLine structure to
+// render.h. Got rid of the divide by zero error.
+//
+// 1.4 05-Nov-96 PRP Moved defines of RENDERWIDE, RENDERDEEP, etc.,
+// to render.h
+//
+// 1.5 15-Nov-96 PRP Definition of menu size is now obtained from
+// menu.h
+//
+// 1.6 18-Nov-96 PRP Changed the direct draw interface to
+// IDirectDraw2. Added the PlotPoint and
+// DrawLine functions.
+//
+// 1,7 21-Nov-96 PRP Implemented the DrawLine function.
+//
+// 1.8 24-Jan-97 PRP Added parallaxScrollx and parallaxScrolly to
+// define the offset for linking sprites to
+// parallax layers.
+//
+// 1.9 06-Feb-97 PRP Added rendering functions to draw from display
+// memory. Made the code switchable so that if
+// the hardware is not available, the old software
+// rendering functions are used.
+//
+// 1.10 06-Feb-97 PRP Fixed a bug with releasing the surfaces for a
+// room.
+//
+// 1.11 06-Feb-97 PRP Implemented PlotPoint and DrawLine for hardware
+// version.
+//
+// 1.12 07-Feb-97 PRP Implemented function to restore the background
+// layers. Changed the layer rendering code to
+// restore the layers when they've gone.
+//
+// 1.13 07-Feb-97 PRP Fixed a bug in the layer renderer, which
+// dropped out when the first block in a layer was
+// blank.
+//
+// 1.14 10-Feb-97 PRP Changed the calls to the direct draw error
+// reporting code, and made the rendering dependant
+// upon the hardware functions availability.
+//
+// 1.15 12-Feb-97 PRP Fixed rendering position bug.
+//
+// 1.16 18-Mar-97 PRP Fixed the smooth scroll, and render timing.
+// Added a function to initialise the render timer
+//
+// 1.17 18-Mar-97 PRP Added code to profile the rendering functions.
+//
+// 1.18 04-Apr-97 PRP Restored the primary surface and back buffer
+// before the parallax layers.
+//
+// 1.19 07-Apr-97 PRP No changes.
+//
+// 1.20 08-Apr-97 JEL Made location wide and location deep global.
+//
+// 1.21 10-Apr-97 PRP Added the return value RDERR_LOCKFAILED to
+// the CopyScreenBuffer function.
+//
+// 1.22 11-Apr-97 PRP Added function to clear the software render
+// buffer.
+//
+// 1.23 11-Apr-97 PRP Fixed benign redefinition of type bug
+//
+// 1.24 13-Jun-97 PRP Fixed switching between hardware and software
+// rendering during gameplay.
+//
+// 1.25 30-Jun-97 JEL Tried to fix sc23 sprite position bug, but no changes made in the end
+//
+// 1.26 08-July-97 JEL Fixed bug in RenderParallax for when not gotTheFocus, to prevent crash when switching task in NT
+//
+// Functions
+// ---------
+//
+// ---------------------------------------------------------------------------
+//
+// int32 RenderParallax(_parallax *p, int16 layer)
+//
+// Draws a parallax layer at the current position determined by the scroll.
+// A parallax can be either foreground, background or the main screen.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 CopyScreenBuffer(void)
+//
+// Copies the screen buffer to screen memory. This function should be called
+// when the drawing should be done to the back buffer. It only does this
+// when we are using a software screen buffer.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 SetScrollTarget(int16 sx, int16 sy)
+//
+// Sets the scroll target position for the end of the game cycle. The drivers
+// will then automatically scroll as many times as it can to reach this
+// position in the allotted time.
+//
+// --------------------------------------------------------------------------
+//
+// int32 StartRenderCycle(void)
+//
+// This function should be called when the game engine is ready to start
+// the render cycle.
+//
+// --------------------------------------------------------------------------
+//
+// int32 EndRenderCycle(BOOL *end)
+//
+// This function should be called at the end of the render cycle. If the
+// render cycle is to be terminated, the function sets *end to 1. Otherwise,
+// the render cycle should continue.
+//
+// --------------------------------------------------------------------------
+//
+// int32 SetLocationMetrics(uint16 w, uint16 h)
+//
+// This function tells the drivers the size of the background screen for the
+// current location.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlotPoint(uint16 x, uint16 y, uint8 colour)
+//
+// Plots the point x,y in relation to the top left corner of the background.
+//
+// --------------------------------------------------------------------------
+//
+// int32 DrawLine(int16 x1, int16 y1, int16 x2, int16 y2, uint8 colour)
+//
+// Draws a line from the point x1,y1 to x2,y2 of the specified colour.
+//
+// --------------------------------------------------------------------------
+//
+// int32 InitialiseBackgroundLayer(_parallax *p)
+//
+// 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 CloseBackgroundLayer(void)
+//
+// Should be called once after leaving a room to free up video memory.
+//
+// --------------------------------------------------------------------------
+//
+// int32 PlotDots(int16 x, int16 y, int16 count)
+//
+// Plots 'count' dots at the position x,y.
+//
+//=============================================================================
+
+
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+//#include <mmsystem.h>
+#include <stdio.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+#include "d_draw.h"
+#include "rdwin.h"
+#include "_mouse.h"
+#include "render.h"
+#include "menu.h"
+
+
+
+#define MILLISECSPERCYCLE 83
+
+
+
+#if PROFILING == 1
+int32 profileCopyScreenBuffer = 0;
+int32 profileRenderLayers = 0;
+int32 profileSpriteRender = 0;
+int32 profileDecompression = 0;
+#endif
+
+
+
+
+uint8 myScreenBuffer[RENDERWIDE * RENDERDEEP];
+
+
+
+
+
+// Scroll variables. scrollx and scrolly hold the current scroll position,
+// and scrollxTarget and scrollyTarget are the target position for the end
+// of the game cycle.
+
+//int16 scrollx;
+//int16 scrolly;
+extern int16 scrollx;
+extern int16 scrolly;
+int16 parallaxScrollx;
+int16 parallaxScrolly;
+int16 locationWide;
+int16 locationDeep;
+
+static int16 scrollxTarget;
+static int16 scrollyTarget;
+static int16 scrollxOld;
+static int16 scrollyOld;
+static uint16 layer = 0;
+
+
+
+#define RENDERAVERAGETOTAL 4
+int32 renderCountIndex = 0;
+int32 renderTimeLog[RENDERAVERAGETOTAL] = {60, 60, 60, 60};
+int32 initialTime;
+int32 startTime;
+int32 originTime;
+int32 totalTime;
+int32 renderAverageTime = 60;
+int32 framesPerGameCycle;
+int32 renderTooSlow;
+
+
+
+
+#define BLOCKWIDTH 64
+#define BLOCKHEIGHT 64
+#define BLOCKWBITS 6
+#define BLOCKHBITS 6
+#define MAXLAYERS 5
+
+uint8 xblocks[MAXLAYERS];
+uint8 yblocks[MAXLAYERS];
+uint8 restoreLayer[MAXLAYERS];
+//LPDIRECTDRAWSURFACE *blockSurfaces[MAXLAYERS] = {0,0,0,0,0};
+
+
+
+
+int32 RestoreBackgroundLayer(_parallax *p, int16 l)
+{
+ warning("stub RestoreBackgroundLayer %d", l);
+/*
+ int16 oldLayer = layer;
+ int16 i;
+
+ layer = l;
+ if (blockSurfaces[l])
+ {
+ for (i=0; i<xblocks[l] * yblocks[l]; i++)
+ if (*(blockSurfaces[l]+i))
+ IDirectDrawSurface2_Release(*(blockSurfaces[l] + i));
+ free(blockSurfaces[l]);
+ blockSurfaces[l] = NULL;
+ }
+ RestoreSurfaces();
+ InitialiseBackgroundLayer(p);
+ layer = oldLayer;
+*/
+ return(RD_OK);
+
+}
+
+
+
+
+
+
+int32 PlotPoint(uint16 x, uint16 y, uint8 colour)
+
+{
+ warning("stub PlotPoint( %d, %d, %d )", x, y, colour);
+/*
+ int16 newx, newy;
+
+ newx = x - scrollx;
+ newy = y - scrolly;
+
+ if ((newx < 0) || (newx > RENDERWIDE) || (newy < 0) || (newy > RENDERDEEP))
+ {
+ return(RD_OK);
+ }
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ {
+ DDSURFACEDESC ddsd;
+ HRESULT hr;
+
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ RestoreSurfaces();
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ }
+
+ if (hr == DD_OK)
+ {
+
+ *((uint8 *) ddsd.lpSurface + (newy + 40) * ddsd.lPitch + newx) = colour;
+ IDirectDrawSurface2_Unlock(lpBackBuffer, ddsd.lpSurface);
+ }
+ }
+ else
+ myScreenBuffer[newy * RENDERWIDE + newx] = colour;
+*/
+ return(RD_OK);
+
+}
+
+
+// Uses Bressnham's incremental algorithm!
+int32 DrawLine(int16 x0, int16 y0, int16 x1, int16 y1, uint8 colour)
+
+{
+ warning("stub DrawLine( %d, %d, %d, %d, %d )", x0, y0, x1, y1, colour);
+/*
+ int dx, dy;
+ int dxmod, dymod;
+ int ince, incne;
+ int d;
+ int x, y;
+ int addTo;
+ DDSURFACEDESC ddsd;
+ HRESULT hr;
+
+ x1 -= scrollx;
+ y1 -= scrolly;
+ x0 -= scrollx;
+ y0 -= scrolly;
+
+
+ // Lock the surface if we're rendering to the back buffer.
+
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ {
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ RestoreSurfaces();
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ }
+ if (hr != DD_OK)
+ return(RD_OK);
+
+ (uint8 *) ddsd.lpSurface += (40 * ddsd.lPitch);
+
+ }
+
+
+
+
+ //Make sure we're going from left to right
+ if (x1 < x0)
+ {
+ x = x1;
+ x1 = x0;
+ x0 = x;
+ y = y1;
+ y1 = y0;
+ y0 = y;
+ }
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ if (dx < 0)
+ dxmod = -dx;
+ else
+ dxmod = dx;
+
+ if (dy < 0)
+ dymod = -dy;
+ else
+ dymod = dy;
+
+ if (dxmod >= dymod)
+ {
+ if (dy > 0)
+ {
+ d = 2 * dy - dx;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ x = x0;
+ y = y0;
+ if ((x >= 0) && (x < RENDERWIDE) && (y >= 0) && (y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + y * ddsd.lPitch + x) = colour;
+ else
+ myScreenBuffer[y * RENDERWIDE + x] = colour;
+ while (x < x1)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ if ((x >= 0) && (x < RENDERWIDE) && (y >= 0) && (y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + y * ddsd.lPitch + x) = colour;
+ else
+ myScreenBuffer[y * RENDERWIDE + x] = colour;
+ }
+ }
+ else
+ {
+ addTo = y0;
+ y0 = 0;
+ y1 -= addTo;
+ y1 = -y1;
+ dy = y1 - y0;
+
+ d = 2 * dy - dx;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ x = x0;
+ y = y0;
+ if ((x >= 0) && (x < RENDERWIDE) && (addTo - y >= 0) && (addTo - y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + (addTo - y) * ddsd.lPitch + x) = colour;
+ else
+ myScreenBuffer[(addTo - y) * RENDERWIDE + x] = colour;
+ while (x < x1)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ if ((x >= 0) && (x < RENDERWIDE) && (addTo - y >= 0) && (addTo - y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + (addTo - y) * ddsd.lPitch + x) = colour;
+ else
+ myScreenBuffer[(addTo - y) * RENDERWIDE + x] = colour;
+ }
+
+ }
+ }
+ else
+ {
+ //OK, y is now going to be the single increment.
+ // Ensure the line is going top to bottom
+ if (y1 < y0)
+ {
+ x = x1;
+ x1 = x0;
+ x0 = x;
+ y = y1;
+ y1 = y0;
+ y0 = y;
+ }
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ if (dx > 0)
+ {
+ d = 2 * dx - dy;
+ ince = 2 * dx;
+ incne = 2 * (dx - dy);
+ x = x0;
+ y = y0;
+ if ((x >= 0) && (x < RENDERWIDE) && (y >= 0) && (y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + y * ddsd.lPitch + x) = colour;
+ else
+ myScreenBuffer[y * RENDERWIDE + x] = colour;
+ while (y < y1)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ y += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ if ((x >= 0) && (x < RENDERWIDE) && (y >= 0) && (y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + y * ddsd.lPitch + x) = colour;
+ else
+ myScreenBuffer[y * RENDERWIDE + x] = colour;
+ }
+ }
+ else
+ {
+ addTo = x0;
+ x0 = 0;
+ x1 -= addTo;
+ x1 = -x1;
+ dx = x1 - x0;
+
+ d = 2 * dx - dy;
+ ince = 2 * dx;
+ incne = 2 * (dx - dy);
+ x = x0;
+ y = y0;
+ if ((addTo - x >= 0) && (addTo - x < RENDERWIDE) && (y >= 0) && (y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + y * ddsd.lPitch + addTo - x) = colour;
+ else
+ myScreenBuffer[y * RENDERWIDE + addTo - x] = colour;
+ while (y < y1)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ y += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ if ((addTo - x >= 0) && (addTo - x < RENDERWIDE) && (y >= 0) && (y < RENDERDEEP))
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ *((uint8 *) ddsd.lpSurface + y * ddsd.lPitch + addTo - x) = colour;
+ else
+ myScreenBuffer[y * RENDERWIDE + addTo - x] = colour;
+ }
+
+ }
+
+ }
+
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ {
+ (uint8 *) ddsd.lpSurface -= (40 * ddsd.lPitch);
+ IDirectDrawSurface2_Unlock(lpBackBuffer, ddsd.lpSurface);
+ }
+*/
+ return(RD_OK);
+
+}
+
+
+
+int32 SetLocationMetrics(uint16 w, uint16 h)
+
+{
+
+ locationWide = w;
+ locationDeep = h;
+
+ return(RD_OK);
+
+}
+
+
+
+int32 RenderParallax(_parallax *p, int16 layer)
+
+{
+ warning("stub RenderParallax %d", layer);
+/*
+
+#if PROFILING == 1
+
+ LARGE_INTEGER startTime, endTime;
+
+ QueryPerformanceCounter(&startTime);
+
+#endif
+
+ if ((renderCaps & RDBLTFX_ALLHARDWARE) || ((renderCaps & RDBLTFX_FGPARALLAX) && (layer > 2)))
+ {
+
+ int16 x, y;
+ int16 i, j;
+ int16 restoreSurfaces = 0;
+ HRESULT hr = 0;
+ RECT r, rd;
+
+ if (restoreLayer[layer])
+ {
+ RestoreBackgroundLayer(p, layer);
+ restoreLayer[layer] = 0;
+ }
+
+ 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)));
+
+
+ while (TRUE)
+ {
+ j = 0;
+ while (j < yblocks[layer])
+ {
+ i = 0;
+ while (i < xblocks[layer])
+ {
+ if (*(blockSurfaces[layer] + i + j * xblocks[layer]))
+ {
+ r.left = i * BLOCKWIDTH - x;
+ r.right = r.left + BLOCKWIDTH;
+ r.top = j * BLOCKHEIGHT - y + 40;
+ r.bottom = r.top + BLOCKHEIGHT;
+ rd.left = 0;
+ rd.right = BLOCKWIDTH;
+ rd.top = 0;
+ rd.bottom = BLOCKHEIGHT;
+
+ if ((r.left < 0) && (r.left > 0 - BLOCKWIDTH))
+ {
+ rd.left = 0 - r.left;
+ r.left = 0;
+ }
+ if ((r.top < 40) && (r.top > 40 - BLOCKHEIGHT))
+ {
+ rd.top = 40 - r.top;
+ r.top = 40;
+ }
+ if ((r.right > 640) && (r.right < 640 + BLOCKWIDTH))
+ {
+ rd.right = BLOCKWIDTH - (r.right - 640);
+ r.right = 640;
+ }
+ if ((r.bottom > 440) && (r.bottom < 440 + BLOCKHEIGHT))
+ {
+ 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);
+ if (hr == DDERR_INVALIDRECT)
+ hr = 0;
+ if (hr)
+ break;
+ }
+ i++;
+ if (hr)
+ break;
+ }
+ j++;
+ if (hr)
+ break;
+ }
+ if (hr)
+ {
+ if (hr == DDERR_SURFACELOST)
+ {
+ if (gotTheFocus)
+ {
+ if (++restoreSurfaces == 4)
+ return(RDERR_RESTORELAYERS);
+ else
+ RestoreBackgroundLayer(p, layer);
+ }
+ else
+ return(RD_OK);
+ }
+ else
+ return(hr);
+
+ }
+ else
+ break;
+ }
+
+ parallaxScrollx = scrollx - x;
+ parallaxScrolly = scrolly - y;
+ }
+ else
+ {
+ uint8 zeros;
+ uint16 count;
+ uint16 skip;
+ uint16 i, j;
+ uint16 x;
+ int32 px, py;
+ uint8 *data;
+ uint8 *dst;
+ _parallaxLine *line;
+
+ if (locationWide == screenWide)
+ px = 0;
+ else
+ px = ( (int32) ((p->w - screenWide) * scrollx) / (int32) (locationWide - screenWide));
+
+ if (locationDeep == (screenDeep - MENUDEEP*2))
+ py = 0;
+ else
+ py = ( (int32) ((p->h - (screenDeep - MENUDEEP*2)) * scrolly) / (int32) (locationDeep - (screenDeep - MENUDEEP*2)));
+
+
+ for (i = py; i < py + (screenDeep - MENUDEEP * 2); i++)
+ {
+ if (p->offset[i] == 0)
+ continue;
+
+ line = (_parallaxLine *) ((uint8 *) p + p->offset[i]);
+ data = (uint8 *) line + sizeof(_parallaxLine);
+ x = line->offset;
+ if (x > px)
+ skip = x - px;
+ else
+ skip = 0;
+
+ dst = myScreenBuffer + (i - py) * RENDERWIDE + skip;
+
+
+ zeros = 0;
+ if (line->packets == 0)
+ {
+ data += px;
+ memcpy(dst, data, screenWide);
+ continue;
+ }
+
+ for (j=0; j<line->packets; j++)
+ {
+ if (zeros)
+ {
+ if (x >= px)
+ {
+ dst += *data;
+ x += *data;
+ }
+ else
+ {
+ x += *data;
+ if (x > px)
+ {
+ dst += (x - px);
+ }
+ }
+ data += 1;
+ zeros = 0;
+ }
+ else
+ {
+ if (*data == 0)
+ {
+ data ++;
+ }
+ else if (x >= px)
+ {
+ if (x + *data <= px + screenWide)
+ {
+ count = *data++;
+ memcpy(dst, data, count);
+ data += count;
+ dst += count;
+ x += count;
+ }
+ else if (x < px + screenWide)
+ {
+ data++;
+ count = screenWide - (x - px);
+ memcpy(dst, data, count);
+ j = line->packets;
+ }
+ }
+ else
+ {
+ count = *data++;
+
+ if (x + count > px)
+ {
+ skip = px - x;
+ data += skip;
+ count -= skip;
+ memcpy(dst, data, count);
+ data += count;
+ dst += count;
+ x += count + skip;
+ }
+ else
+ {
+ data += count;
+ x += count;
+ if (x > px)
+ {
+ dst += (x - px);
+ }
+ }
+ }
+ zeros = 1;
+ }
+ }
+ }
+
+ parallaxScrollx = scrollx - px;
+ parallaxScrolly = scrolly - py;
+ }
+
+#if PROFILING == 1
+ QueryPerformanceCounter(&endTime);
+ profileRenderLayers += (endTime.LowPart - startTime.LowPart);
+#endif
+*/
+ return(RD_OK);
+
+}
+
+
+
+
+
+
+/*
+#define LOGSIZE 10
+int32 previousTimeLog[LOGSIZE];
+int32 renderCycleStartLog[LOGSIZE];
+int32 lastRenderTimeLog[LOGSIZE];
+int32 renderCycleEndLog[LOGSIZE];
+int32 timeLeftLog[LOGSIZE];
+int32 scrollxOldLog[LOGSIZE];
+int32 scrollxLog[LOGSIZE];
+int32 scrollxTargetLog[LOGSIZE];
+
+
+void LogMe(int32 in)
+{
+ static int32 i;
+
+ if (in == 0)
+ i = 0;
+
+ previousTimeLog[i] = previousTime;
+ aveRenderCycleLog[i] = aveRenderCycle;
+ renderCycleStartLog[i] = renderCycleStart;
+ lastRenderTimeLog[i] = lastRenderTime;
+ renderCycleEndLog[i] = renderCycleEnd;
+ timeLeftLog[i] = timeLeft;
+ scrollxOldLog[i] = scrollxOld;
+ scrollxLog[i] = scrollx;
+ scrollxTargetLog[i] = scrollxTarget;
+
+ if (++i == LOGSIZE)
+ i = 0;
+
+}
+*/
+
+
+int32 InitialiseRenderCycle(void)
+
+{
+
+ initialTime = timeGetTime();
+ originTime = initialTime;
+ totalTime = initialTime + MILLISECSPERCYCLE;
+
+ return(RD_OK);
+
+}
+
+
+
+int32 StartRenderCycle(void)
+
+{
+
+
+ scrollxOld = scrollx;
+ scrollyOld = scrolly;
+
+ startTime = timeGetTime();
+
+ if (startTime + renderAverageTime >= totalTime)
+ {
+ scrollx = scrollxTarget;
+ scrolly = scrollyTarget;
+ renderTooSlow = 1;
+ }
+ else
+ {
+ scrollx = scrollxOld + ((scrollxTarget - scrollxOld) * (startTime - initialTime + renderAverageTime)) / (totalTime - initialTime);
+ scrolly = scrollyOld + ((scrollyTarget - scrollyOld) * (startTime - initialTime + renderAverageTime)) / (totalTime - initialTime);
+ renderTooSlow = 0;
+ }
+
+ framesPerGameCycle = 0;
+
+ return(RD_OK);
+
+}
+
+
+
+int32 EndRenderCycle(BOOL *end)
+
+{
+
+ int32 time;
+
+ time = timeGetTime();
+ renderTimeLog[renderCountIndex] = time - startTime;
+ startTime += renderTimeLog[renderCountIndex];
+ renderAverageTime = (renderTimeLog[0] + renderTimeLog[1] + renderTimeLog[2] + renderTimeLog[3]) >> 2;
+
+ framesPerGameCycle += 1;
+
+ if (++renderCountIndex == RENDERAVERAGETOTAL)
+ renderCountIndex = 0;
+
+ if (renderTooSlow)
+ {
+ *end = TRUE;
+ InitialiseRenderCycle();
+ }
+ else if (startTime + renderAverageTime >= totalTime)
+ {
+ *end = TRUE;
+ originTime = totalTime;
+ totalTime += MILLISECSPERCYCLE;
+ initialTime = time;
+ }
+ else
+ {
+ *end = FALSE;
+ scrollx = scrollxOld + ((scrollxTarget - scrollxOld) * (startTime - initialTime + renderAverageTime)) / (totalTime - initialTime);
+ scrolly = scrollyOld + ((scrollyTarget - scrollyOld) * (startTime - initialTime + renderAverageTime)) / (totalTime - initialTime);
+ }
+
+ return(RD_OK);
+
+}
+
+
+int32 SetScrollTarget(int16 sx, int16 sy)
+
+{
+
+ scrollxTarget = sx;
+ scrollyTarget = sy;
+
+ return(RD_OK);
+
+}
+
+int32 CopyScreenBuffer(void)
+
+{
+ warning("stub CopyScreenBuffer");
+/*
+
+ uint8 *dst, *src;
+ int16 i;
+ DDSURFACEDESC ddDescription;
+ HRESULT hr;
+
+#if PROFILING == 1
+ static LARGE_INTEGER endTime;
+ LARGE_INTEGER startTime;
+ int32 lastEndTime, profileTotalTime;
+#endif
+
+
+#if PROFILING == 1
+ QueryPerformanceCounter(&startTime);
+// time = timeGetTime();
+#endif
+
+
+ if (!(renderCaps & RDBLTFX_ALLHARDWARE))
+ {
+ ddDescription.dwSize = sizeof(ddDescription);
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddDescription, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ RestoreSurfaces();
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddDescription, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ }
+ if (hr == DD_OK)
+ {
+ dst = (uint8 *) ddDescription.lpSurface + MENUDEEP * ddDescription.lPitch;
+ src = myScreenBuffer;
+ for (i=0; i<RENDERDEEP; i++)
+ {
+ memcpy(dst, src, screenWide);
+ src += RENDERWIDE;
+ dst += ddDescription.lPitch;
+ }
+ IDirectDrawSurface2_Unlock(lpBackBuffer, ddDescription.lpSurface);
+ }
+ else
+ {
+ return(RDERR_LOCKFAILED);
+ }
+ }
+
+#if PROFILING == 1
+ lastEndTime = endTime.LowPart;
+ QueryPerformanceCounter(&endTime);
+ profileCopyScreenBuffer = (int32) (endTime.LowPart - startTime.LowPart) / 1000;
+ profileTotalTime = (endTime.LowPart - lastEndTime) / 1000;
+ if ((profileTotalTime > 0) && (profileTotalTime < 5000))
+ PlotDots(0, 5, (int16) profileTotalTime);
+ PlotDots(0, 10, (int16) profileCopyScreenBuffer);
+ PlotDots(0, 15, (int16) (profileRenderLayers / 1000));
+ PlotDots(0, 20, (int16) (profileSpriteRender / 1000));
+ PlotDots(0, 25, (int16) (profileDecompression / 1000));
+ profileRenderLayers = 0;
+ profileSpriteRender = 0;
+ profileDecompression = 0;
+#endif
+*/
+ return(RD_OK);
+}
+
+
+
+int32 InitialiseBackgroundLayer(_parallax *p)
+
+{
+ warning("stub InitialiseBackgroundLayer");
+/*
+ uint8 *memchunk;
+ uint32 *quaddata;
+ uint8 zeros;
+ uint16 count;
+// uint16 skip;
+ uint16 i, j, k;
+ uint16 x;
+ uint8 *data;
+ uint8 *dst;
+ _parallaxLine *line;
+ HRESULT hr;
+ DDSURFACEDESC ddsd;
+
+
+ if ((renderCaps & RDBLTFX_ALLHARDWARE) || ((renderCaps & RDBLTFX_FGPARALLAX) && (layer > 2)))
+ {
+
+ // This function is called to re-initialise the layers if they have been lost.
+ // We know this if the layers have already been assigned.
+ if (layer == MAXLAYERS)
+ {
+ CloseBackgroundLayer();
+ // RestoreSurfaces(); // for the primary and back buffer.
+ }
+
+
+ if (p == NULL)
+ {
+ layer += 1;
+ return(RD_OK);
+ }
+
+ xblocks[layer] = (p->w + BLOCKWIDTH - 1) >> BLOCKWBITS;
+ yblocks[layer] = (p->h + BLOCKHEIGHT - 1) >> BLOCKHBITS;
+ blockSurfaces[layer] = (LPDIRECTDRAWSURFACE *) malloc(xblocks[layer] * yblocks[layer] * sizeof(LPDIRECTDRAWSURFACE));
+ if (blockSurfaces[layer] == NULL)
+ return(RDERR_OUTOFMEMORY);
+
+ // Decode the parallax layer into a large chunk of memory
+ memchunk = (uint8 *) malloc(xblocks[layer] * BLOCKWIDTH * yblocks[layer] * BLOCKHEIGHT);
+ if (memchunk == NULL)
+ return(RDERR_OUTOFMEMORY);
+
+ 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 += 1;
+ 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!
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ if (dxHalCaps & RDCAPS_SRCBLTCKEY)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+
+ ddsd.dwWidth = BLOCKWIDTH;
+ ddsd.dwHeight = BLOCKHEIGHT;
+ for (i=0; i<xblocks[layer] * yblocks[layer]; i++)
+ {
+ // Only assign a surface to the block if it contains data.
+ quaddata = (int32 *) (memchunk + (p->w * BLOCKHEIGHT * (i / xblocks[layer])) + BLOCKWIDTH * (i % xblocks[layer]));
+ for (j=0; j<BLOCKHEIGHT; j++)
+ {
+ for (k=0; k<BLOCKWIDTH / 4; k++)
+ {
+ if (*quaddata)
+ break;
+ quaddata++;
+ }
+ quaddata += ((p->w - BLOCKWIDTH) / 4);
+ if (k < BLOCKWIDTH / 4)
+ break;
+ }
+
+ if (k < BLOCKWIDTH / 4)
+ {
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, blockSurfaces[layer] + i, NULL);
+ if (hr != DD_OK)
+ {
+ if (hr == DDERR_OUTOFVIDEOMEMORY)
+ {
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, blockSurfaces[layer] + i, NULL);
+ }
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create parallax surface", hr);
+ return(hr);
+ }
+ }
+ // Set the surface blt source colour key
+ hr = IDirectDrawSurface2_SetColorKey(*(blockSurfaces[layer] + i), DDCKEY_SRCBLT, &blackColorKey);
+
+ // Copy the data into the surfaces.
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ hr = IDirectDrawSurface2_Lock(*(blockSurfaces[layer] + i), NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ IDirectDrawSurface2_Restore(*(blockSurfaces[layer] + i));
+ hr = IDirectDrawSurface2_Lock(*(blockSurfaces[layer] + i), NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot lock parallax surface", hr);
+ return(hr);
+ }
+ }
+
+ data = memchunk + (p->w * BLOCKHEIGHT * (i / xblocks[layer])) + BLOCKWIDTH * (i % xblocks[layer]);
+ dst = ddsd.lpSurface;
+ for (j=0; j<BLOCKHEIGHT; j++)
+ {
+ memcpy(dst, data, BLOCKWIDTH);
+ data += p->w;
+ dst += ddsd.lPitch;
+ }
+ IDirectDrawSurface2_Unlock(*(blockSurfaces[layer] + i), ddsd.lpSurface);
+ }
+ else
+ {
+ *(blockSurfaces[layer] + i) = NULL;
+ }
+ }
+ free(memchunk);
+ }
+ layer += 1;
+*/
+ return(RD_OK);
+
+}
+
+
+int32 CloseBackgroundLayer(void)
+
+{
+ warning("stub CloseBackgroundLayer");
+/*
+ int16 i, j;
+
+// if (renderCaps & RDBLTFX_ALLHARDWARE)
+// {
+ for (j=0; j<MAXLAYERS; j++)
+ {
+ if (blockSurfaces[j])
+ {
+ for (i=0; i<xblocks[j] * yblocks[j]; i++)
+ if (*(blockSurfaces[j]+i))
+ IDirectDrawSurface2_Release(*(blockSurfaces[j] + i));
+ free(blockSurfaces[j]);
+ blockSurfaces[j] = NULL;
+ }
+ }
+ layer = 0;
+// }
+*/
+ return(RD_OK);
+
+}
+
+
+int32 EraseSoftwareScreenBuffer(void)
+{
+ memset(myScreenBuffer, 0, RENDERWIDE * RENDERDEEP);
+ return(RD_OK);
+}
diff --git a/sword2/driver/render.h b/sword2/driver/render.h
new file mode 100644
index 0000000000..287e243bc8
--- /dev/null
+++ b/sword2/driver/render.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : render.h
+// Created : 26th August 1996
+// By : P.R.Porter
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 16-Sep-96 PRP Interface to the current scroll position.
+//
+// 1.1 23-Oct-96 PRP Added definition of _parallaxLine structure.
+//
+// 1.2 05-Nov-96 PRP Added definition of myScreenBuffer.
+//
+// 1.3 06-Nov-96 PRP Fixed definition of myScreenBuffer.
+//
+// 1.4 15-Nov-96 PRP Definition of menubar size removed, and put
+// into menu.h
+//
+// 1.5 24-Jan-97 PRP Added references to parallaxScrollx and
+// parallaxScrolly. These are used by the sprite
+// drawing code to link sprites to parallax
+// layers.
+//
+// 1.6 19-Mar-97 PRP Added profiling flag for testing purposes.
+//
+// 1.7 24-Mar-97 PRP Turned profiling off
+//
+// 1.8 08-Apr-97 JEL Made locationWide and locationDeep accessible
+// to other drivers.
+//
+//
+//
+// Summary : This include file defines links to all data which is
+// defined in the render.c module, but can be accessed by
+// other parts of the driver96 library.
+//
+//
+//=============================================================================
+
+
+#ifndef RENDER_H
+#define RENDER_H
+
+#include "menu.h"
+
+#define RENDERWIDE 640
+#define ALIGNRENDERDEEP 480
+#define RENDERDEEP (ALIGNRENDERDEEP - (MENUDEEP * 2))
+
+
+#define PROFILING 0
+
+
+typedef struct
+{
+ uint16 packets;
+ uint16 offset;
+} _parallaxLine;
+
+
+
+extern int16 scrollx; // current x offset into background of display
+extern int16 scrolly; // current y offset into background of display
+extern int16 parallaxScrollx; // current x offset to link a sprite to the parallax layer
+extern int16 parallaxScrolly; // current y offset to link a sprite to the parallax layer
+extern int16 locationWide;
+extern int16 locationDeep;
+
+extern uint8 myScreenBuffer[RENDERWIDE * RENDERDEEP];
+
+
+#endif
+
diff --git a/sword2/driver/sprite.cpp b/sword2/driver/sprite.cpp
new file mode 100644
index 0000000000..33573405e2
--- /dev/null
+++ b/sword2/driver/sprite.cpp
@@ -0,0 +1,3240 @@
+/* Copyright (C) 1994-2003 Revolution Software Ltd
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+//=============================================================================
+//
+// Filename : sprite.c
+// Created : 23rd September 1996
+// By : P.R.Porter
+//
+// Summary : This module holds the sprite drawing functions.
+//
+// Version Date By Description
+// ------- --------- --- -----------------------------------------------
+// 1.0 25-Sep-96 PRP Blits full sprites only. Attempting to draw
+// any other type of sprite will return an error
+// code. Also, scroll target position is handled
+// here
+//
+// 1.1 26-Sep-96 PRP Added include file render.h for link to scroll
+// position.
+//
+// 1.2 04-Oct-96 PRP Added direct path to ddraw.h
+//
+// 1.3 09-Oct-96 PRP Made the sprite drawing routines write to either
+// the screen buffer or video memory.
+//
+// 1.4 23-Oct-96 PRP Added the ability to draw a transparent sprite,
+// i.e. one with holes in. (with clipping and
+// everything)
+//
+// 1.5 29-Oct-96 PRP Sprite drawing greatly improved. We can now
+// combine flags to define whether the sprite is
+// compressed, transparent or aligned to the
+// top corner of the monitor, as well as adding
+// a flag for fx.
+//
+// 1.6 29-Oct-96 PRP Fixed drawing of sprites with the display align
+// bit set in type.
+//
+// 1.7 29-Oct-96 PRP Made it so that when RDSPR_DISPLAYALIGN is
+// combined with RDSPR_TRANS the sprite is drawn
+// in the correct place.
+//
+// 1.8 31-Oct-96 PRP Fixed bug in sprite width calculation.
+//
+// 1.9 01-Nov-96 PRP Fixed transparent sprite clipping at the bottom
+//
+// 1.10 01-Nov-96 PRP Added RDSPR_SPRITECOMPRESSION to the attributes
+// which may be passed into DrawSprite, and
+// implemented a basic decompression piece of code
+// which is currently very slooowwww.
+//
+// 1.11 05-Nov-96 PRP RENDERWIDE and RENDERDEEP now defined in
+// render.h
+//
+// 1.12 06-Nov-96 PRP Fixed clipping for RDSPR_DISPLAYALIGN sprites.
+//
+// 1.13 08-Nov-96 PRP Added decompression for types RDSPR_RLE256 and
+// RDSPR_RLE16. Also changed the format of
+// DrawSprite() so that the details required by
+// it are passed in a structure.
+//
+// 1.14 12-Nov-96 PRP Enabled drawing of flipped sprites. This is
+// only possible for sprites which are compressed
+// and not drawn with DISPLAYALIGN
+//
+// 1.15 15-Nov-96 PRP Size of menubar moved to menu.h
+//
+// 1.16 21-Nov-96 PRP Implemented scaling for sprites - only certain
+// types mind.
+//
+// 1.17 25-Nov-96 PRP Removed the second displayed sprite to compare
+// the anti-aliasing code.
+//
+// 1.18 25-Nov-96 PRP Removed the ColourMatch function which only
+// worked on a reduced sub-set of the palette,
+// and replaced it with QuickMatch in palette.c.
+//
+// 1.19 26-Nov-96 PRP Implemented scaling of sprites which are
+// larger than their original size.
+//
+// 1.20 27-Nov-96 PRP Fixed the problem with displaying sprites which
+// are transparent, uncompressed and display
+// aligned. (James will be happy)
+//
+// 1.21 02-Dec-96 PRP Implemented sprites which blend with the
+// background.
+//
+// 1.22 18-Dec-96 PRP Moved origin of sprites which are not transparent
+// and display aligned.
+//
+// 1.23 09-Jan-97 PRP Display align clipping fixed for sprites which
+// are completely off the screen.
+//
+// 1.24 24-Jan-97 PRP Added an offset to a sprite's x and y position
+// depending upon where the latest parallax layer
+// was with reference to the background position.
+//
+// 1.25 28-Jan-97 PRP Updated sprite drawing code to utilise hardware
+// blitting where available.
+//
+// 1.26 06-Feb-97 PRP Fixed drawing of sprites after video memory
+// is full up.
+//
+// 1.27 10-Feb-97 PRP Changed direct draw error reporting function
+// calls.
+//
+// 1.28 11-Feb-97 PRP Implemented blending of sprites - depending
+// upon values passed in by spriteInfo.
+//
+// 1.29 12-Feb-97 PRP Fixed the blended sprite rendering position
+// bug.
+//
+// 1.30 12-Feb-97 PRP Changed the rendering code for blended sprites
+// in ALLHARDWARE mode.
+//
+// 1.31 19-Mar-97 PRP Added CreateSurface, DrawSurface and, you
+// guessed it, DeleteSurface functions.
+// Added temporary profiling code to optimise
+// sprite drawing.
+// Implemented sprite compression, and drawing
+// whilst decompressing code for sprite
+// optimisation
+//
+// 1.32 24-Mar-97 PRP Fixed DrawSurface so that it returns an error
+// code if the surface has been lost.
+//
+// 1.33 25-Mar-97 PRP Initialised freeSprite in the create surface
+// function.
+//
+// 1.34 27-Mar-97 PRP Further optimisation of different types
+// of sprites. New sprite compression type
+// RDSPR_RLE256FAST which decompresses and
+// draws at the same time. This type should
+// be used for static 256 colour transparent
+// sprites.
+//
+// 1.35 01-Apr-97 PRP Got rid of the RDSPR_LAYERCOMPRESSION
+// sprite type.
+//
+// 1.36 01-Apr-97 PRP Made transparent sprites stippled when
+// hardware acceleration is used.
+//
+// 1.37 01-Apr-97 PRP Fixed the bug which was tring to anti-alias
+// sprites which were not over the screen area.
+//
+// 1.38 07-Apr-97 PRP Added code which looks at the light mask
+// and renders George accordingly.
+//
+// 1.38 08-Apr-97 PRP Added code to decompress the light mask!
+//
+// 1.38 08-Apr-97 JEL Added another instance of light mask check.
+//
+// 1.39 08-Apr-97 JEL Changed screenWide to locationWide
+//
+// 1.40 09-Apr-97 PRP Fixed bug with fast draw not clipping
+// correctly on the left edge. Now it does :)
+//
+// 1.41 09-Apr-97 PRP Added shadow layer effects for sprites which
+// are not scaled, but have the RDSPR_SHADOW
+// flag set.
+//
+// 1.42 09-Apr-97 JEL No changes.
+//
+// 1.43 09-Apr-97 PRP Fixed bug. Shadow mask was being referenced
+// from the top of the screen, rather than the
+// top of the background!!!
+//
+// 1.44 09-Apr-97 JEL Changed starty to scrolly for driver bug.
+//
+// 1.45 22-Apr-97 PRP Added return values for decompression code.
+//
+// 1.46 24-Apr-97 JEL Fixed the decompression choice code.
+//
+// 1.47 28-May-97 CJR Added more information to the Direct draw
+// errors.
+//
+// 1.48 13-Jun-97 PRP Enabled the shadow mask when the arithmetic
+// stretching and anti-aliasing is switched off.
+//
+// 1.49 13-Jun-97 PRP Made use of shadow mask independently switchable.
+//
+// 1.50 07-Jul-97 PRP Fixed a bug with the offset of sprites which are
+// not compressed.
+//
+// 1.51 23-Jul-97 PRP Checked src colour key blitting flag before creating
+// a surface in video memory
+//
+// 1.52 31-Jul-97 PRP Only allowed shadow masks to affect the sprite palette.
+//
+// 1.53 31-Jul-97 PRP Fixed a bug with the above change. Non sprite
+// palette sprites were not being drawn, but are now :)
+//
+// 1.54 31-Jul-97 PRP Fixed the black box from around shadow sprites.
+//
+// 1.55 31-Jul-97 JEL Fixed the bug of transparent sprites suddenly printing in wrong position!
+//
+// 1.56 01-Aug-97 PRP Tried to fix the corruption at the end of stippled sprites.
+//
+// 1.57 01-Aug-97 PRP Replaced algorithm to fix corruption at end of stippled sprites.
+//
+// 1.58 01-Aug-97 PRP Removed the shitty sprite palette fix (1.52)
+//
+// 1.60 27-Aug-97 PRP Changed the drawing of transparent sprites so that
+// the uncompressed sprites display properly.
+//
+// 1.61 02-Sep-97 CJR Changed the Decompression code to return an error before causing
+// an access violation.
+//
+// Functions
+// ---------
+//
+// --------------------------------------------------------------------------
+//
+// int32 CreateSurface(_spriteInfo *s, uint32 *surface)
+//
+// Creates a sprite surface in video memory (if possible) and returns it's
+// handle in surface.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 DrawSurface(_spriteInfo *s, uint32 surface)
+//
+// Draws the sprite surface created earlier. If the surface has been lost,
+// it is recreated.
+//
+// ---------------------------------------------------------------------------
+//
+// int32 DeleteSurface(uint32 surface)
+//
+// Deletes a surface from video memory.
+//
+// --------------------------------------------------------------------------
+//
+// int32 DrawSprite(_spriteInfo *s)
+//
+// Draws a sprite onto the screen. The _spriteInfo structure holds all of
+// the information needed to draw the sprite - see driver96.h for details
+//
+//=============================================================================
+
+
+
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h>
+//#include <windowsx.h>
+#include <stdio.h>
+//#include <mmsystem.h>
+
+//#include "ddraw.h"
+
+#include "driver96.h"
+#include "d_draw.h"
+#include "render.h"
+#include "menu.h"
+#include "palette.h"
+
+
+#if PROFILING == 1
+extern int32 profileSpriteRender;
+extern int32 profileDecompression;
+#endif
+
+
+#define DEBUG_TIMING 0
+//LARGE_INTEGER myTimers[10][2];
+
+
+char shitColourTable[1024];
+static uint8 *lightMask = 0;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// --------------------------------------------------------------------------
+//
+// int32 MirrorSprite(uint8 *dst, uint8 *src, int16 w, int16 h)
+//
+// This function takes the sprite pointed to by src and creates a mirror
+// image of it in dst.
+//
+// --------------------------------------------------------------------------
+int32 MirrorSprite(uint8 *dst, uint8 *src, int16 w, int16 h)
+
+{
+
+ int16 x, y;
+
+ for (y=0; y<h; y++)
+ {
+ for (x=0; x<w; x++)
+ {
+ *dst++ = *(src + w-x-1);
+ }
+ src += w;
+ }
+
+ return(RD_OK);
+
+}
+
+
+// --------------------------------------------------------------------------
+//
+// int32 DecompressRLE256(uint8 *dest, uint8 *source, int32 decompSize)
+//
+// This function takes a compressed frame of a sprite (with up to 256 colours)
+// and decompresses it into the area of memory marked by the destination
+// pointer. The decompSize is used to measure when the decompression process
+// has completed.
+//
+// --------------------------------------------------------------------------
+int32 DecompressRLE256(uint8 *dest, uint8 *source, int32 decompSize)
+{
+ // PARAMETERS:
+ // source points to the start of the sprite data for input
+ // decompSize gives size of decompressed data in bytes
+ // dest points to start of destination buffer for decompressed data
+
+ uint8 headerByte; // block header byte
+ uint8 *endDest=dest+decompSize; // pointer to byte after end of decomp buffer
+ int32 rv;
+
+#if PROFILING == 1
+ LARGE_INTEGER startTime, endTime;
+ QueryPerformanceCounter(&startTime);
+#endif
+
+
+ while(1)
+ {
+ //----------------------------
+ // FLAT block
+ headerByte = *source++; // read FLAT block header & increment 'scan' to first pixel of block
+
+ if (headerByte) // if this isn't a zero-length block
+ {
+ if (dest+headerByte > endDest)
+ {
+ rv = 1;
+ break;
+ }
+
+ memset(dest,*source,headerByte); // set the next 'headerByte' pixels to the next colour at 'source'
+ dest+=headerByte; // increment destination pointer to just after this block
+ source++; // increment source pointer to just after this colour
+
+ if (dest==endDest) // if we've decompressed all of the data
+ {
+ rv = 0; // return "OK"
+ break;
+ }
+ }
+ //----------------------------
+ // RAW block
+ headerByte = *source++; // read RAW block header & increment 'scan' to first pixel of block
+
+ if (headerByte) // if this isn't a zero-length block
+ {
+ if (dest+headerByte > endDest)
+ {
+ rv = 1;
+ break;
+ }
+
+ memcpy(dest,source,headerByte); // copy the next 'headerByte' pixels from source to destination
+ dest+=headerByte; // increment destination pointer to just after this block
+ source+=headerByte; // increment source pointer to just after this block
+
+ if (dest==endDest) // if we've decompressed all of the data
+ {
+ rv = 0; // return "OK"
+ break;
+ }
+ }
+ //----------------------------
+ }
+#if PROFILING == 1
+ QueryPerformanceCounter(&endTime);
+ profileDecompression += (endTime.LowPart - startTime.LowPart);
+#endif
+
+ return(rv);
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// void UnwindRaw16(uint8 *dest, uint8 *source, uint8 blockSize, uint8 *colTable)
+//
+// This function unwinds a run of colour 16 data into 256 colour palette
+// data.
+// --------------------------------------------------------------------------
+void UnwindRaw16(uint8 *dest, uint8 *source, uint8 blockSize, uint8 *colTable)
+{
+ while(blockSize>1) // for each pair of pixels
+ {
+ *dest++ = colTable[(*source) >> 4]; // 1st colour = number in table at position given by upper nibble of source byte
+ *dest++ = colTable[(*source) & 0x0f]; // 2nd colour = number in table at position given by lower nibble of source byte
+ source++; // point to next source byte
+ blockSize-=2; // decrement count of how many pixels left to read
+ }
+
+ if (blockSize) // if there's a final odd pixel
+ *dest++ = colTable[(*source)>>4]; // colour = number in table at position given by upper nibble of source byte
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// int32 DecompressRLE16(uint8 *dest, uint8 *source, int32 decompSize, uint8 *colTable)
+//
+// This function takes a compressed frame of a sprite (with up to 16 colours)
+// and decompresses it into the area of memory marked by the destination
+// pointer. The decompSize is used to measure when the decompression process
+// has completed. The colour table which maps the 16 encoded colours to the
+// current palette is passed in to colTable.
+//
+// --------------------------------------------------------------------------
+int32 DecompressRLE16(uint8 *dest, uint8 *source, int32 decompSize, uint8 *colTable)
+{
+ // PARAMETERS:
+ // source points to the start of the sprite data for input
+ // decompSize gives size of decompressed data in bytes
+ // dest points to start of destination buffer for decompressed data
+ // colTable points to a 16-byte table of colours used to encode the RAW pixels into 4-bits each
+
+ uint8 headerByte; // block header byte
+ uint8 *endDest=dest+decompSize; // pointer to byte after end of decomp buffer
+ int32 rv;
+
+#if PROFILING == 1
+ LARGE_INTEGER startTime, endTime;
+ QueryPerformanceCounter(&startTime);
+#endif
+
+ while(1)
+ {
+ //----------------------------
+ // FLAT block
+ headerByte = *source++; // read FLAT block header & increment 'scan' to first pixel of block
+
+ if (headerByte) // if this isn't a zero-length block
+ {
+ if (dest+headerByte > endDest)
+ {
+ rv = 1;
+ break;
+ }
+
+ memset(dest,*source,headerByte); // set the next 'headerByte' pixels to the next colour at 'source'
+ dest+=headerByte; // increment destination pointer to just after this block
+ source++; // increment source pointer to just after this colour
+
+ if (dest==endDest) // if we've decompressed all of the data
+ {
+ rv = 0; // return "OK"
+ break;
+ }
+ }
+ //----------------------------
+ // RAW block
+ headerByte = *source++; // read RAW block header & increment 'scan' to first pixel of block
+
+ if (headerByte) // if this isn't a zero-length block
+ {
+ if (dest+headerByte > endDest)
+ {
+ rv = 1;
+ break;
+ }
+
+ UnwindRaw16(dest,source,headerByte,colTable); // copy the next 'headerByte' pixels from source to destination (NB. 2 pixels per byte)
+ dest+=headerByte; // increment destination pointer to just after this block
+ source+=(headerByte+1)/2; // increment source pointer to just after this block (NB. headerByte gives pixels, so /2 for bytes)
+
+ if (dest>=endDest) // if we've decompressed all of the data
+ {
+ rv = 0; // return "OK"
+ break;
+ }
+ }
+ //----------------------------
+ }
+
+#if PROFILING == 1
+ QueryPerformanceCounter(&endTime);
+ profileDecompression += (endTime.LowPart - startTime.LowPart);
+#endif
+
+ return(rv);
+
+}
+
+
+
+int32 PaulCompression(_spriteInfo *s, uint8 *src, uint8 *dst)
+
+{
+
+ int j;
+ int bytesToGo;
+ uint8 colour;
+ uint8 runCount;
+ uint8 *runPointer;
+
+ // Compressed the 256 colour source data into line compressed data.
+ for (j=0; j<s->h; j++)
+ {
+ bytesToGo = s->w;
+
+ while (bytesToGo)
+ {
+ // Look for a run of flat colour or zeros first.
+ if ((bytesToGo == 1) || (*src == 0) || (*src == *(src+1)))
+ {
+ colour = *src;
+ runCount = 0;
+ while ((*src == colour) && (bytesToGo) && (runCount < 255))
+ {
+ runCount++;
+ bytesToGo--;
+ src++;
+ }
+ *dst++ = runCount;
+ *dst++ = colour;
+ }
+ else
+ {
+ // We do not have a run of flat colour, so set the run length to zero
+ *dst++ = 0;
+ }
+
+ if (bytesToGo)
+ {
+ // Look for a run of different colours excluding zero
+ runCount = 0;
+ colour = 0;
+ if (((bytesToGo == 1) && (*src)) || ((*src) && (*(src) != *(src+1))))
+ {
+ runPointer = dst++;
+ while ((bytesToGo) && (runCount < 255) && (*src != colour) && (*src))
+ {
+ runCount++;
+ bytesToGo--;
+ colour = *src;
+ *dst++ = *src++;
+ }
+ if (*src == colour)
+ {
+ runCount--;
+ bytesToGo++;
+ dst--;
+ src--;
+ }
+ *runPointer = runCount;
+ }
+ else
+ {
+ *dst++ = 0;
+ }
+ }
+ else
+ {
+ // We do not have a run of different colours
+ *dst++ = 0;
+ }
+ }
+ }
+ return(RD_OK);
+}
+
+
+
+int32 SoftwareFlipRenderCompressed256(_spriteInfo *s)
+
+{
+
+ return(RDERR_NOTIMPLEMENTED);
+
+}
+
+
+
+
+int32 SoftwareRenderCompressed256(_spriteInfo *s)
+
+{
+ warning("stub SoftwareRenderCompressed256");
+/*
+ int32 rv;
+ int32 i;
+ int32 clipped = 0;
+ int32 clippedLeft, clippedRight;
+ int32 clippedCount;
+ RECT rSrc;
+ RECT rDst;
+
+ if (s->type & RDSPR_DISPLAYALIGN)
+ return(RDERR_NOTIMPLEMENTED);
+
+ if (s->type & RDSPR_FLIP)
+ {
+ rv = SoftwareFlipRenderCompressed256(s);
+ }
+ else
+ {
+ // Check to see whether we are dealing with a scaled sprite or not.
+ if ((s->scale == 0) || (s->scale == 256))
+ {
+ // The sprite is not scaled
+ // Work out the clip rectangles - source and destination
+ rDst.left = s->x - scrollx;
+ rDst.right = rDst.left + s->w;
+ rDst.top = s->y - scrolly;
+ rDst.bottom = rDst.top + s->h;
+
+ // Do major clipping
+ if ((rDst.left <= 0) && (rDst.right <= 0))
+ return(RD_OK);
+ if ((rDst.left >= RENDERWIDE) && (rDst.right >= RENDERWIDE))
+ return(RD_OK);
+ if ((rDst.top <= 0) && (rDst.bottom <= 0))
+ return(RD_OK);
+ if ((rDst.top >= RENDERDEEP) && (rDst.bottom >= RENDERDEEP))
+ return(RD_OK);
+
+ rSrc.top = 0;
+ rSrc.bottom = s->h;
+ rSrc.left = 0;
+ rSrc.right = s->w;
+ clippedLeft = 0;
+ clippedRight = 0;
+
+ // Now clip the fuckers
+ if (rDst.top < 0)
+ {
+ rSrc.top -= rDst.top;
+ rDst.top = 0;
+ clipped = 1;
+ }
+ if (rDst.bottom > RENDERDEEP)
+ {
+ rSrc.bottom -= (rDst.bottom - RENDERDEEP);
+ rDst.bottom = RENDERDEEP;
+ clipped = 1;
+ }
+ if (rDst.left < 0)
+ {
+ clippedLeft = -rDst.left;
+ rSrc.left += clippedLeft;
+ rDst.left = 0;
+ clipped = 1;
+ }
+ if (rDst.right > RENDERWIDE)
+ {
+ clippedRight = rDst.right - RENDERWIDE;
+ rSrc.right -= clippedRight;
+ rDst.right = RENDERWIDE;
+ clipped = 1;
+ }
+
+ if (s->type & RDSPR_BLEND)
+ {
+ // THE SPRITE IS BLENDED
+ int32 lineBytesToGo = s->w;
+// int32 bytesToGo;
+ uint8 *spr = s->data;
+ uint8 *dst = myScreenBuffer + rDst.left + rDst.top * RENDERWIDE;
+ uint8 runLength = 0;
+
+ // The sprite is not blended
+
+ // Decompress the source data until we are at the line where
+ // the drawing is to start.
+
+ if (clipped)
+ {
+ // Clip off any whole lines from the top of the sprite
+ for (i=0; i<rSrc.top; i++)
+ {
+ lineBytesToGo = s->w;
+ while (lineBytesToGo)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ if (*spr)
+ {
+ memset(dst, *spr, runLength);
+ }
+// dst += runLength;
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ memcpy(dst, spr, runLength);
+ spr += runLength;
+// dst += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+// dst += (RENDERWIDE - s->w);
+ }
+
+ // Draw until we get to the clipped bottom of the sprite.
+ while (i < rSrc.bottom)
+ {
+ lineBytesToGo = s->w;
+ // Do the first part of the line
+ if (clippedLeft)
+ {
+ clippedCount = clippedLeft;
+ while (clippedCount > 0)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ // Check that we aren't going to go over clippedCount
+ if (runLength > clippedCount)
+ {
+ runLength -= clippedCount;
+ if (*spr)
+ memset(dst, *spr, runLength);
+ dst += runLength;
+// memset(dst + clippedCount, *spr, runLength);
+// dst += (runLength + clippedCount);
+ spr++;
+ lineBytesToGo -= (runLength + clippedCount);
+ clippedCount = -runLength;
+ }
+ else
+ {
+// WE DON'T DO THIS BIT BECUASE WE ARE IN THE CLIPPED REGION
+// if (*spr)
+// {
+// memset(dst, *spr, runLength);
+// }
+
+// dst += runLength;
+
+ spr++;
+ clippedCount -= runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ // See if we are already over the clipped count
+ if (clippedCount < 0)
+ {
+ memcpy(dst, spr, runLength);
+ dst += runLength;
+ spr += runLength;
+ lineBytesToGo -= runLength;
+ }
+ // See if we are going to go over the clipped count
+ else if (runLength > clippedCount)
+ {
+ runLength -= clippedCount;
+// memcpy(dst + clippedCount , spr + clippedCount, runLength);
+// dst += (runLength + clippedCount);
+ memcpy(dst, spr + clippedCount, runLength);
+ dst += runLength;
+ spr += (runLength + clippedCount);
+ lineBytesToGo -= (runLength + clippedCount);
+ clippedCount = -runLength;
+ }
+ else
+ {
+// WE DON'T DO THIS BIT BECAUSE WE ARE IN THE CLIPPED REGION
+// memcpy(dst, spr, runLength);
+ spr += runLength;
+// dst += runLength;
+ lineBytesToGo -= runLength;
+ clippedCount -= runLength;
+ }
+ }
+ }
+ }
+
+// lineBytesToGo > clippedRight;
+ while (lineBytesToGo > clippedRight)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ // Ensure we're not going over the clipped region
+ if (*spr)
+ {
+ // Let's check that the run is not longer than the clipped region
+ if (lineBytesToGo - runLength < clippedRight)
+ {
+ if (lineBytesToGo - clippedRight > 0)
+ {
+ memset(dst, *spr, lineBytesToGo - clippedRight);
+ dst += (lineBytesToGo - clippedRight);
+ }
+ }
+ else
+ {
+ memset(dst, *spr, runLength);
+ dst += runLength;
+ }
+ }
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ // Let's check that the run is not longer than the clipped region
+ if (lineBytesToGo - runLength < clippedRight)
+ {
+ if (lineBytesToGo - clippedRight > 0)
+ {
+ memcpy(dst, spr, lineBytesToGo - clippedRight);
+ dst += (lineBytesToGo - clippedRight);
+ }
+ }
+ else
+ {
+ memcpy(dst, spr, runLength);
+ dst += runLength;
+ }
+ spr += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+
+ // Go through the compressed data to the end of the line.
+ while (lineBytesToGo)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+// DON'T DO THIS COS WE'RE OUTSIDE CLIP REGION
+// if (*spr)
+// {
+// memset(dst, *spr, runLength);
+// }
+
+// dst += runLength;
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+// DON'T DO THIS COS WE'RE OUTSIDE CLIP REGION
+// memcpy(dst, spr, runLength);
+ spr += runLength;
+// dst += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+
+// dst += (RENDERWIDE - s->w);
+ dst += (RENDERWIDE - (rDst.right - rDst.left));
+ i++;
+ }
+ }
+ else
+ {
+ // Fuck the clipping, let's just draw it for now
+ for (i=0; i<s->h; i++)
+ {
+ lineBytesToGo = s->w;
+ while (lineBytesToGo)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ if (*spr)
+ {
+ memset(dst, *spr, runLength);
+ }
+ dst += runLength;
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ memcpy(dst, spr, runLength);
+ spr += runLength;
+ dst += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+ dst += (RENDERWIDE - s->w);
+ }
+ }
+ }
+ else
+ {
+ int32 lineBytesToGo = s->w;
+// int32 bytesToGo;
+ uint8 *spr = s->data;
+ uint8 *dst = myScreenBuffer + rDst.left + rDst.top * RENDERWIDE;
+ uint8 runLength = 0;
+
+ // The sprite is not blended
+
+ // Decompress the source data until we are at the line where
+ // the drawing is to start.
+
+ if (clipped)
+ {
+ // Clip off any whole lines from the top of the sprite
+ for (i=0; i<rSrc.top; i++)
+ {
+ lineBytesToGo = s->w;
+ while (lineBytesToGo)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ if (*spr)
+ {
+ memset(dst, *spr, runLength);
+ }
+// dst += runLength;
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ memcpy(dst, spr, runLength);
+ spr += runLength;
+// dst += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+// dst += (RENDERWIDE - s->w);
+ }
+
+ // Draw until we get to the clipped bottom of the sprite.
+ while (i < rSrc.bottom)
+ {
+ lineBytesToGo = s->w;
+ // Do the first part of the line
+ if (clippedLeft)
+ {
+ clippedCount = clippedLeft;
+ while (clippedCount > 0)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ // Check that we aren't going to go over clippedCount
+ if (runLength > clippedCount)
+ {
+ runLength -= clippedCount;
+ if (*spr)
+ memset(dst, *spr, runLength);
+ dst += runLength;
+// memset(dst + clippedCount, *spr, runLength);
+// dst += (runLength + clippedCount);
+ spr++;
+ lineBytesToGo -= (runLength + clippedCount);
+ clippedCount = -runLength;
+ }
+ else
+ {
+// WE DON'T DO THIS BIT BECUASE WE ARE IN THE CLIPPED REGION
+// if (*spr)
+// {
+// memset(dst, *spr, runLength);
+// }
+
+// dst += runLength;
+
+ spr++;
+ clippedCount -= runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ // See if we are already over the clipped count
+ if (clippedCount < 0)
+ {
+ memcpy(dst, spr, runLength);
+ dst += runLength;
+ spr += runLength;
+ lineBytesToGo -= runLength;
+ }
+ // See if we are going to go over the clipped count
+ else if (runLength > clippedCount)
+ {
+ runLength -= clippedCount;
+// memcpy(dst + clippedCount , spr + clippedCount, runLength);
+// dst += (runLength + clippedCount);
+ memcpy(dst, spr + clippedCount, runLength);
+ dst += runLength;
+ spr += (runLength + clippedCount);
+ lineBytesToGo -= (runLength + clippedCount);
+ clippedCount = -runLength;
+ }
+ else
+ {
+// WE DON'T DO THIS BIT BECAUSE WE ARE IN THE CLIPPED REGION
+// memcpy(dst, spr, runLength);
+ spr += runLength;
+// dst += runLength;
+ lineBytesToGo -= runLength;
+ clippedCount -= runLength;
+ }
+ }
+ }
+ }
+
+// lineBytesToGo > clippedRight;
+ while (lineBytesToGo > clippedRight)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ // Ensure we're not going over the clipped region
+ // Let's check that the run is not longer than the clipped region
+ if (lineBytesToGo - runLength < clippedRight)
+ {
+ if (lineBytesToGo - clippedRight > 0)
+ {
+ if (*spr)
+ memset(dst, *spr, lineBytesToGo - clippedRight);
+ dst += (lineBytesToGo - clippedRight);
+ }
+ }
+ else
+ {
+ if (*spr)
+ memset(dst, *spr, runLength);
+ dst += runLength;
+ }
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ // Let's check that the run is not longer than the clipped region
+ if (lineBytesToGo - runLength < clippedRight)
+ {
+ if (lineBytesToGo - clippedRight > 0)
+ {
+ memcpy(dst, spr, lineBytesToGo - clippedRight);
+ dst += (lineBytesToGo - clippedRight);
+ }
+ }
+ else
+ {
+ memcpy(dst, spr, runLength);
+ dst += runLength;
+ }
+ spr += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+
+ // Go through the compressed data to the end of the line.
+ while (lineBytesToGo)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+// DON'T DO THIS COS WE'RE OUTSIDE CLIP REGION
+// if (*spr)
+// {
+// memset(dst, *spr, runLength);
+// }
+
+// dst += runLength;
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+// DON'T DO THIS COS WE'RE OUTSIDE CLIP REGION
+// memcpy(dst, spr, runLength);
+ spr += runLength;
+// dst += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+
+// dst += (RENDERWIDE - s->w);
+ dst += (RENDERWIDE - (rDst.right - rDst.left));
+ i++;
+ }
+ }
+ else
+ {
+ // Fuck the clipping, let's just draw it for now
+ for (i=0; i<s->h; i++)
+ {
+ lineBytesToGo = s->w;
+ while (lineBytesToGo)
+ {
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of the same colour or zeros
+ if (*spr)
+ {
+ memset(dst, *spr, runLength);
+ }
+ dst += runLength;
+ spr++;
+ lineBytesToGo -= runLength;
+ }
+
+ runLength = *spr++;
+ if (runLength)
+ {
+ // This is a run of different colours
+ memcpy(dst, spr, runLength);
+ spr += runLength;
+ dst += runLength;
+ lineBytesToGo -= runLength;
+ }
+ }
+ dst += (RENDERWIDE - s->w);
+ }
+ }
+ }
+ }
+ else
+ {
+ // The sprite is scaled.
+ rv = RDERR_NOTIMPLEMENTED;
+ }
+ }
+ return(rv);
+*/
+ return 0;
+}
+
+
+int32 CreateSurface(_spriteInfo *s, uint32 *surface)
+
+{
+ warning("stub CreateSurface");
+/*
+
+ uint8 *sprite, *newSprite;
+ uint8 *src, *dst;
+ int32 freeSprite = 0;
+ int32 i;
+ HRESULT hr;
+ DDSURFACEDESC ddsd;
+ LPDIRECTDRAWSURFACE dds;
+
+
+ // Create a surface for the sprite and then draw it.
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ if (s->scale & 0xff)
+ {
+ if (dxHalCaps & RDCAPS_BLTSTRETCH)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ }
+ else
+ {
+ if (dxHalCaps & RDCAPS_SRCBLTCKEY)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ }
+
+ ddsd.dwWidth = s->w;
+ ddsd.dwHeight = s->h;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &dds, NULL);
+ if (hr == DDERR_OUTOFVIDEOMEMORY)
+ {
+ ddsd.ddsCaps.dwCaps &= (0xffffffff - DDSCAPS_VIDEOMEMORY);
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &dds, NULL);
+ }
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create sprite surface", hr);
+ return(hr);
+ }
+
+ if (s->type & RDSPR_TRANS)
+ hr = IDirectDrawSurface2_SetColorKey(dds, DDCKEY_SRCBLT, &blackColorKey);
+
+ if (s->type &RDSPR_NOCOMPRESSION)
+ {
+ sprite = s->data;
+ }
+ else
+ {
+ sprite = (uint8 *) malloc(s->w * s->h);
+ freeSprite = 1;
+ if (sprite == NULL)
+ {
+ IDirectDrawSurface2_Release(dds);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ if (s->type >> 8 == RDSPR_RLE16 >> 8)
+ {
+ if (DecompressRLE16(sprite, s->data, s->w * s->h, s->colourTable))
+ return(RDERR_DECOMPRESSION);
+ }
+ else
+ {
+ if (DecompressRLE256(sprite, s->data, s->w * s->h))
+ return(RDERR_DECOMPRESSION);
+ }
+
+ if (s->type & RDSPR_FLIP)
+ {
+ newSprite = (uint8 *) malloc(s->w * s->h);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+ MirrorSprite(newSprite, sprite, s->w, s->h);
+ free(sprite);
+ sprite = newSprite;
+ }
+ }
+
+ hr = IDirectDrawSurface2_Lock(dds, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ IDirectDrawSurface2_Restore(dds);
+ hr = IDirectDrawSurface2_Lock(dds, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot lock sprite surface", hr);
+ return(hr);
+ }
+ }
+
+ src = sprite;
+ dst = ddsd.lpSurface;
+ for (i=0; i<s->h; i++)
+ {
+ memcpy(dst, src, s->w);
+ src += s->w;
+ dst += ddsd.lPitch;
+ }
+
+ IDirectDrawSurface2_Unlock(dds, ddsd.lpSurface);
+
+ *surface = (uint32) dds;
+
+ if (freeSprite)
+ free(sprite);
+*/
+ return(RD_OK);
+
+}
+
+
+int32 DrawSurface(_spriteInfo *s, uint32 surface)
+
+{
+ warning("stub DrawSurface");
+/*
+
+ HRESULT hr;
+ RECT rd, rs;
+ LPDIRECTDRAWSURFACE dds;
+ char myString[256];
+
+
+ dds = (LPDIRECTDRAWSURFACE) surface;
+
+ // Set startx and starty for the screen buffer ADDED THIS!
+ if (s->type & RDSPR_DISPLAYALIGN)
+ rd.top = s->y;
+ else
+ rd.top = s->y - scrolly;
+
+ if (s->type & RDSPR_DISPLAYALIGN)
+ rd.left = s->x;
+ else
+ rd.left = s->x - scrollx;
+
+ rs.left = 0;
+ rs.right = s->w;
+ rs.top = 0;
+ rs.bottom = s->h;
+ if (s->scale & 0xff)
+ {
+ rd.right = rd.left + s->scaledWidth;
+ rd.bottom = rd.top + s->scaledHeight;
+ // Do clipping
+ if (rd.top < 40)
+ {
+ rs.top = (40 - rd.top) * 256 / s->scale;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440)
+ {
+ rs.bottom -= ((rd.bottom - 440) * 256 / s->scale);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0)
+ {
+ rs.left = (0 - rd.left) * 256 / s->scale;
+ rd.left = 0;
+ }
+ if (rd.right > 640)
+ {
+ rs.right -= ((rd.right - 640) * 256 / s->scale);
+ rd.right = 640;
+ }
+ }
+ else
+ {
+ rd.right = rd.left + s->w;
+ rd.bottom = rd.top + s->h;
+
+ // Do clipping
+ if (rd.top < 40)
+ {
+ rs.top = 40 - rd.top;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440)
+ {
+ rs.bottom -= (rd.bottom - 440);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0)
+ {
+ rs.left = 0 - rd.left;
+ rd.left = 0;
+ }
+ if (rd.right > 640)
+ {
+ rs.right -= (rd.right - 640);
+ rd.right = 640;
+ }
+ }
+
+ if (s->type & RDSPR_TRANS)
+ {
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &rd, dds, &rs, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
+ if (hr)
+ {
+ if (hr == DDERR_SURFACELOST)
+ hr = RDERR_SURFACELOST;
+ else if (dxHalCaps & RDCAPS_BLTSTRETCH)
+ dxHalCaps -= RDCAPS_BLTSTRETCH;
+ else
+ {
+ sprintf(myString, "DrawSurface failed, sprite: x%d y%d w%d h%d s%d t%d sx%d sy%d", s->x, s->y, s->w, s->h, s->scale, s->type, scrollx, scrolly);
+ DirectDrawError(myString, hr);
+ }
+ }
+ }
+ else
+ {
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &rd, dds, &rs, DDBLT_WAIT, NULL);
+ if (hr)
+ {
+ if (hr == DDERR_SURFACELOST)
+ hr = RDERR_SURFACELOST;
+ else
+ {
+ sprintf(myString, "DrawSurface failed, sprite: x%d y%d w%d h%d s%d t%d sx%d sy%d", s->x, s->y, s->w, s->h, s->scale, s->type, scrollx, scrolly);
+ DirectDrawError(myString, hr);
+ }
+ }
+ }
+
+ return(hr);
+*/
+ return 0;
+}
+
+
+int32 DeleteSurface(uint32 surface)
+
+{
+ warning("stub DeleteSurface( %d )", surface);
+/*
+
+ LPDIRECTDRAWSURFACE dds;
+
+ dds = (LPDIRECTDRAWSURFACE) surface;
+ return(IDirectDrawSurface2_Release(dds));
+*/
+ return 0;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define SCALE_MAXWIDTH 512
+#define SCALE_MAXHEIGHT 512
+
+uint16 xScale[SCALE_MAXWIDTH];
+uint16 yScale[SCALE_MAXHEIGHT];
+
+
+int32 DrawSprite(_spriteInfo *s)
+
+{
+ warning("stub DrawSprite");
+/*
+
+#if PROFILING == 1
+ LARGE_INTEGER startTime, endTime;
+
+ QueryPerformanceCounter(&startTime);
+#endif
+
+ if (!(s->type & RDSPR_DISPLAYALIGN))
+ {
+ s->x += parallaxScrollx;
+ s->y += parallaxScrolly;
+ }
+
+ if (renderCaps & RDBLTFX_ALLHARDWARE)
+ {
+ uint8 *src, *dst;
+ uint8 *sprite, *newSprite;
+ uint8 pixel, red, green, blue;
+ int16 i, j;
+ int16 flag = 0;
+ int16 freeSprite = 0;
+ // int32 start, total; // For timing!
+ RECT rd, rs;
+ HRESULT hr;
+ DDSURFACEDESC ddsd;
+ LPDIRECTDRAWSURFACE dds;
+
+ s->y += 40;
+
+ // For now, we draw blended sprites with our own code, as they
+ // are not supported by DX3.
+ if ((s->type & RDSPR_BLEND) && (renderCaps & RDBLTFX_FLATALPHA))
+ {
+ if (s->type & RDSPR_NOCOMPRESSION)
+ sprite = s->data;
+ else
+ {
+ sprite = malloc(s->w * s->h);
+ if (sprite == NULL)
+ return(RDERR_OUTOFMEMORY);
+ freeSprite = 1;
+ if (s->type >> 8 == RDSPR_RLE16 >> 8)
+ {
+ if (DecompressRLE16(sprite, s->data, s->w * s->h, s->colourTable))
+ return(RDERR_DECOMPRESSION);
+ }
+ else
+ {
+ if (DecompressRLE256(sprite, s->data, s->w * s->h))
+ return(RDERR_DECOMPRESSION);
+ }
+ }
+
+ // We want to blend the sprite FROM the RECT rs.
+ // We want to blend the sprite TO the RECT rd.
+ rd.left = s->x - scrollx;
+ rd.right = rd.left + s->w;
+ rd.top = s->y - scrolly;
+ rd.bottom = rd.top + s->h;
+
+ rs.top = 0;
+ rs.bottom = s->h;
+ rs.left = 0;
+ rs.right = s->w;
+
+ //Now do the clipping - top
+ if (rd.top < 40)
+ {
+ rs.top = (40 - rd.top);
+ rd.top = 40;
+ }
+ //Clip the bottom
+ if (rd.bottom > RENDERDEEP)
+ {
+ rs.bottom -= (rd.bottom - RENDERDEEP);
+ rd.bottom = RENDERDEEP;
+ }
+ //Clip the left
+ if (rd.left < 0)
+ {
+ rs.left -= rd.left;
+ rd.left = 0;
+ }
+ //Clip the right
+ if (rd.right > RENDERWIDE)
+ {
+ rs.right -= (rd.right - RENDERWIDE);
+ rd.right = RENDERWIDE;
+ }
+
+ // start = timeGetTime();
+ memset(&ddsd, 0, sizeof(ddsd));
+ ddsd.dwSize = sizeof(ddsd);
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ RestoreSurfaces();
+ hr = IDirectDrawSurface2_Lock(lpBackBuffer, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ }
+ if (hr == DD_OK)
+ {
+ if (s->blend & 0x01)
+ {
+ red = s->blend >> 8;
+ for (i=0; i<rs.bottom - rs.top; i++)
+ {
+ src = sprite + (rs.top + i) * s->w + rs.left;
+ dst = (uint8 *) ddsd.lpSurface + ddsd.lPitch * (rd.top + i) + rd.left;
+ // newSprite = (uint8 *) ddsdSystem.lpSurface + ddsdSystem.lPitch * i;
+ for (j=0; j<rs.right - rs.left; j++)
+ {
+ if (*src)
+ {
+ pixel = *dst;
+ // pixel = *newSprite;
+ *dst = paletteMatch[(((palCopy[*src][0] * red + palCopy[pixel][0] * (8 - red)) >> 5) << 12) +
+ (((palCopy[*src][1] * red + palCopy[pixel][1] * (8 - red)) >> 5) << 6) +
+ (((palCopy[*src][2] * red + palCopy[pixel][2] * (8 - red)) >> 5) )];
+ }
+ src++;
+ dst++;
+ // newSprite++;
+ }
+ }
+ }
+ else if (s->blend & 0x02)
+ {
+ red = palCopy[s->blend >> 8][0];
+ green = palCopy[s->blend >> 8][0];
+ blue = palCopy[s->blend >> 8][0];
+ for (i=0; i<rs.bottom - rs.top; i++)
+ {
+ src = sprite + (rs.top + i) * s->w + rs.left;
+ dst = (uint8 *) ddsd.lpSurface + ddsd.lPitch * (rd.top + i) + rd.left;
+ // newSprite = (uint8 *) ddsdSystem.lpSurface + ddsdSystem.lPitch * i;
+ for (j=0; j<rs.right - rs.left; j++)
+ {
+ if (*src)
+ {
+ pixel = *dst;
+ // pixel = *newSprite;
+ *dst = paletteMatch[((((*src * red + (16 - *src) * palCopy[pixel][0]) >> 4) >> 2) << 12) +
+ ((((*src * green + (16 - *src) * palCopy[pixel][1]) >> 4) >> 2) << 6) +
+ (((*src * blue + (16 - *src) * palCopy[pixel][2]) >> 4) >> 2)];
+ }
+ src++;
+ dst++;
+ // newSprite++;
+ }
+ }
+ }
+ else
+ {
+ IDirectDrawSurface2_Unlock(lpBackBuffer, ddsd.lpSurface);
+ if (freeSprite)
+ free(sprite);
+ DirectDrawError("Invalid blended sprite", 0);
+ return(RDERR_UNKNOWNTYPE);
+ }
+ IDirectDrawSurface2_Unlock(lpBackBuffer, ddsd.lpSurface);
+ }
+
+ // IDirectDrawSurface2_Unlock(ddsSystem, ddsdSystem.lpSurface);
+ // IDirectDrawSurface2_Release(ddsSystem);
+
+ // total = timeGetTime() - start;
+ // PlotDots(10, 14, total);
+
+ if (freeSprite)
+ free(sprite);
+
+ }
+ else
+ {
+
+ // Create a surface for the sprite and then draw it.
+ memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+ ddsd.dwSize = sizeof(DDSURFACEDESC);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ if (s->scale & 0xff)
+ {
+ if (dxHalCaps & RDCAPS_BLTSTRETCH)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ }
+ else
+ {
+ if (dxHalCaps & RDCAPS_SRCBLTCKEY)
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ }
+
+ ddsd.dwWidth = s->w;
+ ddsd.dwHeight = s->h;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &dds, NULL);
+ if (hr == DDERR_OUTOFVIDEOMEMORY)
+ {
+ ddsd.ddsCaps.dwCaps &= (0xffffffff - DDSCAPS_VIDEOMEMORY);
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+ hr = IDirectDraw2_CreateSurface(lpDD2, &ddsd, &dds, NULL);
+ }
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot create sprite surface", hr);
+ return(hr);
+ }
+
+ if (s->type & RDSPR_TRANS)
+ hr = IDirectDrawSurface2_SetColorKey(dds, DDCKEY_SRCBLT, &blackColorKey);
+
+ if (s->type &RDSPR_NOCOMPRESSION)
+ {
+ sprite = s->data;
+ }
+ else
+ {
+ sprite = (uint8 *) malloc(s->w * s->h);
+ freeSprite = 1;
+ if (sprite == NULL)
+ {
+ IDirectDrawSurface2_Release(dds);
+ return(RDERR_OUTOFMEMORY);
+ }
+ if (s->type >> 8 == RDSPR_RLE16 >> 8)
+ {
+ if (DecompressRLE16(sprite, s->data, s->w * s->h, s->colourTable))
+ return(RDERR_DECOMPRESSION);
+ }
+ else
+ {
+ if (DecompressRLE256(sprite, s->data, s->w * s->h))
+ return(RDERR_DECOMPRESSION);
+ }
+
+ if (s->type & RDSPR_FLIP)
+ {
+ newSprite = (uint8 *) malloc(s->w * s->h);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+ MirrorSprite(newSprite, sprite, s->w, s->h);
+ free(sprite);
+ sprite = newSprite;
+ }
+ }
+
+ hr = IDirectDrawSurface2_Lock(dds, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ IDirectDrawSurface2_Restore(dds);
+ hr = IDirectDrawSurface2_Lock(dds, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
+ if (hr != DD_OK)
+ {
+ DirectDrawError("Cannot lock sprite surface", hr);
+ return(hr);
+ }
+ }
+
+ flag = 0;
+ if (s->type & RDSPR_BLEND)
+ {
+ for (i=0; i<s->h; i++)
+ {
+ src = sprite + i * s->w;
+ dst = (uint8 *) ddsd.lpSurface + ddsd.lPitch * i;
+ flag ^= 1;
+ if (flag)
+ {
+ j=0;
+ while (j < s->w)
+ {
+ *dst = *src;
+ if (++j == s->w)
+ break;
+ *(dst+1) = 0;
+ j++;
+ dst += 2;
+ src += 2;
+ }
+
+// for (j=0; j<(s->w-1)/2; j++)
+// {
+// *dst = *src;
+// *(dst+1) = 0;
+// dst += 2;
+// src += 2;
+// }
+ }
+ else
+ {
+// dst += 1;
+// src += 1;
+ j = 0;
+ while (j < s->w)
+ {
+ *dst = 0;
+ if (++j == s->w)
+ break;
+ *(dst + 1) = *(src + 1);
+ j++;
+ dst += 2;
+ src += 2;
+ }
+// for (j=0; j<s->w/2; j++)
+// {
+// *dst = 0;
+// *(dst+1) = *(src+1);
+// dst += 2;
+// src += 2;
+// }
+ }
+ }
+ }
+ else
+ {
+ src = sprite;
+ dst = (uint8 *) ddsd.lpSurface;
+ for (i=0; i<s->h; i++)
+ {
+ memcpy(dst, src, s->w);
+ src += s->w;
+ dst += ddsd.lPitch;
+ }
+ }
+
+ IDirectDrawSurface2_Unlock(dds, ddsd.lpSurface);
+
+ // Set startx and starty for the screen buffer ADDED THIS!
+ if (s->type & RDSPR_DISPLAYALIGN)
+ rd.top = s->y;
+ else
+ rd.top = s->y - scrolly;
+
+ if (s->type & RDSPR_DISPLAYALIGN)
+ rd.left = s->x;
+ else
+ rd.left = s->x - scrollx;
+
+ rs.left = 0;
+ rs.right = s->w;
+ rs.top = 0;
+ rs.bottom = s->h;
+ if (s->scale & 0xff)
+ {
+ rd.right = rd.left + s->scaledWidth;
+ rd.bottom = rd.top + s->scaledHeight;
+ // Do clipping
+ if (rd.top < 40)
+ {
+ rs.top = (40 - rd.top) * 256 / s->scale;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440)
+ {
+ rs.bottom -= ((rd.bottom - 440) * 256 / s->scale);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0)
+ {
+ rs.left = (0 - rd.left) * 256 / s->scale;
+ rd.left = 0;
+ }
+ if (rd.right > 640)
+ {
+ rs.right -= ((rd.right - 640) * 256 / s->scale);
+ rd.right = 640;
+ }
+ }
+ else
+ {
+ rd.right = rd.left + s->w;
+ rd.bottom = rd.top + s->h;
+
+ // Do clipping
+ if (rd.top < 40)
+ {
+ rs.top = 40 - rd.top;
+ rd.top = 40;
+ }
+ if (rd.bottom > 440)
+ {
+ rs.bottom -= (rd.bottom - 440);
+ rd.bottom = 440;
+ }
+ if (rd.left < 0)
+ {
+ rs.left = 0 - rd.left;
+ rd.left = 0;
+ }
+ if (rd.right > 640)
+ {
+ rs.right -= (rd.right - 640);
+ rd.right = 640;
+ }
+ }
+
+ if (s->type & RDSPR_TRANS)
+ {
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &rd, dds, &rs, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
+ if (hr)
+ if (dxHalCaps & RDCAPS_BLTSTRETCH)
+ dxHalCaps -= RDCAPS_BLTSTRETCH;
+ }
+ else
+ hr = IDirectDrawSurface2_Blt(lpBackBuffer, &rd, dds, &rs, DDBLT_WAIT, NULL);
+
+ IDirectDrawSurface2_Release(dds);
+ if (freeSprite)
+ free(sprite);
+ }
+
+ }
+ else
+ {
+ uint16 i, j, k;
+ int16 starty, endy;
+ int16 startx, endx;
+ uint8 *src, *dst;
+ uint8 *lightMap;
+ uint8 *srcExtra[4];
+ uint8 *sprite, *newSprite, *newerSprite, *spr, *p;
+ uint8 pixel;
+ int32 dx, dy, ince, incne, d;
+ int16 x, y;
+ static int16 randCount = 0;
+ int16 count, spriteCount;
+ int16 red, green, blue;
+ uint8 pt[5];
+ RECT clippedTarget, clippedSprite;
+ int32 diff;
+
+// if (!(s->type & RDSPR_DISPLAYALIGN))
+// {
+// s->x += parallaxScrollx;
+// s->y += parallaxScrolly;
+// }
+
+ if (s->type & RDSPR_TRANS)
+ {
+
+ if (s->type & RDSPR_NOCOMPRESSION)
+ {
+
+ // We want to blend the sprite FROM the RECT clippedSprite.
+ // We want to blend the sprite TO the RECT clippedTarget.
+ clippedSprite.top = 0;
+ clippedSprite.bottom = s->h;
+ clippedSprite.left = 0;
+ clippedSprite.right = s->w;
+ if (s->type & RDSPR_DISPLAYALIGN)
+ clippedTarget.top = s->y;
+ else
+ clippedTarget.top = s->y - scrolly;
+
+ if (s->type & RDSPR_DISPLAYALIGN)
+ clippedTarget.left = s->x;
+ else
+ clippedTarget.left = s->x - scrollx;
+
+ clippedTarget.right = clippedTarget.left + s->w;
+ clippedTarget.bottom = clippedTarget.top + s->h;
+
+ //Now do the clipping - top
+ if (clippedTarget.top < 0)
+ {
+ clippedSprite.top -= clippedTarget.top;
+ clippedTarget.top = 0;
+ }
+ //Clip the bottom
+ if (clippedTarget.bottom > RENDERDEEP)
+ {
+ clippedSprite.bottom -= (clippedTarget.bottom - RENDERDEEP);
+ clippedTarget.bottom = RENDERDEEP;
+ }
+ //Clip the left
+ if (clippedTarget.left < 0)
+ {
+ clippedSprite.left -= clippedTarget.left;
+ clippedTarget.left = 0;
+ }
+ //Clip the right
+ if (clippedTarget.right > RENDERWIDE)
+ {
+ clippedSprite.right -= (clippedTarget.right - RENDERWIDE);
+ clippedTarget.right = RENDERWIDE;
+ }
+
+ if (s->type & RDSPR_BLEND)
+ {
+ if (renderCaps & RDBLTFX_FLATALPHA)
+ {
+ red = s->blend >> 8;
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ src = s->data + (clippedSprite.top + i) * s->w + clippedSprite.left;
+ dst = myScreenBuffer + RENDERWIDE * (clippedTarget.top + i) + clippedTarget.left;
+ // newSprite = (uint8 *) ddsdSystem.lpSurface + ddsdSystem.lPitch * i;
+ for (j=0; j<clippedSprite.right - clippedSprite.left; j++)
+ {
+ if (*src)
+ {
+ pixel = *dst;
+ // pixel = *newSprite;
+ *dst = paletteMatch[(((palCopy[*src][0] * red + palCopy[pixel][0] * (8 - red)) >> 5) << 12) +
+ (((palCopy[*src][1] * red + palCopy[pixel][1] * (8 - red)) >> 5) << 6) +
+ (((palCopy[*src][2] * red + palCopy[pixel][2] * (8 - red)) >> 5) )];
+ }
+ src++;
+ dst++;
+ // newSprite++;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ src = s->data + (clippedSprite.top + i) * s->w + clippedSprite.left;
+ dst = myScreenBuffer + RENDERWIDE * (clippedTarget.top + i) + clippedTarget.left;
+ for (j=0; j<clippedSprite.right - clippedSprite.left; j++)
+ {
+ if (*src)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ }
+ }
+ else
+ {
+
+ // Ok, the sprite is compressed, so lets find out what type
+ switch (s->type >> 8)
+ {
+
+ case (RDSPR_RLE256FAST >> 8):
+ SoftwareRenderCompressed256(s);
+ break;
+
+ case (RDSPR_RLE256 >> 8):
+ case (RDSPR_RLE16>>8):
+
+ if (s->type & RDSPR_DISPLAYALIGN)
+ return(RDERR_NOTIMPLEMENTED);
+
+ sprite = malloc(s->w * s->h);
+ if (sprite == NULL)
+ return(RDERR_OUTOFMEMORY);
+
+ if (s->type >> 8 == RDSPR_RLE16 >> 8)
+ {
+ if (DecompressRLE16(sprite, s->data, s->w * s->h, s->colourTable))
+ return(RDERR_DECOMPRESSION);
+ }
+ else
+ {
+ if (DecompressRLE256(sprite, s->data, s->w * s->h))
+ return(RDERR_DECOMPRESSION);
+ }
+
+ if (s->type & RDSPR_FLIP)
+ {
+ newSprite = (uint8 *) malloc(s->w * s->h);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+ MirrorSprite(newSprite, sprite, s->w, s->h);
+ free(sprite);
+ sprite = newSprite;
+ }
+
+ if ((s->scale == 0) || (s->scale == 256))
+ {
+ if ((s->type & RDSPR_EDGEBLEND) && (renderCaps & RDBLTFX_EDGEBLEND))
+ {
+ // The sprite is to be edge blended. Let's get a copy of the background
+ // into a new sprite buffer, and write the sprite over it with edge blending
+ newSprite = malloc(s->w * s->h);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // RIGHT, SORT THIS FUCKING MESS OUT.
+ // We want to draw the sprite FROM the RECT clippedSprite.
+ // We want to draw the sprite TO the RECT clippedTarget.
+ clippedTarget.left = s->x - scrollx;
+ clippedTarget.right = clippedTarget.left + s->w;
+ clippedTarget.top = s->y - scrolly;
+ clippedTarget.bottom = clippedTarget.top + s->h;
+
+ clippedSprite.top = 0;
+ clippedSprite.bottom = s->h;
+ clippedSprite.left = 0;
+ clippedSprite.right = s->w;
+
+ //Now do the clipping - top
+ if (clippedTarget.top < 0)
+ {
+ clippedSprite.top -= clippedTarget.top;
+ clippedTarget.top = 0;
+ }
+ //Clip the bottom
+ if (clippedTarget.bottom > RENDERDEEP)
+ {
+ clippedSprite.bottom -= (clippedTarget.bottom - RENDERDEEP);
+ clippedTarget.bottom = RENDERDEEP;
+ }
+ //Clip the left
+ if (clippedTarget.left < 0)
+ {
+ clippedSprite.left -= clippedTarget.left;
+ clippedTarget.left = 0;
+ }
+ //Clip the right
+ if (clippedTarget.right > RENDERWIDE)
+ {
+ clippedSprite.right -= (clippedTarget.right - RENDERWIDE);
+ clippedTarget.right = RENDERWIDE;
+ }
+
+ // We now have our clipped regions, so let's copy the background to the sprite.
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ memcpy(newSprite + s->w * i + clippedSprite.left, myScreenBuffer + RENDERWIDE * (clippedTarget.top+i) + clippedTarget.left, clippedSprite.right - clippedSprite.left);
+ }
+
+
+ // Now put the sprite onto the background sprite!?!
+ src = sprite + (clippedSprite.top + 1) * s->w + clippedSprite.left + 1;
+ srcExtra[0] = src - s->w;
+ srcExtra[1] = src - 1;
+ srcExtra[2] = src + 1;
+ srcExtra[3] = src + s->w;
+ dst = newSprite + (clippedSprite.top + 1) * s->w + clippedSprite.left + 1;
+ for (j=1; j<clippedSprite.bottom - clippedSprite.top - 1; j++)
+ {
+ for (i=1; i<clippedSprite.right - clippedSprite.left - 1; i++)
+ {
+ if (*src)
+ {
+ uint8 newp = *src;
+ count = 1;
+
+ red = palCopy[newp][0];
+ green = palCopy[newp][1];
+ blue = palCopy[newp][2];
+ for (k=0; k<4; k++)
+ {
+ if (newp = *srcExtra[k])
+ {
+ red += palCopy[newp][0];
+ green += palCopy[newp][1];
+ blue += palCopy[newp][2];
+ count += 1;
+ }
+ else
+ {
+ newp = *(dst - (src - srcExtra[k]));
+ red += palCopy[newp][0];
+ green += palCopy[newp][1];
+ blue += palCopy[newp][2];
+ }
+ }
+
+ if (count != 5)
+ *dst = QuickMatch((uint8) (red / 5), (uint8) (green / 5), (uint8) (blue / 5));
+ else
+ *dst = *src;
+ }
+ src++;
+ dst++;
+ for (k=0; k<4; k++)
+ srcExtra[k]++;
+ }
+ diff = (s->w - (clippedSprite.right - clippedSprite.left)) + 2;
+ for (k=0; k<4; k++)
+ srcExtra[k] += diff;
+ src += diff;
+ dst += diff;
+ }
+
+ // And copy the sprite back to the screen
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ memcpy(myScreenBuffer + RENDERWIDE * (clippedTarget.top+i) + clippedTarget.left, newSprite + s->w * i + clippedSprite.left, clippedSprite.right - clippedSprite.left);
+ }
+
+ free(newSprite);
+ }
+ else if (s->type & RDSPR_BLEND)
+ {
+
+ // We want to blend the sprite FROM the RECT clippedSprite.
+ // We want to blend the sprite TO the RECT clippedTarget.
+ clippedTarget.left = s->x - scrollx;
+ clippedTarget.right = clippedTarget.left + s->w;
+ clippedTarget.top = s->y - scrolly;
+ clippedTarget.bottom = clippedTarget.top + s->h;
+
+ clippedSprite.top = 0;
+ clippedSprite.bottom = s->h;
+ clippedSprite.left = 0;
+ clippedSprite.right = s->w;
+
+ //Now do the clipping - top
+ if (clippedTarget.top < 0)
+ {
+ clippedSprite.top -= clippedTarget.top;
+ clippedTarget.top = 0;
+ }
+ //Clip the bottom
+ if (clippedTarget.bottom > RENDERDEEP)
+ {
+ clippedSprite.bottom -= (clippedTarget.bottom - RENDERDEEP);
+ clippedTarget.bottom = RENDERDEEP;
+ }
+ //Clip the left
+ if (clippedTarget.left < 0)
+ {
+ clippedSprite.left -= clippedTarget.left;
+ clippedTarget.left = 0;
+ }
+ //Clip the right
+ if (clippedTarget.right > RENDERWIDE)
+ {
+ clippedSprite.right -= (clippedTarget.right - RENDERWIDE);
+ clippedTarget.right = RENDERWIDE;
+ }
+
+ if (s->blend & 0x01)
+ {
+ if (renderCaps & RDBLTFX_FLATALPHA)
+ {
+ red = s->blend >> 8;
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ src = sprite + (clippedSprite.top + i) * s->w + clippedSprite.left;
+ dst = myScreenBuffer + RENDERWIDE * (clippedTarget.top + i) + clippedTarget.left;
+ // newSprite = (uint8 *) ddsdSystem.lpSurface + ddsdSystem.lPitch * i;
+ for (j=0; j<clippedSprite.right - clippedSprite.left; j++)
+ {
+ if (*src)
+ {
+ pixel = *dst;
+ // pixel = *newSprite;
+ *dst = paletteMatch[(((palCopy[*src][0] * red + palCopy[pixel][0] * (8 - red)) >> 5) << 12) +
+ (((palCopy[*src][1] * red + palCopy[pixel][1] * (8 - red)) >> 5) << 6) +
+ (((palCopy[*src][2] * red + palCopy[pixel][2] * (8 - red)) >> 5) )];
+ }
+ src++;
+ dst++;
+ // newSprite++;
+ }
+ }
+ }
+ else
+ {
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ src = sprite + (clippedSprite.top + i) * s->w + clippedSprite.left;
+ dst = myScreenBuffer + RENDERWIDE * (clippedTarget.top + i) + clippedTarget.left;
+ // newSprite = (uint8 *) ddsdSystem.lpSurface + ddsdSystem.lPitch * i;
+ for (j=0; j<clippedSprite.right - clippedSprite.left; j++)
+ {
+ if (*src)
+ {
+ *dst = *src;
+ }
+ src++;
+ dst++;
+ }
+ }
+ }
+ }
+ else if (s->blend & 0x02)
+ {
+ red = palCopy[s->blend >> 8][0];
+ green = palCopy[s->blend >> 8][0];
+ blue = palCopy[s->blend >> 8][0];
+
+
+ if (renderCaps & RDBLTFX_GRADEDALPHA)
+ {
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ src = sprite + (clippedSprite.top + i) * s->w + clippedSprite.left;
+ dst = myScreenBuffer + RENDERWIDE * (clippedTarget.top + i) + clippedTarget.left;
+ for (j=0; j<clippedSprite.right - clippedSprite.left; j++)
+ {
+ if (*src)
+ {
+ *dst = paletteMatch[((((*src * red + (16 - *src) * palCopy[*(dst)][0]) >> 4) >> 2) << 12) +
+ ((((*src * green + (16 - *src) * palCopy[*(dst)][1]) >> 4) >> 2) << 6) +
+ (((*src * blue + (16 - *src) * palCopy[*(dst)][2]) >> 4) >> 2)];
+
+ }
+ src++;
+ dst++;
+ }
+ }
+ }
+ else
+ {
+ char col = paletteMatch[((36 >> 2) << 12) + ((35 >> 2) << 6) + (34 >> 2)];
+ for (i=0; i<clippedSprite.bottom - clippedSprite.top; i++)
+ {
+ src = sprite + (clippedSprite.top + i) * s->w + clippedSprite.left;
+ dst = myScreenBuffer + RENDERWIDE * (clippedTarget.top + i) + clippedTarget.left;
+ for (j=0; j<clippedSprite.right - clippedSprite.left; j++)
+ {
+ if (*src)
+ {
+ *dst = col;
+ }
+ src++;
+ dst++;
+ }
+ }
+ }
+ }
+ else
+ {
+ free(sprite);
+ DirectDrawError("Invalid blended sprite params", RDERR_UNKNOWNTYPE);
+ return(RDERR_UNKNOWNTYPE);
+ }
+
+
+
+ }
+ else
+ {
+
+ starty = s->y - scrolly;
+ endy = starty + s->h;
+ if (starty < 0)
+ starty = 0;
+ if (endy > RENDERDEEP)
+ endy = RENDERDEEP;
+
+ startx = s->x - scrollx;
+ endx = startx + s->w;
+ if (startx < 0)
+ startx = 0;
+ if (endx > RENDERWIDE)
+ endx = RENDERWIDE;
+
+ for (i=starty; i<endy; i++)
+ {
+ dst = myScreenBuffer + i * RENDERWIDE+ startx;
+ src = sprite + (i - (s->y - scrolly)) * s->w + (startx - (s->x - scrollx));
+ if ((s->type & RDSPR_SHADOW) && (lightMask) && (renderCaps & RDBLTFX_SHADOWBLEND))
+ {
+ lightMap = lightMask + (i+scrolly) * locationWide + s->x;
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ {
+ if (*lightMap)
+ *dst = QuickMatch((uint8) (((int32) (32 - *lightMap) * palCopy[*src][0]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][1]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][2]) >> 5));
+ else
+ *dst = *src;
+ }
+ dst++;
+ src++;
+ lightMap++;
+ }
+ }
+ else
+ {
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ }
+ }
+ }
+ else if (s->scale < 256) // Draw the sprite with scaling and arithmetic stretching
+ {
+ if (renderCaps & RDBLTFX_ARITHMETICSTRETCH)
+ {
+
+ if ((s->scaledWidth > SCALE_MAXWIDTH) || (s->scaledHeight > SCALE_MAXHEIGHT))
+ {
+ free(sprite);
+ return(RDERR_NOTIMPLEMENTED);
+ }
+
+ // Create the buffer to copy the small sprite into
+ newSprite = malloc(s->scaledWidth * s->scaledHeight);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // Work out the x-scale
+ dx = s->w;
+ dy = s->scaledWidth;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ xScale[y] = x;
+ while (x < s->w)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ xScale[y] = x;
+ }
+
+ // Work out the y-scale
+ dx = s->h;
+ dy = s->scaledHeight;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ yScale[y] = x;
+ while (x < s->h)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ yScale[y] = x;
+ }
+
+ // If the sprite is clipped, then don't try to anti-alias it and arithmetic stretch.
+ // Just go for the quick and dirty squash!
+ if ((s->x - scrollx < 0) || (s->x - scrollx + s->scaledWidth > RENDERWIDE) ||
+ (s->y - scrolly < 0) || (s->y - scrolly + s->scaledHeight > RENDERDEEP))
+ {
+ spr = newSprite;
+ for (y=0; y<s->scaledHeight; y++)
+ {
+ for (x=0; x<s->scaledWidth; x++)
+ {
+ *spr++ = *(sprite + yScale[y] * s->w + xScale[x]);
+ }
+ }
+ }
+ else
+ {
+ spr = newSprite;
+ for (y=0; y<s->scaledHeight; y++)
+ {
+ for (x=0; x<s->scaledWidth; x++)
+ {
+ count = 0;
+ spriteCount = 0;
+ red = 0;
+ green = 0;
+ blue = 0;
+ for (j=yScale[y]; j<yScale[y+1]; j++)
+ {
+ for (i=xScale[x]; i<xScale[x+1]; i++)
+ {
+ p = sprite + j * s->w + i;
+ if (*p == 0)
+ {
+ uint8 newp;
+
+ newp = myScreenBuffer[(s->y - scrolly + y) * RENDERWIDE + s->x - scrollx + x];
+ red += palCopy[newp][0];
+ green += palCopy[newp][1];
+ blue += palCopy[newp][2];
+ }
+ else
+ {
+ red += palCopy[*p][0];
+ green += palCopy[*p][1];
+ blue += palCopy[*p][2];
+ spriteCount += 1;
+ }
+ count += 1;
+ }
+ }
+ if (spriteCount == 0)
+ {
+ *spr++ = 0;
+ }
+ else if (count == 1)
+ {
+ *spr++ = *p;
+ }
+ else
+ {
+ *spr++ = QuickMatch((uint8) (red / count), (uint8) (green / count), (uint8) (blue / count));
+ }
+ }
+ }
+ }
+
+ // Draw the sprite
+ starty = s->y - scrolly;
+ endy = starty + s->scaledHeight;
+ if (starty < 0)
+ starty = 0;
+ if (endy > RENDERDEEP)
+ endy = RENDERDEEP;
+
+ startx = s->x - scrollx;
+ endx = startx + s->scaledWidth;
+ if (startx < 0)
+ startx = 0;
+ if (endx > RENDERWIDE)
+ endx = RENDERWIDE;
+
+ for (i=starty; i<endy; i++)
+ {
+ dst = myScreenBuffer + i * RENDERWIDE+ startx;
+ src = newSprite + (i - (s->y - scrolly)) * s->scaledWidth + (startx - (s->x - scrollx));
+
+ if ((lightMask) && (renderCaps & RDBLTFX_SHADOWBLEND))
+ {
+ lightMap = lightMask + (i+scrolly) * locationWide + s->x;
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ {
+ if (*lightMap)
+ *dst = QuickMatch((uint8) (((int32) (32 - *lightMap) * palCopy[*src][0]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][1]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][2]) >> 5));
+ else
+ *dst = *src;
+ }
+ dst++;
+ src++;
+ lightMap++;
+ }
+ }
+ else
+ {
+
+
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ }
+
+ free(newSprite);
+
+ }
+ else // Draw scaled, value less than 256, line doubling
+ {
+ if ((s->scaledWidth > SCALE_MAXWIDTH) || (s->scaledHeight > SCALE_MAXHEIGHT))
+ {
+ free(sprite);
+ return(RDERR_NOTIMPLEMENTED);
+ }
+
+ // Create the buffer to copy the small sprite into
+ newSprite = malloc(s->scaledWidth * s->scaledHeight);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // Work out the x-scale
+ dx = s->w;
+ dy = s->scaledWidth;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ xScale[y] = x;
+ while (x < s->w)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ xScale[y] = x;
+ }
+
+ // Work out the y-scale
+ dx = s->h;
+ dy = s->scaledHeight;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ yScale[y] = x;
+ while (x < s->h)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ }
+ yScale[y] = x;
+ }
+
+ // Copy the sprite
+ // InitialiseColourMatch(s->colourTable);
+ spr = newSprite;
+ for (y=0; y<s->scaledHeight; y++)
+ {
+ for (x=0; x<s->scaledWidth; x++)
+ {
+ *spr++ = *(sprite + yScale[y] * s->w + xScale[x]);
+ }
+ }
+
+ // Draw the sprite
+ starty = s->y - scrolly;
+ endy = starty + s->scaledHeight;
+ if (starty < 0)
+ starty = 0;
+ if (endy > RENDERDEEP)
+ endy = RENDERDEEP;
+
+ startx = s->x - scrollx;
+ endx = startx + s->scaledWidth;
+ if (startx < 0)
+ startx = 0;
+ if (endx > RENDERWIDE)
+ endx = RENDERWIDE;
+
+ for (i=starty; i<endy; i++)
+ {
+ dst = myScreenBuffer + i * RENDERWIDE+ startx;
+ src = newSprite + (i - (s->y - scrolly)) * s->scaledWidth + (startx - (s->x - scrollx));
+ if ((lightMask) && (renderCaps & RDBLTFX_SHADOWBLEND))
+ {
+ lightMap = lightMask + (i + scrolly) * locationWide + s->x;
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ {
+ if (*lightMap)
+ *dst = QuickMatch((uint8) (((int32) (32 - *lightMap) * palCopy[*src][0]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][1]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][2]) >> 5));
+ else
+ *dst = *src;
+ }
+ dst++;
+ src++;
+ lightMap++;
+ }
+ }
+ else
+ {
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ }
+
+ free(newSprite);
+ }
+
+ }
+ else //if (s->scale > 256)
+ {
+ if (s->scale > 512)
+ {
+ free(sprite);
+ return(RDERR_INVALIDSCALING);
+ }
+
+ if (renderCaps & RDBLTFX_ARITHMETICSTRETCH) // Draw the sprite with scaling and anti-aliasing
+ {
+
+ // Create the buffer to copy the bigger sprite into
+ newSprite = malloc(s->scaledWidth * s->scaledHeight);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // Work out the x-scale
+ dy = s->w;
+ dx = s->scaledWidth;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ xScale[y] = x;
+ while (x < s->scaledWidth)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ xScale[y] = x;
+ }
+ }
+
+ // Work out the y-scale
+ dy = s->h;
+ dx = s->scaledHeight;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ yScale[y] = x;
+ while (x < s->scaledHeight)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ yScale[y] = x;
+ }
+ }
+
+ // Copy the sprite
+ // InitialiseColourMatch(s->colourTable);
+ spr = newSprite;
+ for (y=0; y<s->h; y++)
+ {
+ for (j=yScale[y]; j<yScale[y+1]; j++)
+ {
+ for (x=0; x<s->w; x++)
+ {
+ for (i=xScale[x]; i<xScale[x+1]; i++)
+ {
+ *spr++ = *(sprite + y * s->w + x);
+ }
+ }
+ }
+ }
+
+ // Piece of code to anti-alias the sprite.
+ newerSprite = malloc(s->scaledWidth * s->scaledHeight);
+ if (newerSprite == NULL)
+ {
+ free(newSprite);
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // THIS IS THE ANTI-ALIAS LOOP - IF THE SPRITE IS CLIPPED, DON'T ANTI-ALIAS
+
+ if (!((s->x - scrollx < 0) || (s->x - scrollx + s->scaledWidth > RENDERWIDE) ||
+ (s->y - scrolly < 0) || (s->y - scrolly + s->scaledHeight > RENDERDEEP)))
+ {
+ memcpy(newerSprite, newSprite, s->scaledWidth);
+ for (y = 1; y < s->scaledHeight-1; y++)
+ {
+ src = newSprite + y * s->scaledWidth;
+ dst = newerSprite + y * s->scaledWidth;
+ *dst++ = *src++;
+ for (x=1; x<s->scaledWidth-1; x++)
+ {
+ p = &myScreenBuffer[(s->y - scrolly + y) * RENDERWIDE + s->x - scrollx + x];
+ count = 0;
+ if (*src)
+ {
+ count ++;
+ pt[0] = *src;
+ }
+ else
+ pt[0] = *p;
+
+ pt[1] = *(src - s->scaledWidth);
+ if (pt[1] == 0)
+ pt[1] = *(p - RENDERWIDE);
+ else
+ count++;
+
+ pt[2] = *(src - 1);
+ if (pt[2] == 0)
+ pt[2] = *(p - 1);
+ else
+ count++;
+
+ pt[3] = *(src + 1);
+ if (pt[3] == 0)
+ pt[3] = *(p + 1);
+ else
+ count++;
+
+ pt[4] = *(src + s->scaledWidth);
+ if (pt[4] == 0)
+ pt[4] = *(p + RENDERWIDE);
+ else
+ count++;
+
+ if (count)
+ {
+ red = palCopy[pt[0]][0] << 2;
+ green = palCopy[pt[0]][1] << 2;
+ blue = palCopy[pt[0]][2] << 2;
+ for (i=1; i<5; i++)
+ {
+ red += palCopy[pt[i]][0];
+ green += palCopy[pt[i]][1];
+ blue += palCopy[pt[i]][2];
+ }
+
+ *dst++ = QuickMatch((uint8) (red >> 3), (uint8) (green >> 3), (uint8) (blue >> 3));
+ }
+ else
+ {
+ *dst++ = 0;
+ }
+ src++;
+ }
+ *dst++ = *src++;
+
+ }
+ memcpy(dst, src, s->scaledWidth);
+ free(newSprite);
+ newSprite = newerSprite;
+ }
+
+
+
+
+
+ // Draw the sprite
+ starty = s->y - scrolly;
+ endy = starty + s->scaledHeight;
+ if (starty < 0)
+ starty = 0;
+ if (endy > RENDERDEEP)
+ endy = RENDERDEEP;
+
+ startx = s->x - scrollx;
+ endx = startx + s->scaledWidth;
+ if (startx < 0)
+ startx = 0;
+ if (endx > RENDERWIDE)
+ endx = RENDERWIDE;
+
+ for (i=starty; i<endy; i++)
+ {
+ dst = myScreenBuffer + i * RENDERWIDE+ startx;
+ src = newSprite + (i - (s->y - scrolly)) * s->scaledWidth + (startx - (s->x - scrollx));
+ if ((lightMask) && (renderCaps & RDBLTFX_SHADOWBLEND))
+ {
+ lightMap = lightMask + (i + scrolly) * locationWide + s->x;
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ {
+ if (*lightMap)
+ *dst = QuickMatch((uint8) (((int32) (32 - *lightMap) * palCopy[*src][0]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][1]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][2]) >> 5));
+ else
+ *dst = *src;
+ }
+ dst++;
+ src++;
+ lightMap++;
+ }
+ }
+ else
+ {
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ }
+
+ free(newSprite);
+ }
+ else // Draw the stretched sprite with line doubling.
+ {
+ // Create the buffer to copy the bigger sprite into
+ newSprite = malloc(s->scaledWidth * s->scaledHeight);
+ if (newSprite == NULL)
+ {
+ free(sprite);
+ return(RDERR_OUTOFMEMORY);
+ }
+
+ // Work out the x-scale
+ dy = s->w;
+ dx = s->scaledWidth;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ xScale[y] = x;
+ while (x < s->scaledWidth)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ xScale[y] = x;
+ }
+ }
+
+ // Work out the y-scale
+ dy = s->h;
+ dx = s->scaledHeight;
+ ince = 2 * dy;
+ incne = 2 * (dy - dx);
+ d = 2 * dy - dx;
+
+ x = 0;
+ y = 0;
+ yScale[y] = x;
+ while (x < s->scaledHeight)
+ {
+ if (d <= 0)
+ {
+ d += ince;
+ x += 1;
+ }
+ else
+ {
+ d += incne;
+ x += 1;
+ y += 1;
+ yScale[y] = x;
+ }
+ }
+
+ // Copy the sprite
+ // InitialiseColourMatch(s->colourTable);
+ spr = newSprite;
+ for (y=0; y<s->h; y++)
+ {
+ for (j=yScale[y]; j<yScale[y+1]; j++)
+ {
+ for (x=0; x<s->w; x++)
+ {
+ for (i=xScale[x]; i<xScale[x+1]; i++)
+ {
+ *spr++ = *(sprite + y * s->w + x);
+ }
+ }
+ }
+ }
+
+ // Piece of code to anti-alias the sprite.
+
+ // Draw the sprite
+ starty = s->y - scrolly;
+ endy = starty + s->scaledHeight;
+ if (starty < 0)
+ starty = 0;
+ if (endy > RENDERDEEP)
+ endy = RENDERDEEP;
+
+ startx = s->x - scrollx;
+ endx = startx + s->scaledWidth;
+ if (startx < 0)
+ startx = 0;
+ if (endx > RENDERWIDE)
+ endx = RENDERWIDE;
+
+ for (i=starty; i<endy; i++)
+ {
+ dst = myScreenBuffer + i * RENDERWIDE+ startx;
+ src = newSprite + (i - (s->y - scrolly)) * s->scaledWidth + (startx - (s->x - scrollx));
+
+
+
+ if ((lightMask) && (renderCaps & RDBLTFX_SHADOWBLEND))
+ {
+ lightMap = lightMask + (i + scrolly) * locationWide + s->x;
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ {
+ if (*lightMap)
+ *dst = QuickMatch((uint8) (((int32) (32 - *lightMap) * palCopy[*src][0]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][1]) >> 5),
+ (uint8) (((int32) (32 - *lightMap) * palCopy[*src][2]) >> 5));
+ else
+ *dst = *src;
+ }
+ dst++;
+ src++;
+ lightMap++;
+ }
+ }
+ else
+ {
+ for (j=startx; j<endx; j++)
+ {
+ if (*src)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+ }
+ }
+
+ free(newSprite);
+ }
+
+ }
+
+ free(sprite);
+ break;
+// case (RDSPR_LAYERCOMPRESSION>>8):
+// return(RDERR_NOTIMPLEMENTED);
+// break;
+ default:
+ return(RDERR_UNKNOWNTYPE);
+ }
+ }
+ }
+ else //(type & RDSPR_FULL):
+ {
+
+ // Set startx and starty for the screen buffer
+ if (s->type & RDSPR_DISPLAYALIGN)
+ {
+ starty = s->y;
+ startx = s->x;
+ }
+ else
+ {
+ starty = s->y - scrolly;
+ startx = s->x - scrollx;
+ }
+
+
+ // Set end position of x and y.
+ endy = s->h + starty;
+ endx = s->w + startx;
+
+
+ // Do clipping
+ if ((starty < RENDERDEEP) && (endy > 0) && (startx < RENDERWIDE) && (endx > 0))
+ {
+ if (starty < 0)
+ starty = 0;
+
+ if (endy > RENDERDEEP)
+ endy = RENDERDEEP;
+
+ if (startx < 0)
+ startx = 0;
+
+ if (endx > RENDERWIDE)
+ endx = RENDERWIDE;
+
+
+ dst = (uint8 *) myScreenBuffer + starty * RENDERWIDE + s->x;
+ if (s->type & RDSPR_DISPLAYALIGN)
+ src = (uint8 *) s->data + s->w * (starty - (s->y)) + (startx - s->x);
+ else
+ src = (uint8 *) s->data + s->w * (starty - (s->y - scrolly)) + (startx - (s->x - scrollx));
+
+ for (i=starty; i<endy; i++)
+ {
+ memcpy(dst, src, endx - startx);
+ src += s->w;
+ dst += RENDERWIDE;
+ }
+ }
+ }
+ }
+
+#if PROFILING == 1
+ QueryPerformanceCounter(&endTime);
+ profileSpriteRender += (endTime.LowPart - startTime.LowPart);
+#endif
+*/
+ return(RD_OK);
+}
+
+
+
+int32 OpenLightMask(_spriteInfo *s)
+
+{
+
+ if (lightMask)
+ return(RDERR_NOTCLOSED);
+
+ lightMask = (uint8 *) malloc(s->w * s->h);
+
+ if (lightMask == NULL)
+ return(RDERR_OUTOFMEMORY);
+
+ if (DecompressRLE256(lightMask, s->data, s->w * s->h))
+ return(RDERR_DECOMPRESSION);
+
+ return(RD_OK);
+
+}
+
+int32 CloseLightMask(void)
+{
+
+ if (!lightMask)
+ return(RDERR_NOTOPEN);
+
+ free(lightMask);
+
+ lightMask = 0;
+
+ return(RD_OK);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+