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;
|
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;
|
||||||
|
|
||||||
|
@ -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
@ -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__
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user