2004-07-24 21:38:12 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-07-27 02:26:51 +02:00
|
|
|
#include <string.h>
|
2004-07-29 18:14:22 +02:00
|
|
|
#include <sstream>
|
2004-07-27 02:26:51 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
#define USE_WINDOWS_CURSOR
|
2004-07-27 02:26:51 +02:00
|
|
|
|
2004-07-24 21:38:12 +02:00
|
|
|
#ifdef _WIN32
|
2004-07-29 18:14:22 +02:00
|
|
|
#include "lib/sysdep/win/win_internal.h"
|
2004-08-12 19:36:48 +02:00
|
|
|
#endif
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-10-06 16:00:43 +02:00
|
|
|
#include "res.h"
|
|
|
|
#include "ogl_tex.h"
|
2004-07-29 18:14:22 +02:00
|
|
|
#include "lib/ogl.h"
|
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
struct ogl_cursor {
|
|
|
|
Handle tex;
|
|
|
|
int hotspotx, hotspoty;
|
|
|
|
int w, h;
|
|
|
|
void draw(int x, int y)
|
|
|
|
{
|
|
|
|
tex_bind(tex);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
glBegin(GL_QUADS);
|
2005-01-07 15:10:14 +01:00
|
|
|
glTexCoord2i(0, 0); glVertex2i( x-hotspotx, y+hotspoty );
|
|
|
|
glTexCoord2i(1, 0); glVertex2i( x-hotspotx+w, y+hotspoty );
|
|
|
|
glTexCoord2i(1, 1); glVertex2i( x-hotspotx+w, y+hotspoty-h );
|
|
|
|
glTexCoord2i(0, 1); glVertex2i( x-hotspotx, y+hotspoty-h );
|
2004-08-12 19:36:48 +02:00
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
};
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-01-23 18:42:28 +01:00
|
|
|
extern int g_mouse_x, g_mouse_y;
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
// On Windows, allow runtime choice between Windows cursors and OpenGL
|
|
|
|
// cursors (Windows = more responsive, OpenGL = more consistent with what
|
|
|
|
// the game sees)
|
|
|
|
struct Cursor
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
HICON wincursor; // Windows handle
|
|
|
|
ogl_cursor* cursor; // font texture
|
|
|
|
};
|
|
|
|
char type; // 0 for OpenGL cursor, 1 for Windows cursor
|
|
|
|
};
|
|
|
|
#else // #ifdef _WIN32
|
|
|
|
struct Cursor
|
|
|
|
{
|
|
|
|
ogl_cursor* cursor; // font texture
|
|
|
|
};
|
|
|
|
#endif // #ifdef _WIN32 / #else
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
H_TYPE_DEFINE(Cursor);
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
static void Cursor_init(Cursor* c, va_list)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
# ifdef USE_WINDOWS_CURSOR
|
|
|
|
c->type = 1;
|
|
|
|
# else
|
|
|
|
c->type = 0;
|
|
|
|
# endif
|
|
|
|
c->wincursor = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
c->cursor = NULL;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
static void Cursor_dtor(Cursor* c)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (c->type == 1)
|
|
|
|
{
|
|
|
|
if (c->wincursor)
|
|
|
|
DestroyIcon(c->wincursor);
|
2004-07-29 18:14:22 +02:00
|
|
|
}
|
2004-08-12 19:36:48 +02:00
|
|
|
else
|
|
|
|
#endif // _WIN32
|
2004-07-29 18:14:22 +02:00
|
|
|
{
|
2004-08-12 19:36:48 +02:00
|
|
|
if (c->cursor)
|
|
|
|
{
|
|
|
|
tex_free(c->cursor->tex);
|
|
|
|
delete c->cursor;
|
|
|
|
c->cursor = NULL;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
}
|
2004-08-12 19:36:48 +02:00
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
static void* ptr_from_HICON(HICON hIcon)
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
2005-07-16 19:52:05 +02:00
|
|
|
return (void*)(uintptr_t)hIcon;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
static HICON HICON_from_ptr(void* p)
|
|
|
|
{
|
|
|
|
return (HICON)(uintptr_t)p;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
static int cursor_load(Handle ht, int hotspotx, int hotspoty, void** sysdep_cursor)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
*sysdep_cursor = 0;
|
2005-01-07 02:10:00 +01:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
void* bgra_mem = 0;
|
2005-01-07 02:10:00 +01:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
{
|
|
|
|
// get format
|
|
|
|
int w, h, fmt, bpp;
|
|
|
|
const u8* imgdata;
|
|
|
|
CHECK_ERR(tex_info(ht, &w, &h, &fmt, &bpp, (void**)&imgdata));
|
|
|
|
if(bpp != 32 || (fmt != GL_BGRA && fmt != GL_RGBA))
|
|
|
|
{
|
|
|
|
debug_warn("Cursor texture not 32-bit RGBA/BGRA");
|
|
|
|
ret = ERR_TEX_FMT_INVALID;
|
|
|
|
goto fail;
|
2004-07-29 18:14:22 +02:00
|
|
|
}
|
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
// convert to BGRA if not already in that format (required by BMP)
|
|
|
|
if(fmt != GL_BGRA)
|
2004-07-29 18:14:22 +02:00
|
|
|
{
|
2005-07-16 19:52:05 +02:00
|
|
|
// don't convert in-place so we don't spoil someone else's
|
|
|
|
// use of the texture (however unlikely that may be).
|
|
|
|
bgra_mem = malloc(w*h*4);
|
|
|
|
if(!bgra_mem)
|
2004-07-29 18:14:22 +02:00
|
|
|
{
|
2005-07-16 19:52:05 +02:00
|
|
|
ret = ERR_NO_MEM;
|
|
|
|
goto fail;
|
2004-07-29 18:14:22 +02:00
|
|
|
}
|
2005-07-16 19:52:05 +02:00
|
|
|
const u8* src = imgdata;
|
|
|
|
u8* dst = (u8*)bgra_mem;
|
|
|
|
for(int i = 0; i < w*h; i++)
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
2005-07-16 19:52:05 +02:00
|
|
|
const u8 r = src[0], g = src[1], b = src[2], a = src[3];
|
|
|
|
dst[0] = b; dst[1] = g; dst[2] = r; dst[3] = a;
|
|
|
|
dst += 4;
|
|
|
|
src += 4;
|
2004-08-12 19:36:48 +02:00
|
|
|
}
|
2005-07-16 19:52:05 +02:00
|
|
|
imgdata = (const u8*)bgra_mem;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-07-20 02:57:17 +02:00
|
|
|
HBITMAP hbmColor = CreateBitmap(w, h, 1, 32, imgdata);
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-07-20 02:57:17 +02:00
|
|
|
// CreateIconIndirect doesn't access it; we just need to pass
|
|
|
|
// an empty bitmap.
|
|
|
|
HBITMAP hbmMask = CreateBitmap(w, h, 1, 1, 0);
|
2005-07-16 19:52:05 +02:00
|
|
|
|
|
|
|
ICONINFO ii;
|
|
|
|
ii.fIcon = FALSE; // cursor
|
|
|
|
ii.xHotspot = hotspotx;
|
|
|
|
ii.yHotspot = hotspoty;
|
2005-07-20 02:57:17 +02:00
|
|
|
ii.hbmMask = hbmMask;
|
|
|
|
ii.hbmColor = hbmColor;
|
|
|
|
HICON hIcon = CreateIconIndirect(&ii);
|
2005-07-16 19:52:05 +02:00
|
|
|
|
2005-07-20 02:57:17 +02:00
|
|
|
// CreateIconIndirect makes copies, so we no longer need these.
|
|
|
|
DeleteObject(hbmMask);
|
|
|
|
DeleteObject(hbmColor);
|
2005-07-16 19:52:05 +02:00
|
|
|
|
2005-07-20 02:57:17 +02:00
|
|
|
if(!hIcon) // not INVALID_HANDLE_VALUE
|
2005-07-16 19:52:05 +02:00
|
|
|
{
|
|
|
|
debug_warn("cursor CreateIconIndirect failed");
|
|
|
|
goto fail;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-07-20 02:57:17 +02:00
|
|
|
*sysdep_cursor = ptr_from_HICON(hIcon);
|
2005-07-16 19:52:05 +02:00
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
free(bgra_mem);
|
|
|
|
|
|
|
|
CHECK_ERR(ret);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
static int Cursor_reload(Cursor* c, const char* name, Handle)
|
|
|
|
{
|
|
|
|
char filename[VFS_MAX_PATH];
|
|
|
|
|
|
|
|
// Load the .txt file containing the pixel offset of
|
|
|
|
// the cursor's hotspot (the bit of it that's
|
|
|
|
// drawn at (g_mouse_x,g_mouse_y) )
|
|
|
|
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.txt", name);
|
|
|
|
int hotspotx, hotspoty;
|
|
|
|
{
|
|
|
|
void* p;
|
|
|
|
size_t size;
|
|
|
|
Handle hm = vfs_load(filename, p, size);
|
|
|
|
RETURN_ERR(hm);
|
|
|
|
|
|
|
|
std::stringstream s(std::string((const char*)p, size));
|
|
|
|
s >> hotspotx >> hotspoty;
|
|
|
|
|
|
|
|
mem_free_h(hm);
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.png", name);
|
|
|
|
|
|
|
|
Handle ht = tex_load(filename);
|
|
|
|
CHECK_ERR(ht);
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (c->type == 1)
|
|
|
|
{
|
|
|
|
int err = cursor_load(ht, hotspotx, hotspoty, (void**)&c->wincursor);
|
|
|
|
if(err < 0)
|
|
|
|
{
|
|
|
|
tex_free(ht);
|
|
|
|
return err;
|
|
|
|
}
|
2004-07-24 21:38:12 +02:00
|
|
|
}
|
2004-08-12 19:36:48 +02:00
|
|
|
else
|
|
|
|
#endif // _WIN32
|
2004-07-24 21:38:12 +02:00
|
|
|
{
|
2005-07-16 19:52:05 +02:00
|
|
|
int err = tex_upload(ht, GL_NEAREST);
|
2004-12-01 22:37:01 +01:00
|
|
|
CHECK_ERR(err);
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-02-02 18:01:33 +01:00
|
|
|
c->cursor = new ogl_cursor;
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-07-16 19:52:05 +02:00
|
|
|
c->cursor->tex = ht;
|
2004-08-12 19:36:48 +02:00
|
|
|
c->cursor->hotspotx = hotspotx;
|
|
|
|
c->cursor->hotspoty = hotspoty;
|
|
|
|
// Get the width/height
|
|
|
|
tex_info(c->cursor->tex, &c->cursor->w, &c->cursor->h, NULL, NULL, NULL);
|
2004-07-24 21:38:12 +02:00
|
|
|
}
|
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
Handle cursor_load(const char* name)
|
|
|
|
{
|
|
|
|
return h_alloc(H_Cursor, name, 0);
|
|
|
|
}
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
int cursor_free(Handle& h)
|
|
|
|
{
|
|
|
|
return h_free(h, H_Cursor);
|
|
|
|
}
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
extern int g_yres; // from main.cpp. Required because GL's (0,0) is in the bottom-left
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
void cursor_draw(const char* name)
|
|
|
|
{
|
|
|
|
// Use 'null' to disable the cursor
|
|
|
|
if (!name)
|
2004-07-24 21:38:12 +02:00
|
|
|
{
|
2004-08-12 19:36:48 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
|
|
#endif
|
|
|
|
return;
|
2004-07-24 21:38:12 +02:00
|
|
|
}
|
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
Handle h = cursor_load(name);
|
|
|
|
if (h <= 0)
|
|
|
|
return;
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
Cursor* c = (Cursor*) h_user_data(h, H_Cursor);
|
|
|
|
if (!c)
|
2004-07-24 21:38:12 +02:00
|
|
|
return;
|
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (c->type == 1)
|
2004-07-24 21:38:12 +02:00
|
|
|
{
|
2004-08-12 19:36:48 +02:00
|
|
|
SetCursor(c->wincursor);
|
2004-07-24 21:38:12 +02:00
|
|
|
}
|
2004-08-12 19:36:48 +02:00
|
|
|
else
|
|
|
|
#endif // _WIN32
|
2004-07-24 21:38:12 +02:00
|
|
|
{
|
2005-01-23 18:42:28 +01:00
|
|
|
c->cursor->draw(g_mouse_x, g_yres - g_mouse_y);
|
2004-07-24 21:38:12 +02:00
|
|
|
}
|
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
cursor_free(h);
|
|
|
|
}
|