- Add ability to build MojoShader as a shared library
- Off by default, turn on BUILD_SHARED in CMake
- Add ability to disable shader profiles from CMake
- Add MOJOSHADER_glSetVertexAttribDivisor
- Behaves like glSetVertexAttribute, but for glVertexAttribDivisor
- Add MOJOSHADER_glGetVertexAttribLocation
- Allows user to directly call glVertexAttribPointer in their program
- Full Effect framework support
- API is in a separate header, see mojoshader_effects.h for details
- Off by default, turn on EFFECT_SUPPORT in CMake
- #define MOJOSHADER_EFFECT_SUPPORT before including mojoshader.h
- Add MOJOSHADER_PROFILE_GLSLES shader profile
- Basically just GLSL120 without using builtins
- Add ability to flip gl_Position via MOJOSHADER_glProgramViewportFlip
- You probably shouldn't use this unless you're a project like FNA.
- Off by default, turn on FLIP_VIEWPORT in CMake
- #define MOJOSHADER_FLIP_RENDERTARGET before including mojoshader.h
- Add ability to adjust Z coordinates for [0, 1]-like depth clipping
- You probably shouldn't use this unless you're a project like FNA.
- Off by default, turn on DEPTH_CLIPPING in CMake
- Add ability to build MojoShader with XNA4 vertex texturing behavior
- You probably shouldn't use this unless you're reimplementing XNA.
- Off by default, turn on XNA4_VERTEXTEXTURE in CMake
- Add DECLSPEC/MOJOSHADERCALL to functions/function pointers
- This allows for easier interop with other languages, i.e. C# P/Invoke
- Fix printing float values for locales where radix is not '.'
- Various minor bugfixes, optimizations, Win32 buildfixes, etc.
--- a/CMakeLists.txt Tue Oct 13 12:08:55 2015 -0400
+++ b/CMakeLists.txt Fri Jan 01 02:12:19 2016 -0500
@@ -1,6 +1,18 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(MojoShader)
+OPTION(BUILD_SHARED "Build MojoShader as a shared library" OFF)
+OPTION(PROFILE_D3D "Build MojoShader with support for the D3D profile" ON)
+OPTION(PROFILE_BYTECODE "Build MojoShader with support for the BYTECODE profile" ON)
+OPTION(PROFILE_GLSL120 "Build MojoShader with support for the GLSL120 profile" ON)
+OPTION(PROFILE_GLSL "Build MojoShader with support for the GLSL profile" ON)
+OPTION(PROFILE_ARB1 "Build MojoShader with support for the ARB1 profile" ON)
+OPTION(PROFILE_ARB1_NV "Build MojoShader with support for the ARB1_NV profile" ON)
+OPTION(EFFECT_SUPPORT "Build MojoShader with support for Effect framework files" OFF)
+OPTION(FLIP_VIEWPORT "Build MojoShader with the ability to flip the GL viewport" OFF)
+OPTION(DEPTH_CLIPPING "Build MojoShader with the ability to simulate [0, 1] depth clipping" OFF)
+OPTION(XNA4_VERTEXTEXTURE "Build MojoShader with XNA4 vertex texturing behavior" OFF)
+
INCLUDE_DIRECTORIES(.)
FIND_PROGRAM(HG hg DOC "Path to hg command line app: http://www.selenic.com/mercurial/")
@@ -61,7 +73,55 @@
ARGS -q "-T${CMAKE_CURRENT_SOURCE_DIR}/misc/lempar.c" "${CMAKE_CURRENT_SOURCE_DIR}/mojoshader_parser_hlsl.lemon"
)
-ADD_LIBRARY(mojoshader STATIC
+IF(APPLE)
+ find_library(CARBON_FRAMEWORK Carbon) # Stupid Gestalt.
+ENDIF(APPLE)
+
+IF(NOT PROFILE_D3D)
+ ADD_DEFINITIONS(-DSUPPORT_PROFILE_D3D=0)
+ENDIF(NOT PROFILE_D3D)
+IF(NOT PROFILE_BYTECODE)
+ ADD_DEFINITIONS(-DSUPPORT_PROFILE_BYTECODE=0)
+ENDIF(NOT PROFILE_BYTECODE)
+IF(NOT PROFILE_GLSL120)
+ ADD_DEFINITIONS(-DSUPPORT_PROFILE_GLSL120=0)
+ENDIF(NOT PROFILE_GLSL120)
+IF(NOT PROFILE_GLSL)
+ ADD_DEFINITIONS(-DSUPPORT_PROFILE_GLSL=0)
+ENDIF(NOT PROFILE_GLSL)
+IF(NOT PROFILE_ARB1)
+ ADD_DEFINITIONS(-DSUPPORT_PROFILE_ARB1=0)
+ENDIF(NOT PROFILE_ARB1)
+IF(NOT PROFILE_ARB1_NV)
+ ADD_DEFINITIONS(-DSUPPORT_PROFILE_ARB1_NV=0)
+ENDIF(NOT PROFILE_ARB1_NV)
+
+IF(EFFECT_SUPPORT)
+ IF(UNIX)
+ SET(LIBM -lm)
+ ENDIF(UNIX)
+ ADD_DEFINITIONS(-DMOJOSHADER_EFFECT_SUPPORT)
+ENDIF(EFFECT_SUPPORT)
+
+IF(FLIP_VIEWPORT)
+ ADD_DEFINITIONS(-DMOJOSHADER_FLIP_RENDERTARGET)
+ENDIF(FLIP_VIEWPORT)
+
+IF(DEPTH_CLIPPING)
+ ADD_DEFINITIONS(-DMOJOSHADER_DEPTH_CLIPPING)
+ENDIF(DEPTH_CLIPPING)
+
+IF(XNA4_VERTEXTEXTURE)
+ ADD_DEFINITIONS(-DMOJOSHADER_XNA4_VERTEX_TEXTURES)
+ENDIF(XNA4_VERTEXTEXTURE)
+
+IF(BUILD_SHARED)
+ SET(LIBRARY_FORMAT SHARED)
+ELSE(BUILD_SHARED)
+ SET(LIBRARY_FORMAT STATIC)
+ENDIF(BUILD_SHARED)
+
+ADD_LIBRARY(mojoshader ${LIBRARY_FORMAT}
mojoshader.c
mojoshader_common.c
mojoshader_effects.c
@@ -71,10 +131,9 @@
mojoshader_assembler.c
mojoshader_opengl.c
)
-
-IF(UNIX)
- SET(LIBM -lm)
-ENDIF(UNIX)
+IF(BUILD_SHARED)
+ TARGET_LINK_LIBRARIES(mojoshader ${LIBM} ${CARBON_FRAMEWORK})
+ENDIF(BUILD_SHARED)
SET_SOURCE_FILES_PROPERTIES(
mojoshader_compiler.c
@@ -94,10 +153,6 @@
)
ENDIF(NOT RE2C)
-IF(APPLE)
- find_library(CARBON_FRAMEWORK Carbon) # Stupid Gestalt.
-ENDIF(APPLE)
-
find_path(SDL2_INCLUDE_DIR SDL.h PATH_SUFFIXES include/SDL2)
find_library(SDL2 NAMES SDL2 PATH_SUFFIXES lib)
IF(SDL2)
--- a/mojoshader.c Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader.c Fri Jan 01 02:12:19 2016 -0500
@@ -178,6 +178,9 @@
#if SUPPORT_PROFILE_GLSL120
int profile_supports_glsl120;
#endif
+#if SUPPORT_PROFILE_GLSLES
+ int profile_supports_glsles;
+#endif
} Context;
@@ -198,6 +201,12 @@
#define support_glsl120(ctx) (0)
#endif
+#if SUPPORT_PROFILE_GLSLES
+#define support_glsles(ctx) ((ctx)->profile_supports_glsles)
+#else
+#define support_glsles(ctx) (0)
+#endif
+
// Profile entry points...
@@ -300,12 +309,12 @@
ctx->free(ptr, ctx->malloc_data);
} // Free
-static void *MallocBridge(int bytes, void *data)
+static void * MOJOSHADERCALL MallocBridge(int bytes, void *data)
{
return Malloc((Context *) data, (size_t) bytes);
} // MallocBridge
-static void FreeBridge(void *ptr, void *data)
+static void MOJOSHADERCALL FreeBridge(void *ptr, void *data)
{
Free((Context *) data, ptr);
} // FreeBridge
@@ -446,7 +455,7 @@
static void floatstr(Context *ctx, char *buf, size_t bufsize, float f,
int leavedecimal)
{
- const size_t len = snprintf(buf, bufsize, "%f", f);
+ const size_t len = MOJOSHADER_printFloat(buf, bufsize, f);
if ((len+2) >= bufsize)
fail(ctx, "BUG: internal buffer is too small");
else
@@ -2185,6 +2194,24 @@
} // else if
#endif
+ #if SUPPORT_PROFILE_GLSLES
+ else if (strcmp(profilestr, MOJOSHADER_PROFILE_GLSLES) == 0)
+ {
+ ctx->profile_supports_glsles = 1;
+ push_output(ctx, &ctx->preflight);
+ output_line(ctx, "#version 100");
+ if (shader_is_vertex(ctx))
+ output_line(ctx, "precision highp float;");
+ else
+ output_line(ctx, "precision mediump float;");
+ output_line(ctx, "precision mediump int;");
+ output_line(ctx, "varying vec4 v_FrontColor;");
+ output_line(ctx, "varying vec4 v_FrontSecondaryColor;");
+ output_line(ctx, "varying vec4 v_TexCoord[10];"); // 10 according to SM3
+ pop_output(ctx);
+ } // else if
+ #endif
+
else
{
failf(ctx, "Profile '%s' unsupported or unknown.", profilestr);
@@ -2212,6 +2239,15 @@
set_used_register(ctx, REG_TYPE_COLOROUT, 0, 1);
output_line(ctx, "%s_oC0 = %s_r0;", shstr, shstr);
} // if
+ else if (shader_is_vertex(ctx))
+ {
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+ output_line(ctx, "gl_Position.y = gl_Position.y * vpFlip;");
+#endif
+#ifdef MOJOSHADER_DEPTH_CLIPPING
+ output_line(ctx, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;");
+#endif
+ } // else if
// force a RET opcode if we're at the end of the stream without one.
if (ctx->previous_opcode != OPCODE_RET)
@@ -2230,7 +2266,19 @@
{
char buf[64];
get_GLSL_uniform_array_varname(ctx, regtype, buf, sizeof (buf));
- output_line(ctx, "uniform vec4 %s[%d];", buf, size);
+ const char *typ;
+ switch (regtype)
+ {
+ case REG_TYPE_CONST: typ = "vec4"; break;
+ case REG_TYPE_CONSTINT: typ ="ivec4"; break;
+ case REG_TYPE_CONSTBOOL: typ = "bool"; break;
+ default:
+ {
+ fail(ctx, "BUG: used a uniform we don't know how to define.");
+ return;
+ } // default
+ } // switch
+ output_line(ctx, "uniform %s %s[%d];", typ, buf, size);
} // if
} // output_GLSL_uniform_array
@@ -2252,6 +2300,10 @@
output_GLSL_uniform_array(ctx, REG_TYPE_CONST, ctx->uniform_float4_count);
output_GLSL_uniform_array(ctx, REG_TYPE_CONSTINT, ctx->uniform_int4_count);
output_GLSL_uniform_array(ctx, REG_TYPE_CONSTBOOL, ctx->uniform_bool_count);
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+ if (shader_is_vertex(ctx))
+ output_line(ctx, "uniform float vpFlip;");
+#endif
pop_output(ctx);
} // emit_GLSL_finalize
@@ -2535,15 +2587,34 @@
case MOJOSHADER_USAGE_COLOR:
index_str[0] = '\0'; // no explicit number.
if (index == 0)
+ {
+#if SUPPORT_PROFILE_GLSLES
+ if (support_glsles(ctx))
+ usage_str = "v_FrontColor";
+ else
+#endif
usage_str = "gl_FrontColor";
+ } // if
else if (index == 1)
+ {
+#if SUPPORT_PROFILE_GLSLES
+ if (support_glsles(ctx))
+ usage_str = "v_FrontSecondaryColor";
+ else
+#endif
usage_str = "gl_FrontSecondaryColor";
+ } // else if
break;
case MOJOSHADER_USAGE_FOG:
usage_str = "gl_FogFragCoord";
break;
case MOJOSHADER_USAGE_TEXCOORD:
snprintf(index_str, sizeof (index_str), "%u", (uint) index);
+#if SUPPORT_PROFILE_GLSLES
+ if (support_glsles(ctx))
+ usage_str = "v_TexCoord";
+ else
+#endif
usage_str = "gl_TexCoord";
arrayleft = "[";
arrayright = "]";
@@ -2609,6 +2680,11 @@
if (shader_version_atleast(ctx, 1, 4))
{
snprintf(index_str, sizeof (index_str), "%u", (uint) index);
+#if SUPPORT_PROFILE_GLSLES
+ if (support_glsles(ctx))
+ usage_str = "v_TexCoord";
+ else
+#endif
usage_str = "gl_TexCoord";
arrayleft = "[";
arrayright = "]";
@@ -2619,12 +2695,33 @@
{
index_str[0] = '\0'; // no explicit number.
if (index == 0)
+ {
+#if SUPPORT_PROFILE_GLSLES
+ if (support_glsles(ctx))
+ usage_str = "v_FrontColor";
+ else
+#endif
usage_str = "gl_Color";
+ } // if
else if (index == 1)
+ {
+#if SUPPORT_PROFILE_GLSLES
+ if (support_glsles(ctx))
+ usage_str = "v_FrontSecondaryColor";
+ else
+#endif
usage_str = "gl_SecondaryColor";
+ } // else if
else
fail(ctx, "unsupported color index");
} // else if
+
+ else if (usage == MOJOSHADER_USAGE_DEPTH) // !!! FIXME: Possibly more! -flibit
+ {
+ push_output(ctx, &ctx->globals);
+ output_line(ctx, "attribute vec4 %s;", var);
+ pop_output(ctx);
+ } // else if
} // else if
else if (regtype == REG_TYPE_MISCTYPE)
@@ -6155,6 +6252,7 @@
// This is for profiles that extend other profiles...
static const struct { const char *from; const char *to; } profileMap[] =
{
+ { MOJOSHADER_PROFILE_GLSLES, MOJOSHADER_PROFILE_GLSL },
{ MOJOSHADER_PROFILE_GLSL120, MOJOSHADER_PROFILE_GLSL },
{ MOJOSHADER_PROFILE_NV2, MOJOSHADER_PROFILE_ARB1 },
{ MOJOSHADER_PROFILE_NV3, MOJOSHADER_PROFILE_ARB1 },
@@ -6843,6 +6941,35 @@
ctx->dwords[0] = usage;
ctx->dwords[1] = index;
} // if
+ else if (regtype == REG_TYPE_TEXTURE)
+ {
+ const uint32 usage = (token & 0xF);
+ const uint32 index = ((token >> 16) & 0xF);
+ if (usage == MOJOSHADER_USAGE_TEXCOORD)
+ {
+ if (index > 7)
+ fail(ctx, "DCL texcoord usage must have 0-7 index");
+ } // if
+ else if (usage == MOJOSHADER_USAGE_COLOR)
+ {
+ if (index != 0)
+ fail(ctx, "DCL texcoord usage must have 0 index");
+ } // else if
+ else
+ fail(ctx, "Invalid DCL texture usage");
+
+ reserved_mask = 0x7FF0FFE0;
+ ctx->dwords[0] = usage;
+ ctx->dwords[1] = index;
+ } // else if
+ else if (regtype == REG_TYPE_SAMPLER)
+ {
+ const uint32 ttype = ((token >> 27) & 0xF);
+ if (!valid_texture_type(ttype))
+ fail(ctx, "Unknown sampler texture type");
+ reserved_mask = 0x6FFFFFFF;
+ ctx->dwords[0] = ttype;
+ } // else if
else
{
unsupported = 1;
@@ -7086,14 +7213,19 @@
else if (shader_is_vertex(ctx))
{
- const MOJOSHADER_usage usage = (const MOJOSHADER_usage) ctx->dwords[0];
- const int index = ctx->dwords[1];
- if (usage >= MOJOSHADER_USAGE_TOTAL)
- {
- fail(ctx, "unknown DCL usage");
- return;
- } // if
- add_attribute_register(ctx, regtype, regnum, usage, index, wmask, mods);
+ if (regtype == REG_TYPE_SAMPLER)
+ add_sampler(ctx, regnum, (TextureType) ctx->dwords[0], 0);
+ else
+ {
+ const MOJOSHADER_usage usage = (const MOJOSHADER_usage) ctx->dwords[0];
+ const int index = ctx->dwords[1];
+ if (usage >= MOJOSHADER_USAGE_TOTAL)
+ {
+ fail(ctx, "unknown DCL usage");
+ return;
+ } // if
+ add_attribute_register(ctx, regtype, regnum, usage, index, wmask, mods);
+ } // else
} // if
else if (shader_is_pixel(ctx))
@@ -7470,8 +7602,6 @@
const RegisterType regtype = ctx->source_args[0].regtype;
if ((regtype != REG_TYPE_PREDICATE) && (regtype != REG_TYPE_CONSTBOOL))
fail(ctx, "IF src0 must be CONSTBOOL or PREDICATE");
- else if (!replicate_swizzle(ctx->source_args[0].swizzle))
- fail(ctx, "IF src0 must have replicate swizzle");
// !!! FIXME: track if nesting depth.
} // state_IF
@@ -8061,7 +8191,7 @@
// !!! FIXME: check that (start+target) points to "ps_3_0", etc.
ctab->symbol_count = constants;
- ctab->symbols = Malloc(ctx, sizeof (MOJOSHADER_symbol) * constants);
+ ctab->symbols = (MOJOSHADER_symbol *) Malloc(ctx, sizeof (MOJOSHADER_symbol) * constants);
if (ctab->symbols == NULL)
return;
memset(ctab->symbols, '\0', sizeof (MOJOSHADER_symbol) * constants);
@@ -8173,8 +8303,8 @@
if ((tokcount < 2) || (SWAP32(tokens[1]) != PRES_ID))
return; // not a preshader.
-#if !SUPPORT_PRESHADERS
- fail(ctx, "Preshader found, but preshader support is disabled!");
+#ifndef MOJOSHADER_EFFECT_SUPPORT
+ fail(ctx, "Preshader found, but effect support is disabled!");
#else
assert(ctx->have_preshader == 0); // !!! FIXME: can you have more than one?
@@ -8183,10 +8313,12 @@
// !!! FIXME: I don't know what specific versions signify, but we need to
// !!! FIXME: save this to test against the CTAB version field, if
// !!! FIXME: nothing else.
- // !!! FIXME: 0x02 0x01 is probably the version (fx_2_1),
+ // !!! FIXME: 0x02 0x0? is probably the version (fx_2_?),
// !!! FIXME: and 0x4658 is the magic, like a real shader's version token.
- const uint32 okay_version = 0x46580201;
- if (SWAP32(tokens[2]) != okay_version)
+ const uint32 min_version = 0x46580200;
+ const uint32 max_version = 0x46580201;
+ const uint32 version = SWAP32(tokens[2]);
+ if (version < min_version || version > max_version)
{
fail(ctx, "Unsupported preshader version.");
return; // fail because the shader will malfunction w/o this.
@@ -8313,7 +8445,7 @@
// Now we'll figure out the CTAB...
CtabData ctabdata = { 0, 0, 0 };
parse_constant_table(ctx, ctab.tokens - 1, ctab.tokcount * 4,
- okay_version, 0, &ctabdata);
+ version, 0, &ctabdata);
// preshader owns this now. Don't free it in this function.
preshader->symbol_count = ctabdata.symbol_count;
@@ -8412,7 +8544,7 @@
{
case 1: // literal from CLIT block.
{
- if (item >= preshader->literal_count)
+ if (item > preshader->literal_count)
{
fail(ctx, "Bogus preshader literal index.");
break;
@@ -8480,6 +8612,27 @@
inst++;
} // while
+
+ // Registers need to be vec4, round up to nearest 4
+ preshader->temp_count = (preshader->temp_count + 3) & ~3;
+
+ unsigned int largest = 0;
+ const MOJOSHADER_symbol *sym = preshader->symbols;
+ int i;
+ for (i = 0; i < preshader->symbol_count; i++, sym++)
+ {
+ const unsigned int val = sym->register_index + sym->register_count;
+ if (val > largest)
+ largest = val;
+ } // for
+
+ if (largest > 0)
+ {
+ const size_t len = largest * sizeof (float) * 4;
+ preshader->registers = (float *) Malloc(ctx, len);
+ memset(preshader->registers, '\0', len);
+ preshader->register_count = largest;
+ } // if
#endif
} // parse_preshader
@@ -8702,19 +8855,6 @@
} // free_symbols
-static void free_preshader(MOJOSHADER_free f, void *d,
- MOJOSHADER_preshader *preshader)
-{
- if (preshader != NULL)
- {
- f((void *) preshader->literals, d);
- f((void *) preshader->instructions, d);
- free_symbols(f, d, preshader->symbols, preshader->symbol_count);
- f((void *) preshader, d);
- } // if
-} // free_preshader
-
-
static void destroy_context(Context *ctx)
{
if (ctx != NULL)
@@ -8737,7 +8877,7 @@
free_variable_list(f, d, ctx->variables);
errorlist_destroy(ctx->errors);
free_symbols(f, d, ctx->ctab.symbols, ctx->ctab.symbol_count);
- free_preshader(f, d, ctx->preshader);
+ MOJOSHADER_freePreshader(ctx->preshader, f, d);
f(ctx, d);
} // if
} // destroy_context
@@ -9514,7 +9654,7 @@
f((void *) data->samplers, d);
free_symbols(f, d, data->symbols, data->symbol_count);
- free_preshader(f, d, data->preshader);
+ MOJOSHADER_freePreshader(data->preshader, f, d);
f(data, d);
} // MOJOSHADER_freeParseData
@@ -9539,6 +9679,7 @@
PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_BYTECODE, 3);
PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_GLSL, 3);
PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_GLSL120, 3);
+ PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_GLSLES, 3);
PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_ARB1, 2);
PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_NV2, 2);
PROFILE_SHADER_MODEL(MOJOSHADER_PROFILE_NV3, 2);
@@ -9547,5 +9688,378 @@
return -1; // unknown profile?
} // MOJOSHADER_maxShaderModel
+
+const MOJOSHADER_preshader *MOJOSHADER_parsePreshader(const unsigned char *buf,
+ const unsigned int _len,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d)
+{
+ // !!! FIXME: This is copypasta ripped from parse_preshader -flibit
+ int i;
+
+ const uint32 *tokens = (const uint32 *) buf;
+ uint32 tokcount = _len / 4;
+
+ // !!! FIXME: This is stupid. -flibit
+ Context fillerContext;
+ fillerContext.malloc = m;
+ fillerContext.free = f;
+ fillerContext.malloc_data = d;
+ fillerContext.out_of_memory = 0;
+
+ MOJOSHADER_preshader *preshader = NULL;
+
+ const uint32 version_magic = 0x46580000;
+ const uint32 min_version = 0x00000200 | version_magic;
+ const uint32 max_version = 0x00000201 | version_magic;
+ const uint32 version = SWAP32(tokens[0]);
+ if (version < min_version || version > max_version)
+ {
+ // fail because the shader will malfunction w/o this.
+ goto parsePreshader_notAPreshader;
+ } // if
+
+ tokens++;
+ tokcount++;
+
+ // All sections of a preshader are packed into separate comment tokens,
+ // inside the containing comment token block. Find them all before
+ // we start, so we don't care about the order they appear in the file.
+ PreshaderBlockInfo ctab = { 0, 0, 0 };
+ PreshaderBlockInfo prsi = { 0, 0, 0 };
+ PreshaderBlockInfo fxlc = { 0, 0, 0 };
+ PreshaderBlockInfo clit = { 0, 0, 0 };
+
+ while (tokcount > 0)
+ {
+ uint32 subtokcount = 0;
+ // !!! FIXME: Passing a NULL ctx! -flibit
+ if ( (!is_comment_token(&fillerContext, *tokens, &subtokcount)) ||
+ (subtokcount > tokcount) )
+ {
+ goto parsePreshader_notAPreshader;
+ } // if
+
+ tokens++;
+ tokcount--;
+
+ const uint32 *nexttokens = tokens + subtokcount;
+ const uint32 nexttokcount = tokcount - subtokcount;
+
+ if (subtokcount > 0)
+ {
+ switch (SWAP32(*tokens))
+ {
+ #define PRESHADER_BLOCK_CASE(id, var) \
+ case id##_ID: { \
+ if (var.seen) \
+ goto parsePreshader_notAPreshader; \
+ var.tokens = tokens; \
+ var.tokcount = subtokcount; \
+ var.seen = 1; \
+ break; \
+ }
+ PRESHADER_BLOCK_CASE(CTAB, ctab);
+ PRESHADER_BLOCK_CASE(PRSI, prsi);
+ PRESHADER_BLOCK_CASE(FXLC, fxlc);
+ PRESHADER_BLOCK_CASE(CLIT, clit);
+ default:
+ // Bogus preshader section
+ goto parsePreshader_notAPreshader;
+ #undef PRESHADER_BLOCK_CASE
+ } // switch
+ } // if
+
+ tokens = nexttokens;
+ tokcount = nexttokcount;
+ } // while
+
+ if (!ctab.seen) // No CTAB block in preshader
+ goto parsePreshader_notAPreshader;
+ if (!fxlc.seen) // No FXLC block in preshader
+ goto parsePreshader_notAPreshader;
+ if (!clit.seen) // No CLIT block in preshader
+ goto parsePreshader_notAPreshader;
+
+ preshader = (MOJOSHADER_preshader *) m(sizeof (MOJOSHADER_preshader), d);
+ if (preshader == NULL)
+ goto parsePreshader_outOfMemory;
+ memset(preshader, '\0', sizeof (MOJOSHADER_preshader));
+
+ // Let's set up the constant literals first...
+ if (clit.tokcount == 0) // Bogus CLIT block in preshader
+ goto parsePreshader_notAPreshader;
+ else
+ {
+ const uint32 lit_count = SWAP32(clit.tokens[1]);
+ if (lit_count > ((clit.tokcount - 2) / 2))
+ // Bogus CLIT block in preshader
+ goto parsePreshader_notAPreshader;
+ else if (lit_count > 0)
+ {
+ preshader->literal_count = (unsigned int) lit_count;
+ assert(sizeof (double) == 8); // just in case.
+ const size_t len = sizeof (double) * lit_count;
+ preshader->literals = (double *) m(len, d);
+ if (preshader->literals == NULL)
+ goto parsePreshader_notAPreshader; // oh well.
+ const double *litptr = (const double *) (clit.tokens + 2);
+ for (i = 0; i < lit_count; i++)
+ preshader->literals[i] = SWAPDBL(litptr[i]);
+ } // else if
+ } // else
+
+ // Parse out the PRSI block. This is used to map the output registers.
+ uint32 output_map_count = 0;
+ const uint32 *output_map = NULL;
+ if (prsi.seen)
+ {
+ if (prsi.tokcount < 8) // Bogus preshader PRSI data
+ goto parsePreshader_notAPreshader;
+
+ //const uint32 first_output_reg = SWAP32(prsi.tokens[1]);
+ // !!! FIXME: there are a lot of fields here I don't know about.
+ // !!! FIXME: maybe [2] and [3] are for int4 and bool registers?
+ //const uint32 output_reg_count = SWAP32(prsi.tokens[4]);
+ // !!! FIXME: maybe [5] and [6] are for int4 and bool registers?
+ output_map_count = SWAP32(prsi.tokens[7]);
+
+ prsi.tokcount -= 8;
+ prsi.tokens += 8;
+
+ if (prsi.tokcount < ((output_map_count + 1) * 2))
+ // Bogus preshader PRSI data
+ goto parsePreshader_notAPreshader;
+
+ output_map = prsi.tokens;
+ }
+
+ // Now we'll figure out the CTAB...
+ CtabData ctabdata = { 0, 0, 0 };
+ parse_constant_table(&fillerContext, ctab.tokens - 1, ctab.tokcount * 4,
+ version, 0, &ctabdata);
+
+ // preshader owns this now. Don't free it in this function.
+ preshader->symbol_count = ctabdata.symbol_count;
+ preshader->symbols = ctabdata.symbols;
+
+ if (!ctabdata.have_ctab) // Bogus preshader CTAB data
+ goto parsePreshader_notAPreshader;
+
+ // The FXLC block has the actual instructions...
+ uint32 opcode_count = SWAP32(fxlc.tokens[1]);
+
+ size_t len = sizeof (MOJOSHADER_preshaderInstruction) * opcode_count;
+ preshader->instruction_count = (unsigned int) opcode_count;
+ preshader->instructions = (MOJOSHADER_preshaderInstruction *)
+ m(len, d);
+ if (preshader->instructions == NULL)
+ goto parsePreshader_outOfMemory;
+ memset(preshader->instructions, '\0', len);
+
+ fxlc.tokens += 2;
+ fxlc.tokcount -= 2;
+ if (opcode_count > (fxlc.tokcount / 2)) // Bogus preshader FXLC block
+ goto parsePreshader_notAPreshader;
+
+ MOJOSHADER_preshaderInstruction *inst = preshader->instructions;
+ while (opcode_count--)
+ {
+ const uint32 opcodetok = SWAP32(fxlc.tokens[0]);
+ MOJOSHADER_preshaderOpcode opcode = MOJOSHADER_PRESHADEROP_NOP;
+ switch ((opcodetok >> 16) & 0xFFFF)
+ {
+ case 0x1000: opcode = MOJOSHADER_PRESHADEROP_MOV; break;
+ case 0x1010: opcode = MOJOSHADER_PRESHADEROP_NEG; break;
+ case 0x1030: opcode = MOJOSHADER_PRESHADEROP_RCP; break;
+ case 0x1040: opcode = MOJOSHADER_PRESHADEROP_FRC; break;
+ case 0x1050: opcode = MOJOSHADER_PRESHADEROP_EXP; break;
+ case 0x1060: opcode = MOJOSHADER_PRESHADEROP_LOG; break;
+ case 0x1070: opcode = MOJOSHADER_PRESHADEROP_RSQ; break;
+ case 0x1080: opcode = MOJOSHADER_PRESHADEROP_SIN; break;
+ case 0x1090: opcode = MOJOSHADER_PRESHADEROP_COS; break;
+ case 0x10A0: opcode = MOJOSHADER_PRESHADEROP_ASIN; break;
+ case 0x10B0: opcode = MOJOSHADER_PRESHADEROP_ACOS; break;
+ case 0x10C0: opcode = MOJOSHADER_PRESHADEROP_ATAN; break;
+ case 0x2000: opcode = MOJOSHADER_PRESHADEROP_MIN; break;
+ case 0x2010: opcode = MOJOSHADER_PRESHADEROP_MAX; break;
+ case 0x2020: opcode = MOJOSHADER_PRESHADEROP_LT; break;
+ case 0x2030: opcode = MOJOSHADER_PRESHADEROP_GE; break;
+ case 0x2040: opcode = MOJOSHADER_PRESHADEROP_ADD; break;
+ case 0x2050: opcode = MOJOSHADER_PRESHADEROP_MUL; break;
+ case 0x2060: opcode = MOJOSHADER_PRESHADEROP_ATAN2; break;
+ case 0x2080: opcode = MOJOSHADER_PRESHADEROP_DIV; break;
+ case 0x3000: opcode = MOJOSHADER_PRESHADEROP_CMP; break;
+ case 0x3010: opcode = MOJOSHADER_PRESHADEROP_MOVC; break;
+ case 0x5000: opcode = MOJOSHADER_PRESHADEROP_DOT; break;
+ case 0x5020: opcode = MOJOSHADER_PRESHADEROP_NOISE; break;
+ case 0xA000: opcode = MOJOSHADER_PRESHADEROP_MIN_SCALAR; break;
+ case 0xA010: opcode = MOJOSHADER_PRESHADEROP_MAX_SCALAR; break;
+ case 0xA020: opcode = MOJOSHADER_PRESHADEROP_LT_SCALAR; break;
+ case 0xA030: opcode = MOJOSHADER_PRESHADEROP_GE_SCALAR; break;
+ case 0xA040: opcode = MOJOSHADER_PRESHADEROP_ADD_SCALAR; break;
+ case 0xA050: opcode = MOJOSHADER_PRESHADEROP_MUL_SCALAR; break;
+ case 0xA060: opcode = MOJOSHADER_PRESHADEROP_ATAN2_SCALAR; break;
+ case 0xA080: opcode = MOJOSHADER_PRESHADEROP_DIV_SCALAR; break;
+ case 0xD000: opcode = MOJOSHADER_PRESHADEROP_DOT_SCALAR; break;
+ case 0xD020: opcode = MOJOSHADER_PRESHADEROP_NOISE_SCALAR; break;
+ default:
+ // Unknown preshader opcode
+ goto parsePreshader_notAPreshader;
+ } // switch
+
+ uint32 operand_count = SWAP32(fxlc.tokens[1]) + 1; // +1 for dest.
+
+ inst->opcode = opcode;
+ inst->element_count = (unsigned int) (opcodetok & 0xFF);
+ inst->operand_count = (unsigned int) operand_count;
+
+ fxlc.tokens += 2;
+ fxlc.tokcount -= 2;
+ if ((operand_count * 3) > fxlc.tokcount)
+ // Bogus preshader FXLC block
+ goto parsePreshader_notAPreshader;
+
+ MOJOSHADER_preshaderOperand *operand = inst->operands;
+ while (operand_count--)
+ {
+ const unsigned int item = (unsigned int) SWAP32(fxlc.tokens[2]);
+
+ // !!! FIXME: Is this used anywhere other than INPUT? -flibit
+ const uint32 numArrays = SWAP32(fxlc.tokens[0]);
+
+ switch (SWAP32(fxlc.tokens[1]))
+ {
+ case 1: // literal from CLIT block.
+ {
+ if ((item + inst->element_count) >= preshader->literal_count)
+ // Bogus preshader literal index
+ goto parsePreshader_notAPreshader;
+ operand->type = MOJOSHADER_PRESHADEROPERAND_LITERAL;
+ break;
+ } // case
+
+ case 2: // item from ctabdata.
+ {
+ MOJOSHADER_symbol *sym = ctabdata.symbols;
+ for (i = 0; i < ctabdata.symbol_count; i++, sym++)
+ {
+ const uint32 base = sym->register_index * 4;
+ const uint32 count = sym->register_count * 4;
+ assert(sym->register_set==MOJOSHADER_SYMREGSET_FLOAT4);
+ if ( (base <= item) && ((base + count) >= (item + inst->element_count)) )
+ break;
+ } // for
+ if (i == ctabdata.symbol_count)
+ // Bogus preshader input index
+ goto parsePreshader_notAPreshader;
+ operand->type = MOJOSHADER_PRESHADEROPERAND_INPUT;
+ if (numArrays > 0)
+ {
+ // malloc the array symbol name array
+ const uint32 siz = numArrays * sizeof (uint32);
+ operand->array_register_count = numArrays;
+ operand->array_registers = (uint32 *) m(siz, d);
+ memset(operand->array_registers, '\0', siz);
+ // Get each register base, indicating the arrays used.
+ for (i = 0; i < numArrays; i++)
+ {
+ const uint32 jmp = SWAP32(fxlc.tokens[4]);
+ const uint32 bigjmp = (jmp >> 4) * 4;
+ const uint32 ltljmp = (jmp >> 2) & 3;
+ operand->array_registers[i] = bigjmp + ltljmp;
+ fxlc.tokens += 2;
+ fxlc.tokcount -= 2;
+ } // for
+ } // if
+ break;
+ } // case
+
+ case 4:
+ {
+ operand->type = MOJOSHADER_PRESHADEROPERAND_OUTPUT;
+ if (!prsi.seen)
+ // No PRSI tokens, no output map.
+ continue;
+ for (i = 0; i < output_map_count; i++)
+ {
+ const uint32 base = output_map[(i*2)] * 4;
+ const uint32 count = output_map[(i*2)+1] * 4;
+ if ( (base <= item) && ((base + count) >= (item + inst->element_count)) )
+ break;
+ } // for
+ if (i == output_map_count)
+ // Bogus preshader output index
+ goto parsePreshader_notAPreshader;
+ break;
+ } // case
+
+ case 7:
+ {
+ operand->type = MOJOSHADER_PRESHADEROPERAND_TEMP;
+ if (item >= preshader->temp_count)
+ preshader->temp_count = item + inst->element_count;
+ break;
+ } // case
+ } // switch
+
+ operand->index = item;
+
+ fxlc.tokens += 3;
+ fxlc.tokcount -= 3;
+ operand++;
+ } // while
+
+ inst++;
+ } // while
+
+ // Registers need to be vec4, round up to nearest 4
+ preshader->temp_count = (preshader->temp_count + 3) & ~3;
+
+ unsigned int largest = 0;
+ const MOJOSHADER_symbol *sym = preshader->symbols;
+ for (i = 0; i < preshader->symbol_count; i++, sym++)
+ {
+ const unsigned int val = sym->register_index + sym->register_count;
+ if (val > largest)
+ largest = val;
+ } // for
+
+ if (largest > 0)
+ {
+ const size_t len = largest * sizeof (float) * 4;
+ preshader->registers = (float *) m(len, d);
+ memset(preshader->registers, '\0', len);
+ preshader->register_count = largest;
+ } // if
+
+ return preshader;
+
+parsePreshader_notAPreshader:
+parsePreshader_outOfMemory:
+ MOJOSHADER_freePreshader(preshader, f, d);
+ return NULL;
+} // MOJOSHADER_parsePreshader
+
+
+void MOJOSHADER_freePreshader(const MOJOSHADER_preshader *preshader,
+ MOJOSHADER_free f,
+ void *d)
+{
+ int i, j;
+ if (preshader != NULL)
+ {
+ f((void *) preshader->literals, d);
+ for (i = 0; i < preshader->instruction_count; i++)
+ for (j = 0; j < preshader->instructions[i].operand_count; j++)
+ f((void *) preshader->instructions[i].operands[j].array_registers, d);
+ f((void *) preshader->instructions, d);
+ f((void *) preshader->registers, d);
+ free_symbols(f, d, preshader->symbols, preshader->symbol_count);
+ f((void *) preshader, d);
+ } // if
+} // MOJOSHADER_freePreshader
+
// end of mojoshader.c ...
--- a/mojoshader.h Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader.h Fri Jan 01 02:12:19 2016 -0500
@@ -27,6 +27,22 @@
#define MOJOSHADER_CHANGESET "???"
#endif
+#ifndef DECLSPEC
+#ifdef _WIN32
+#define DECLSPEC __declspec(dllexport)
+#else
+#define DECLSPEC
+#endif
+#endif
+
+#ifndef MOJOSHADERCALL
+#ifdef _WIN32
+#define MOJOSHADERCALL __stdcall
+#else
+#define MOJOSHADERCALL
+#endif
+#endif
+
/*
* For determining the version of MojoShader you are using:
* const int compiled_against = MOJOSHADER_VERSION;
@@ -34,7 +50,7 @@
*
* The version is a single integer that increments, not a major/minor value.
*/
-int MOJOSHADER_version(void);
+DECLSPEC int MOJOSHADER_version(void);
/*
* For determining the revision control changeset of MojoShader you are using:
@@ -47,7 +63,7 @@
*
* Do not attempt to free this string; it's statically allocated.
*/
-const char *MOJOSHADER_changeset(void);
+DECLSPEC const char *MOJOSHADER_changeset(void);
/*
* These allocators work just like the C runtime's malloc() and free()
@@ -57,8 +73,8 @@
* callbacks, in case you need instance-specific data...it is passed through
* to your allocator unmolested, and can be NULL if you like.
*/
-typedef void *(*MOJOSHADER_malloc)(int bytes, void *data);
-typedef void (*MOJOSHADER_free)(void *ptr, void *data);
+typedef void *(MOJOSHADERCALL *MOJOSHADER_malloc)(int bytes, void *data);
+typedef void (MOJOSHADERCALL *MOJOSHADER_free)(void *ptr, void *data);
/*
@@ -428,6 +444,8 @@
{
MOJOSHADER_preshaderOperandType type;
unsigned int index;
+ unsigned int array_register_count;
+ unsigned int *array_registers;
} MOJOSHADER_preshaderOperand;
typedef struct MOJOSHADER_preshaderInstruction
@@ -435,7 +453,7 @@
MOJOSHADER_preshaderOpcode opcode;
unsigned int element_count;
unsigned int operand_count;
- MOJOSHADER_preshaderOperand operands[3];
+ MOJOSHADER_preshaderOperand operands[4];
} MOJOSHADER_preshaderInstruction;
typedef struct MOJOSHADER_preshader
@@ -447,6 +465,8 @@
MOJOSHADER_symbol *symbols;
unsigned int instruction_count;
MOJOSHADER_preshaderInstruction *instructions;
+ unsigned int register_count;
+ float *registers;
} MOJOSHADER_preshader;
/*
@@ -651,6 +671,11 @@
#define MOJOSHADER_PROFILE_GLSL120 "glsl120"
/*
+ * Profile string for GLSL ES: minor changes to GLSL output for ES compliance.
+ */
+#define MOJOSHADER_PROFILE_GLSLES "glsles"
+
+/*
* Profile string for OpenGL ARB 1.0 shaders: GL_ARB_(vertex|fragment)_program.
*/
#define MOJOSHADER_PROFILE_ARB1 "arb1"
@@ -676,7 +701,7 @@
/*
* Determine the highest supported Shader Model for a profile.
*/
-int MOJOSHADER_maxShaderModel(const char *profile);
+DECLSPEC int MOJOSHADER_maxShaderModel(const char *profile);
/*
@@ -732,16 +757,17 @@
* (tokenbuf) remains intact for the duration of the call. This allows you
* to parse several shaders on separate CPU cores at the same time.
*/
-const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
- const unsigned char *tokenbuf,
- const unsigned int bufsize,
- const MOJOSHADER_swizzle *swiz,
- const unsigned int swizcount,
- const MOJOSHADER_samplerMap *smap,
- const unsigned int smapcount,
- MOJOSHADER_malloc m,
- MOJOSHADER_free f,
- void *d);
+DECLSPEC const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
+ const unsigned char *tokenbuf,
+ const unsigned int bufsize,
+ const MOJOSHADER_swizzle *swiz,
+ const unsigned int swizcount,
+ const MOJOSHADER_samplerMap *smap,
+ const unsigned int smapcount,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d);
+
/*
* Call this to dispose of parsing results when you are done with them.
@@ -752,152 +778,25 @@
* This function is thread safe, so long as any allocator you passed into
* MOJOSHADER_parse() is, too.
*/
-void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *data);
-
-
-/* Effects interface... */ /* !!! FIXME: THIS API IS NOT STABLE YET! */
-
-typedef struct MOJOSHADER_effectParam
-{
- const char *name;
- const char *semantic;
-} MOJOSHADER_effectParam;
-
-typedef struct MOJOSHADER_effectState
-{
- unsigned int type;
-} MOJOSHADER_effectState;
-
-typedef struct MOJOSHADER_effectPass
-{
- const char *name;
- unsigned int state_count;
- MOJOSHADER_effectState *states;
-} MOJOSHADER_effectPass;
-
-typedef struct MOJOSHADER_effectTechnique
-{
- const char *name;
- unsigned int pass_count;
- MOJOSHADER_effectPass *passes;
-} MOJOSHADER_effectTechnique;
-
-typedef struct MOJOSHADER_effectTexture
-{
- unsigned int param;
- const char *name;
-} MOJOSHADER_effectTexture;
-
-typedef struct MOJOSHADER_effectShader
-{
- unsigned int technique;
- unsigned int pass;
- const MOJOSHADER_parseData *shader;
-} MOJOSHADER_effectShader;
-
-/*
- * Structure used to return data from parsing of an effect file...
- */
-/* !!! FIXME: most of these ints should be unsigned. */
-typedef struct MOJOSHADER_effect
-{
- /*
- * The number of elements pointed to by (errors).
- */
- int error_count;
-
- /*
- * (error_count) elements of data that specify errors that were generated
- * by parsing this shader.
- * This can be NULL if there were no errors or if (error_count) is zero.
- */
- MOJOSHADER_error *errors;
-
- /*
- * The name of the profile used to parse the shader. Will be NULL on error.
- */
- const char *profile;
-
- /*
- * The number of params pointed to by (params).
- */
- int param_count;
-
- /*
- * (param_count) elements of data that specify parameter bind points for
- * this effect.
- * This can be NULL on error or if (param_count) is zero.
- */
- MOJOSHADER_effectParam *params;
-
- /*
- * The number of elements pointed to by (techniques).
- */
- int technique_count;
-
- /*
- * (technique_count) elements of data that specify techniques used in
- * this effect. Each technique contains a series of passes, and each pass
- * specifies state and shaders that affect rendering.
- * This can be NULL on error or if (technique_count) is zero.
- */
- MOJOSHADER_effectTechnique *techniques;
-
- /*
- * The number of elements pointed to by (textures).
- */
- int texture_count;
-
- /*
- * (texture_count) elements of data that specify textures used in
- * this effect.
- * This can be NULL on error or if (texture_count) is zero.
- */
- MOJOSHADER_effectTexture *textures;
-
- /*
- * The number of elements pointed to by (shaders).
- */
- int shader_count;
-
- /*
- * (shader_count) elements of data that specify shaders used in
- * this effect.
- * This can be NULL on error or if (shader_count) is zero.
- */
- MOJOSHADER_effectShader *shaders;
-
- /*
- * This is the malloc implementation you passed to MOJOSHADER_parseEffect().
- */
- MOJOSHADER_malloc malloc;
-
- /*
- * This is the free implementation you passed to MOJOSHADER_parseEffect().
- */
- MOJOSHADER_free free;
-
- /*
- * This is the pointer you passed as opaque data for your allocator.
- */
- void *malloc_data;
-} MOJOSHADER_effect;
-
-/* !!! FIXME: document me. */
-const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
- const unsigned char *buf,
- const unsigned int _len,
- const MOJOSHADER_swizzle *swiz,
- const unsigned int swizcount,
- const MOJOSHADER_samplerMap *smap,
- const unsigned int smapcount,
- MOJOSHADER_malloc m,
- MOJOSHADER_free f,
- void *d);
+DECLSPEC void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *data);
/* !!! FIXME: document me. */
-void MOJOSHADER_freeEffect(const MOJOSHADER_effect *effect);
+DECLSPEC const MOJOSHADER_preshader *MOJOSHADER_parsePreshader(const unsigned char *buf,
+ const unsigned int len,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d);
+
+
+/* !!! FIXME: document me. */
+DECLSPEC void MOJOSHADER_freePreshader(const MOJOSHADER_preshader *preshader,
+ MOJOSHADER_free f,
+ void *d);
+
+
+/* Effects interface... */
+#include "mojoshader_effects.h"
/* Preprocessor interface... */
@@ -1001,7 +900,7 @@
*
* If you supply an includeOpen callback, you must supply includeClose, too.
*/
-typedef int (*MOJOSHADER_includeOpen)(MOJOSHADER_includeType inctype,
+typedef int (MOJOSHADERCALL *MOJOSHADER_includeOpen)(MOJOSHADER_includeType inctype,
const char *fname, const char *parent,
const char **outdata, unsigned int *outbytes,
MOJOSHADER_malloc m, MOJOSHADER_free f, void *d);
@@ -1019,7 +918,7 @@
*
* If you supply an includeClose callback, you must supply includeOpen, too.
*/
-typedef void (*MOJOSHADER_includeClose)(const char *data,
+typedef void (MOJOSHADERCALL *MOJOSHADER_includeClose)(const char *data,
MOJOSHADER_malloc m, MOJOSHADER_free f, void *d);
@@ -1079,7 +978,7 @@
* call. This allows you to preprocess several shaders on separate CPU cores
* at the same time.
*/
-const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename,
+DECLSPEC const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename,
const char *source, unsigned int sourcelen,
const MOJOSHADER_preprocessorDefine *defines,
unsigned int define_count,
@@ -1097,7 +996,7 @@
* This function is thread safe, so long as any allocator you passed into
* MOJOSHADER_preprocess() is, too.
*/
-void MOJOSHADER_freePreprocessData(const MOJOSHADER_preprocessData *data);
+DECLSPEC void MOJOSHADER_freePreprocessData(const MOJOSHADER_preprocessData *data);
/* Assembler interface... */
@@ -1159,7 +1058,7 @@
* call. This allows you to assemble several shaders on separate CPU cores
* at the same time.
*/
-const MOJOSHADER_parseData *MOJOSHADER_assemble(const char *filename,
+DECLSPEC const MOJOSHADER_parseData *MOJOSHADER_assemble(const char *filename,
const char *source, unsigned int sourcelen,
const char **comments, unsigned int comment_count,
const MOJOSHADER_symbol *symbols,
@@ -2010,7 +1909,7 @@
* call. This allows you to parse several shaders on separate CPU cores
* at the same time.
*/
-const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
+DECLSPEC const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
const char *filename, const char *source,
unsigned int sourcelen,
const MOJOSHADER_preprocessorDefine *defs,
@@ -2033,7 +1932,7 @@
* This function is thread safe, so long as any allocator you passed into
* MOJOSHADER_parseAst() is, too.
*/
-void MOJOSHADER_freeAstData(const MOJOSHADER_astData *data);
+DECLSPEC void MOJOSHADER_freeAstData(const MOJOSHADER_astData *data);
/* Intermediate Representation interface... */
@@ -2450,7 +2349,7 @@
* call. This allows you to compile several shaders on separate CPU cores
* at the same time.
*/
-const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
+DECLSPEC const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
const char *filename, const char *source,
unsigned int sourcelen,
const MOJOSHADER_preprocessorDefine *defs,
@@ -2470,7 +2369,7 @@
* This function is thread safe, so long as any allocator you passed into
* MOJOSHADER_compile() is, too.
*/
-void MOJOSHADER_freeCompileData(const MOJOSHADER_compileData *data);
+DECLSPEC void MOJOSHADER_freeCompileData(const MOJOSHADER_compileData *data);
/* OpenGL interface... */
@@ -2493,7 +2392,7 @@
* to check two places to find the desired entry point, depending on your
* platform (Windows might need to look in OpenGL32.dll and use WGL, etc).
*/
-typedef void *(*MOJOSHADER_glGetProcAddress)(const char *fnname, void *data);
+typedef void *(MOJOSHADERCALL *MOJOSHADER_glGetProcAddress)(const char *fnname, void *data);
/*
@@ -2544,11 +2443,11 @@
* safe, you should probably only call this from the same thread that created
* the GL context.
*/
-int MOJOSHADER_glAvailableProfiles(MOJOSHADER_glGetProcAddress lookup,
- void *lookup_d,
- const char **profs, const int size,
- MOJOSHADER_malloc m, MOJOSHADER_free f,
- void *malloc_d);
+DECLSPEC int MOJOSHADER_glAvailableProfiles(MOJOSHADER_glGetProcAddress lookup,
+ void *lookup_d,
+ const char **profs, const int size,
+ MOJOSHADER_malloc m, MOJOSHADER_free f,
+ void *malloc_d);
/*
@@ -2581,7 +2480,7 @@
* safe, you should probably only call this from the same thread that created
* the GL context.
*/
-const char *MOJOSHADER_glBestProfile(MOJOSHADER_glGetProcAddress lookup,
+DECLSPEC const char *MOJOSHADER_glBestProfile(MOJOSHADER_glGetProcAddress lookup,
void *lookup_d,
MOJOSHADER_malloc m, MOJOSHADER_free f,
void *malloc_d);
@@ -2623,7 +2522,7 @@
* are not thread safe, you should probably only call this from the same
* thread that created the GL context.
*/
-MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile,
+DECLSPEC MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile,
MOJOSHADER_glGetProcAddress lookup,
void *lookup_d,
MOJOSHADER_malloc m, MOJOSHADER_free f,
@@ -2640,7 +2539,7 @@
* It is legal to call this with a NULL pointer to make no context current,
* but you need a valid context to be current to use most of MojoShader.
*/
-void MOJOSHADER_glMakeContextCurrent(MOJOSHADER_glContext *ctx);
+DECLSPEC void MOJOSHADER_glMakeContextCurrent(MOJOSHADER_glContext *ctx);
/*
* Get any error state we might have picked up. MojoShader will NOT call
@@ -2667,7 +2566,7 @@
* current. The error buffer is shared between contexts, so you can get
* error results from a failed MOJOSHADER_glCreateContext().
*/
-const char *MOJOSHADER_glGetError(void);
+DECLSPEC const char *MOJOSHADER_glGetError(void);
/*
* Get the maximum uniforms a shader can support for the current GL context,
@@ -2684,7 +2583,7 @@
* This call requires a valid MOJOSHADER_glContext to have been made current,
* or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
*/
-int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type);
+DECLSPEC int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type);
/*
* Compile a buffer of Direct3D shader bytecode into an OpenGL shader.
@@ -2706,12 +2605,12 @@
*
* Compiled shaders from this function may not be shared between contexts.
*/
-MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
- const unsigned int bufsize,
- const MOJOSHADER_swizzle *swiz,
- const unsigned int swizcount,
- const MOJOSHADER_samplerMap *smap,
- const unsigned int smapcount);
+DECLSPEC MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
+ const unsigned int bufsize,
+ const MOJOSHADER_swizzle *swiz,
+ const unsigned int swizcount,
+ const MOJOSHADER_samplerMap *smap,
+ const unsigned int smapcount);
/*
@@ -2721,7 +2620,7 @@
* This data is read-only, and you should NOT attempt to free it. This
* pointer remains valid until the shader is deleted.
*/
-const MOJOSHADER_parseData *MOJOSHADER_glGetShaderParseData(
+DECLSPEC const MOJOSHADER_parseData *MOJOSHADER_glGetShaderParseData(
MOJOSHADER_glShader *shader);
/*
* Link a vertex and pixel shader into an OpenGL program.
@@ -2746,8 +2645,8 @@
*
* Linked programs from this function may not be shared between contexts.
*/
-MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader,
- MOJOSHADER_glShader *pshader);
+DECLSPEC MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader,
+ MOJOSHADER_glShader *pshader);
/*
* This binds the program (using, for example, glUseProgramObjectARB()), and
@@ -2770,7 +2669,7 @@
* This call requires a valid MOJOSHADER_glContext to have been made current,
* or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
*/
-void MOJOSHADER_glBindProgram(MOJOSHADER_glProgram *program);
+DECLSPEC void MOJOSHADER_glBindProgram(MOJOSHADER_glProgram *program);
/*
* This binds individual shaders as if you had linked them with
@@ -2797,8 +2696,8 @@
* This call requires a valid MOJOSHADER_glContext to have been made current,
* or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
*/
-void MOJOSHADER_glBindShaders(MOJOSHADER_glShader *vshader,
- MOJOSHADER_glShader *pshader);
+DECLSPEC void MOJOSHADER_glBindShaders(MOJOSHADER_glShader *vshader,
+ MOJOSHADER_glShader *pshader);
/*
* Set a floating-point uniform value (what Direct3D calls a "constant").
@@ -2821,8 +2720,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glSetVertexShaderUniformF(unsigned int idx, const float *data,
- unsigned int vec4count);
+DECLSPEC void MOJOSHADER_glSetVertexShaderUniformF(unsigned int idx, const float *data,
+ unsigned int vec4count);
/*
* Retrieve a floating-point uniform value (what Direct3D calls a "constant").
@@ -2851,8 +2750,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glGetVertexShaderUniformF(unsigned int idx, float *data,
- unsigned int vec4count);
+DECLSPEC void MOJOSHADER_glGetVertexShaderUniformF(unsigned int idx, float *data,
+ unsigned int vec4count);
/*
@@ -2876,8 +2775,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glSetVertexShaderUniformI(unsigned int idx, const int *data,
- unsigned int ivec4count);
+DECLSPEC void MOJOSHADER_glSetVertexShaderUniformI(unsigned int idx, const int *data,
+ unsigned int ivec4count);
/*
* Retrieve an integer uniform value (what Direct3D calls a "constant").
@@ -2906,8 +2805,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glGetVertexShaderUniformI(unsigned int idx, int *data,
- unsigned int ivec4count);
+DECLSPEC void MOJOSHADER_glGetVertexShaderUniformI(unsigned int idx, int *data,
+ unsigned int ivec4count);
/*
* Set a boolean uniform value (what Direct3D calls a "constant").
@@ -2935,8 +2834,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glSetVertexShaderUniformB(unsigned int idx, const int *data,
- unsigned int bcount);
+DECLSPEC void MOJOSHADER_glSetVertexShaderUniformB(unsigned int idx, const int *data,
+ unsigned int bcount);
/*
* Retrieve a boolean uniform value (what Direct3D calls a "constant").
@@ -2972,8 +2871,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glGetVertexShaderUniformB(unsigned int idx, int *data,
- unsigned int bcount);
+DECLSPEC void MOJOSHADER_glGetVertexShaderUniformB(unsigned int idx, int *data,
+ unsigned int bcount);
/*
* The equivalent of MOJOSHADER_glSetVertexShaderUniformF() for pixel
@@ -2989,8 +2888,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glSetPixelShaderUniformF(unsigned int idx, const float *data,
- unsigned int vec4count);
+DECLSPEC void MOJOSHADER_glSetPixelShaderUniformF(unsigned int idx, const float *data,
+ unsigned int vec4count);
/*
@@ -3007,8 +2906,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glGetPixelShaderUniformF(unsigned int idx, float *data,
- unsigned int vec4count);
+DECLSPEC void MOJOSHADER_glGetPixelShaderUniformF(unsigned int idx, float *data,
+ unsigned int vec4count);
/*
@@ -3025,8 +2924,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glSetPixelShaderUniformI(unsigned int idx, const int *data,
- unsigned int ivec4count);
+DECLSPEC void MOJOSHADER_glSetPixelShaderUniformI(unsigned int idx, const int *data,
+ unsigned int ivec4count);
/*
@@ -3043,8 +2942,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glGetPixelShaderUniformI(unsigned int idx, int *data,
- unsigned int ivec4count);
+DECLSPEC void MOJOSHADER_glGetPixelShaderUniformI(unsigned int idx, int *data,
+ unsigned int ivec4count);
/*
* The equivalent of MOJOSHADER_glSetVertexShaderUniformB() for pixel
@@ -3060,8 +2959,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glSetPixelShaderUniformB(unsigned int idx, const int *data,
- unsigned int bcount);
+DECLSPEC void MOJOSHADER_glSetPixelShaderUniformB(unsigned int idx, const int *data,
+ unsigned int bcount);
/*
* The equivalent of MOJOSHADER_glGetVertexShaderUniformB() for pixel
@@ -3077,8 +2976,8 @@
*
* Uniforms are not shared between contexts.
*/
-void MOJOSHADER_glGetPixelShaderUniformB(unsigned int idx, int *data,
- unsigned int bcount);
+DECLSPEC void MOJOSHADER_glGetPixelShaderUniformB(unsigned int idx, int *data,
+ unsigned int bcount);
/*
* Set up the vector for the TEXBEM opcode. Most apps can ignore this API.
@@ -3115,9 +3014,23 @@
*
* These values are not shared between contexts.
*/
-void MOJOSHADER_glSetLegacyBumpMapEnv(unsigned int sampler, float mat00,
- float mat01, float mat10, float mat11,
- float lscale, float loffset);
+DECLSPEC void MOJOSHADER_glSetLegacyBumpMapEnv(unsigned int sampler, float mat00,
+ float mat01, float mat10, float mat11,
+ float lscale, float loffset);
+
+/*
+ * Return the location of a vertex attribute for the currently-bound program.
+ *
+ * (usage) and (index) map to Direct3D vertex declaration values: COLOR1 would
+ * be MOJOSHADER_USAGE_COLOR and 1.
+ *
+ * The return value is the index of the attribute to be sent to
+ * glVertexAttribPointer, or -1 if the stream is not used.
+ *
+ * This call requires a valid MOJOSHADER_glContext to have been made current,
+ * or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
+ */
+DECLSPEC int MOJOSHADER_glGetVertexAttribLocation(MOJOSHADER_usage usage, int index);
/*
* Connect a client-side array to the currently-bound program.
@@ -3146,30 +3059,30 @@
*/
/* !!! FIXME: this should probably be "input" and not "attribute" */
/* !!! FIXME: or maybe "vertex array" or something. */
-void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage,
- int index, unsigned int size,
- MOJOSHADER_attributeType type,
- int normalized, unsigned int stride,
- const void *ptr);
-
-
-
+DECLSPEC void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage,
+ int index, unsigned int size,
+ MOJOSHADER_attributeType type,
+ int normalized, unsigned int stride,
+ const void *ptr);
-/* These below functions are temporary and will be removed from the API once
- the real Effects API is written. Do not use! */
-void MOJOSHADER_glSetVertexPreshaderUniformF(unsigned int idx, const float *data,
- unsigned int vec4n);
-void MOJOSHADER_glGetVertexPreshaderUniformF(unsigned int idx, float *data,
- unsigned int vec4n);
-void MOJOSHADER_glSetPixelPreshaderUniformF(unsigned int idx, const float *data,
- unsigned int vec4n);
-void MOJOSHADER_glGetPixelPreshaderUniformF(unsigned int idx, float *data,
- unsigned int vec4n);
-/* These above functions are temporary and will be removed from the API once
- the real Effects API is written. Do not use! */
-
-
-
+/*
+ * Modify the rate at which this vertex attribute advances during instanced
+ * rendering.
+ *
+ * This should be called alongside glSetVertexAttribute, as this does not flag
+ * the vertex array as being in use. This just calls glVertexAttribDivisorARB.
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ *
+ * This call requires a valid MOJOSHADER_glContext to have been made current,
+ * or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
+ *
+ * Vertex attributes are not shared between contexts.
+ */
+DECLSPEC void MOJOSHADER_glSetVertexAttribDivisor(MOJOSHADER_usage usage,
+ int index, unsigned int divisor);
/*
* Inform MojoShader that it should commit any pending state to the GL. This
@@ -3184,7 +3097,12 @@
* This call requires a valid MOJOSHADER_glContext to have been made current,
* or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
*/
-void MOJOSHADER_glProgramReady(void);
+DECLSPEC void MOJOSHADER_glProgramReady(void);
+
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+// !!! FIXME: Document me.
+DECLSPEC void MOJOSHADER_glProgramViewportFlip(int flip);
+#endif
/*
* Free the resources of a linked program. This will delete the GL object
@@ -3200,7 +3118,7 @@
* This call requires a valid MOJOSHADER_glContext to have been made current,
* or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
*/
-void MOJOSHADER_glDeleteProgram(MOJOSHADER_glProgram *program);
+DECLSPEC void MOJOSHADER_glDeleteProgram(MOJOSHADER_glProgram *program);
/*
* Free the resources of a compiled shader. This will delete the GL object
@@ -3217,7 +3135,7 @@
* This call requires a valid MOJOSHADER_glContext to have been made current,
* or it will crash your program. See MOJOSHADER_glMakeContextCurrent().
*/
-void MOJOSHADER_glDeleteShader(MOJOSHADER_glShader *shader);
+DECLSPEC void MOJOSHADER_glDeleteShader(MOJOSHADER_glShader *shader);
/*
* Deinitialize MojoShader's OpenGL shader management.
@@ -3241,7 +3159,7 @@
* are not thread safe, you should probably only call this from the same
* thread that created the GL context.
*/
-void MOJOSHADER_glDestroyContext(MOJOSHADER_glContext *ctx);
+DECLSPEC void MOJOSHADER_glDestroyContext(MOJOSHADER_glContext *ctx);
#ifdef __cplusplus
}
--- a/mojoshader_common.c Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader_common.c Fri Jan 01 02:12:19 2016 -0500
@@ -3,8 +3,8 @@
// Convenience functions for allocators...
#if !MOJOSHADER_FORCE_ALLOCATOR
-void *MOJOSHADER_internal_malloc(int bytes, void *d) { return malloc(bytes); }
-void MOJOSHADER_internal_free(void *ptr, void *d) { free(ptr); }
+void * MOJOSHADERCALL MOJOSHADER_internal_malloc(int bytes, void *d) { return malloc(bytes); }
+void MOJOSHADERCALL MOJOSHADER_internal_free(void *ptr, void *d) { free(ptr); }
#endif
MOJOSHADER_error MOJOSHADER_out_of_mem_error = {
@@ -78,7 +78,7 @@
int hash_iter(const HashTable *table, const void *key,
const void **_value, void **iter)
{
- HashItem *item = *iter;
+ HashItem *item = (HashItem *) *iter;
if (item == NULL)
item = table->table[calc_hash(table, key)];
else
@@ -103,7 +103,7 @@
int hash_iter_keys(const HashTable *table, const void **_key, void **iter)
{
- HashItem *item = *iter;
+ HashItem *item = (HashItem *) *iter;
int idx = 0;
if (item != NULL)
@@ -1011,5 +1011,73 @@
return -1; // no match found.
} // buffer_find
+
+// Based on SDL_string.c's SDL_PrintFloat function
+size_t MOJOSHADER_printFloat(char *text, size_t maxlen, float arg)
+{
+ size_t len;
+ size_t left = maxlen;
+ char *textstart = text;
+
+ int precision = 9;
+
+ if (arg)
+ {
+ /* This isn't especially accurate, but hey, it's easy. :) */
+ unsigned long value;
+
+ if (arg < 0)
+ {
+ if (left > 1)
+ {
+ *text = '-';
+ --left;
+ } // if
+ ++text;
+ arg = -arg;
+ } // if
+ value = (unsigned long) arg;
+ len = snprintf(text, left, "%lu", value);
+ text += len;
+ if (len >= left)
+ left = (left < 1) ? left : 1;
+ else
+ left -= len;
+ arg -= value;
+
+ int mult = 10;
+ if (left > 1)
+ {
+ *text = '.';
+ --left;
+ } // if
+ ++text;
+ while (precision-- > 0)
+ {
+ value = (unsigned long) (arg * mult);
+ len = snprintf(text, left, "%lu", value);
+ text += len;
+ if (len >= left)
+ left = (left < 1) ? left : 1;
+ else
+ left -= len;
+ arg -= (double) value / mult;
+ if (arg < 0) arg = -arg; // Sometimes that bit gets flipped...
+ mult *= 10;
+ } // while
+ } // if
+ else
+ {
+ if (left > 3)
+ {
+ snprintf(text, left, "0.0");
+ left -= 3;
+ } // if
+ text += 3;
+ } // else
+
+ return (text - textstart);
+} // MOJOSHADER_printFloat
+
// end of mojoshader_common.c ...
--- a/mojoshader_effects.c Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader_effects.c Fri Jan 01 02:12:19 2016 -0500
@@ -10,12 +10,15 @@
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
+#ifdef MOJOSHADER_EFFECT_SUPPORT
+
#include <math.h>
-#if SUPPORT_PRESHADERS
void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
- const float *inregs, float *outregs)
+ float *outregs)
{
+ const float *inregs = preshader->registers;
+
// this is fairly straightforward, as there aren't any branching
// opcodes in the preshader instruction set (at the moment, at least).
const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
@@ -56,21 +59,32 @@
{
case MOJOSHADER_PRESHADEROPERAND_LITERAL:
{
- const double *lit = &preshader->literals[index];
- assert((index + elems) <= preshader->literal_count);
if (!isscalar)
- memcpy(&src[opiter][0], lit, elemsbytes);
+ {
+ assert((index + elems) <= preshader->literal_count);
+ memcpy(&src[opiter][0], &preshader->literals[index], elemsbytes);
+ } // if
else
{
- const double val = *lit;
for (elemiter = 0; elemiter < elems; elemiter++)
- src[opiter][elemiter] = val;
+ src[opiter][elemiter] = preshader->literals[index];
} // else
break;
} // case
case MOJOSHADER_PRESHADEROPERAND_INPUT:
- if (isscalar)
+ if (operand->array_register_count > 0)
+ {
+ int i;
+ const int *regsi = (const int *) inregs;
+ int arrIndex = regsi[((index >> 4) * 4) + ((index >> 2) & 3)];
+ for (i = 0; i < operand->array_register_count; i++)
+ {
+ arrIndex = regsi[operand->array_registers[i] + arrIndex];
+ }
+ src[opiter][0] = arrIndex;
+ } // if
+ else if (isscalar)
src[opiter][0] = inregs[index];
else
{
@@ -159,6 +173,7 @@
final += src0[i] * src1[i];
for (i = 0; i < elems; i++)
dst[i] = final; // !!! FIXME: is this right?
+ break;
} // case
default:
@@ -181,7 +196,6 @@
} // else
} // for
} // MOJOSHADER_runPreshader
-#endif
static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -202,357 +216,671 @@
return retval;
} // readui32
-// !!! FIXME: this is sort of a big, ugly function.
-const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
- const unsigned char *buf,
- const unsigned int _len,
- const MOJOSHADER_swizzle *swiz,
- const unsigned int swizcount,
- const MOJOSHADER_samplerMap *smap,
- const unsigned int smapcount,
- MOJOSHADER_malloc m,
- MOJOSHADER_free f,
- void *d)
+static char *readstring(const uint8 *base,
+ const uint32 offset,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ // !!! FIXME: sanity checks!
+ // !!! FIXME: verify this doesn't go past EOF looking for a null.
+ const char *str = ((const char *) base) + offset;
+ const uint32 len = *((const uint32 *) str);
+ char *strptr = NULL;
+ if (len == 0) return NULL; /* No length? No string. */
+ strptr = (char *) m(len, d);
+ memcpy(strptr, str + 4, len);
+ return strptr;
+} // readstring
+
+static int findparameter(const MOJOSHADER_effectParam *params,
+ const uint32 param_count,
+ const char *name)
+{
+ int i;
+ for (i = 0; i < param_count; i++)
+ if (strcmp(name, params[i].value.name) == 0)
+ return i;
+ assert(0 && "Parameter not found!");
+}
+
+static void readvalue(const uint8 *base,
+ const uint32 typeoffset,
+ const uint32 valoffset,
+ MOJOSHADER_effectValue *value,
+ MOJOSHADER_effectObject *objects,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ const uint8 *typeptr = base + typeoffset;
+ const uint8 *valptr = base + valoffset;
+ unsigned int typelen = 9999999; // !!! FIXME
+ const uint32 type = readui32(&typeptr, &typelen);
+ const uint32 valclass = readui32(&typeptr, &typelen);
+ const uint32 name = readui32(&typeptr, &typelen);
+ const uint32 semantic = readui32(&typeptr, &typelen);
+ const uint32 numelements = readui32(&typeptr, &typelen);
+
+ value->value_type = (MOJOSHADER_symbolType) type;
+ value->value_class = (MOJOSHADER_symbolClass) valclass;
+ value->name = readstring(base, name, m, d);
+ value->semantic = readstring(base, semantic, m, d);
+ value->element_count = numelements;
+
+ /* Class sanity check */
+ assert(valclass >= MOJOSHADER_SYMCLASS_SCALAR && valclass <= MOJOSHADER_SYMCLASS_STRUCT);
+
+ if (valclass == MOJOSHADER_SYMCLASS_SCALAR
+ || valclass == MOJOSHADER_SYMCLASS_VECTOR
+ || valclass == MOJOSHADER_SYMCLASS_MATRIX_ROWS
+ || valclass == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS)
+ {
+ /* These classes only ever contain scalar values */
+ assert(type >= MOJOSHADER_SYMTYPE_BOOL && type <= MOJOSHADER_SYMTYPE_FLOAT);
+
+ const uint32 columncount = readui32(&typeptr, &typelen);
+ const uint32 rowcount = readui32(&typeptr, &typelen);
+
+ value->column_count = columncount;
+ value->row_count = rowcount;
+
+ uint32 siz = columncount * rowcount;
+ if (numelements > 0)
+ siz *= numelements;
+ value->value_count = siz;
+ siz *= 4;
+ value->values = m(siz, d);
+ memcpy(value->values, valptr, siz);
+ } // if
+ else if (valclass == MOJOSHADER_SYMCLASS_OBJECT)
+ {
+ /* This class contains either samplers or "objects" */
+ assert(type >= MOJOSHADER_SYMTYPE_STRING && type <= MOJOSHADER_SYMTYPE_VERTEXSHADER);
+
+ if (type == MOJOSHADER_SYMTYPE_SAMPLER
+ || type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ {
+ unsigned int vallen = 9999999; // !!! FIXME
+ const uint32 numstates = readui32(&valptr, &vallen);
+
+ value->value_count = numstates;
+
+ const uint32 siz = sizeof(MOJOSHADER_effectSamplerState) * numstates;
+ value->values = m(siz, d);
+ memset(value->values, '\0', siz);
+
+ for (i = 0; i < numstates; i++)
+ {
+ MOJOSHADER_effectSamplerState *state = &value->valuesSS[i];
+ const uint32 stype = readui32(&valptr, &vallen) & ~0xA0;
+ /*const uint32 FIXME =*/ readui32(&valptr, &vallen);
+ const uint32 statetypeoffset = readui32(&valptr, &vallen);
+ const uint32 statevaloffset = readui32(&valptr, &vallen);
+
+ state->type = (MOJOSHADER_samplerStateType) stype;
+ readvalue(base, statetypeoffset, statevaloffset,
+ &state->value, objects,
+ m, d);
+ if (stype == MOJOSHADER_SAMP_TEXTURE)
+ objects[state->value.valuesI[0]].type = (MOJOSHADER_symbolType) type;
+ } // for
+ } // if
+ else
+ {
+ uint32 numobjects = 1;
+ if (numelements > 0)
+ numobjects = numelements;
+
+ value->value_count = numobjects;
+
+ const uint32 siz = 4 * numobjects;
+ value->values = m(siz, d);
+ memcpy(value->values, valptr, siz);
+
+ for (i = 0; i < value->value_count; i++)
+ objects[value->valuesI[i]].type = (MOJOSHADER_symbolType) type;
+ } // else
+ } // else if
+ else if (valclass == MOJOSHADER_SYMCLASS_STRUCT)
+ {
+ /* TODO: Maybe this is like parse_ctab_typeinfo? -flibit */
+ assert(0 && "Effect struct value parsing not implemented!");
+ } // else if
+} // readvalue
+
+static void readannotations(const uint32 numannos,
+ const uint8 *base,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effectAnnotation **annotations,
+ MOJOSHADER_effectObject *objects,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ if (numannos == 0) return;
+
+ const uint32 siz = sizeof(MOJOSHADER_effectAnnotation) * numannos;
+ *annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
+ memset(*annotations, '\0', siz);
+
+ for (i = 0; i < numannos; i++)
+ {
+ MOJOSHADER_effectAnnotation *anno = &(*annotations)[i];
+
+ const uint32 typeoffset = readui32(ptr, len);
+ const uint32 valoffset = readui32(ptr, len);
+
+ readvalue(base, typeoffset, valoffset,
+ anno, objects,
+ m, d);
+ } // for
+} // readannotation
+
+static void readparameters(const uint32 numparams,
+ const uint8 *base,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effectParam **params,
+ MOJOSHADER_effectObject *objects,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ if (numparams == 0) return;
+
+ uint32 siz = sizeof(MOJOSHADER_effectParam) * numparams;
+ *params = (MOJOSHADER_effectParam *) m(siz, d);
+ memset(*params, '\0', siz);
+
+ for (i = 0; i < numparams; i++)
+ {
+ MOJOSHADER_effectParam *param = &(*params)[i];
+
+ const uint32 typeoffset = readui32(ptr, len);
+ const uint32 valoffset = readui32(ptr, len);
+ /*const uint32 flags =*/ readui32(ptr, len);
+ const uint32 numannos = readui32(ptr, len);
+
+ param->annotation_count = numannos;
+ readannotations(numannos, base, ptr, len,
+ ¶m->annotations, objects,
+ m, d);
+
+ readvalue(base, typeoffset, valoffset,
+ ¶m->value, objects,
+ m, d);
+ } // for
+} // readparameters
+
+static void readstates(const uint32 numstates,
+ const uint8 *base,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effectState **states,
+ MOJOSHADER_effectObject *objects,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ if (numstates == 0) return;
+
+ const uint32 siz = sizeof (MOJOSHADER_effectState) * numstates;
+ *states = (MOJOSHADER_effectState *) m(siz, d);
+ memset(*states, '\0', siz);
+
+ for (i = 0; i < numstates; i++)
+ {
+ MOJOSHADER_effectState *state = &(*states)[i];
+
+ const uint32 type = readui32(ptr, len);
+ /*const uint32 FIXME =*/ readui32(ptr, len);
+ const uint32 typeoffset = readui32(ptr, len);
+ const uint32 valoffset = readui32(ptr, len);
+
+ state->type = (MOJOSHADER_renderStateType) type;
+ readvalue(base, typeoffset, valoffset,
+ &state->value, objects,
+ m, d);
+ } // for
+} // readstates
+
+static void readpasses(const uint32 numpasses,
+ const uint8 *base,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effectPass **passes,
+ MOJOSHADER_effectObject *objects,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ if (numpasses == 0) return;
+
+ const uint32 siz = sizeof (MOJOSHADER_effectPass) * numpasses;
+ *passes = (MOJOSHADER_effectPass *) m(siz, d);
+ memset(*passes, '\0', siz);
+
+ for (i = 0; i < numpasses; i++)
+ {
+ MOJOSHADER_effectPass *pass = &(*passes)[i];
+
+ const uint32 passnameoffset = readui32(ptr, len);
+ const uint32 numannos = readui32(ptr, len);
+ const uint32 numstates = readui32(ptr, len);
+
+ pass->name = readstring(base, passnameoffset, m, d);
+
+ pass->annotation_count = numannos;
+ readannotations(numannos, base, ptr, len,
+ &pass->annotations, objects,
+ m, d);
+
+ pass->state_count = numstates;
+ readstates(numstates, base, ptr, len,
+ &pass->states, objects,
+ m, d);
+ } // for
+} // readpasses
+
+static void readtechniques(const uint32 numtechniques,
+ const uint8 *base,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effectTechnique **techniques,
+ MOJOSHADER_effectObject *objects,
+ MOJOSHADER_malloc m,
+ void *d)
{
+ int i;
+ if (numtechniques == 0) return;
+
+ const uint32 siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
+ *techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
+ memset(*techniques, '\0', siz);
+
+ for (i = 0; i < numtechniques; i++)
+ {
+ MOJOSHADER_effectTechnique *technique = &(*techniques)[i];
+
+ const uint32 nameoffset = readui32(ptr, len);
+ const uint32 numannos = readui32(ptr, len);
+ const uint32 numpasses = readui32(ptr, len);
+
+ technique->name = readstring(base, nameoffset, m, d);
+
+ technique->annotation_count = numannos;
+ readannotations(numannos, base, ptr, len,
+ &technique->annotations, objects,
+ m, d);
+
+ technique->pass_count = numpasses;
+ readpasses(numpasses, base, ptr, len,
+ &technique->passes, objects,
+ m, d);
+ } // for
+} // readtechniques
+
+static void readsmallobjects(const uint32 numsmallobjects,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effect *effect,
+ const char *profile,
+ const MOJOSHADER_swizzle *swiz,
+ const unsigned int swizcount,
+ const MOJOSHADER_samplerMap *smap,
+ const unsigned int smapcount,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d)
+{
+ int i, j;
+ if (numsmallobjects == 0) return;
+
+ for (i = 1; i < numsmallobjects + 1; i++)
+ {
+ const uint32 index = readui32(ptr, len);
+ const uint32 length = readui32(ptr, len);
+
+ MOJOSHADER_effectObject *object = &effect->objects[index];
+ if (object->type == MOJOSHADER_SYMTYPE_STRING)
+ {
+ if (length > 0)
+ {
+ char *str = (char *) m(length, d);
+ memcpy(str, *ptr, length);
+ object->string.string = str;
+ } // if
+ } // if
+ else if (object->type == MOJOSHADER_SYMTYPE_TEXTURE
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURE1D
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURE2D
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURE3D
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURECUBE)
+ {
+ // No-op. Why is this even here?
+ } // else if
+ else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ {
+ if (length > 0)
+ {
+ char *str = (char *) m(length, d);
+ memcpy(str, *ptr, length);
+ object->mapping.name = str;
+ } // if
+ } // else if
+ else if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ object->shader.technique = -1;
+ object->shader.pass = -1;
+ object->shader.shader = MOJOSHADER_parse(profile, *ptr, length,
+ swiz, swizcount, smap, smapcount,
+ m, f, d);
+ // !!! FIXME: check for errors.
+ for (j = 0; j < object->shader.shader->symbol_count; j++)
+ if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
+ object->shader.sampler_count++;
+ object->shader.param_count = object->shader.shader->symbol_count;
+ object->shader.params = (uint32 *) m(object->shader.param_count * sizeof (uint32), d);
+ object->shader.samplers = (MOJOSHADER_samplerStateRegister *) m(object->shader.sampler_count * sizeof (MOJOSHADER_samplerStateRegister), d);
+ uint32 curSampler = 0;
+ for (j = 0; j < object->shader.shader->symbol_count; j++)
+ {
+ int par = findparameter(effect->params,
+ effect->param_count,
+ object->shader.shader->symbols[j].name);
+ object->shader.params[j] = par;
+ if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
+ {
+ object->shader.samplers[curSampler].sampler_name = object->shader.shader->symbols[j].name;
+ object->shader.samplers[curSampler].sampler_register = object->shader.shader->symbols[j].register_index;
+ object->shader.samplers[curSampler].sampler_state_count = effect->params[par].value.value_count;
+ object->shader.samplers[curSampler].sampler_states = effect->params[par].value.valuesSS;
+ curSampler++;
+ } // if
+ } // for
+ if (object->shader.shader->preshader)
+ {
+ object->shader.preshader_param_count = object->shader.shader->preshader->symbol_count;
+ object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
+ for (j = 0; j < object->shader.shader->preshader->symbol_count; j++)
+ {
+ object->shader.preshader_params[j] = findparameter(effect->params,
+ effect->param_count,
+ object->shader.shader->preshader->symbols[j].name);
+ } // for
+ } // if
+ } // else if
+ else
+ {
+ assert(0 && "Small object type unknown!");
+ } // else
+
+ /* Object block is always a multiple of four */
+ const uint32 blocklen = (length + 3) - ((length - 1) % 4);
+ *ptr += blocklen;
+ *len -= blocklen;
+ } // for
+} // readstrings
+
+static void readlargeobjects(const uint32 numlargeobjects,
+ const uint32 numsmallobjects,
+ const uint8 **ptr,
+ uint32 *len,
+ MOJOSHADER_effect *effect,
+ const char *profile,
+ const MOJOSHADER_swizzle *swiz,
+ const unsigned int swizcount,
+ const MOJOSHADER_samplerMap *smap,
+ const unsigned int smapcount,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d)
+{
+ int i, j;
+ if (numlargeobjects == 0) return;
+
+ int numobjects = numsmallobjects + numlargeobjects + 1;
+ for (i = numsmallobjects + 1; i < numobjects; i++)
+ {
+ const uint32 technique = readui32(ptr, len);
+ const uint32 index = readui32(ptr, len);
+ /*const uint32 FIXME =*/ readui32(ptr, len);
+ const uint32 state = readui32(ptr, len);
+ const uint32 type = readui32(ptr, len);
+ const uint32 length = readui32(ptr, len);
+
+ uint32 objectIndex;
+ if (technique == -1)
+ objectIndex = effect->params[index].value.valuesSS[state].value.valuesI[0];
+ else
+ objectIndex = effect->techniques[technique].passes[index].states[state].value.valuesI[0];
+
+ MOJOSHADER_effectObject *object = &effect->objects[objectIndex];
+ if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ object->shader.technique = technique;
+ object->shader.pass = index;
+
+ const char *emitter = profile;
+ if (type == 2)
+ {
+ /* This is a standalone preshader!
+ * It exists solely for effect passes that do not use a single
+ * vertex/fragment shader.
+ */
+ object->shader.is_preshader = 1;
+ const uint32 start = *((uint32 *) *ptr) + 4;
+ const uint32 end = 24; // FIXME: Why? -flibit
+ const char *array = readstring(*ptr, 0, m, d);
+ object->shader.param_count = 1;
+ object->shader.params = (uint32 *) m(sizeof (uint32), d);
+ object->shader.params[0] = findparameter(effect->params,
+ effect->param_count,
+ array);
+ f((void *) array, d);
+ object->shader.preshader = MOJOSHADER_parsePreshader(*ptr + start, length - end,
+ m, f, d);
+ // !!! FIXME: check for errors.
+ object->shader.preshader_param_count = object->shader.preshader->symbol_count;
+ object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
+ for (j = 0; j < object->shader.preshader->symbol_count; j++)
+ {
+ object->shader.preshader_params[j] = findparameter(effect->params,
+ effect->param_count,
+ object->shader.preshader->symbols[j].name);
+ } // for
+ } // if
+ else
+ {
+ object->shader.shader = MOJOSHADER_parse(emitter, *ptr, length,
+ swiz, swizcount, smap, smapcount,
+ m, f, d);
+ // !!! FIXME: check for errors.
+ for (j = 0; j < object->shader.shader->symbol_count; j++)
+ if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
+ object->shader.sampler_count++;
+ object->shader.param_count = object->shader.shader->symbol_count;
+ object->shader.params = (uint32 *) m(object->shader.param_count * sizeof (uint32), d);
+ object->shader.samplers = (MOJOSHADER_samplerStateRegister *) m(object->shader.sampler_count * sizeof (MOJOSHADER_samplerStateRegister), d);
+ uint32 curSampler = 0;
+ for (j = 0; j < object->shader.shader->symbol_count; j++)
+ {
+ int par = findparameter(effect->params,
+ effect->param_count,
+ object->shader.shader->symbols[j].name);
+ object->shader.params[j] = par;
+ if (object->shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
+ {
+ object->shader.samplers[curSampler].sampler_name = object->shader.shader->symbols[j].name;
+ object->shader.samplers[curSampler].sampler_register = object->shader.shader->symbols[j].register_index;
+ object->shader.samplers[curSampler].sampler_state_count = effect->params[par].value.value_count;
+ object->shader.samplers[curSampler].sampler_states = effect->params[par].value.valuesSS;
+ curSampler++;
+ } // if
+ } // for
+ if (object->shader.shader->preshader)
+ {
+ object->shader.preshader_param_count = object->shader.shader->preshader->symbol_count;
+ object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
+ for (j = 0; j < object->shader.shader->preshader->symbol_count; j++)
+ {
+ object->shader.preshader_params[j] = findparameter(effect->params,
+ effect->param_count,
+ object->shader.shader->preshader->symbols[j].name);
+ } // for
+ } // if
+ }
+ } // if
+ else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ {
+ if (length > 0)
+ {
+ char *str = (char *) m(length, d);
+ memcpy(str, *ptr, length);
+ object->mapping.name = str;
+ } // if
+ } // else if
+ else if (object->type != MOJOSHADER_SYMTYPE_VOID) // FIXME: Why? -flibit
+ {
+ assert(0 && "Large object type unknown!");
+ } // else
+
+ /* Object block is always a multiple of four */
+ const uint32 blocklen = (length + 3) - ((length - 1) % 4);
+ *ptr += blocklen;
+ *len -= blocklen;
+ } // for
+} // readobjects
+
+MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
+ const unsigned char *buf,
+ const unsigned int _len,
+ const MOJOSHADER_swizzle *swiz,
+ const unsigned int swizcount,
+ const MOJOSHADER_samplerMap *smap,
+ const unsigned int smapcount,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d)
+{
+ const uint8 *ptr = (const uint8 *) buf;
+ uint32 len = (uint32) _len;
+
+ /* Supply both m and f, or neither */
if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
- return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
+ return &MOJOSHADER_out_of_mem_effect;
+ /* Use default malloc/free if m/f were not passed */
if (m == NULL) m = MOJOSHADER_internal_malloc;
if (f == NULL) f = MOJOSHADER_internal_free;
- MOJOSHADER_effect *retval = m(sizeof (MOJOSHADER_effect), d);
+ /* malloc base effect structure */
+ MOJOSHADER_effect *retval = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
if (retval == NULL)
- return &MOJOSHADER_out_of_mem_effect; // supply both or neither.
+ return &MOJOSHADER_out_of_mem_effect;
memset(retval, '\0', sizeof (*retval));
+ /* Store m/f/d in effect structure */
retval->malloc = m;
retval->free = f;
retval->malloc_data = d;
- const uint8 *ptr = (const uint8 *) buf;
- uint32 len = (uint32) _len;
- size_t siz = 0;
- int i, j, k;
-
if (len < 8)
goto parseEffect_unexpectedEOF;
+ /* Read in header magic, seek to initial offset */
const uint8 *base = NULL;
- if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic?
+ uint32 header = readui32(&ptr, &len);
+ if (header == 0xBCF00BCF)
+ {
+ /* The Effect compiler provided with XNA4 adds some extra mess at the
+ * beginning of the file. It's useless though, so just skip it.
+ * -flibit
+ */
+ const uint32 skip = readui32(&ptr, &len) - 8;
+ ptr += skip;
+ len += skip;
+ header = readui32(&ptr, &len);
+ } // if
+ if (header != 0xFEFF0901)
goto parseEffect_notAnEffectsFile;
else
{
const uint32 offset = readui32(&ptr, &len);
base = ptr;
-//printf("base offset == %u\n", offset);
if (offset > len)
goto parseEffect_unexpectedEOF;
ptr += offset;
len -= offset;
} // else
- // params...
-
if (len < 16)
goto parseEffect_unexpectedEOF;
+ /* Parse structure counts */
const uint32 numparams = readui32(&ptr, &len);
const uint32 numtechniques = readui32(&ptr, &len);
-
- readui32(&ptr, &len); // !!! FIXME: there are 8 unknown bytes here. Annotations?
- /*const uint32 numobjects = */ readui32(&ptr, &len);
-
- if (numparams > 0)
- {
- siz = sizeof (MOJOSHADER_effectParam) * numparams;
- retval->params = (MOJOSHADER_effectParam *) m(siz, d);
- if (retval->params == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->params, '\0', siz);
-
- retval->param_count = numparams;
-
- for (i = 0; i < numparams; i++)
- {
- if (len < 16)
- goto parseEffect_unexpectedEOF;
-
- const uint32 typeoffset = readui32(&ptr, &len);
- /*const uint32 valoffset =*/ readui32(&ptr, &len);
- /*const uint32 flags =*/ readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- for (j = 0; j < numannos; j++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: parse annotations.
- readui32(&ptr, &len);
- readui32(&ptr, &len);
- } // for
-
- const uint8 *typeptr = base + typeoffset;
- unsigned int typelen = 9999999; // !!! FIXME
- /*const uint32 paramtype =*/ readui32(&typeptr, &typelen);
- /*const uint32 paramclass =*/ readui32(&typeptr, &typelen);
- const uint32 paramname = readui32(&typeptr, &typelen);
- const uint32 paramsemantic = readui32(&typeptr, &typelen);
+ /*const uint32 FIXME =*/ readui32(&ptr, &len);
+ const uint32 numobjects = readui32(&ptr, &len);
- // !!! FIXME: sanity checks!
- const char *namestr = ((const char *) base) + paramname;
- const char *semstr = ((const char *) base) + paramsemantic;
- uint32 len;
- char *strptr;
- len = *((const uint32 *) namestr);
- strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- retval->params[i].name = strptr;
- len = *((const uint32 *) semstr);
- strptr = (char *) m(len + 1, d);
- memcpy(strptr, semstr + 4, len);
- strptr[len] = '\0';
- retval->params[i].semantic = strptr;
- } // for
- } // if
-
- uint32 numshaders = 0; // we'll calculate this later.
-
- // techniques...
-
- if (numtechniques > 0)
- {
- siz = sizeof (MOJOSHADER_effectTechnique) * numtechniques;
- retval->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
- if (retval->techniques == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->techniques, '\0', siz);
-
- retval->technique_count = numtechniques;
-
- for (i = 0; i < numtechniques; i++)
- {
- if (len < 12)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectTechnique *technique = &retval->techniques[i];
-
- const uint32 nameoffset = readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- const uint32 numpasses = readui32(&ptr, &len);
-
- if (nameoffset >= _len)
- goto parseEffect_unexpectedEOF;
+ /* Alloc structures now, so object types can be stored */
+ retval->object_count = numobjects;
+ const uint32 siz = sizeof (MOJOSHADER_effectObject) * numobjects;
+ retval->objects = (MOJOSHADER_effectObject *) m(siz, d);
+ if (retval->objects == NULL)
+ goto parseEffect_outOfMemory;
+ memset(retval->objects, '\0', siz);
- if (numannos > 0)
- {
- // !!! FIXME: expose these to the caller?
- for (j = 0; j < numannos; j++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- readui32(&ptr, &len); // typedef offset
- readui32(&ptr, &len); // value offset
- } // for
- } // if
-
- // !!! FIXME: verify this doesn't go past EOF looking for a null.
- {
- const char *namestr = ((char *) base) + nameoffset;
- uint32 len = *((const uint32 *) namestr);
- char *strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- technique->name = strptr;
- }
-
- if (numpasses > 0)
- {
- technique->pass_count = numpasses;
-
- siz = sizeof (MOJOSHADER_effectPass) * numpasses;
- technique->passes = (MOJOSHADER_effectPass *) m(siz, d);
- if (technique->passes == NULL)
- goto parseEffect_outOfMemory;
- memset(technique->passes, '\0', siz);
-
- for (j = 0; j < numpasses; j++)
- {
- if (len < 12)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectPass *pass = &technique->passes[j];
-
- const uint32 passnameoffset = readui32(&ptr, &len);
- const uint32 numannos = readui32(&ptr, &len);
- const uint32 numstates = readui32(&ptr, &len);
-
- if (passnameoffset >= _len)
- goto parseEffect_unexpectedEOF;
+ /* Parse effect parameters */
+ retval->param_count = numparams;
+ readparameters(numparams, base, &ptr, &len,
+ &retval->params, retval->objects,
+ m, d);
- // !!! FIXME: verify this doesn't go past EOF looking for a null.
- {
- const char *namestr = ((char *) base) + passnameoffset;
- uint32 len = *((const uint32 *) namestr);
- char *strptr = (char *) m(len + 1, d);
- memcpy(strptr, namestr + 4, len);
- strptr[len] = '\0';
- pass->name = strptr;
- }
-
- if (numannos > 0)
- {
- for (k = 0; k < numannos; k++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
- // !!! FIXME: do something with this.
- readui32(&ptr, &len);
- readui32(&ptr, &len);
- } // for
- } // if
-
- if (numstates > 0)
- {
- pass->state_count = numstates;
+ /* Parse effect techniques */
+ retval->technique_count = numtechniques;
+ readtechniques(numtechniques, base, &ptr, &len,
+ &retval->techniques, retval->objects,
+ m, d);
- siz = sizeof (MOJOSHADER_effectState) * numstates;
- pass->states = (MOJOSHADER_effectState *) m(siz, d);
- if (pass->states == NULL)
- goto parseEffect_outOfMemory;
- memset(pass->states, '\0', siz);
-
- for (k = 0; k < numstates; k++)
- {
- if (len < 16)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectState *state = &pass->states[k];
- const uint32 type = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: don't know what this field does.
- /*const uint32 offsetend = */ readui32(&ptr, &len);
- /*const uint32 offsetstart = */ readui32(&ptr, &len);
- state->type = type;
-
- if ((type == 0x92) || (type == 0x93))
- numshaders++;
- } // for
- } // if
- } // for
- } // if
- } // for
- } // if
-
- // textures...
+ /* Initial effect technique/pass */
+ retval->current_technique = &retval->techniques[0];
+ retval->current_pass = -1;
if (len < 8)
goto parseEffect_unexpectedEOF;
- const int numtextures = readui32(&ptr, &len);
- const int numobjects = readui32(&ptr, &len); // !!! FIXME: "objects" for lack of a better word.
-
- if (numtextures > 0)
- {
- siz = sizeof (MOJOSHADER_effectTexture) * numtextures;
- retval->textures = m(siz, d);
- if (retval->textures == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->textures, '\0', siz);
-
- for (i = 0; i < numtextures; i++)
- {
- if (len < 8)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectTexture *texture = &retval->textures[i];
- const uint32 texparam = readui32(&ptr, &len);
- const uint32 texsize = readui32(&ptr, &len);
- // apparently texsize will pad out to 32 bits.
- const uint32 readsize = (((texsize + 3) / 4) * 4);
- if (len < readsize)
- goto parseEffect_unexpectedEOF;
-
- texture->param = texparam;
- char *str = m(texsize + 1, d);
- if (str == NULL)
- goto parseEffect_outOfMemory;
- memcpy(str, ptr, texsize);
- str[texsize] = '\0';
- texture->name = str;
-
- ptr += readsize;
- len -= readsize;
- } // for
- } // if
-
- // shaders...
-
- if (numshaders > 0)
- {
- siz = sizeof (MOJOSHADER_effectShader) * numshaders;
- retval->shaders = (MOJOSHADER_effectShader *) m(siz, d);
- if (retval->shaders == NULL)
- goto parseEffect_outOfMemory;
- memset(retval->shaders, '\0', siz);
-
- retval->shader_count = numshaders;
+ /* Parse object counts */
+ const int numsmallobjects = readui32(&ptr, &len);
+ const int numlargeobjects = readui32(&ptr, &len);
- // !!! FIXME: I wonder if we should pull these from offsets and not
- // !!! FIXME: count on them all being in a line like this.
- for (i = 0; i < numshaders; i++)
- {
- if (len < 24)
- goto parseEffect_unexpectedEOF;
-
- MOJOSHADER_effectShader *shader = &retval->shaders[i];
- const uint32 technique = readui32(&ptr, &len);
- const uint32 pass = readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: don't know what this does.
- readui32(&ptr, &len); // !!! FIXME: don't know what this does (vertex/pixel/geometry?)
- readui32(&ptr, &len); // !!! FIXME: don't know what this does.
- const uint32 shadersize = readui32(&ptr, &len);
-
- if (len < shadersize)
- goto parseEffect_unexpectedEOF;
-
- shader->technique = technique;
- shader->pass = pass;
- shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
- swiz, swizcount, smap, smapcount,
- m, f, d);
-
- // !!! FIXME: check for errors.
+ /* Parse "small" object table */
+ readsmallobjects(numsmallobjects, &ptr, &len,
+ retval,
+ profile, swiz, swizcount, smap, smapcount,
+ m, f, d);
- ptr += shadersize;
- len -= shadersize;
- } // for
- } // if
-
- // !!! FIXME: we parse this, but don't expose the data, yet.
- // mappings ...
- assert(numshaders <= numobjects);
- const uint32 nummappings = numobjects - numshaders;
- if (nummappings > 0)
- {
- for (i = 0; i < nummappings; i++)
- {
- if (len < 24)
- goto parseEffect_unexpectedEOF;
+ /* Parse "large" object table. */
+ readlargeobjects(numlargeobjects, numsmallobjects, &ptr, &len,
+ retval,
+ profile, swiz, swizcount, smap, smapcount,
+ m, f, d);
- /*const uint32 magic = */ readui32(&ptr, &len);
- /*const uint32 index = */ readui32(&ptr, &len);
- readui32(&ptr, &len); // !!! FIXME: what is this field?
- readui32(&ptr, &len); // !!! FIXME: what is this field?
- /*const uint32 type = */ readui32(&ptr, &len);
- const uint32 mapsize = readui32(&ptr, &len);
- if (mapsize > 0)
- {
- const uint32 readsize = (((mapsize + 3) / 4) * 4);
- if (len < readsize)
- goto parseEffect_unexpectedEOF;
- } // if
- } // for
- } // if
-
+ /* Store MojoShader profile in effect structure */
retval->profile = (char *) m(strlen(profile) + 1, d);
if (retval->profile == NULL)
goto parseEffect_outOfMemory;
@@ -560,7 +888,6 @@
return retval;
-
// !!! FIXME: do something with this.
parseEffect_notAnEffectsFile:
parseEffect_unexpectedEOF:
@@ -570,6 +897,22 @@
} // MOJOSHADER_parseEffect
+void freevalue(MOJOSHADER_effectValue *value, MOJOSHADER_free f, void *d)
+{
+ int i;
+ f((void *) value->name, d);
+ f((void *) value->semantic, d);
+ if (value->value_type == MOJOSHADER_SYMTYPE_SAMPLER
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ for (i = 0; i < value->value_count; i++)
+ freevalue(&value->valuesSS[i].value, f, d);
+ f(value->values, d);
+} // freevalue
+
+
void MOJOSHADER_freeEffect(const MOJOSHADER_effect *_effect)
{
MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
@@ -578,8 +921,9 @@
MOJOSHADER_free f = effect->free;
void *d = effect->malloc_data;
- int i, j;
+ int i, j, k;
+ /* Free errors */
for (i = 0; i < effect->error_count; i++)
{
f((void *) effect->errors[i].error, d);
@@ -587,39 +931,702 @@
} // for
f((void *) effect->errors, d);
+ /* Free profile string */
f((void *) effect->profile, d);
+ /* Free parameters, including annotations */
for (i = 0; i < effect->param_count; i++)
{
- f((void *) effect->params[i].name, d);
- f((void *) effect->params[i].semantic, d);
+ MOJOSHADER_effectParam *param = &effect->params[i];
+ freevalue(¶m->value, f, d);
+ for (j = 0; j < param->annotation_count; j++)
+ {
+ freevalue(¶m->annotations[j], f, d);
+ } // for
+ f((void *) param->annotations, d);
} // for
- f(effect->params, d);
+ f((void *) effect->params, d);
+ /* Free techniques, including passes and all annotations */
for (i = 0; i < effect->technique_count; i++)
{
MOJOSHADER_effectTechnique *technique = &effect->techniques[i];
f((void *) technique->name, d);
for (j = 0; j < technique->pass_count; j++)
{
- f((void *) technique->passes[j].name, d);
- f(technique->passes[j].states, d);
+ MOJOSHADER_effectPass *pass = &technique->passes[j];
+ f((void *) pass->name, d);
+ for (k = 0; k < pass->state_count; k++)
+ {
+ freevalue(&pass->states[k].value, f, d);
+ } // for
+ f((void *) pass->states, d);
+ for (k = 0; k < pass->annotation_count; k++)
+ {
+ freevalue(&pass->annotations[k], f, d);
+ } // for
+ f((void *) pass->annotations, d);
+ } // for
+ f((void *) technique->passes, d);
+ for (j = 0; j < technique->annotation_count; j++)
+ {
+ freevalue(&technique->annotations[j], f, d);
+ } // for
+ f((void *) technique->annotations, d);
+ } // for
+ f((void *) effect->techniques, d);
+
+ /* Free object table */
+ for (i = 0; i < effect->object_count; i++)
+ {
+ MOJOSHADER_effectObject *object = &effect->objects[i];
+ if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ if (object->shader.is_preshader)
+ MOJOSHADER_freePreshader(object->shader.preshader, f, d);
+ else
+ MOJOSHADER_freeParseData(object->shader.shader);
+ f((void *) object->shader.params, d);
+ f((void *) object->shader.samplers, d);
+ f((void *) object->shader.preshader_params, d);
+ } // if
+ else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ f((void *) object->mapping.name, d);
+ else if (object->type == MOJOSHADER_SYMTYPE_STRING)
+ f((void *) object->string.string, d);
+ } // for
+ f((void *) effect->objects, d);
+
+ /* Free base effect structure */
+ f((void *) effect, d);
+} // MOJOSHADER_freeEffect
+
+
+void copyvalue(MOJOSHADER_effectValue *dst,
+ MOJOSHADER_effectValue *src,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ uint32 siz = 0;
+ char *stringcopy = NULL;
+
+ // !!! FIXME: Out of memory check!
+ #define COPY_STRING(location) \
+ if (src->location != NULL) \
+ { \
+ siz = strlen(src->location) + 1; \
+ stringcopy = (char *) m(siz, d); \
+ strcpy(stringcopy, src->location); \
+ dst->location = stringcopy; \
+ } // if
+
+ COPY_STRING(name)
+ COPY_STRING(semantic)
+ dst->element_count = src->element_count;
+ dst->row_count = src->row_count;
+ dst->column_count = src->column_count;
+ dst->value_class = src->value_class;
+ dst->value_type = src->value_type;
+ dst->value_count = src->value_count;
+
+ if (dst->value_class == MOJOSHADER_SYMCLASS_SCALAR
+ || dst->value_class == MOJOSHADER_SYMCLASS_VECTOR
+ || dst->value_class == MOJOSHADER_SYMCLASS_MATRIX_ROWS
+ || dst->value_class == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS)
+ {
+ siz = dst->value_count * 4;
+ dst->values = m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(dst->values, src->values, siz);
+ } // if
+ else if (dst->value_class == MOJOSHADER_SYMCLASS_OBJECT)
+ {
+ if (dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || dst->value_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ {
+ siz = dst->value_count * sizeof (MOJOSHADER_effectSamplerState);
+ dst->values = m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(dst->values, '\0', siz);
+ for (i = 0; i < dst->value_count; i++)
+ {
+ dst->valuesSS[i].type = src->valuesSS[i].type;
+ copyvalue(&dst->valuesSS[i].value,
+ &src->valuesSS[i].value,
+ m, d);
+ } // for
+ } // if
+ else
+ {
+ siz = dst->value_count * 4;
+ dst->values = m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(dst->values, src->values, siz);
+ } // else
+ } // else if
+ else if (dst->value_class == MOJOSHADER_SYMCLASS_STRUCT)
+ {
+ /* TODO: See readvalue! -flibit */
+ } // else if
+
+ #undef COPY_STRING
+} // copyvalue
+
+
+void copysymbolinfo(MOJOSHADER_symbolTypeInfo *dst,
+ MOJOSHADER_symbolTypeInfo *src,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ uint32 siz;
+ char *stringcopy;
+
+ dst->parameter_class = src->parameter_class;
+ dst->parameter_type = src->parameter_type;
+ dst->rows = src->rows;
+ dst->columns = src->columns;
+ dst->elements = src->elements;
+ dst->member_count = src->member_count;
+
+ if (dst->member_count > 0)
+ {
+ siz = sizeof (MOJOSHADER_symbolStructMember) * dst->member_count;
+ dst->members = (MOJOSHADER_symbolStructMember *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ for (i = 0; i < dst->member_count; i++)
+ {
+ if (src->members[i].name != NULL)
+ {
+ siz = strlen(src->members[i].name) + 1;
+ stringcopy = (char *) m(siz, d);
+ strcpy(stringcopy, src->members[i].name);
+ dst->members[i].name = stringcopy;
+ } // if
+ copysymbolinfo(&dst->members[i].info, &src->members[i].info, m, d);
} // for
- f(technique->passes, d);
+ } // if
+} // copysymbolinfo
+
+
+void copysymbol(MOJOSHADER_symbol *dst,
+ MOJOSHADER_symbol *src,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ uint32 siz = strlen(src->name) + 1;
+ char *stringcopy = (char *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ strcpy(stringcopy, src->name);
+ dst->name = stringcopy;
+ dst->register_set = src->register_set;
+ dst->register_index = src->register_index;
+ dst->register_count = src->register_count;
+ copysymbolinfo(&dst->info, &src->info, m, d);
+} // copysymbol
+
+
+MOJOSHADER_preshader *copypreshader(const MOJOSHADER_preshader *src,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i, j;
+ uint32 siz;
+ MOJOSHADER_preshader *retval;
+
+ retval = (MOJOSHADER_preshader *) m(sizeof (MOJOSHADER_preshader), d);
+ // !!! FIXME: Out of memory check!
+ memset(retval, '\0', sizeof (MOJOSHADER_preshader));
+
+ siz = sizeof (double) * src->literal_count;
+ retval->literal_count = src->literal_count;
+ retval->literals = (double *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(retval->literals, src->literals, siz);
+
+ retval->temp_count = src->temp_count;
+
+ siz = sizeof (MOJOSHADER_symbol) * src->symbol_count;
+ retval->symbol_count = src->symbol_count;
+ retval->symbols = (MOJOSHADER_symbol *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->symbols, '\0', siz);
+
+ for (i = 0; i < retval->symbol_count; i++)
+ copysymbol(&retval->symbols[i], &src->symbols[i], m, d);
+
+ siz = sizeof (MOJOSHADER_preshaderInstruction) * src->instruction_count;
+ retval->instruction_count = src->instruction_count;
+ retval->instructions = (MOJOSHADER_preshaderInstruction *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(retval->instructions, src->instructions, siz);
+ for (i = 0; i < retval->instruction_count; i++)
+ for (j = 0; j < retval->instructions[i].operand_count; j++)
+ {
+ siz = sizeof (unsigned int) * retval->instructions[i].operands[j].array_register_count;
+ retval->instructions[i].operands[j].array_registers = (unsigned int *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(retval->instructions[i].operands[j].array_registers,
+ src->instructions[i].operands[j].array_registers,
+ siz);
+ } // for
+
+ siz = sizeof (float) * 4 * src->register_count;
+ retval->register_count = src->register_count;
+ retval->registers = (float *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(retval->registers, src->registers, siz);
+
+ return retval;
+} // copypreshader
+
+
+MOJOSHADER_parseData *copyparsedata(const MOJOSHADER_parseData *src,
+ MOJOSHADER_malloc m,
+ void *d)
+{
+ int i;
+ uint32 siz;
+ char *stringcopy;
+ MOJOSHADER_parseData *retval;
+
+ retval = (MOJOSHADER_parseData *) m(sizeof (MOJOSHADER_parseData), d);
+ memset(retval, '\0', sizeof (MOJOSHADER_parseData));
+
+ /* Copy malloc/free */
+ retval->malloc = src->malloc;
+ retval->free = src->free;
+ retval->malloc_data = src->malloc_data;
+
+ // !!! FIXME: Out of memory check!
+ #define COPY_STRING(location) \
+ siz = strlen(src->location) + 1; \
+ stringcopy = (char *) m(siz, d); \
+ strcpy(stringcopy, src->location); \
+ retval->location = stringcopy; \
+
+ /* Copy errors */
+ siz = sizeof (MOJOSHADER_error) * src->error_count;
+ retval->error_count = src->error_count;
+ retval->errors = (MOJOSHADER_error *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->errors, '\0', siz);
+ for (i = 0; i < retval->error_count; i++)
+ {
+ COPY_STRING(errors[i].error)
+ COPY_STRING(errors[i].filename)
+ retval->errors[i].error_position = src->errors[i].error_position;
+ } // for
+
+ /* Copy profile string constant */
+ retval->profile = src->profile;
+
+ /* Copy shader output */
+ retval->output_len = src->output_len;
+ stringcopy = (char *) m(src->output_len, d);
+ memcpy(stringcopy, src->output, src->output_len);
+ retval->output = stringcopy;
+
+ /* Copy miscellaneous shader info */
+ retval->instruction_count = src->instruction_count;
+ retval->shader_type = src->shader_type;
+ retval->major_ver = src->major_ver;
+ retval->minor_ver = src->minor_ver;
+
+ /* Copy uniforms */
+ siz = sizeof (MOJOSHADER_uniform) * src->uniform_count;
+ retval->uniform_count = src->uniform_count;
+ retval->uniforms = (MOJOSHADER_uniform *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->uniforms, '\0', siz);
+ for (i = 0; i < retval->uniform_count; i++)
+ {
+ retval->uniforms[i].type = src->uniforms[i].type;
+ retval->uniforms[i].index = src->uniforms[i].index;
+ retval->uniforms[i].array_count = src->uniforms[i].array_count;
+ retval->uniforms[i].constant = src->uniforms[i].constant;
+ COPY_STRING(uniforms[i].name)
+ } // for
+
+ /* Copy constants */
+ siz = sizeof (MOJOSHADER_constant) * src->constant_count;
+ retval->constant_count = src->constant_count;
+ retval->constants = (MOJOSHADER_constant *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(retval->constants, src->constants, siz);
+
+ /* Copy samplers */
+ siz = sizeof (MOJOSHADER_sampler) * src->sampler_count;
+ retval->sampler_count = src->sampler_count;
+ retval->samplers = (MOJOSHADER_sampler *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->samplers, '\0', siz);
+ for (i = 0; i < retval->sampler_count; i++)
+ {
+ retval->samplers[i].type = src->samplers[i].type;
+ retval->samplers[i].index = src->samplers[i].index;
+ COPY_STRING(samplers[i].name)
+ retval->samplers[i].texbem = src->samplers[i].texbem;
+ } // for
+
+ /* Copy attributes */
+ siz = sizeof (MOJOSHADER_attribute) * src->attribute_count;
+ retval->attribute_count = src->attribute_count;
+ retval->attributes = (MOJOSHADER_attribute *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->attributes, '\0', siz);
+ for (i = 0; i < retval->attribute_count; i++)
+ {
+ retval->attributes[i].usage = src->attributes[i].usage;
+ retval->attributes[i].index = src->attributes[i].index;
+ COPY_STRING(attributes[i].name)
} // for
- f(effect->techniques, d);
+ /* Copy outputs */
+ siz = sizeof (MOJOSHADER_attribute) * src->output_count;
+ retval->output_count = src->output_count;
+ retval->outputs = (MOJOSHADER_attribute *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->outputs, '\0', siz);
+ for (i = 0; i < retval->output_count; i++)
+ {
+ retval->outputs[i].usage = src->outputs[i].usage;
+ retval->outputs[i].index = src->outputs[i].index;
+ COPY_STRING(outputs[i].name)
+ } // for
+
+ #undef COPY_STRING
+
+ /* Copy swizzles */
+ siz = sizeof (MOJOSHADER_swizzle) * src->swizzle_count;
+ retval->swizzle_count = src->swizzle_count;
+ retval->swizzles = (MOJOSHADER_swizzle *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memcpy(retval->swizzles, src->swizzles, siz);
+
+ /* Copy symbols */
+ siz = sizeof (MOJOSHADER_symbol) * src->symbol_count;
+ retval->symbol_count = src->symbol_count;
+ retval->symbols = (MOJOSHADER_symbol *) m(siz, d);
+ // !!! FIXME: Out of memory check!
+ memset(retval->symbols, '\0', siz);
+ for (i = 0; i < retval->symbol_count; i++)
+ copysymbol(&retval->symbols[i], &src->symbols[i], m, d);
+
+ /* Copy preshader */
+ if (src->preshader != NULL)
+ retval->preshader = copypreshader(src->preshader, m, d);
+
+ return retval;
+} // copyparsedata
+
+
+MOJOSHADER_effect *MOJOSHADER_cloneEffect(const MOJOSHADER_effect *effect)
+{
+ int i, j, k;
+ MOJOSHADER_effect *clone;
+ MOJOSHADER_malloc m = effect->malloc;
+ void *d = effect->malloc_data;
+ uint32 siz = 0;
+ char *stringcopy = NULL;
+ uint32 curSampler;
+
+ if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
+ return NULL; // no-op.
+
+ clone = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
+ if (clone == NULL)
+ return NULL; // Maybe out_of_mem_effect instead?
+ memset(clone, '\0', sizeof (MOJOSHADER_effect));
+
+ /* Copy malloc/free */
+ clone->malloc = effect->malloc;
+ clone->free = effect->free;
+ clone->malloc_data = effect->malloc_data;
+
+ #define COPY_STRING(location) \
+ siz = strlen(effect->location) + 1; \
+ stringcopy = (char *) m(siz, d); \
+ if (stringcopy == NULL) \
+ goto cloneEffect_outOfMemory; \
+ strcpy(stringcopy, effect->location); \
+ clone->location = stringcopy; \
- for (i = 0; i < effect->texture_count; i++)
- f((void *) effect->textures[i].name, d);
- f(effect->textures, d);
+ /* Copy errors */
+ siz = sizeof (MOJOSHADER_error) * effect->error_count;
+ clone->error_count = effect->error_count;
+ clone->errors = (MOJOSHADER_error *) m(siz, d);
+ if (clone->errors == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->errors, '\0', siz);
+ for (i = 0; i < clone->error_count; i++)
+ {
+ COPY_STRING(errors[i].error)
+ COPY_STRING(errors[i].filename)
+ clone->errors[i].error_position = effect->errors[i].error_position;
+ } // for
+
+ /* Copy profile string */
+ COPY_STRING(profile)
+
+ /* Copy parameters */
+ siz = sizeof (MOJOSHADER_effectParam) * effect->param_count;
+ clone->param_count = effect->param_count;
+ clone->params = (MOJOSHADER_effectParam *) m(siz, d);
+ if (clone->params == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->params, '\0', siz);
+ for (i = 0; i < clone->param_count; i++)
+ {
+ copyvalue(&clone->params[i].value, &effect->params[i].value, m, d);
+
+ /* Copy parameter annotations */
+ siz = sizeof (MOJOSHADER_effectAnnotation) * effect->params[i].annotation_count;
+ clone->params[i].annotation_count = effect->params[i].annotation_count;
+ clone->params[i].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
+ if (clone->params[i].annotations == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->params[i].annotations, '\0', siz);
+ for (j = 0; j < clone->params[i].annotation_count; j++)
+ copyvalue(&clone->params[i].annotations[j],
+ &effect->params[i].annotations[j],
+ m, d);
+ } // for
+
+ /* Copy techniques */
+ siz = sizeof (MOJOSHADER_effectTechnique) * effect->technique_count;
+ clone->technique_count = effect->technique_count;
+ clone->techniques = (MOJOSHADER_effectTechnique *) m(siz, d);
+ if (clone->techniques == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->techniques, '\0', siz);
+ for (i = 0; i < clone->technique_count; i++)
+ {
+ COPY_STRING(techniques[i].name)
+
+ /* Copy passes */
+ siz = sizeof (MOJOSHADER_effectPass) * effect->techniques[i].pass_count;
+ clone->techniques[i].pass_count = effect->techniques[i].pass_count;
+ clone->techniques[i].passes = (MOJOSHADER_effectPass *) m(siz, d);
+ if (clone->techniques[i].passes == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->techniques[i].passes, '\0', siz);
+ for (j = 0; j < clone->techniques[i].pass_count; j++)
+ {
+ COPY_STRING(techniques[i].passes[j].name)
+
+ /* Copy pass states */
+ siz = sizeof (MOJOSHADER_effectState) * effect->techniques[i].passes[j].state_count;
+ clone->techniques[i].passes[j].state_count = effect->techniques[i].passes[j].state_count;
+ clone->techniques[i].passes[j].states = (MOJOSHADER_effectState *) m(siz, d);
+ if (clone->techniques[i].passes[j].states == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->techniques[i].passes[j].states, '\0', siz);
+ for (k = 0; k < clone->techniques[i].passes[j].state_count; k++)
+ {
+ clone->techniques[i].passes[j].states[k].type = effect->techniques[i].passes[j].states[k].type;
+ copyvalue(&clone->techniques[i].passes[j].states[k].value,
+ &effect->techniques[i].passes[j].states[k].value,
+ m, d);
+ } // for
+
+ /* Copy pass annotations */
+ siz = sizeof (MOJOSHADER_effectAnnotation) * effect->techniques[i].passes[j].annotation_count;
+ clone->techniques[i].passes[j].annotation_count = effect->techniques[i].passes[j].annotation_count;
+ clone->techniques[i].passes[j].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
+ if (clone->techniques[i].passes[j].annotations == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->techniques[i].passes[j].annotations, '\0', siz);
+ for (k = 0; k < clone->techniques[i].passes[j].annotation_count; k++)
+ copyvalue(&clone->techniques[i].passes[j].annotations[k],
+ &effect->techniques[i].passes[j].annotations[k],
+ m, d);
+ } // for
- for (i = 0; i < effect->shader_count; i++)
- MOJOSHADER_freeParseData(effect->shaders[i].shader);
- f(effect->shaders, d);
+ /* Copy technique annotations */
+ siz = sizeof (MOJOSHADER_effectAnnotation) * effect->techniques[i].annotation_count;
+ clone->techniques[i].annotation_count = effect->techniques[i].annotation_count;
+ clone->techniques[i].annotations = (MOJOSHADER_effectAnnotation *) m(siz, d);
+ if (clone->techniques[i].annotations == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->techniques[i].annotations, '\0', siz);
+ for (j = 0; j < clone->techniques[i].annotation_count; j++)
+ copyvalue(&clone->techniques[i].annotations[j],
+ &effect->techniques[i].annotations[j],
+ m, d);
+ } // for
+
+ /* Copy the current technique/pass */
+ for (i = 0; i < effect->technique_count; i++)
+ if (&effect->techniques[i] == effect->current_technique)
+ {
+ clone->current_technique = &clone->techniques[i];
+ break;
+ } // if
+ assert(clone->current_technique != NULL);
+ clone->current_pass = effect->current_pass;
+ assert(clone->current_pass == -1);
+
+ /* Copy object table */
+ siz = sizeof (MOJOSHADER_effectObject) * effect->object_count;
+ clone->object_count = effect->object_count;
+ clone->objects = (MOJOSHADER_effectObject *) m(siz, d);
+ if (clone->objects == NULL)
+ goto cloneEffect_outOfMemory;
+ memset(clone->objects, '\0', siz);
+ for (i = 0; i < clone->object_count; i++)
+ {
+ clone->objects[i].type = effect->objects[i].type;
+ if (clone->objects[i].type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || clone->objects[i].type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ clone->objects[i].shader.technique = effect->objects[i].shader.technique;
+ clone->objects[i].shader.pass = effect->objects[i].shader.pass;
+ clone->objects[i].shader.is_preshader = effect->objects[i].shader.is_preshader;
+ siz = sizeof (uint32) * effect->objects[i].shader.preshader_param_count;
+ clone->objects[i].shader.preshader_param_count = effect->objects[i].shader.preshader_param_count;
+ clone->objects[i].shader.preshader_params = (uint32 *) m(siz, d);
+ memcpy(clone->objects[i].shader.preshader_params,
+ effect->objects[i].shader.preshader_params,
+ siz);
+ siz = sizeof (uint32) * effect->objects[i].shader.param_count;
+ clone->objects[i].shader.param_count = effect->objects[i].shader.param_count;
+ clone->objects[i].shader.params = (uint32 *) m(siz, d);
+ memcpy(clone->objects[i].shader.params,
+ effect->objects[i].shader.params,
+ siz);
+
+ if (clone->objects[i].shader.is_preshader)
+ {
+ clone->objects[i].shader.preshader = copypreshader(effect->objects[i].shader.preshader,
+ m, d);
+ continue;
+ } // if
+
+ clone->objects[i].shader.shader = copyparsedata(effect->objects[i].shader.shader,
+ m, d);
- f(effect, d);
-} // MOJOSHADER_freeEffect
+ siz = sizeof (MOJOSHADER_samplerStateRegister) * effect->objects[i].shader.sampler_count;
+ clone->objects[i].shader.sampler_count = effect->objects[i].shader.sampler_count;
+ clone->objects[i].shader.samplers = (MOJOSHADER_samplerStateRegister *) m(siz, d);
+ if (clone->objects[i].shader.samplers == NULL)
+ goto cloneEffect_outOfMemory;
+ curSampler = 0;
+ for (j = 0; j < clone->objects[i].shader.shader->symbol_count; j++)
+ if (clone->objects[i].shader.shader->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
+ {
+ clone->objects[i].shader.samplers[curSampler].sampler_name = clone->objects[i].shader.shader->symbols[j].name;
+ clone->objects[i].shader.samplers[curSampler].sampler_register = clone->objects[i].shader.shader->symbols[j].register_index;
+ clone->objects[i].shader.samplers[curSampler].sampler_state_count = clone->params[clone->objects[i].shader.params[j]].value.value_count;
+ clone->objects[i].shader.samplers[curSampler].sampler_states = clone->params[clone->objects[i].shader.params[j]].value.valuesSS;
+ curSampler++;
+ } // if
+ } // if
+ else if (clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER
+ || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || clone->objects[i].type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ {
+ COPY_STRING(objects[i].mapping.name)
+ } // else if
+ else if (clone->objects[i].type == MOJOSHADER_SYMTYPE_STRING)
+ {
+ COPY_STRING(objects[i].string.string)
+ } // else if
+ } // for
+
+ #undef COPY_STRING
+
+ return clone;
+
+cloneEffect_outOfMemory:
+ MOJOSHADER_freeEffect(clone);
+ return NULL;
+} // MOJOSHADER_cloneEffect
+
+
+void MOJOSHADER_effectSetRawValueHandle(const MOJOSHADER_effectParam *parameter,
+ const void *data,
+ const unsigned int offset,
+ const unsigned int len)
+{
+ // !!! FIXME: uint32* case is arbitary, for Win32 -flibit
+ memcpy((uint32 *) parameter->value.values + offset, data, len);
+} // MOJOSHADER_effectSetRawValueHandle
+
+
+void MOJOSHADER_effectSetRawValueName(const MOJOSHADER_effect *effect,
+ const char *name,
+ const void *data,
+ const unsigned int offset,
+ const unsigned int len)
+{
+ int i;
+ for (i = 0; i < effect->param_count; i++)
+ {
+ if (strcmp(name, effect->params[i].value.name) == 0)
+ {
+ // !!! FIXME: uint32* case is arbitary, for Win32 -flibit
+ memcpy((uint32 *) effect->params[i].value.values + offset, data, len);
+ return;
+ } // if
+ } // for
+ assert(0 && "Effect parameter not found!");
+} // MOJOSHADER_effectSetRawValueName
+
+
+const MOJOSHADER_effectTechnique *MOJOSHADER_effectGetCurrentTechnique(const MOJOSHADER_effect *effect)
+{
+ return effect->current_technique;
+} // MOJOSHADER_effectGetCurrentTechnique
+
+
+void MOJOSHADER_effectSetTechnique(MOJOSHADER_effect *effect,
+ const MOJOSHADER_effectTechnique *technique)
+{
+ int i;
+ for (i = 0; i < effect->technique_count; i++)
+ {
+ if (technique == &effect->techniques[i])
+ {
+ effect->current_technique = technique;
+ return;
+ } // if
+ } // for
+ assert(0 && "Technique is not part of this effect!");
+} // MOJOSHADER_effectSetTechnique
+
+
+const MOJOSHADER_effectTechnique *MOJOSHADER_effectFindNextValidTechnique(const MOJOSHADER_effect *effect,
+ const MOJOSHADER_effectTechnique *technique
+)
+{
+ int i;
+ if (technique == NULL)
+ return &effect->techniques[0];
+ for (i = 0; i < effect->technique_count; i++)
+ {
+ if (technique == &effect->techniques[i])
+ {
+ if (i == effect->technique_count - 1)
+ return NULL; /* We were passed the last technique! */
+ return &effect->techniques[i + 1];
+ } // if
+ } // for
+ assert(0 && "Technique is not part of this effect!");
+} // MOJOSHADER_effectFindNextValidTechnique
+
+#endif // MOJOSHADER_EFFECT_SUPPORT
// end of mojoshader_effects.c ...
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mojoshader_effects.h Fri Jan 01 02:12:19 2016 -0500
@@ -0,0 +1,809 @@
+/**
+ * MojoShader; generate shader programs from bytecode of compiled
+ * Direct3D shaders.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon.
+ */
+
+#ifndef MOJOSHADER_EFFECTS_H
+#define MOJOSHADER_EFFECTS_H
+
+#ifdef MOJOSHADER_EFFECT_SUPPORT
+
+/* MOJOSHADER_effectState types... */
+
+typedef enum MOJOSHADER_renderStateType
+{
+ /* Note that we are NOT using the actual RS values from D3D here.
+ * For some reason, in the binary data, it's 0-based.
+ * Even worse, it doesn't even seem to be in order.
+ * Here is the list of changes compared to the real D3DRS enum:
+ * - All of the RS_WRAP values are in a row, not separate!
+ *
+ * -flibit
+ */
+ MOJOSHADER_RS_ZENABLE,
+ MOJOSHADER_RS_FILLMODE,
+ MOJOSHADER_RS_SHADEMODE,
+ MOJOSHADER_RS_ZWRITEENABLE,
+ MOJOSHADER_RS_ALPHATESTENABLE,
+ MOJOSHADER_RS_LASTPIXEL,
+ MOJOSHADER_RS_SRCBLEND,
+ MOJOSHADER_RS_DESTBLEND,
+ MOJOSHADER_RS_CULLMODE,
+ MOJOSHADER_RS_ZFUNC,
+ MOJOSHADER_RS_ALPHAREF,
+ MOJOSHADER_RS_ALPHAFUNC,
+ MOJOSHADER_RS_DITHERENABLE,
+ MOJOSHADER_RS_ALPHABLENDENABLE,
+ MOJOSHADER_RS_FOGENABLE,
+ MOJOSHADER_RS_SPECULARENABLE,
+ MOJOSHADER_RS_FOGCOLOR,
+ MOJOSHADER_RS_FOGTABLEMODE,
+ MOJOSHADER_RS_FOGSTART,
+ MOJOSHADER_RS_FOGEND,
+ MOJOSHADER_RS_FOGDENSITY,
+ MOJOSHADER_RS_RANGEFOGENABLE,
+ MOJOSHADER_RS_STENCILENABLE,
+ MOJOSHADER_RS_STENCILFAIL,
+ MOJOSHADER_RS_STENCILZFAIL,
+ MOJOSHADER_RS_STENCILPASS,
+ MOJOSHADER_RS_STENCILFUNC,
+ MOJOSHADER_RS_STENCILREF,
+ MOJOSHADER_RS_STENCILMASK,
+ MOJOSHADER_RS_STENCILWRITEMASK,
+ MOJOSHADER_RS_TEXTUREFACTOR,
+ MOJOSHADER_RS_WRAP0,
+ MOJOSHADER_RS_WRAP1,
+ MOJOSHADER_RS_WRAP2,
+ MOJOSHADER_RS_WRAP3,
+ MOJOSHADER_RS_WRAP4,
+ MOJOSHADER_RS_WRAP5,
+ MOJOSHADER_RS_WRAP6,
+ MOJOSHADER_RS_WRAP7,
+ MOJOSHADER_RS_WRAP8,
+ MOJOSHADER_RS_WRAP9,
+ MOJOSHADER_RS_WRAP10,
+ MOJOSHADER_RS_WRAP11,
+ MOJOSHADER_RS_WRAP12,
+ MOJOSHADER_RS_WRAP13,
+ MOJOSHADER_RS_WRAP14,
+ MOJOSHADER_RS_WRAP15,
+ MOJOSHADER_RS_CLIPPING,
+ MOJOSHADER_RS_LIGHTING,
+ MOJOSHADER_RS_AMBIENT,
+ MOJOSHADER_RS_FOGVERTEXMODE,
+ MOJOSHADER_RS_COLORVERTEX,
+ MOJOSHADER_RS_LOCALVIEWER,
+ MOJOSHADER_RS_NORMALIZENORMALS,
+ MOJOSHADER_RS_DIFFUSEMATERIALSOURCE,
+ MOJOSHADER_RS_SPECULARMATERIALSOURCE,
+ MOJOSHADER_RS_AMBIENTMATERIALSOURCE,
+ MOJOSHADER_RS_EMISSIVEMATERIALSOURCE,
+ MOJOSHADER_RS_VERTEXBLEND,
+ MOJOSHADER_RS_CLIPPLANEENABLE,
+ MOJOSHADER_RS_POINTSIZE,
+ MOJOSHADER_RS_POINTSIZE_MIN,
+ MOJOSHADER_RS_POINTSPRITEENABLE,
+ MOJOSHADER_RS_POINTSCALEENABLE,
+ MOJOSHADER_RS_POINTSCALE_A,
+ MOJOSHADER_RS_POINTSCALE_B,
+ MOJOSHADER_RS_POINTSCALE_C,
+ MOJOSHADER_RS_MULTISAMPLEANTIALIAS,
+ MOJOSHADER_RS_MULTISAMPLEMASK,
+ MOJOSHADER_RS_PATCHEDGESTYLE,
+ MOJOSHADER_RS_DEBUGMONITORTOKEN,
+ MOJOSHADER_RS_POINTSIZE_MAX,
+ MOJOSHADER_RS_INDEXEDVERTEXBLENDENABLE,
+ MOJOSHADER_RS_COLORWRITEENABLE,
+ MOJOSHADER_RS_TWEENFACTOR,
+ MOJOSHADER_RS_BLENDOP,
+ MOJOSHADER_RS_POSITIONDEGREE,
+ MOJOSHADER_RS_NORMALDEGREE,
+ MOJOSHADER_RS_SCISSORTESTENABLE,
+ MOJOSHADER_RS_SLOPESCALEDEPTHBIAS,
+ MOJOSHADER_RS_ANTIALIASEDLINEENABLE,
+ MOJOSHADER_RS_MINTESSELLATIONLEVEL,
+ MOJOSHADER_RS_MAXTESSELLATIONLEVEL,
+ MOJOSHADER_RS_ADAPTIVETESS_X,
+ MOJOSHADER_RS_ADAPTIVETESS_Y,
+ MOJOSHADER_RS_ADAPTIVETESS_Z,
+ MOJOSHADER_RS_ADAPTIVETESS_W,
+ MOJOSHADER_RS_ENABLEADAPTIVETESSELLATION,
+ MOJOSHADER_RS_TWOSIDEDSTENCILMODE,
+ MOJOSHADER_RS_CCW_STENCILFAIL,
+ MOJOSHADER_RS_CCW_STENCILZFAIL,
+ MOJOSHADER_RS_CCW_STENCILPASS,
+ MOJOSHADER_RS_CCW_STENCILFUNC,
+ MOJOSHADER_RS_COLORWRITEENABLE1,
+ MOJOSHADER_RS_COLORWRITEENABLE2,
+ MOJOSHADER_RS_COLORWRITEENABLE3,
+ MOJOSHADER_RS_BLENDFACTOR,
+ MOJOSHADER_RS_SRGBWRITEENABLE,
+ MOJOSHADER_RS_DEPTHBIAS,
+ MOJOSHADER_RS_SEPARATEALPHABLENDENABLE,
+ MOJOSHADER_RS_SRCBLENDALPHA,
+ MOJOSHADER_RS_DESTBLENDALPHA,
+ MOJOSHADER_RS_BLENDOPALPHA,
+
+ /* These aren't really "states", but these numbers are
+ * referred to by MOJOSHADER_effectStateType as such.
+ */
+ MOJOSHADER_RS_VERTEXSHADER = 146,
+ MOJOSHADER_RS_PIXELSHADER = 147
+} MOJOSHADER_renderStateType;
+
+typedef enum MOJOSHADER_zBufferType
+{
+ MOJOSHADER_ZB_FALSE,
+ MOJOSHADER_ZB_TRUE,
+ MOJOSHADER_ZB_USEW
+} MOJOSHADER_zBufferType;
+
+typedef enum MOJOSHADER_fillMode
+{
+ MOJOSHADER_FILL_POINT = 1,
+ MOJOSHADER_FILL_WIREFRAME = 2,
+ MOJOSHADER_FILL_SOLID = 3
+} MOJOSHADER_fillMode;
+
+typedef enum MOJOSHADER_shadeMode
+{
+ MOJOSHADER_SHADE_FLAT = 1,
+ MOJOSHADER_SHADE_GOURAUD = 2,
+ MOJOSHADER_SHADE_PHONG = 3,
+} MOJOSHADER_shadeMode;
+
+typedef enum MOJOSHADER_blendMode
+{
+ MOJOSHADER_BLEND_ZERO = 1,
+ MOJOSHADER_BLEND_ONE = 2,
+ MOJOSHADER_BLEND_SRCCOLOR = 3,
+ MOJOSHADER_BLEND_INVSRCCOLOR = 4,
+ MOJOSHADER_BLEND_SRCALPHA = 5,
+ MOJOSHADER_BLEND_INVSRCALPHA = 6,
+ MOJOSHADER_BLEND_DESTALPHA = 7,
+ MOJOSHADER_BLEND_INVDESTALPHA = 8,
+ MOJOSHADER_BLEND_DESTCOLOR = 9,
+ MOJOSHADER_BLEND_INVDESTCOLOR = 10,
+ MOJOSHADER_BLEND_SRCALPHASAT = 11,
+ MOJOSHADER_BLEND_BOTHSRCALPHA = 12,
+ MOJOSHADER_BLEND_BOTHINVSRCALPHA = 13,
+ MOJOSHADER_BLEND_BLENDFACTOR = 14,
+ MOJOSHADER_BLEND_INVBLENDFACTOR = 15,
+ MOJOSHADER_BLEND_SRCCOLOR2 = 16,
+ MOJOSHADER_BLEND_INVSRCCOLOR2 = 17
+} MOJOSHADER_blendMode;
+
+typedef enum MOJOSHADER_cullMode
+{
+ MOJOSHADER_CULL_NONE = 1,
+ MOJOSHADER_CULL_CW = 2,
+ MOJOSHADER_CULL_CCW = 3
+} MOJOSHADER_cullMode;
+
+typedef enum MOJOSHADER_compareFunc
+{
+ MOJOSHADER_CMP_NEVER = 1,
+ MOJOSHADER_CMP_LESS = 2,
+ MOJOSHADER_CMP_EQUAL = 3,
+ MOJOSHADER_CMP_LESSEQUAL = 4,
+ MOJOSHADER_CMP_GREATER = 5,
+ MOJOSHADER_CMP_NOTEQUAL = 6,
+ MOJOSHADER_CMP_GREATEREQUAL = 7,
+ MOJOSHADER_CMP_ALWAYS = 8
+} MOJOSHADER_compareFunc;
+
+typedef enum MOJOSHADER_fogMode
+{
+ MOJOSHADER_FOG_NONE,
+ MOJOSHADER_FOG_EXP,
+ MOJOSHADER_FOG_EXP2,
+ MOJOSHADER_FOG_LINEAR
+} MOJOSHADER_fogMode;
+
+typedef enum MOJOSHADER_stencilOp
+{
+ MOJOSHADER_STENCILOP_KEEP = 1,
+ MOJOSHADER_STENCILOP_ZERO = 2,
+ MOJOSHADER_STENCILOP_REPLACE = 3,
+ MOJOSHADER_STENCILOP_INCRSAT = 4,
+ MOJOSHADER_STENCILOP_DECRSAT = 5,
+ MOJOSHADER_STENCILOP_INVERT = 6,
+ MOJOSHADER_STENCILOP_INCR = 7,
+ MOJOSHADER_STENCILOP_DECR = 8
+} MOJOSHADER_stencilOp;
+
+typedef enum MOJOSHADER_materialColorSource
+{
+ MOJOSHADER_MCS_MATERIAL,
+ MOJOSHADER_MCS_COLOR1,
+ MOJOSHADER_MCS_COLOR2
+} MOJOSHADER_materialColorSource;
+
+typedef enum MOJOSHADER_vertexBlendFlags
+{
+ MOJOSHADER_VBF_DISABLE = 0,
+ MOJOSHADER_VBF_1WEIGHTS = 1,
+ MOJOSHADER_VBF_2WEIGHTS = 2,
+ MOJOSHADER_VBF_3WEIGHTS = 3,
+ MOJOSHADER_VBF_TWEENING = 255,
+ MOJOSHADER_VBF_0WEIGHTS = 256,
+} MOJOSHADER_vertexBlendFlags;
+
+typedef enum MOJOSHADER_patchedEdgeStyle
+{
+ MOJOSHADER_PATCHEDGE_DISCRETE,
+ MOJOSHADER_PATCHEDGE_CONTINUOUS
+} MOJOSHADER_patchedEdgeStyle;
+
+typedef enum MOJOSHADER_debugMonitorTokens
+{
+ MOJOSHADER_DMT_ENABLE,
+ MOJOSHADER_DMT_DISABLE
+} MOJOSHADER_debugMonitorTokens;
+
+typedef enum MOJOSHADER_blendOp
+{
+ MOJOSHADER_BLENDOP_ADD = 1,
+ MOJOSHADER_BLENDOP_SUBTRACT = 2,
+ MOJOSHADER_BLENDOP_REVSUBTRACT = 3,
+ MOJOSHADER_BLENDOP_MIN = 4,
+ MOJOSHADER_BLENDOP_MAX = 5
+} MOJOSHADER_blendOp;
+
+typedef enum MOJOSHADER_degreeType
+{
+ MOJOSHADER_DEGREE_LINEAR = 1,
+ MOJOSHADER_DEGREE_QUADRATIC = 2,
+ MOJOSHADER_DEGREE_CUBIC = 3,
+ MOJOSHADER_DEGREE_QUINTIC = 5
+} MOJOSHADER_degreeType;
+
+
+/* MOJOSHADER_effectSamplerState types... */
+
+typedef enum MOJOSHADER_samplerStateType
+{
+ MOJOSHADER_SAMP_UNKNOWN0 = 0,
+ MOJOSHADER_SAMP_UNKNOWN1 = 1,
+ MOJOSHADER_SAMP_UNKNOWN2 = 2,
+ MOJOSHADER_SAMP_UNKNOWN3 = 3,
+ MOJOSHADER_SAMP_TEXTURE = 4,
+ MOJOSHADER_SAMP_ADDRESSU = 5,
+ MOJOSHADER_SAMP_ADDRESSV = 6,
+ MOJOSHADER_SAMP_ADDRESSW = 7,
+ MOJOSHADER_SAMP_BORDERCOLOR = 8,
+ MOJOSHADER_SAMP_MAGFILTER = 9,
+ MOJOSHADER_SAMP_MINFILTER = 10,
+ MOJOSHADER_SAMP_MIPFILTER = 11,
+ MOJOSHADER_SAMP_MIPMAPLODBIAS = 12,
+ MOJOSHADER_SAMP_MAXMIPLEVEL = 13,
+ MOJOSHADER_SAMP_MAXANISOTROPY = 14,
+ MOJOSHADER_SAMP_SRGBTEXTURE = 15,
+ MOJOSHADER_SAMP_ELEMENTINDEX = 16,
+ MOJOSHADER_SAMP_DMAPOFFSET = 17
+} MOJOSHADER_samplerStateType;
+
+typedef enum MOJOSHADER_textureAddress
+{
+ MOJOSHADER_TADDRESS_WRAP = 1,
+ MOJOSHADER_TADDRESS_MIRROR = 2,
+ MOJOSHADER_TADDRESS_CLAMP = 3,
+ MOJOSHADER_TADDRESS_BORDER = 4,
+ MOJOSHADER_TADDRESS_MIRRORONCE = 5
+} MOJOSHADER_textureAddress;
+
+typedef enum MOJOSHADER_textureFilterType
+{
+ MOJOSHADER_TEXTUREFILTER_NONE,
+ MOJOSHADER_TEXTUREFILTER_POINT,
+ MOJOSHADER_TEXTUREFILTER_LINEAR,
+ MOJOSHADER_TEXTUREFILTER_ANISOTROPIC,
+ MOJOSHADER_TEXTUREFILTER_PYRAMIDALQUAD,
+ MOJOSHADER_TEXTUREFILTER_GAUSSIANQUAD,
+ MOJOSHADER_TEXTUREFILTER_CONVOLUTIONMONO
+} MOJOSHADER_textureFilterType;
+
+
+/* Effect value types... */
+
+typedef struct MOJOSHADER_effectSamplerState MOJOSHADER_effectSamplerState;
+
+typedef struct MOJOSHADER_effectValue
+{
+ const char *name;
+ const char *semantic;
+ unsigned int element_count;
+ unsigned int row_count;
+ unsigned int column_count;
+ MOJOSHADER_symbolClass value_class;
+ MOJOSHADER_symbolType value_type;
+ unsigned int value_count;
+ union
+ {
+ /* Raw value types */
+ void *values;
+ int *valuesI;
+ float *valuesF;
+ /* As used by MOJOSHADER_effectState */
+ MOJOSHADER_zBufferType *valuesZBT;
+ MOJOSHADER_fillMode *valuesFiM;
+ MOJOSHADER_shadeMode *valuesSM;
+ MOJOSHADER_blendMode *valuesBM;
+ MOJOSHADER_cullMode *valuesCM;
+ MOJOSHADER_compareFunc *valuesCF;
+ MOJOSHADER_fogMode *valuesFoM;
+ MOJOSHADER_stencilOp *valuesSO;
+ MOJOSHADER_materialColorSource *valuesMCS;
+ MOJOSHADER_vertexBlendFlags *valuesVBF;
+ MOJOSHADER_patchedEdgeStyle *valuesPES;
+ MOJOSHADER_debugMonitorTokens *valuesDMT;
+ MOJOSHADER_blendOp *valuesBO;
+ MOJOSHADER_degreeType *valuesDT;
+ /* As used by MOJOSHADER_effectSamplerState */
+ MOJOSHADER_textureAddress *valuesTA;
+ MOJOSHADER_textureFilterType *valuesTFT;
+ /* As used by MOJOSHADER_effectParameter */
+ MOJOSHADER_effectSamplerState *valuesSS;
+ };
+} MOJOSHADER_effectValue;
+
+typedef struct MOJOSHADER_effectState
+{
+ MOJOSHADER_renderStateType type;
+ MOJOSHADER_effectValue value;
+} MOJOSHADER_effectState;
+
+struct MOJOSHADER_effectSamplerState
+{
+ MOJOSHADER_samplerStateType type;
+ MOJOSHADER_effectValue value;
+};
+
+typedef MOJOSHADER_effectValue MOJOSHADER_effectAnnotation;
+
+
+/* Effect interface structures... */
+
+typedef struct MOJOSHADER_effectParam
+{
+ MOJOSHADER_effectValue value;
+ unsigned int annotation_count;
+ MOJOSHADER_effectAnnotation *annotations;
+} MOJOSHADER_effectParam;
+
+typedef struct MOJOSHADER_effectPass
+{
+ const char *name;
+ unsigned int state_count;
+ MOJOSHADER_effectState *states;
+ unsigned int annotation_count;
+ MOJOSHADER_effectAnnotation* annotations;
+} MOJOSHADER_effectPass;
+
+typedef struct MOJOSHADER_effectTechnique
+{
+ const char *name;
+ unsigned int pass_count;
+ MOJOSHADER_effectPass *passes;
+ unsigned int annotation_count;
+ MOJOSHADER_effectAnnotation* annotations;
+} MOJOSHADER_effectTechnique;
+
+
+/* Effect "objects"... */
+
+/* Defined later in the state change types... */
+typedef struct MOJOSHADER_samplerStateRegister MOJOSHADER_samplerStateRegister;
+
+typedef struct MOJOSHADER_effectShader
+{
+ MOJOSHADER_symbolType type;
+ unsigned int technique;
+ unsigned int pass;
+ unsigned int is_preshader;
+ unsigned int preshader_param_count;
+ unsigned int *preshader_params;
+ unsigned int param_count;
+ unsigned int *params;
+ unsigned int sampler_count;
+ MOJOSHADER_samplerStateRegister *samplers;
+ union
+ {
+ const MOJOSHADER_parseData *shader;
+ const MOJOSHADER_preshader *preshader;
+ };
+} MOJOSHADER_effectShader;
+
+typedef struct MOJOSHADER_effectSamplerMap
+{
+ MOJOSHADER_symbolType type;
+ const char *name;
+} MOJOSHADER_effectSamplerMap;
+
+typedef struct MOJOSHADER_effectString
+{
+ MOJOSHADER_symbolType type;
+ const char *string;
+} MOJOSHADER_effectString;
+
+typedef struct MOJOSHADER_effectTexture
+{
+ MOJOSHADER_symbolType type;
+ /* FIXME: Does this even do anything? */
+} MOJOSHADER_effectTexture;
+
+typedef union MOJOSHADER_effectObject
+{
+ MOJOSHADER_symbolType type;
+ union
+ {
+ MOJOSHADER_effectShader shader;
+ MOJOSHADER_effectSamplerMap mapping;
+ MOJOSHADER_effectString string;
+ MOJOSHADER_effectTexture texture;
+ };
+} MOJOSHADER_effectObject;
+
+
+/* Effect state change types... */
+
+/* Used to store sampler states with accompanying sampler registers */
+struct MOJOSHADER_samplerStateRegister
+{
+ const char *sampler_name;
+ unsigned int sampler_register;
+ unsigned int sampler_state_count;
+ const MOJOSHADER_effectSamplerState *sampler_states;
+};
+
+/*
+ * Used to acquire the desired render state by the effect pass.
+ */
+typedef struct MOJOSHADER_effectStateChanges
+{
+ /* Render state changes caused by effect technique */
+ unsigned int render_state_change_count;
+ const MOJOSHADER_effectState *render_state_changes;
+
+ /* Sampler state changes caused by effect technique */
+ unsigned int sampler_state_change_count;
+ const MOJOSHADER_samplerStateRegister *sampler_state_changes;
+
+ /* Vertex sampler state changes caused by effect technique */
+ unsigned int vertex_sampler_state_change_count;
+ const MOJOSHADER_samplerStateRegister *vertex_sampler_state_changes;
+} MOJOSHADER_effectStateChanges;
+
+
+/*
+ * Structure used to return data from parsing of an effect file...
+ */
+/* !!! FIXME: most of these ints should be unsigned. */
+typedef struct MOJOSHADER_effect
+{
+ /*
+ * The number of elements pointed to by (errors).
+ */
+ int error_count;
+
+ /*
+ * (error_count) elements of data that specify errors that were generated
+ * by parsing this shader.
+ * This can be NULL if there were no errors or if (error_count) is zero.
+ */
+ MOJOSHADER_error *errors;
+
+ /*
+ * The name of the profile used to parse the shader. Will be NULL on error.
+ */
+ const char *profile;
+
+ /*
+ * The number of params pointed to by (params).
+ */
+ int param_count;
+
+ /*
+ * (param_count) elements of data that specify parameter bind points for
+ * this effect.
+ * This can be NULL on error or if (param_count) is zero.
+ */
+ MOJOSHADER_effectParam *params;
+
+ /*
+ * The number of elements pointed to by (techniques).
+ */
+ int technique_count;
+
+ /*
+ * (technique_count) elements of data that specify techniques used in
+ * this effect. Each technique contains a series of passes, and each pass
+ * specifies state and shaders that affect rendering.
+ * This can be NULL on error or if (technique_count) is zero.
+ */
+ MOJOSHADER_effectTechnique *techniques;
+
+ /*
+ * The technique currently being rendered by this effect.
+ */
+ const MOJOSHADER_effectTechnique *current_technique;
+
+ /*
+ * The index of the current pass being rendered by this effect.
+ */
+ int current_pass;
+
+ /*
+ * The number of elements pointed to by (objects).
+ */
+ int object_count;
+
+ /*
+ * (object_count) elements of data that specify objects used in
+ * this effect.
+ * This can be NULL on error or if (object_count) is zero.
+ */
+ MOJOSHADER_effectObject *objects;
+
+ /*
+ * Value used to determine whether or not to restore the previous shader
+ * state after rendering an effect, as requested by application.
+ */
+ int restore_shader_state;
+
+ /*
+ * The structure provided by the appliation to store the state changes.
+ */
+ MOJOSHADER_effectStateChanges *state_changes;
+
+ /*
+ * This is the malloc implementation you passed to MOJOSHADER_parseEffect().
+ */
+ MOJOSHADER_malloc malloc;
+
+ /*
+ * This is the free implementation you passed to MOJOSHADER_parseEffect().
+ */
+ MOJOSHADER_free free;
+
+ /*
+ * This is the pointer you passed as opaque data for your allocator.
+ */
+ void *malloc_data;
+} MOJOSHADER_effect;
+
+
+/* Effect parsing interface... */
+
+/* !!! FIXME: document me. */
+DECLSPEC MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
+ const unsigned char *buf,
+ const unsigned int _len,
+ const MOJOSHADER_swizzle *swiz,
+ const unsigned int swizcount,
+ const MOJOSHADER_samplerMap *smap,
+ const unsigned int smapcount,
+ MOJOSHADER_malloc m,
+ MOJOSHADER_free f,
+ void *d);
+
+
+/* !!! FIXME: document me. */
+DECLSPEC void MOJOSHADER_freeEffect(const MOJOSHADER_effect *effect);
+
+
+/* !!! FIXME: document me. */
+DECLSPEC MOJOSHADER_effect *MOJOSHADER_cloneEffect(const MOJOSHADER_effect *effect);
+
+
+/* Effect parameter interface... */
+
+/* Set the constant value for the specified effect parameter.
+ *
+ * This function maps to ID3DXEffect::SetRawValue.
+ *
+ * (parameter) is a parameter obtained from a MOJOSHADER_effect*.
+ * (data) is the constant values to be applied to the parameter.
+ * (offset) is the offset, in bytes, of the parameter data being modified.
+ * (len) is the size, in bytes, of the data buffer being applied.
+ *
+ * This function is thread safe.
+ */
+DECLSPEC void MOJOSHADER_effectSetRawValueHandle(const MOJOSHADER_effectParam *parameter,
+ const void *data,
+ const unsigned int offset,
+ const unsigned int len);
+
+/* Set the constant value for the effect parameter, specified by name.
+ * Note: this function is slower than MOJOSHADER_effectSetRawValueHandle(),
+ * but we still provide it to fully map to ID3DXEffect.
+ *
+ * This function maps to ID3DXEffect::SetRawValue.
+ *
+ * (effect) is a MOJOSHADER_effect* obtained from MOJOSHADER_parseEffect().
+ * (name) is the human-readable name of the parameter being modified.
+ * (data) is the constant values to be applied to the parameter.
+ * (offset) is the offset, in bytes, of the parameter data being modified.
+ * (len) is the size, in bytes, of the data buffer being applied.
+ *
+ * This function is thread safe.
+ */
+DECLSPEC void MOJOSHADER_effectSetRawValueName(const MOJOSHADER_effect *effect,
+ const char *name,
+ const void *data,
+ const unsigned int offset,
+ const unsigned int len);
+
+
+/* Effect technique interface... */
+
+/* Get the current technique in use by an effect.
+ *
+ * This function maps to ID3DXEffect::GetCurrentTechnique.
+ *
+ * (effect) is a MOJOSHADER_effect* obtained from MOJOSHADER_parseEffect().
+ *
+ * This function returns the technique currently used by the given effect.
+ *
+ * This function is thread safe.
+ */
+DECLSPEC const MOJOSHADER_effectTechnique *MOJOSHADER_effectGetCurrentTechnique(const MOJOSHADER_effect *effect);
+
+/* Set the current technique to be used an effect.
+ *
+ * This function maps to ID3DXEffect::SetTechnique.
+ *
+ * (effect) is a MOJOSHADER_effect* obtained from MOJOSHADER_parseEffect().
+ * (technique) is the technique to be used by the effect when rendered.
+ *
+ * This function is thread safe.
+ */
+DECLSPEC void MOJOSHADER_effectSetTechnique(MOJOSHADER_effect *effect,
+ const MOJOSHADER_effectTechnique *technique);
+
+/* Get the next technique in an effect's list.
+ *
+ * This function maps to ID3DXEffect::FindNextValidTechnique.
+ *
+ * (effect) is a MOJOSHADER_effect* obtained from MOJOSHADER_parseEffect().
+ * (technique) can either be a technique found in the given effect, or NULL to
+ * find the first technique in the given effect.
+ *
+ * This function returns either the next technique after the passed technique,
+ * or the first technique if the passed technique is NULL.
+ *
+ * This function is thread safe.
+ */
+DECLSPEC const MOJOSHADER_effectTechnique *MOJOSHADER_effectFindNextValidTechnique(const MOJOSHADER_effect *effect,
+ const MOJOSHADER_effectTechnique *technique);
+
+
+/* OpenGL effect interface... */
+
+typedef struct MOJOSHADER_glEffect MOJOSHADER_glEffect;
+
+/* Fully compile/link the shaders found within the effect.
+ *
+ * The MOJOSHADER_glEffect* is solely for use within the OpenGL-specific calls.
+ * In all other cases you will be using the MOJOSHADER_effect* instead.
+ *
+ * In a typical use case, you will be calling this immediately after obtaining
+ * the MOJOSHADER_effect*.
+ *
+ * (effect) is a MOJOSHADER_effect* obtained from MOJOSHADER_parseEffect().
+ *
+ * This function returns a MOJOSHADER_glEffect*, containing OpenGL-specific
+ * data for an accompanying MOJOSHADER_effect*.
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC MOJOSHADER_glEffect *MOJOSHADER_glCompileEffect(MOJOSHADER_effect *effect);
+
+/* Delete the shaders that were allocated for an effect.
+ *
+ * (glEffect) is a MOJOSHADER_glEffect* obtained from
+ * MOJOSHADER_glCompileEffect().
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC void MOJOSHADER_glDeleteEffect(MOJOSHADER_glEffect *glEffect);
+
+/* Prepare the effect for rendering with the currently applied technique.
+ *
+ * This function maps to ID3DXEffect::Begin.
+ *
+ * In addition to the expected Begin parameters, we also include a parameter
+ * to pass in a MOJOSHADER_effectRenderState. Rather than change the render
+ * state within MojoShader itself we will simply provide what the effect wants
+ * and allow you to use this information with your own renderer.
+ * MOJOSHADER_glEffectBeginPass will update with the render state desired by
+ * the current effect pass.
+ *
+ * Note that we only provide the ability to preserve the shader state, but NOT
+ * the ability to preserve the render/sampler states. You are expected to
+ * track your own GL state and restore these states as needed for your
+ * application.
+ *
+ * (glEffect) is a MOJOSHADER_glEffect* obtained from
+ * MOJOSHADER_glCompileEffect().
+ * (numPasses) will be filled with the number of passes that this technique
+ * will need to fully render.
+ * (saveShaderState) is a boolean value informing the effect whether or not to
+ * restore the shader bindings after calling MOJOSHADER_glEffectEnd.
+ * (renderState) will be filled by the effect to inform you of the render state
+ * changes introduced by the technique and its passes.
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC void MOJOSHADER_glEffectBegin(MOJOSHADER_glEffect *glEffect,
+ unsigned int *numPasses,
+ int saveShaderState,
+ MOJOSHADER_effectStateChanges *stateChanges);
+
+/* Begin an effect pass from the currently applied technique.
+ *
+ * This function maps to ID3DXEffect::BeginPass.
+ *
+ * (glEffect) is a MOJOSHADER_glEffect* obtained from
+ * MOJOSHADER_glCompileEffect().
+ * (pass) is the index of the effect pass as found in the current technique.
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC void MOJOSHADER_glEffectBeginPass(MOJOSHADER_glEffect *glEffect,
+ unsigned int pass);
+
+/* Push render state changes that occurred within an actively rendering pass.
+ *
+ * This function maps to ID3DXEffect::CommitChanges.
+ *
+ * (glEffect) is a MOJOSHADER_glEffect* obtained from
+ * MOJOSHADER_glCompileEffect().
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC void MOJOSHADER_glEffectCommitChanges(MOJOSHADER_glEffect *glEffect);
+
+/* End an effect pass from the currently applied technique.
+ *
+ * This function maps to ID3DXEffect::EndPass.
+ *
+ * (glEffect) is a MOJOSHADER_glEffect* obtained from
+ * MOJOSHADER_glCompileEffect().
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC void MOJOSHADER_glEffectEndPass(MOJOSHADER_glEffect *glEffect);
+
+/* Complete rendering the effect technique, and restore the render state.
+ *
+ * This function maps to ID3DXEffect::End.
+ *
+ * (glEffect) is a MOJOSHADER_glEffect* obtained from
+ * MOJOSHADER_glCompileEffect().
+ *
+ * This call is NOT thread safe! As most OpenGL implementations are not thread
+ * safe, you should probably only call this from the same thread that created
+ * the GL context.
+ */
+DECLSPEC void MOJOSHADER_glEffectEnd(MOJOSHADER_glEffect *glEffect);
+
+#endif /* MOJOSHADER_EFFECT_SUPPORT */
+
+#endif /* MOJOSHADER_EFFECTS_H */
--- a/mojoshader_internal.h Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader_internal.h Fri Jan 01 02:12:19 2016 -0500
@@ -52,6 +52,10 @@
#define SUPPORT_PROFILE_GLSL120 1
#endif
+#ifndef SUPPORT_PROFILE_GLSLES
+#define SUPPORT_PROFILE_GLSLES 1
+#endif
+
#ifndef SUPPORT_PROFILE_ARB1
#define SUPPORT_PROFILE_ARB1 1
#endif
@@ -68,6 +72,10 @@
#error glsl120 profile requires glsl profile. Fix your build.
#endif
+#if SUPPORT_PROFILE_GLSLES && !SUPPORT_PROFILE_GLSL
+#error glsles profile requires glsl profile. Fix your build.
+#endif
+
// Microsoft's preprocessor has some quirks. In some ways, it doesn't work
// like you'd expect a C preprocessor to function.
#ifndef MATCH_MICROSOFT_PREPROCESSOR
@@ -76,16 +84,8 @@
// Other stuff you can disable...
-// This removes the preshader parsing and execution code. You can save some
-// bytes if you have normal shaders and not Effect files.
-#ifndef SUPPORT_PRESHADERS
-#define SUPPORT_PRESHADERS 1
-#endif
-
-#if SUPPORT_PRESHADERS
-void MOJOSHADER_runPreshader(const MOJOSHADER_preshader*, const float*, float*);
-#else
-#define MOJOSHADER_runPreshader(a, b)
+#ifdef MOJOSHADER_EFFECT_SUPPORT
+void MOJOSHADER_runPreshader(const MOJOSHADER_preshader*, float*);
#endif
@@ -99,6 +99,9 @@
typedef unsigned int uint; // this is a printf() helper. don't use for code.
+// Locale-independent float printing replacement for snprintf
+size_t MOJOSHADER_printFloat(char *text, size_t maxlen, float arg);
+
#ifdef _MSC_VER
#include <malloc.h>
#define va_copy(a, b) a = b
@@ -293,8 +296,8 @@
#define MOJOSHADER_internal_malloc NULL
#define MOJOSHADER_internal_free NULL
#else
-void *MOJOSHADER_internal_malloc(int bytes, void *d);
-void MOJOSHADER_internal_free(void *ptr, void *d);
+void * MOJOSHADERCALL MOJOSHADER_internal_malloc(int bytes, void *d);
+void MOJOSHADERCALL MOJOSHADER_internal_free(void *ptr, void *d);
#endif
#if MOJOSHADER_FORCE_INCLUDE_CALLBACKS
--- a/mojoshader_opengl.c Tue Oct 13 12:08:55 2015 -0400
+++ b/mojoshader_opengl.c Fri Jan 01 02:12:19 2016 -0500
@@ -7,9 +7,6 @@
* This file written by Ryan C. Gordon.
*/
-// !!! FIXME: preshaders shouldn't be handled in here at all. This should
-// !!! FIXME: be in the Effects API, once that's actually written.
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -98,15 +95,13 @@
size_t ps_uniforms_bool_count;
GLint *ps_uniforms_bool;
- size_t vs_preshader_reg_count;
- GLfloat *vs_preshader_regs;
- size_t ps_preshader_reg_count;
- GLfloat *ps_preshader_regs;
-
uint32 refcount;
int uses_pointsize;
+ // 10 is apparently the resource limit according to SM3 -flibit
+ GLint vertex_attrib_loc[MOJOSHADER_USAGE_TOTAL][10];
+
// GLSL uses these...location of uniform arrays.
GLint vs_float4_loc;
GLint vs_int4_loc;
@@ -114,6 +109,10 @@
GLint ps_float4_loc;
GLint ps_int4_loc;
GLint ps_bool_loc;
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+ GLint vs_flip_loc;
+ int current_flip;
+#endif
};
#ifndef WINGDIAPI
@@ -163,6 +162,9 @@
uint8 want_attr[32];
uint8 have_attr[32];
+ // This shadows vertex attribute and divisor states.
+ GLuint attr_divisor[32];
+
// rarely used, so we don't touch when we don't have to.
int pointsize_enabled;
@@ -174,10 +176,16 @@
MOJOSHADER_glProgram *bound_program;
char profile[16];
+#ifdef MOJOSHADER_XNA4_VERTEX_TEXTURES
+ // Vertex texture sampler offset...
+ int vertex_sampler_offset;
+#endif
+
// Extensions...
int have_core_opengl;
int have_opengl_2; // different entry points than ARB extensions.
int have_opengl_3; // different extension query.
+ int have_opengl_es; // different extension requirements
int have_GL_ARB_vertex_program;
int have_GL_ARB_fragment_program;
int have_GL_NV_vertex_program2_option;
@@ -191,6 +199,7 @@
int have_GL_NV_half_float;
int have_GL_ARB_half_float_vertex;
int have_GL_OES_vertex_half_float;
+ int have_GL_ARB_instanced_arrays;
// Entry points...
PFNGLGETSTRINGPROC glGetString;
@@ -217,6 +226,9 @@
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLUNIFORM1IVPROC glUniform1iv;
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+ PFNGLUNIFORM1FPROC glUniform1f;
+#endif
PFNGLUNIFORM4FVPROC glUniform4fv;
PFNGLUNIFORM4IVPROC glUniform4iv;
PFNGLUSEPROGRAMPROC glUseProgram;
@@ -247,6 +259,7 @@
PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
PFNGLBINDPROGRAMARBPROC glBindProgramARB;
PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
+ PFNGLVERTEXATTRIBDIVISORARBPROC glVertexAttribDivisorARB;
// interface for profile-specific things.
int (*profileMaxUniforms)(MOJOSHADER_shaderType shader_type);
@@ -562,6 +575,9 @@
program->ps_float4_loc = glsl_uniform_loc(program, "ps_uniforms_vec4");
program->ps_int4_loc = glsl_uniform_loc(program, "ps_uniforms_ivec4");
program->ps_bool_loc = glsl_uniform_loc(program, "ps_uniforms_bool");
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+ program->vs_flip_loc = glsl_uniform_loc(program, "vpFlip");
+#endif
} // impl_GLSL_FinalInitProgram
@@ -951,6 +967,9 @@
DO_LOOKUP(opengl_2, PFNGLSHADERSOURCEPROC, glShaderSource);
DO_LOOKUP(opengl_2, PFNGLUNIFORM1IPROC, glUniform1i);
DO_LOOKUP(opengl_2, PFNGLUNIFORM1IVPROC, glUniform1iv);
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+ DO_LOOKUP(opengl_2, PFNGLUNIFORM1FPROC, glUniform1f);
+#endif
DO_LOOKUP(opengl_2, PFNGLUNIFORM4FVPROC, glUniform4fv);
DO_LOOKUP(opengl_2, PFNGLUNIFORM4IVPROC, glUniform4iv);
DO_LOOKUP(opengl_2, PFNGLUSEPROGRAMPROC, glUseProgram);
@@ -982,6 +1001,7 @@
DO_LOOKUP(GL_ARB_vertex_program, PFNGLBINDPROGRAMARBPROC, glBindProgramARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLPROGRAMSTRINGARBPROC, glProgramStringARB);
DO_LOOKUP(GL_NV_gpu_program4, PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC, glProgramLocalParameterI4ivNV);
+ DO_LOOKUP(GL_ARB_instanced_arrays, PFNGLVERTEXATTRIBDIVISORARBPROC, glVertexAttribDivisorARB);
#undef DO_LOOKUP
} // lookup_entry_points
@@ -1054,6 +1074,8 @@
const char *str = (const char *) ctx->glGetString(enumval);
if (ctx->glGetError() == GL_INVALID_ENUM)
str = NULL;
+ if (strstr(str, "OpenGL ES GLSL ES "))
+ str += 18;
parse_opengl_version_str(str, &ctx->glsl_major, &ctx->glsl_minor);
} // if
#endif
@@ -1095,6 +1117,7 @@
ctx->have_GL_NV_half_float = 1;
ctx->have_GL_ARB_half_float_vertex = 1;
ctx->have_GL_OES_vertex_half_float = 1;
+ ctx->have_GL_ARB_instanced_arrays = 1;
lookup_entry_points(lookup, d);
@@ -1103,6 +1126,11 @@
else
{
const char *str = (const char *) ctx->glGetString(GL_VERSION);
+ if (strstr(str, "OpenGL ES "))
+ {
+ ctx->have_opengl_es = 1;
+ str += 10;
+ }
parse_opengl_version_str(str, &ctx->opengl_major, &ctx->opengl_minor);
if ((ctx->have_opengl_3) && (opengl_version_atleast(3, 0)))
@@ -1187,6 +1215,7 @@
VERIFY_EXT(GL_NV_half_float, -1, -1);
VERIFY_EXT(GL_ARB_half_float_vertex, 3, 0);
VERIFY_EXT(GL_OES_vertex_half_float, -1, -1);
+ VERIFY_EXT(GL_ARB_instanced_arrays, 3, 3);
#undef VERIFY_EXT
@@ -1247,6 +1276,13 @@
} // else if
#endif
+ #if SUPPORT_PROFILE_GLSLES
+ else if (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0)
+ {
+ MUST_HAVE_GLSL(MOJOSHADER_PROFILE_GLSLES, 1, 10);
+ } // else if
+ #endif
+
#if SUPPORT_PROFILE_GLSL120
else if (strcmp(profile, MOJOSHADER_PROFILE_GLSL120) == 0)
{
@@ -1311,6 +1347,14 @@
load_extensions(lookup, lookup_d);
+#if SUPPORT_PROFILE_GLSLES
+ if (ctx->have_opengl_es)
+ {
+ profs[0] = MOJOSHADER_PROFILE_GLSLES;
+ return 1;
+ } // if
+#endif
+
if (ctx->have_core_opengl)
{
size_t i;
@@ -1381,15 +1425,24 @@
if (!valid_profile(profile))
goto init_fail;
+#ifdef MOJOSHADER_XNA4_VERTEX_TEXTURES
+ GLint maxTextures;
+ GLint maxVertexTextures;
+ ctx->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextures);
+ maxVertexTextures = ((maxTextures - 16) < 4) ? (maxTextures - 16) : 4;
+ ctx->vertex_sampler_offset = maxTextures - maxVertexTextures;
+#endif
+
MOJOSHADER_glBindProgram(NULL);
// !!! FIXME: generalize this part.
if (profile == NULL) {}
- // We don't check SUPPORT_PROFILE_GLSL120 here, since valid_profile() does.
+ // We don't check SUPPORT_PROFILE_GLSL120/ES here, since valid_profile() does.
#if SUPPORT_PROFILE_GLSL
else if ( (strcmp(profile, MOJOSHADER_PROFILE_GLSL) == 0) ||
- (strcmp(profile, MOJOSHADER_PROFILE_GLSL120) == 0) )
+ (strcmp(profile, MOJOSHADER_PROFILE_GLSL120) == 0) ||
+ (strcmp(profile, MOJOSHADER_PROFILE_GLSLES) == 0) )
{
ctx->profileMaxUniforms = impl_GLSL_MaxUniforms;
ctx->profileCompileShader = impl_GLSL_CompileShader;
@@ -1555,8 +1608,6 @@
ctx->profileDeleteProgram(program->handle);
shader_unref(program->vertex);
shader_unref(program->fragment);
- Free(program->vs_preshader_regs);
- Free(program->ps_preshader_regs);
Free(program->vs_uniforms_float4);
Free(program->vs_uniforms_int4);
Free(program->vs_uniforms_bool);
@@ -1685,38 +1736,6 @@
#undef MAKE_ARRAY
- if (pd->preshader)
- {
- unsigned int largest = 0;
- const MOJOSHADER_symbol *sym = pd->preshader->symbols;
- for (i = 0; i < pd->preshader->symbol_count; i++, sym++)
- {
- const unsigned int val = sym->register_index + sym->register_count;
- if (val > largest)
- largest = val;
- } // for
-
- if (largest > 0)
- {
- const size_t len = largest * sizeof (GLfloat) * 4;
- GLfloat *buf = (GLfloat *) Malloc(len);
- if (buf == NULL)
- return 0;
- memset(buf, '\0', len);
-
- if (shader_type == MOJOSHADER_TYPE_VERTEX)
- {
- program->vs_preshader_reg_count = largest;
- program->vs_preshader_regs = buf;
- } // if
- else if (shader_type == MOJOSHADER_TYPE_PIXEL)
- {
- program->ps_preshader_reg_count = largest;
- program->ps_preshader_regs = buf;
- } // else if
- } // if
- } // if
-
return 1;
} // lookup_uniforms
@@ -1744,7 +1763,14 @@
{
const GLint loc = ctx->profileGetSamplerLocation(program, shader, i);
if (loc >= 0) // maybe the Sampler was optimized out?
- ctx->profilePushSampler(loc, s[i].index);
+ {
+#ifdef MOJOSHADER_XNA4_VERTEX_TEXTURES
+ if (pd->shader_type == MOJOSHADER_TYPE_VERTEX)
+ ctx->profilePushSampler(loc, s[i].index + ctx->vertex_sampler_offset);
+ else
+#endif
+ ctx->profilePushSampler(loc, s[i].index);
+ } // if
} // for
} // lookup_samplers
@@ -1784,6 +1810,7 @@
AttributeMap *map = &program->attributes[program->attribute_count];
map->attribute = &a[i];
map->location = loc;
+ program->vertex_attrib_loc[map->attribute->usage][map->attribute->index] = loc;
program->attribute_count++;
if (((size_t)loc) > STATICARRAYLEN(ctx->want_attr))
@@ -1844,6 +1871,7 @@
if (retval == NULL)
goto link_program_fail;
memset(retval, '\0', sizeof (MOJOSHADER_glProgram));
+ memset(retval->vertex_attrib_loc, 0xFF, sizeof(retval->vertex_attrib_loc));
numregs = 0;
if (vshader != NULL) numregs += vshader->parseData->uniform_count;
@@ -2278,6 +2306,15 @@
} // opengl_attr_type
+int MOJOSHADER_glGetVertexAttribLocation(MOJOSHADER_usage usage, int index)
+{
+ if ((ctx->bound_program == NULL) || (ctx->bound_program->vertex == NULL))
+ return -1;
+
+ return ctx->bound_program->vertex_attrib_loc[usage][index];
+} // MOJOSHADER_glGetVertexAttribLocation
+
+
// !!! FIXME: shouldn't (index) be unsigned?
void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage,
int index, unsigned int size,
@@ -2290,27 +2327,10 @@
const GLenum gl_type = opengl_attr_type(type);
const GLboolean norm = (normalized) ? GL_TRUE : GL_FALSE;
- const int count = ctx->bound_program->attribute_count;
- GLint gl_index = 0;
- int i;
-
- for (i = 0; i < count; i++)
- {
- const AttributeMap *map = &ctx->bound_program->attributes[i];
- const MOJOSHADER_attribute *a = map->attribute;
-
- // !!! FIXME: is this array guaranteed to be sorted by usage?
- // !!! FIXME: if so, we can break if a->usage > usage.
-
- if ((a->usage == usage) && (a->index == index))
- {
- gl_index = map->location;
- break;
- } // if
- } // for
-
- if (i == count)
- return; // nothing to do, this shader doesn't use this stream.
+ const GLint gl_index = ctx->bound_program->vertex_attrib_loc[usage][index];
+
+ if (gl_index == -1)
+ return; // Nothing to do, this shader doesn't use this stream.
// this happens to work in both ARB1 and GLSL, but if something alien
// shows up, we'll have to split these into profile*() functions.
@@ -2323,76 +2343,26 @@
} // MOJOSHADER_glSetVertexAttribute
-void MOJOSHADER_glSetVertexPreshaderUniformF(unsigned int idx,
- const float *data,
- unsigned int vec4n)
+// !!! FIXME: shouldn't (index) be unsigned?
+void MOJOSHADER_glSetVertexAttribDivisor(MOJOSHADER_usage usage,
+ int index, unsigned int divisor)
{
- MOJOSHADER_glProgram *program = ctx->bound_program;
- if (program == NULL)
- return; // nothing to do.
-
- const uint maxregs = program->vs_preshader_reg_count;
- if (idx < maxregs)
+ assert(ctx->have_GL_ARB_instanced_arrays);
+
+ if ((ctx->bound_program == NULL) || (ctx->bound_program->vertex == NULL))
+ return;
+
+ const GLint gl_index = ctx->bound_program->vertex_attrib_loc[usage][index];
+
+ if (gl_index == -1)
+ return; // Nothing to do, this shader doesn't use this stream.
+
+ if (divisor != ctx->attr_divisor[gl_index])
{
- assert(sizeof (GLfloat) == sizeof (float));
- const uint cpy = (minuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
- memcpy(program->vs_preshader_regs + (idx * 4), data, cpy);
- program->generation = ctx->generation-1;
- } // if
-} // MOJOSHADER_glSetVertexPreshaderUniformF
-
-
-void MOJOSHADER_glGetVertexPreshaderUniformF(unsigned int idx, float *data,
- unsigned int vec4n)
-{
- MOJOSHADER_glProgram *program = ctx->bound_program;
- if (program == NULL)
- return; // nothing to do.
-
- const uint maxregs = program->vs_preshader_reg_count;
- if (idx < maxregs)
- {
- assert(sizeof (GLfloat) == sizeof (float));
- const uint cpy = (minuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
- memcpy(data, program->vs_preshader_regs + (idx * 4), cpy);
+ ctx->glVertexAttribDivisorARB(gl_index, divisor);
+ ctx->attr_divisor[gl_index] = divisor;
} // if
-} // MOJOSHADER_glGetVertexPreshaderUniformF
-
-
-void MOJOSHADER_glSetPixelPreshaderUniformF(unsigned int idx,
- const float *data,
- unsigned int vec4n)
-{
- MOJOSHADER_glProgram *program = ctx->bound_program;
- if (program == NULL)
- return; // nothing to do.
-
- const uint maxregs = program->ps_preshader_reg_count;
- if (idx < maxregs)
- {
- assert(sizeof (GLfloat) == sizeof (float));
- const uint cpy = (minuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
- memcpy(program->ps_preshader_regs + (idx * 4), data, cpy);
- program->generation = ctx->generation-1;
- } // if
-} // MOJOSHADER_glSetPixelPreshaderUniformF
-
-
-void MOJOSHADER_glGetPixelPreshaderUniformF(unsigned int idx, float *data,
- unsigned int vec4n)
-{
- MOJOSHADER_glProgram *program = ctx->bound_program;
- if (program == NULL)
- return; // nothing to do.
-
- const uint maxregs = program->ps_preshader_reg_count;
- if (idx < maxregs)
- {
- assert(sizeof (GLfloat) == sizeof (float));
- const uint cpy = (minuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
- memcpy(data, program->ps_preshader_regs + (idx * 4), cpy);
- } // if
-} // MOJOSHADER_glGetPixelPreshaderUniformF
+} // MOJOSHADER_glSetVertexAttribDivisor
void MOJOSHADER_glSetLegacyBumpMapEnv(unsigned int sampler, float mat00,
@@ -2445,38 +2415,9 @@
GLfloat *dstf = program->vs_uniforms_float4;
GLint *dsti = program->vs_uniforms_int4;
GLint *dstb = program->vs_uniforms_bool;
- const MOJOSHADER_preshader *preshader = NULL;
+ uint8 uniforms_changed = 0;
uint32 i;
- // !!! FIXME: shouldn't this run even if the generation hasn't changed?
- #if SUPPORT_PRESHADERS
- int ran_preshader = 0;
- if (program->vertex)
- {
- preshader = program->vertex->parseData->preshader;
- if (preshader)
- {
- MOJOSHADER_runPreshader(preshader, program->vs_preshader_regs,
- ctx->vs_reg_file_f);
- ran_preshader = 1;
- } // if
- } // if
-
- if (program->fragment)
- {
- preshader = program->fragment->parseData->preshader;
- if (preshader)
- {
- MOJOSHADER_runPreshader(preshader, program->ps_preshader_regs,
- ctx->ps_reg_file_f);
- ran_preshader = 1;
- } // if
- } // if
-
- if (ran_preshader)
- ctx->generation++;
- #endif
-
for (i = 0; i < count; i++)
{
UniformMap *map = &program->uniforms[i];
@@ -2516,14 +2457,22 @@
{
const size_t count = 4 * size;
const GLfloat *f = &srcf[index * 4];
- memcpy(dstf, f, sizeof (GLfloat) * count);
+ if (memcmp(dstf, f, sizeof (GLfloat) * count) != 0)
+ {
+ memcpy(dstf, f, sizeof (GLfloat) * count);
+ uniforms_changed = 1;
+ }
dstf += count;
} // if
else if (type == MOJOSHADER_UNIFORM_INT)
{
const size_t count = 4 * size;
const GLint *i = &srci[index * 4];
- memcpy(dsti, i, sizeof (GLint) * count);
+ if (memcmp(dsti, i, sizeof (GLint) * count) != 0)
+ {
+ memcpy(dsti, i, sizeof (GLint) * count);
+ uniforms_changed = 1;
+ } // if
dsti += count;
} // else if
else if (type == MOJOSHADER_UNIFORM_BOOL)
@@ -2532,7 +2481,11 @@
const uint8 *b = &srcb[index];
size_t i;
for (i = 0; i < count; i++)
- dstb[i] = (GLint) b[i];
+ if (dstb[i] != b[i])
+ {
+ dstb[i] = (GLint) b[i];
+ uniforms_changed = 1;
+ } // if
dstb += count;
} // else if
@@ -2572,7 +2525,8 @@
program->generation = ctx->generation;
- ctx->profilePushUniforms();
+ if (uniforms_changed)
+ ctx->profilePushUniforms();
} // if
} // MOJOSHADER_glProgramReady
@@ -2620,5 +2574,510 @@
ctx = ((current_ctx == _ctx) ? NULL : current_ctx);
} // MOJOSHADER_glDestroyContext
+
+#ifdef MOJOSHADER_FLIP_RENDERTARGET
+
+
+void MOJOSHADER_glProgramViewportFlip(int flip)
+{
+ assert(ctx->bound_program->vs_flip_loc != -1);
+
+ /* Some compilers require that vpFlip be a float value, rather than int.
+ * However, there's no real reason for it to be a float in the API, so we
+ * do a cast in here. That's not so bad, right...?
+ * -flibit
+ */
+ if (flip != ctx->bound_program->current_flip)
+ {
+ ctx->glUniform1f(ctx->bound_program->vs_flip_loc, (float) flip);
+ ctx->bound_program->current_flip = flip;
+ } // if
+}
+
+
+#endif
+
+
+#ifdef MOJOSHADER_EFFECT_SUPPORT
+
+
+struct MOJOSHADER_glEffect
+{
+ MOJOSHADER_effect *effect;
+ unsigned int num_shaders;
+ MOJOSHADER_glShader *shaders;
+ unsigned int *shader_indices;
+ unsigned int num_preshaders;
+ unsigned int *preshader_indices;
+ MOJOSHADER_glShader *current_vert;
+ MOJOSHADER_glShader *current_frag;
+ MOJOSHADER_effectShader *current_vert_raw;
+ MOJOSHADER_effectShader *current_frag_raw;
+ MOJOSHADER_glProgram *prev_program;
+};
+
+
+MOJOSHADER_glEffect *MOJOSHADER_glCompileEffect(MOJOSHADER_effect *effect)
+{
+ int i;
+ MOJOSHADER_malloc m = effect->malloc;
+ MOJOSHADER_free f = effect->free;
+ void *d = effect->malloc_data;
+ int current_shader = 0;
+ int current_preshader = 0;
+ GLuint shader = 0;
+
+ MOJOSHADER_glEffect *retval = (MOJOSHADER_glEffect *) m(sizeof (MOJOSHADER_glEffect), d);
+ if (retval == NULL)
+ {
+ out_of_memory();
+ return NULL;
+ } // if
+ memset(retval, '\0', sizeof (MOJOSHADER_glEffect));
+
+ // Count the number of shaders before allocating
+ for (i = 0; i < effect->object_count; i++)
+ {
+ MOJOSHADER_effectObject *object = &effect->objects[i];
+ if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ if (object->shader.is_preshader)
+ retval->num_preshaders++;
+ else
+ retval->num_shaders++;
+ } // if
+ } // for
+
+ // Alloc shader information
+ retval->shaders = (MOJOSHADER_glShader *) m(retval->num_shaders * sizeof (MOJOSHADER_glShader), d);
+ if (retval->shaders == NULL)
+ {
+ f(retval, d);
+ out_of_memory();
+ return NULL;
+ } // if
+ memset(retval->shaders, '\0', retval->num_shaders * sizeof (MOJOSHADER_glShader));
+ retval->shader_indices = (unsigned int *) m(retval->num_shaders * sizeof (unsigned int), d);
+ if (retval->shader_indices == NULL)
+ {
+ f(retval->shaders, d);
+ f(retval, d);
+ out_of_memory();
+ return NULL;
+ } // if
+ memset(retval->shader_indices, '\0', retval->num_shaders * sizeof (unsigned int));
+
+ // Alloc preshader information
+ if (retval->num_preshaders > 0)
+ {
+ retval->preshader_indices = (unsigned int *) m(retval->num_preshaders * sizeof (unsigned int), d);
+ if (retval->preshader_indices == NULL)
+ {
+ f(retval->shaders, d);
+ f(retval->shader_indices, d);
+ f(retval, d);
+ out_of_memory();
+ return NULL;
+ } // if
+ memset(retval->preshader_indices, '\0', retval->num_preshaders * sizeof (unsigned int));
+ } // if
+
+ // Run through the shaders again, compiling and tracking the object indices
+ for (i = 0; i < effect->object_count; i++)
+ {
+ MOJOSHADER_effectObject *object = &effect->objects[i];
+ if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ if (object->shader.is_preshader)
+ {
+ retval->preshader_indices[current_preshader++] = i;
+ continue;
+ } // if
+ if (!ctx->profileCompileShader(object->shader.shader, &shader))
+ goto compile_shader_fail;
+ retval->shaders[current_shader].parseData = object->shader.shader;
+ retval->shaders[current_shader].handle = shader;
+ retval->shaders[current_shader].refcount = 1;
+ retval->shader_indices[current_shader] = i;
+ current_shader++;
+ } // if
+ } // for
+
+ retval->effect = effect;
+ return retval;
+
+compile_shader_fail:
+ for (i = 0; i < retval->num_shaders; i++)
+ if (retval->shaders[i].handle != 0)
+ ctx->profileDeleteShader(retval->shaders[i].handle);
+ f(retval->shader_indices, d);
+ f(retval->shaders, d);
+ f(retval, d);
+ return NULL;
+} // MOJOSHADER_glCompileEffect
+
+
+void MOJOSHADER_glDeleteEffect(MOJOSHADER_glEffect *glEffect)
+{
+ int i;
+ MOJOSHADER_free f = glEffect->effect->free;
+ void *d = glEffect->effect->malloc_data;
+
+ for (i = 0; i < glEffect->num_shaders; i++)
+ {
+ /* Arbitarily add a reference to the refcount.
+ * We're going to be calling glDeleteShader so we can clean out the
+ * program cache, but we can NOT let it free() the array elements!
+ * We'll do that ourselves, as we malloc()'d in CompileEffect.
+ * -flibit
+ */
+ glEffect->shaders[i].refcount++;
+ MOJOSHADER_glDeleteShader(&glEffect->shaders[i]);
+
+ /* Delete the shader, but do NOT delete the parse data!
+ * The parse data belongs to the parent effect.
+ * -flibit
+ */
+ ctx->profileDeleteShader(glEffect->shaders[i].handle);
+ } // for
+
+ f(glEffect->shader_indices, d);
+ f(glEffect->preshader_indices, d);
+ f(glEffect, d);
+} // MOJOSHADER_glDeleteEffect
+
+
+void MOJOSHADER_glEffectBegin(MOJOSHADER_glEffect *glEffect,
+ unsigned int *numPasses,
+ int saveShaderState,
+ MOJOSHADER_effectStateChanges *stateChanges)
+{
+ *numPasses = glEffect->effect->current_technique->pass_count;
+ glEffect->effect->restore_shader_state = saveShaderState;
+ glEffect->effect->state_changes = stateChanges;
+
+ if (glEffect->effect->restore_shader_state)
+ glEffect->prev_program = ctx->bound_program;
+} // MOJOSHADER_glEffectBegin
+
+
+void MOJOSHADER_glEffectBeginPass(MOJOSHADER_glEffect *glEffect,
+ unsigned int pass)
+{
+ int i, j;
+ MOJOSHADER_effectPass *curPass;
+ MOJOSHADER_effectState *state;
+ MOJOSHADER_effectShader *rawVert = glEffect->current_vert_raw;
+ MOJOSHADER_effectShader *rawFrag = glEffect->current_frag_raw;
+ int has_preshader = 0;
+
+ if (ctx->bound_program != NULL)
+ {
+ glEffect->current_vert = ctx->bound_program->vertex;
+ glEffect->current_frag = ctx->bound_program->fragment;
+ } // if
+
+ assert(glEffect->effect->current_pass == -1);
+ glEffect->effect->current_pass = pass;
+ curPass = &glEffect->effect->current_technique->passes[pass];
+
+ // !!! FIXME: I bet this could be stored at parse/compile time. -flibit
+ for (i = 0; i < curPass->state_count; i++)
+ {
+ state = &curPass->states[i];
+ #define ASSIGN_SHADER(stype, raw, gls) \
+ (state->type == stype) \
+ { \
+ j = 0; \
+ do \
+ { \
+ if (*state->value.valuesI == glEffect->shader_indices[j]) \
+ { \
+ raw = &glEffect->effect->objects[*state->value.valuesI].shader; \
+ glEffect->gls = &glEffect->shaders[j]; \
+ break; \
+ } \
+ else if (glEffect->num_preshaders > 0 \
+ && *state->value.valuesI == glEffect->preshader_indices[j]) \
+ { \
+ raw = &glEffect->effect->objects[*state->value.valuesI].shader; \
+ has_preshader = 1; \
+ break; \
+ } \
+ } while (++j < glEffect->num_shaders); \
+ }
+ if ASSIGN_SHADER(MOJOSHADER_RS_VERTEXSHADER, rawVert, current_vert)
+ else if ASSIGN_SHADER(MOJOSHADER_RS_PIXELSHADER, rawFrag, current_frag)
+ #undef ASSIGN_SHADER
+ } // for
+
+ glEffect->effect->state_changes->render_state_changes = curPass->states;
+ glEffect->effect->state_changes->render_state_change_count = curPass->state_count;
+
+ glEffect->current_vert_raw = rawVert;
+ glEffect->current_frag_raw = rawFrag;
+
+ /* If this effect pass has an array of shaders, we get to wait until
+ * CommitChanges to actually bind the final shaders.
+ * -flibit
+ */
+ if (!has_preshader)
+ {
+ MOJOSHADER_glBindShaders(glEffect->current_vert,
+ glEffect->current_frag);
+ if (glEffect->current_vert_raw != NULL)
+ {
+ glEffect->effect->state_changes->vertex_sampler_state_changes = rawVert->samplers;
+ glEffect->effect->state_changes->vertex_sampler_state_change_count = rawVert->sampler_count;
+ } // if
+ if (glEffect->current_frag_raw != NULL)
+ {
+ glEffect->effect->state_changes->sampler_state_changes = rawFrag->samplers;
+ glEffect->effect->state_changes->sampler_state_change_count = rawFrag->sampler_count;
+ } // if
+ } // if
+
+ MOJOSHADER_glEffectCommitChanges(glEffect);
+} // MOJOSHADER_glEffectBeginPass
+
+
+static inline void copy_parameter_data(MOJOSHADER_effectParam *params,
+ unsigned int *param_loc,
+ MOJOSHADER_symbol *symbols,
+ unsigned int symbol_count,
+ GLfloat *regf, GLint *regi, uint8 *regb)
+{
+ int i, j, r, c;
+
+ i = 0;
+ for (i = 0; i < symbol_count; i++)
+ {
+ const MOJOSHADER_symbol *sym = &symbols[i];
+ const MOJOSHADER_effectValue *param = ¶ms[param_loc[i]].value;
+
+ // float/int registers are vec4, so they have 4 elements each
+ const uint32 start = sym->register_index << 2;
+
+ if (param->value_type == MOJOSHADER_SYMTYPE_FLOAT)
+ {
+ // Matrices have to be transposed from row-major to column-major!
+ if (param->value_class == MOJOSHADER_SYMCLASS_MATRIX_ROWS)
+ {
+ if (param->element_count > 1)
+ {
+ const uint32 regcount = sym->register_count / param->element_count;
+ j = 0;
+ do
+ {
+ r = 0;
+ do
+ {
+ c = 0;
+ do
+ {
+ const uint32 dest = start + c +
+ (r << 2) +
+ ((j << 2) * regcount);
+ const uint32 src = r +
+ (c * param->row_count) +
+ (j * param->row_count * param->column_count);
+ regf[dest] = param->valuesF[src];
+ } while (++c < param->column_count);
+ } while (++r < regcount);
+ } while (++j < param->element_count);
+ } // if
+ else
+ {
+ r = 0;
+ do
+ {
+ c = 0;
+ do
+ {
+ regf[start + (r << 2 ) + c] = param->valuesF[r + (c * param->row_count)];
+ } while (++c < param->column_count);
+ } while (++r < sym->register_count);
+ } // else
+ } // if
+ else if (sym->register_count > 1)
+ {
+ j = 0;
+ do
+ {
+ memcpy(regf + start + (j << 2),
+ param->valuesF + (j * param->column_count),
+ param->column_count << 2);
+ } while (++j < sym->register_count);
+ } // else if
+ else
+ memcpy(regf + start, param->valuesF, param->column_count << 2);
+ } // if
+ else if (sym->register_set == MOJOSHADER_SYMREGSET_FLOAT4)
+ {
+ // Sometimes int/bool parameters get thrown into float registers...
+ j = 0;
+ do
+ {
+ c = 0;
+ do
+ {
+ regf[start + (j << 2) + c] = (float) param->valuesI[(j * param->column_count) + c];
+ } while (++c < param->column_count);
+ } while (++j < sym->register_count);
+ } // else if
+ else if (sym->register_set == MOJOSHADER_SYMREGSET_INT4)
+ {
+ if (sym->register_count > 1)
+ {
+ j = 0;
+ do
+ {
+ memcpy(regi + start + (j << 2),
+ param->valuesI + (j * param->column_count),
+ param->column_count << 2);
+ } while (++j < sym->register_count);
+ } // if
+ else
+ memcpy(regi + start, param->valuesI, param->column_count << 2);
+ } // else if
+ else if (sym->register_set == MOJOSHADER_SYMREGSET_BOOL)
+ {
+ j = 0;
+ do
+ {
+ // regb is not a vec4, enjoy this bitshift! -flibit
+ regb[(start >> 2) + j] = param->valuesI[j];
+ } while (++j < sym->register_count);
+ } // else if
+ } // for
+} // copy_parameter_data
+
+
+void MOJOSHADER_glEffectCommitChanges(MOJOSHADER_glEffect *glEffect)
+{
+ MOJOSHADER_effectShader *rawVert = glEffect->current_vert_raw;
+ MOJOSHADER_effectShader *rawFrag = glEffect->current_frag_raw;
+
+ /* Used for shader selection from preshaders */
+ int i;
+ MOJOSHADER_effectValue *param;
+ float selector;
+ int shader_object;
+ int selector_ran = 0;
+
+ /* For effect passes with arrays of shaders, we have to run a preshader
+ * that determines which shader to use, based on a parameter's value.
+ * -flibit
+ */
+ // !!! FIXME: We're just running the preshaders every time. Blech. -flibit
+ #define SELECT_SHADER_FROM_PRESHADER(raw, gls) \
+ if (raw != NULL && raw->is_preshader) \
+ { \
+ i = 0; \
+ do \
+ { \
+ param = &glEffect->effect->params[raw->preshader_params[i]].value; \
+ memcpy(raw->preshader->registers + raw->preshader->symbols[i].register_index, \
+ param->values, \
+ param->value_count << 2); \
+ } while (++i < raw->preshader->symbol_count); \
+ MOJOSHADER_runPreshader(raw->preshader, &selector); \
+ shader_object = glEffect->effect->params[raw->params[0]].value.valuesI[(int) selector]; \
+ raw = &glEffect->effect->objects[shader_object].shader; \
+ i = 0; \
+ do \
+ { \
+ if (shader_object == glEffect->shader_indices[i]) \
+ { \
+ gls = &glEffect->shaders[i]; \
+ break; \
+ } \
+ } while (++i < glEffect->num_shaders); \
+ selector_ran = 1; \
+ }
+ SELECT_SHADER_FROM_PRESHADER(rawVert, glEffect->current_vert)
+ SELECT_SHADER_FROM_PRESHADER(rawFrag, glEffect->current_frag)
+ #undef SELECT_SHADER_FROM_PRESHADER
+ if (selector_ran)
+ {
+ MOJOSHADER_glBindShaders(glEffect->current_vert,
+ glEffect->current_frag);
+ if (glEffect->current_vert_raw != NULL)
+ {
+ glEffect->effect->state_changes->vertex_sampler_state_changes = rawVert->samplers;
+ glEffect->effect->state_changes->vertex_sampler_state_change_count = rawVert->sampler_count;
+ } // if
+ if (glEffect->current_frag_raw != NULL)
+ {
+ glEffect->effect->state_changes->sampler_state_changes = rawFrag->samplers;
+ glEffect->effect->state_changes->sampler_state_change_count = rawFrag->sampler_count;
+ } // if
+ } // if
+
+ /* This is where parameters are copied into the constant buffers.
+ * If you're looking for where things slow down immensely, look at
+ * the copy_parameter_data() and MOJOSHADER_runPreshader() functions.
+ * -flibit
+ */
+ // !!! FIXME: We're just copying everything every time. Blech. -flibit
+ // !!! FIXME: We're just running the preshaders every time. Blech. -flibit
+ // !!! FIXME: Will the preshader ever want int/bool registers? -flibit
+ #define COPY_PARAMETER_DATA(raw, stage) \
+ if (raw != NULL) \
+ { \
+ if (ctx->bound_program->stage##_float4_loc != -1) \
+ memset(ctx->stage##_reg_file_f, '\0', ctx->bound_program->stage##_uniforms_float4_count << 4); \
+ if (ctx->bound_program->stage##_int4_loc != -1) \
+ memset(ctx->stage##_reg_file_i, '\0', ctx->bound_program->stage##_uniforms_int4_count << 4); \
+ if (ctx->bound_program->stage##_bool_loc != -1) \
+ memset(ctx->stage##_reg_file_b, '\0', ctx->bound_program->stage##_uniforms_bool_count << 2); \
+ copy_parameter_data(glEffect->effect->params, raw->params, \
+ raw->shader->symbols, \
+ raw->shader->symbol_count, \
+ ctx->stage##_reg_file_f, \
+ ctx->stage##_reg_file_i, \
+ ctx->stage##_reg_file_b); \
+ if (raw->shader->preshader) \
+ { \
+ copy_parameter_data(glEffect->effect->params, raw->preshader_params, \
+ raw->shader->preshader->symbols, \
+ raw->shader->preshader->symbol_count, \
+ raw->shader->preshader->registers, \
+ NULL, \
+ NULL); \
+ MOJOSHADER_runPreshader(raw->shader->preshader, ctx->stage##_reg_file_f); \
+ } \
+ }
+ COPY_PARAMETER_DATA(rawVert, vs)
+ COPY_PARAMETER_DATA(rawFrag, ps)
+ #undef COPY_PARAMETER_DATA
+
+ ctx->generation++;
+} // MOJOSHADER_glEffectCommitChanges
+
+
+void MOJOSHADER_glEffectEndPass(MOJOSHADER_glEffect *glEffect)
+{
+ assert(glEffect->effect->current_pass != -1);
+ glEffect->effect->current_pass = -1;
+} // MOJOSHADER_glEffectEndPass
+
+
+void MOJOSHADER_glEffectEnd(MOJOSHADER_glEffect *glEffect)
+{
+ if (glEffect->effect->restore_shader_state)
+ {
+ glEffect->effect->restore_shader_state = 0;
+ MOJOSHADER_glBindProgram(glEffect->prev_program);
+ } // if
+
+ glEffect->effect->state_changes = NULL;
+} // MOJOSHADER_glEffectEnd
+
+
+#endif // MOJOSHADER_EFFECT_SUPPORT
+
// end of mojoshader_opengl.c ...
--- a/utils/testparse.c Tue Oct 13 12:08:55 2015 -0400
+++ b/utils/testparse.c Fri Jan 01 02:12:19 2016 -0500
@@ -177,6 +177,15 @@
if (operand->type == MOJOSHADER_PRESHADEROPERAND_TEMP)
regch = 'r';
+ if (operand->array_register_count > 0)
+ {
+ for (i = operand->array_register_count - 1; i >= 0; i--)
+ printf("c%d[", operand->array_registers[i]);
+ printf("%c%d.%c", regch, operand->index / 4, mask[idx]);
+ for (i = 0; i < operand->array_register_count; i++)
+ printf("]");
+ break;
+ } // if
printf("%c%d", regch, operand->index / 4);
if (isscalar)
printf(".%c", mask[idx]);
@@ -403,10 +412,149 @@
} // print_shader
+#ifdef MOJOSHADER_EFFECT_SUPPORT
+
+
+static void print_value(const MOJOSHADER_effectValue *value,
+ const unsigned int indent)
+{
+ int i;
+
+ INDENT();
+ printf("VALUE: %s -> %s\n", value->name, value->semantic);
+
+ static const char *classes[] =
+ {
+ "SCALAR",
+ "VECTOR",
+ "ROW-MAJOR MATRIX",
+ "COLUMN-MAJOR MATRIX",
+ "OBJECT",
+ "STRUCT"
+ };
+ static const char *types[] =
+ {
+ "VOID",
+ "BOOL",
+ "INT",
+ "FLOAT",
+ "STRING",
+ "TEXTURE",
+ "TEXTURE1D",
+ "TEXTURE2D",
+ "TEXTURE3D",
+ "TEXTURECUBE",
+ "SAMPLER",
+ "SAMPLER1D",
+ "SAMPLER2D",
+ "SAMPLER3D",
+ "SAMPLERCUBE",
+ "PIXELSHADER",
+ "VERTEXSHADER",
+ "UNSUPPORTED"
+ };
+ do_indent(indent + 1);
+ printf("CLASS: %s\n", classes[value->value_class]);
+ do_indent(indent + 1);
+ printf("TYPE: %s\n", types[value->value_type]);
+
+ do_indent(indent + 1);
+ printf("ROWS/COLUMNS/ELEMENTS: %d, %d, %d\n",
+ value->row_count, value->column_count, value->element_count);
+ do_indent(indent + 1);
+ printf("TOTAL VALUES: %d\n", value->value_count);
+
+ if (value->value_type == MOJOSHADER_SYMTYPE_SAMPLER
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || value->value_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ {
+ do_indent(indent + 1);
+ printf("SAMPLER VALUES:\n");
+ for (i = 0; i < value->value_count; i++)
+ {
+ MOJOSHADER_effectSamplerState *state = &value->valuesSS[i];
+
+ static const char *samplerstatetypes[] =
+ {
+ "UNKNOWN0",
+ "UNKNOWN1",
+ "UNKNOWN2",
+ "UNKNOWN3",
+ "TEXTURE",
+ "ADDRESSU",
+ "ADDRESSV",
+ "ADDRESSW",
+ "BORDERCOLOR",
+ "MAGFILTER",
+ "MINFILTER",
+ "MIPFILTER",
+ "MIPMAPLODBIAS",
+ "MAXMIPLEVEL",
+ "MAXANISOTROPY",
+ "SRGBTEXTURE",
+ "ELEMENTINDEX",
+ "DMAPOFFSET",
+ };
+ do_indent(indent + 2);
+ printf("TYPE: %s -> ", samplerstatetypes[state->type]);
+
+ /* Assuming only one value per state! */
+ if (state->type == MOJOSHADER_SAMP_MIPMAPLODBIAS)
+ {
+ /* float types */
+ printf("%.2f\n", *state->value.valuesF);
+ } // if
+ else
+ {
+ /* int/enum types */
+ printf("%d\n", *state->value.valuesI);
+ } // else
+ } // for
+ } // if
+ else
+ {
+ do_indent(indent + 1);
+ printf("%s VALUES:\n", types[value->value_type]);
+ for (i = 0; i < value->value_count; i++)
+ {
+ do_indent(indent + 2);
+ static const char *prints[] =
+ {
+ "%X\n",
+ "%d\n",
+ "%d\n",
+ "%.2f\n",
+ "%d\n",
+ "%d\n",
+ "%d\n",
+ "%d\n",
+ "%d\n",
+ "%d\n",
+ "SAMPLER?!\n",
+ "SAMPLER?!\n",
+ "SAMPLER?!\n",
+ "SAMPLER?!\n",
+ "SAMPLER?!\n",
+ "%d\n",
+ "%d\n",
+ "%X\n"
+ };
+ if (value->value_type == MOJOSHADER_SYMTYPE_FLOAT)
+ printf(prints[value->value_type], value->valuesF[i]);
+ else
+ printf(prints[value->value_type], value->valuesI[i]);
+ } // for
+ } // else
+} // print_value
+
+
static void print_effect(const char *fname, const MOJOSHADER_effect *effect,
const unsigned int indent)
{
- INDENT(); printf("PROFILE: %s\n", effect->profile);
+ INDENT();
+ printf("PROFILE: %s\n", effect->profile);
printf("\n");
if (effect->error_count > 0)
{
@@ -424,63 +572,107 @@
{
int i, j, k;
const MOJOSHADER_effectTechnique *technique = effect->techniques;
- const MOJOSHADER_effectTexture *texture = effect->textures;
- const MOJOSHADER_effectShader *shader = effect->shaders;
+ const MOJOSHADER_effectObject *object = effect->objects;
const MOJOSHADER_effectParam *param = effect->params;
for (i = 0; i < effect->param_count; i++, param++)
{
INDENT();
- printf("PARAM #%d '%s' -> '%s'\n", i, param->name, param->semantic);
+ printf("PARAM #%d\n", i);
+ print_value(¶m->value, indent + 1);
+
+ if (param->annotation_count > 0)
+ {
+ do_indent(indent + 1);
+ printf("ANNOTATIONS:\n");
+ } // if
+ for (j = 0; j < param->annotation_count; j++)
+ {
+ print_value(¶m->annotations[j], indent + 2);
+ } // for
} // for
-
printf("\n");
for (i = 0; i < effect->technique_count; i++, technique++)
{
const MOJOSHADER_effectPass *pass = technique->passes;
- INDENT(); printf("TECHNIQUE #%d ('%s'):\n", i, technique->name);
+ INDENT();
+ printf("TECHNIQUE #%d ('%s'):\n", i, technique->name);
for (j = 0; j < technique->pass_count; j++, pass++)
{
const MOJOSHADER_effectState *state = pass->states;
- INDENT(); printf(" PASS #%d ('%s'):\n", j, pass->name);
+ do_indent(indent + 1);
+ printf("PASS #%d ('%s'):\n", j, pass->name);
for (k = 0; k < pass->state_count; k++, state++)
{
- INDENT(); printf(" STATE 0x%X\n", state->type);
+ do_indent(indent + 2);
+ printf("STATE %d:\n", state->type);
+ print_value(&state->value, indent + 3);
} // for
} // for
- printf("\n");
} // for
+ printf("\n");
- for (i = 0; i < effect->texture_count; i++, texture++)
+ /* Start at index 1, 0 is always empty (thanks Microsoft!) */
+ object++;
+ for (i = 1; i < effect->object_count; i++, object++)
{
INDENT();
- printf("TEXTURE #%d ('%s'): %u\n", i,
- texture->name, texture->param);
- } // for
-
- printf("\n");
-
- for (i = 0; i < effect->shader_count; i++, shader++)
- {
- INDENT();
- printf("SHADER #%d: technique %u, pass %u\n", i,
- shader->technique, shader->pass);
- print_shader(fname, shader->shader, indent + 1);
+ if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
+ || object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
+ {
+ if (object->shader.is_preshader)
+ {
+ printf("OBJECT #%d: PRESHADER, technique %u, pass %u, param %s\n", i,
+ object->shader.technique, object->shader.pass,
+ effect->params[object->shader.params[0]].value.name);
+ print_preshader(object->shader.preshader, indent + 1);
+ } // if
+ else
+ {
+ printf("OBJECT #%d: SHADER, technique %u, pass %u\n", i,
+ object->shader.technique, object->shader.pass);
+ print_shader(fname, object->shader.shader, indent + 1);
+ } // else
+ } // if
+ else if (object->type == MOJOSHADER_SYMTYPE_STRING)
+ printf("OBJECT #%d: STRING, '%s'\n", i,
+ object->string.string);
+ else if (object->type == MOJOSHADER_SYMTYPE_SAMPLER
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER1D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER2D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLER3D
+ || object->type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
+ printf("OBJECT #%d: MAPPING, '%s'\n", i,
+ object->mapping.name);
+ else if (object->type == MOJOSHADER_SYMTYPE_TEXTURE
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURE1D
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURE2D
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURE3D
+ || object->type == MOJOSHADER_SYMTYPE_TEXTURECUBE)
+ printf("OBJECT #%d: TEXTURE\n", i);
+ else
+ printf("UNKNOWN OBJECT: #%d\n", i);
} // for
} // else
} // print_effect
+#endif // MOJOSHADER_EFFECT_SUPPORT
+
+
static int do_parse(const char *fname, const unsigned char *buf,
const int len, const char *prof)
{
int retval = 0;
// magic for an effects file (!!! FIXME: I _think_).
- if ( (buf[0] == 0x01) && (buf[1] == 0x09) &&
- (buf[2] == 0xFF) && (buf[3] == 0xFE) )
+ if ( ((buf[0] == 0x01) && (buf[1] == 0x09) &&
+ (buf[2] == 0xFF) && (buf[3] == 0xFE)) ||
+ ((buf[0] == 0xCF) && (buf[1] == 0x0B) &&
+ (buf[2] == 0xF0) && (buf[3] == 0xBC)) )
{
+#ifdef MOJOSHADER_EFFECT_SUPPORT
const MOJOSHADER_effect *effect;
effect = MOJOSHADER_parseEffect(prof, buf, len, NULL, 0,
NULL, 0, Malloc, Free, 0);
@@ -488,6 +680,9 @@
printf("EFFECT: %s\n", fname);
print_effect(fname, effect, 1);
MOJOSHADER_freeEffect(effect);
+#else
+ printf("Is an effect, but effect support is disabled!\n");
+#endif
} // if
else // do it as a regular compiled shader.