// !!! 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) { if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) ) return &MOJOSHADER_out_of_mem_effect; // supply both or neither. if (m == NULL) m = MOJOSHADER_internal_malloc; if (f == NULL) f = MOJOSHADER_internal_free; MOJOSHADER_effect *retval = (MOJOSHADER_effect*)m(sizeof (MOJOSHADER_effect), d); if (retval == NULL) return &MOJOSHADER_out_of_mem_effect; // supply both or neither. memset(retval, '\0', sizeof (*retval)); 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; const uint8 *base = NULL; if (readui32(&ptr, &len) != 0xFEFF0901) // !!! FIXME: is this always magic? 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; 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); // !!! 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; 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; // !!! 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; 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... 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 = (MOJOSHADER_effectTexture*)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 = (char*)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; // !!! 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. 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; /*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 retval->profile = (char *) m(strlen(profile) + 1, d); if (retval->profile == NULL) goto parseEffect_outOfMemory; strcpy((char *) retval->profile, profile); return retval; // !!! FIXME: do something with this. parseEffect_notAnEffectsFile: parseEffect_unexpectedEOF: parseEffect_outOfMemory: MOJOSHADER_freeEffect(retval); return &MOJOSHADER_out_of_mem_effect; } // MOJOSHADER_parseEffect
int main(int argc, char **argv) { SDL_Window *window; SDL_GLContext context; SDL_Event evt; MOJOSHADER_glContext *shaderContext; MOJOSHADER_effect *effect; MOJOSHADER_glEffect *glEffect; SDL_Surface *bitmap; GLuint texture; GLuint buffers[2]; FILE *fileIn; unsigned int fileLen; unsigned char *effectData; unsigned int passes; MOJOSHADER_effectStateChanges changes; Uint8 run = 1; /* Create the window and GL context */ SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); window = SDL_CreateWindow( "Sprite Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL ); context = SDL_GL_CreateContext(window); shaderContext = MOJOSHADER_glCreateContext( MOJOSHADER_PROFILE, GetGLProcAddress, NULL, NULL, NULL, NULL ); MOJOSHADER_glMakeContextCurrent(shaderContext); /* ARB_debug_output setup */ glDebugMessageCallbackARB(GLDebugCallback, NULL); glDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE ); /* Set up the viewport, create the texture/buffer data */ glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f); bitmap = SDL_LoadBMP("../Sprite.bmp"); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, bitmap->w, bitmap->h, 0, GL_BGR, GL_UNSIGNED_BYTE, bitmap->pixels ); SDL_FreeSurface(bitmap); glGenBuffersARB(2, buffers); glBindBufferARB(GL_ARRAY_BUFFER, buffers[0]); glBufferDataARB( GL_ARRAY_BUFFER, sizeof(vertexstruct_t) * 4, vertex_array, GL_STATIC_DRAW ); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER, 12, index_array, GL_STATIC_DRAW ); /* Load and read the SpriteBatch effect file */ fileIn = fopen("../SpriteEffect.fxb", "rb"); fseek(fileIn, 0, SEEK_END); fileLen = ftell(fileIn); fseek(fileIn, 0, SEEK_SET); effectData = (unsigned char*) malloc(fileLen); fread(effectData, 1, fileLen, fileIn); fclose(fileIn); effect = MOJOSHADER_parseEffect( MOJOSHADER_PROFILE, effectData, fileLen, NULL, 0, NULL, 0, NULL, NULL, NULL ); free(effectData); glEffect = MOJOSHADER_glCompileEffect(effect); MOJOSHADER_effectSetRawValueName( effect, "MatrixTransform", transform_matrix, 0, 64 ); while (run) { while (SDL_PollEvent(&evt) > 0) { if (evt.type == SDL_QUIT) { run = 0; } } /* Clear the screen to black. */ glClear(GL_COLOR_BUFFER_BIT); /* Bind the effect */ MOJOSHADER_glEffectBegin(glEffect, &passes, 0, &changes); MOJOSHADER_glEffectBeginPass(glEffect, 0); /* Set the attrib pointers now, while the effect is bound */ MOJOSHADER_glSetVertexAttribute( MOJOSHADER_USAGE_POSITION, 0, 3, MOJOSHADER_ATTRIBUTE_FLOAT, 0, sizeof(vertexstruct_t), (void*) 0 ); MOJOSHADER_glSetVertexAttribute( MOJOSHADER_USAGE_COLOR, 0, 4, MOJOSHADER_ATTRIBUTE_UBYTE, 1, sizeof(vertexstruct_t), (void*) 12 ); MOJOSHADER_glSetVertexAttribute( MOJOSHADER_USAGE_TEXCOORD, 0, 2, MOJOSHADER_ATTRIBUTE_FLOAT, 0, sizeof(vertexstruct_t), (void*) 16 ); /* Flush all changes to the shader and constant buffers */ MOJOSHADER_glProgramReady(); /* Draw! */ glDrawRangeElements( GL_TRIANGLES, 0, 3, 6, GL_UNSIGNED_SHORT, NULL ); /* We've finished drawing. Present what we've drawn. */ MOJOSHADER_glEffectEndPass(glEffect); MOJOSHADER_glEffectEnd(glEffect); SDL_GL_SwapWindow(window); } /* Clean up. We out. */ glDeleteBuffersARB(2, buffers); glDeleteTextures(1, &texture); MOJOSHADER_glDeleteEffect(glEffect); MOJOSHADER_freeEffect(effect); MOJOSHADER_glMakeContextCurrent(NULL); MOJOSHADER_glDestroyContext(shaderContext); SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); SDL_Quit(); return 0; }