/** * 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 __INCL_MOJOSHADER_H_ #define __INCL_MOJOSHADER_H_ #ifdef __cplusplus extern "C" { #endif /* * For determining the version of MojoShader you are using: * const int compiled_against = MOJOSHADER_VERSION; * const int linked_against = MOJOSHADER_version(); * * The version is a single integer that increments, not a major/minor value. */ #define MOJOSHADER_VERSION 1 int MOJOSHADER_version(void); /* * These allocators work just like the C runtime's malloc() and free() * (in fact, they probably use malloc() and free() internally if you don't * specify your own allocator, but don't rely on that behaviour). * (data) is the pointer you supplied when specifying these allocator * 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); /* * These are enum values, but they also can be used in bitmasks, so we can * test if an opcode is acceptable: if (op->shader_types & ourtype) {} ... */ typedef enum { MOJOSHADER_TYPE_UNKNOWN = 0, MOJOSHADER_TYPE_PIXEL = (1 << 0), MOJOSHADER_TYPE_VERTEX = (1 << 1), MOJOSHADER_TYPE_GEOMETRY = (1 << 2), /* (not supported yet.) */ MOJOSHADER_TYPE_ANY = 0xFFFFFFFF /* used for bitmasks */ } MOJOSHADER_shaderType; /* * Data types for vertex attribute streams. */ typedef enum { MOJOSHADER_ATTRIBUTE_BYTE, MOJOSHADER_ATTRIBUTE_UBYTE, MOJOSHADER_ATTRIBUTE_SHORT, MOJOSHADER_ATTRIBUTE_USHORT, MOJOSHADER_ATTRIBUTE_INT, MOJOSHADER_ATTRIBUTE_UINT, MOJOSHADER_ATTRIBUTE_FLOAT, MOJOSHADER_ATTRIBUTE_DOUBLE } MOJOSHADER_attributeType; /* * Data types for uniforms. See MOJOSHADER_uniform for more information. */ typedef enum { MOJOSHADER_UNIFORM_FLOAT, MOJOSHADER_UNIFORM_INT, MOJOSHADER_UNIFORM_BOOL, } MOJOSHADER_uniformType; /* * These are the uniforms to be set for a shader. "Uniforms" are what Direct3D * calls "Constants" ... IDirect3DDevice::SetVertexShaderConstantF() would * need this data, for example. These integers are register indexes. So if * index==6 and type==MOJOSHADER_UNIFORM_FLOAT, that means we'd expect a * 4-float vector to be specified for what would be register "c6" in D3D * assembly language, before drawing with the shader. * (name) is a profile-specific variable name; it may be NULL if it isn't * applicable to the requested profile. */ typedef struct { MOJOSHADER_uniformType type; int index; const char *name; } MOJOSHADER_uniform; /* * Data types for samplers. See MOJOSHADER_sampler for more information. */ typedef enum { MOJOSHADER_SAMPLER_2D, MOJOSHADER_SAMPLER_CUBE, MOJOSHADER_SAMPLER_VOLUME, } MOJOSHADER_samplerType; /* * These are the samplers to be set for a shader. ... * IDirect3DDevice::SetTexture() would need this data, for example. * These integers are the sampler "stage". So if index==6 and * type==MOJOSHADER_SAMPLER_2D, that means we'd expect a regular 2D texture * to be specified for what would be register "s6" in D3D assembly language, * before drawing with the shader. * (name) is a profile-specific variable name; it may be NULL if it isn't * applicable to the requested profile. */ typedef struct { MOJOSHADER_samplerType type; int index; const char *name; } MOJOSHADER_sampler; /* * Data types for attributes. See MOJOSHADER_attribute for more information. */ typedef enum { MOJOSHADER_USAGE_POSITION, MOJOSHADER_USAGE_BLENDWEIGHT, MOJOSHADER_USAGE_BLENDINDICES, MOJOSHADER_USAGE_NORMAL, MOJOSHADER_USAGE_POINTSIZE, MOJOSHADER_USAGE_TEXCOORD, MOJOSHADER_USAGE_TANGENT, MOJOSHADER_USAGE_BINORMAL, MOJOSHADER_USAGE_TESSFACTOR, MOJOSHADER_USAGE_POSITIONT, MOJOSHADER_USAGE_COLOR, MOJOSHADER_USAGE_FOG, MOJOSHADER_USAGE_DEPTH, MOJOSHADER_USAGE_SAMPLE, MOJOSHADER_USAGE_TOTAL, /* housekeeping value; not ever returned. */ } MOJOSHADER_usage; /* * These are the attributes to be set for a shader. "Attributes" are what * Direct3D calls "Vertex Declarations Usages" ... * IDirect3DDevice::CreateVertexDeclaration() would need this data, for * example. Each attribute is associated with an array of data that uses one * element per-vertex. So if usage==MOJOSHADER_USAGE_COLOR and index==1, that * means we'd expect a secondary color array to be bound to this shader * before drawing. * (name) is a profile-specific variable name; it may be NULL if it isn't * applicable to the requested profile. */ typedef struct { MOJOSHADER_usage usage; int index; const char *name; } MOJOSHADER_attribute; /* * Structure used to return data from parsing of a shader... */ typedef struct { /* * Human-readable error, if there is one. Will be NULL if there was no * error. The string will be UTF-8 encoded, and English only. Most of * these shouldn't be shown to the end-user anyhow. */ const char *error; /* * The name of the profile used to parse the shader. Will be NULL on error. */ const char *profile; /* * Bytes of output from parsing. Most profiles produce a string of source * code, but profiles that do binary output may not be text at all. * Will be NULL on error. */ const char *output; /* * Byte count for output, not counting any null terminator. Most profiles * produce an ASCII string of source code (which will be null-terminated * even though that null char isn't included in output_len), but profiles * that do binary output may not be text at all. Will be 0 on error. */ int output_len; /* * Count of Direct3D instructions we parsed. This is meaningless in terms * of the actual output, as the profile will probably grow or reduce * the count (or for high-level languages, not have that information at * all), but it can give you a rough idea of the size of your shader. * Will be zero on error. */ int instruction_count; /* * The type of shader we parsed. Will be MOJOSHADER_TYPE_UNKNOWN on error. */ MOJOSHADER_shaderType shader_type; /* * The shader's major version. If this was a "vs_3_0", this would be 3. */ int major_ver; /* * The shader's minor version. If this was a "ps_1_4", this would be 4. * Two notes: for "vs_2_x", this is 1, and for "vs_3_sw", this is 255. */ int minor_ver; /* * The number of elements pointed to by (uniforms). */ int uniform_count; /* * (uniform_count) elements of data that specify Uniforms to be set for * this shader. See discussion on MOJOSHADER_uniform for details. * This can be NULL on error or if (uniform_count) is zero. */ MOJOSHADER_uniform *uniforms; /* * The number of elements pointed to by (samplers). */ int sampler_count; /* * (sampler_count) elements of data that specify Samplers to be set for * this shader. See discussion on MOJOSHADER_sampler for details. * This can be NULL on error or if (sampler_count) is zero. */ MOJOSHADER_sampler *samplers; /* * The number of elements pointed to by (attributes). */ int attribute_count; /* * (attribute_count) elements of data that specify Attributes to be set * for this shader. See discussion on MOJOSHADER_attribute for details. * This can be NULL on error or if (attribute_count) is zero. */ MOJOSHADER_attribute *attributes; /* * This is the malloc implementation you passed to MOJOSHADER_parse(). */ MOJOSHADER_malloc malloc; /* * This is the free implementation you passed to MOJOSHADER_parse(). */ MOJOSHADER_free free; /* * This is the pointer you passed as opaque data for your allocator. */ void *malloc_data; } MOJOSHADER_parseData; /* * Profile string for Direct3D assembly language output. */ #define MOJOSHADER_PROFILE_D3D "d3d" /* * Profile string for passthrough of the original bytecode, unchanged. */ #define MOJOSHADER_PROFILE_PASSTHROUGH "passthrough" /* * Profile string for GLSL: OpenGL high-level shader language output. */ #define MOJOSHADER_PROFILE_GLSL "glsl" /* * Parse a compiled Direct3D shader's bytecode. * * This is your primary entry point into MojoShader. You need to pass it * a compiled D3D shader and tell it which "profile" you want to use to * convert it into useful data. * * The available profiles are the set of MOJOSHADER_PROFILE_* defines. * Note that MojoShader may be built without support for all listed * profiles (in which case using one here will return with an error). * * As parsing requires some memory to be allocated, you may provide a custom * allocator to this function, which will be used to allocate/free memory. * They function just like malloc() and free(). We do not use realloc(). * If you don't care, pass NULL in for the allocator functions. If your * allocator needs instance-specific data, you may supply it with the * (d) parameter. This pointer is passed as-is to your (m) and (f) functions. * * This function returns a MOJOSHADER_parseData. * * This function will never return NULL, even if the system is completely * out of memory upon entry (in which case, this function returns a static * MOJOSHADER_parseData object, which is still safe to pass to * MOJOSHADER_freeParseData()). * * This function is thread safe, so long as (m) and (f) are too, and that * (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, MOJOSHADER_malloc m, MOJOSHADER_free f, void *d); /* * Call this to dispose of parsing results when you are done with them. * This will call the MOJOSHADER_free function you provided to * MOJOSHADER_parse multiple times, if you provided one. * Passing a NULL here is a safe no-op. * * This function is thread safe, so long as any allocator you passed into * MOJOSHADER_parse() is, too. */ void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *data); /* OpenGL interface... */ /* * Prepare MojoShader to manage OpenGL shaders. * * You do not need to call this if all you want is MOJOSHADER_parse(). * * You must call this once AFTER you have successfully built your GL context * and made it current. This function will lookup the GL functions it needs * through the callback you supply, after which it may call them at any time * up until you call MOJOSHADER_glDeinit(). The lookup function is neither * stored nor used by MojoShader after this function returns. * * (profile) is an OpenGL-specific MojoShader profile, which decides how * Direct3D bytecode shaders get turned into OpenGL programs, and how they * are fed to the GL. * * (lookup) is a callback that is used to load GL entry points. This callback * has to look up base GL functions and extension entry points. * * As MojoShader requires some memory to be allocated, you may provide a * custom allocator to this function, which will be used to allocate/free * memory. They function just like malloc() and free(). We do not use * realloc(). If you don't care, pass NULL in for the allocator functions. * If your allocator needs instance-specific data, you may supply it with the * (d) parameter. This pointer is passed as-is to your (m) and (f) functions. * * Returns zero on error, non-zero on success. * * This call is NOT thread safe! It must return success before you may call * any other MOJOSHADER_gl* function. Also, as most OpenGL implementations * are not thread safe, you should probably only call this from the same * thread that created the GL context. */ int MOJOSHADER_glInit(const char *profile, void *(*lookup)(const char *fnname), MOJOSHADER_malloc m, MOJOSHADER_free f, void *d); /* * Get any error state we might have picked up. MojoShader will NOT call * glGetError() internally, but there are other errors we can pick up, * such as failed shader compilation, etc. * * Returns a human-readable string. This string is for debugging purposes, and * not guaranteed to be localized, coherent, or user-friendly in any way. * It's for programmers! * * The latest error may remain between calls. New errors replace any existing * error. Don't check this string for a sign that an error happened, check * return codes instead and use this for explanation when debugging. * * Do not free the returned string: it's a pointer to a static internal * buffer. Do not keep the pointer around, either, as it's likely to become * invalid as soon as you call into MojoShader again. * * This is safe to call even if MOJOSHADER_glInit() failed. * * 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. */ const char *MOJOSHADER_glGetError(void); /* * "Shaders" refer to individual vertex or pixel programs, and are created * by "compiling" Direct3D shader bytecode. A vertex and pixel shader are * "linked" into a "Program" before you can use them to render. * * To the calling application, these are opaque handles. */ typedef struct MOJOSHADER_glShader MOJOSHADER_glShader; typedef struct MOJOSHADER_glProgram MOJOSHADER_glProgram; /* * Compile a buffer of Direct3D shader bytecode into an OpenGL shader. * You still need to link the shader before you may render with it. * * (tokenbuf) is a buffer of Direct3D shader bytecode. * (bufsize) is the size, in bytes, of the bytecode buffer. * * Returns NULL on error, or a shader handle on success. * * 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. */ MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf, const unsigned int bufsize); /* * Link a vertex and pixel shader into an OpenGL program. * (vshader) or (pshader) can be NULL, to specify that the GL should use the * fixed-function pipeline instead of the programmable pipeline for that * portion of the work. You can reuse shaders in various combinations across * multiple programs, by relinking different pairs. * * It is illegal to give a vertex shader for (pshader) or a pixel shader * for (vshader). * * Once you have successfully linked a program, you may render with it. * * Returns NULL on error, or a program handle on success. * * 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. */ MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader, MOJOSHADER_glShader *pshader); /* * This binds the program (using, for example, glUseProgramObjectARB()), and * disables all the client-side arrays so we can reset them with new values * if appropriate. * * Call with NULL to disable the programmable pipeline and all enabled * client-side arrays. * * After binding a program, you should update any uniforms you care about * with MOJOSHADER_glSetVertexShaderUniformF() (etc), set any vertex arrays * you want to use with MOJOSHADER_glSetVertexAttribute(), and finally call * MOJOSHADER_glProgramReady() to commit everything to the GL. Then you may * begin drawing through standard GL entry points. * * 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. */ void MOJOSHADER_glBindProgram(MOJOSHADER_glProgram *program); /* * Set a floating-point uniform value (what Direct3D calls a "constant"). * * There is a single array of 4-float "registers" shared by all vertex shaders. * This is the "c" register file in Direct3D (c0, c1, c2, etc...) * MojoShader will take care of synchronizing this internal array with the * appropriate variables in the GL shaders. * * (idx) is the index into the internal array: 0 is the first four floats, * 1 is the next four, etc. * (data) is a pointer to (vec4count*4) floats. * * 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. */ void MOJOSHADER_glSetVertexShaderUniformF(unsigned int idx, const float *data, unsigned int vec4count); /* * Set an integer uniform value (what Direct3D calls a "constant"). * * There is a single array of 4-int "registers" shared by all vertex shaders. * This is the "i" register file in Direct3D (i0, i1, i2, etc...) * MojoShader will take care of synchronizing this internal array with the * appropriate variables in the GL shaders. * * (idx) is the index into the internal array: 0 is the first four ints, * 1 is the next four, etc. * (data) is a pointer to (ivec4count*4) ints. * * 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. */ void MOJOSHADER_glSetVertexShaderUniformI(unsigned int idx, const int *data, unsigned int ivec4count); /* * Set a boolean uniform value (what Direct3D calls a "constant"). * * There is a single array of "registers" shared by all vertex shaders. * This is the "b" register file in Direct3D (b0, b1, b2, etc...) * MojoShader will take care of synchronizing this internal array with the * appropriate variables in the GL shaders. * * Unlike the float and int counterparts, booleans are single values, not * four-element vectors...so idx==1 is the second boolean in the internal * array, not the fifth. * * Non-zero values are considered "true" and zero is considered "false". * * (idx) is the index into the internal array. * (data) is a pointer to (bcount) ints. * * 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. */ void MOJOSHADER_glSetVertexShaderUniformB(unsigned int idx, const int *data, unsigned int bcount); /* * The equivalent of MOJOSHADER_glSetVertexShaderUniformF() for pixel * shaders. Other than using a different internal array that is specific * to pixel shaders, this functions just like its vertex array equivalent. * * 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. */ void MOJOSHADER_glSetPixelShaderUniformF(unsigned int idx, const float *data, unsigned int vec4count); /* * The equivalent of MOJOSHADER_glSetVertexShaderUniformI() for pixel * shaders. Other than using a different internal array that is specific * to pixel shaders, this functions just like its vertex array equivalent. * * 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. */ void MOJOSHADER_glSetPixelShaderUniformI(unsigned int idx, const int *data, unsigned int ivec4count); /* * The equivalent of MOJOSHADER_glSetVertexShaderUniformB() for pixel * shaders. Other than using a different internal array that is specific * to pixel shaders, this functions just like its vertex array equivalent. * * 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. */ void MOJOSHADER_glSetPixelShaderUniformB(unsigned int idx, const int *data, unsigned int bcount); /* * Connect a client-side array to the currently-bound program. * * (usage) and (index) map to Direct3D vertex declaration values: COLOR1 would * be MOJOSHADER_USAGE_COLOR and 1. * * The caller should bind VBOs before this call and treat (ptr) as an offset, * if appropriate. * * MojoShader will figure out where to plug this stream into the * currently-bound program, and enable the appropriate client-side array. * * (size), (type), (normalized), (stride), and (ptr) correspond to * glVertexAttribPointer()'s parameters (in most cases, these get passed * unmolested to that very entry point during this function). * * 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. */ void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage, int index, unsigned int size, MOJOSHADER_attributeType type, int normalized, unsigned int stride, const void *ptr); /* * Inform MojoShader that it should commit any pending state to the GL. This * must be called after you bind a program and update any inputs, right * before you start drawing, so any outstanding changes made to the shared * constants array (etc) can propagate to the shader during this call. * * 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. */ void MOJOSHADER_glProgramReady(void); /* * Free the resources of a linked program. This will delete the GL object * and free memory. * * If the program is currently bound by MOJOSHADER_glBindProgram(), it will * be deleted as soon as it becomes unbound. * * 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. */ void MOJOSHADER_glDeleteProgram(MOJOSHADER_glProgram *program); /* * Free the resources of a compiled shader. This will delete the GL object * and free memory. * * If the shader is currently referenced by a linked program, it will * be deleted as soon as all referencing programs are deleted, too. * * 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. */ void MOJOSHADER_glDeleteShader(MOJOSHADER_glShader *shader); /* * Deinitialize MojoShader's OpenGL shader management. * * You must call this once, while your GL context is still current, if you * previously had a successful call to MOJOSHADER_glInit(). This should * be the last MOJOSHADER_gl* function you call until you've initialized * again. * * This will clean up resources previously allocated, and may call into the GL. * * This will not clean up shaders and programs you created! Please call * MOJOSHADER_glDeleteShader() and MOJOSHADER_glDeleteProgram() to clean * those up before calling this function! * * This call is NOT thread safe! There must not be any other MOJOSHADER_gl* * functions running when this is called. Also, as most OpenGL implementations * are not thread safe, you should probably only call this from the same * thread that created the GL context. */ void MOJOSHADER_glDeinit(void); #ifdef __cplusplus } #endif #endif /* include-once blocker. */ /* end of mojoshader.h ... */