mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 21:34:08 -07:00
- sysdep cursor functions renamed sys_cursor_*
- res/cursor.cpp cleaned up, uses sys_cursor_*; also fixed some bugs. This was SVN commit r2593.
This commit is contained in:
parent
b63bc42245
commit
4b33f49da1
5 changed files with 141 additions and 138 deletions
|
|
@ -3,30 +3,52 @@
|
|||
#include <string.h>
|
||||
#include <sstream>
|
||||
|
||||
#define USE_WINDOWS_CURSOR
|
||||
|
||||
#if OS_WIN
|
||||
#include "lib/sysdep/win/win_internal.h"
|
||||
#endif
|
||||
// On Windows, allow runtime choice between system cursors and OpenGL
|
||||
// cursors (Windows = more responsive, OpenGL = more consistent with what
|
||||
// the game sees)
|
||||
#define USE_WINDOWS_CURSOR 1
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "sysdep/sysdep.h" // sys_cursor_*
|
||||
#include "res.h"
|
||||
#include "ogl_tex.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "sysdep/sysdep.h"
|
||||
#include "cursor.h"
|
||||
|
||||
struct ogl_cursor {
|
||||
Handle tex;
|
||||
int hotspotx, hotspoty;
|
||||
// no init is necessary because this is stored in struct Cursor, which
|
||||
// is 0-initialized by h_mgr.
|
||||
class GLCursor
|
||||
{
|
||||
Handle ht;
|
||||
int w, h;
|
||||
int hotspotx, hotspoty;
|
||||
|
||||
public:
|
||||
void create(Handle ht_, int w_, int h_, int hotspotx_, int hotspoty_)
|
||||
{
|
||||
ht = ht_;
|
||||
w = w_; h = h_;
|
||||
hotspotx = hotspotx_; hotspoty = hotspoty_;
|
||||
|
||||
WARN_ERR(tex_upload(ht, GL_NEAREST));
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
WARN_ERR(tex_free(ht));
|
||||
}
|
||||
|
||||
void draw(int x, int y)
|
||||
{
|
||||
tex_bind(tex);
|
||||
WARN_ERR(tex_bind(ht));
|
||||
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);
|
||||
|
||||
// OpenGL's coordinate system is "upside-down"; correct for that.
|
||||
y = g_yres - y;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2i(0, 0); glVertex2i( x-hotspotx, y+hotspoty );
|
||||
glTexCoord2i(1, 0); glVertex2i( x-hotspotx+w, y+hotspoty );
|
||||
|
|
@ -36,170 +58,114 @@ struct ogl_cursor {
|
|||
}
|
||||
};
|
||||
|
||||
extern int g_mouse_x, g_mouse_y;
|
||||
|
||||
#if OS_WIN
|
||||
// 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
|
||||
void* sys_cursor;
|
||||
|
||||
// valid iff sys_cursor == 0.
|
||||
GLCursor gl_cursor;
|
||||
};
|
||||
#else // #if OS_WIN
|
||||
struct Cursor
|
||||
{
|
||||
ogl_cursor* cursor; // font texture
|
||||
};
|
||||
#endif // #if OS_WIN / #else
|
||||
|
||||
H_TYPE_DEFINE(Cursor);
|
||||
|
||||
static void Cursor_init(Cursor* c, va_list)
|
||||
static void Cursor_init(Cursor* UNUSED(c), va_list UNUSED(args))
|
||||
{
|
||||
#if OS_WIN
|
||||
# ifdef USE_WINDOWS_CURSOR
|
||||
c->type = 1;
|
||||
# else
|
||||
c->type = 0;
|
||||
# endif
|
||||
c->wincursor = NULL;
|
||||
#endif
|
||||
|
||||
c->cursor = NULL;
|
||||
}
|
||||
|
||||
static void Cursor_dtor(Cursor* c)
|
||||
{
|
||||
#if OS_WIN
|
||||
if (c->type == 1)
|
||||
{
|
||||
if (c->wincursor)
|
||||
DestroyIcon(c->wincursor);
|
||||
}
|
||||
if(c->sys_cursor)
|
||||
WARN_ERR(sys_cursor_free(c->sys_cursor));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (c->cursor)
|
||||
{
|
||||
tex_free(c->cursor->tex);
|
||||
delete c->cursor;
|
||||
c->cursor = NULL;
|
||||
}
|
||||
}
|
||||
c->gl_cursor.destroy();
|
||||
}
|
||||
|
||||
static int Cursor_reload(Cursor* c, const char* name, Handle)
|
||||
{
|
||||
char filename[VFS_MAX_PATH];
|
||||
int ret;
|
||||
|
||||
// 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) )
|
||||
// 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;
|
||||
int hotspotx = 0, hotspoty = 0;
|
||||
{
|
||||
void* p;
|
||||
size_t size;
|
||||
void* p; size_t size;
|
||||
Handle hm = vfs_load(filename, p, size);
|
||||
RETURN_ERR(hm);
|
||||
WARN_ERR(hm);
|
||||
if(hm > 0)
|
||||
{
|
||||
std::stringstream s(std::string((const char*)p, size));
|
||||
s >> hotspotx >> hotspoty;
|
||||
|
||||
std::stringstream s(std::string((const char*)p, size));
|
||||
s >> hotspotx >> hotspoty;
|
||||
|
||||
mem_free_h(hm);
|
||||
WARN_ERR(mem_free_h(hm));
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.png", name);
|
||||
|
||||
Handle ht = tex_load(filename);
|
||||
CHECK_ERR(ht);
|
||||
RETURN_ERR(ht);
|
||||
|
||||
#if OS_WIN
|
||||
if (c->type == 1)
|
||||
{
|
||||
int w, h, gl_fmt, bpp;
|
||||
void* img;
|
||||
if(tex_info(ht, &w, &h, &gl_fmt, &bpp, &img) < 0 ||
|
||||
(bpp != 32 || gl_fmt != GL_RGBA))
|
||||
{
|
||||
debug_warn("Cursor_reload: invalid texture format");
|
||||
ret = ERR_TEX_FMT_INVALID;
|
||||
goto fail;
|
||||
}
|
||||
int w = 0, h = 0;
|
||||
int gl_fmt = 0, bpp = 0;
|
||||
void* img = 0;
|
||||
WARN_ERR(tex_info(ht, &w, &h, &gl_fmt, &bpp, &img));
|
||||
|
||||
ret = cursor_create(w, h, img, hotspotx, hotspoty, (void**)&c->wincursor);
|
||||
if(ret < 0)
|
||||
{
|
||||
fail:
|
||||
tex_free(ht);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#if USE_WINDOWS_CURSOR
|
||||
// verify texture format (this isn't done in sys_cursor_create to
|
||||
// avoid needing to pass gl_fmt and bpp; it assumes 32-bit RGBA).
|
||||
if(bpp != 32 || gl_fmt != GL_RGBA)
|
||||
debug_warn("Cursor_reload: invalid texture format");
|
||||
else
|
||||
WARN_ERR(sys_cursor_create(w, h, img, hotspotx, hotspoty, &c->sys_cursor));
|
||||
#endif
|
||||
{
|
||||
int err = tex_upload(ht, GL_NEAREST);
|
||||
CHECK_ERR(err);
|
||||
|
||||
c->cursor = new ogl_cursor;
|
||||
|
||||
c->cursor->tex = ht;
|
||||
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);
|
||||
}
|
||||
// if the system cursor code is disabled or failed, fall back to GLCursor.
|
||||
if(!c->sys_cursor)
|
||||
c->gl_cursor.create(ht, w, h, hotspotx, hotspoty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle cursor_load(const char* name)
|
||||
// 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)
|
||||
{
|
||||
return h_alloc(H_Cursor, name, 0);
|
||||
}
|
||||
|
||||
int cursor_free(Handle& h)
|
||||
static int cursor_free(Handle& h)
|
||||
{
|
||||
return h_free(h, H_Cursor);
|
||||
}
|
||||
|
||||
extern int g_yres; // from main.cpp. Required because GL's (0,0) is in the bottom-left
|
||||
|
||||
void cursor_draw(const char* name)
|
||||
// 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)
|
||||
{
|
||||
// Use 'null' to disable the cursor
|
||||
if (!name)
|
||||
if(!name)
|
||||
{
|
||||
#if OS_WIN
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
#endif
|
||||
return;
|
||||
WARN_ERR(sys_cursor_set(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle h = cursor_load(name);
|
||||
if (h <= 0)
|
||||
return;
|
||||
Handle hc = cursor_load(name);
|
||||
RETURN_ERR(hc);
|
||||
H_DEREF(hc, Cursor, c);
|
||||
|
||||
Cursor* c = (Cursor*) h_user_data(h, H_Cursor);
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
#if OS_WIN
|
||||
if (c->type == 1)
|
||||
{
|
||||
SetCursor(c->wincursor);
|
||||
}
|
||||
if(c->sys_cursor)
|
||||
WARN_ERR(sys_cursor_set(c->sys_cursor));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
c->cursor->draw(g_mouse_x, g_yres - g_mouse_y);
|
||||
}
|
||||
c->gl_cursor.draw(x, y);
|
||||
|
||||
cursor_free(h);
|
||||
(void)cursor_free(hc);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,13 @@
|
|||
void cursor_draw(const char* name);
|
||||
#ifndef CURSOR_H__
|
||||
#define CURSOR_H__
|
||||
|
||||
// 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.
|
||||
extern int cursor_draw(const char* name, int x, int y);
|
||||
|
||||
// internal use only:
|
||||
extern int g_yres;
|
||||
|
||||
#endif // #ifndef CURSOR_H__
|
||||
|
|
|
|||
|
|
@ -108,20 +108,22 @@ extern int clipboard_free(wchar_t* copy);
|
|||
// mouse cursor
|
||||
//
|
||||
|
||||
// note: these do not warn on error; that is left to the caller.
|
||||
|
||||
// creates a cursor from the given 32 bpp RGBA texture. hotspot (hx,hy) is
|
||||
// the offset from its upper-left corner to the position where mouse clicks
|
||||
// are registered.
|
||||
// the cursor must be cursor_free-ed when no longer needed.
|
||||
extern int cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
extern int sys_cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
void** cursor);
|
||||
|
||||
// replaces the current system cursor with the one indicated. need only be
|
||||
// called once per cursor; pass 0 to restore the default.
|
||||
extern int cursor_set(void* cursor);
|
||||
extern int sys_cursor_set(void* cursor);
|
||||
|
||||
// destroys the indicated cursor and frees its resources. if it is
|
||||
// currently the system cursor, the default cursor is restored first.
|
||||
extern int cursor_free(void* cursor);
|
||||
extern int sys_cursor_free(void* cursor);
|
||||
|
||||
|
||||
extern int get_executable_name(char* n_path, size_t buf_size);
|
||||
|
|
|
|||
|
|
@ -79,3 +79,29 @@ ErrorReaction display_error_impl(const wchar_t* text, int flags)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mouse cursor stubs (required by lib/res/cursor.cpp)
|
||||
// note: do not return ERR_NOT_IMPLEMENTED or similar because that
|
||||
// would result in WARN_ERRs.
|
||||
//
|
||||
// TODO: implementing these would be nice because then the game can
|
||||
// take advantage of hardware mouse cursors instead of the (jerky when
|
||||
// loading) OpenGL cursor.
|
||||
|
||||
int sys_cursor_create(int UNUSED(w), int UNUSED(h), void* UNUSED(img),
|
||||
int UNUSED(hx), UNUSED(int hy), void** cursor)
|
||||
{
|
||||
*cursor = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_cursor_set(void* cursor)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_cursor_free(void* cursor)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ static HCURSOR HCURSOR_from_ptr(void* p)
|
|||
// the offset from its upper-left corner to the position where mouse clicks
|
||||
// are registered.
|
||||
// the cursor must be cursor_free-ed when no longer needed.
|
||||
int cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
int sys_cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
void** cursor)
|
||||
{
|
||||
*cursor = 0;
|
||||
|
|
@ -569,7 +569,7 @@ int cursor_create(int w, int h, void* img, int hx, int hy,
|
|||
// CreateBitmap; bpp/format must be checked against those of the DC.
|
||||
// this is the simplest way and we don't care about slight performance
|
||||
// differences because this is typically only called once.
|
||||
HBITMAP hbmColor = CreateBitmap(w, h, 1, 32, img_bgra);
|
||||
HBITMAP hbmColour = CreateBitmap(w, h, 1, 32, img_bgra);
|
||||
|
||||
free(img_bgra);
|
||||
|
||||
|
|
@ -584,18 +584,15 @@ int cursor_create(int w, int h, void* img, int hx, int hy,
|
|||
ii.xHotspot = hx;
|
||||
ii.yHotspot = hy;
|
||||
ii.hbmMask = hbmMask;
|
||||
ii.hbmColor = hbmColor;
|
||||
ii.hbmColor = hbmColour;
|
||||
HICON hIcon = CreateIconIndirect(&ii);
|
||||
|
||||
// CreateIconIndirect makes copies, so we no longer need these.
|
||||
DeleteObject(hbmMask);
|
||||
DeleteObject(hbmColor);
|
||||
DeleteObject(hbmColour);
|
||||
|
||||
if(!hIcon) // not INVALID_HANDLE_VALUE
|
||||
{
|
||||
debug_warn("cursor CreateIconIndirect failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*cursor = ptr_from_HICON(hIcon);
|
||||
return 0;
|
||||
|
|
@ -604,7 +601,7 @@ int cursor_create(int w, int h, void* img, int hx, int hy,
|
|||
|
||||
// replaces the current system cursor with the one indicated. need only be
|
||||
// called once per cursor; pass 0 to restore the default.
|
||||
int cursor_set(void* cursor)
|
||||
int sys_cursor_set(void* cursor)
|
||||
{
|
||||
// restore default cursor.
|
||||
if(!cursor)
|
||||
|
|
@ -619,7 +616,7 @@ int cursor_set(void* cursor)
|
|||
|
||||
// destroys the indicated cursor and frees its resources. if it is
|
||||
// currently the system cursor, the default cursor is restored first.
|
||||
int cursor_free(void* cursor)
|
||||
int sys_cursor_free(void* cursor)
|
||||
{
|
||||
// bail now to prevent potential confusion below; there's nothing to do.
|
||||
if(!cursor)
|
||||
|
|
@ -628,7 +625,7 @@ int cursor_free(void* cursor)
|
|||
// if the cursor being freed is active, restore the default arrow
|
||||
// (just for safety).
|
||||
if(ptr_from_HCURSOR(GetCursor()) == cursor)
|
||||
WARN_ERR(cursor_set(0));
|
||||
WARN_ERR(sys_cursor_set(0));
|
||||
|
||||
BOOL ok = DestroyIcon(HICON_from_ptr(cursor));
|
||||
return ok? 0 : -1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue