changed sys_cursor interface to load directly from file; can add createFromMemory version later if ever needed.
cursor: reflects the above; much simplified now. ogl_tex: preserve all texture state across reloads. add quality mechanism (perf boost on older cards). split up upload code. add ogl_tex_transform(). add more docs. renderer, GUIrenderer, unifont: bring in line with ogl_tex changes (int -> uint and call setters before ogl_tex_upload) GameSetup.cpp: add tex quality mechanism This was SVN commit r2803.
This commit is contained in:
parent
14df805761
commit
cd2f3948dd
@ -389,7 +389,9 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, CStr &SpriteName, CRect
|
||||
return;
|
||||
}
|
||||
|
||||
int err = ogl_tex_upload(h, GL_LINEAR);
|
||||
(void)ogl_tex_set_filter(h, GL_LINEAR);
|
||||
|
||||
int err = ogl_tex_upload(h);
|
||||
if (err < 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "Error uploading texture '%s': %d", (const char*)cit->m_TextureName, err);
|
||||
@ -398,11 +400,11 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, CStr &SpriteName, CRect
|
||||
|
||||
Call.m_TexHandle = h;
|
||||
|
||||
int t_w = 0, t_h = 0;
|
||||
uint t_w = 0, t_h = 0;
|
||||
(void)ogl_tex_get_size(h, &t_w, &t_h, 0);
|
||||
float TexWidth = t_w, TexHeight = t_h;
|
||||
|
||||
int flags = 0; // assume no alpha on failure
|
||||
uint flags = 0; // assume no alpha on failure
|
||||
(void)ogl_tex_get_format(h, &flags, 0);
|
||||
Call.m_EnableBlending = (flags & TEX_ALPHA) != 0;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
// 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
|
||||
#define ALLOW_SYS_CURSOR 1
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "sysdep/sysdep.h" // sys_cursor_*
|
||||
@ -19,27 +19,32 @@
|
||||
class GLCursor
|
||||
{
|
||||
Handle ht;
|
||||
int w, h;
|
||||
int hotspotx, hotspoty;
|
||||
uint w, h;
|
||||
uint hotspotx, hotspoty;
|
||||
|
||||
public:
|
||||
void create(Handle ht_, int w_, int h_, int hotspotx_, int hotspoty_)
|
||||
int create(const char* filename, uint hotspotx_, uint hotspoty_)
|
||||
{
|
||||
ht = ht_;
|
||||
w = w_; h = h_;
|
||||
ht = ogl_tex_load(filename);
|
||||
RETURN_ERR(ht);
|
||||
|
||||
(void)ogl_tex_get_size(ht, &w, &h, 0);
|
||||
|
||||
hotspotx = hotspotx_; hotspoty = hotspoty_;
|
||||
|
||||
WARN_ERR(ogl_tex_upload(ht, GL_NEAREST));
|
||||
(void)ogl_tex_set_filter(ht, GL_NEAREST);
|
||||
(void)ogl_tex_upload(ht);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
WARN_ERR(ogl_tex_free(ht));
|
||||
(void)ogl_tex_free(ht);
|
||||
}
|
||||
|
||||
void draw(int x, int y)
|
||||
void draw(uint x, uint y)
|
||||
{
|
||||
WARN_ERR(ogl_tex_bind(ht));
|
||||
(void)ogl_tex_bind(ht);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
@ -85,46 +90,28 @@ 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 = 0, hotspoty = 0;
|
||||
// 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;
|
||||
{
|
||||
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.txt", name);
|
||||
void* p; size_t size;
|
||||
Handle hm = vfs_load(filename, p, size);
|
||||
WARN_ERR(hm);
|
||||
if(hm > 0)
|
||||
{
|
||||
std::stringstream s(std::string((const char*)p, size));
|
||||
s >> hotspotx >> hotspoty;
|
||||
|
||||
WARN_ERR(mem_free_h(hm));
|
||||
}
|
||||
RETURN_ERR(hm);
|
||||
std::stringstream s(std::string((const char*)p, size));
|
||||
s >> hotspotx >> hotspoty;
|
||||
(void)mem_free_h(hm);
|
||||
}
|
||||
|
||||
// load actual cursor
|
||||
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.png", name);
|
||||
Handle ht = ogl_tex_load(filename);
|
||||
RETURN_ERR(ht);
|
||||
|
||||
int w = 0, h = 0, bpp = 0; // remain 0 on failure
|
||||
GLenum gl_fmt = 0; // (caught below)
|
||||
void* img = 0;
|
||||
(void)ogl_tex_get_size(ht, &w, &h, &bpp);
|
||||
(void)ogl_tex_get_format(ht, 0, &gl_fmt);
|
||||
(void)ogl_tex_get_data(ht, &img);
|
||||
|
||||
#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));
|
||||
// .. system cursor (2d, hardware accelerated)
|
||||
#if ALLOW_SYS_CURSOR
|
||||
WARN_ERR(sys_cursor_load(filename, hotspotx, hotspoty, &c->sys_cursor));
|
||||
#endif
|
||||
|
||||
// if the system cursor code is disabled or failed, fall back to GLCursor.
|
||||
// .. fall back to GLCursor (system cursor code is disabled or failed)
|
||||
if(!c->sys_cursor)
|
||||
c->gl_cursor.create(ht, w, h, hotspotx, hotspoty);
|
||||
RETURN_ERR(c->gl_cursor.create(filename, hotspotx, hotspoty));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -160,7 +147,7 @@ int cursor_draw(const char* name, int x, int y)
|
||||
}
|
||||
|
||||
Handle hc = cursor_load(name);
|
||||
RETURN_ERR(hc);
|
||||
CHECK_ERR(hc);
|
||||
H_DEREF(hc, Cursor, c);
|
||||
|
||||
if(c->sys_cursor)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,15 +32,21 @@ It basically wraps tex.cpp's texture info in a resource object
|
||||
reference counting, caching, hotloading and safe access.
|
||||
|
||||
|
||||
Caching and Texture Instances
|
||||
-----------------------------
|
||||
Texture Parameters
|
||||
------------------
|
||||
|
||||
Caching is both an advantage and drawback. When opening the same
|
||||
texture twice without previously freeing it, a reference to the
|
||||
first instance is returned. Therefore, be advised that concurrent use of the
|
||||
same texture but with differing parameters (e.g. upload quality) followed by
|
||||
a reload of the first instance will result in using the wrong parameters.
|
||||
For background and rationale why this is acceptable, see struct OglTex.
|
||||
OpenGL textures are conditioned on several parameters including
|
||||
filter and wrap mode. These are typically set once when the texture is
|
||||
created, but must survive reloads (1). To that end, all state (2) is
|
||||
set via ogl_tex_set_* (instead of direct glTexParameter calls) and
|
||||
re-applied after a reload.
|
||||
|
||||
(1) the purpose of hotloading is to permit artists to see their changes
|
||||
in-game without having to restart the map. reloads where the
|
||||
texture looks different due to changed state are useless.
|
||||
|
||||
(2) currently only filter and wrap mode. no other glTexParameter
|
||||
settings are used ATM; if that changes, add to OglTexState.
|
||||
|
||||
|
||||
Uploading to OpenGL
|
||||
@ -51,15 +57,27 @@ Uploading to OpenGL
|
||||
texture parameters and data from system memory to OpenGL
|
||||
(and thereby usually video memory).
|
||||
|
||||
In so doing, choices are made as to filtering algorithm and the
|
||||
texture's internal representation (how it is stored in vmem) -
|
||||
in particular, the bit depth. This can trade performance
|
||||
(more/less data to copy) for quality (fidelity to original).
|
||||
In so doing, choices are made as to the texture's internal representation
|
||||
(how it is stored in vmem) - in particular, the bit depth.
|
||||
This can trade performance (more/less data to copy) for quality
|
||||
(fidelity to original).
|
||||
|
||||
We provide a mechanism that applies defaults to all uploads unless
|
||||
overrides are specified (for individual ogl_tex_upload calls).
|
||||
This allows a global "quality" setting that can boost performance on
|
||||
We provide a mechanism that applies defaults to all uploads;
|
||||
this allows a global "quality" setting that can boost performance on
|
||||
older graphics cards without requiring anything else to be changed.
|
||||
Textures with specific quality needs can override this via
|
||||
ogl_tex_set_* or ogl_tex_upload parameters.
|
||||
|
||||
|
||||
Caching and Texture Instances
|
||||
-----------------------------
|
||||
|
||||
Caching is both an advantage and drawback. When opening the same
|
||||
texture twice without previously freeing it, a reference to the
|
||||
first instance is returned. Therefore, be advised that concurrent use of the
|
||||
same texture but with differing parameters (e.g. upload quality) followed by
|
||||
a reload of the first instance will result in using the wrong parameters.
|
||||
For background and rationale why this is acceptable, see struct OglTex.
|
||||
|
||||
|
||||
Example Usage
|
||||
@ -84,14 +102,15 @@ Handle hTexture = ogl_tex_load("filename.dds");
|
||||
(void)ogl_tex_free(hTexture);
|
||||
|
||||
|
||||
2) Advanced usage: wrap existing texture data and specify
|
||||
filter/internal_format overrides.
|
||||
2) Advanced usage: wrap existing texture data, override filter,
|
||||
specify internal_format and use multitexturing.
|
||||
Tex t;
|
||||
const uint flags = 0; // image is plain RGB, default orientation
|
||||
void* data = [pre-existing image]
|
||||
(void)tex_wrap(w, h, 24, flags, data, &t);
|
||||
Handle hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)");
|
||||
(void)ogl_tex_upload(hCompositeAlphaMap, GL_LINEAR, GL_INTENSITY);
|
||||
(void)ogl_tex_set_filter(hCompositeAlphaMap, GL_LINEAR);
|
||||
(void)ogl_tex_upload(hCompositeAlphaMap, 0, GL_INTENSITY);
|
||||
// (your responsibility! tex_wrap attaches a reference but it is
|
||||
// removed by ogl_tex_upload.)
|
||||
free(data);
|
||||
@ -114,13 +133,52 @@ free(data);
|
||||
#include "lib/ogl.h"
|
||||
#include "tex.h"
|
||||
|
||||
// change default upload settings - these affect performance vs. quality.
|
||||
// may be overridden for individual textures via ogl_tex_upload parameters.
|
||||
// pass 0 to keep the current setting; defaults and legal values are:
|
||||
// - filter: GL_LINEAR; any valid OpenGL minification filter
|
||||
// - bpp : 32; 16 or 32 (this toggles between RGBA4 and RGBA8)
|
||||
extern void ogl_tex_set_default_upload(GLint filter, uint bpp);
|
||||
|
||||
//
|
||||
// quality mechanism
|
||||
//
|
||||
|
||||
enum OglTexQualityFlags
|
||||
{
|
||||
// emphatically require full quality for this texture.
|
||||
// (q_flags are invalid if this is set together with any other bit)
|
||||
// rationale: the value 0 is used to indicate "use default flags" in
|
||||
// ogl_tex_upload and ogl_tex_set_defaults, so this is the only
|
||||
// way we can say "disregard default and do not reduce anything".
|
||||
OGL_TEX_FULL_QUALITY = 0x20,
|
||||
|
||||
// store the texture at half the normal bit depth
|
||||
// (4 bits per pixel component, as opposed to 8).
|
||||
// this increases performance on older graphics cards due to
|
||||
// decreased size in vmem. it has no effect on
|
||||
// compressed textures because they have a fixed internal format.
|
||||
OGL_TEX_HALF_BPP = 0x10,
|
||||
|
||||
// store the texture at half its original resolution.
|
||||
// this increases performance on older graphics cards due to
|
||||
// decreased size in vmem.
|
||||
// this is useful for also reducing quality of compressed textures,
|
||||
// which are not affected by OGL_TEX_HALF_BPP.
|
||||
// currently only implemented for images that contain mipmaps
|
||||
// (otherwise, we'd have to resample, which is slow).
|
||||
// note: scaling down to 1/4, 1/8, .. is easily possible without
|
||||
// extra work, so we leave some bits free for that.
|
||||
OGL_TEX_HALF_RES = 0x01
|
||||
};
|
||||
|
||||
// change default settings - these affect performance vs. quality.
|
||||
// may be overridden for individual textures via parameter to
|
||||
// ogl_tex_upload or ogl_tex_set_filter, respectively.
|
||||
//
|
||||
// pass 0 to keep the current setting; defaults and legal values are:
|
||||
// - q_flags: OGL_TEX_FULL_QUALITY; combination of OglTexQualityFlags
|
||||
// - filter: GL_LINEAR; any valid OpenGL minification filter
|
||||
extern void ogl_tex_set_defaults(uint q_flags, GLint filter);
|
||||
|
||||
|
||||
//
|
||||
// open/close
|
||||
//
|
||||
|
||||
// load and return a handle to the texture given in <fn>.
|
||||
// for a list of supported formats, see tex.h's tex_load.
|
||||
@ -142,27 +200,59 @@ extern Handle ogl_tex_wrap(Tex* t, const char* fn = 0, uint flags = 0);
|
||||
extern int ogl_tex_free(Handle& ht);
|
||||
|
||||
|
||||
// upload the texture to OpenGL. texture filter and [internal] format
|
||||
// may be specified to override the global defaults (see below).
|
||||
// side effects:
|
||||
// - enables texturing on TMU 0 and binds the texture to it;
|
||||
// - frees the texel data! see ogl_tex_get_data.
|
||||
extern int ogl_tex_upload(Handle ht, GLint filter_override = 0, GLint internal_fmt_override = 0, GLenum format_override = 0);
|
||||
//
|
||||
// set texture parameters
|
||||
//
|
||||
|
||||
// these must be called before uploading; this simplifies
|
||||
// things and avoids calling glTexParameter twice.
|
||||
|
||||
// override default filter (as set above) for this texture.
|
||||
// must be called before uploading (raises a warning if called afterwards).
|
||||
// filter is as defined by OpenGL; it is applied for both minification and
|
||||
// magnification (for rationale and details, see OglTexState)
|
||||
extern int ogl_tex_set_filter(Handle ht, GLint filter);
|
||||
|
||||
// override default wrap mode (GL_REPEAT) for this texture.
|
||||
// must be called before uploading (raises a warning if called afterwards).
|
||||
// wrap is as defined by OpenGL and applies to both S and T coordinates
|
||||
// (rationale: see OglTexState).
|
||||
extern int ogl_tex_set_wrap(Handle ht, GLint wrap);
|
||||
|
||||
|
||||
//
|
||||
// upload
|
||||
//
|
||||
|
||||
// bind the texture to the specified unit [number] in preparation for
|
||||
// using it in rendering. assumes multitexturing is available.
|
||||
// not necessary before calling ogl_tex_upload!
|
||||
// side effects:
|
||||
// - enables (or disables, if <ht> == 0) texturing on the given unit.
|
||||
extern int ogl_tex_bind(Handle ht, GLenum unit = 0);
|
||||
|
||||
// upload the texture to OpenGL.
|
||||
// if q_flags_ovr != 0, it overrides the default quality vs. perf. flags;
|
||||
// if (int_)fmt_over != 0, it overrides the texture loader's decision.
|
||||
// side effects:
|
||||
// - enables texturing on TMU 0 and binds the texture to it;
|
||||
// - frees the texel data! see ogl_tex_get_data.
|
||||
extern int ogl_tex_upload(Handle ht, uint q_flags_override = 0,
|
||||
GLint internal_fmt_override = 0, GLenum fmt_override = 0);
|
||||
|
||||
|
||||
//
|
||||
// return information about the texture
|
||||
//
|
||||
|
||||
// retrieve texture dimensions and bits per pixel.
|
||||
// all params are optional and filled if non-NULL.
|
||||
extern int ogl_tex_get_size(Handle ht, int* w, int* h, int* bpp);
|
||||
extern int ogl_tex_get_size(Handle ht, uint* w, uint* h, uint* bpp);
|
||||
|
||||
// retrieve Tex.flags and the corresponding OpenGL format.
|
||||
// the latter is determined during ogl_tex_upload and is 0 before that.
|
||||
// all params are optional and filled if non-NULL.
|
||||
extern int ogl_tex_get_format(Handle ht, int* flags, GLenum* fmt);
|
||||
extern int ogl_tex_get_format(Handle ht, uint* flags, GLenum* fmt);
|
||||
|
||||
// retrieve pointer to texel data.
|
||||
//
|
||||
@ -173,4 +263,13 @@ extern int ogl_tex_get_format(Handle ht, int* flags, GLenum* fmt);
|
||||
// uploading it or read directly from OpenGL (discouraged).
|
||||
extern int ogl_tex_get_data(Handle ht, void** p);
|
||||
|
||||
|
||||
//
|
||||
// misc
|
||||
//
|
||||
|
||||
// apply the specified transforms (as in tex_transform) to the image.
|
||||
// must be called before uploading (raises a warning if called afterwards).
|
||||
extern int ogl_tex_transform(Handle ht, uint flags);
|
||||
|
||||
#endif // #ifndef OGL_TEX_H__
|
||||
|
@ -163,7 +163,16 @@ static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
|
||||
if (ht <= 0)
|
||||
return (int)ht;
|
||||
|
||||
ogl_tex_upload(ht, GL_NEAREST, GL_ALPHA8, GL_ALPHA);
|
||||
// the GL format is chosen as LUMINANCE, but we want ALPHA.
|
||||
/*/*
|
||||
There doesn't seem to be much difference between ALPHA4 and ALPHA8.
|
||||
I can't notice an increase/decrease in visual quality when quantising to 4-bit values,
|
||||
and it's more space-efficient; but it'd need run-time conversion or 4-bit TGAs,
|
||||
and the memory difference is probably insignificant [assuming only active fonts are cached,
|
||||
and it doesn't keep in memory every font that's ever been displayed], so it's probably easiest to just use ALPHA8 always.
|
||||
*/
|
||||
(void)ogl_tex_set_filter(ht, GL_NEAREST);
|
||||
ogl_tex_upload(ht, 0, GL_ALPHA8, GL_ALPHA);
|
||||
|
||||
f->ht = ht;
|
||||
|
||||
|
@ -112,12 +112,19 @@ extern int clipboard_free(wchar_t* copy);
|
||||
|
||||
// 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.
|
||||
// creates a cursor from the given 32 bpp texture (described by tex.h flags).
|
||||
// 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 sys_cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
void** cursor);
|
||||
extern int sys_cursor_create(uint w, uint h, uint flags, void* img,
|
||||
uint hx, uint hy, void** cursor);
|
||||
|
||||
// creates a cursor from the given texture file.
|
||||
// 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 sys_cursor_load(const char* filename,
|
||||
uint hx, uint 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.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "lib.h"
|
||||
#include "posix.h"
|
||||
#include "error_dialog.h"
|
||||
#include "lib/res/graphics/tex.h"
|
||||
|
||||
#if MSC_VERSION
|
||||
#pragma comment(lib, "shell32.lib") // for pick_directory SH* calls
|
||||
@ -547,39 +548,29 @@ static HCURSOR HCURSOR_from_ptr(void* p)
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
// creates a cursor from the given texture file.
|
||||
// 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.
|
||||
int sys_cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
void** cursor)
|
||||
int sys_cursor_load(const char* filename,
|
||||
uint hx, uint hy, void** cursor)
|
||||
{
|
||||
*cursor = 0;
|
||||
Tex t;
|
||||
RETURN_ERR(tex_load(filename, &t));
|
||||
uint w = t.w, h = t.h;
|
||||
|
||||
// convert to BGRA (required by BMP).
|
||||
// don't do this in-place so we don't spoil someone else's
|
||||
// use of the texture (however unlikely that may be).
|
||||
void* img_bgra = malloc(w*h*4);
|
||||
if(!img_bgra)
|
||||
return ERR_NO_MEM;
|
||||
const u8* src = (const u8*)img;
|
||||
u8* dst = (u8*)img_bgra;
|
||||
for(int i = 0; i < w*h; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
img = img_bgra;
|
||||
// convert to BGRA (required by CreateBitmap).
|
||||
const uint transforms = (t.flags & TEX_BGR) ^ TEX_BGR;
|
||||
RETURN_ERR(tex_transform(&t, transforms));
|
||||
void* tex_bgra = tex_get_data(&t);
|
||||
|
||||
// MSDN says selecting this HBITMAP into a DC is slower since we use
|
||||
// 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 hbmColour = CreateBitmap(w, h, 1, 32, img_bgra);
|
||||
HBITMAP hbmColour = CreateBitmap(w, h, 1, 32, tex_bgra);
|
||||
|
||||
free(img_bgra);
|
||||
tex_free(&t);
|
||||
|
||||
// CreateIconIndirect doesn't access it; we just need to pass
|
||||
// an empty bitmap.
|
||||
@ -607,6 +598,7 @@ int sys_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 sys_cursor_set(void* cursor)
|
||||
|
@ -592,6 +592,65 @@ static void InitSDL()
|
||||
}
|
||||
|
||||
|
||||
static const uint SANE_TEX_QUALITY_DEFAULT = 5; // keep in sync with code
|
||||
|
||||
static void SetTextureQuality(uint quality)
|
||||
{
|
||||
uint q_flags;
|
||||
GLint filter;
|
||||
|
||||
retry:
|
||||
// keep this in sync with SANE_TEX_QUALITY_DEFAULT
|
||||
switch(quality)
|
||||
{
|
||||
// worst quality
|
||||
case 0:
|
||||
q_flags = OGL_TEX_HALF_RES|OGL_TEX_HALF_BPP;
|
||||
filter = GL_NEAREST;
|
||||
break;
|
||||
// [perf] add bilinear filtering
|
||||
case 1:
|
||||
q_flags = OGL_TEX_HALF_RES|OGL_TEX_HALF_BPP;
|
||||
filter = GL_LINEAR;
|
||||
break;
|
||||
// [vmem] no longer reduce resolution
|
||||
case 2:
|
||||
q_flags = OGL_TEX_HALF_BPP;
|
||||
filter = GL_LINEAR;
|
||||
break;
|
||||
// [vmem] add mipmaps
|
||||
case 3:
|
||||
q_flags = OGL_TEX_HALF_BPP;
|
||||
filter = GL_NEAREST_MIPMAP_LINEAR;
|
||||
break;
|
||||
// [perf] better filtering
|
||||
case 4:
|
||||
q_flags = OGL_TEX_HALF_BPP;
|
||||
filter = GL_LINEAR_MIPMAP_LINEAR;
|
||||
break;
|
||||
// [vmem] no longer reduce bpp
|
||||
case SANE_TEX_QUALITY_DEFAULT:
|
||||
q_flags = OGL_TEX_FULL_QUALITY;
|
||||
filter = GL_LINEAR_MIPMAP_LINEAR;
|
||||
break;
|
||||
// [perf] add anisotropy
|
||||
case 6:
|
||||
// TODO: add anisotropic filtering
|
||||
q_flags = OGL_TEX_FULL_QUALITY;
|
||||
filter = GL_LINEAR_MIPMAP_LINEAR;
|
||||
break;
|
||||
// invalid
|
||||
default:
|
||||
debug_warn("SetTextureQuality: invalid quality");
|
||||
quality = SANE_TEX_QUALITY_DEFAULT;
|
||||
// careful: recursion doesn't work and we don't want to duplicate
|
||||
// the "sane" default values.
|
||||
goto retry;
|
||||
}
|
||||
|
||||
ogl_tex_set_defaults(q_flags, filter);
|
||||
}
|
||||
|
||||
|
||||
void EndGame()
|
||||
{
|
||||
@ -793,14 +852,17 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
|
||||
|
||||
if (setup_gfx)
|
||||
{
|
||||
MICROLOG(L"set vmode");
|
||||
SDL_WM_SetCaption("0 A.D.", "0 A.D.");
|
||||
|
||||
MICROLOG(L"SetVideoMode");
|
||||
if(SetVideoMode(g_xres, g_yres, 32, !windowed) < 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "Could not set %dx%d graphics mode: %s", g_xres, g_yres, SDL_GetError());
|
||||
throw PSERROR_System_VmodeFailed();
|
||||
}
|
||||
SDL_WM_SetCaption("0 A.D.", "0 A.D.");
|
||||
|
||||
uint quality = SANE_TEX_QUALITY_DEFAULT; // TODO: set value from config file
|
||||
SetTextureQuality(quality);
|
||||
}
|
||||
|
||||
oglCheck();
|
||||
|
@ -42,15 +42,6 @@
|
||||
|
||||
#define LOG_CATEGORY "graphics"
|
||||
|
||||
/*
|
||||
// jw: unused
|
||||
static bool saveTGA(const char* filename,int width,int height,int bpp,unsigned char* data)
|
||||
{
|
||||
int err = tex_write(filename, width, height, bpp, TEX_BGR, data);
|
||||
return (err == 0);
|
||||
}
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// CRenderer destructor
|
||||
CRenderer::CRenderer()
|
||||
@ -86,7 +77,7 @@ CRenderer::CRenderer()
|
||||
m_SWaterScrollCounter=0;
|
||||
m_TWaterScrollCounter=0;
|
||||
m_WaterCurrentTex=0;
|
||||
|
||||
|
||||
for (int x=0; x<60; x++)
|
||||
{
|
||||
char waterName[1000];
|
||||
@ -98,22 +89,7 @@ CRenderer::CRenderer()
|
||||
ogl_tex_free(m_WaterTexture[x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int tw=0,th=0;
|
||||
(void)ogl_tex_get_size(m_WaterTexture[x], &tw, &th, 0);
|
||||
if(!is_pow2(tw) || !is_pow2(th))
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\" : not a power of 2 texture",waterName);
|
||||
ogl_tex_free(m_WaterTexture[x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ogl_tex_bind(m_WaterTexture[x]);
|
||||
ogl_tex_upload(m_WaterTexture[x], GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
}
|
||||
}
|
||||
ogl_tex_upload(m_WaterTexture[x]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1194,40 +1170,38 @@ bool CRenderer::LoadTexture(CTexture* texture,u32 wrapflags)
|
||||
const Handle errorhandle = -1;
|
||||
|
||||
Handle h=texture->GetHandle();
|
||||
if (h) {
|
||||
// already tried to load this texture, nothing to do here - just return success according
|
||||
// to whether this is a valid handle or not
|
||||
// already tried to load this texture
|
||||
if (h)
|
||||
{
|
||||
// nothing to do here - just return success according to
|
||||
// whether this is a valid handle or not
|
||||
return h==errorhandle ? true : false;
|
||||
} else {
|
||||
h=ogl_tex_load(texture->GetName());
|
||||
if (h <= 0) {
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\"",(const char*) texture->GetName());
|
||||
texture->SetHandle(errorhandle);
|
||||
return false;
|
||||
} else {
|
||||
int tw=0,th=0;
|
||||
(void)ogl_tex_get_size(h, &tw, &th, 0);
|
||||
if(!is_pow2(tw) || !is_pow2(th)) {
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\" : not a power of 2 texture",(const char*) texture->GetName());
|
||||
ogl_tex_free(h);
|
||||
texture->SetHandle(errorhandle);
|
||||
return false;
|
||||
} else {
|
||||
ogl_tex_bind(h);
|
||||
ogl_tex_upload(h,GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
if (wrapflags) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapflags);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapflags);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
texture->SetHandle(h);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h=ogl_tex_load(texture->GetName());
|
||||
if (h <= 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\"",(const char*) texture->GetName());
|
||||
texture->SetHandle(errorhandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!wrapflags)
|
||||
wrapflags = GL_CLAMP_TO_EDGE;
|
||||
(void)ogl_tex_set_wrap(h, wrapflags);
|
||||
(void)ogl_tex_set_filter(h, GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
// (this also verifies that the texture is a power-of-two)
|
||||
if(ogl_tex_upload(h) < 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\" : upload failed",(const char*) texture->GetName());
|
||||
ogl_tex_free(h);
|
||||
texture->SetHandle(errorhandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
texture->SetHandle(h);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1277,7 +1251,7 @@ bool CRenderer::IsTextureTransparent(CTexture* texture)
|
||||
if (!texture) return false;
|
||||
Handle h=texture->GetHandle();
|
||||
|
||||
int flags = 0; // assume no alpha on failure
|
||||
uint flags = 0; // assume no alpha on failure
|
||||
(void)ogl_tex_get_format(h, &flags, 0);
|
||||
return (flags & TEX_ALPHA) != 0;
|
||||
}
|
||||
@ -1319,11 +1293,11 @@ int CRenderer::LoadAlphaMaps()
|
||||
"blendushape.png",
|
||||
"blendbad.png"
|
||||
};
|
||||
int base = 0; // texture width/height (see below)
|
||||
uint base = 0; // texture width/height (see below)
|
||||
// for convenience, we require all alpha maps to be of the same BPP
|
||||
// (avoids another ogl_tex_get_size call, and doesn't hurt)
|
||||
int bpp = 0;
|
||||
for(int i=0;i<NumAlphaMaps;i++)
|
||||
uint bpp = 0;
|
||||
for(uint i=0;i<NumAlphaMaps;i++)
|
||||
{
|
||||
(void)pp_append_file(&pp, fnames[i]);
|
||||
textures[i] = ogl_tex_load(pp.path);
|
||||
@ -1331,7 +1305,7 @@ int CRenderer::LoadAlphaMaps()
|
||||
|
||||
// get its size and make sure they are all equal.
|
||||
// (the packing algo assumes this)
|
||||
int this_width = 0, this_bpp = 0; // fail-safe
|
||||
uint this_width = 0, this_bpp = 0; // fail-safe
|
||||
(void)ogl_tex_get_size(textures[i], &this_width, 0, &this_bpp);
|
||||
// .. first iteration: establish size
|
||||
if(i == 0)
|
||||
@ -1347,24 +1321,24 @@ int CRenderer::LoadAlphaMaps()
|
||||
//
|
||||
// copy each alpha map (tile) into one buffer, arrayed horizontally.
|
||||
//
|
||||
int tile_w = 2+base+2; // 2 pixel border (avoids bilinear filtering artifacts)
|
||||
int total_w = RoundUpToPowerOf2(tile_w * NumAlphaMaps);
|
||||
int total_h = base; debug_assert(is_pow2(total_h));
|
||||
uint tile_w = 2+base+2; // 2 pixel border (avoids bilinear filtering artifacts)
|
||||
uint total_w = RoundUpToPowerOf2(tile_w * NumAlphaMaps);
|
||||
uint total_h = base; debug_assert(is_pow2(total_h));
|
||||
u8* data=new u8[total_w*total_h*3];
|
||||
// for each tile on row
|
||||
for(int i=0;i<NumAlphaMaps;i++)
|
||||
for(uint i=0;i<NumAlphaMaps;i++)
|
||||
{
|
||||
// get src of copy
|
||||
const u8* src = 0;
|
||||
(void)ogl_tex_get_data(textures[i], (void**)&src);
|
||||
|
||||
int srcstep=bpp/8;
|
||||
uint srcstep=bpp/8;
|
||||
|
||||
// get destination of copy
|
||||
u8* dst=data+3*(i*tile_w);
|
||||
|
||||
// for each row of image
|
||||
for (int j=0;j<base;j++) {
|
||||
for (uint j=0;j<base;j++) {
|
||||
// duplicate first pixel
|
||||
CopyTriple(dst,src);
|
||||
dst+=3;
|
||||
@ -1372,7 +1346,7 @@ int CRenderer::LoadAlphaMaps()
|
||||
dst+=3;
|
||||
|
||||
// copy a row
|
||||
for (int k=0;k<base;k++) {
|
||||
for (uint k=0;k<base;k++) {
|
||||
CopyTriple(dst,src);
|
||||
dst+=3;
|
||||
src+=srcstep;
|
||||
@ -1393,17 +1367,16 @@ int CRenderer::LoadAlphaMaps()
|
||||
m_AlphaMapCoords[i].v1=1.0f;
|
||||
}
|
||||
|
||||
for (int i=0;i<NumAlphaMaps;i++)
|
||||
for (uint i=0;i<NumAlphaMaps;i++)
|
||||
ogl_tex_free(textures[i]);
|
||||
|
||||
// upload the composite texture
|
||||
Tex t;
|
||||
(void)tex_wrap(total_w, total_h, 24, 0, data, &t);
|
||||
m_hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)");
|
||||
(void)ogl_tex_upload(m_hCompositeAlphaMap, GL_LINEAR, GL_INTENSITY);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
|
||||
oglSquelchError(GL_INVALID_ENUM); // GL_CLAMP_TO_EDGE
|
||||
(void)ogl_tex_set_filter(m_hCompositeAlphaMap, GL_LINEAR);
|
||||
(void)ogl_tex_set_wrap (m_hCompositeAlphaMap, GL_CLAMP_TO_EDGE);
|
||||
(void)ogl_tex_upload(m_hCompositeAlphaMap, 0, GL_INTENSITY);
|
||||
delete[] data;
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user