/* * Mesa 3-D graphics library * Version: 6.5 * * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * \file slang_assemble_typeinfo.c * slang type info * \author Michal Krol */ #include "main/imports.h" #include "shader/prog_instruction.h" #include "slang_typeinfo.h" #include "slang_compile.h" #include "slang_log.h" #include "slang_mem.h" /** * Checks if a field selector is a general swizzle (an r-value swizzle * with replicated components or an l-value swizzle mask) for a * vector. Returns GL_TRUE if this is the case, is filled with * swizzle information. Returns GL_FALSE otherwise. */ GLboolean _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz) { GLuint i; GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE; /* init to undefined. * We rely on undefined/nil values to distinguish between * regular swizzles and writemasks. * For example, the swizzle ".xNNN" is the writemask ".x". * That's different than the swizzle ".xxxx". */ for (i = 0; i < 4; i++) swz->swizzle[i] = SWIZZLE_NIL; /* the swizzle can be at most 4-component long */ swz->num_components = slang_string_length(field); if (swz->num_components > 4) return GL_FALSE; for (i = 0; i < swz->num_components; i++) { /* mark which swizzle group is used */ switch (field[i]) { case 'x': case 'y': case 'z': case 'w': xyzw = GL_TRUE; break; case 'r': case 'g': case 'b': case 'a': rgba = GL_TRUE; break; case 's': case 't': case 'p': case 'q': stpq = GL_TRUE; break; default: return GL_FALSE; } /* collect swizzle component */ switch (field[i]) { case 'x': case 'r': case 's': swz->swizzle[i] = 0; break; case 'y': case 'g': case 't': swz->swizzle[i] = 1; break; case 'z': case 'b': case 'p': swz->swizzle[i] = 2; break; case 'w': case 'a': case 'q': swz->swizzle[i] = 3; break; } /* check if the component is valid for given vector's row count */ if (rows <= swz->swizzle[i]) return GL_FALSE; } /* only one swizzle group can be used */ if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq)) return GL_FALSE; return GL_TRUE; } /** * Checks if a general swizzle is an l-value swizzle - these swizzles * do not have duplicated fields. Returns GL_TRUE if this is a * swizzle mask. Returns GL_FALSE otherwise */ static GLboolean _slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows) { GLuint i, c = 0; /* the swizzle may not be longer than the vector dim */ if (swz->num_components > rows) return GL_FALSE; /* the swizzle components cannot be duplicated */ for (i = 0; i < swz->num_components; i++) { if ((c & (1 << swz->swizzle[i])) != 0) return GL_FALSE; c |= 1 << swz->swizzle[i]; } return GL_TRUE; } /** * Combines (multiplies) two swizzles to form single swizzle. * Example: "vec.wzyx.yx" --> "vec.zw". */ static void _slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left, const slang_swizzle * right) { GLuint i; dst->num_components = right->num_components; for (i = 0; i < right->num_components; i++) dst->swizzle[i] = left->swizzle[right->swizzle[i]]; } typedef struct { const char *name; slang_type_specifier_type type; } type_specifier_type_name; static const type_specifier_type_name type_specifier_type_names[] = { {"void", SLANG_SPEC_VOID}, {"bool", SLANG_SPEC_BOOL}, {"bvec2", SLANG_SPEC_BVEC2}, {"bvec3", SLANG_SPEC_BVEC3}, {"bvec4", SLANG_SPEC_BVEC4}, {"int", SLANG_SPEC_INT}, {"ivec2", SLANG_SPEC_IVEC2}, {"ivec3", SLANG_SPEC_IVEC3}, {"ivec4", SLANG_SPEC_IVEC4}, {"float", SLANG_SPEC_FLOAT}, {"vec2", SLANG_SPEC_VEC2}, {"vec3", SLANG_SPEC_VEC3}, {"vec4", SLANG_SPEC_VEC4}, {"mat2", SLANG_SPEC_MAT2}, {"mat3", SLANG_SPEC_MAT3}, {"mat4", SLANG_SPEC_MAT4}, {"mat2x3", SLANG_SPEC_MAT23}, {"mat3x2", SLANG_SPEC_MAT32}, {"mat2x4", SLANG_SPEC_MAT24}, {"mat4x2", SLANG_SPEC_MAT42}, {"mat3x4", SLANG_SPEC_MAT34}, {"mat4x3", SLANG_SPEC_MAT43}, {"sampler1D", SLANG_SPEC_SAMPLER1D}, {"sampler2D", SLANG_SPEC_SAMPLER2D}, {"sampler3D", SLANG_SPEC_SAMPLER3D}, {"samplerCube", SLANG_SPEC_SAMPLERCUBE}, {"sampler1DShadow", SLANG_SPEC_SAMPLER1DSHADOW}, {"sampler2DShadow", SLANG_SPEC_SAMPLER2DSHADOW}, {"sampler2DRect", SLANG_SPEC_SAMPLER2DRECT}, {"sampler2DRectShadow", SLANG_SPEC_SAMPLER2DRECTSHADOW}, {NULL, SLANG_SPEC_VOID} }; slang_type_specifier_type slang_type_specifier_type_from_string(const char *name) { const type_specifier_type_name *p = type_specifier_type_names; while (p->name != NULL) { if (slang_string_compare(p->name, name) == 0) break; p++; } return p->type; } const char * slang_type_specifier_type_to_string(slang_type_specifier_type type) { const type_specifier_type_name *p = type_specifier_type_names; while (p->name != NULL) { if (p->type == type) break; p++; } return p->name; } /* slang_fully_specified_type */ int slang_fully_specified_type_construct(slang_fully_specified_type * type) { type->qualifier = SLANG_QUAL_NONE; slang_type_specifier_ctr(&type->specifier); return 1; } void slang_fully_specified_type_destruct(slang_fully_specified_type * type) { slang_type_specifier_dtr(&type->specifier); } int slang_fully_specified_type_copy(slang_fully_specified_type * x, const slang_fully_specified_type * y) { slang_fully_specified_type z; if (!slang_fully_specified_type_construct(&z)) return 0; z.qualifier = y->qualifier; z.precision = y->precision; z.variant = y->variant; z.centroid = y->centroid; z.array_len = y->array_len; if (!slang_type_specifier_copy(&z.specifier, &y->specifier)) { slang_fully_specified_type_destruct(&z); return 0; } slang_fully_specified_type_destruct(x); *x = z; return 1; } GLvoid slang_type_specifier_ctr(slang_type_specifier * self) { self->type = SLANG_SPEC_VOID; self->_struct = NULL; self->_array = NULL; } GLvoid slang_type_specifier_dtr(slang_type_specifier * self) { if (self->_struct != NULL) { slang_struct_destruct(self->_struct); _slang_free(self->_struct); } if (self->_array != NULL) { slang_type_specifier_dtr(self->_array); _slang_free(self->_array); } } slang_type_specifier * slang_type_specifier_new(slang_type_specifier_type type, struct slang_struct_ *_struct, struct slang_type_specifier_ *_array) { slang_type_specifier *spec = (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier)); if (spec) { spec->type = type; spec->_struct = _struct; spec->_array = _array; } return spec; } GLboolean slang_type_specifier_copy(slang_type_specifier * x, const slang_type_specifier * y) { slang_type_specifier z; slang_type_specifier_ctr(&z); z.type = y->type; if (z.type == SLANG_SPEC_STRUCT) { z._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); if (z._struct == NULL) { slang_type_specifier_dtr(&z); return GL_FALSE; } if (!slang_struct_construct(z._struct)) { _slang_free(z._struct); slang_type_specifier_dtr(&z); return GL_FALSE; } if (!slang_struct_copy(z._struct, y->_struct)) { slang_type_specifier_dtr(&z); return GL_FALSE; } } else if (z.type == SLANG_SPEC_ARRAY) { z._array = (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier)); if (z._array == NULL) { slang_type_specifier_dtr(&z); return GL_FALSE; } slang_type_specifier_ctr(z._array); if (!slang_type_specifier_copy(z._array, y->_array)) { slang_type_specifier_dtr(&z); return GL_FALSE; } } slang_type_specifier_dtr(x); *x = z; return GL_TRUE; } /** * Test if two types are equal. */ GLboolean slang_type_specifier_equal(const slang_type_specifier * x, const slang_type_specifier * y) { if (x->type != y->type) return GL_FALSE; if (x->type == SLANG_SPEC_STRUCT) return slang_struct_equal(x->_struct, y->_struct); if (x->type == SLANG_SPEC_ARRAY) return slang_type_specifier_equal(x->_array, y->_array); return GL_TRUE; } /** * As above, but allow float/int casting. */ GLboolean slang_type_specifier_compatible(const slang_type_specifier * x, const slang_type_specifier * y) { /* special case: float == int */ if (x->type == SLANG_SPEC_INT && y->type == SLANG_SPEC_FLOAT) { return GL_TRUE; } /* XXX may need to add bool/int compatibility, etc */ if (x->type != y->type) return GL_FALSE; if (x->type == SLANG_SPEC_STRUCT) return slang_struct_equal(x->_struct, y->_struct); if (x->type == SLANG_SPEC_ARRAY) return slang_type_specifier_compatible(x->_array, y->_array); return GL_TRUE; } GLboolean slang_typeinfo_construct(slang_typeinfo * ti) { _mesa_bzero(ti, sizeof(*ti)); slang_type_specifier_ctr(&ti->spec); ti->array_len = 0; return GL_TRUE; } GLvoid slang_typeinfo_destruct(slang_typeinfo * ti) { slang_type_specifier_dtr(&ti->spec); } /** * Determine the return type of a function. * \param a_name the function name * \param param function parameters (overloading) * \param num_params number of parameters to function * \param space namespace to search * \param spec returns the type * \param funFound returns pointer to the function, or NULL if not found. * \return GL_TRUE for success, GL_FALSE if failure (bad function name) */ static GLboolean _slang_typeof_function(slang_atom a_name, slang_operation * params, GLuint num_params, const slang_name_space * space, slang_type_specifier * spec, slang_function **funFound, slang_atom_pool *atoms, slang_info_log *log) { GLboolean error; *funFound = _slang_function_locate(space->funcs, a_name, params, num_params, space, atoms, log, &error); if (error) return GL_FALSE; if (!*funFound) return GL_TRUE; /* yes, not false */ return slang_type_specifier_copy(spec, &(*funFound)->header.type.specifier); } /** * Determine the type of a math function. * \param name name of the operator, one of +,-,*,/ or unary - * \param params array of function parameters * \param num_params number of parameters * \param space namespace to use * \param spec returns the function's type * \param atoms atom pool * \return GL_TRUE for success, GL_FALSE if failure */ static GLboolean typeof_math_call(const char *name, slang_operation *call, const slang_name_space * space, slang_type_specifier * spec, slang_atom_pool * atoms, slang_info_log *log) { if (call->fun) { /* we've previously resolved this function call */ slang_type_specifier_copy(spec, &call->fun->header.type.specifier); return GL_TRUE; } else { slang_atom atom; slang_function *fun; /* number of params: */ assert(call->num_children == 1 || call->num_children == 2); atom = slang_atom_pool_atom(atoms, name); if (!_slang_typeof_function(atom, call->children, call->num_children, space, spec, &fun, atoms, log)) return GL_FALSE; if (fun) { /* Save pointer to save time in future */ call->fun = fun; return GL_TRUE; } return GL_FALSE; } } /** * Determine the return type of an operation. * \param op the operation node * \param space the namespace to use * \param ti the returned type * \param atoms atom pool * \return GL_TRUE for success, GL_FALSE if failure */ GLboolean _slang_typeof_operation(slang_operation * op, const slang_name_space * space, slang_typeinfo * ti, slang_atom_pool * atoms, slang_info_log *log) { ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; switch (op->type) { case SLANG_OPER_BLOCK_NO_NEW_SCOPE: case SLANG_OPER_BLOCK_NEW_SCOPE: case SLANG_OPER_ASM: case SLANG_OPER_BREAK: case SLANG_OPER_CONTINUE: case SLANG_OPER_DISCARD: case SLANG_OPER_RETURN: case SLANG_OPER_IF: case SLANG_OPER_WHILE: case SLANG_OPER_DO: case SLANG_OPER_FOR: case SLANG_OPER_VOID: ti->spec.type = SLANG_SPEC_VOID; break; case SLANG_OPER_EXPRESSION: case SLANG_OPER_ASSIGN: case SLANG_OPER_ADDASSIGN: case SLANG_OPER_SUBASSIGN: case SLANG_OPER_MULASSIGN: case SLANG_OPER_DIVASSIGN: case SLANG_OPER_PREINCREMENT: case SLANG_OPER_PREDECREMENT: if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) return GL_FALSE; break; case SLANG_OPER_LITERAL_BOOL: if (op->literal_size == 1) ti->spec.type = SLANG_SPEC_BOOL; else if (op->literal_size == 2) ti->spec.type = SLANG_SPEC_BVEC2; else if (op->literal_size == 3) ti->spec.type = SLANG_SPEC_BVEC3; else if (op->literal_size == 4) ti->spec.type = SLANG_SPEC_BVEC4; else { _mesa_problem(NULL, "Unexpected bool literal_size %d in _slang_typeof_operation()", op->literal_size); ti->spec.type = SLANG_SPEC_BOOL; } break; case SLANG_OPER_LOGICALOR: case SLANG_OPER_LOGICALXOR: case SLANG_OPER_LOGICALAND: case SLANG_OPER_EQUAL: case SLANG_OPER_NOTEQUAL: case SLANG_OPER_LESS: case SLANG_OPER_GREATER: case SLANG_OPER_LESSEQUAL: case SLANG_OPER_GREATEREQUAL: case SLANG_OPER_NOT: ti->spec.type = SLANG_SPEC_BOOL; break; case SLANG_OPER_LITERAL_INT: if (op->literal_size == 1) ti->spec.type = SLANG_SPEC_INT; else if (op->literal_size == 2) ti->spec.type = SLANG_SPEC_IVEC2; else if (op->literal_size == 3) ti->spec.type = SLANG_SPEC_IVEC3; else if (op->literal_size == 4) ti->spec.type = SLANG_SPEC_IVEC4; else { _mesa_problem(NULL, "Unexpected int literal_size %d in _slang_typeof_operation()", op->literal_size); ti->spec.type = SLANG_SPEC_INT; } break; case SLANG_OPER_LITERAL_FLOAT: if (op->literal_size == 1) ti->spec.type = SLANG_SPEC_FLOAT; else if (op->literal_size == 2) ti->spec.type = SLANG_SPEC_VEC2; else if (op->literal_size == 3) ti->spec.type = SLANG_SPEC_VEC3; else if (op->literal_size == 4) ti->spec.type = SLANG_SPEC_VEC4; else { _mesa_problem(NULL, "Unexpected float literal_size %d in _slang_typeof_operation()", op->literal_size); ti->spec.type = SLANG_SPEC_FLOAT; } break; case SLANG_OPER_IDENTIFIER: case SLANG_OPER_VARIABLE_DECL: { slang_variable *var; var = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); if (!var) { slang_info_log_error(log, "undefined variable '%s'", (char *) op->a_id); return GL_FALSE; } if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) { slang_info_log_memory(log); return GL_FALSE; } ti->can_be_referenced = GL_TRUE; if (var->type.specifier.type == SLANG_SPEC_ARRAY && var->type.array_len >= 1) { /* the datatype is an array, ex: float[3] x; */ ti->array_len = var->type.array_len; } else { /* the variable is an array, ex: float x[3]; */ ti->array_len = var->array_len; } } break; case SLANG_OPER_SEQUENCE: /* TODO: check [0] and [1] if they match */ if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { return GL_FALSE; } ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; /*case SLANG_OPER_MODASSIGN: */ /*case SLANG_OPER_LSHASSIGN: */ /*case SLANG_OPER_RSHASSIGN: */ /*case SLANG_OPER_ORASSIGN: */ /*case SLANG_OPER_XORASSIGN: */ /*case SLANG_OPER_ANDASSIGN: */ case SLANG_OPER_SELECT: /* TODO: check [1] and [2] if they match */ if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { return GL_FALSE; } ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; /*case SLANG_OPER_BITOR: */ /*case SLANG_OPER_BITXOR: */ /*case SLANG_OPER_BITAND: */ /*case SLANG_OPER_LSHIFT: */ /*case SLANG_OPER_RSHIFT: */ case SLANG_OPER_ADD: assert(op->num_children == 2); if (!typeof_math_call("+", op, space, &ti->spec, atoms, log)) return GL_FALSE; break; case SLANG_OPER_SUBTRACT: assert(op->num_children == 2); if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) return GL_FALSE; break; case SLANG_OPER_MULTIPLY: assert(op->num_children == 2); if (!typeof_math_call("*", op, space, &ti->spec, atoms, log)) return GL_FALSE; break; case SLANG_OPER_DIVIDE: assert(op->num_children == 2); if (!typeof_math_call("/", op, space, &ti->spec, atoms, log)) return GL_FALSE; break; /*case SLANG_OPER_MODULUS: */ case SLANG_OPER_PLUS: if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) return GL_FALSE; ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; case SLANG_OPER_MINUS: assert(op->num_children == 1); if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) return GL_FALSE; break; /*case SLANG_OPER_COMPLEMENT: */ case SLANG_OPER_SUBSCRIPT: { slang_typeinfo _ti; if (!slang_typeinfo_construct(&_ti)) return GL_FALSE; if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { slang_typeinfo_destruct(&_ti); return GL_FALSE; } ti->can_be_referenced = _ti.can_be_referenced; if (_ti.spec.type == SLANG_SPEC_ARRAY) { if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) { slang_typeinfo_destruct(&_ti); return GL_FALSE; } } else { if (!_slang_type_is_vector(_ti.spec.type) && !_slang_type_is_matrix(_ti.spec.type)) { slang_typeinfo_destruct(&_ti); slang_info_log_error(log, "cannot index a non-array type"); return GL_FALSE; } ti->spec.type = _slang_type_base(_ti.spec.type); } slang_typeinfo_destruct(&_ti); } break; case SLANG_OPER_CALL: if (op->array_constructor) { /* build array typeinfo */ ti->spec.type = SLANG_SPEC_ARRAY; ti->spec._array = (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier)); slang_type_specifier_ctr(ti->spec._array); ti->spec._array->type = slang_type_specifier_type_from_string((char *) op->a_id); ti->array_len = op->num_children; } else if (op->fun) { /* we've resolved this call before */ slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier); } else { slang_function *fun; if (!_slang_typeof_function(op->a_id, op->children, op->num_children, space, &ti->spec, &fun, atoms, log)) return GL_FALSE; if (fun) { /* save result for future use */ op->fun = fun; } else { slang_struct *s = slang_struct_scope_find(space->structs, op->a_id, GL_TRUE); if (s) { /* struct initializer */ ti->spec.type = SLANG_SPEC_STRUCT; ti->spec._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); if (ti->spec._struct == NULL) return GL_FALSE; if (!slang_struct_construct(ti->spec._struct)) { _slang_free(ti->spec._struct); ti->spec._struct = NULL; return GL_FALSE; } if (!slang_struct_copy(ti->spec._struct, s)) return GL_FALSE; } else { /* float, int, vec4, mat3, etc. constructor? */ const char *name; slang_type_specifier_type type; name = slang_atom_pool_id(atoms, op->a_id); type = slang_type_specifier_type_from_string(name); if (type == SLANG_SPEC_VOID) { slang_info_log_error(log, "undefined function '%s'", name); return GL_FALSE; } ti->spec.type = type; } } } break; case SLANG_OPER_METHOD: /* at this time, GLSL 1.20 only has one method: array.length() * which returns an integer. */ ti->spec.type = SLANG_SPEC_INT; break; case SLANG_OPER_FIELD: { slang_typeinfo _ti; if (!slang_typeinfo_construct(&_ti)) return GL_FALSE; if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { slang_typeinfo_destruct(&_ti); return GL_FALSE; } if (_ti.spec.type == SLANG_SPEC_STRUCT) { slang_variable *field; field = _slang_variable_locate(_ti.spec._struct->fields, op->a_id, GL_FALSE); if (field == NULL) { slang_typeinfo_destruct(&_ti); return GL_FALSE; } if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) { slang_typeinfo_destruct(&_ti); return GL_FALSE; } ti->can_be_referenced = _ti.can_be_referenced; } else { GLuint rows; const char *swizzle; slang_type_specifier_type base; /* determine the swizzle of the field expression */ if (!_slang_type_is_vector(_ti.spec.type)) { slang_typeinfo_destruct(&_ti); slang_info_log_error(log, "Can't swizzle scalar expression"); return GL_FALSE; } rows = _slang_type_dim(_ti.spec.type); swizzle = slang_atom_pool_id(atoms, op->a_id); if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) { slang_typeinfo_destruct(&_ti); slang_info_log_error(log, "bad swizzle '%s'", swizzle); return GL_FALSE; } ti->is_swizzled = GL_TRUE; ti->can_be_referenced = _ti.can_be_referenced && _slang_is_swizzle_mask(&ti->swz, rows); if (_ti.is_swizzled) { slang_swizzle swz; /* swizzle the swizzle */ _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz); ti->swz = swz; } base = _slang_type_base(_ti.spec.type); switch (ti->swz.num_components) { case 1: ti->spec.type = base; break; case 2: switch (base) { case SLANG_SPEC_FLOAT: ti->spec.type = SLANG_SPEC_VEC2; break; case SLANG_SPEC_INT: ti->spec.type = SLANG_SPEC_IVEC2; break; case SLANG_SPEC_BOOL: ti->spec.type = SLANG_SPEC_BVEC2; break; default: break; } break; case 3: switch (base) { case SLANG_SPEC_FLOAT: ti->spec.type = SLANG_SPEC_VEC3; break; case SLANG_SPEC_INT: ti->spec.type = SLANG_SPEC_IVEC3; break; case SLANG_SPEC_BOOL: ti->spec.type = SLANG_SPEC_BVEC3; break; default: break; } break; case 4: switch (base) { case SLANG_SPEC_FLOAT: ti->spec.type = SLANG_SPEC_VEC4; break; case SLANG_SPEC_INT: ti->spec.type = SLANG_SPEC_IVEC4; break; case SLANG_SPEC_BOOL: ti->spec.type = SLANG_SPEC_BVEC4; break; default: break; } break; default: break; } } slang_typeinfo_destruct(&_ti); } break; case SLANG_OPER_POSTINCREMENT: case SLANG_OPER_POSTDECREMENT: if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) return GL_FALSE; ti->can_be_referenced = GL_FALSE; ti->is_swizzled = GL_FALSE; break; default: return GL_FALSE; } return GL_TRUE; } /** * Determine if a type is a matrix. * \return GL_TRUE if is a matrix, GL_FALSE otherwise. */ GLboolean _slang_type_is_matrix(slang_type_specifier_type ty) { switch (ty) { case SLANG_SPEC_MAT2: case SLANG_SPEC_MAT3: case SLANG_SPEC_MAT4: case SLANG_SPEC_MAT23: case SLANG_SPEC_MAT32: case SLANG_SPEC_MAT24: case SLANG_SPEC_MAT42: case SLANG_SPEC_MAT34: case SLANG_SPEC_MAT43: return GL_TRUE; default: return GL_FALSE; } } /** * Determine if a type is a vector. * \return GL_TRUE if is a vector, GL_FALSE otherwise. */ GLboolean _slang_type_is_vector(slang_type_specifier_type ty) { switch (ty) { case SLANG_SPEC_VEC2: case SLANG_SPEC_VEC3: case SLANG_SPEC_VEC4: case SLANG_SPEC_IVEC2: case SLANG_SPEC_IVEC3: case SLANG_SPEC_IVEC4: case SLANG_SPEC_BVEC2: case SLANG_SPEC_BVEC3: case SLANG_SPEC_BVEC4: return GL_TRUE; default: return GL_FALSE; } } /** * Determine if a type is a float, float vector or float matrix. * \return GL_TRUE if so, GL_FALSE otherwise */ GLboolean _slang_type_is_float_vec_mat(slang_type_specifier_type ty) { switch (ty) { case SLANG_SPEC_FLOAT: case SLANG_SPEC_VEC2: case SLANG_SPEC_VEC3: case SLANG_SPEC_VEC4: case SLANG_SPEC_MAT2: case SLANG_SPEC_MAT3: case SLANG_SPEC_MAT4: case SLANG_SPEC_MAT23: case SLANG_SPEC_MAT32: case SLANG_SPEC_MAT24: case SLANG_SPEC_MAT42: case SLANG_SPEC_MAT34: case SLANG_SPEC_MAT43: return GL_TRUE; default: return GL_FALSE; } } /** * Given a vector type, return the type of the vector's elements. * For a matrix, return the type of the columns. */ slang_type_specifier_type _slang_type_base(slang_type_specifier_type ty) { switch (ty) { case SLANG_SPEC_FLOAT: case SLANG_SPEC_VEC2: case SLANG_SPEC_VEC3: case SLANG_SPEC_VEC4: return SLANG_SPEC_FLOAT; case SLANG_SPEC_INT: case SLANG_SPEC_IVEC2: case SLANG_SPEC_IVEC3: case SLANG_SPEC_IVEC4: return SLANG_SPEC_INT; case SLANG_SPEC_BOOL: case SLANG_SPEC_BVEC2: case SLANG_SPEC_BVEC3: case SLANG_SPEC_BVEC4: return SLANG_SPEC_BOOL; case SLANG_SPEC_MAT2: return SLANG_SPEC_VEC2; case SLANG_SPEC_MAT3: return SLANG_SPEC_VEC3; case SLANG_SPEC_MAT4: return SLANG_SPEC_VEC4; case SLANG_SPEC_MAT23: return SLANG_SPEC_VEC3; case SLANG_SPEC_MAT32: return SLANG_SPEC_VEC2; case SLANG_SPEC_MAT24: return SLANG_SPEC_VEC4; case SLANG_SPEC_MAT42: return SLANG_SPEC_VEC2; case SLANG_SPEC_MAT34: return SLANG_SPEC_VEC4; case SLANG_SPEC_MAT43: return SLANG_SPEC_VEC3; default: return SLANG_SPEC_VOID; } } /** * Return the dimensionality of a vector, or for a matrix, return number * of columns. */ GLuint _slang_type_dim(slang_type_specifier_type ty) { switch (ty) { case SLANG_SPEC_FLOAT: case SLANG_SPEC_INT: case SLANG_SPEC_BOOL: return 1; case SLANG_SPEC_VEC2: case SLANG_SPEC_IVEC2: case SLANG_SPEC_BVEC2: case SLANG_SPEC_MAT2: return 2; case SLANG_SPEC_VEC3: case SLANG_SPEC_IVEC3: case SLANG_SPEC_BVEC3: case SLANG_SPEC_MAT3: return 3; case SLANG_SPEC_VEC4: case SLANG_SPEC_IVEC4: case SLANG_SPEC_BVEC4: case SLANG_SPEC_MAT4: return 4; case SLANG_SPEC_MAT23: return 2; case SLANG_SPEC_MAT32: return 3; case SLANG_SPEC_MAT24: return 2; case SLANG_SPEC_MAT42: return 4; case SLANG_SPEC_MAT34: return 3; case SLANG_SPEC_MAT43: return 4; default: return 0; } } /** * Return the GL_* type that corresponds to a SLANG_SPEC_* type. */ GLenum _slang_gltype_from_specifier(const slang_type_specifier *type) { switch (type->type) { case SLANG_SPEC_BOOL: return GL_BOOL; case SLANG_SPEC_BVEC2: return GL_BOOL_VEC2; case SLANG_SPEC_BVEC3: return GL_BOOL_VEC3; case SLANG_SPEC_BVEC4: return GL_BOOL_VEC4; case SLANG_SPEC_INT: return GL_INT; case SLANG_SPEC_IVEC2: return GL_INT_VEC2; case SLANG_SPEC_IVEC3: return GL_INT_VEC3; case SLANG_SPEC_IVEC4: return GL_INT_VEC4; case SLANG_SPEC_FLOAT: return GL_FLOAT; case SLANG_SPEC_VEC2: return GL_FLOAT_VEC2; case SLANG_SPEC_VEC3: return GL_FLOAT_VEC3; case SLANG_SPEC_VEC4: return GL_FLOAT_VEC4; case SLANG_SPEC_MAT2: return GL_FLOAT_MAT2; case SLANG_SPEC_MAT3: return GL_FLOAT_MAT3; case SLANG_SPEC_MAT4: return GL_FLOAT_MAT4; case SLANG_SPEC_MAT23: return GL_FLOAT_MAT2x3; case SLANG_SPEC_MAT32: return GL_FLOAT_MAT3x2; case SLANG_SPEC_MAT24: return GL_FLOAT_MAT2x4; case SLANG_SPEC_MAT42: return GL_FLOAT_MAT4x2; case SLANG_SPEC_MAT34: return GL_FLOAT_MAT3x4; case SLANG_SPEC_MAT43: return GL_FLOAT_MAT4x3; case SLANG_SPEC_SAMPLER1D: return GL_SAMPLER_1D; case SLANG_SPEC_SAMPLER2D: return GL_SAMPLER_2D; case SLANG_SPEC_SAMPLER3D: return GL_SAMPLER_3D; case SLANG_SPEC_SAMPLERCUBE: return GL_SAMPLER_CUBE; case SLANG_SPEC_SAMPLER1DSHADOW: return GL_SAMPLER_1D_SHADOW; case SLANG_SPEC_SAMPLER2DSHADOW: return GL_SAMPLER_2D_SHADOW; case SLANG_SPEC_SAMPLER2DRECT: return GL_SAMPLER_2D_RECT_ARB; case SLANG_SPEC_SAMPLER2DRECTSHADOW: return GL_SAMPLER_2D_RECT_SHADOW_ARB; case SLANG_SPEC_ARRAY: return _slang_gltype_from_specifier(type->_array); case SLANG_SPEC_STRUCT: /* fall-through */ default: return GL_NONE; } }