#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
#ifdef MOJOSHADER_EFFECT_SUPPORT
#ifndef MOJOSHADER_USE_SDL_STDLIB
#include <math.h>
#endif
void MOJOSHADER_runPreshader(const MOJOSHADER_preshader *preshader,
float *outregs)
{
const float *inregs = preshader->registers;
const int scalarstart = (int) MOJOSHADER_PRESHADEROP_SCALAR_OPS;
double *temps = NULL;
if (preshader->temp_count > 0)
{
temps = (double *) alloca(sizeof (double) * preshader->temp_count);
memset(temps, '\0', sizeof (double) * preshader->temp_count);
}
double dst[4] = { 0, 0, 0, 0 };
double src[3][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
const double *src0 = &src[0][0];
const double *src1 = &src[1][0];
const double *src2 = &src[2][0];
MOJOSHADER_preshaderInstruction *inst = preshader->instructions;
int instit;
#if 0#endif
for (instit = 0; instit < preshader->instruction_count; instit++, inst++)
{
const MOJOSHADER_preshaderOperand *operand = inst->operands;
const int elems = inst->element_count;
const int elemsbytes = sizeof (double) * elems;
const int isscalarop = (inst->opcode >= scalarstart);
assert(elems >= 0);
assert(elems <= 4);
int opiter, elemiter;
for (opiter = 0; opiter < inst->operand_count-1; opiter++, operand++)
{
const int isscalar = ((isscalarop) && (opiter == 0));
const unsigned int index = operand->index;
switch (operand->type)
{
case MOJOSHADER_PRESHADEROPERAND_LITERAL:
{
if (!isscalar)
{
assert((index + elems) <= preshader->literal_count);
memcpy(&src[opiter][0], &preshader->literals[index], elemsbytes);
} else
{
for (elemiter = 0; elemiter < elems; elemiter++)
src[opiter][elemiter] = preshader->literals[index];
} break;
}
case MOJOSHADER_PRESHADEROPERAND_INPUT:
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;
} else if (isscalar)
src[opiter][0] = inregs[index];
else
{
int cpy;
for (cpy = 0; cpy < elems; cpy++)
src[opiter][cpy] = inregs[index+cpy];
} break;
case MOJOSHADER_PRESHADEROPERAND_OUTPUT:
if (isscalar)
src[opiter][0] = outregs[index];
else
{
int cpy;
for (cpy = 0; cpy < elems; cpy++)
src[opiter][cpy] = outregs[index+cpy];
} break;
case MOJOSHADER_PRESHADEROPERAND_TEMP:
if (temps != NULL)
{
if (isscalar)
src[opiter][0] = temps[index];
else
memcpy(src[opiter], temps + index, elemsbytes);
} break;
default:
assert(0 && "unexpected preshader operand type.");
return;
} }
int i;
switch (inst->opcode)
{
#define OPCODE_CASE(op, val) \
case MOJOSHADER_PRESHADEROP_##op: \
for (i = 0; i < elems; i++) { dst[i] = val; } \
break;
OPCODE_CASE(MOV, src0[i])
OPCODE_CASE(NEG, -src0[i])
OPCODE_CASE(RCP, 1.0 / src0[i])
OPCODE_CASE(FRC, src0[i] - floor(src0[i]))
OPCODE_CASE(EXP, exp(src0[i]))
OPCODE_CASE(LOG, log(src0[i]))
OPCODE_CASE(RSQ, 1.0 / sqrt(src0[i]))
OPCODE_CASE(SIN, sin(src0[i]))
OPCODE_CASE(COS, cos(src0[i]))
OPCODE_CASE(ASIN, asin(src0[i]))
OPCODE_CASE(ACOS, acos(src0[i]))
OPCODE_CASE(ATAN, atan(src0[i]))
OPCODE_CASE(MIN, (src0[i] < src1[i]) ? src0[i] : src1[i])
OPCODE_CASE(MAX, (src0[i] > src1[i]) ? src0[i] : src1[i])
OPCODE_CASE(LT, (src0[i] < src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(GE, (src0[i] >= src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(ADD, src0[i] + src1[i])
OPCODE_CASE(MUL, src0[i] * src1[i])
OPCODE_CASE(ATAN2, atan2(src0[i], src1[i]))
OPCODE_CASE(DIV, src0[i] / src1[i])
OPCODE_CASE(CMP, (src0[i] >= 0.0) ? src1[i] : src2[i])
OPCODE_CASE(MIN_SCALAR, (src0[0] < src1[i]) ? src0[0] : src1[i])
OPCODE_CASE(MAX_SCALAR, (src0[0] > src1[i]) ? src0[0] : src1[i])
OPCODE_CASE(LT_SCALAR, (src0[0] < src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(GE_SCALAR, (src0[0] >= src1[i]) ? 1.0 : 0.0)
OPCODE_CASE(ADD_SCALAR, src0[0] + src1[i])
OPCODE_CASE(MUL_SCALAR, src0[0] * src1[i])
OPCODE_CASE(ATAN2_SCALAR, atan2(src0[0], src1[i]))
OPCODE_CASE(DIV_SCALAR, src0[0] / src1[i])
#undef OPCODE_CASE
case MOJOSHADER_PRESHADEROP_DOT:
{
double final = 0.0;
for (i = 0; i < elems; i++)
final += src0[i] * src1[i];
for (i = 0; i < elems; i++)
dst[i] = final; break;
}
default:
assert(0 && "Unhandled preshader opcode!");
break;
}
if (operand->type == MOJOSHADER_PRESHADEROPERAND_TEMP)
{
assert(preshader->temp_count >=
operand->index + (elemsbytes / sizeof (double)));
memcpy(temps + operand->index, dst, elemsbytes);
} else
{
assert(operand->type == MOJOSHADER_PRESHADEROPERAND_OUTPUT);
for (i = 0; i < elems; i++)
outregs[operand->index + i] = (float) dst[i];
} } }
static MOJOSHADER_effect MOJOSHADER_out_of_mem_effect = {
1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static MOJOSHADER_error MOJOSHADER_need_a_backend_error = {
"Need a MOJOSHADER_effectShaderContext", NULL, MOJOSHADER_POSITION_NONE
};
static MOJOSHADER_effect MOJOSHADER_need_a_backend_effect = {
1, &MOJOSHADER_need_a_backend_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static MOJOSHADER_error MOJOSHADER_unexpected_eof_error = {
"Unexpected EOF", NULL, MOJOSHADER_POSITION_NONE
};
static MOJOSHADER_effect MOJOSHADER_unexpected_eof_effect = {
1, &MOJOSHADER_unexpected_eof_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static MOJOSHADER_error MOJOSHADER_not_an_effect_error = {
"Not an Effects Framework binary", NULL, MOJOSHADER_POSITION_NONE
};
static MOJOSHADER_effect MOJOSHADER_not_an_effect_effect = {
1, &MOJOSHADER_not_an_effect_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static void push_errors(ErrorList *list, MOJOSHADER_error *errors, int len)
{
int i;
for (i = 0; i < len; i += 1)
errorlist_add(list, errors[i].filename, errors[i].error_position, errors[i].error);
}
static uint32 readui32(const uint8 **_ptr, uint32 *_len)
{
uint32 retval = 0;
if (*_len < sizeof (retval))
*_len = 0;
else
{
const uint32 *ptr = (const uint32 *) *_ptr;
retval = SWAP32(*ptr);
*_ptr += sizeof (retval);
*_len -= sizeof (retval);
} return retval;
}
static char *readstring(const uint8 *base,
const uint32 offset,
MOJOSHADER_malloc m,
void *d)
{
const char *str = ((const char *) base) + offset;
const uint32 len = *((const uint32 *) str);
char *strptr = NULL;
if (len == 0) return NULL;
strptr = (char *) m(len, d);
memcpy(strptr, str + 4, len);
return strptr;
}
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!");
return -1;
}
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, j, k;
const uint8 *typeptr = base + typeoffset;
const uint8 *valptr = base + valoffset;
unsigned int typelen = 9999999; 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->type.parameter_type = (MOJOSHADER_symbolType) type;
value->type.parameter_class = (MOJOSHADER_symbolClass) valclass;
value->name = readstring(base, name, m, d);
value->semantic = readstring(base, semantic, m, d);
value->type.elements = numelements;
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)
{
assert(type >= MOJOSHADER_SYMTYPE_BOOL && type <= MOJOSHADER_SYMTYPE_FLOAT);
const uint32 columncount = readui32(&typeptr, &typelen);
const uint32 rowcount = readui32(&typeptr, &typelen);
value->type.columns = columncount;
value->type.rows = rowcount;
uint32 siz = 4 * rowcount;
if (numelements > 0)
siz *= numelements;
value->value_count = siz;
siz *= 4;
value->values = m(siz, d);
memset(value->values, '\0', siz);
siz /= 16;
for (i = 0; i < siz; i++)
memcpy(value->valuesF + (i << 2), valptr + ((columncount << 2) * i), columncount << 2);
} else if (valclass == MOJOSHADER_SYMCLASS_OBJECT)
{
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; 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;
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;
} } 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 if (valclass == MOJOSHADER_SYMCLASS_STRUCT)
{
uint32 siz;
value->type.member_count = readui32(&typeptr, &typelen);
siz = value->type.member_count * sizeof (MOJOSHADER_symbolStructMember);
value->type.members = (MOJOSHADER_symbolStructMember *) m(siz, d);
uint32 structsize = 0;
for (i = 0; i < value->type.member_count; i++)
{
MOJOSHADER_symbolStructMember *mem = &value->type.members[i];
mem->info.parameter_type = (MOJOSHADER_symbolType) readui32(&typeptr, &typelen);
mem->info.parameter_class = (MOJOSHADER_symbolClass) readui32(&typeptr, &typelen);
const uint32 memname = readui32(&typeptr, &typelen);
readui32(&typeptr, &typelen);
mem->name = readstring(base, memname, m, d);
mem->info.elements = readui32(&typeptr, &typelen);
mem->info.columns = readui32(&typeptr, &typelen);
mem->info.rows = readui32(&typeptr, &typelen);
assert(mem->info.parameter_class >= MOJOSHADER_SYMCLASS_SCALAR
&& mem->info.parameter_class <= MOJOSHADER_SYMCLASS_MATRIX_COLUMNS);
assert(mem->info.parameter_type >= MOJOSHADER_SYMTYPE_BOOL
&& mem->info.parameter_type <= MOJOSHADER_SYMTYPE_FLOAT);
mem->info.member_count = 0;
mem->info.members = NULL;
uint32 memsize = 4 * mem->info.rows;
if (mem->info.elements > 0)
memsize *= mem->info.elements;
structsize += memsize;
}
value->type.columns = structsize;
value->type.rows = 1;
value->value_count = structsize;
if (numelements > 0)
value->value_count *= numelements;
siz = value->value_count * 4;
value->values = m(siz, d);
memset(value->values, '\0', siz);
int dst_offset = 0, src_offset = 0;
i = 0;
do
{
for (j = 0; j < value->type.member_count; j++)
{
siz = value->type.members[j].info.rows * value->type.members[j].info.elements;
for (k = 0; k < siz; k++)
{
memcpy(value->valuesF + dst_offset,
typeptr + src_offset,
value->type.members[j].info.columns << 2);
dst_offset += 4;
src_offset += value->type.members[j].info.columns << 2;
} }
} while (++i < numelements);
} }
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);
} }
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);
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);
} }
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);
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);
} }
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);
} }
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);
} }
static void readsmallobjects(const uint32 numsmallobjects,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effect *effect,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
ErrorList *errors)
{
int i, j;
MOJOSHADER_parseData *pd;
MOJOSHADER_malloc m = effect->ctx.m;
void *d = effect->ctx.malloc_data;
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;
} } 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
|| 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;
} } else if (object->type == MOJOSHADER_SYMTYPE_PIXELSHADER
|| object->type == MOJOSHADER_SYMTYPE_VERTEXSHADER)
{
char mainfn[32];
snprintf(mainfn, sizeof(mainfn), "ShaderFunction%u", (unsigned int) index);
object->shader.technique = -1;
object->shader.pass = -1;
object->shader.shader = effect->ctx.compileShader(mainfn, *ptr, length,
swiz, swizcount,
smap, smapcount);
if (object->shader.shader == NULL)
{
errorlist_add(errors, NULL, 0, effect->ctx.getError());
return;
} pd = effect->ctx.getParseData(object->shader.shader);
if (pd->error_count > 0)
{
push_errors(errors, pd->errors, pd->error_count);
return;
}
for (j = 0; j < pd->symbol_count; j++)
if (pd->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
object->shader.sampler_count++;
object->shader.param_count = pd->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 < pd->symbol_count; j++)
{
int par = findparameter(effect->params,
effect->param_count,
pd->symbols[j].name);
object->shader.params[j] = par;
if (pd->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
{
object->shader.samplers[curSampler].sampler_name = effect->params[par].value.name;
object->shader.samplers[curSampler].sampler_register = pd->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 (pd->preshader)
{
object->shader.preshader_param_count = pd->preshader->symbol_count;
object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
for (j = 0; j < pd->preshader->symbol_count; j++)
{
object->shader.preshader_params[j] = findparameter(effect->params,
effect->param_count,
pd->preshader->symbols[j].name);
} } } else
{
assert(0 && "Small object type unknown!");
}
const uint32 blocklen = (length + 3) - ((length - 1) % 4);
*ptr += blocklen;
*len -= blocklen;
} }
static void readlargeobjects(const uint32 numlargeobjects,
const uint32 numsmallobjects,
const uint8 **ptr,
uint32 *len,
MOJOSHADER_effect *effect,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
ErrorList *errors)
{
int i, j;
MOJOSHADER_parseData *pd;
MOJOSHADER_malloc m = effect->ctx.m;
MOJOSHADER_free f = effect->ctx.f;
void *d = effect->ctx.malloc_data;
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);
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;
if (type == 2)
{
object->shader.is_preshader = 1;
const uint32 start = *((uint32 *) *ptr) + 4;
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,
m, f, d);
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);
} } else
{
char mainfn[32];
snprintf(mainfn, sizeof (mainfn), "ShaderFunction%u", (unsigned int) objectIndex);
object->shader.shader = effect->ctx.compileShader(mainfn, *ptr, length,
swiz, swizcount,
smap, smapcount);
if (object->shader.shader == NULL)
{
errorlist_add(errors, NULL, 0, effect->ctx.getError());
return;
} pd = effect->ctx.getParseData(object->shader.shader);
if (pd->error_count > 0)
{
push_errors(errors, pd->errors, pd->error_count);
return;
}
for (j = 0; j < pd->symbol_count; j++)
if (pd->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
object->shader.sampler_count++;
object->shader.param_count = pd->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 < pd->symbol_count; j++)
{
int par = findparameter(effect->params,
effect->param_count,
pd->symbols[j].name);
object->shader.params[j] = par;
if (pd->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
{
object->shader.samplers[curSampler].sampler_name = effect->params[par].value.name;
object->shader.samplers[curSampler].sampler_register = pd->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 (pd->preshader)
{
object->shader.preshader_param_count = pd->preshader->symbol_count;
object->shader.preshader_params = (uint32 *) m(object->shader.preshader_param_count * sizeof (uint32), d);
for (j = 0; j < pd->preshader->symbol_count; j++)
{
object->shader.preshader_params[j] = findparameter(effect->params,
effect->param_count,
pd->preshader->symbols[j].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
|| 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;
} } else if (object->type != MOJOSHADER_SYMTYPE_VOID) {
assert(0 && "Large object type unknown!");
}
const uint32 blocklen = (length + 3) - ((length - 1) % 4);
*ptr += blocklen;
*len -= blocklen;
} }
MOJOSHADER_effect *MOJOSHADER_compileEffect(const unsigned char *buf,
const unsigned int _len,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
const MOJOSHADER_effectShaderContext *ctx)
{
const uint8 *ptr = (const uint8 *) buf;
uint32 len = (uint32) _len;
ErrorList *errors;
MOJOSHADER_malloc m;
MOJOSHADER_free f;
void *d;
if (ctx == NULL)
return &MOJOSHADER_need_a_backend_effect;
if ( ((ctx->m == NULL) && (ctx->f != NULL))
|| ((ctx->m != NULL) && (ctx->f == NULL)) )
return &MOJOSHADER_out_of_mem_effect;
if (ctx->m == NULL)
m = MOJOSHADER_internal_malloc;
else
m = ctx->m;
if (ctx->f == NULL)
f = MOJOSHADER_internal_free;
else
f = ctx->f;
d = ctx->malloc_data;
MOJOSHADER_effect *retval = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect),
ctx->malloc_data);
if (retval == NULL)
return &MOJOSHADER_out_of_mem_effect;
memset(retval, '\0', sizeof (*retval));
memcpy(&retval->ctx, ctx, sizeof(MOJOSHADER_effectShaderContext));
retval->ctx.m = m;
retval->ctx.f = f;
if (len < 8)
goto parseEffect_unexpectedEOF;
const uint8 *base = NULL;
uint32 header = readui32(&ptr, &len);
if (header == 0xBCF00BCF)
{
const uint32 skip = readui32(&ptr, &len) - 8;
ptr += skip;
len += skip;
header = readui32(&ptr, &len);
} if (header != 0xFEFF0901)
{
MOJOSHADER_deleteEffect(retval);
return &MOJOSHADER_not_an_effect_effect;
} else
{
const uint32 offset = readui32(&ptr, &len);
base = ptr;
if (offset > len)
goto parseEffect_unexpectedEOF;
ptr += offset;
len -= offset;
}
if (len < 16)
goto parseEffect_unexpectedEOF;
const uint32 numparams = readui32(&ptr, &len);
const uint32 numtechniques = readui32(&ptr, &len);
readui32(&ptr, &len);
const uint32 numobjects = readui32(&ptr, &len);
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);
retval->param_count = numparams;
readparameters(numparams, base, &ptr, &len,
&retval->params, retval->objects,
m, d);
retval->technique_count = numtechniques;
readtechniques(numtechniques, base, &ptr, &len,
&retval->techniques, retval->objects,
m, d);
retval->current_technique = &retval->techniques[0];
retval->current_pass = -1;
if (len < 8)
goto parseEffect_unexpectedEOF;
const int numsmallobjects = readui32(&ptr, &len);
const int numlargeobjects = readui32(&ptr, &len);
errors = errorlist_create(m, f, d);
if (errors == NULL)
goto parseEffect_outOfMemory;
readsmallobjects(numsmallobjects, &ptr, &len, retval,
swiz, swizcount, smap, smapcount, errors);
if (errorlist_count(errors) == 0)
{
readlargeobjects(numlargeobjects, numsmallobjects, &ptr, &len, retval,
swiz, swizcount, smap, smapcount, errors);
}
retval->error_count = errorlist_count(errors);
retval->errors = errorlist_flatten(errors);
errorlist_destroy(errors);
return retval;
parseEffect_unexpectedEOF:
MOJOSHADER_deleteEffect(retval);
return &MOJOSHADER_unexpected_eof_effect;
parseEffect_outOfMemory:
MOJOSHADER_deleteEffect(retval);
return &MOJOSHADER_out_of_mem_effect;
}
void freetypeinfo(MOJOSHADER_symbolTypeInfo *typeinfo,
MOJOSHADER_free f, void *d)
{
int i;
for (i = 0; i < typeinfo->member_count; i++)
{
f((void *) typeinfo->members[i].name, d);
freetypeinfo(&typeinfo->members[i].info, f, d);
} f((void *) typeinfo->members, d);
}
void freevalue(MOJOSHADER_effectValue *value, MOJOSHADER_free f, void *d)
{
int i;
f((void *) value->name, d);
f((void *) value->semantic, d);
freetypeinfo(&value->type, f, d);
if (value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| value->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
for (i = 0; i < value->value_count; i++)
freevalue(&value->valuesSS[i].value, f, d);
f(value->values, d);
}
void MOJOSHADER_deleteEffect(const MOJOSHADER_effect *_effect)
{
MOJOSHADER_effect *effect = (MOJOSHADER_effect *) _effect;
if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
return;
MOJOSHADER_free f = effect->ctx.f;
void *d = effect->ctx.malloc_data;
int i, j, k;
for (i = 0; i < effect->error_count; i++)
{
f((void *) effect->errors[i].error, d);
f((void *) effect->errors[i].filename, d);
} f((void *) effect->errors, d);
for (i = 0; i < effect->param_count; i++)
{
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);
} f((void *) param->annotations, d);
} f((void *) effect->params, d);
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++)
{
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);
} f((void *) pass->states, d);
for (k = 0; k < pass->annotation_count; k++)
{
freevalue(&pass->annotations[k], f, d);
} f((void *) pass->annotations, d);
} f((void *) technique->passes, d);
for (j = 0; j < technique->annotation_count; j++)
{
freevalue(&technique->annotations[j], f, d);
} f((void *) technique->annotations, d);
} f((void *) effect->techniques, d);
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);
else
effect->ctx.deleteShader(object->shader.shader);
f((void *) object->shader.params, d);
f((void *) object->shader.samplers, d);
f((void *) object->shader.preshader_params, d);
} 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);
} f((void *) effect->objects, d);
f((void *) effect, d);
}
#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; \
}
void copysymboltypeinfo(MOJOSHADER_symbolTypeInfo *dst,
MOJOSHADER_symbolTypeInfo *src,
MOJOSHADER_malloc m,
void *d)
{
int i;
uint32 siz = 0;
char *stringcopy = NULL;
memcpy(dst, src, sizeof (MOJOSHADER_symbolTypeInfo));
if (dst->member_count > 0)
{
siz = dst->member_count * sizeof (MOJOSHADER_symbolStructMember);
dst->members = (MOJOSHADER_symbolStructMember *) m(siz, d);
for (i = 0; i < dst->member_count; i++)
{
COPY_STRING(members[i].name)
copysymboltypeinfo(&dst->members[i].info, &src->members[i].info, m, d);
} } }
void copyvalue(MOJOSHADER_effectValue *dst,
MOJOSHADER_effectValue *src,
MOJOSHADER_malloc m,
void *d)
{
int i;
uint32 siz = 0;
char *stringcopy = NULL;
COPY_STRING(name)
COPY_STRING(semantic)
copysymboltypeinfo(&dst->type, &src->type, m, d);
dst->value_count = src->value_count;
if (dst->type.parameter_class == MOJOSHADER_SYMCLASS_SCALAR
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_VECTOR
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_MATRIX_ROWS
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_MATRIX_COLUMNS
|| dst->type.parameter_class == MOJOSHADER_SYMCLASS_STRUCT)
{
siz = dst->value_count * 4;
dst->values = m(siz, d);
memcpy(dst->values, src->values, siz);
} else if (dst->type.parameter_class == MOJOSHADER_SYMCLASS_OBJECT)
{
if (dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER1D
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER2D
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLER3D
|| dst->type.parameter_type == MOJOSHADER_SYMTYPE_SAMPLERCUBE)
{
siz = dst->value_count * sizeof (MOJOSHADER_effectSamplerState);
dst->values = m(siz, d);
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);
} } else
{
siz = dst->value_count * 4;
dst->values = m(siz, d);
memcpy(dst->values, src->values, siz);
} }
}
#undef COPY_STRING
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);
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;
} copysymbolinfo(&dst->members[i].info, &src->members[i].info, m, d);
} } }
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);
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);
}
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);
memset(retval, '\0', sizeof (MOJOSHADER_preshader));
siz = sizeof (double) * src->literal_count;
retval->literal_count = src->literal_count;
retval->literals = (double *) m(siz, d);
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);
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);
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);
memcpy(retval->instructions[i].operands[j].array_registers,
src->instructions[i].operands[j].array_registers,
siz);
}
siz = sizeof (float) * 4 * src->register_count;
retval->register_count = src->register_count;
retval->registers = (float *) m(siz, d);
memcpy(retval->registers, src->registers, siz);
return retval;
}
MOJOSHADER_effect *MOJOSHADER_cloneEffect(const MOJOSHADER_effect *effect)
{
int i, j, k;
MOJOSHADER_parseData *pd;
MOJOSHADER_effect *clone;
MOJOSHADER_malloc m = effect->ctx.m;
void *d = effect->ctx.malloc_data;
uint32 siz = 0;
char *stringcopy = NULL;
uint32 curSampler;
if ((effect == NULL) || (effect == &MOJOSHADER_out_of_mem_effect))
return NULL;
clone = (MOJOSHADER_effect *) m(sizeof (MOJOSHADER_effect), d);
if (clone == NULL)
return NULL; memset(clone, '\0', sizeof (MOJOSHADER_effect));
memcpy(&clone->ctx, &effect->ctx, sizeof(MOJOSHADER_effectShaderContext));
#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; \
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;
}
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);
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);
}
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)
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)
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);
}
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);
}
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 (i = 0; i < effect->technique_count; i++)
if (&effect->techniques[i] == effect->current_technique)
{
clone->current_technique = &clone->techniques[i];
break;
} assert(clone->current_technique != NULL);
clone->current_pass = effect->current_pass;
assert(clone->current_pass == -1);
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;
}
effect->ctx.shaderAddRef(effect->objects[i].shader.shader);
clone->objects[i].shader.shader = effect->objects[i].shader.shader;
pd = clone->ctx.getParseData(clone->objects[i].shader.shader);
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 < pd->symbol_count; j++)
if (pd->symbols[j].register_set == MOJOSHADER_SYMREGSET_SAMPLER)
{
clone->objects[i].shader.samplers[curSampler].sampler_name = clone->params[clone->objects[i].shader.params[j]].value.name;
clone->objects[i].shader.samplers[curSampler].sampler_register = pd->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++;
} } 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 (clone->objects[i].type == MOJOSHADER_SYMTYPE_STRING)
{
COPY_STRING(objects[i].string.string)
} }
#undef COPY_STRING
return clone;
cloneEffect_outOfMemory:
MOJOSHADER_deleteEffect(clone);
return NULL;
}
void MOJOSHADER_effectSetRawValueHandle(const MOJOSHADER_effectParam *parameter,
const void *data,
const unsigned int offset,
const unsigned int len)
{
memcpy((char *) parameter->value.values + offset, data, len);
}
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)
{
memcpy((char *) effect->params[i].value.values + offset, data, len);
return;
} } assert(0 && "Effect parameter not found!");
}
const MOJOSHADER_effectTechnique *MOJOSHADER_effectGetCurrentTechnique(const MOJOSHADER_effect *effect)
{
return effect->current_technique;
}
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;
} } assert(0 && "Technique is not part of this effect!");
}
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;
return &effect->techniques[i + 1];
} } assert(0 && "Technique is not part of this effect!");
return NULL;
}
void MOJOSHADER_effectBegin(MOJOSHADER_effect *effect,
unsigned int *numPasses,
int saveShaderState,
MOJOSHADER_effectStateChanges *stateChanges)
{
*numPasses = effect->current_technique->pass_count;
effect->restore_shader_state = saveShaderState;
effect->state_changes = stateChanges;
if (effect->restore_shader_state)
{
effect->ctx.getBoundShaders(&effect->prev_vertex_shader,
&effect->prev_pixel_shader);
} }
void MOJOSHADER_effectBeginPass(MOJOSHADER_effect *effect,
unsigned int pass)
{
int i;
MOJOSHADER_effectPass *curPass;
MOJOSHADER_effectState *state;
MOJOSHADER_effectShader *rawVert = effect->current_vert_raw;
MOJOSHADER_effectShader *rawPixl = effect->current_pixl_raw;
int has_preshader = 0;
effect->ctx.getBoundShaders(&effect->current_vert,
&effect->current_pixl);
assert(effect->current_pass == -1);
effect->current_pass = pass;
curPass = &effect->current_technique->passes[pass];
for (i = 0; i < curPass->state_count; i++)
{
state = &curPass->states[i];
if (state->type == MOJOSHADER_RS_VERTEXSHADER)
{
rawVert = &effect->objects[*state->value.valuesI].shader;
if (rawVert->is_preshader)
has_preshader = 1;
else
effect->current_vert = rawVert->shader;
} else if (state->type == MOJOSHADER_RS_PIXELSHADER)
{
rawPixl = &effect->objects[*state->value.valuesI].shader;
if (rawPixl->is_preshader)
has_preshader = 1;
else
effect->current_pixl = rawPixl->shader;
}
}
effect->state_changes->render_state_changes = curPass->states;
effect->state_changes->render_state_change_count = curPass->state_count;
effect->current_vert_raw = rawVert;
effect->current_pixl_raw = rawPixl;
if (!has_preshader)
{
effect->ctx.bindShaders(effect->current_vert,
effect->current_pixl);
if (effect->current_vert_raw != NULL)
{
effect->state_changes->vertex_sampler_state_changes = rawVert->samplers;
effect->state_changes->vertex_sampler_state_change_count = rawVert->sampler_count;
} if (effect->current_pixl_raw != NULL)
{
effect->state_changes->sampler_state_changes = rawPixl->samplers;
effect->state_changes->sampler_state_change_count = rawPixl->sampler_count;
} }
MOJOSHADER_effectCommitChanges(effect);
}
static inline void copy_parameter_data(MOJOSHADER_effectParam *params,
unsigned int *param_loc,
MOJOSHADER_symbol *symbols,
unsigned int symbol_count,
float *regf, int *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;
const uint32 start = sym->register_index << 2;
if (param->type.parameter_type == MOJOSHADER_SYMTYPE_FLOAT)
memcpy(regf + start, param->valuesF, sym->register_count << 4);
else if (sym->register_set == MOJOSHADER_SYMREGSET_FLOAT4)
{
if (param->type.parameter_class == MOJOSHADER_SYMCLASS_STRUCT)
memcpy(regf + start, param->valuesF, sym->register_count << 4);
else
{
j = 0;
do
{
c = 0;
do
{
regf[start + (j << 2) + c] = (float) param->valuesI[(j << 2) + c];
} while (++c < param->type.columns);
} while (++j < sym->register_count);
} } else if (sym->register_set == MOJOSHADER_SYMREGSET_INT4)
memcpy(regi + start, param->valuesI, sym->register_count << 4);
else if (sym->register_set == MOJOSHADER_SYMREGSET_BOOL)
{
j = 0;
r = 0;
do
{
c = 0;
do
{
regb[(start >> 2) + r + c] = param->valuesI[(j << 2) + c];
c++;
} while (c < param->type.columns && ((r + c) < sym->register_count));
r += c;
j++;
} while (r < sym->register_count);
} } }
void MOJOSHADER_effectCommitChanges(MOJOSHADER_effect *effect)
{
MOJOSHADER_effectShader *rawVert = effect->current_vert_raw;
MOJOSHADER_effectShader *rawPixl = effect->current_pixl_raw;
int i, j;
MOJOSHADER_effectValue *param;
MOJOSHADER_parseData *pd;
float selector;
int shader_object;
int selector_ran = 0;
float *vs_reg_file_f, *ps_reg_file_f;
int *vs_reg_file_i, *ps_reg_file_i;
uint8 *vs_reg_file_b, *ps_reg_file_b;
#define SELECT_SHADER_FROM_PRESHADER(raw, gls) \
if (raw != NULL && raw->is_preshader) \
{ \
i = 0; \
do \
{ \
param = &effect->params[raw->preshader_params[i]].value; \
for (j = 0; j < (param->value_count >> 2); j++) \
memcpy(raw->preshader->registers + raw->preshader->symbols[i].register_index + j, \
param->valuesI + (j << 2), \
param->type.columns << 2); \
} while (++i < raw->preshader->symbol_count); \
MOJOSHADER_runPreshader(raw->preshader, &selector); \
shader_object = effect->params[raw->params[0]].value.valuesI[(int) selector]; \
raw = &effect->objects[shader_object].shader; \
gls = raw->shader; \
selector_ran = 1; \
}
SELECT_SHADER_FROM_PRESHADER(rawVert, effect->current_vert)
SELECT_SHADER_FROM_PRESHADER(rawPixl, effect->current_pixl)
#undef SELECT_SHADER_FROM_PRESHADER
if (selector_ran)
{
effect->ctx.bindShaders(effect->current_vert,
effect->current_pixl);
if (effect->current_vert_raw != NULL)
{
effect->state_changes->vertex_sampler_state_changes = rawVert->samplers;
effect->state_changes->vertex_sampler_state_change_count = rawVert->sampler_count;
} if (effect->current_pixl_raw != NULL)
{
effect->state_changes->sampler_state_changes = rawPixl->samplers;
effect->state_changes->sampler_state_change_count = rawPixl->sampler_count;
} }
#define COPY_PARAMETER_DATA(raw, stage) \
if (raw != NULL) \
{ \
pd = effect->ctx.getParseData(raw->shader); \
copy_parameter_data(effect->params, raw->params, \
pd->symbols, \
pd->symbol_count, \
stage##_reg_file_f, \
stage##_reg_file_i, \
stage##_reg_file_b); \
if (pd->preshader) \
{ \
copy_parameter_data(effect->params, raw->preshader_params, \
pd->preshader->symbols, \
pd->preshader->symbol_count, \
pd->preshader->registers, \
NULL, \
NULL); \
MOJOSHADER_runPreshader(pd->preshader, stage##_reg_file_f); \
} \
}
effect->ctx.mapUniformBufferMemory(&vs_reg_file_f, &vs_reg_file_i, &vs_reg_file_b,
&ps_reg_file_f, &ps_reg_file_i, &ps_reg_file_b);
COPY_PARAMETER_DATA(rawVert, vs)
COPY_PARAMETER_DATA(rawPixl, ps)
effect->ctx.unmapUniformBufferMemory();
#undef COPY_PARAMETER_DATA
}
void MOJOSHADER_effectEndPass(MOJOSHADER_effect *effect)
{
assert(effect->current_pass != -1);
effect->current_pass = -1;
}
void MOJOSHADER_effectEnd(MOJOSHADER_effect *effect)
{
if (effect->restore_shader_state)
{
effect->restore_shader_state = 0;
effect->ctx.bindShaders(effect->prev_vertex_shader,
effect->prev_pixel_shader);
}
effect->state_changes = NULL;
}
#endif