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
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
// On Windows, allow runtime choice between system cursors and OpenGL
|
|
|
|
// cursors (Windows = more responsive, OpenGL = more consistent with what
|
|
|
|
// the game sees)
|
2005-09-29 23:48:04 +02:00
|
|
|
#if OS_WIN
|
2005-09-29 07:00:20 +02:00
|
|
|
#define ALLOW_SYS_CURSOR 1
|
2005-09-29 23:48:04 +02:00
|
|
|
#endif
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
#include "lib/ogl.h"
|
|
|
|
#include "sysdep/sysdep.h" // sys_cursor_*
|
2005-08-12 19:06:53 +02:00
|
|
|
#include "../res.h"
|
2004-10-06 16:00:43 +02:00
|
|
|
#include "ogl_tex.h"
|
2005-08-10 02:27:56 +02:00
|
|
|
#include "cursor.h"
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
// no init is necessary because this is stored in struct Cursor, which
|
|
|
|
// is 0-initialized by h_mgr.
|
|
|
|
class GLCursor
|
|
|
|
{
|
|
|
|
Handle ht;
|
2005-10-12 06:35:01 +02:00
|
|
|
|
2005-09-29 07:00:20 +02:00
|
|
|
uint w, h;
|
|
|
|
uint hotspotx, hotspoty;
|
2005-08-10 02:27:56 +02:00
|
|
|
|
|
|
|
public:
|
2005-09-29 07:00:20 +02:00
|
|
|
int create(const char* filename, uint hotspotx_, uint hotspoty_)
|
2005-08-10 02:27:56 +02:00
|
|
|
{
|
2005-09-29 07:00:20 +02:00
|
|
|
ht = ogl_tex_load(filename);
|
|
|
|
RETURN_ERR(ht);
|
|
|
|
|
|
|
|
(void)ogl_tex_get_size(ht, &w, &h, 0);
|
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
hotspotx = hotspotx_; hotspoty = hotspoty_;
|
|
|
|
|
2005-09-29 07:00:20 +02:00
|
|
|
(void)ogl_tex_set_filter(ht, GL_NEAREST);
|
|
|
|
(void)ogl_tex_upload(ht);
|
|
|
|
return 0;
|
2005-08-10 02:27:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void destroy()
|
|
|
|
{
|
2005-10-12 06:35:01 +02:00
|
|
|
// note: we're stored in a resource => ht is initially 0 =>
|
|
|
|
// this is safe, no need for an is_valid flag
|
2005-09-29 07:00:20 +02:00
|
|
|
(void)ogl_tex_free(ht);
|
2005-08-10 02:27:56 +02:00
|
|
|
}
|
|
|
|
|
2005-10-12 06:35:01 +02:00
|
|
|
void draw(uint x, uint y) const
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
2005-09-29 07:00:20 +02:00
|
|
|
(void)ogl_tex_bind(ht);
|
2004-08-12 19:36:48 +02:00
|
|
|
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
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
// OpenGL's coordinate system is "upside-down"; correct for that.
|
|
|
|
y = g_yres - y;
|
|
|
|
|
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();
|
|
|
|
}
|
2005-10-12 06:35:01 +02:00
|
|
|
|
|
|
|
int validate() const
|
|
|
|
{
|
|
|
|
const uint A = 128; // no cursor is expected to get this big
|
|
|
|
if(w > A || h > A || hotspotx > A || hotspoty > A)
|
|
|
|
return -2;
|
|
|
|
if(ht < 0)
|
|
|
|
return -3;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-08-12 19:36:48 +02:00
|
|
|
};
|
2004-07-29 18:14:22 +02:00
|
|
|
|
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
struct Cursor
|
|
|
|
{
|
2005-08-10 02:27:56 +02:00
|
|
|
void* sys_cursor;
|
|
|
|
|
|
|
|
// valid iff sys_cursor == 0.
|
|
|
|
GLCursor gl_cursor;
|
2004-08-12 19:36:48 +02:00
|
|
|
};
|
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
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
static void Cursor_init(Cursor* UNUSED(c), va_list UNUSED(args))
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
|
|
|
}
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2004-08-12 19:36:48 +02:00
|
|
|
static void Cursor_dtor(Cursor* c)
|
|
|
|
{
|
2005-10-12 06:35:01 +02:00
|
|
|
// (note: these are safe, no need for an is_valid flag)
|
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
if(c->sys_cursor)
|
|
|
|
WARN_ERR(sys_cursor_free(c->sys_cursor));
|
2004-08-12 19:36:48 +02:00
|
|
|
else
|
2005-08-10 02:27:56 +02:00
|
|
|
c->gl_cursor.destroy();
|
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 int Cursor_reload(Cursor* c, const char* name, Handle)
|
|
|
|
{
|
|
|
|
char filename[VFS_MAX_PATH];
|
|
|
|
|
2005-09-29 07:00:20 +02:00
|
|
|
// read pixel offset of the cursor's hotspot [the bit of it that's
|
|
|
|
// drawn at (g_mouse_x,g_mouse_y)] from file.
|
|
|
|
uint hotspotx = 0, hotspoty = 0;
|
2005-07-16 19:52:05 +02:00
|
|
|
{
|
2005-09-29 07:00:20 +02:00
|
|
|
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.txt", name);
|
2005-08-10 02:27:56 +02:00
|
|
|
void* p; size_t size;
|
2005-07-16 19:52:05 +02:00
|
|
|
Handle hm = vfs_load(filename, p, size);
|
2005-09-29 07:00:20 +02:00
|
|
|
RETURN_ERR(hm);
|
|
|
|
std::stringstream s(std::string((const char*)p, size));
|
|
|
|
s >> hotspotx >> hotspoty;
|
|
|
|
(void)mem_free_h(hm);
|
2005-07-16 19:52:05 +02:00
|
|
|
}
|
|
|
|
|
2005-09-29 07:00:20 +02:00
|
|
|
// load actual cursor
|
2005-07-16 19:52:05 +02:00
|
|
|
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.png", name);
|
2005-09-29 07:00:20 +02:00
|
|
|
// .. system cursor (2d, hardware accelerated)
|
|
|
|
#if ALLOW_SYS_CURSOR
|
|
|
|
WARN_ERR(sys_cursor_load(filename, hotspotx, hotspoty, &c->sys_cursor));
|
2005-09-29 23:48:04 +02:00
|
|
|
#else
|
|
|
|
c->sys_cursor = 0;
|
2005-08-09 18:23:19 +02:00
|
|
|
#endif
|
2005-09-29 07:00:20 +02:00
|
|
|
// .. fall back to GLCursor (system cursor code is disabled or failed)
|
2005-08-10 02:27:56 +02:00
|
|
|
if(!c->sys_cursor)
|
2005-09-29 07:00:20 +02:00
|
|
|
RETURN_ERR(c->gl_cursor.create(filename, hotspotx, hotspoty));
|
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
|
|
|
|
2005-10-12 06:35:01 +02:00
|
|
|
static int Cursor_validate(const Cursor* c)
|
|
|
|
{
|
|
|
|
// note: system cursors have no state to speak of, so we don't need to
|
|
|
|
// validate them.
|
|
|
|
|
|
|
|
if(!c->sys_cursor)
|
|
|
|
RETURN_ERR(c->gl_cursor.validate());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
// note: these standard resource interface functions are not exposed to the
|
|
|
|
// caller. all we need here is storage for the sys_cursor / GLCursor and
|
|
|
|
// a name -> data lookup mechanism, both provided by h_mgr.
|
|
|
|
// in other words, we continually create/free the cursor resource in
|
|
|
|
// cursor_draw and trust h_mgr's caching to absorb it.
|
|
|
|
|
|
|
|
static Handle cursor_load(const char* name)
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
|
|
|
return h_alloc(H_Cursor, name, 0);
|
|
|
|
}
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
static int cursor_free(Handle& h)
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
|
|
|
return h_free(h, H_Cursor);
|
|
|
|
}
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2004-07-29 18:14:22 +02:00
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
// draw the specified cursor at the given pixel coordinates
|
|
|
|
// (origin is top-left to match the windowing system).
|
|
|
|
// uses a hardware mouse cursor where available, otherwise a
|
|
|
|
// portable OpenGL implementation.
|
|
|
|
int cursor_draw(const char* name, int x, int y)
|
2004-08-12 19:36:48 +02:00
|
|
|
{
|
|
|
|
// Use 'null' to disable the cursor
|
2005-08-10 02:27:56 +02:00
|
|
|
if(!name)
|
2004-07-24 21:38:12 +02:00
|
|
|
{
|
2005-08-10 02:27:56 +02:00
|
|
|
WARN_ERR(sys_cursor_set(0));
|
|
|
|
return 0;
|
2004-07-24 21:38:12 +02:00
|
|
|
}
|
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
Handle hc = cursor_load(name);
|
2005-09-29 07:00:20 +02:00
|
|
|
CHECK_ERR(hc);
|
2005-08-10 02:27:56 +02:00
|
|
|
H_DEREF(hc, Cursor, c);
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
if(c->sys_cursor)
|
|
|
|
WARN_ERR(sys_cursor_set(c->sys_cursor));
|
2004-08-12 19:36:48 +02:00
|
|
|
else
|
2005-08-10 02:27:56 +02:00
|
|
|
c->gl_cursor.draw(x, y);
|
2004-07-24 21:38:12 +02:00
|
|
|
|
2005-08-10 02:27:56 +02:00
|
|
|
(void)cursor_free(hc);
|
|
|
|
return 0;
|
2004-08-12 19:36:48 +02:00
|
|
|
}
|