aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/util/glsprites
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/util/glsprites')
-rwxr-xr-xengines/sword25/util/glsprites/glsprites.h108
-rwxr-xr-xengines/sword25/util/glsprites/internal/core.c212
-rwxr-xr-xengines/sword25/util/glsprites/internal/core.h40
-rwxr-xr-xengines/sword25/util/glsprites/internal/glinclude.h36
-rwxr-xr-xengines/sword25/util/glsprites/internal/glswindow.c449
-rwxr-xr-xengines/sword25/util/glsprites/internal/glswindow.h42
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite.c156
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite.h40
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite_pow2.c170
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite_pow2.h27
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite_rectangle.c164
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite_rectangle.h27
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite_tiled.c370
-rwxr-xr-xengines/sword25/util/glsprites/internal/sprite_tiled.h41
-rwxr-xr-xengines/sword25/util/glsprites/internal/util.c77
-rwxr-xr-xengines/sword25/util/glsprites/internal/util.h42
16 files changed, 2001 insertions, 0 deletions
diff --git a/engines/sword25/util/glsprites/glsprites.h b/engines/sword25/util/glsprites/glsprites.h
new file mode 100755
index 0000000000..28b00a7fe6
--- /dev/null
+++ b/engines/sword25/util/glsprites/glsprites.h
@@ -0,0 +1,108 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_GLSPRITES_H
+#define GLS_GLSPRITES_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Typedefs */
+typedef unsigned __int32 GLS_UInt32;
+typedef signed __int32 GLS_SInt32;
+typedef unsigned __int8 GLS_UInt8;
+typedef float GLS_Float;
+typedef enum { GLS_True = 1, GLS_False = 0 } GLS_Bool;
+
+/* Errors */
+typedef enum
+{
+ GLS_OK,
+ GLS_OUT_OF_MEMORY,
+ GLS_WINDOW_CREATION_FAILED,
+ GLS_WINDOW_PREPARATION_FAILED,
+ GLS_DISPLAY_MODE_CHANGE_FAILED,
+ GLS_WINDOW_WAS_CLOSED,
+ GLS_OPENGL_CONTEXT_CREATION_FAILED,
+ GLS_COULD_NOT_FLIP,
+ GLS_TEXTURE_CREATION_FAILED,
+ GLS_NO_WINDOW,
+ GLS_INVALID_SPRITE_OBJECT,
+ GLS_INVALID_SPRITE_DIMENSIONS,
+ GLS_NO_DRIVER_SUPPORT_FOR_VSYNC,
+ GLS_OPENGL_ERROR,
+ GLS_INVALID_DATA_DIMENSIONS,
+ GLS_INVALID_DATA_POINTER,
+ GLS_INVALID_SUB_IMAGE,
+} GLS_Result;
+
+/* GLS_Rect */
+typedef struct
+{
+ GLS_UInt32 x1;
+ GLS_UInt32 y1;
+ GLS_UInt32 x2;
+ GLS_UInt32 y2;
+} GLS_Rect;
+
+/* GLS_Color */
+typedef struct
+{
+ GLS_UInt8 r;
+ GLS_UInt8 g;
+ GLS_UInt8 b;
+ GLS_UInt8 a;
+} GLS_Color;
+
+/* GLS_Sprite */
+typedef void * GLS_Sprite;
+
+/* Functions */
+GLS_Result GLS_Init(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, const char * windowTitle, GLS_Bool allowCloseWindow);
+GLS_Result GLS_InitExternalWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, void * windowHandle);
+GLS_Result GLS_Quit();
+
+GLS_Result GLS_SetVSync(GLS_Bool status);
+GLS_Result GLS_IsVsync(GLS_Bool * pStatus);
+
+GLS_Result GLS_StartFrame();
+GLS_Result GLS_EndFrame();
+
+GLS_Result GLS_NewSprite(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, const void * data, GLS_Sprite * pSprite);
+GLS_Result GLS_DeleteSprite(GLS_Sprite sprite);
+
+GLS_Result GLS_SetSpriteData(GLS_Sprite sprite, GLS_UInt32 width, GLS_UInt32 height, const void * data, GLS_UInt32 stride);
+
+GLS_Result GLS_Blit(GLS_Sprite sprite,
+ GLS_SInt32 x, GLS_SInt32 y,
+ const GLS_Rect * subImage,
+ const GLS_Color * color,
+ GLS_Bool flipH, GLS_Bool flipV,
+ GLS_Float scaleX, GLS_Float scaleY);
+
+GLS_Result GLS_GetWindowHandle(void ** pWindowHandle);
+
+const char * GLS_ResultString(GLS_Result ResultCode);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/core.c b/engines/sword25/util/glsprites/internal/core.c
new file mode 100755
index 0000000000..deb1dcbd3d
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/core.c
@@ -0,0 +1,212 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+#include "glinclude.h"
+#include "core.h"
+#include "glswindow.h"
+
+
+/* --------------------------------------------------------------------------
+ GLOBALS
+ -------------------------------------------------------------------------- */
+
+GLS_OGLCaps GLS_TheOGLCaps;
+static GLS_Window * window = 0;
+static GLS_Bool vsyncActive = GLS_False;
+typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
+static PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
+
+
+/* -------------------------------------------------------------------------- */
+
+void InitGL(GLS_UInt32 width, GLS_UInt32 height)
+{
+ if (height == 0) height = 1;
+
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, width, height, 0, 1, -1);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glShadeModel(GL_SMOOTH);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void InitGLCaps(GLS_OGLCaps * OGLCaps)
+{
+ if (strstr(glGetString(GL_EXTENSIONS), "GL_ARB_texture_rectangle") != 0 ||
+ strstr(glGetString(GL_EXTENSIONS), "GL_EXT_texture_rectangle") != 0 ||
+ strstr(glGetString(GL_EXTENSIONS), "GL_NV_texture_rectangle") != 0)
+ {
+ OGLCaps->textureRectanglesSupported = GLS_True;
+ glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &(OGLCaps->maxTextureRectangleSize));
+ }
+ else
+ OGLCaps->textureRectanglesSupported = GLS_False;
+
+ if (strstr(glGetString(GL_EXTENSIONS), "WGL_EXT_swap_control") != 0)
+ {
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC) wglGetProcAddress("wglSwapIntervalEXT");
+ }
+
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &(OGLCaps->maxTextureSize));
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_Init(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, const char * windowTitle, GLS_Bool allowCloseWindow)
+{
+ GLS_Result Result;
+
+ Result = GLS_CreateGLWindow(width, height, fullscreen, windowTitle, allowCloseWindow, &window);
+ if (Result != GLS_OK) return Result;
+ InitGL(width, height);
+ InitGLCaps(&GLS_TheOGLCaps);
+
+ return GLS_OK;
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_InitExternalWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, void * windowHandle)
+{
+ GLS_Result Result;
+
+ Result = GLS_CreateGLExternalWindow(width, height, fullscreen, windowHandle, &window);
+ if (Result != GLS_OK) return Result;
+ InitGL(width, height);
+ InitGLCaps(&GLS_TheOGLCaps);
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_Quit()
+{
+ if (window) GLS_CloseGLWindow(window);
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_StartFrame()
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+ return GLS_ProcessWindowMessages(window);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_EndFrame()
+{
+ if (GLS_WindowFlip(window))
+ return GLS_OK;
+ else
+ return GLS_COULD_NOT_FLIP;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_GetWindowHandle(void ** pWindowHandle)
+{
+ if (window)
+ {
+ *pWindowHandle = window->hwnd;
+ return GLS_OK;
+ }
+ else
+ {
+ return GLS_NO_WINDOW;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_SetVSync(GLS_Bool status)
+{
+ if (wglSwapIntervalEXT)
+ {
+ if (wglSwapIntervalEXT(status ? 1 : 0))
+ {
+ vsyncActive = status;
+ return GLS_OK;
+ }
+ else
+ return GLS_OPENGL_ERROR;
+ }
+ else
+ return GLS_NO_DRIVER_SUPPORT_FOR_VSYNC;
+}
+
+GLS_Result GLS_IsVsync(GLS_Bool * pStatus)
+{
+ if (wglSwapIntervalEXT)
+ {
+ *pStatus = vsyncActive;
+ return GLS_OK;
+ }
+ else
+ return GLS_NO_DRIVER_SUPPORT_FOR_VSYNC;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+#define GLRS(ERR) case GLS_##ERR: return #ERR;
+const char * GLS_ResultString(GLS_Result ResultCode)
+{
+ switch (ResultCode)
+ {
+ GLRS(OK)
+ GLRS(OUT_OF_MEMORY)
+ GLRS(WINDOW_CREATION_FAILED)
+ GLRS(WINDOW_PREPARATION_FAILED)
+ GLRS(DISPLAY_MODE_CHANGE_FAILED)
+ GLRS(WINDOW_WAS_CLOSED)
+ GLRS(OPENGL_CONTEXT_CREATION_FAILED)
+ GLRS(COULD_NOT_FLIP)
+ GLRS(TEXTURE_CREATION_FAILED)
+ GLRS(NO_WINDOW)
+ GLRS(INVALID_SPRITE_OBJECT)
+ GLRS(INVALID_SPRITE_DIMENSIONS)
+ GLRS(NO_DRIVER_SUPPORT_FOR_VSYNC)
+ GLRS(OPENGL_ERROR)
+ GLRS(INVALID_DATA_DIMENSIONS)
+ GLRS(INVALID_DATA_POINTER)
+ GLRS(INVALID_SUB_IMAGE)
+ default:
+ return "unknown result code";
+ }
+}
+#undef GLRS
diff --git a/engines/sword25/util/glsprites/internal/core.h b/engines/sword25/util/glsprites/internal/core.h
new file mode 100755
index 0000000000..9baa3e1c98
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/core.h
@@ -0,0 +1,40 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_CORE_H
+#define GLS_CORE_H
+
+#include "../glsprites.h"
+
+/* GL_ARB_texture_rectangle / GL_EXT_texture_rectangle / GL_NV_texture_rectangle */
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+
+typedef struct
+{
+ GLS_UInt32 maxTextureSize;
+ GLS_Bool textureRectanglesSupported;
+ GLS_UInt32 maxTextureRectangleSize;
+} GLS_OGLCaps;
+
+extern GLS_OGLCaps GLS_TheOGLCaps;
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/glinclude.h b/engines/sword25/util/glsprites/internal/glinclude.h
new file mode 100755
index 0000000000..0ac11cccb2
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/glinclude.h
@@ -0,0 +1,36 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_GL_INCLUDE_H
+#define GLS_GL_INCLUDE_H
+
+/* This header is included by all GLS files that need OpenGL. */
+
+#ifdef WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#endif
+
+#include <GL/gl.h>
+
+#ifndef GL_CLAMP_TO_EDGE
+ #define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/glswindow.c b/engines/sword25/util/glsprites/internal/glswindow.c
new file mode 100755
index 0000000000..dcb8424d73
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/glswindow.c
@@ -0,0 +1,449 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <malloc.h>
+
+#include "glswindow.h"
+
+
+/* --------------------------------------------------------------------------
+ CONSTANTS
+ -------------------------------------------------------------------------- */
+
+static const char * WINDOW_CLASSNAME = "GLsprites class";
+static const GLS_UInt32 BITS_PER_PIXEL = 32;
+
+
+/* -------------------------------------------------------------------------- */
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_SYSCOMMAND:
+ {
+ switch (wParam)
+ {
+ case SC_SCREENSAVE:
+ case SC_MONITORPOWER:
+ return 0;
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ {
+ if (GetWindowLong(hWnd, GWL_USERDATA)) PostQuitMessage(0);
+ return 0;
+ }
+ }
+
+ return DefWindowProc(hWnd,uMsg,wParam,lParam);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Bool RegisterWindowClass()
+{
+ WNDCLASS wc;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ wc.lpfnWndProc = (WNDPROC) WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "OpenGL";
+
+ if (RegisterClass(&wc))
+ return GLS_True;
+ else
+ return GLS_False;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void CenterWindow(RECT * pWR, int * pX, int * pY)
+{
+ int screenX, screenY;
+
+ screenX = GetSystemMetrics(SM_CXSCREEN);
+ screenY = GetSystemMetrics(SM_CYSCREEN);
+
+ if (screenX == 0 || screenY == 0)
+ {
+ *pX = 0;
+ *pY = 0;
+ }
+ else
+ {
+ *pX = (screenX - (pWR->right - pWR->left)) / 2;
+ *pY = (screenY - (pWR->bottom - pWR->top)) / 2;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Bool CreateTheWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, const char * windowTitle, GLS_Bool allowCloseWindow, HWND * pHwnd)
+{
+ DWORD style;
+ DWORD exStyle;
+ RECT windowRect;
+ int x, y;
+
+ if (fullscreen)
+ {
+ exStyle = WS_EX_APPWINDOW;
+ style = WS_POPUP;
+ }
+ else
+ {
+ exStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+ style = WS_CAPTION;
+ if (allowCloseWindow) style |= WS_SYSMENU;
+ }
+
+ windowRect.left = 0;
+ windowRect.right = width;
+ windowRect.top= 0;
+ windowRect.bottom = height;
+ if (!AdjustWindowRectEx(&windowRect, style, FALSE, exStyle)) return GLS_False;
+
+ if (fullscreen)
+ {
+ x = 0;
+ y = 0;
+ }
+ else
+ CenterWindow(&windowRect, &x, &y);
+
+ *pHwnd = CreateWindowEx(
+ exStyle,
+ "OpenGL",
+ windowTitle,
+ style | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
+ x, y,
+ windowRect.right - windowRect.left,
+ windowRect.bottom - windowRect.top,
+ NULL,
+ NULL,
+ GetModuleHandle(NULL),
+ NULL);
+
+ if (!*pHwnd) return GLS_False;
+
+ SetWindowLong(*pHwnd, GWL_USERDATA, (allowCloseWindow == GLS_True) ? 1 : 0);
+
+ return GLS_True;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void SetWindowClientSize(HWND hwnd, int cx, int cy)
+{
+ HMENU hmenu = GetMenu(hwnd);
+ RECT rcWindow = { 0, 0, cx, cy };
+
+ /*
+ * First convert the client rectangle to a window rectangle the
+ * menu-wrap-agnostic way.
+ */
+ AdjustWindowRectEx(&rcWindow, GetWindowLong(hwnd, GWL_STYLE), hmenu != NULL, GetWindowLong(hwnd, GWL_EXSTYLE));
+
+ /*
+ * If there is a menu, then check how much wrapping occurs
+ * when we set a window to the width specified by AdjustWindowRect
+ * and an infinite amount of height. An infinite height allows
+ * us to see every single menu wrap.
+ */
+ if (hmenu) {
+ RECT rcTemp = rcWindow;
+ rcTemp.bottom = 0x7FFF; /* "Infinite" height */
+ SendMessage(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcTemp);
+
+ /*
+ * Adjust our previous calculation to compensate for menu
+ * wrapping.
+ */
+ rcWindow.bottom += rcTemp.top;
+ }
+
+ SetWindowPos(hwnd, NULL, 0, 0, rcWindow.right - rcWindow.left,
+ rcWindow.bottom - rcWindow.top, SWP_NOMOVE | SWP_NOZORDER);
+
+}
+
+/* ---------------------------------------------------------------------------- */
+
+static GLS_Bool PrepareWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, HWND hwnd)
+{
+ if (fullscreen)
+ {
+ SetWindowLong(hwnd, GWL_STYLE, WS_POPUP);
+ SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOPMOST);
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ }
+
+ SetWindowClientSize(hwnd, width, height);
+ ShowWindow(hwnd, SW_SHOW);
+
+ return GLS_True;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Bool ChangeDisplayMode(GLS_UInt32 width, GLS_UInt32 height)
+{
+ DEVMODE dmScreenSettings;
+ memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
+ dmScreenSettings.dmSize = sizeof(dmScreenSettings);
+ dmScreenSettings.dmPelsWidth = width;
+ dmScreenSettings.dmPelsHeight = height;
+ dmScreenSettings.dmBitsPerPel = BITS_PER_PIXEL;
+ dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+
+ if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL)
+ return GLS_True;
+ else
+ return GLS_False;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Bool CreateOpenGLContext(HWND hwnd, HGLRC * pHrc)
+{
+ HDC hdc;
+ int pixelformat;
+ PIXELFORMATDESCRIPTOR pfd =
+ {
+ sizeof(PIXELFORMATDESCRIPTOR),
+ 1,
+ PFD_DRAW_TO_WINDOW |
+ PFD_SUPPORT_OPENGL |
+ PFD_DOUBLEBUFFER,
+ PFD_TYPE_RGBA,
+ BITS_PER_PIXEL,
+ 0, 0, 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ PFD_MAIN_PLANE,
+ 0,
+ 0, 0, 0
+ };
+
+ hdc = GetDC(hwnd);
+ if (!hdc) return GLS_False;
+
+ pixelformat = ChoosePixelFormat(hdc, &pfd);
+ if (!pixelformat)
+ {
+ ReleaseDC(hwnd, hdc);
+ return GLS_False;
+ }
+
+ if (!SetPixelFormat(hdc, pixelformat, &pfd))
+ {
+ ReleaseDC(hwnd, hdc);
+ return GLS_False;
+ }
+
+ *pHrc = wglCreateContext(hdc);
+ if (!*pHrc)
+ {
+ ReleaseDC(hwnd, hdc);
+ return GLS_False;
+ }
+
+ if (!wglMakeCurrent(hdc, *pHrc))
+ {
+ wglDeleteContext(*pHrc);
+ *pHrc = 0;
+ ReleaseDC(hwnd, hdc);
+ return GLS_False;
+ }
+
+ ReleaseDC(hwnd, hdc);
+ return GLS_True;
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_CreateGLWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, const char * windowTitle, GLS_Bool allowCloseWindow, GLS_Window ** pWindow)
+{
+ *pWindow = (GLS_Window *) malloc(sizeof(GLS_Window));
+ if (!*pWindow) return GLS_OUT_OF_MEMORY;
+
+ (*pWindow)->hrc = 0;
+ (*pWindow)->hwnd = 0;
+ (*pWindow)->fullscreen = GLS_False;
+ (*pWindow)->ownHwnd = GLS_True;
+
+ if (!RegisterWindowClass())
+ {
+ GLS_CloseGLWindow(*pWindow);
+ return GLS_WINDOW_CREATION_FAILED;
+ }
+
+ if (!CreateTheWindow(width, height, fullscreen, windowTitle, allowCloseWindow, &((*pWindow)->hwnd)))
+ {
+ GLS_CloseGLWindow(*pWindow);
+ return GLS_WINDOW_CREATION_FAILED;
+ }
+
+ if (fullscreen)
+ {
+ if (!ChangeDisplayMode(width, height))
+ {
+ return GLS_DISPLAY_MODE_CHANGE_FAILED;
+ }
+ (*pWindow)->fullscreen = GLS_True;
+ }
+
+ if (!CreateOpenGLContext((*pWindow)->hwnd, &((*pWindow)->hrc)))
+ {
+ GLS_CloseGLWindow(*pWindow);
+ return GLS_OPENGL_CONTEXT_CREATION_FAILED;
+ }
+
+ return GLS_OK;
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_CreateGLExternalWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, void * windowHandle, GLS_Window ** pWindow)
+{
+ *pWindow = (GLS_Window *) malloc(sizeof(GLS_Window));
+ if (!*pWindow) return GLS_OUT_OF_MEMORY;
+
+ (*pWindow)->hrc = 0;
+ (*pWindow)->hwnd = windowHandle;
+ (*pWindow)->fullscreen = GLS_False;
+ (*pWindow)->ownHwnd = GLS_False;
+
+ if (!PrepareWindow(width, height, fullscreen, (*pWindow)->hwnd))
+ {
+ GLS_CloseGLWindow(*pWindow);
+ return GLS_WINDOW_PREPARATION_FAILED;
+ }
+
+ if (fullscreen)
+ {
+ if (!ChangeDisplayMode(width, height))
+ {
+ return GLS_DISPLAY_MODE_CHANGE_FAILED;
+ }
+ (*pWindow)->fullscreen = GLS_True;
+ }
+
+ if (!CreateOpenGLContext((*pWindow)->hwnd, &((*pWindow)->hrc)))
+ {
+ GLS_CloseGLWindow(*pWindow);
+ return GLS_OPENGL_CONTEXT_CREATION_FAILED;
+ }
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_CloseGLWindow(GLS_Window * window)
+{
+ if (window)
+ {
+ if (window->hrc)
+ {
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(window->hrc);
+ }
+
+ if (window->fullscreen) ChangeDisplaySettings(NULL, 0);
+ if (window->ownHwnd)
+ {
+ if (window->hwnd) DestroyWindow(window->hwnd);
+ UnregisterClass(WINDOW_CLASSNAME, GetModuleHandle(NULL));
+ }
+
+ free(window);
+ }
+
+ return GLS_True;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_ProcessWindowMessages(GLS_Window * window)
+{
+ MSG msg;
+ GLS_Result Result = GLS_OK;
+
+ if (window->ownHwnd)
+ {
+ while (PeekMessage(&msg, window->hwnd, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ Result = GLS_WINDOW_WAS_CLOSED;
+ }
+
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ return Result;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_WindowFlip(GLS_Window * window)
+{
+ HDC hdc;
+
+ hdc = GetDC(window->hwnd);
+ if (!hdc) return GLS_False;
+
+ if (SwapBuffers(hdc))
+ {
+ ReleaseDC(window->hwnd, hdc);
+ return GLS_True;
+ }
+ else
+ {
+ ReleaseDC(window->hwnd, hdc);
+ return GLS_False;
+ }
+}
diff --git a/engines/sword25/util/glsprites/internal/glswindow.h b/engines/sword25/util/glsprites/internal/glswindow.h
new file mode 100755
index 0000000000..1311513e45
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/glswindow.h
@@ -0,0 +1,42 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_WINDOW_H
+#define GLS_WINDOW_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "../glsprites.h"
+
+typedef struct
+{
+ HWND hwnd;
+ HGLRC hrc;
+ GLS_Bool fullscreen;
+ GLS_Bool ownHwnd;
+} GLS_Window;
+
+GLS_Result GLS_CreateGLWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, const char * windowTitle, GLS_Bool allowCloseWindow, GLS_Window ** pWindow);
+GLS_Result GLS_CreateGLExternalWindow(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool fullscreen, void * windowHandle, GLS_Window ** pWindow);
+GLS_Result GLS_CloseGLWindow(GLS_Window * window);
+GLS_Result GLS_ProcessWindowMessages(GLS_Window * window);
+GLS_Result GLS_WindowFlip(GLS_Window * window);
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/sprite.c b/engines/sword25/util/glsprites/internal/sprite.c
new file mode 100755
index 0000000000..261ce207e6
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite.c
@@ -0,0 +1,156 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+
+#include <malloc.h>
+
+#include "glinclude.h"
+#include "util.h"
+#include "core.h"
+#include "sprite.h"
+#include "sprite_rectangle.h"
+#include "sprite_pow2.h"
+#include "sprite_tiled.h"
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ /* These first three members are present at the start of each sprite type.
+ Therefore it is safe to cast all sprite to this. */
+ GLS_spriteFunctionTable * functionTable;
+ GLS_UInt32 width;
+ GLS_UInt32 height;
+} spriteBase;
+
+/* -------------------------------------------------------------------------- */
+
+#define MAX_WASTED_TEXTURE_MEMORY_PERCENT 30
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_NewSprite(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite)
+{
+ //* The sprite needs to be at least 1x1 pixel in size */
+ if (width == 0 || height == 0) return GLS_INVALID_SPRITE_DIMENSIONS;
+
+ /* If both dimensions are powers of 2 a power of 2 texture will be used for the sprite */
+ if (GLS_IsPowerOf2(width) && GLS_IsPowerOf2(height)) return GLS_NewSpritePow2(width, height, useAlphachannel, data, pSprite);
+
+ /* Use TEXTURE_RECTANGLE_ARB for non power of 2 dimensions whenever possible */
+ if (GLS_TheOGLCaps.textureRectanglesSupported &&
+ GLS_TheOGLCaps.maxTextureRectangleSize >= width &&
+ GLS_TheOGLCaps.maxTextureRectangleSize >= height)
+ return GLS_NewSpriteRectangle(width, height, useAlphachannel, data, pSprite);
+
+ /* Use a power of 2 texture if TEXTURE_RECTANGLE_ARB is not possible, the image is small enough and the amount of wasted texture memory
+ is not too big */
+ if ((width <= GLS_TheOGLCaps.maxTextureSize && height <= GLS_TheOGLCaps.maxTextureSize) &&
+ (GLS_NextPowerOf2(width) * GLS_NextPowerOf2(height) * 100) / (width * height) <= MAX_WASTED_TEXTURE_MEMORY_PERCENT)
+ return GLS_NewSpritePow2(width, height, useAlphachannel, data, pSprite);
+
+ /* Otherwise use tiled power of 2 textures */
+ return GLS_NewSpriteTiled(width, height, useAlphachannel, data, pSprite);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_DeleteSprite(GLS_Sprite * sprite)
+{
+ /* Poor mans polymorphism. */
+ spriteBase * s = (spriteBase *) sprite;
+ return s->functionTable->Delete(sprite);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_Blit(GLS_Sprite * sprite,
+ GLS_SInt32 x, GLS_SInt32 y,
+ const GLS_Rect * subImage,
+ const GLS_Color * color,
+ GLS_Bool flipH, GLS_Bool flipV,
+ GLS_Float scaleX, GLS_Float scaleY)
+{
+ spriteBase * s = (spriteBase *) sprite;
+ GLS_Rect localSubImage;
+ const GLS_Rect * subImagePtr;
+ GLS_Result result;
+
+ /* Check parameters for validity. */
+ if (subImage && (subImage->x2 > s->width || subImage->y2 > s->height)) return GLS_INVALID_SUB_IMAGE;
+
+ /* If no subimage was supplied, create one that covers the whole sprite. */
+ if (subImage)
+ subImagePtr = subImage;
+ else
+ {
+ localSubImage.x1 = 0;
+ localSubImage.y1 = 0;
+ localSubImage.x2 = s->width;
+ localSubImage.y2 = s->height;
+ subImagePtr = &localSubImage;
+ }
+
+ /* Modify the Modelview-Matrix to reflect the sprites position, flip settings, and scale. */
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glTranslatef((GLfloat) x, (GLfloat) y, 0);
+ if (flipH == GLS_True || flipV == GLS_True || scaleX != 1.0f || scaleY != 1.0f)
+ {
+ glScalef(scaleX * (flipH == GLS_True ? -1.0f : 1.0f), scaleY * (flipV == GLS_True ? -1.0f : 1.0f), 1.0f);
+ glTranslatef(flipH == GLS_True ? (subImagePtr->x2 - subImagePtr->x1) * -1.0f : 0.0f,
+ flipV == GLS_True ? (subImagePtr->y2 - subImagePtr->y1) * -1.0f : 0.0f, 0.0f);
+ }
+
+ /* Set the color to be used. Use white if no color was provided. */
+ if (color)
+ glColor4ub(color->r, color->g, color->b, color->a);
+ else
+ glColor4ub(255, 255, 255, 255);
+
+ /* Display the sprite by calling the Blit() function of the specific sprite type. */
+ result = s->functionTable->Blit(sprite, subImagePtr);
+
+ /* Restore the old matrix. */
+ glPopMatrix();
+
+ return result;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_SetSpriteData(GLS_Sprite sprite, GLS_UInt32 width, GLS_UInt32 height, const void * data, GLS_UInt32 stride)
+{
+ spriteBase * s = (spriteBase *) sprite;
+
+ /* Check parameters for validity. */
+ if (width == 0 || height == 0 || width > s->width || height > s->height) return GLS_INVALID_DATA_DIMENSIONS;
+ if (data == 0) return GLS_INVALID_DATA_POINTER;
+
+ /* Poor mans polymorphism. */
+ return s->functionTable->SetData(sprite, width, height, data, stride);
+}
diff --git a/engines/sword25/util/glsprites/internal/sprite.h b/engines/sword25/util/glsprites/internal/sprite.h
new file mode 100755
index 0000000000..8cb7fd41e7
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite.h
@@ -0,0 +1,40 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_SPRITE_H
+#define GLS_SPRITE_H
+
+#include "../glsprites.h"
+
+typedef enum
+{
+ ST_POW2,
+ ST_TILED,
+ ST_RECTANGLE,
+} GLS_spriteType;
+
+typedef struct
+{
+ GLS_spriteType type;
+ GLS_Result (*Delete)(GLS_Sprite *);
+ GLS_Result (*Blit)(GLS_Sprite *, const GLS_Rect *);
+ GLS_Result (*SetData)(GLS_Sprite *, GLS_UInt32, GLS_UInt32, const void *, GLS_UInt32);
+} GLS_spriteFunctionTable;
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/sprite_pow2.c b/engines/sword25/util/glsprites/internal/sprite_pow2.c
new file mode 100755
index 0000000000..8b4ebe18fe
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite_pow2.c
@@ -0,0 +1,170 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+#include <malloc.h>
+
+#include "glinclude.h"
+#include "util.h"
+#include "sprite.h"
+#include "sprite_pow2.h"
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Delete(GLS_Sprite *);
+static GLS_Result Blit(GLS_Sprite *, const GLS_Rect *);
+static GLS_Result SetData(GLS_Sprite *, GLS_UInt32, GLS_UInt32, const void *, GLS_UInt32);
+static GLS_spriteFunctionTable pow2FunctionTable = { ST_POW2, Delete, Blit, SetData };
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ /* These first three members have to be present at the start of each sprite type. */
+ GLS_spriteFunctionTable * functionTable;
+ GLS_UInt32 width;
+ GLS_UInt32 height;
+
+ GLS_UInt32 widthPow2;
+ GLS_UInt32 heightPow2;
+ GLint textureID;
+} spritePow2;
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_NewSpritePow2(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite)
+{
+ GLS_UInt32 widthPow2 = GLS_NextPowerOf2(width);
+ GLS_UInt32 heightPow2 = GLS_NextPowerOf2(height);
+
+ /* Allocate memory for sprite object */
+ spritePow2 * sprite = (spritePow2 *) malloc(sizeof(spritePow2));
+ if (!sprite) return GLS_OUT_OF_MEMORY;
+
+ /* Initialize sprite object */
+ sprite->functionTable = &pow2FunctionTable;
+ sprite->textureID = 0;
+ sprite->width = width;
+ sprite->height = height;
+ sprite->widthPow2 = widthPow2;
+ sprite->heightPow2 = heightPow2;
+
+ /* Create OpenGL texture */
+ glGenTextures(1, &(sprite->textureID));
+ glBindTexture(GL_TEXTURE_2D, sprite->textureID);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, useAlphachannel ? GL_RGBA8 : GL_RGB8, widthPow2, heightPow2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+ /* Fill the texture with the supplied pixel data.
+ We don't use glTexImage2D for this, because the created sprite might not have power of 2 dimensions and therefore the
+ supplied pixeldata wouldn't cover the whole texture. */
+ if (data) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ *pSprite = (GLS_Sprite) sprite;
+
+ if (glGetError())
+ {
+ Delete(*pSprite);
+ return GLS_TEXTURE_CREATION_FAILED;
+ }
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Delete(GLS_Sprite * sprite)
+{
+ spritePow2 * s = (spritePow2 *) sprite;
+
+ if (s->textureID) glDeleteTextures(1, &s->textureID);
+ free(s);
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Blit(GLS_Sprite * sprite,
+ const GLS_Rect * subImage)
+{
+ GLfloat width, height;
+ GLfloat texX1, texY1, texX2, texY2;
+
+ spritePow2 * s = (spritePow2 *) sprite;
+
+ width = (float) (subImage->x2 - subImage->x1);
+ height = (float) (subImage->y2 - subImage->y1);
+
+ texX1 = (GLfloat) subImage->x1 / (GLfloat) s->widthPow2;
+ texY1 = (GLfloat) subImage->y1 / (GLfloat) s->heightPow2;
+ texX2 = (GLfloat) subImage->x2 / (GLfloat) s->widthPow2;
+ texY2 = (GLfloat) subImage->y2 / (GLfloat) s->heightPow2;
+
+ glBindTexture(GL_TEXTURE_2D, s->textureID);
+
+ glEnable(GL_TEXTURE_2D);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(texX1, texY1);
+ glVertex2f(0.0f, 0.0f);
+
+ glTexCoord2f(texX2, texY1);
+ glVertex2f(width, 0.0f);
+
+ glTexCoord2f(texX2, texY2);
+ glVertex2f(width, height);
+
+ glTexCoord2f(texX1, texY2);
+ glVertex2f(0.0f, height);
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+
+ return glGetError() ? GLS_OPENGL_ERROR : GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result SetData(GLS_Sprite * sprite, GLS_UInt32 width, GLS_UInt32 height, const void * data, GLS_UInt32 stride)
+{
+ spritePow2 * s = (spritePow2 *) sprite;
+
+ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, width + stride);
+
+ glBindTexture(GL_TEXTURE_2D, s->textureID);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ glPopClientAttrib();
+
+ return glGetError() ? GLS_OPENGL_ERROR : GLS_OK;
+}
diff --git a/engines/sword25/util/glsprites/internal/sprite_pow2.h b/engines/sword25/util/glsprites/internal/sprite_pow2.h
new file mode 100755
index 0000000000..bbce39c4dc
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite_pow2.h
@@ -0,0 +1,27 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_SPRITE_POW2_H
+#define GLS_SPRITE_POW2_H
+
+#include "../glsprites.h"
+
+GLS_Result GLS_NewSpritePow2(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite);
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/sprite_rectangle.c b/engines/sword25/util/glsprites/internal/sprite_rectangle.c
new file mode 100755
index 0000000000..546634eaac
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite_rectangle.c
@@ -0,0 +1,164 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+#include <malloc.h>
+
+#include "glinclude.h"
+#include "core.h"
+#include "sprite.h"
+#include "sprite_rectangle.h"
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Delete(GLS_Sprite *);
+static GLS_Result Blit(GLS_Sprite *, const GLS_Rect *);
+static GLS_Result SetData(GLS_Sprite *, GLS_UInt32, GLS_UInt32, const void *, GLS_UInt32);
+static GLS_spriteFunctionTable rectangleFunctionTable = { ST_RECTANGLE, Delete, Blit, SetData };
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ /* These first three members have to be present at the start of each sprite type. */
+ GLS_spriteFunctionTable * functionTable;
+ GLS_UInt32 width;
+ GLS_UInt32 height;
+
+ GLint textureID;
+} spriteRectangle;
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_NewSpriteRectangle(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite)
+{
+ /* Allocate memory for sprite object */
+ spriteRectangle * sprite = (spriteRectangle *) malloc(sizeof(spriteRectangle));
+ if (!sprite) return GLS_OUT_OF_MEMORY;
+
+ /* Initialize sprite object */
+ sprite->functionTable = &rectangleFunctionTable;
+ sprite->textureID = 0;
+ sprite->width = width;
+ sprite->height = height;
+
+ /* Create OpenGL texture */
+ glGenTextures(1, &(sprite->textureID));
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sprite->textureID);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, useAlphachannel ? GL_RGBA8 : GL_RGB8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ *pSprite = (GLS_Sprite) sprite;
+
+ /* The unbind here is not really necessary but some GL drivers (e.g. GeForce 4 488 Go) screw up subsequent GL_TEXTURE_2D
+ render operations if a GL_TEXTURE_RECTANGLE_ARB texture is still bound. */
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+ if (glGetError())
+ {
+ Delete(*pSprite);
+ return GLS_TEXTURE_CREATION_FAILED;
+ }
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Delete(GLS_Sprite * sprite)
+{
+ spriteRectangle * s = (spriteRectangle *) sprite;
+
+ if (s->textureID) glDeleteTextures(1, &s->textureID);
+ free(s);
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Blit(GLS_Sprite * sprite,
+ const GLS_Rect * subImage)
+{
+ GLfloat width;
+ GLfloat height;
+
+ spriteRectangle * s = (spriteRectangle *) sprite;
+
+ width = (float)(subImage->x2 - subImage->x1);
+ height = (float)(subImage->y2 - subImage->y1);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s->textureID);
+
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+
+ glBegin(GL_QUADS);
+ glTexCoord2i(subImage->x1, subImage->y1);
+ glVertex2f(0.0f, 0.0f);
+
+ glTexCoord2i(subImage->x2, subImage->y1);
+ glVertex2f(width, 0.0f);
+
+ glTexCoord2i(subImage->x2, subImage->y2);
+ glVertex2f(width, height);
+
+ glTexCoord2i(subImage->x1, subImage->y2);
+ glVertex2f(0.0f, height);
+ glEnd();
+
+ /* The unbind here is not really necessary but some GL drivers (e.g. GeForce 4 488 Go) screw up subsequent GL_TEXTURE_2D
+ render operations if a GL_TEXTURE_RECTANGLE_ARB texture is still bound. */
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ return glGetError() ? GLS_OPENGL_ERROR : GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result SetData(GLS_Sprite * sprite, GLS_UInt32 width, GLS_UInt32 height, const void * data, GLS_UInt32 stride)
+{
+ spriteRectangle * s = (spriteRectangle *) sprite;
+
+ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, width + stride);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s->textureID);
+ glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ /* The unbind here is not really necessary but some GL drivers (e.g. GeForce 4 488 Go) screw up subsequent GL_TEXTURE_2D
+ render operations if a GL_TEXTURE_RECTANGLE_ARB texture is still bound. */
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+
+ glPopClientAttrib();
+
+ return glGetError() ? GLS_OPENGL_ERROR : GLS_OK;
+}
diff --git a/engines/sword25/util/glsprites/internal/sprite_rectangle.h b/engines/sword25/util/glsprites/internal/sprite_rectangle.h
new file mode 100755
index 0000000000..65bdf6a3ef
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite_rectangle.h
@@ -0,0 +1,27 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_SPRITE_RECTANGLE_H
+#define GLS_SPRITE_RECTANGLE_H
+
+#include "../glsprites.h"
+
+GLS_Result GLS_NewSpriteRectangle(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite);
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/sprite_tiled.c b/engines/sword25/util/glsprites/internal/sprite_tiled.c
new file mode 100755
index 0000000000..82435a638e
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite_tiled.c
@@ -0,0 +1,370 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+#include <malloc.h>
+
+#include "glinclude.h"
+#include "core.h"
+#include "util.h"
+#include "sprite.h"
+#include "sprite_tiled.h"
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Delete(GLS_Sprite *);
+static GLS_Result Blit(GLS_Sprite *, const GLS_Rect *);
+static GLS_Result SetData(GLS_Sprite *, GLS_UInt32, GLS_UInt32, const void *, GLS_UInt32);
+static GLS_spriteFunctionTable tiledFunctionTable = { ST_TILED, Delete, Blit, SetData };
+
+/* -------------------------------------------------------------------------- */
+
+#define MIN_TEXTURE_SIZE_LOG2 6
+#define MIN_TEXTURE_SIZE (1 << MIN_TEXTURE_SIZE_LOG2)
+
+#define MAX_POSSIBLE_TEXTURE_SIZE_LOG2 31
+#define MAX_POSSIBLE_TEXTURE_SIZE (1 << MAX_POSSIBLE_TEXTURE_SIZE_LOG2)
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GLint textureID;
+ GLfloat x;
+ GLfloat y;
+ GLfloat width;
+ GLfloat height;
+} tile;
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ /* These first three members have to be present at the start of each sprite type. */
+ GLS_spriteFunctionTable * functionTable;
+ GLS_UInt32 width;
+ GLS_UInt32 height;
+
+ GLS_UInt32 widthSubdivisionCount;
+ GLS_UInt32 heightSubdivisionCount;
+ tile tiles[1]; /* Has to be last member. */
+} spriteTiled;
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_UInt32 CalculateSubdivisions(GLS_UInt32 value, GLS_UInt32 maxTextureSize, GLS_UInt32 maxTextureSizeLog2,
+ GLS_UInt32 subdivisions[MAX_POSSIBLE_TEXTURE_SIZE_LOG2 + 1])
+{
+ /* This function takes a value and determines how it best can be divided up into pieces of power of 2 length.
+ The resulting parts are at least MIN_TEXTURE_SIZE long and at most maxTextureSize long.
+ If we do this for both width and height of a sprite, we can determine how this sprite can be split up into
+ smaller power of 2 textures using a simple two dimensional loop.
+
+ This returns the number of subdivisions as the return value.
+ The sizes of the different pieces are encoded in the subdivisions array. The indicies into the array determine the
+ power of 2 and the values in the array the number of pieces with that size.
+ E.g. if the array contains the value 3 at index 4 this means you have 3 pieces of size 16 (2^4 = 16).
+ */
+
+ GLS_UInt32 subdivisionCount = 0;
+ GLS_UInt32 maxSizeCount;
+ GLS_UInt32 counter = 0;
+
+ /* First determine how many pieces of maximal size we can fill and write this into the result array.
+ Update the value and the subdivision count accordingly. */
+ maxSizeCount = value / maxTextureSize;
+ subdivisions[maxTextureSizeLog2] = maxSizeCount;
+ subdivisionCount += maxSizeCount;
+ value -= maxSizeCount * maxTextureSize;
+
+ /* The remaining value is rounded up to a multiple of the minimal texture size. */
+ value = ((value + MIN_TEXTURE_SIZE - 1) / MIN_TEXTURE_SIZE) * MIN_TEXTURE_SIZE;
+
+ /* Determine the remaining pieces by using the binary representation of the value.
+ If a bit is set, we need to add a piece of the according size. */
+ while (value)
+ {
+ if (value & 1)
+ {
+ ++subdivisions[counter];
+ ++subdivisionCount;
+ }
+
+ ++counter;
+ value >>= 1;
+ }
+
+ return subdivisionCount;
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Result GLS_NewSpriteTiled(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite)
+{
+ GLS_UInt32 maxTextureSize, maxTextureSizeLog2;
+ GLS_UInt32 widthSubdivisions[MAX_POSSIBLE_TEXTURE_SIZE_LOG2 + 1] = { 0 };
+ GLS_UInt32 widthSubdivisionCount;
+ GLS_UInt32 heightSubdivisions[MAX_POSSIBLE_TEXTURE_SIZE_LOG2 + 1] = { 0 };
+ GLS_UInt32 heightSubdivisionCount;
+ GLS_UInt32 subdivisonX, subdivisionY, pixelX = 0, pixelY = 0, i;
+ spriteTiled * sprite;
+ tile * curTile;
+
+ /* Determine the maximal texture size to be used and make sure it is a power of two. */
+ maxTextureSize = GLS_TheOGLCaps.maxTextureSize > MAX_POSSIBLE_TEXTURE_SIZE ? MAX_POSSIBLE_TEXTURE_SIZE : GLS_TheOGLCaps.maxTextureSize;
+ maxTextureSize = GLS_IsPowerOf2(maxTextureSize) ? maxTextureSize : GLS_NextPowerOf2(maxTextureSize >> 1);
+
+ /* Determine the log2 of the maximal texture size. */
+ maxTextureSizeLog2 = GLS_Log2(maxTextureSize);
+
+ /* Determine the subdivisions along the width and the height. */
+ widthSubdivisionCount = CalculateSubdivisions(width, maxTextureSize, maxTextureSizeLog2, widthSubdivisions);
+ heightSubdivisionCount = CalculateSubdivisions(height, maxTextureSize, maxTextureSizeLog2, heightSubdivisions);
+
+ /* Allocate memory for sprite object */
+ sprite = (spriteTiled *) calloc(sizeof(spriteTiled) + sizeof(tile) * (widthSubdivisionCount * heightSubdivisionCount - 1), 1);
+ if (!sprite) return GLS_OUT_OF_MEMORY;
+
+ /* Initialize sprite object. */
+ sprite->functionTable = &tiledFunctionTable;
+ sprite->width = width;
+ sprite->height = height;
+ sprite->widthSubdivisionCount = widthSubdivisionCount;
+ sprite->heightSubdivisionCount = heightSubdivisionCount;
+
+ /* Create the textures. */
+ curTile = &sprite->tiles[0];
+ for (subdivisionY = MAX_POSSIBLE_TEXTURE_SIZE_LOG2;; --subdivisionY)
+ {
+ while (heightSubdivisions[subdivisionY]--)
+ {
+ for (subdivisonX = MAX_POSSIBLE_TEXTURE_SIZE_LOG2;; --subdivisonX)
+ {
+ for (i = 0; i < widthSubdivisions[subdivisonX]; ++i)
+ {
+ /* Initialize tile. Store as GLfloat to avoid unnecessary integer conversions when drawing. */
+ curTile->x = (GLfloat) pixelX;
+ curTile->y = (GLfloat) pixelY;
+ curTile->width = (GLfloat) (1 << subdivisonX);
+ curTile->height = (GLfloat) (1 << subdivisionY);
+
+ /* Create OpenGL texture */
+ glGenTextures(1, &(curTile->textureID));
+ glBindTexture(GL_TEXTURE_2D, curTile->textureID);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, useAlphachannel ? GL_RGBA8 : GL_RGB8, 1 << subdivisonX, 1 << subdivisionY, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+ /* Advance to the next empty tile. */
+ pixelX += 1 << subdivisonX;
+ ++curTile;
+ }
+
+ /* Test for loop end. Prevents underflow of unsigned integer. */
+ if (subdivisonX == 0) break;
+ }
+
+ /* Enter next row. */
+ pixelX = 0;
+ pixelY += 1 << subdivisionY;
+ }
+
+ /* Test for loop end. Prevents underflow of unsigned integer. */
+ if (subdivisionY == 0) break;
+ }
+
+ *pSprite = (GLS_Sprite) sprite;
+
+ /* Intialize the sprite with the supplied pixel data (if any). */
+ if (data) SetData(*pSprite, width, height, data, 0);
+
+ /* If an error occured the sprite is deleted and the function returns with an error. */
+ if (glGetError())
+ {
+ Delete(*pSprite);
+ return GLS_TEXTURE_CREATION_FAILED;
+ }
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Delete(GLS_Sprite * sprite)
+{
+ spriteTiled * s = (spriteTiled *) sprite;
+ GLS_UInt32 tileCount = s->widthSubdivisionCount * s->heightSubdivisionCount;
+ GLS_UInt32 i;
+
+ /* Delete each texture. */
+ for (i = 0; i < tileCount; ++i)
+ {
+ if (s->tiles[i].textureID) glDeleteTextures(1, &s->tiles[i].textureID);
+ }
+
+ /* Free the memory used by the sprite. */
+ free(s);
+
+ return GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result Blit(GLS_Sprite * sprite,
+ const GLS_Rect * subImage)
+{
+ GLfloat width, height;
+ GLfloat texX1, texY1, texX2, texY2;
+ GLS_UInt32 tileIndex = 0;
+ GLS_UInt32 tileX, tileY;
+ GLfloat tileRectX1, tileRectY1;
+ GLfloat tileRectX2, tileRectY2;
+ GLfloat tileWidth, tileHeight;
+ GLfloat lastHeight = 0;
+ GLS_GLfloatRect tileRect, resultRect;
+ GLfloat x = 0.0f, y = 0.0f;
+ GLS_GLfloatRect subImageF = { (GLfloat) subImage->x1, (GLfloat) subImage->y1, (GLfloat) subImage->x2, (GLfloat) subImage->y2 };
+
+ spriteTiled * s = (spriteTiled *) sprite;
+
+ /* Determine width and height of the subimage to display. */
+ width = (float)(subImage->x2 - subImage->x1);
+ height = (float)(subImage->y2 - subImage->y1);
+
+ glEnable(GL_TEXTURE_2D);
+
+ /* Draw all required tiles. */
+ for (tileY = 0; tileY < s->heightSubdivisionCount; ++tileY)
+ {
+ for (tileX = 0; tileX < s->widthSubdivisionCount; ++tileX)
+ {
+ tileRect.x1 = s->tiles[tileIndex].x;
+ tileRect.y1 = s->tiles[tileIndex].y;
+ tileRect.x2 = tileRect.x1 + s->tiles[tileIndex].width;
+ tileRect.y2 = tileRect.y1 + s->tiles[tileIndex].height;
+
+ if (GLS_IntersectGLfloatRects(&tileRect, &subImageF, &resultRect))
+ {
+ tileRectX1 = resultRect.x1;
+ tileRectY1 = resultRect.y1;
+ tileRectX2 = resultRect.x2;
+ tileRectY2 = resultRect.y2;
+
+ glBindTexture(GL_TEXTURE_2D, s->tiles[tileIndex].textureID);
+
+ texX1 = (tileRectX1 - s->tiles[tileIndex].x) / (GLfloat) s->tiles[tileIndex].width;
+ texY1 = (tileRectY1 - s->tiles[tileIndex].y) / (GLfloat) s->tiles[tileIndex].height;
+ texX2 = (GLfloat) (tileRectX2 - s->tiles[tileIndex].x) / (GLfloat) s->tiles[tileIndex].width;
+ texY2 = (GLfloat) (tileRectY2 - s->tiles[tileIndex].y) / (GLfloat) s->tiles[tileIndex].height;
+
+ tileWidth = resultRect.x2 - resultRect.x1;
+ tileHeight = resultRect.y2 - resultRect.y1;
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(texX1, texY1);
+ glVertex2f(x, y);
+
+ glTexCoord2f(texX2, texY1);
+ glVertex2f(x + tileWidth, y);
+
+ glTexCoord2f(texX2, texY2);
+ glVertex2f(x + tileWidth, y + tileHeight);
+
+ glTexCoord2f(texX1, texY2);
+ glVertex2f(x, y + tileHeight);
+ glEnd();
+
+ x += tileWidth;
+ lastHeight = tileHeight;
+ }
+
+ ++tileIndex;
+ }
+
+ x = 0;
+ y += lastHeight;
+ }
+
+ glDisable(GL_TEXTURE_2D);
+
+ return glGetError() ? GLS_OPENGL_ERROR : GLS_OK;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+static GLS_Result SetData(GLS_Sprite * sprite, GLS_UInt32 width, GLS_UInt32 height, const void * data, GLS_UInt32 stride)
+{
+ spriteTiled * s = (spriteTiled *) sprite;
+ GLS_UInt32 x = 0, y = 0, tileIndex = 0;
+ GLS_UInt32 tileX, tileY;
+ GLS_UInt32 copyWidth, copyHeight;
+ const GLS_UInt32 * pixelData = (const GLS_UInt32 *) data;
+
+ /* Set the source image row length and push the original value that it can be restored later. */
+ glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, width + stride);
+
+ /* Loop through all tiles width first. */
+ for (tileY = 0; tileY < s->heightSubdivisionCount; ++tileY)
+ {
+ /* Is there enough pixel data to reach the next tile? */
+ if (height > y)
+ {
+ for (tileX = 0; tileX < s->widthSubdivisionCount; ++tileX)
+ {
+ /* Is the enough pixel data to reach the next tile? */
+ if (width > x)
+ {
+ /* Determine the amount of pixels to be copied to the current tile.
+ They might either cover the whole tile, or just part of the tile if not enough
+ pixel data is left. */
+ copyWidth = GLS_MIN(width - x, (GLS_UInt32) s->tiles[tileIndex].width);
+ copyHeight = GLS_MIN(height - y, (GLS_UInt32) s->tiles[tileIndex].height);
+
+ /* Copy the pixels. */
+ glBindTexture(GL_TEXTURE_2D, s->tiles[tileIndex].textureID);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, copyWidth, copyHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ &pixelData[x + y * (width + stride)]);
+ }
+
+ /* Update the x position inside the pixel data and advance to the next tile. */
+ x += (GLS_UInt32) s->tiles[tileIndex].width;
+ ++tileIndex;
+ }
+ }
+
+ /* Restet the x position inside the pixel data (we have reached another row) and update the y position. */
+ x = 0;
+ y += (GLS_UInt32) s->tiles[tileIndex - 1].height;
+ }
+
+ glPopClientAttrib();
+
+ return glGetError() ? GLS_OPENGL_ERROR : GLS_OK;
+}
diff --git a/engines/sword25/util/glsprites/internal/sprite_tiled.h b/engines/sword25/util/glsprites/internal/sprite_tiled.h
new file mode 100755
index 0000000000..8fb0d83ba7
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/sprite_tiled.h
@@ -0,0 +1,41 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_SPRITE_TILED_H
+#define GLS_SPRITE_TILED_H
+
+#include "../glsprites.h"
+
+GLS_Result GLS_NewSpriteTiled(GLS_UInt32 width, GLS_UInt32 height, GLS_Bool useAlphachannel, void * data, GLS_Sprite ** pSprite);
+GLS_Result GLS_DeleteSpriteTiled(GLS_Sprite * sprite);
+
+GLS_Result GLS_BlitTiled(GLS_Sprite * sprite,
+ GLS_SInt32 x, GLS_SInt32 y,
+ const GLS_Rect * subImage,
+ const GLS_Color * color,
+ GLS_Bool flipH, GLS_Bool flipV,
+ GLS_Float scaleX, GLS_Float scaleY);
+
+GLS_Result GLS_SetSpriteDataTiled(GLS_Sprite * sprite,
+ GLS_UInt32 width, GLS_UInt32 height,
+ GLS_Bool useAlphachannel,
+ const void * data,
+ GLS_UInt32 stride);
+
+#endif
diff --git a/engines/sword25/util/glsprites/internal/util.c b/engines/sword25/util/glsprites/internal/util.c
new file mode 100755
index 0000000000..590f7e3459
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/util.c
@@ -0,0 +1,77 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+/* --------------------------------------------------------------------------
+ INCLUDES
+ -------------------------------------------------------------------------- */
+
+#include "util.h"
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Bool GLS_IsPowerOf2(GLS_UInt32 value)
+{
+ return !(value & (value - 1)) && value;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+GLS_UInt32 GLS_NextPowerOf2(GLS_UInt32 value)
+{
+ --value;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ ++value;
+
+ return value;
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_UInt32 GLS_Log2(GLS_UInt32 value)
+{
+ GLS_UInt32 result = 0;
+ while (value >>= 1) ++result;
+ return result;
+}
+
+/* -------------------------------------------------------------------------- */
+
+GLS_Bool GLS_IntersectGLfloatRects(const GLS_GLfloatRect * r1, const GLS_GLfloatRect * r2, GLS_GLfloatRect * result)
+{
+ GLS_Bool rectsIntersect = (r1->x1 >= r2->x2 ||
+ r1->x2 <= r2->x1 ||
+ r1->y1 >= r2->y2 ||
+ r1->y2 <= r2->y1) ? GLS_False : GLS_True;
+
+ if(rectsIntersect)
+ {
+ result->x1 = GLS_MAX(r1->x1, r2->x1);
+ result->y1 = GLS_MAX(r1->y1, r2->y1);
+ result->x2 = GLS_MIN(r1->x2, r2->x2);
+ result->y2 = GLS_MIN(r1->y2, r2->y2);
+ }
+
+ return rectsIntersect;
+}
diff --git a/engines/sword25/util/glsprites/internal/util.h b/engines/sword25/util/glsprites/internal/util.h
new file mode 100755
index 0000000000..cdd69e2953
--- /dev/null
+++ b/engines/sword25/util/glsprites/internal/util.h
@@ -0,0 +1,42 @@
+/******************************************************************************/
+/* This file is part of Broken Sword 2.5 */
+/* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer */
+/* */
+/* Broken Sword 2.5 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. */
+/* */
+/* Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+/******************************************************************************/
+
+#ifndef GLS_UTIL_H
+#define GLS_UTIL_H
+
+#include "../glsprites.h"
+#include "glinclude.h"
+
+typedef struct
+{
+ GLfloat x1;
+ GLfloat y1;
+ GLfloat x2;
+ GLfloat y2;
+} GLS_GLfloatRect;
+
+GLS_Bool GLS_IsPowerOf2(GLS_UInt32 value);
+GLS_UInt32 GLS_NextPowerOf2(GLS_UInt32 value);
+GLS_UInt32 GLS_Log2(GLS_UInt32 value);
+GLS_Bool GLS_IntersectGLfloatRects(const GLS_GLfloatRect * r1, const GLS_GLfloatRect * r2, GLS_GLfloatRect * result);
+
+#define GLS_MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define GLS_MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#endif