0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 13:08:50 +02:00
obs-studio/libobs/graphics/shader-parser.c
jp9000 5780f3f177 (API Change) Improve graphics API consistency
Summary:
- Prefix all graphics subsystem names with gs_ or GS_
- Unsquish funciton names (for example _setfloat to _set_float)
- Changed create functions to be more consistent with the rest of the
  API elsewhere.  For exmaple, instead of
  gs_create_texture/gs_texture_destroy, it's now
  gs_texture_create/gs_texture_destroy
- Renamed gs_stencil_op enum to gs_stencil_op_type

From:                            To:
-----------------------------------------------------------
tvertarray                       gs_tvertarray
vb_data                          gs_vb_data
vbdata_create                    gs_vbdata_create
vbdata_destroy                   gs_vbdata_destroy
shader_param                     gs_shader_param
gs_effect                        gs_effect
effect_technique                 gs_effect_technique
effect_pass                      gs_effect_pass
effect_param                     gs_effect_param
texture_t                        gs_texture_t
stagesurf_t                      gs_stagesurf_t
zstencil_t                       gs_zstencil_t
vertbuffer_t                     gs_vertbuffer_t
indexbuffer_t                    gs_indexbuffer_t
samplerstate_t                   gs_samplerstate_t
swapchain_t                      gs_swapchain_t
texrender_t                      gs_texrender_t
shader_t                         gs_shader_t
sparam_t                         gs_sparam_t
effect_t                         gs_effect_t
technique_t                      gs_technique_t
eparam_t                         gs_eparam_t
device_t                         gs_device_t
graphics_t                       graphics_t
shader_param_type                gs_shader_param_type
SHADER_PARAM_UNKNOWN             GS_SHADER_PARAM_UNKNOWN
SHADER_PARAM_BOOL                GS_SHADER_PARAM_BOOL
SHADER_PARAM_FLOAT               GS_SHADER_PARAM_FLOAT
SHADER_PARAM_INT                 GS_SHADER_PARAM_INT
SHADER_PARAM_STRING              GS_SHADER_PARAM_STRING
SHADER_PARAM_VEC2                GS_SHADER_PARAM_VEC2
SHADER_PARAM_VEC3                GS_SHADER_PARAM_VEC3
SHADER_PARAM_VEC4                GS_SHADER_PARAM_VEC4
SHADER_PARAM_MATRIX4X4           GS_SHADER_PARAM_MATRIX4X4
SHADER_PARAM_TEXTURE             GS_SHADER_PARAM_TEXTURE
shader_param_info                gs_shader_param_info
shader_type                      gs_shader_type
SHADER_VERTEX                    GS_SHADER_VERTEX
SHADER_PIXEL                     GS_SHADER_PIXEL
shader_destroy                   gs_shader_destroy
shader_numparams                 gs_shader_get_num_params
shader_getparambyidx             gs_shader_get_param_by_idx
shader_getparambyname            gs_shader_get_param_by_name
shader_getviewprojmatrix         gs_shader_get_viewproj_matrix
shader_getworldmatrix            gs_shader_get_world_matrix
shader_getparaminfo              gs_shader_get_param_info
shader_setbool                   gs_shader_set_bool
shader_setfloat                  gs_shader_set_float
shader_setint                    gs_shader_set_int
shader_setmatrix3                gs_shader_setmatrix3
shader_setmatrix4                gs_shader_set_matrix4
shader_setvec2                   gs_shader_set_vec2
shader_setvec3                   gs_shader_set_vec3
shader_setvec4                   gs_shader_set_vec4
shader_settexture                gs_shader_set_texture
shader_setval                    gs_shader_set_val
shader_setdefault                gs_shader_set_default
effect_property_type             gs_effect_property_type
EFFECT_NONE                      GS_EFFECT_NONE
EFFECT_BOOL                      GS_EFFECT_BOOL
EFFECT_FLOAT                     GS_EFFECT_FLOAT
EFFECT_COLOR                     GS_EFFECT_COLOR
EFFECT_TEXTURE                   GS_EFFECT_TEXTURE
effect_param_info                gs_effect_param_info
effect_destroy                   gs_effect_destroy
effect_gettechnique              gs_effect_get_technique
technique_begin                  gs_technique_begin
technique_end                    gs_technique_end
technique_beginpass              gs_technique_begin_pass
technique_beginpassbyname        gs_technique_begin_pass_by_name
technique_endpass                gs_technique_end_pass
effect_numparams                 gs_effect_get_num_params
effect_getparambyidx             gs_effect_get_param_by_idx
effect_getparambyname            gs_effect_get_param_by_name
effect_updateparams              gs_effect_update_params
effect_getviewprojmatrix         gs_effect_get_viewproj_matrix
effect_getworldmatrix            gs_effect_get_world_matrix
effect_getparaminfo              gs_effect_get_param_info
effect_setbool                   gs_effect_set_bool
effect_setfloat                  gs_effect_set_float
effect_setint                    gs_effect_set_int
effect_setmatrix4                gs_effect_set_matrix4
effect_setvec2                   gs_effect_set_vec2
effect_setvec3                   gs_effect_set_vec3
effect_setvec4                   gs_effect_set_vec4
effect_settexture                gs_effect_set_texture
effect_setval                    gs_effect_set_val
effect_setdefault                gs_effect_set_default
texrender_create                 gs_texrender_create
texrender_destroy                gs_texrender_destroy
texrender_begin                  gs_texrender_begin
texrender_end                    gs_texrender_end
texrender_reset                  gs_texrender_reset
texrender_gettexture             gs_texrender_get_texture
GS_BUILDMIPMAPS                  GS_BUILD_MIPMAPS
GS_RENDERTARGET                  GS_RENDER_TARGET
gs_device_name                   gs_get_device_name
gs_device_type                   gs_get_device_type
gs_entercontext                  gs_enter_context
gs_leavecontext                  gs_leave_context
gs_getcontext                    gs_get_context
gs_renderstart                   gs_render_start
gs_renderstop                    gs_render_stop
gs_rendersave                    gs_render_save
gs_getinput                      gs_get_input
gs_geteffect                     gs_get_effect
gs_create_effect_from_file       gs_effect_create_from_file
gs_create_effect                 gs_effect_create
gs_create_vertexshader_from_file gs_vertexshader_create_from_file
gs_create_pixelshader_from_file  gs_pixelshader_create_from_file
gs_create_texture_from_file      gs_texture_create_from_file
gs_resetviewport                 gs_reset_viewport
gs_set2dmode                     gs_set_2d_mode
gs_set3dmode                     gs_set_3d_mode
gs_create_swapchain              gs_swapchain_create
gs_getsize                       gs_get_size
gs_getwidth                      gs_get_width
gs_getheight                     gs_get_height
gs_create_texture                gs_texture_create
gs_create_cubetexture            gs_cubetexture_create
gs_create_volumetexture          gs_voltexture_create
gs_create_zstencil               gs_zstencil_create
gs_create_stagesurface           gs_stagesurface_create
gs_create_samplerstate           gs_samplerstate_create
gs_create_vertexshader           gs_vertexshader_create
gs_create_pixelshader            gs_pixelshader_create
gs_create_vertexbuffer           gs_vertexbuffer_create
gs_create_indexbuffer            gs_indexbuffer_create
gs_gettexturetype                gs_get_texture_type
gs_load_defaultsamplerstate      gs_load_default_samplerstate
gs_getvertexshader               gs_get_vertex_shader
gs_getpixelshader                gs_get_pixel_shader
gs_getrendertarget               gs_get_render_target
gs_getzstenciltarget             gs_get_zstencil_target
gs_setrendertarget               gs_set_render_target
gs_setcuberendertarget           gs_set_cube_render_target
gs_beginscene                    gs_begin_scene
gs_draw                          gs_draw
gs_endscene                      gs_end_scene
gs_setcullmode                   gs_set_cull_mode
gs_getcullmode                   gs_get_cull_mode
gs_enable_depthtest              gs_enable_depth_test
gs_enable_stenciltest            gs_enable_stencil_test
gs_enable_stencilwrite           gs_enable_stencil_write
gs_blendfunction                 gs_blend_function
gs_depthfunction                 gs_depth_function
gs_stencilfunction               gs_stencil_function
gs_stencilop                     gs_stencil_op
gs_setviewport                   gs_set_viewport
gs_getviewport                   gs_get_viewport
gs_setscissorrect                gs_set_scissor_rect
gs_create_texture_from_iosurface gs_texture_create_from_iosurface
gs_create_gdi_texture            gs_texture_create_gdi
gs_is_compressed_format          gs_is_compressed_format
gs_num_total_levels              gs_get_total_levels
texture_setimage                 gs_texture_set_image
cubetexture_setimage             gs_cubetexture_set_image
swapchain_destroy                gs_swapchain_destroy
texture_destroy                  gs_texture_destroy
texture_getwidth                 gs_texture_get_width
texture_getheight                gs_texture_get_height
texture_getcolorformat           gs_texture_get_color_format
texture_map                      gs_texture_map
texture_unmap                    gs_texture_unmap
texture_isrect                   gs_texture_is_rect
texture_getobj                   gs_texture_get_obj
cubetexture_destroy              gs_cubetexture_destroy
cubetexture_getsize              gs_cubetexture_get_size
cubetexture_getcolorformat       gs_cubetexture_get_color_format
volumetexture_destroy            gs_voltexture_destroy
volumetexture_getwidth           gs_voltexture_get_width
volumetexture_getheight          gs_voltexture_get_height
volumetexture_getdepth           gs_voltexture_getdepth
volumetexture_getcolorformat     gs_voltexture_get_color_format
stagesurface_destroy             gs_stagesurface_destroy
stagesurface_getwidth            gs_stagesurface_get_width
stagesurface_getheight           gs_stagesurface_get_height
stagesurface_getcolorformat      gs_stagesurface_get_color_format
stagesurface_map                 gs_stagesurface_map
stagesurface_unmap               gs_stagesurface_unmap
zstencil_destroy                 gs_zstencil_destroy
samplerstate_destroy             gs_samplerstate_destroy
vertexbuffer_destroy             gs_vertexbuffer_destroy
vertexbuffer_flush               gs_vertexbuffer_flush
vertexbuffer_getdata             gs_vertexbuffer_get_data
indexbuffer_destroy              gs_indexbuffer_destroy
indexbuffer_flush                gs_indexbuffer_flush
indexbuffer_getdata              gs_indexbuffer_get_data
indexbuffer_numindices           gs_indexbuffer_get_num_indices
indexbuffer_gettype              gs_indexbuffer_get_type
texture_rebind_iosurface         gs_texture_rebind_iosurface
texture_get_dc                   gs_texture_get_dc
texture_release_dc               gs_texture_release_dc
2014-08-09 11:57:38 -07:00

682 lines
17 KiB
C

/******************************************************************************
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "shader-parser.h"
enum gs_shader_param_type get_shader_param_type(const char *type)
{
if (strcmp(type, "float") == 0)
return GS_SHADER_PARAM_FLOAT;
else if (strcmp(type, "float2") == 0)
return GS_SHADER_PARAM_VEC2;
else if (strcmp(type, "float3") == 0)
return GS_SHADER_PARAM_VEC3;
else if (strcmp(type, "float4") == 0)
return GS_SHADER_PARAM_VEC4;
else if (astrcmp_n(type, "texture", 7) == 0)
return GS_SHADER_PARAM_TEXTURE;
else if (strcmp(type, "float4x4") == 0)
return GS_SHADER_PARAM_MATRIX4X4;
else if (strcmp(type, "bool") == 0)
return GS_SHADER_PARAM_BOOL;
else if (strcmp(type, "int") == 0)
return GS_SHADER_PARAM_INT;
else if (strcmp(type, "string") == 0)
return GS_SHADER_PARAM_STRING;
return GS_SHADER_PARAM_UNKNOWN;
}
enum gs_sample_filter get_sample_filter(const char *filter)
{
if (astrcmpi(filter, "Anisotropy") == 0)
return GS_FILTER_ANISOTROPIC;
else if (astrcmpi(filter, "Point") == 0 ||
strcmp(filter, "MIN_MAG_MIP_POINT") == 0)
return GS_FILTER_POINT;
else if (astrcmpi(filter, "Linear") == 0 ||
strcmp(filter, "MIN_MAG_MIP_LINEAR") == 0)
return GS_FILTER_LINEAR;
else if (strcmp(filter, "MIN_MAG_POINT_MIP_LINEAR") == 0)
return GS_FILTER_MIN_MAG_POINT_MIP_LINEAR;
else if (strcmp(filter, "MIN_POINT_MAG_LINEAR_MIP_POINT") == 0)
return GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
else if (strcmp(filter, "MIN_POINT_MAG_MIP_LINEAR") == 0)
return GS_FILTER_MIN_POINT_MAG_MIP_LINEAR;
else if (strcmp(filter, "MIN_LINEAR_MAG_MIP_POINT") == 0)
return GS_FILTER_MIN_LINEAR_MAG_MIP_POINT;
else if (strcmp(filter, "MIN_LINEAR_MAG_POINT_MIP_LINEAR") == 0)
return GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
else if (strcmp(filter, "MIN_MAG_LINEAR_MIP_POINT") == 0)
return GS_FILTER_MIN_MAG_LINEAR_MIP_POINT;
return GS_FILTER_LINEAR;
}
extern enum gs_address_mode get_address_mode(const char *mode)
{
if (astrcmpi(mode, "Wrap") == 0 || astrcmpi(mode, "Repeat") == 0)
return GS_ADDRESS_WRAP;
else if (astrcmpi(mode, "Clamp") == 0 || astrcmpi(mode, "None") == 0)
return GS_ADDRESS_CLAMP;
else if (astrcmpi(mode, "Mirror") == 0)
return GS_ADDRESS_MIRROR;
else if (astrcmpi(mode, "Border") == 0)
return GS_ADDRESS_BORDER;
else if (astrcmpi(mode, "MirrorOnce") == 0)
return GS_ADDRESS_MIRRORONCE;
return GS_ADDRESS_CLAMP;
}
void shader_sampler_convert(struct shader_sampler *ss,
struct gs_sampler_info *info)
{
size_t i;
memset(info, 0, sizeof(struct gs_sampler_info));
for (i = 0; i < ss->states.num; i++) {
const char *state = ss->states.array[i];
const char *value = ss->values.array[i];
if (astrcmpi(state, "Filter") == 0)
info->filter = get_sample_filter(value);
else if (astrcmpi(state, "AddressU") == 0)
info->address_u = get_address_mode(value);
else if (astrcmpi(state, "AddressV") == 0)
info->address_v = get_address_mode(value);
else if (astrcmpi(state, "AddressW") == 0)
info->address_w = get_address_mode(value);
else if (astrcmpi(state, "MaxAnisotropy") == 0)
info->max_anisotropy = (int)strtol(value, NULL, 10);
/*else if (astrcmpi(state, "BorderColor") == 0)
// TODO */
}
}
/* ------------------------------------------------------------------------- */
static int sp_parse_sampler_state_item(struct shader_parser *sp,
struct shader_sampler *ss)
{
int ret;
char *state = NULL, *value = NULL;
ret = cf_next_name(&sp->cfp, &state, "state name", ";");
if (ret != PARSE_SUCCESS) goto fail;
ret = cf_next_token_should_be(&sp->cfp, "=", ";", NULL);
if (ret != PARSE_SUCCESS) goto fail;
ret = cf_next_name(&sp->cfp, &value, "value name", ";");
if (ret != PARSE_SUCCESS) goto fail;
ret = cf_next_token_should_be(&sp->cfp, ";", ";", NULL);
if (ret != PARSE_SUCCESS) goto fail;
da_push_back(ss->states, &state);
da_push_back(ss->values, &value);
return ret;
fail:
bfree(state);
bfree(value);
return ret;
}
static void sp_parse_sampler_state(struct shader_parser *sp)
{
struct shader_sampler ss;
struct cf_token peek;
shader_sampler_init(&ss);
if (cf_next_name(&sp->cfp, &ss.name, "name", ";") != PARSE_SUCCESS)
goto error;
if (cf_next_token_should_be(&sp->cfp, "{", ";", NULL) != PARSE_SUCCESS)
goto error;
if (!cf_peek_valid_token(&sp->cfp, &peek))
goto error;
while (strref_cmp(&peek.str, "}") != 0) {
int ret = sp_parse_sampler_state_item(sp, &ss);
if (ret == PARSE_EOF)
goto error;
if (!cf_peek_valid_token(&sp->cfp, &peek))
goto error;
}
if (cf_next_token_should_be(&sp->cfp, "}", ";", NULL) != PARSE_SUCCESS)
goto error;
if (cf_next_token_should_be(&sp->cfp, ";", NULL, NULL) != PARSE_SUCCESS)
goto error;
da_push_back(sp->samplers, &ss);
return;
error:
shader_sampler_free(&ss);
}
static inline int sp_parse_struct_var(struct shader_parser *sp,
struct shader_var *var)
{
int code;
/* -------------------------------------- */
/* variable type */
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
if (cf_token_is(&sp->cfp, ";")) return PARSE_CONTINUE;
if (cf_token_is(&sp->cfp, "}")) return PARSE_BREAK;
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME, "type name", ";");
if (code != PARSE_SUCCESS)
return code;
cf_copy_token(&sp->cfp, &var->type);
/* -------------------------------------- */
/* variable name */
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
if (cf_token_is(&sp->cfp, ";")) return PARSE_UNEXPECTED_CONTINUE;
if (cf_token_is(&sp->cfp, "}")) return PARSE_UNEXPECTED_BREAK;
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME, "variable name",
";");
if (code != PARSE_SUCCESS)
return code;
cf_copy_token(&sp->cfp, &var->name);
/* -------------------------------------- */
/* variable mapping if any (POSITION, TEXCOORD, etc) */
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
if (cf_token_is(&sp->cfp, ":")) {
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
if (cf_token_is(&sp->cfp, ";"))
return PARSE_UNEXPECTED_CONTINUE;
if (cf_token_is(&sp->cfp, "}"))
return PARSE_UNEXPECTED_BREAK;
code = cf_token_is_type(&sp->cfp, CFTOKEN_NAME,
"mapping name", ";");
if (code != PARSE_SUCCESS)
return code;
cf_copy_token(&sp->cfp, &var->mapping);
if (!cf_next_valid_token(&sp->cfp)) return PARSE_EOF;
}
/* -------------------------------------- */
if (!cf_token_is(&sp->cfp, ";")) {
if (!cf_go_to_valid_token(&sp->cfp, ";", "}"))
return PARSE_EOF;
return PARSE_CONTINUE;
}
return PARSE_SUCCESS;
}
static void sp_parse_struct(struct shader_parser *sp)
{
struct shader_struct ss;
shader_struct_init(&ss);
if (cf_next_name(&sp->cfp, &ss.name, "name", ";") != PARSE_SUCCESS)
goto error;
if (cf_next_token_should_be(&sp->cfp, "{", ";", NULL) != PARSE_SUCCESS)
goto error;
/* get structure variables */
while (true) {
bool do_break = false;
struct shader_var var;
shader_var_init(&var);
switch (sp_parse_struct_var(sp, &var)) {
case PARSE_UNEXPECTED_CONTINUE:
cf_adderror_syntax_error(&sp->cfp);
case PARSE_CONTINUE:
shader_var_free(&var);
continue;
case PARSE_UNEXPECTED_BREAK:
cf_adderror_syntax_error(&sp->cfp);
case PARSE_BREAK:
shader_var_free(&var);
do_break = true;
break;
case PARSE_EOF:
shader_var_free(&var);
goto error;
}
if (do_break)
break;
da_push_back(ss.vars, &var);
}
if (cf_next_token_should_be(&sp->cfp, ";", NULL, NULL) != PARSE_SUCCESS)
goto error;
da_push_back(sp->structs, &ss);
return;
error:
shader_struct_free(&ss);
}
static inline int sp_check_for_keyword(struct shader_parser *sp,
const char *keyword, bool *val)
{
bool new_val = cf_token_is(&sp->cfp, keyword);
if (new_val) {
if (!cf_next_valid_token(&sp->cfp))
return PARSE_EOF;
if (new_val && *val)
cf_adderror(&sp->cfp, "'$1' keyword already specified",
LEX_WARNING, keyword, NULL, NULL);
*val = new_val;
return PARSE_CONTINUE;
}
return PARSE_SUCCESS;
}
static inline int sp_parse_func_param(struct shader_parser *sp,
struct shader_var *var)
{
int code;
bool is_uniform = false;
if (!cf_next_valid_token(&sp->cfp))
return PARSE_EOF;
code = sp_check_for_keyword(sp, "uniform", &is_uniform);
if (code == PARSE_EOF)
return PARSE_EOF;
var->var_type = is_uniform ? SHADER_VAR_UNIFORM : SHADER_VAR_NONE;
code = cf_get_name(&sp->cfp, &var->type, "type", ")");
if (code != PARSE_SUCCESS)
return code;
code = cf_next_name(&sp->cfp, &var->name, "name", ")");
if (code != PARSE_SUCCESS)
return code;
if (!cf_next_valid_token(&sp->cfp))
return PARSE_EOF;
if (cf_token_is(&sp->cfp, ":")) {
code = cf_next_name(&sp->cfp, &var->mapping,
"mapping specifier", ")");
if (code != PARSE_SUCCESS)
return code;
if (!cf_next_valid_token(&sp->cfp))
return PARSE_EOF;
}
return PARSE_SUCCESS;
}
static bool sp_parse_func_params(struct shader_parser *sp,
struct shader_func *func)
{
struct cf_token peek;
int code;
cf_token_clear(&peek);
if (!cf_peek_valid_token(&sp->cfp, &peek))
return false;
if (*peek.str.array == ')') {
cf_next_token(&sp->cfp);
goto exit;
}
do {
struct shader_var var;
shader_var_init(&var);
if (!cf_token_is(&sp->cfp, "(") && !cf_token_is(&sp->cfp, ","))
cf_adderror_syntax_error(&sp->cfp);
code = sp_parse_func_param(sp, &var);
if (code != PARSE_SUCCESS) {
shader_var_free(&var);
if (code == PARSE_CONTINUE)
goto exit;
else if (code == PARSE_EOF)
return false;
}
da_push_back(func->params, &var);
} while (!cf_token_is(&sp->cfp, ")"));
exit:
return true;
}
static void sp_parse_function(struct shader_parser *sp, char *type, char *name)
{
struct shader_func func;
shader_func_init(&func, type, name);
if (!sp_parse_func_params(sp, &func))
goto error;
if (!cf_next_valid_token(&sp->cfp))
goto error;
/* if function is mapped to something, for example COLOR */
if (cf_token_is(&sp->cfp, ":")) {
char *mapping = NULL;
int errorcode = cf_next_name(&sp->cfp, &mapping, "mapping",
"{");
if (errorcode != PARSE_SUCCESS)
goto error;
func.mapping = mapping;
if (!cf_next_valid_token(&sp->cfp))
goto error;
}
if (!cf_token_is(&sp->cfp, "{")) {
cf_adderror_expecting(&sp->cfp, "{");
goto error;
}
func.start = sp->cfp.cur_token;
if (!cf_pass_pair(&sp->cfp, '{', '}'))
goto error;
/* it is established that the current token is '}' if we reach this */
cf_next_token(&sp->cfp);
func.end = sp->cfp.cur_token;
da_push_back(sp->funcs, &func);
return;
error:
shader_func_free(&func);
}
/* parses "array[count]" */
static bool sp_parse_param_array(struct shader_parser *sp,
struct shader_var *param)
{
if (!cf_next_valid_token(&sp->cfp))
return false;
if (sp->cfp.cur_token->type != CFTOKEN_NUM ||
!valid_int_str(sp->cfp.cur_token->str.array,
sp->cfp.cur_token->str.len))
return false;
param->array_count =(int)strtol(sp->cfp.cur_token->str.array, NULL, 10);
if (cf_next_token_should_be(&sp->cfp, "]", ";", NULL) == PARSE_EOF)
return false;
if (!cf_next_valid_token(&sp->cfp))
return false;
return true;
}
static inline int sp_parse_param_assign_intfloat(struct shader_parser *sp,
struct shader_var *param, bool is_float)
{
int code;
if (!cf_next_valid_token(&sp->cfp))
return PARSE_EOF;
code = cf_token_is_type(&sp->cfp, CFTOKEN_NUM, "numeric value", ";");
if (code != PARSE_SUCCESS)
return code;
if (is_float) {
float f = (float)strtod(sp->cfp.cur_token->str.array, NULL);
da_push_back_array(param->default_val, &f, sizeof(float));
} else {
long l = strtol(sp->cfp.cur_token->str.array, NULL, 10);
da_push_back_array(param->default_val, &l, sizeof(long));
}
return PARSE_SUCCESS;
}
/*
* parses assignment for float1, float2, float3, float4, and any combination
* for float3x3, float4x4, etc
*/
static inline int sp_parse_param_assign_float_array(struct shader_parser *sp,
struct shader_var *param)
{
const char *float_type = param->type+5;
int float_count = 0, code, i;
/* -------------------------------------------- */
if (float_type[0] < '1' || float_type[0] > '4')
cf_adderror(&sp->cfp, "Invalid row count", LEX_ERROR,
NULL, NULL, NULL);
float_count = float_type[0]-'0';
if (float_type[1] == 'x') {
if (float_type[2] < '1' || float_type[2] > '4')
cf_adderror(&sp->cfp, "Invalid column count",
LEX_ERROR, NULL, NULL, NULL);
float_count *= float_type[2]-'0';
}
/* -------------------------------------------- */
code = cf_next_token_should_be(&sp->cfp, "{", ";", NULL);
if (code != PARSE_SUCCESS) return code;
for (i = 0; i < float_count; i++) {
char *next = ((i+1) < float_count) ? "," : "}";
code = sp_parse_param_assign_intfloat(sp, param, true);
if (code != PARSE_SUCCESS) return code;
code = cf_next_token_should_be(&sp->cfp, next, ";", NULL);
if (code != PARSE_SUCCESS) return code;
}
return PARSE_SUCCESS;
}
static int sp_parse_param_assignment_val(struct shader_parser *sp,
struct shader_var *param)
{
if (strcmp(param->type, "int") == 0)
return sp_parse_param_assign_intfloat(sp, param, false);
else if (strcmp(param->type, "float") == 0)
return sp_parse_param_assign_intfloat(sp, param, true);
else if (astrcmp_n(param->type, "float", 5) == 0)
return sp_parse_param_assign_float_array(sp, param);
cf_adderror(&sp->cfp, "Invalid type '$1' used for assignment",
LEX_ERROR, param->type, NULL, NULL);
return PARSE_CONTINUE;
}
static inline bool sp_parse_param_assign(struct shader_parser *sp,
struct shader_var *param)
{
if (sp_parse_param_assignment_val(sp, param) != PARSE_SUCCESS)
return false;
if (!cf_next_valid_token(&sp->cfp))
return false;
return true;
}
static void sp_parse_param(struct shader_parser *sp,
char *type, char *name, bool is_const, bool is_uniform)
{
struct shader_var param;
shader_var_init_param(&param, type, name, is_uniform, is_const);
if (cf_token_is(&sp->cfp, ";"))
goto complete;
if (cf_token_is(&sp->cfp, "[") && !sp_parse_param_array(sp, &param))
goto error;
if (cf_token_is(&sp->cfp, "=") && !sp_parse_param_assign(sp, &param))
goto error;
if (!cf_token_is(&sp->cfp, ";"))
goto error;
complete:
da_push_back(sp->params, &param);
return;
error:
shader_var_free(&param);
}
static bool sp_get_var_specifiers(struct shader_parser *sp,
bool *is_const, bool *is_uniform)
{
while(true) {
int code = sp_check_for_keyword(sp, "const", is_const);
if (code == PARSE_EOF)
return false;
else if (code == PARSE_CONTINUE)
continue;
code = sp_check_for_keyword(sp, "uniform", is_uniform);
if (code == PARSE_EOF)
return false;
else if (code == PARSE_CONTINUE)
continue;
break;
}
return true;
}
static inline void report_invalid_func_keyword(struct shader_parser *sp,
const char *name, bool val)
{
if (val)
cf_adderror(&sp->cfp, "'$1' keyword cannot be used with a "
"function", LEX_ERROR,
name, NULL, NULL);
}
static void sp_parse_other(struct shader_parser *sp)
{
bool is_const = false, is_uniform = false;
char *type = NULL, *name = NULL;
if (!sp_get_var_specifiers(sp, &is_const, &is_uniform))
goto error;
if (cf_get_name(&sp->cfp, &type, "type", ";") != PARSE_SUCCESS)
goto error;
if (cf_next_name(&sp->cfp, &name, "name", ";") != PARSE_SUCCESS)
goto error;
if (!cf_next_valid_token(&sp->cfp))
goto error;
if (cf_token_is(&sp->cfp, "(")) {
report_invalid_func_keyword(sp, "const", is_const);
report_invalid_func_keyword(sp, "uniform", is_uniform);
sp_parse_function(sp, type, name);
return;
} else {
sp_parse_param(sp, type, name, is_const, is_uniform);
return;
}
error:
bfree(type);
bfree(name);
}
bool shader_parse(struct shader_parser *sp, const char *shader,
const char *file)
{
if (!cf_parser_parse(&sp->cfp, shader, file))
return false;
while (sp->cfp.cur_token && sp->cfp.cur_token->type != CFTOKEN_NONE) {
if (cf_token_is(&sp->cfp, ";") ||
is_whitespace(*sp->cfp.cur_token->str.array)) {
sp->cfp.cur_token++;
} else if (cf_token_is(&sp->cfp, "struct")) {
sp_parse_struct(sp);
} else if (cf_token_is(&sp->cfp, "sampler_state")) {
sp_parse_sampler_state(sp);
} else if (cf_token_is(&sp->cfp, "{")) {
cf_adderror(&sp->cfp, "Unexpected code segment",
LEX_ERROR, NULL, NULL, NULL);
cf_pass_pair(&sp->cfp, '{', '}');
} else {
/* parameters and functions */
sp_parse_other(sp);
}
}
return !error_data_has_errors(&sp->cfp.error_list);
}