1
1
forked from 0ad/0ad

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:
janwas 2005-09-29 05:00:20 +00:00
parent 14df805761
commit cd2f3948dd
9 changed files with 809 additions and 476 deletions

View File

@ -389,7 +389,9 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, CStr &SpriteName, CRect
return; 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) if (err < 0)
{ {
LOG(ERROR, LOG_CATEGORY, "Error uploading texture '%s': %d", (const char*)cit->m_TextureName, err); 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; 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); (void)ogl_tex_get_size(h, &t_w, &t_h, 0);
float TexWidth = t_w, TexHeight = t_h; 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); (void)ogl_tex_get_format(h, &flags, 0);
Call.m_EnableBlending = (flags & TEX_ALPHA) != 0; Call.m_EnableBlending = (flags & TEX_ALPHA) != 0;

View File

@ -6,7 +6,7 @@
// On Windows, allow runtime choice between system cursors and OpenGL // On Windows, allow runtime choice between system cursors and OpenGL
// cursors (Windows = more responsive, OpenGL = more consistent with what // cursors (Windows = more responsive, OpenGL = more consistent with what
// the game sees) // the game sees)
#define USE_WINDOWS_CURSOR 1 #define ALLOW_SYS_CURSOR 1
#include "lib/ogl.h" #include "lib/ogl.h"
#include "sysdep/sysdep.h" // sys_cursor_* #include "sysdep/sysdep.h" // sys_cursor_*
@ -19,27 +19,32 @@
class GLCursor class GLCursor
{ {
Handle ht; Handle ht;
int w, h; uint w, h;
int hotspotx, hotspoty; uint hotspotx, hotspoty;
public: public:
void create(Handle ht_, int w_, int h_, int hotspotx_, int hotspoty_) int create(const char* filename, uint hotspotx_, uint hotspoty_)
{ {
ht = ht_; ht = ogl_tex_load(filename);
w = w_; h = h_; RETURN_ERR(ht);
(void)ogl_tex_get_size(ht, &w, &h, 0);
hotspotx = hotspotx_; hotspoty = hotspoty_; 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() 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); glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -85,46 +90,28 @@ static int Cursor_reload(Cursor* c, const char* name, Handle)
{ {
char filename[VFS_MAX_PATH]; char filename[VFS_MAX_PATH];
// Load the .txt file containing the pixel offset of the cursor's // read pixel offset of the cursor's hotspot [the bit of it that's
// hotspot (the bit of it that's drawn at (g_mouse_x,g_mouse_y) ) // drawn at (g_mouse_x,g_mouse_y)] from file.
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.txt", name); uint hotspotx = 0, hotspoty = 0;
int hotspotx = 0, hotspoty = 0;
{ {
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.txt", name);
void* p; size_t size; void* p; size_t size;
Handle hm = vfs_load(filename, p, size); Handle hm = vfs_load(filename, p, size);
WARN_ERR(hm); RETURN_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)); (void)mem_free_h(hm);
s >> hotspotx >> hotspoty;
WARN_ERR(mem_free_h(hm));
}
} }
// load actual cursor
snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.png", name); snprintf(filename, ARRAY_SIZE(filename), "art/textures/cursors/%s.png", name);
Handle ht = ogl_tex_load(filename); // .. system cursor (2d, hardware accelerated)
RETURN_ERR(ht); #if ALLOW_SYS_CURSOR
WARN_ERR(sys_cursor_load(filename, hotspotx, hotspoty, &c->sys_cursor));
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));
#endif #endif
// .. fall back to GLCursor (system cursor code is disabled or failed)
// if the system cursor code is disabled or failed, fall back to GLCursor.
if(!c->sys_cursor) if(!c->sys_cursor)
c->gl_cursor.create(ht, w, h, hotspotx, hotspoty); RETURN_ERR(c->gl_cursor.create(filename, hotspotx, hotspoty));
return 0; return 0;
} }
@ -160,7 +147,7 @@ int cursor_draw(const char* name, int x, int y)
} }
Handle hc = cursor_load(name); Handle hc = cursor_load(name);
RETURN_ERR(hc); CHECK_ERR(hc);
H_DEREF(hc, Cursor, c); H_DEREF(hc, Cursor, c);
if(c->sys_cursor) if(c->sys_cursor)

File diff suppressed because it is too large Load Diff

View File

@ -32,15 +32,21 @@ It basically wraps tex.cpp's texture info in a resource object
reference counting, caching, hotloading and safe access. reference counting, caching, hotloading and safe access.
Caching and Texture Instances Texture Parameters
----------------------------- ------------------
Caching is both an advantage and drawback. When opening the same OpenGL textures are conditioned on several parameters including
texture twice without previously freeing it, a reference to the filter and wrap mode. These are typically set once when the texture is
first instance is returned. Therefore, be advised that concurrent use of the created, but must survive reloads (1). To that end, all state (2) is
same texture but with differing parameters (e.g. upload quality) followed by set via ogl_tex_set_* (instead of direct glTexParameter calls) and
a reload of the first instance will result in using the wrong parameters. re-applied after a reload.
For background and rationale why this is acceptable, see struct OglTex.
(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 Uploading to OpenGL
@ -51,15 +57,27 @@ Uploading to OpenGL
texture parameters and data from system memory to OpenGL texture parameters and data from system memory to OpenGL
(and thereby usually video memory). (and thereby usually video memory).
In so doing, choices are made as to filtering algorithm and the In so doing, choices are made as to the texture's internal representation
texture's internal representation (how it is stored in vmem) - (how it is stored in vmem) - in particular, the bit depth.
in particular, the bit depth. This can trade performance This can trade performance (more/less data to copy) for quality
(more/less data to copy) for quality (fidelity to original). (fidelity to original).
We provide a mechanism that applies defaults to all uploads unless We provide a mechanism that applies defaults to all uploads;
overrides are specified (for individual ogl_tex_upload calls). this allows a global "quality" setting that can boost performance on
This allows a global "quality" setting that can boost performance on
older graphics cards without requiring anything else to be changed. 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 Example Usage
@ -84,14 +102,15 @@ Handle hTexture = ogl_tex_load("filename.dds");
(void)ogl_tex_free(hTexture); (void)ogl_tex_free(hTexture);
2) Advanced usage: wrap existing texture data and specify 2) Advanced usage: wrap existing texture data, override filter,
filter/internal_format overrides. specify internal_format and use multitexturing.
Tex t; Tex t;
const uint flags = 0; // image is plain RGB, default orientation const uint flags = 0; // image is plain RGB, default orientation
void* data = [pre-existing image] void* data = [pre-existing image]
(void)tex_wrap(w, h, 24, flags, data, &t); (void)tex_wrap(w, h, 24, flags, data, &t);
Handle hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)"); 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 // (your responsibility! tex_wrap attaches a reference but it is
// removed by ogl_tex_upload.) // removed by ogl_tex_upload.)
free(data); free(data);
@ -114,13 +133,52 @@ free(data);
#include "lib/ogl.h" #include "lib/ogl.h"
#include "tex.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>. // load and return a handle to the texture given in <fn>.
// for a list of supported formats, see tex.h's tex_load. // 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); 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). // set texture parameters
// side effects: //
// - enables texturing on TMU 0 and binds the texture to it;
// - frees the texel data! see ogl_tex_get_data. // these must be called before uploading; this simplifies
extern int ogl_tex_upload(Handle ht, GLint filter_override = 0, GLint internal_fmt_override = 0, GLenum format_override = 0); // 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 // bind the texture to the specified unit [number] in preparation for
// using it in rendering. assumes multitexturing is available. // using it in rendering. assumes multitexturing is available.
// not necessary before calling ogl_tex_upload!
// side effects: // side effects:
// - enables (or disables, if <ht> == 0) texturing on the given unit. // - enables (or disables, if <ht> == 0) texturing on the given unit.
extern int ogl_tex_bind(Handle ht, GLenum unit = 0); 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. // retrieve texture dimensions and bits per pixel.
// all params are optional and filled if non-NULL. // 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. // 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. // 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. // 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). // uploading it or read directly from OpenGL (discouraged).
extern int ogl_tex_get_data(Handle ht, void** p); 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__ #endif // #ifndef OGL_TEX_H__

View File

@ -163,7 +163,16 @@ static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
if (ht <= 0) if (ht <= 0)
return (int)ht; 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; f->ht = ht;

View File

@ -112,12 +112,19 @@ extern int clipboard_free(wchar_t* copy);
// note: these do not warn on error; that is left to the caller. // 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 // creates a cursor from the given 32 bpp texture (described by tex.h flags).
// the offset from its upper-left corner to the position where mouse clicks // hotspot (hx,hy) is the offset from its upper-left corner to the
// are registered. // position where mouse clicks are registered.
// the cursor must be cursor_free-ed when no longer needed. // 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, extern int sys_cursor_create(uint w, uint h, uint flags, void* img,
void** cursor); 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 // replaces the current system cursor with the one indicated. need only be
// called once per cursor; pass 0 to restore the default. // called once per cursor; pass 0 to restore the default.

View File

@ -26,6 +26,7 @@
#include "lib.h" #include "lib.h"
#include "posix.h" #include "posix.h"
#include "error_dialog.h" #include "error_dialog.h"
#include "lib/res/graphics/tex.h"
#if MSC_VERSION #if MSC_VERSION
#pragma comment(lib, "shell32.lib") // for pick_directory SH* calls #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 // creates a cursor from the given texture file.
// the offset from its upper-left corner to the position where mouse clicks // hotspot (hx,hy) is the offset from its upper-left corner to the
// are registered. // position where mouse clicks are registered.
// the cursor must be cursor_free-ed when no longer needed. // 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, int sys_cursor_load(const char* filename,
void** cursor) 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). // convert to BGRA (required by CreateBitmap).
// don't do this in-place so we don't spoil someone else's const uint transforms = (t.flags & TEX_BGR) ^ TEX_BGR;
// use of the texture (however unlikely that may be). RETURN_ERR(tex_transform(&t, transforms));
void* img_bgra = malloc(w*h*4); void* tex_bgra = tex_get_data(&t);
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;
// MSDN says selecting this HBITMAP into a DC is slower since we use // MSDN says selecting this HBITMAP into a DC is slower since we use
// CreateBitmap; bpp/format must be checked against those of the DC. // CreateBitmap; bpp/format must be checked against those of the DC.
// this is the simplest way and we don't care about slight performance // this is the simplest way and we don't care about slight performance
// differences because this is typically only called once. // 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 // CreateIconIndirect doesn't access it; we just need to pass
// an empty bitmap. // 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 // replaces the current system cursor with the one indicated. need only be
// called once per cursor; pass 0 to restore the default. // called once per cursor; pass 0 to restore the default.
int sys_cursor_set(void* cursor) int sys_cursor_set(void* cursor)

View File

@ -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() void EndGame()
{ {
@ -793,14 +852,17 @@ void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
if (setup_gfx) 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) 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()); LOG(ERROR, LOG_CATEGORY, "Could not set %dx%d graphics mode: %s", g_xres, g_yres, SDL_GetError());
throw PSERROR_System_VmodeFailed(); 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(); oglCheck();

View File

@ -42,15 +42,6 @@
#define LOG_CATEGORY "graphics" #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 destructor
CRenderer::CRenderer() CRenderer::CRenderer()
@ -86,7 +77,7 @@ CRenderer::CRenderer()
m_SWaterScrollCounter=0; m_SWaterScrollCounter=0;
m_TWaterScrollCounter=0; m_TWaterScrollCounter=0;
m_WaterCurrentTex=0; m_WaterCurrentTex=0;
for (int x=0; x<60; x++) for (int x=0; x<60; x++)
{ {
char waterName[1000]; char waterName[1000];
@ -98,22 +89,7 @@ CRenderer::CRenderer()
ogl_tex_free(m_WaterTexture[x]); ogl_tex_free(m_WaterTexture[x]);
} }
else else
{ ogl_tex_upload(m_WaterTexture[x]);
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);
}
}
} }
} }
@ -1194,40 +1170,38 @@ bool CRenderer::LoadTexture(CTexture* texture,u32 wrapflags)
const Handle errorhandle = -1; const Handle errorhandle = -1;
Handle h=texture->GetHandle(); Handle h=texture->GetHandle();
if (h) { // already tried to load this texture
// already tried to load this texture, nothing to do here - just return success according if (h)
// to whether this is a valid handle or not {
// nothing to do here - just return success according to
// whether this is a valid handle or not
return h==errorhandle ? true : false; 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; if (!texture) return false;
Handle h=texture->GetHandle(); 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); (void)ogl_tex_get_format(h, &flags, 0);
return (flags & TEX_ALPHA) != 0; return (flags & TEX_ALPHA) != 0;
} }
@ -1319,11 +1293,11 @@ int CRenderer::LoadAlphaMaps()
"blendushape.png", "blendushape.png",
"blendbad.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 // for convenience, we require all alpha maps to be of the same BPP
// (avoids another ogl_tex_get_size call, and doesn't hurt) // (avoids another ogl_tex_get_size call, and doesn't hurt)
int bpp = 0; uint bpp = 0;
for(int i=0;i<NumAlphaMaps;i++) for(uint i=0;i<NumAlphaMaps;i++)
{ {
(void)pp_append_file(&pp, fnames[i]); (void)pp_append_file(&pp, fnames[i]);
textures[i] = ogl_tex_load(pp.path); textures[i] = ogl_tex_load(pp.path);
@ -1331,7 +1305,7 @@ int CRenderer::LoadAlphaMaps()
// get its size and make sure they are all equal. // get its size and make sure they are all equal.
// (the packing algo assumes this) // (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); (void)ogl_tex_get_size(textures[i], &this_width, 0, &this_bpp);
// .. first iteration: establish size // .. first iteration: establish size
if(i == 0) if(i == 0)
@ -1347,24 +1321,24 @@ int CRenderer::LoadAlphaMaps()
// //
// copy each alpha map (tile) into one buffer, arrayed horizontally. // copy each alpha map (tile) into one buffer, arrayed horizontally.
// //
int tile_w = 2+base+2; // 2 pixel border (avoids bilinear filtering artifacts) uint tile_w = 2+base+2; // 2 pixel border (avoids bilinear filtering artifacts)
int total_w = RoundUpToPowerOf2(tile_w * NumAlphaMaps); uint total_w = RoundUpToPowerOf2(tile_w * NumAlphaMaps);
int total_h = base; debug_assert(is_pow2(total_h)); uint total_h = base; debug_assert(is_pow2(total_h));
u8* data=new u8[total_w*total_h*3]; u8* data=new u8[total_w*total_h*3];
// for each tile on row // for each tile on row
for(int i=0;i<NumAlphaMaps;i++) for(uint i=0;i<NumAlphaMaps;i++)
{ {
// get src of copy // get src of copy
const u8* src = 0; const u8* src = 0;
(void)ogl_tex_get_data(textures[i], (void**)&src); (void)ogl_tex_get_data(textures[i], (void**)&src);
int srcstep=bpp/8; uint srcstep=bpp/8;
// get destination of copy // get destination of copy
u8* dst=data+3*(i*tile_w); u8* dst=data+3*(i*tile_w);
// for each row of image // for each row of image
for (int j=0;j<base;j++) { for (uint j=0;j<base;j++) {
// duplicate first pixel // duplicate first pixel
CopyTriple(dst,src); CopyTriple(dst,src);
dst+=3; dst+=3;
@ -1372,7 +1346,7 @@ int CRenderer::LoadAlphaMaps()
dst+=3; dst+=3;
// copy a row // copy a row
for (int k=0;k<base;k++) { for (uint k=0;k<base;k++) {
CopyTriple(dst,src); CopyTriple(dst,src);
dst+=3; dst+=3;
src+=srcstep; src+=srcstep;
@ -1393,17 +1367,16 @@ int CRenderer::LoadAlphaMaps()
m_AlphaMapCoords[i].v1=1.0f; 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]); ogl_tex_free(textures[i]);
// upload the composite texture // upload the composite texture
Tex t; Tex t;
(void)tex_wrap(total_w, total_h, 24, 0, data, &t); (void)tex_wrap(total_w, total_h, 24, 0, data, &t);
m_hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)"); m_hCompositeAlphaMap = ogl_tex_wrap(&t, "(alpha map composite)");
(void)ogl_tex_upload(m_hCompositeAlphaMap, GL_LINEAR, GL_INTENSITY); (void)ogl_tex_set_filter(m_hCompositeAlphaMap, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); (void)ogl_tex_set_wrap (m_hCompositeAlphaMap, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); (void)ogl_tex_upload(m_hCompositeAlphaMap, 0, GL_INTENSITY);
oglSquelchError(GL_INVALID_ENUM); // GL_CLAMP_TO_EDGE
delete[] data; delete[] data;
return 0; return 0;