diff --git a/src/gc_gl.c b/src/gc_gl.c index d339fff..4413c40 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -195,11 +195,28 @@ int ogx_prepare_swap_buffers() return glparamstate.render_mode == GL_RENDER ? 0 : -1; } +static int parse_hints() +{ + OgxHints hints = OGX_HINT_NONE; + + /* comma separated list of operations for which a faster (but inaccurate) + * implementation is to be preferred over a more standard-compliant one. + * By default, we always prefer standard-compliance over speed. */ + const char *env = getenv("OPENGX_FAST_OPS"); + if (env) { + if (strstr(env, "sphere_map") != NULL) + hints |= OGX_HINT_FAST_SPHERE_MAP; + } + + glparamstate.hints = hints; +} + void ogx_initialize() { _ogx_log_init(); _ogx_gpu_resources_init(); + parse_hints(); glparamstate.current_call_list.index = -1; GX_SetDispCopyGamma(GX_GM_1_0); diff --git a/src/state.h b/src/state.h index 0b7f70b..180533b 100644 --- a/src/state.h +++ b/src/state.h @@ -63,6 +63,12 @@ extern "C" { * opengx when stencil is enabled. */ #define MAX_TEXTURE_UNITS 4 +typedef enum { + OGX_HINT_NONE = 0, + /* Enables fast (but wrong) GPU-accelerated GL_SPHERE_MAP */ + OGX_HINT_FAST_SPHERE_MAP = 1 << 0, +} OgxHints; + typedef struct { Pos3f pos; Norm3f norm; @@ -131,6 +137,8 @@ typedef struct glparams_ int viewport[4]; + OgxHints hints; + unsigned char srcblend, dstblend; unsigned char blendenabled; unsigned char zwrite, ztest, zfunc; diff --git a/src/texture_gen_sw.c b/src/texture_gen_sw.c index ee0846b..609f115 100644 --- a/src/texture_gen_sw.c +++ b/src/texture_gen_sw.c @@ -37,11 +37,35 @@ POSSIBILITY OF SUCH DAMAGE. bool _ogx_texture_gen_sw_enabled(uint8_t unit) { const OgxTextureUnit *tu = &glparamstate.texture_unit[unit]; + OgxHints hint = OGX_HINT_NONE; + bool needs_normals = false; - if (tu->gen_mode != GL_SPHERE_MAP) return false; + switch (tu->gen_mode) { + case GL_SPHERE_MAP: + hint = OGX_HINT_FAST_SPHERE_MAP; + needs_normals = true; + break; + case GL_REFLECTION_MAP: + /* We don't support a standard-compiant generation of the reflection + * map yet, because its output should consist of three float + * components, whereas the TEV only supports two components for + * GX_VA_TEX*. One way to implement it would be to (ab)use the + * GX_VA_NBT format: storing the computed texture generated coordinates + * into the binormal part of the array, and then use them in the TEV as + * GX_TG_BINRM. + * But this requires yet one more refactoring of the array classes, to + * let the normals array switch between GX_VA_NRM and GX_VA_NBT + * depending on whether GL_REFLECTION_MAP is enabled. Let's leave this + * as a TODO. + */ + default: + return false; + } - /* We need normal coordinates to be there */ - if (!glparamstate.cs.normal_enabled) return false; + /* If the client prefers the inaccurate GPU implementation, let it be */ + if (hint != OGX_HINT_NONE && (glparamstate.hints & hint)) return false; + + if (needs_normals && !glparamstate.cs.normal_enabled) return false; return true; }