2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* shader_language.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2020-01-01 11:16:22 +01:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 02:10:30 +01:00
/* */
/* 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 THE AUTHORS OR COPYRIGHT HOLDERS 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. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "shader_language.h"
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
# include "core/print_string.h"
2019-10-30 10:38:35 +01:00
# include "servers/visual_server.h"
2014-02-10 02:10:30 +01:00
static bool _is_text_char ( CharType c ) {
2017-03-05 16:44:50 +01:00
return ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' _ ' ;
2014-02-10 02:10:30 +01:00
}
static bool _is_number ( CharType c ) {
2017-03-05 16:44:50 +01:00
return ( c > = ' 0 ' & & c < = ' 9 ' ) ;
2014-02-10 02:10:30 +01:00
}
static bool _is_hex ( CharType c ) {
2017-03-05 16:44:50 +01:00
return ( c > = ' 0 ' & & c < = ' 9 ' ) | | ( c > = ' a ' & & c < = ' f ' ) | | ( c > = ' A ' & & c < = ' F ' ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
String ShaderLanguage : : get_operator_text ( Operator p_op ) {
2017-03-05 16:44:50 +01:00
static const char * op_names [ OP_MAX ] = { " == " ,
" != " ,
" < " ,
" <= " ,
" > " ,
" >= " ,
" && " ,
" || " ,
" ! " ,
" - " ,
" + " ,
" - " ,
" * " ,
" / " ,
" % " ,
" << " ,
" >> " ,
" = " ,
" += " ,
" -= " ,
" *= " ,
" /= " ,
" %= " ,
" <<= " ,
" >>= " ,
" &= " ,
" |= " ,
" ^= " ,
" & " ,
" | " ,
" ^ " ,
" ~ " ,
2017-09-05 20:22:33 +02:00
" ++ " ,
" -- " ,
" ? " ,
" : " ,
" ++ " ,
2017-03-05 16:44:50 +01:00
" -- " ,
" () " ,
2017-04-07 04:36:37 +02:00
" construct " ,
" index " } ;
2016-10-07 16:31:18 +02:00
return op_names [ p_op ] ;
}
2017-03-05 16:44:50 +01:00
const char * ShaderLanguage : : token_names [ TK_MAX ] = {
2014-02-10 02:10:30 +01:00
" EMPTY " ,
2016-10-03 21:33:42 +02:00
" IDENTIFIER " ,
2014-02-10 02:10:30 +01:00
" TRUE " ,
" FALSE " ,
" REAL_CONSTANT " ,
2016-10-07 16:31:18 +02:00
" INT_CONSTANT " ,
2014-02-10 02:10:30 +01:00
" TYPE_VOID " ,
" TYPE_BOOL " ,
2016-10-07 16:31:18 +02:00
" TYPE_BVEC2 " ,
" TYPE_BVEC3 " ,
" TYPE_BVEC4 " ,
" TYPE_INT " ,
" TYPE_IVEC2 " ,
" TYPE_IVEC3 " ,
" TYPE_IVEC4 " ,
" TYPE_UINT " ,
" TYPE_UVEC2 " ,
" TYPE_UVEC3 " ,
" TYPE_UVEC4 " ,
2014-02-10 02:10:30 +01:00
" TYPE_FLOAT " ,
" TYPE_VEC2 " ,
" TYPE_VEC3 " ,
" TYPE_VEC4 " ,
2015-03-10 04:53:09 +01:00
" TYPE_MAT2 " ,
2014-02-10 02:10:30 +01:00
" TYPE_MAT3 " ,
" TYPE_MAT4 " ,
2016-10-07 16:31:18 +02:00
" TYPE_SAMPLER2D " ,
" TYPE_ISAMPLER2D " ,
" TYPE_USAMPLER2D " ,
2018-06-26 13:59:26 +02:00
" TYPE_SAMPLER2DARRAY " ,
" TYPE_ISAMPLER2DARRAY " ,
" TYPE_USAMPLER2DARRAY " ,
" TYPE_SAMPLER3D " ,
" TYPE_ISAMPLER3D " ,
" TYPE_USAMPLER3D " ,
2016-10-07 16:31:18 +02:00
" TYPE_SAMPLERCUBE " ,
2018-03-08 00:56:47 +01:00
" INTERPOLATION_FLAT " ,
" INTERPOLATION_SMOOTH " ,
2019-05-30 16:19:24 +02:00
" CONST " ,
2016-10-07 16:31:18 +02:00
" PRECISION_LOW " ,
" PRECISION_MID " ,
" PRECISION_HIGH " ,
2014-02-10 02:10:30 +01:00
" OP_EQUAL " ,
" OP_NOT_EQUAL " ,
" OP_LESS " ,
" OP_LESS_EQUAL " ,
" OP_GREATER " ,
" OP_GREATER_EQUAL " ,
" OP_AND " ,
" OP_OR " ,
" OP_NOT " ,
" OP_ADD " ,
" OP_SUB " ,
" OP_MUL " ,
" OP_DIV " ,
2016-10-07 16:31:18 +02:00
" OP_MOD " ,
" OP_SHIFT_LEFT " ,
" OP_SHIFT_RIGHT " ,
2014-02-10 02:10:30 +01:00
" OP_ASSIGN " ,
" OP_ASSIGN_ADD " ,
" OP_ASSIGN_SUB " ,
" OP_ASSIGN_MUL " ,
" OP_ASSIGN_DIV " ,
2016-10-07 16:31:18 +02:00
" OP_ASSIGN_MOD " ,
" OP_ASSIGN_SHIFT_LEFT " ,
" OP_ASSIGN_SHIFT_RIGHT " ,
" OP_ASSIGN_BIT_AND " ,
" OP_ASSIGN_BIT_OR " ,
" OP_ASSIGN_BIT_XOR " ,
" OP_BIT_AND " ,
" OP_BIT_OR " ,
" OP_BIT_XOR " ,
" OP_BIT_INVERT " ,
" OP_INCREMENT " ,
" OP_DECREMENT " ,
2014-02-10 02:10:30 +01:00
" CF_IF " ,
" CF_ELSE " ,
2016-10-07 16:31:18 +02:00
" CF_FOR " ,
" CF_WHILE " ,
" CF_DO " ,
" CF_SWITCH " ,
" CF_CASE " ,
" CF_BREAK " ,
" CF_CONTINUE " ,
2014-02-10 02:10:30 +01:00
" CF_RETURN " ,
2017-08-29 15:14:07 +02:00
" CF_DISCARD " ,
2014-02-10 02:10:30 +01:00
" BRACKET_OPEN " ,
" BRACKET_CLOSE " ,
" CURLY_BRACKET_OPEN " ,
" CURLY_BRACKET_CLOSE " ,
" PARENTHESIS_OPEN " ,
" PARENTHESIS_CLOSE " ,
2016-10-07 16:31:18 +02:00
" QUESTION " ,
2014-02-10 02:10:30 +01:00
" COMMA " ,
2016-10-07 16:31:18 +02:00
" COLON " ,
2014-02-10 02:10:30 +01:00
" SEMICOLON " ,
" PERIOD " ,
" UNIFORM " ,
2016-10-07 16:31:18 +02:00
" VARYING " ,
2017-04-07 04:36:37 +02:00
" IN " ,
" OUT " ,
" INOUT " ,
2016-10-07 16:31:18 +02:00
" RENDER_MODE " ,
" HINT_WHITE_TEXTURE " ,
" HINT_BLACK_TEXTURE " ,
" HINT_NORMAL_TEXTURE " ,
2016-11-21 02:49:53 +01:00
" HINT_ANISO_TEXTURE " ,
2016-10-07 16:31:18 +02:00
" HINT_ALBEDO_TEXTURE " ,
2016-11-21 02:49:53 +01:00
" HINT_BLACK_ALBEDO_TEXTURE " ,
2016-10-07 16:31:18 +02:00
" HINT_COLOR " ,
" HINT_RANGE " ,
2019-07-21 16:31:30 +02:00
" FILTER_NEAREST " ,
" FILTER_LINEAR " ,
" FILTER_NEAREST_MIPMAP " ,
" FILTER_LINEAR_MIPMAP " ,
" FILTER_NEAREST_MIPMAP_ANISO " ,
" FILTER_LINEAR_MIPMAP_ANISO " ,
" REPEAT_ENABLE " ,
" REPEAT_DISABLE " ,
2017-04-07 04:36:37 +02:00
" SHADER_TYPE " ,
2016-10-07 16:31:18 +02:00
" CURSOR " ,
2014-02-10 02:10:30 +01:00
" ERROR " ,
2016-10-07 16:31:18 +02:00
" EOF " ,
2014-02-10 02:10:30 +01:00
} ;
2016-10-03 21:33:42 +02:00
String ShaderLanguage : : get_token_text ( Token p_token ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String name = token_names [ p_token . type ] ;
if ( p_token . type = = TK_INT_CONSTANT | | p_token . type = = TK_REAL_CONSTANT ) {
name + = " ( " + rtos ( p_token . constant ) + " ) " ;
} else if ( p_token . type = = TK_IDENTIFIER ) {
name + = " ( " + String ( p_token . text ) + " ) " ;
} else if ( p_token . type = = TK_ERROR ) {
name + = " ( " + String ( p_token . text ) + " ) " ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return name ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ShaderLanguage : : Token ShaderLanguage : : _make_token ( TokenType p_type , const StringName & p_text ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
Token tk ;
2017-03-05 16:44:50 +01:00
tk . type = p_type ;
tk . text = p_text ;
tk . line = tk_line ;
if ( tk . type = = TK_ERROR ) {
2016-10-07 16:31:18 +02:00
_set_error ( p_text ) ;
}
2016-10-03 21:33:42 +02:00
return tk ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const ShaderLanguage : : KeyWord ShaderLanguage : : keyword_list [ ] = {
{ TK_TRUE , " true " } ,
{ TK_FALSE , " false " } ,
{ TK_TYPE_VOID , " void " } ,
{ TK_TYPE_BOOL , " bool " } ,
{ TK_TYPE_BVEC2 , " bvec2 " } ,
{ TK_TYPE_BVEC3 , " bvec3 " } ,
{ TK_TYPE_BVEC4 , " bvec4 " } ,
{ TK_TYPE_INT , " int " } ,
{ TK_TYPE_IVEC2 , " ivec2 " } ,
{ TK_TYPE_IVEC3 , " ivec3 " } ,
{ TK_TYPE_IVEC4 , " ivec4 " } ,
{ TK_TYPE_UINT , " uint " } ,
{ TK_TYPE_UVEC2 , " uvec2 " } ,
{ TK_TYPE_UVEC3 , " uvec3 " } ,
{ TK_TYPE_UVEC4 , " uvec4 " } ,
{ TK_TYPE_FLOAT , " float " } ,
{ TK_TYPE_VEC2 , " vec2 " } ,
{ TK_TYPE_VEC3 , " vec3 " } ,
{ TK_TYPE_VEC4 , " vec4 " } ,
{ TK_TYPE_MAT2 , " mat2 " } ,
{ TK_TYPE_MAT3 , " mat3 " } ,
{ TK_TYPE_MAT4 , " mat4 " } ,
{ TK_TYPE_SAMPLER2D , " sampler2D " } ,
{ TK_TYPE_ISAMPLER2D , " isampler2D " } ,
{ TK_TYPE_USAMPLER2D , " usampler2D " } ,
2018-06-26 13:59:26 +02:00
{ TK_TYPE_SAMPLER2DARRAY , " sampler2DArray " } ,
{ TK_TYPE_ISAMPLER2DARRAY , " isampler2DArray " } ,
{ TK_TYPE_USAMPLER2DARRAY , " usampler2DArray " } ,
{ TK_TYPE_SAMPLER3D , " sampler3D " } ,
{ TK_TYPE_ISAMPLER3D , " isampler3D " } ,
{ TK_TYPE_USAMPLER3D , " usampler3D " } ,
2017-03-05 16:44:50 +01:00
{ TK_TYPE_SAMPLERCUBE , " samplerCube " } ,
2017-11-27 16:47:46 +01:00
{ TK_INTERPOLATION_FLAT , " flat " } ,
{ TK_INTERPOLATION_SMOOTH , " smooth " } ,
2019-05-30 16:19:24 +02:00
{ TK_CONST , " const " } ,
2020-01-17 20:35:22 +01:00
{ TK_STRUCT , " struct " } ,
2017-03-05 16:44:50 +01:00
{ TK_PRECISION_LOW , " lowp " } ,
{ TK_PRECISION_MID , " mediump " } ,
{ TK_PRECISION_HIGH , " highp " } ,
{ TK_CF_IF , " if " } ,
{ TK_CF_ELSE , " else " } ,
{ TK_CF_FOR , " for " } ,
{ TK_CF_WHILE , " while " } ,
{ TK_CF_DO , " do " } ,
{ TK_CF_SWITCH , " switch " } ,
{ TK_CF_CASE , " case " } ,
2019-08-14 13:22:25 +02:00
{ TK_CF_DEFAULT , " default " } ,
2017-03-05 16:44:50 +01:00
{ TK_CF_BREAK , " break " } ,
{ TK_CF_CONTINUE , " continue " } ,
{ TK_CF_RETURN , " return " } ,
2017-09-24 09:27:12 +02:00
{ TK_CF_DISCARD , " discard " } ,
2017-03-05 16:44:50 +01:00
{ TK_UNIFORM , " uniform " } ,
{ TK_VARYING , " varying " } ,
2017-04-07 04:36:37 +02:00
{ TK_ARG_IN , " in " } ,
{ TK_ARG_OUT , " out " } ,
{ TK_ARG_INOUT , " inout " } ,
2017-03-05 16:44:50 +01:00
{ TK_RENDER_MODE , " render_mode " } ,
{ TK_HINT_WHITE_TEXTURE , " hint_white " } ,
{ TK_HINT_BLACK_TEXTURE , " hint_black " } ,
{ TK_HINT_NORMAL_TEXTURE , " hint_normal " } ,
2019-09-14 05:37:42 +02:00
{ TK_HINT_ROUGHNESS_NORMAL_TEXTURE , " hint_roughness_normal " } ,
{ TK_HINT_ROUGHNESS_R , " hint_roughness_r " } ,
{ TK_HINT_ROUGHNESS_G , " hint_roughness_g " } ,
{ TK_HINT_ROUGHNESS_B , " hint_roughness_b " } ,
{ TK_HINT_ROUGHNESS_A , " hint_roughness_a " } ,
{ TK_HINT_ROUGHNESS_GRAY , " hint_roughness_gray " } ,
2017-03-05 16:44:50 +01:00
{ TK_HINT_ANISO_TEXTURE , " hint_aniso " } ,
{ TK_HINT_ALBEDO_TEXTURE , " hint_albedo " } ,
{ TK_HINT_BLACK_ALBEDO_TEXTURE , " hint_black_albedo " } ,
{ TK_HINT_COLOR , " hint_color " } ,
{ TK_HINT_RANGE , " hint_range " } ,
2019-07-21 16:31:30 +02:00
{ TK_FILTER_NEAREST , " filter_nearest " } ,
{ TK_FILTER_LINEAR , " filter_linear " } ,
{ TK_FILTER_NEAREST_MIPMAP , " filter_nearest_mipmap " } ,
{ TK_FILTER_LINEAR_MIPMAP , " filter_linear_mipmap " } ,
{ TK_FILTER_NEAREST_MIPMAP_ANISO , " filter_nearest_mipmap_aniso " } ,
{ TK_FILTER_LINEAR_MIPMAP_ANISO , " filter_linear_mipmap_aniso " } ,
{ TK_REPEAT_ENABLE , " repeat_enable " } ,
{ TK_REPEAT_DISABLE , " repeat_disable " } ,
2017-04-07 04:36:37 +02:00
{ TK_SHADER_TYPE , " shader_type " } ,
2017-03-05 16:44:50 +01:00
{ TK_ERROR , NULL }
2016-10-07 16:31:18 +02:00
} ;
2015-04-26 17:34:42 +02:00
2016-10-03 21:33:42 +02:00
ShaderLanguage : : Token ShaderLanguage : : _get_token ( ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
# define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : CharType(0))
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
2017-03-05 16:44:50 +01:00
switch ( GETCHAR ( - 1 ) ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
case 0 :
return _make_token ( TK_EOF ) ;
case 0xFFFF :
return _make_token ( TK_CURSOR ) ; //for completion
2016-10-03 21:33:42 +02:00
case ' \t ' :
case ' \r ' :
case ' ' :
continue ;
case ' \n ' :
tk_line + + ;
continue ;
case ' / ' : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( GETCHAR ( 0 ) ) {
2016-10-03 21:33:42 +02:00
case ' * ' : { // block comment
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
char_idx + + ;
2017-03-05 16:44:50 +01:00
while ( true ) {
if ( GETCHAR ( 0 ) = = 0 ) {
2016-10-03 21:33:42 +02:00
return _make_token ( TK_EOF ) ;
2017-03-05 16:44:50 +01:00
}
if ( GETCHAR ( 0 ) = = ' * ' & & GETCHAR ( 1 ) = = ' / ' ) {
char_idx + = 2 ;
2016-10-03 21:33:42 +02:00
break ;
2017-03-05 16:44:50 +01:00
} else if ( GETCHAR ( 0 ) = = ' \n ' ) {
2016-10-03 21:33:42 +02:00
tk_line + + ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
char_idx + + ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case ' / ' : { // line comment skip
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
if ( GETCHAR ( 0 ) = = ' \n ' ) {
2017-12-29 19:32:21 +01:00
tk_line + + ;
2016-10-03 21:33:42 +02:00
char_idx + + ;
break ;
}
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = 0 ) {
2016-10-03 21:33:42 +02:00
return _make_token ( TK_EOF ) ;
}
char_idx + + ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case ' = ' : { // diveq
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_DIV ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
default :
return _make_token ( TK_OP_DIV ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
continue ; //a comment, continue to next token
} break ;
case ' = ' : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_EQUAL ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_ASSIGN ) ;
} break ;
case ' < ' : {
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_LESS_EQUAL ) ;
2017-03-05 16:44:50 +01:00
} else if ( GETCHAR ( 0 ) = = ' < ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_SHIFT_LEFT ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_SHIFT_LEFT ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_LESS ) ;
} break ;
case ' > ' : {
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_GREATER_EQUAL ) ;
2017-04-07 04:36:37 +02:00
} else if ( GETCHAR ( 0 ) = = ' > ' ) {
2017-01-14 18:03:38 +01:00
char_idx + + ;
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_SHIFT_RIGHT ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_SHIFT_RIGHT ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_GREATER ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case ' ! ' : {
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_NOT_EQUAL ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_NOT ) ;
} break ;
//case '"' //string - no strings in shader
//case '\'' //string - no strings in shader
case ' { ' :
return _make_token ( TK_CURLY_BRACKET_OPEN ) ;
case ' } ' :
return _make_token ( TK_CURLY_BRACKET_CLOSE ) ;
case ' [ ' :
return _make_token ( TK_BRACKET_OPEN ) ;
case ' ] ' :
return _make_token ( TK_BRACKET_CLOSE ) ;
case ' ( ' :
return _make_token ( TK_PARENTHESIS_OPEN ) ;
case ' ) ' :
return _make_token ( TK_PARENTHESIS_CLOSE ) ;
case ' , ' :
return _make_token ( TK_COMMA ) ;
case ' ; ' :
return _make_token ( TK_SEMICOLON ) ;
case ' ? ' :
return _make_token ( TK_QUESTION ) ;
case ' : ' :
return _make_token ( TK_COLON ) ;
case ' ^ ' :
return _make_token ( TK_OP_BIT_XOR ) ;
case ' ~ ' :
return _make_token ( TK_OP_BIT_INVERT ) ;
case ' & ' : {
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_BIT_AND ) ;
2017-03-05 16:44:50 +01:00
} else if ( GETCHAR ( 0 ) = = ' & ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_AND ) ;
}
return _make_token ( TK_OP_BIT_AND ) ;
} break ;
case ' | ' : {
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_BIT_OR ) ;
2017-03-05 16:44:50 +01:00
} else if ( GETCHAR ( 0 ) = = ' | ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_OR ) ;
}
return _make_token ( TK_OP_BIT_OR ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case ' * ' : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_MUL ) ;
}
return _make_token ( TK_OP_MUL ) ;
} break ;
case ' + ' : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_ADD ) ;
2017-03-05 16:44:50 +01:00
} else if ( GETCHAR ( 0 ) = = ' + ' ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_INCREMENT ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_ADD ) ;
} break ;
case ' - ' : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_SUB ) ;
2017-03-05 16:44:50 +01:00
} else if ( GETCHAR ( 0 ) = = ' - ' ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_DECREMENT ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_SUB ) ;
} break ;
case ' % ' : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' = ' ) {
2016-10-03 21:33:42 +02:00
char_idx + + ;
return _make_token ( TK_OP_ASSIGN_MOD ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
return _make_token ( TK_OP_MOD ) ;
} break ;
default : {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
char_idx - - ; //go back one, since we have no idea what this is
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( _is_number ( GETCHAR ( 0 ) ) | | ( GETCHAR ( 0 ) = = ' . ' & & _is_number ( GETCHAR ( 1 ) ) ) ) {
2016-10-03 21:33:42 +02:00
// parse number
2017-03-05 16:44:50 +01:00
bool period_found = false ;
bool exponent_found = false ;
bool hexa_found = false ;
bool sign_found = false ;
2018-07-14 13:28:43 +02:00
bool float_suffix_found = false ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
String str ;
2017-03-05 16:44:50 +01:00
int i = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
if ( GETCHAR ( i ) = = ' . ' ) {
2018-07-14 13:28:43 +02:00
if ( period_found | | exponent_found | | hexa_found | | float_suffix_found )
2017-03-05 16:44:50 +01:00
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
period_found = true ;
} else if ( GETCHAR ( i ) = = ' x ' ) {
if ( hexa_found | | str . length ( ) ! = 1 | | str [ 0 ] ! = ' 0 ' )
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
hexa_found = true ;
} else if ( GETCHAR ( i ) = = ' e ' ) {
2018-07-14 13:28:43 +02:00
if ( hexa_found | | exponent_found | | float_suffix_found )
2017-03-05 16:44:50 +01:00
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
exponent_found = true ;
2018-07-14 13:28:43 +02:00
} else if ( GETCHAR ( i ) = = ' f ' ) {
if ( hexa_found | | exponent_found )
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
float_suffix_found = true ;
2016-10-03 21:33:42 +02:00
} else if ( _is_number ( GETCHAR ( i ) ) ) {
2018-07-14 13:28:43 +02:00
if ( float_suffix_found )
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
2016-10-03 21:33:42 +02:00
} else if ( hexa_found & & _is_hex ( GETCHAR ( i ) ) ) {
2017-03-05 16:44:50 +01:00
} else if ( ( GETCHAR ( i ) = = ' - ' | | GETCHAR ( i ) = = ' + ' ) & & exponent_found ) {
2016-10-03 21:33:42 +02:00
if ( sign_found )
2017-03-05 16:44:50 +01:00
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
sign_found = true ;
2016-10-03 21:33:42 +02:00
} else
break ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
str + = CharType ( GETCHAR ( i ) ) ;
2016-10-03 21:33:42 +02:00
i + + ;
}
2014-02-10 02:10:30 +01:00
2018-07-14 13:28:43 +02:00
CharType last_char = str [ str . length ( ) - 1 ] ;
if ( hexa_found ) {
2019-12-29 10:19:10 +01:00
//integer(hex)
if ( str . size ( ) > 11 | | ! str . is_valid_hex_number ( true ) ) { // > 0xFFFFFFFF
return _make_token ( TK_ERROR , " Invalid (hexadecimal) numeric constant " ) ;
}
2018-12-28 09:20:11 +01:00
} else if ( period_found | | exponent_found | | float_suffix_found ) {
2018-07-14 13:28:43 +02:00
//floats
if ( period_found ) {
if ( float_suffix_found ) {
//checks for eg "1.f" or "1.99f" notations
if ( last_char ! = ' f ' ) {
return _make_token ( TK_ERROR , " Invalid (float) numeric constant " ) ;
}
} else {
//checks for eg. "1." or "1.99" notations
if ( last_char ! = ' . ' & & ! _is_number ( last_char ) ) {
return _make_token ( TK_ERROR , " Invalid (float) numeric constant " ) ;
}
}
} else if ( float_suffix_found ) {
// if no period found the float suffix must be the last character, like in "2f" for "2.0"
if ( last_char ! = ' f ' ) {
return _make_token ( TK_ERROR , " Invalid (float) numeric constant " ) ;
}
}
if ( float_suffix_found ) {
//strip the suffix
str = str . left ( str . length ( ) - 1 ) ;
//compensate reading cursor position
char_idx + = 1 ;
}
if ( ! str . is_valid_float ( ) ) {
return _make_token ( TK_ERROR , " Invalid (float) numeric constant " ) ;
}
} else {
//integers
if ( ! _is_number ( last_char ) ) {
return _make_token ( TK_ERROR , " Invalid (integer) numeric constant " ) ;
}
if ( ! str . is_valid_integer ( ) ) {
return _make_token ( TK_ERROR , " Invalid numeric constant " ) ;
}
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
char_idx + = str . length ( ) ;
2016-10-03 21:33:42 +02:00
Token tk ;
2018-12-28 09:20:11 +01:00
if ( period_found | | exponent_found | | float_suffix_found )
2017-03-05 16:44:50 +01:00
tk . type = TK_REAL_CONSTANT ;
2016-10-03 21:33:42 +02:00
else
2017-03-05 16:44:50 +01:00
tk . type = TK_INT_CONSTANT ;
2015-03-10 04:53:09 +01:00
2019-12-29 10:19:10 +01:00
if ( hexa_found ) {
tk . constant = ( double ) str . hex_to_int64 ( true ) ;
} else {
tk . constant = str . to_double ( ) ;
}
2017-03-05 16:44:50 +01:00
tk . line = tk_line ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return tk ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) = = ' . ' ) {
2016-10-03 21:33:42 +02:00
//parse period
2016-10-07 16:31:18 +02:00
char_idx + + ;
2016-10-03 21:33:42 +02:00
return _make_token ( TK_PERIOD ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
if ( _is_text_char ( GETCHAR ( 0 ) ) ) {
// parse identifier
String str ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( _is_text_char ( GETCHAR ( 0 ) ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
str + = CharType ( GETCHAR ( 0 ) ) ;
2016-10-03 21:33:42 +02:00
char_idx + + ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
//see if keyword
//should be converted to a static map
2017-03-05 16:44:50 +01:00
int idx = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( keyword_list [ idx ] . text ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( str = = keyword_list [ idx ] . text ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
return _make_token ( keyword_list [ idx ] . token ) ;
2016-10-03 21:33:42 +02:00
}
idx + + ;
}
2014-02-10 02:10:30 +01:00
2020-02-01 10:34:02 +01:00
str = str . replace ( " dus_ " , " _ " ) ;
2017-03-05 16:44:50 +01:00
return _make_token ( TK_IDENTIFIER , str ) ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( GETCHAR ( 0 ) > 32 )
return _make_token ( TK_ERROR , " Tokenizer: Unknown character # " + itos ( GETCHAR ( 0 ) ) + " : ' " + String : : chr ( GETCHAR ( 0 ) ) + " ' " ) ;
2016-10-03 21:33:42 +02:00
else
2017-03-05 16:44:50 +01:00
return _make_token ( TK_ERROR , " Tokenizer: Unknown character # " + itos ( GETCHAR ( 0 ) ) ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
2016-10-03 21:33:42 +02:00
ERR_PRINT ( " BUG " ) ;
return Token ( ) ;
2018-01-25 02:00:51 +01:00
# undef GETCHAR
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
String ShaderLanguage : : token_debug ( const String & p_code ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
clear ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
code = p_code ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
String output ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
Token tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
while ( tk . type ! = TK_EOF & & tk . type ! = TK_ERROR ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
output + = itos ( tk_line ) + " : " + get_token_text ( tk ) + " \n " ;
2016-10-07 16:31:18 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
return output ;
2014-02-10 02:10:30 +01:00
}
2018-11-12 12:36:26 +01:00
bool ShaderLanguage : : is_token_variable_datatype ( TokenType p_type ) {
return (
p_type = = TK_TYPE_VOID | |
p_type = = TK_TYPE_BOOL | |
p_type = = TK_TYPE_BVEC2 | |
p_type = = TK_TYPE_BVEC3 | |
p_type = = TK_TYPE_BVEC4 | |
p_type = = TK_TYPE_INT | |
p_type = = TK_TYPE_IVEC2 | |
p_type = = TK_TYPE_IVEC3 | |
p_type = = TK_TYPE_IVEC4 | |
p_type = = TK_TYPE_UINT | |
p_type = = TK_TYPE_UVEC2 | |
p_type = = TK_TYPE_UVEC3 | |
p_type = = TK_TYPE_UVEC4 | |
p_type = = TK_TYPE_FLOAT | |
p_type = = TK_TYPE_VEC2 | |
p_type = = TK_TYPE_VEC3 | |
p_type = = TK_TYPE_VEC4 | |
p_type = = TK_TYPE_MAT2 | |
p_type = = TK_TYPE_MAT3 | |
p_type = = TK_TYPE_MAT4 ) ;
}
2014-02-10 02:10:30 +01:00
bool ShaderLanguage : : is_token_datatype ( TokenType p_type ) {
2016-10-03 21:33:42 +02:00
return (
2017-03-05 16:44:50 +01:00
p_type = = TK_TYPE_VOID | |
p_type = = TK_TYPE_BOOL | |
p_type = = TK_TYPE_BVEC2 | |
p_type = = TK_TYPE_BVEC3 | |
p_type = = TK_TYPE_BVEC4 | |
p_type = = TK_TYPE_INT | |
p_type = = TK_TYPE_IVEC2 | |
p_type = = TK_TYPE_IVEC3 | |
p_type = = TK_TYPE_IVEC4 | |
p_type = = TK_TYPE_UINT | |
p_type = = TK_TYPE_UVEC2 | |
p_type = = TK_TYPE_UVEC3 | |
p_type = = TK_TYPE_UVEC4 | |
p_type = = TK_TYPE_FLOAT | |
p_type = = TK_TYPE_VEC2 | |
p_type = = TK_TYPE_VEC3 | |
p_type = = TK_TYPE_VEC4 | |
p_type = = TK_TYPE_MAT2 | |
p_type = = TK_TYPE_MAT3 | |
p_type = = TK_TYPE_MAT4 | |
p_type = = TK_TYPE_SAMPLER2D | |
p_type = = TK_TYPE_ISAMPLER2D | |
p_type = = TK_TYPE_USAMPLER2D | |
2018-06-26 13:59:26 +02:00
p_type = = TK_TYPE_SAMPLER2DARRAY | |
p_type = = TK_TYPE_ISAMPLER2DARRAY | |
p_type = = TK_TYPE_USAMPLER2DARRAY | |
p_type = = TK_TYPE_SAMPLER3D | |
p_type = = TK_TYPE_ISAMPLER3D | |
p_type = = TK_TYPE_USAMPLER3D | |
2017-03-05 16:44:50 +01:00
p_type = = TK_TYPE_SAMPLERCUBE ) ;
2014-02-10 02:10:30 +01:00
}
ShaderLanguage : : DataType ShaderLanguage : : get_token_datatype ( TokenType p_type ) {
2017-03-05 16:44:50 +01:00
return DataType ( p_type - TK_TYPE_VOID ) ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2017-11-27 16:47:46 +01:00
bool ShaderLanguage : : is_token_interpolation ( TokenType p_type ) {
return (
p_type = = TK_INTERPOLATION_FLAT | |
p_type = = TK_INTERPOLATION_SMOOTH ) ;
}
ShaderLanguage : : DataInterpolation ShaderLanguage : : get_token_interpolation ( TokenType p_type ) {
if ( p_type = = TK_INTERPOLATION_FLAT )
return INTERPOLATION_FLAT ;
else
return INTERPOLATION_SMOOTH ;
}
2016-10-03 21:33:42 +02:00
bool ShaderLanguage : : is_token_precision ( TokenType p_type ) {
return (
2017-03-05 16:44:50 +01:00
p_type = = TK_PRECISION_LOW | |
p_type = = TK_PRECISION_MID | |
p_type = = TK_PRECISION_HIGH ) ;
2016-10-03 21:33:42 +02:00
}
ShaderLanguage : : DataPrecision ShaderLanguage : : get_token_precision ( TokenType p_type ) {
2017-03-05 16:44:50 +01:00
if ( p_type = = TK_PRECISION_LOW )
2016-10-03 21:33:42 +02:00
return PRECISION_LOWP ;
2017-03-05 16:44:50 +01:00
else if ( p_type = = TK_PRECISION_HIGH )
2016-10-03 21:33:42 +02:00
return PRECISION_HIGHP ;
else
return PRECISION_MEDIUMP ;
2014-02-10 02:10:30 +01:00
}
2019-07-15 17:47:22 +02:00
String ShaderLanguage : : get_precision_name ( DataPrecision p_type ) {
switch ( p_type ) {
case PRECISION_LOWP : return " lowp " ;
case PRECISION_MEDIUMP : return " mediump " ;
case PRECISION_HIGHP : return " highp " ;
default :
break ;
}
return " " ;
}
2014-02-10 02:10:30 +01:00
String ShaderLanguage : : get_datatype_name ( DataType p_type ) {
2017-03-05 16:44:50 +01:00
switch ( p_type ) {
2014-02-10 02:10:30 +01:00
case TYPE_VOID : return " void " ;
case TYPE_BOOL : return " bool " ;
2016-10-03 21:33:42 +02:00
case TYPE_BVEC2 : return " bvec2 " ;
case TYPE_BVEC3 : return " bvec3 " ;
case TYPE_BVEC4 : return " bvec4 " ;
case TYPE_INT : return " int " ;
case TYPE_IVEC2 : return " ivec2 " ;
case TYPE_IVEC3 : return " ivec3 " ;
case TYPE_IVEC4 : return " ivec4 " ;
case TYPE_UINT : return " uint " ;
case TYPE_UVEC2 : return " uvec2 " ;
case TYPE_UVEC3 : return " uvec3 " ;
case TYPE_UVEC4 : return " uvec4 " ;
2014-02-10 02:10:30 +01:00
case TYPE_FLOAT : return " float " ;
case TYPE_VEC2 : return " vec2 " ;
case TYPE_VEC3 : return " vec3 " ;
case TYPE_VEC4 : return " vec4 " ;
2015-03-10 04:53:09 +01:00
case TYPE_MAT2 : return " mat2 " ;
2014-02-10 02:10:30 +01:00
case TYPE_MAT3 : return " mat3 " ;
case TYPE_MAT4 : return " mat4 " ;
2016-10-03 21:33:42 +02:00
case TYPE_SAMPLER2D : return " sampler2D " ;
case TYPE_ISAMPLER2D : return " isampler2D " ;
case TYPE_USAMPLER2D : return " usampler2D " ;
2018-06-26 13:59:26 +02:00
case TYPE_SAMPLER2DARRAY : return " sampler2DArray " ;
case TYPE_ISAMPLER2DARRAY : return " isampler2DArray " ;
case TYPE_USAMPLER2DARRAY : return " usampler2DArray " ;
case TYPE_SAMPLER3D : return " sampler3D " ;
case TYPE_ISAMPLER3D : return " isampler3D " ;
case TYPE_USAMPLER3D : return " usampler3D " ;
2016-10-03 21:33:42 +02:00
case TYPE_SAMPLERCUBE : return " samplerCube " ;
2020-01-17 20:35:22 +01:00
case TYPE_STRUCT : return " struct " ;
2014-02-10 02:10:30 +01:00
}
return " " ;
}
bool ShaderLanguage : : is_token_nonvoid_datatype ( TokenType p_type ) {
2017-03-05 16:44:50 +01:00
return is_token_datatype ( p_type ) & & p_type ! = TK_TYPE_VOID ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
void ShaderLanguage : : clear ( ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
current_function = StringName ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
completion_type = COMPLETION_NONE ;
completion_block = NULL ;
completion_function = StringName ( ) ;
2020-01-19 14:35:54 +01:00
completion_class = SubClassTag : : TAG_GLOBAL ;
2020-01-17 20:35:22 +01:00
completion_struct = StringName ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
error_line = 0 ;
tk_line = 1 ;
char_idx = 0 ;
error_set = false ;
error_str = " " ;
while ( nodes ) {
2016-10-03 21:33:42 +02:00
Node * n = nodes ;
2017-03-05 16:44:50 +01:00
nodes = nodes - > next ;
2016-10-03 21:33:42 +02:00
memdelete ( n ) ;
}
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
bool ShaderLanguage : : _find_identifier ( const BlockNode * p_block , const Map < StringName , BuiltInInfo > & p_builtin_types , const StringName & p_identifier , DataType * r_data_type , IdentifierType * r_type , bool * r_is_const , int * r_array_size , StringName * r_struct_name ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( p_builtin_types . has ( p_identifier ) ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( r_data_type ) {
2017-12-15 22:23:16 +01:00
* r_data_type = p_builtin_types [ p_identifier ] . type ;
2016-10-03 21:33:42 +02:00
}
2020-02-12 21:16:47 +01:00
if ( r_is_const ) {
* r_is_const = p_builtin_types [ p_identifier ] . constant ;
}
2016-10-03 21:33:42 +02:00
if ( r_type ) {
2017-03-05 16:44:50 +01:00
* r_type = IDENTIFIER_BUILTIN_VAR ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
FunctionNode * function = NULL ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( p_block ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( p_block - > variables . has ( p_identifier ) ) {
if ( r_data_type ) {
2017-03-05 16:44:50 +01:00
* r_data_type = p_block - > variables [ p_identifier ] . type ;
2014-02-10 02:10:30 +01:00
}
2019-08-05 09:35:53 +02:00
if ( r_is_const ) {
* r_is_const = p_block - > variables [ p_identifier ] . is_const ;
}
2019-07-10 18:52:50 +02:00
if ( r_array_size ) {
* r_array_size = p_block - > variables [ p_identifier ] . array_size ;
}
2016-10-03 21:33:42 +02:00
if ( r_type ) {
2017-03-05 16:44:50 +01:00
* r_type = IDENTIFIER_LOCAL_VAR ;
2014-02-10 02:10:30 +01:00
}
2020-01-17 20:35:22 +01:00
if ( r_struct_name ) {
* r_struct_name = p_block - > variables [ p_identifier ] . struct_name ;
}
2014-02-10 02:10:30 +01:00
return true ;
}
2016-10-03 21:33:42 +02:00
if ( p_block - > parent_function ) {
2017-03-05 16:44:50 +01:00
function = p_block - > parent_function ;
2016-10-03 21:33:42 +02:00
break ;
} else {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! p_block - > parent_block , false ) ;
p_block = p_block - > parent_block ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
if ( function ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < function - > arguments . size ( ) ; i + + ) {
if ( function - > arguments [ i ] . name = = p_identifier ) {
2016-10-03 21:33:42 +02:00
if ( r_data_type ) {
2017-03-05 16:44:50 +01:00
* r_data_type = function - > arguments [ i ] . type ;
2016-10-03 21:33:42 +02:00
}
if ( r_type ) {
2017-03-05 16:44:50 +01:00
* r_type = IDENTIFIER_FUNCTION_ARGUMENT ;
2016-10-03 21:33:42 +02:00
}
2020-01-17 20:35:22 +01:00
if ( r_struct_name ) {
* r_struct_name = function - > arguments [ i ] . type_str ;
}
2016-10-03 21:33:42 +02:00
return true ;
}
}
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
if ( shader - > varyings . has ( p_identifier ) ) {
if ( r_data_type ) {
2017-03-05 16:44:50 +01:00
* r_data_type = shader - > varyings [ p_identifier ] . type ;
2016-10-03 21:33:42 +02:00
}
2019-07-29 16:08:25 +02:00
if ( r_array_size ) {
* r_array_size = shader - > varyings [ p_identifier ] . array_size ;
}
2016-10-03 21:33:42 +02:00
if ( r_type ) {
2017-03-05 16:44:50 +01:00
* r_type = IDENTIFIER_VARYING ;
2016-10-03 21:33:42 +02:00
}
return true ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( shader - > uniforms . has ( p_identifier ) ) {
if ( r_data_type ) {
2017-03-05 16:44:50 +01:00
* r_data_type = shader - > uniforms [ p_identifier ] . type ;
2016-10-03 21:33:42 +02:00
}
if ( r_type ) {
2017-03-05 16:44:50 +01:00
* r_type = IDENTIFIER_UNIFORM ;
2016-10-03 21:33:42 +02:00
}
return true ;
2014-02-10 02:10:30 +01:00
}
2019-05-30 16:19:24 +02:00
if ( shader - > constants . has ( p_identifier ) ) {
if ( r_data_type ) {
* r_data_type = shader - > constants [ p_identifier ] . type ;
}
if ( r_type ) {
* r_type = IDENTIFIER_CONSTANT ;
}
2020-01-17 20:35:22 +01:00
if ( r_struct_name ) {
* r_struct_name = shader - > constants [ p_identifier ] . type_str ;
}
2019-05-30 16:19:24 +02:00
return true ;
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < shader - > functions . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( ! shader - > functions [ i ] . callable )
continue ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( shader - > functions [ i ] . name = = p_identifier ) {
2016-10-03 21:33:42 +02:00
if ( r_data_type ) {
2017-03-05 16:44:50 +01:00
* r_data_type = shader - > functions [ i ] . function - > return_type ;
2016-10-03 21:33:42 +02:00
}
if ( r_type ) {
2017-03-05 16:44:50 +01:00
* r_type = IDENTIFIER_FUNCTION ;
2016-10-03 21:33:42 +02:00
}
2019-08-10 06:15:33 +02:00
return true ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
return false ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool ShaderLanguage : : _validate_operator ( OperatorNode * p_op , DataType * r_ret_type ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool valid = false ;
2019-07-23 09:14:31 +02:00
DataType ret_type = TYPE_VOID ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
switch ( p_op - > op ) {
2016-10-03 21:33:42 +02:00
case OP_EQUAL :
case OP_NOT_EQUAL : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2017-03-05 16:44:50 +01:00
valid = na = = nb ;
ret_type = TYPE_BOOL ;
2016-10-03 21:33:42 +02:00
} break ;
case OP_LESS :
case OP_LESS_EQUAL :
case OP_GREATER :
case OP_GREATER_EQUAL : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
valid = na = = nb & & ( na = = TYPE_UINT | | na = = TYPE_INT | | na = = TYPE_FLOAT ) ;
ret_type = TYPE_BOOL ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case OP_AND :
case OP_OR : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
valid = na = = nb & & na = = TYPE_BOOL ;
ret_type = TYPE_BOOL ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case OP_NOT : {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
2017-03-05 16:44:50 +01:00
valid = na = = TYPE_BOOL ;
ret_type = TYPE_BOOL ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case OP_INCREMENT :
case OP_DECREMENT :
case OP_POST_INCREMENT :
case OP_POST_DECREMENT :
case OP_NEGATE : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
2017-03-05 16:44:50 +01:00
valid = na > TYPE_BOOL & & na < TYPE_MAT2 ;
ret_type = na ;
2016-10-03 21:33:42 +02:00
} break ;
case OP_ADD :
case OP_SUB :
case OP_MUL :
case OP_DIV : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2017-03-05 16:44:50 +01:00
if ( na > nb ) {
2016-10-03 21:33:42 +02:00
//make things easier;
2017-03-05 16:44:50 +01:00
SWAP ( na , nb ) ;
}
if ( na = = nb ) {
2017-04-07 04:36:37 +02:00
valid = ( na > TYPE_BOOL & & na < = TYPE_MAT4 ) ;
2017-03-05 16:44:50 +01:00
ret_type = na ;
} else if ( na = = TYPE_INT & & nb = = TYPE_IVEC2 ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_INT & & nb = = TYPE_IVEC3 ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_INT & & nb = = TYPE_IVEC4 ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
} else if ( na = = TYPE_UINT & & nb = = TYPE_UVEC2 ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UINT & & nb = = TYPE_UVEC3 ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UINT & & nb = = TYPE_UVEC4 ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
} else if ( na = = TYPE_FLOAT & & nb = = TYPE_VEC2 ) {
valid = true ;
ret_type = TYPE_VEC2 ;
} else if ( na = = TYPE_FLOAT & & nb = = TYPE_VEC3 ) {
valid = true ;
ret_type = TYPE_VEC3 ;
} else if ( na = = TYPE_FLOAT & & nb = = TYPE_VEC4 ) {
valid = true ;
ret_type = TYPE_VEC4 ;
2017-04-07 04:36:37 +02:00
} else if ( p_op - > op = = OP_MUL & & na = = TYPE_FLOAT & & nb = = TYPE_MAT2 ) {
2017-03-05 16:44:50 +01:00
valid = true ;
ret_type = TYPE_MAT2 ;
2017-04-07 04:36:37 +02:00
} else if ( p_op - > op = = OP_MUL & & na = = TYPE_FLOAT & & nb = = TYPE_MAT3 ) {
2017-03-05 16:44:50 +01:00
valid = true ;
ret_type = TYPE_MAT3 ;
2017-04-07 04:36:37 +02:00
} else if ( p_op - > op = = OP_MUL & & na = = TYPE_FLOAT & & nb = = TYPE_MAT4 ) {
2017-03-05 16:44:50 +01:00
valid = true ;
ret_type = TYPE_MAT4 ;
2017-04-07 04:36:37 +02:00
} else if ( p_op - > op = = OP_MUL & & na = = TYPE_VEC2 & & nb = = TYPE_MAT2 ) {
valid = true ;
ret_type = TYPE_VEC2 ;
} else if ( p_op - > op = = OP_MUL & & na = = TYPE_VEC3 & & nb = = TYPE_MAT3 ) {
valid = true ;
ret_type = TYPE_VEC3 ;
} else if ( p_op - > op = = OP_MUL & & na = = TYPE_VEC4 & & nb = = TYPE_MAT4 ) {
valid = true ;
ret_type = TYPE_VEC4 ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
} break ;
case OP_ASSIGN_MOD :
case OP_MOD : {
/*
* The operator modulus ( % ) operates on signed or unsigned integers or integer vectors . The operand
* types must both be signed or both be unsigned . The operands cannot be vectors of differing size . If
* one operand is a scalar and the other vector , then the scalar is applied component - wise to the vector ,
* resulting in the same type as the vector . If both are vectors of the same size , the result is computed
* component - wise .
*/
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( na = = TYPE_INT & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_INT ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_IVEC2 ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_IVEC3 ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_IVEC4 ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
/////
} else if ( na = = TYPE_UINT & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UINT ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UVEC2 ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UVEC3 ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UVEC4 ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
} break ;
case OP_ASSIGN_SHIFT_LEFT :
case OP_ASSIGN_SHIFT_RIGHT :
case OP_SHIFT_LEFT :
case OP_SHIFT_RIGHT : {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( na = = TYPE_INT & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_INT ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_IVEC2 ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_IVEC3 ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_IVEC4 ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
2017-04-07 04:36:37 +02:00
} else if ( na = = TYPE_UINT & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UINT ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UVEC2 ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UVEC3 ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UVEC4 ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
2016-10-03 21:33:42 +02:00
}
} break ;
case OP_ASSIGN : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2020-01-17 20:35:22 +01:00
if ( na = = TYPE_STRUCT | | nb = = TYPE_STRUCT ) {
valid = p_op - > arguments [ 0 ] - > get_datatype_name ( ) = = p_op - > arguments [ 1 ] - > get_datatype_name ( ) ;
} else {
valid = na = = nb ;
}
2017-03-05 16:44:50 +01:00
ret_type = na ;
2016-10-03 21:33:42 +02:00
} break ;
case OP_ASSIGN_ADD :
case OP_ASSIGN_SUB :
case OP_ASSIGN_MUL :
case OP_ASSIGN_DIV : {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( na = = nb ) {
valid = ( na > TYPE_BOOL & & na < TYPE_MAT2 ) | | ( p_op - > op = = OP_ASSIGN_MUL & & na > = TYPE_MAT2 & & na < = TYPE_MAT4 ) ;
ret_type = na ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
} else if ( na = = TYPE_VEC2 & & nb = = TYPE_FLOAT ) {
valid = true ;
ret_type = TYPE_VEC2 ;
} else if ( na = = TYPE_VEC3 & & nb = = TYPE_FLOAT ) {
valid = true ;
ret_type = TYPE_VEC3 ;
} else if ( na = = TYPE_VEC4 & & nb = = TYPE_FLOAT ) {
valid = true ;
ret_type = TYPE_VEC4 ;
} else if ( p_op - > op = = OP_ASSIGN_MUL & & na = = TYPE_MAT2 & & nb = = TYPE_VEC2 ) {
valid = true ;
ret_type = TYPE_MAT2 ;
} else if ( p_op - > op = = OP_ASSIGN_MUL & & na = = TYPE_MAT3 & & nb = = TYPE_VEC3 ) {
valid = true ;
ret_type = TYPE_MAT3 ;
} else if ( p_op - > op = = OP_ASSIGN_MUL & & na = = TYPE_MAT4 & & nb = = TYPE_VEC4 ) {
valid = true ;
ret_type = TYPE_MAT4 ;
2018-11-24 18:57:11 +01:00
} else if ( p_op - > op = = OP_ASSIGN_MUL & & na = = TYPE_VEC2 & & nb = = TYPE_MAT2 ) {
valid = true ;
ret_type = TYPE_VEC2 ;
} else if ( p_op - > op = = OP_ASSIGN_MUL & & na = = TYPE_VEC3 & & nb = = TYPE_MAT3 ) {
valid = true ;
ret_type = TYPE_VEC3 ;
} else if ( p_op - > op = = OP_ASSIGN_MUL & & na = = TYPE_VEC4 & & nb = = TYPE_MAT4 ) {
valid = true ;
ret_type = TYPE_VEC4 ;
2016-10-03 21:33:42 +02:00
}
} break ;
case OP_ASSIGN_BIT_AND :
case OP_ASSIGN_BIT_OR :
case OP_ASSIGN_BIT_XOR :
case OP_BIT_AND :
case OP_BIT_OR :
case OP_BIT_XOR : {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
/*
* The bitwise operators and ( & ) , exclusive - or ( ^ ) , and inclusive - or ( | ) . The operands must be of type
* signed or unsigned integers or integer vectors . The operands cannot be vectors of differing size . If
* one operand is a scalar and the other a vector , the scalar is applied component - wise to the vector ,
* resulting in the same type as the vector . The fundamental types of the operands ( signed or unsigned )
* must match .
*/
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( na > nb & & p_op - > op > = OP_BIT_AND ) {
2016-10-03 21:33:42 +02:00
//can swap for non assign
2017-03-05 16:44:50 +01:00
SWAP ( na , nb ) ;
}
if ( na = = TYPE_INT & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_INT ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_INT ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
} else if ( na = = TYPE_IVEC2 & & nb = = TYPE_IVEC2 ) {
valid = true ;
ret_type = TYPE_IVEC2 ;
} else if ( na = = TYPE_IVEC3 & & nb = = TYPE_IVEC3 ) {
valid = true ;
ret_type = TYPE_IVEC3 ;
} else if ( na = = TYPE_IVEC4 & & nb = = TYPE_IVEC4 ) {
valid = true ;
ret_type = TYPE_IVEC4 ;
/////
} else if ( na = = TYPE_UINT & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UINT ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UINT ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
} else if ( na = = TYPE_UVEC2 & & nb = = TYPE_UVEC2 ) {
valid = true ;
ret_type = TYPE_UVEC2 ;
} else if ( na = = TYPE_UVEC3 & & nb = = TYPE_UVEC3 ) {
valid = true ;
ret_type = TYPE_UVEC3 ;
} else if ( na = = TYPE_UVEC4 & & nb = = TYPE_UVEC4 ) {
valid = true ;
ret_type = TYPE_UVEC4 ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
} break ;
case OP_BIT_INVERT : { //unaries
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
2017-03-05 16:44:50 +01:00
valid = na > = TYPE_INT & & na < TYPE_FLOAT ;
ret_type = na ;
2016-10-03 21:33:42 +02:00
} break ;
case OP_SELECT_IF : {
DataType na = p_op - > arguments [ 0 ] - > get_datatype ( ) ;
DataType nb = p_op - > arguments [ 1 ] - > get_datatype ( ) ;
DataType nc = p_op - > arguments [ 2 ] - > get_datatype ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
valid = na = = TYPE_BOOL & & ( nb = = nc ) ;
ret_type = nb ;
2016-10-03 21:33:42 +02:00
} break ;
default : {
ERR_FAIL_V ( false ) ;
2014-02-10 02:10:30 +01:00
}
}
2016-10-03 21:33:42 +02:00
if ( r_ret_type )
2017-03-05 16:44:50 +01:00
* r_ret_type = ret_type ;
2016-10-03 21:33:42 +02:00
return valid ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const ShaderLanguage : : BuiltinFuncDef ShaderLanguage : : builtin_func_defs [ ] = {
2014-02-10 02:10:30 +01:00
//constructors
2019-10-30 10:38:35 +01:00
{ " bool " , TYPE_BOOL , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec2 " , TYPE_BVEC2 , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec2 " , TYPE_BVEC2 , { TYPE_BOOL , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec3 " , TYPE_BVEC3 , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec3 " , TYPE_BVEC3 , { TYPE_BOOL , TYPE_BOOL , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec3 " , TYPE_BVEC3 , { TYPE_BVEC2 , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec3 " , TYPE_BVEC3 , { TYPE_BOOL , TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BOOL , TYPE_BOOL , TYPE_BOOL , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BOOL , TYPE_BVEC2 , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BVEC2 , TYPE_BOOL , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BOOL , TYPE_BOOL , TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BOOL , TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BVEC3 , TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BVEC2 , TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " float " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec2 " , TYPE_VEC2 , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec2 " , TYPE_VEC2 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec3 " , TYPE_VEC3 , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec3 " , TYPE_VEC3 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec3 " , TYPE_VEC3 , { TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec3 " , TYPE_VEC3 , { TYPE_FLOAT , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_VEC2 , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " int " , TYPE_INT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec2 " , TYPE_IVEC2 , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec2 " , TYPE_IVEC2 , { TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec3 " , TYPE_IVEC3 , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec3 " , TYPE_IVEC3 , { TYPE_INT , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec3 " , TYPE_IVEC3 , { TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec3 " , TYPE_IVEC3 , { TYPE_INT , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_INT , TYPE_INT , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_INT , TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_IVEC2 , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_INT , TYPE_INT , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_INT , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " uint " , TYPE_UINT , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec2 " , TYPE_UVEC2 , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec2 " , TYPE_UVEC2 , { TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_UINT , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_UVEC2 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_UINT , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UINT , TYPE_UINT , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UINT , TYPE_UVEC2 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UVEC2 , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UINT , TYPE_UINT , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UINT , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UVEC3 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " mat2 " , TYPE_MAT2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat3 " , TYPE_MAT3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat4 " , TYPE_MAT4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat2 " , TYPE_MAT2 , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat3 " , TYPE_MAT3 , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat4 " , TYPE_MAT4 , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
//conversion scalars
2019-10-30 10:38:35 +01:00
{ " int " , TYPE_INT , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " int " , TYPE_INT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " int " , TYPE_INT , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " int " , TYPE_INT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2019-10-30 10:38:35 +01:00
{ " float " , TYPE_FLOAT , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " float " , TYPE_FLOAT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " float " , TYPE_FLOAT , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " float " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2020-01-20 13:34:25 +01:00
{ " uint " , TYPE_UINT , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uint " , TYPE_UINT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uint " , TYPE_UINT , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uint " , TYPE_UINT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2016-10-03 21:33:42 +02:00
2019-10-30 10:38:35 +01:00
{ " bool " , TYPE_BOOL , { TYPE_BOOL , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bool " , TYPE_BOOL , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " bool " , TYPE_BOOL , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bool " , TYPE_BOOL , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
//conversion vectors
2019-10-30 10:38:35 +01:00
{ " ivec2 " , TYPE_IVEC2 , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec2 " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec2 " , TYPE_IVEC2 , { TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec2 " , TYPE_IVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec2 " , TYPE_VEC2 , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec2 " , TYPE_VEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " vec2 " , TYPE_VEC2 , { TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " vec2 " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " uvec2 " , TYPE_UVEC2 , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec2 " , TYPE_UVEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec2 " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec2 " , TYPE_UVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bvec2 " , TYPE_BVEC2 , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec2 " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " bvec2 " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bvec2 " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec3 " , TYPE_IVEC3 , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec3 " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " ivec3 " , TYPE_IVEC3 , { TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " ivec3 " , TYPE_IVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec3 " , TYPE_VEC3 , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec3 " , TYPE_VEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " vec3 " , TYPE_VEC3 , { TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " vec3 " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " uvec3 " , TYPE_UVEC3 , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec3 " , TYPE_UVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bvec3 " , TYPE_BVEC3 , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec3 " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " bvec3 " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bvec3 " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ivec4 " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " ivec4 " , TYPE_IVEC4 , { TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " ivec4 " , TYPE_IVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " vec4 " , TYPE_VEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " vec4 " , TYPE_VEC4 , { TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " vec4 " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " uvec4 " , TYPE_UVEC4 , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uvec4 " , TYPE_UVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bvec4 " , TYPE_BVEC4 , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " bvec4 " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " bvec4 " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " bvec4 " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2018-07-25 17:14:52 +02:00
//conversion between matrixes
2019-10-30 10:38:35 +01:00
{ " mat2 " , TYPE_MAT2 , { TYPE_MAT3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat2 " , TYPE_MAT2 , { TYPE_MAT4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat3 " , TYPE_MAT3 , { TYPE_MAT2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat3 " , TYPE_MAT3 , { TYPE_MAT4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat4 " , TYPE_MAT4 , { TYPE_MAT2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mat4 " , TYPE_MAT4 , { TYPE_MAT3 , TYPE_VOID } , TAG_GLOBAL , false } ,
2018-07-25 17:14:52 +02:00
2016-10-07 16:31:18 +02:00
//builtins - trigonometry
2018-02-18 16:08:18 +01:00
2019-10-30 10:38:35 +01:00
{ " radians " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " radians " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " radians " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " radians " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " degrees " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " degrees " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " degrees " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " degrees " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sin " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sin " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sin " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sin " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cos " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cos " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cos " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cos " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tan " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tan " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tan " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tan " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asin " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asin " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asin " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asin " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acos " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acos " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acos " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acos " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atan " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sinh " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sinh " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sinh " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sinh " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cosh " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cosh " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cosh " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cosh " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tanh " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tanh " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tanh " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " tanh " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asinh " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asinh " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asinh " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " asinh " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acosh " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acosh " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acosh " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " acosh " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atanh " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atanh " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atanh " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " atanh " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2018-02-18 16:08:18 +01:00
2016-10-07 16:31:18 +02:00
//builtins - exponential
2019-10-30 10:38:35 +01:00
{ " pow " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " pow " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " pow " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " pow " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp2 " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp2 " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp2 " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " exp2 " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log2 " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log2 " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log2 " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " log2 " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sqrt " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sqrt " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sqrt " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sqrt " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inversesqrt " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inversesqrt " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inversesqrt " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inversesqrt " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-07 16:31:18 +02:00
//builtins - common
2019-10-30 10:38:35 +01:00
{ " abs " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_INT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " abs " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_INT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " sign " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " floor " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " floor " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " floor " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " floor " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " trunc " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " trunc " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " trunc " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " trunc " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " round " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " round " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " round " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " round " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " roundEven " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " roundEven " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " roundEven " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " roundEven " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ceil " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ceil " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ceil " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " ceil " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " fract " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " fract " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " fract " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " fract " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mod " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " modf " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " modf " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " modf " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " modf " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_INT , { TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " min " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " min " , TYPE_UINT , { TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " min " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " max " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_INT , { TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " max " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " max " , TYPE_UINT , { TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " max " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " max " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " max " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " max " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " max " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " max " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " clamp " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_INT , { TYPE_INT , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_IVEC2 , { TYPE_IVEC2 , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_IVEC3 , { TYPE_IVEC3 , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " clamp " , TYPE_IVEC4 , { TYPE_IVEC4 , TYPE_INT , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " clamp " , TYPE_UINT , { TYPE_UINT , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " clamp " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " clamp " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " clamp " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " clamp " , TYPE_UVEC2 , { TYPE_UVEC2 , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " clamp " , TYPE_UVEC3 , { TYPE_UVEC3 , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " clamp " , TYPE_UVEC4 , { TYPE_UVEC4 , TYPE_UINT , TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " mix " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " mix " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_VEC2 , { TYPE_FLOAT , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_VEC3 , { TYPE_FLOAT , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " step " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_FLOAT , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_VEC2 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_VEC3 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " smoothstep " , TYPE_VEC4 , { TYPE_FLOAT , TYPE_FLOAT , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isnan " , TYPE_BOOL , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isnan " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isnan " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isnan " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isinf " , TYPE_BOOL , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isinf " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isinf " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " isinf " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " floatBitsToInt " , TYPE_INT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToInt " , TYPE_IVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToInt " , TYPE_IVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToInt " , TYPE_IVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToUint " , TYPE_UINT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToUint " , TYPE_UVEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToUint " , TYPE_UVEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " floatBitsToUint " , TYPE_UVEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " intBitsToFloat " , TYPE_FLOAT , { TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " intBitsToFloat " , TYPE_VEC2 , { TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " intBitsToFloat " , TYPE_VEC3 , { TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " intBitsToFloat " , TYPE_VEC4 , { TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uintBitsToFloat " , TYPE_FLOAT , { TYPE_UINT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uintBitsToFloat " , TYPE_VEC2 , { TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uintBitsToFloat " , TYPE_VEC3 , { TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " uintBitsToFloat " , TYPE_VEC4 , { TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2016-10-03 21:33:42 +02:00
2016-10-07 16:31:18 +02:00
//builtins - geometric
2019-10-30 10:38:35 +01:00
{ " length " , TYPE_FLOAT , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " length " , TYPE_FLOAT , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " length " , TYPE_FLOAT , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " distance " , TYPE_FLOAT , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " distance " , TYPE_FLOAT , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " distance " , TYPE_FLOAT , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " dot " , TYPE_FLOAT , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " dot " , TYPE_FLOAT , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " dot " , TYPE_FLOAT , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " cross " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " normalize " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " normalize " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " normalize " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " reflect " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " refract " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " faceforward " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " faceforward " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " faceforward " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " matrixCompMult " , TYPE_MAT2 , { TYPE_MAT2 , TYPE_MAT2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " matrixCompMult " , TYPE_MAT3 , { TYPE_MAT3 , TYPE_MAT3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " matrixCompMult " , TYPE_MAT4 , { TYPE_MAT4 , TYPE_MAT4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " outerProduct " , TYPE_MAT2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " outerProduct " , TYPE_MAT3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " outerProduct " , TYPE_MAT4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " transpose " , TYPE_MAT2 , { TYPE_MAT2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " transpose " , TYPE_MAT3 , { TYPE_MAT3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " transpose " , TYPE_MAT4 , { TYPE_MAT4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " determinant " , TYPE_FLOAT , { TYPE_MAT2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " determinant " , TYPE_FLOAT , { TYPE_MAT3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " determinant " , TYPE_FLOAT , { TYPE_MAT4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inverse " , TYPE_MAT2 , { TYPE_MAT2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inverse " , TYPE_MAT3 , { TYPE_MAT3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " inverse " , TYPE_MAT4 , { TYPE_MAT4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThan " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThan " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThan " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThan " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThan " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThan " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " lessThan " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " lessThan " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " lessThan " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " greaterThan " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThan " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThan " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThan " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThan " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThan " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " greaterThan " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " greaterThan " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " greaterThan " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " lessThanEqual " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThanEqual " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThanEqual " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThanEqual " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThanEqual " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " lessThanEqual " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " lessThanEqual " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " lessThanEqual " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " lessThanEqual " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " greaterThanEqual " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThanEqual " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThanEqual " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThanEqual " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThanEqual " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " greaterThanEqual " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " greaterThanEqual " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " greaterThanEqual " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " greaterThanEqual " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " equal " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2020-01-20 13:34:25 +01:00
{ " equal " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " equal " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " equal " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " equal " , TYPE_BVEC2 , { TYPE_BVEC2 , TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC3 , { TYPE_BVEC3 , TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " equal " , TYPE_BVEC4 , { TYPE_BVEC4 , TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC2 , { TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC3 , { TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC4 , { TYPE_VEC4 , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC2 , { TYPE_IVEC2 , TYPE_IVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC3 , { TYPE_IVEC3 , TYPE_IVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC4 , { TYPE_IVEC4 , TYPE_IVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2020-01-20 13:34:25 +01:00
{ " notEqual " , TYPE_BVEC2 , { TYPE_UVEC2 , TYPE_UVEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " notEqual " , TYPE_BVEC3 , { TYPE_UVEC3 , TYPE_UVEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " notEqual " , TYPE_BVEC4 , { TYPE_UVEC4 , TYPE_UVEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2016-10-03 21:33:42 +02:00
2019-10-30 10:38:35 +01:00
{ " notEqual " , TYPE_BVEC2 , { TYPE_BVEC2 , TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC3 , { TYPE_BVEC3 , TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " notEqual " , TYPE_BVEC4 , { TYPE_BVEC4 , TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2019-10-30 10:38:35 +01:00
{ " any " , TYPE_BOOL , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " any " , TYPE_BOOL , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " any " , TYPE_BOOL , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2019-10-30 10:38:35 +01:00
{ " all " , TYPE_BOOL , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " all " , TYPE_BOOL , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " all " , TYPE_BOOL , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2019-10-30 10:38:35 +01:00
{ " not " , TYPE_BVEC2 , { TYPE_BVEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " not " , TYPE_BVEC3 , { TYPE_BVEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " not " , TYPE_BVEC4 , { TYPE_BVEC4 , TYPE_VOID } , TAG_GLOBAL , false } ,
2016-10-03 21:33:42 +02:00
2016-10-07 16:31:18 +02:00
//builtins - texture
2019-10-30 10:38:35 +01:00
{ " textureSize " , TYPE_IVEC2 , { TYPE_SAMPLER2D , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC2 , { TYPE_ISAMPLER2D , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC2 , { TYPE_USAMPLER2D , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC3 , { TYPE_SAMPLER2DARRAY , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC3 , { TYPE_ISAMPLER2DARRAY , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC3 , { TYPE_USAMPLER2DARRAY , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC3 , { TYPE_SAMPLER3D , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC3 , { TYPE_ISAMPLER3D , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC3 , { TYPE_USAMPLER3D , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureSize " , TYPE_IVEC2 , { TYPE_SAMPLERCUBE , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2019-11-03 11:28:29 +01:00
{ " texture " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2020-01-15 08:53:13 +01:00
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLER2DARRAY , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLER2DARRAY , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2019-11-03 11:28:29 +01:00
{ " texture " , TYPE_UVEC4 , { TYPE_USAMPLER2DARRAY , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_UVEC4 , { TYPE_USAMPLER2DARRAY , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_IVEC4 , { TYPE_ISAMPLER2DARRAY , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_IVEC4 , { TYPE_ISAMPLER2DARRAY , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2020-01-15 08:53:13 +01:00
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2019-11-03 11:28:29 +01:00
{ " texture " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texture " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLERCUBE , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " texture " , TYPE_VEC4 , { TYPE_SAMPLERCUBE , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " textureProj " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProj " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureLod " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2019-11-03 11:28:29 +01:00
{ " textureLod " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureLod " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC2 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2020-01-15 08:53:13 +01:00
{ " textureLod " , TYPE_VEC4 , { TYPE_SAMPLER2DARRAY , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2019-11-03 11:28:29 +01:00
{ " textureLod " , TYPE_IVEC4 , { TYPE_ISAMPLER2DARRAY , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureLod " , TYPE_UVEC4 , { TYPE_USAMPLER2DARRAY , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2020-01-15 08:53:13 +01:00
{ " textureLod " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
2019-11-03 11:28:29 +01:00
{ " textureLod " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureLod " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-10-30 10:38:35 +01:00
{ " textureLod " , TYPE_VEC4 , { TYPE_SAMPLERCUBE , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , false } ,
{ " texelFetch " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_IVEC2 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_VEC4 , { TYPE_SAMPLER2DARRAY , TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_IVEC4 , { TYPE_ISAMPLER2DARRAY , TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_UVEC4 , { TYPE_USAMPLER2DARRAY , TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " texelFetch " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_IVEC3 , TYPE_INT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC3 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureProjLod " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC4 , TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_VEC4 , { TYPE_SAMPLER2D , TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_IVEC4 , { TYPE_ISAMPLER2D , TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_UVEC4 , { TYPE_USAMPLER2D , TYPE_VEC2 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_VEC4 , { TYPE_SAMPLER2DARRAY , TYPE_VEC3 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_IVEC4 , { TYPE_ISAMPLER2DARRAY , TYPE_VEC3 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_UVEC4 , { TYPE_USAMPLER2DARRAY , TYPE_VEC3 , TYPE_VEC2 , TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_VEC4 , { TYPE_SAMPLER3D , TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_IVEC4 , { TYPE_ISAMPLER3D , TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_UVEC4 , { TYPE_USAMPLER3D , TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " textureGrad " , TYPE_VEC4 , { TYPE_SAMPLERCUBE , TYPE_VEC3 , TYPE_VEC3 , TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdx " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdx " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdx " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdx " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdy " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdy " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdy " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " dFdy " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " fwidth " , TYPE_FLOAT , { TYPE_FLOAT , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " fwidth " , TYPE_VEC2 , { TYPE_VEC2 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " fwidth " , TYPE_VEC3 , { TYPE_VEC3 , TYPE_VOID } , TAG_GLOBAL , true } ,
{ " fwidth " , TYPE_VEC4 , { TYPE_VEC4 , TYPE_VOID } , TAG_GLOBAL , true } ,
2019-07-10 18:52:50 +02:00
//sub-functions
2017-03-05 16:44:50 +01:00
2019-07-10 18:52:50 +02:00
//array
2020-01-16 09:46:11 +01:00
{ " length " , TYPE_INT , { TYPE_VOID } , TAG_ARRAY , true } ,
2017-03-05 16:44:50 +01:00
2019-10-30 10:38:35 +01:00
{ NULL , TYPE_VOID , { TYPE_VOID } , TAG_GLOBAL , false }
2016-10-03 21:33:42 +02:00
} ;
2018-11-14 22:55:38 +01:00
const ShaderLanguage : : BuiltinFuncOutArgs ShaderLanguage : : builtin_func_out_args [ ] = {
//constructors
{ " modf " , 1 } ,
{ NULL , 0 }
} ;
2020-01-17 20:35:22 +01:00
bool ShaderLanguage : : _validate_function_call ( BlockNode * p_block , OperatorNode * p_func , DataType * r_ret_type , StringName * r_ret_type_str ) {
2016-10-03 21:33:42 +02:00
2019-07-12 05:06:58 +02:00
ERR_FAIL_COND_V ( p_func - > op ! = OP_CALL & & p_func - > op ! = OP_CONSTRUCT , false ) ;
2014-02-10 02:10:30 +01:00
Vector < DataType > args ;
2020-01-17 20:35:22 +01:00
Vector < StringName > args2 ;
2014-02-10 02:10:30 +01:00
2019-07-12 05:06:58 +02:00
ERR_FAIL_COND_V ( p_func - > arguments [ 0 ] - > type ! = Node : : TYPE_VARIABLE , false ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
StringName name = static_cast < VariableNode * > ( p_func - > arguments [ 0 ] ) - > name . operator String ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 1 ; i < p_func - > arguments . size ( ) ; i + + ) {
2016-10-03 21:33:42 +02:00
args . push_back ( p_func - > arguments [ i ] - > get_datatype ( ) ) ;
2020-01-17 20:35:22 +01:00
args2 . push_back ( p_func - > arguments [ i ] - > get_datatype_name ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int argcount = args . size ( ) ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
bool failed_builtin = false ;
2019-10-30 10:38:35 +01:00
bool unsupported_builtin = false ;
2019-11-03 11:28:29 +01:00
int builtin_idx = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( argcount < = 4 ) {
2016-10-07 16:31:18 +02:00
// test builtins
2017-03-05 16:44:50 +01:00
int idx = 0 ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
while ( builtin_func_defs [ idx ] . name ) {
2014-02-10 02:10:30 +01:00
2019-07-10 18:52:50 +02:00
if ( completion_class ! = builtin_func_defs [ idx ] . tag ) {
idx + + ;
continue ;
}
2017-03-05 16:44:50 +01:00
if ( name = = builtin_func_defs [ idx ] . name ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
failed_builtin = true ;
bool fail = false ;
for ( int i = 0 ; i < argcount ; i + + ) {
2014-02-10 02:10:30 +01:00
2019-02-27 03:20:39 +01:00
if ( get_scalar_type ( args [ i ] ) = = args [ i ] & & p_func - > arguments [ i + 1 ] - > type = = Node : : TYPE_CONSTANT & & convert_constant ( static_cast < ConstantNode * > ( p_func - > arguments [ i + 1 ] ) , builtin_func_defs [ idx ] . args [ i ] ) ) {
//all good, but needs implicit conversion later
} else if ( args [ i ] ! = builtin_func_defs [ idx ] . args [ i ] ) {
2017-03-05 16:44:50 +01:00
fail = true ;
2014-02-10 02:10:30 +01:00
break ;
}
}
2019-10-30 10:38:35 +01:00
if ( ! fail ) {
if ( VisualServer : : get_singleton ( ) - > is_low_end ( ) ) {
if ( builtin_func_defs [ idx ] . high_end ) {
fail = true ;
unsupported_builtin = true ;
2019-11-03 11:28:29 +01:00
builtin_idx = idx ;
2019-10-30 10:38:35 +01:00
}
}
}
2017-03-05 16:44:50 +01:00
if ( ! fail & & argcount < 4 & & builtin_func_defs [ idx ] . args [ argcount ] ! = TYPE_VOID )
fail = true ; //make sure the number of arguments matches
2014-02-10 02:10:30 +01:00
if ( ! fail ) {
2018-11-14 22:55:38 +01:00
//make sure its not an out argument used in the wrong way
int outarg_idx = 0 ;
while ( builtin_func_out_args [ outarg_idx ] . name ) {
if ( String ( name ) = = builtin_func_out_args [ outarg_idx ] . name ) {
int arg_idx = builtin_func_out_args [ outarg_idx ] . argument ;
if ( arg_idx < argcount ) {
if ( p_func - > arguments [ arg_idx + 1 ] - > type ! = Node : : TYPE_VARIABLE ) {
_set_error ( " Argument " + itos ( arg_idx + 1 ) + " of function ' " + String ( name ) + " ' is not a variable " ) ;
return false ;
}
StringName var_name = static_cast < const VariableNode * > ( p_func - > arguments [ arg_idx + 1 ] ) - > name ;
const BlockNode * b = p_block ;
bool valid = false ;
while ( b ) {
if ( b - > variables . has ( var_name ) ) {
valid = true ;
break ;
}
b = b - > parent_block ;
}
if ( ! valid ) {
_set_error ( " Argument " + itos ( arg_idx + 1 ) + " of function ' " + String ( name ) + " ' can only take a local variable " ) ;
return false ;
}
}
}
outarg_idx + + ;
}
2019-02-27 03:20:39 +01:00
//implicitly convert values if possible
for ( int i = 0 ; i < argcount ; i + + ) {
if ( get_scalar_type ( args [ i ] ) ! = args [ i ] | | args [ i ] = = builtin_func_defs [ idx ] . args [ i ] | | p_func - > arguments [ i + 1 ] - > type ! = Node : : TYPE_CONSTANT ) {
//can't do implicit conversion here
continue ;
}
//this is an implicit conversion
ConstantNode * constant = static_cast < ConstantNode * > ( p_func - > arguments [ i + 1 ] ) ;
ConstantNode * conversion = alloc_node < ConstantNode > ( ) ;
conversion - > datatype = builtin_func_defs [ idx ] . args [ i ] ;
conversion - > values . resize ( 1 ) ;
convert_constant ( constant , builtin_func_defs [ idx ] . args [ i ] , conversion - > values . ptrw ( ) ) ;
p_func - > arguments . write [ i + 1 ] = conversion ;
}
2018-11-14 22:55:38 +01:00
2016-10-03 21:33:42 +02:00
if ( r_ret_type )
2017-03-05 16:44:50 +01:00
* r_ret_type = builtin_func_defs [ idx ] . rettype ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
}
idx + + ;
}
}
2019-10-30 10:38:35 +01:00
if ( unsupported_builtin ) {
2019-11-03 11:28:29 +01:00
String arglist = " " ;
for ( int i = 0 ; i < argcount ; i + + ) {
if ( i > 0 ) {
arglist + = " , " ;
}
arglist + = get_datatype_name ( builtin_func_defs [ builtin_idx ] . args [ i ] ) ;
}
String err = " Built-in function \" " + String ( name ) + " ( " + arglist + " ) \" is supported only on high-end platform! " ;
2019-10-30 10:38:35 +01:00
_set_error ( err ) ;
return false ;
}
2016-10-07 16:31:18 +02:00
if ( failed_builtin ) {
2017-03-05 16:44:50 +01:00
String err = " Invalid arguments for built-in function: " + String ( name ) + " ( " ;
for ( int i = 0 ; i < argcount ; i + + ) {
if ( i > 0 )
err + = " , " ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
if ( p_func - > arguments [ i + 1 ] - > type = = Node : : TYPE_CONSTANT & & p_func - > arguments [ i + 1 ] - > get_datatype ( ) = = TYPE_INT & & static_cast < ConstantNode * > ( p_func - > arguments [ i + 1 ] ) - > values [ 0 ] . sint < 0 ) {
err + = " - " ;
2016-10-07 16:31:18 +02:00
}
2017-03-05 16:44:50 +01:00
err + = get_datatype_name ( args [ i ] ) ;
2016-10-07 16:31:18 +02:00
}
2017-03-05 16:44:50 +01:00
err + = " ) " ;
2016-10-07 16:31:18 +02:00
_set_error ( err ) ;
return false ;
}
2014-02-10 02:10:30 +01:00
// try existing functions..
2016-10-03 21:33:42 +02:00
StringName exclude_function ;
BlockNode * block = p_block ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( block ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( block - > parent_function ) {
2017-03-05 16:44:50 +01:00
exclude_function = block - > parent_function - > name ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
block = block - > parent_block ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( name = = exclude_function ) {
2016-10-07 16:31:18 +02:00
_set_error ( " Recursion is not allowed " ) ;
return false ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < shader - > functions . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
if ( name ! = shader - > functions [ i ] . name )
2014-02-10 02:10:30 +01:00
continue ;
2016-10-03 21:33:42 +02:00
if ( ! shader - > functions [ i ] . callable ) {
2017-03-05 16:44:50 +01:00
_set_error ( " Function ' " + String ( name ) + " can't be called from source code. " ) ;
2016-10-03 21:33:42 +02:00
return false ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
FunctionNode * pfunc = shader - > functions [ i ] . function ;
2017-03-05 16:44:50 +01:00
if ( pfunc - > arguments . size ( ) ! = args . size ( ) )
2014-02-10 02:10:30 +01:00
continue ;
2017-03-05 16:44:50 +01:00
bool fail = false ;
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
for ( int j = 0 ; j < args . size ( ) ; j + + ) {
2020-01-17 20:35:22 +01:00
if ( args [ j ] = = TYPE_STRUCT & & args2 [ j ] ! = pfunc - > arguments [ j ] . type_str ) {
fail = true ;
break ;
}
2019-02-27 03:20:39 +01:00
if ( get_scalar_type ( args [ j ] ) = = args [ j ] & & p_func - > arguments [ j + 1 ] - > type = = Node : : TYPE_CONSTANT & & convert_constant ( static_cast < ConstantNode * > ( p_func - > arguments [ j + 1 ] ) , pfunc - > arguments [ j ] . type ) ) {
//all good, but it needs implicit conversion later
} else if ( args [ j ] ! = pfunc - > arguments [ j ] . type ) {
2017-03-05 16:44:50 +01:00
fail = true ;
2014-02-10 02:10:30 +01:00
break ;
}
}
2016-10-03 21:33:42 +02:00
if ( ! fail ) {
2019-02-27 03:20:39 +01:00
//implicitly convert values if possible
for ( int k = 0 ; k < args . size ( ) ; k + + ) {
if ( get_scalar_type ( args [ k ] ) ! = args [ k ] | | args [ k ] = = pfunc - > arguments [ k ] . type | | p_func - > arguments [ k + 1 ] - > type ! = Node : : TYPE_CONSTANT ) {
//can't do implicit conversion here
continue ;
}
//this is an implicit conversion
ConstantNode * constant = static_cast < ConstantNode * > ( p_func - > arguments [ k + 1 ] ) ;
ConstantNode * conversion = alloc_node < ConstantNode > ( ) ;
conversion - > datatype = pfunc - > arguments [ k ] . type ;
conversion - > values . resize ( 1 ) ;
convert_constant ( constant , pfunc - > arguments [ k ] . type , conversion - > values . ptrw ( ) ) ;
p_func - > arguments . write [ k + 1 ] = conversion ;
}
2020-01-17 20:35:22 +01:00
if ( r_ret_type ) {
2017-08-20 21:15:08 +02:00
* r_ret_type = pfunc - > return_type ;
2020-01-17 20:35:22 +01:00
if ( pfunc - > return_type = = TYPE_STRUCT ) {
* r_ret_type_str = pfunc - > return_struct_name ;
}
}
2016-10-03 21:33:42 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
}
2016-10-03 21:33:42 +02:00
return false ;
2014-02-10 02:10:30 +01:00
}
2020-01-17 20:35:22 +01:00
bool ShaderLanguage : : _compare_datatypes_in_nodes ( Node * a , Node * b ) const {
if ( a - > get_datatype ( ) ! = b - > get_datatype ( ) ) {
return false ;
}
if ( a - > get_datatype ( ) = = TYPE_STRUCT | | b - > get_datatype ( ) = = TYPE_STRUCT ) {
if ( a - > get_datatype_name ( ) ! = b - > get_datatype_name ( ) ) {
return false ;
}
}
return true ;
}
2017-12-15 22:23:16 +01:00
bool ShaderLanguage : : _parse_function_arguments ( BlockNode * p_block , const Map < StringName , BuiltInInfo > & p_builtin_types , OperatorNode * p_func , int * r_complete_arg ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
TkPos pos = _get_tkpos ( ) ;
2016-10-03 21:33:42 +02:00
Token tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
2016-10-07 16:31:18 +02:00
return true ;
}
2014-02-10 02:10:30 +01:00
2017-01-14 18:03:38 +01:00
_set_tkpos ( pos ) ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2016-10-07 16:31:18 +02:00
if ( r_complete_arg ) {
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_CURSOR ) {
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
* r_complete_arg = p_func - > arguments . size ( ) - 1 ;
2016-10-07 16:31:18 +02:00
} else {
_set_tkpos ( pos ) ;
}
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Node * arg = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2016-10-07 16:31:18 +02:00
if ( ! arg ) {
2016-10-03 21:33:42 +02:00
return false ;
2016-10-07 16:31:18 +02:00
}
2016-10-03 21:33:42 +02:00
p_func - > arguments . push_back ( arg ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
2016-10-07 16:31:18 +02:00
return true ;
2017-03-05 16:44:50 +01:00
} else if ( tk . type ! = TK_COMMA ) {
2016-10-03 21:33:42 +02:00
// something is broken
_set_error ( " Expected ',' or ')' after argument " ) ;
return false ;
2014-02-10 02:10:30 +01:00
}
}
2016-10-03 21:33:42 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
bool ShaderLanguage : : is_token_operator ( TokenType p_type ) {
2017-03-05 16:44:50 +01:00
return ( p_type = = TK_OP_EQUAL | |
p_type = = TK_OP_NOT_EQUAL | |
p_type = = TK_OP_LESS | |
p_type = = TK_OP_LESS_EQUAL | |
p_type = = TK_OP_GREATER | |
p_type = = TK_OP_GREATER_EQUAL | |
p_type = = TK_OP_AND | |
p_type = = TK_OP_OR | |
p_type = = TK_OP_NOT | |
p_type = = TK_OP_ADD | |
p_type = = TK_OP_SUB | |
p_type = = TK_OP_MUL | |
p_type = = TK_OP_DIV | |
p_type = = TK_OP_MOD | |
p_type = = TK_OP_SHIFT_LEFT | |
p_type = = TK_OP_SHIFT_RIGHT | |
p_type = = TK_OP_ASSIGN | |
p_type = = TK_OP_ASSIGN_ADD | |
p_type = = TK_OP_ASSIGN_SUB | |
p_type = = TK_OP_ASSIGN_MUL | |
p_type = = TK_OP_ASSIGN_DIV | |
p_type = = TK_OP_ASSIGN_MOD | |
p_type = = TK_OP_ASSIGN_SHIFT_LEFT | |
p_type = = TK_OP_ASSIGN_SHIFT_RIGHT | |
p_type = = TK_OP_ASSIGN_BIT_AND | |
p_type = = TK_OP_ASSIGN_BIT_OR | |
p_type = = TK_OP_ASSIGN_BIT_XOR | |
p_type = = TK_OP_BIT_AND | |
p_type = = TK_OP_BIT_OR | |
p_type = = TK_OP_BIT_XOR | |
p_type = = TK_OP_BIT_INVERT | |
p_type = = TK_OP_INCREMENT | |
p_type = = TK_OP_DECREMENT | |
p_type = = TK_QUESTION | |
p_type = = TK_COLON ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
bool ShaderLanguage : : convert_constant ( ConstantNode * p_constant , DataType p_to_type , ConstantNode : : Value * p_value ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_constant - > datatype = = p_to_type ) {
2016-10-07 16:31:18 +02:00
if ( p_value ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_constant - > values . size ( ) ; i + + ) {
p_value [ i ] = p_constant - > values [ i ] ;
2014-02-10 02:10:30 +01:00
}
}
2016-10-07 16:31:18 +02:00
return true ;
2017-03-05 16:44:50 +01:00
} else if ( p_constant - > datatype = = TYPE_INT & & p_to_type = = TYPE_FLOAT ) {
2016-10-07 16:31:18 +02:00
if ( p_value ) {
2017-03-05 16:44:50 +01:00
p_value - > real = p_constant - > values [ 0 ] . sint ;
2016-10-07 16:31:18 +02:00
}
return true ;
2017-03-05 16:44:50 +01:00
} else if ( p_constant - > datatype = = TYPE_UINT & & p_to_type = = TYPE_FLOAT ) {
2016-10-07 16:31:18 +02:00
if ( p_value ) {
2017-03-05 16:44:50 +01:00
p_value - > real = p_constant - > values [ 0 ] . uint ;
2016-10-07 16:31:18 +02:00
}
return true ;
2017-03-05 16:44:50 +01:00
} else if ( p_constant - > datatype = = TYPE_INT & & p_to_type = = TYPE_UINT ) {
if ( p_constant - > values [ 0 ] . sint < 0 ) {
2016-10-07 16:31:18 +02:00
return false ;
}
if ( p_value ) {
2017-03-05 16:44:50 +01:00
p_value - > uint = p_constant - > values [ 0 ] . sint ;
2016-10-07 16:31:18 +02:00
}
return true ;
2017-03-05 16:44:50 +01:00
} else if ( p_constant - > datatype = = TYPE_UINT & & p_to_type = = TYPE_INT ) {
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
if ( p_constant - > values [ 0 ] . uint > 0x7FFFFFFF ) {
2016-10-07 16:31:18 +02:00
return false ;
}
if ( p_value ) {
2017-03-05 16:44:50 +01:00
p_value - > sint = p_constant - > values [ 0 ] . uint ;
2016-10-07 16:31:18 +02:00
}
return true ;
} else
return false ;
}
bool ShaderLanguage : : is_scalar_type ( DataType p_type ) {
2017-03-05 16:44:50 +01:00
return p_type = = TYPE_BOOL | | p_type = = TYPE_INT | | p_type = = TYPE_UINT | | p_type = = TYPE_FLOAT ;
2016-10-07 16:31:18 +02:00
}
2016-10-10 23:31:01 +02:00
bool ShaderLanguage : : is_sampler_type ( DataType p_type ) {
2018-06-26 13:59:26 +02:00
return p_type = = TYPE_SAMPLER2D | |
p_type = = TYPE_ISAMPLER2D | |
p_type = = TYPE_USAMPLER2D | |
p_type = = TYPE_SAMPLER2DARRAY | |
p_type = = TYPE_ISAMPLER2DARRAY | |
p_type = = TYPE_USAMPLER2DARRAY | |
p_type = = TYPE_SAMPLER3D | |
p_type = = TYPE_ISAMPLER3D | |
p_type = = TYPE_USAMPLER3D | |
p_type = = TYPE_SAMPLERCUBE ;
2016-10-10 23:31:01 +02:00
}
2018-11-16 12:20:23 +01:00
Variant ShaderLanguage : : constant_value_to_variant ( const Vector < ShaderLanguage : : ConstantNode : : Value > & p_value , DataType p_type , ShaderLanguage : : ShaderNode : : Uniform : : Hint p_hint ) {
2018-09-05 00:54:35 +02:00
if ( p_value . size ( ) > 0 ) {
Variant value ;
switch ( p_type ) {
case ShaderLanguage : : TYPE_BOOL :
value = Variant ( p_value [ 0 ] . boolean ) ;
break ;
case ShaderLanguage : : TYPE_BVEC2 :
case ShaderLanguage : : TYPE_BVEC3 :
case ShaderLanguage : : TYPE_BVEC4 :
case ShaderLanguage : : TYPE_INT :
value = Variant ( p_value [ 0 ] . sint ) ;
break ;
case ShaderLanguage : : TYPE_IVEC2 :
value = Variant ( Vector2 ( p_value [ 0 ] . sint , p_value [ 1 ] . sint ) ) ;
break ;
case ShaderLanguage : : TYPE_IVEC3 :
value = Variant ( Vector3 ( p_value [ 0 ] . sint , p_value [ 1 ] . sint , p_value [ 2 ] . sint ) ) ;
break ;
case ShaderLanguage : : TYPE_IVEC4 :
value = Variant ( Plane ( p_value [ 0 ] . sint , p_value [ 1 ] . sint , p_value [ 2 ] . sint , p_value [ 3 ] . sint ) ) ;
break ;
case ShaderLanguage : : TYPE_UINT :
value = Variant ( p_value [ 0 ] . uint ) ;
break ;
case ShaderLanguage : : TYPE_UVEC2 :
value = Variant ( Vector2 ( p_value [ 0 ] . uint , p_value [ 1 ] . uint ) ) ;
break ;
case ShaderLanguage : : TYPE_UVEC3 :
value = Variant ( Vector3 ( p_value [ 0 ] . uint , p_value [ 1 ] . uint , p_value [ 2 ] . uint ) ) ;
break ;
case ShaderLanguage : : TYPE_UVEC4 :
value = Variant ( Plane ( p_value [ 0 ] . uint , p_value [ 1 ] . uint , p_value [ 2 ] . uint , p_value [ 3 ] . uint ) ) ;
break ;
case ShaderLanguage : : TYPE_FLOAT :
value = Variant ( p_value [ 0 ] . real ) ;
break ;
case ShaderLanguage : : TYPE_VEC2 :
value = Variant ( Vector2 ( p_value [ 0 ] . real , p_value [ 1 ] . real ) ) ;
break ;
case ShaderLanguage : : TYPE_VEC3 :
value = Variant ( Vector3 ( p_value [ 0 ] . real , p_value [ 1 ] . real , p_value [ 2 ] . real ) ) ;
break ;
case ShaderLanguage : : TYPE_VEC4 :
2018-11-16 12:20:23 +01:00
if ( p_hint = = ShaderLanguage : : ShaderNode : : Uniform : : HINT_COLOR ) {
value = Variant ( Color ( p_value [ 0 ] . real , p_value [ 1 ] . real , p_value [ 2 ] . real , p_value [ 3 ] . real ) ) ;
} else {
value = Variant ( Plane ( p_value [ 0 ] . real , p_value [ 1 ] . real , p_value [ 2 ] . real , p_value [ 3 ] . real ) ) ;
}
2018-09-05 00:54:35 +02:00
break ;
case ShaderLanguage : : TYPE_MAT2 :
value = Variant ( Transform2D ( p_value [ 0 ] . real , p_value [ 2 ] . real , p_value [ 1 ] . real , p_value [ 3 ] . real , 0.0 , 0.0 ) ) ;
break ;
case ShaderLanguage : : TYPE_MAT3 : {
Basis p ;
p [ 0 ] [ 0 ] = p_value [ 0 ] . real ;
p [ 0 ] [ 1 ] = p_value [ 1 ] . real ;
p [ 0 ] [ 2 ] = p_value [ 2 ] . real ;
p [ 1 ] [ 0 ] = p_value [ 3 ] . real ;
p [ 1 ] [ 1 ] = p_value [ 4 ] . real ;
p [ 1 ] [ 2 ] = p_value [ 5 ] . real ;
p [ 2 ] [ 0 ] = p_value [ 6 ] . real ;
p [ 2 ] [ 1 ] = p_value [ 7 ] . real ;
p [ 2 ] [ 2 ] = p_value [ 8 ] . real ;
value = Variant ( p ) ;
break ;
}
case ShaderLanguage : : TYPE_MAT4 : {
Basis p ;
p [ 0 ] [ 0 ] = p_value [ 0 ] . real ;
p [ 0 ] [ 1 ] = p_value [ 1 ] . real ;
p [ 0 ] [ 2 ] = p_value [ 2 ] . real ;
p [ 1 ] [ 0 ] = p_value [ 4 ] . real ;
p [ 1 ] [ 1 ] = p_value [ 5 ] . real ;
p [ 1 ] [ 2 ] = p_value [ 6 ] . real ;
p [ 2 ] [ 0 ] = p_value [ 8 ] . real ;
p [ 2 ] [ 1 ] = p_value [ 9 ] . real ;
p [ 2 ] [ 2 ] = p_value [ 10 ] . real ;
Transform t = Transform ( p , Vector3 ( p_value [ 3 ] . real , p_value [ 7 ] . real , p_value [ 11 ] . real ) ) ;
value = Variant ( t ) ;
break ;
}
2018-09-26 13:13:56 +02:00
case ShaderLanguage : : TYPE_ISAMPLER2DARRAY :
case ShaderLanguage : : TYPE_ISAMPLER2D :
case ShaderLanguage : : TYPE_ISAMPLER3D :
case ShaderLanguage : : TYPE_SAMPLER2DARRAY :
case ShaderLanguage : : TYPE_SAMPLER2D :
case ShaderLanguage : : TYPE_SAMPLER3D :
case ShaderLanguage : : TYPE_USAMPLER2DARRAY :
case ShaderLanguage : : TYPE_USAMPLER2D :
case ShaderLanguage : : TYPE_USAMPLER3D :
case ShaderLanguage : : TYPE_SAMPLERCUBE : {
// Texture types, likely not relevant here.
break ;
}
2020-01-17 20:35:22 +01:00
case ShaderLanguage : : TYPE_STRUCT :
break ;
2018-09-26 13:13:56 +02:00
case ShaderLanguage : : TYPE_VOID :
break ;
2018-09-05 00:54:35 +02:00
}
return value ;
}
return Variant ( ) ;
}
2019-07-21 16:31:30 +02:00
PropertyInfo ShaderLanguage : : uniform_to_property_info ( const ShaderNode : : Uniform & p_uniform ) {
PropertyInfo pi ;
switch ( p_uniform . type ) {
case ShaderLanguage : : TYPE_VOID : pi . type = Variant : : NIL ; break ;
case ShaderLanguage : : TYPE_BOOL : pi . type = Variant : : BOOL ; break ;
case ShaderLanguage : : TYPE_BVEC2 :
pi . type = Variant : : INT ;
pi . hint = PROPERTY_HINT_FLAGS ;
pi . hint_string = " x,y " ;
break ;
case ShaderLanguage : : TYPE_BVEC3 :
pi . type = Variant : : INT ;
pi . hint = PROPERTY_HINT_FLAGS ;
pi . hint_string = " x,y,z " ;
break ;
case ShaderLanguage : : TYPE_BVEC4 :
pi . type = Variant : : INT ;
pi . hint = PROPERTY_HINT_FLAGS ;
pi . hint_string = " x,y,z,w " ;
break ;
case ShaderLanguage : : TYPE_UINT :
case ShaderLanguage : : TYPE_INT : {
pi . type = Variant : : INT ;
if ( p_uniform . hint = = ShaderLanguage : : ShaderNode : : Uniform : : HINT_RANGE ) {
pi . hint = PROPERTY_HINT_RANGE ;
pi . hint_string = rtos ( p_uniform . hint_range [ 0 ] ) + " , " + rtos ( p_uniform . hint_range [ 1 ] ) ;
}
} break ;
case ShaderLanguage : : TYPE_IVEC2 :
case ShaderLanguage : : TYPE_IVEC3 :
case ShaderLanguage : : TYPE_IVEC4 :
case ShaderLanguage : : TYPE_UVEC2 :
case ShaderLanguage : : TYPE_UVEC3 :
case ShaderLanguage : : TYPE_UVEC4 : {
pi . type = Variant : : POOL_INT_ARRAY ;
} break ;
case ShaderLanguage : : TYPE_FLOAT : {
pi . type = Variant : : REAL ;
if ( p_uniform . hint = = ShaderLanguage : : ShaderNode : : Uniform : : HINT_RANGE ) {
pi . hint = PROPERTY_HINT_RANGE ;
pi . hint_string = rtos ( p_uniform . hint_range [ 0 ] ) + " , " + rtos ( p_uniform . hint_range [ 1 ] ) + " , " + rtos ( p_uniform . hint_range [ 2 ] ) ;
}
} break ;
case ShaderLanguage : : TYPE_VEC2 : pi . type = Variant : : VECTOR2 ; break ;
case ShaderLanguage : : TYPE_VEC3 : pi . type = Variant : : VECTOR3 ; break ;
case ShaderLanguage : : TYPE_VEC4 : {
if ( p_uniform . hint = = ShaderLanguage : : ShaderNode : : Uniform : : HINT_COLOR ) {
pi . type = Variant : : COLOR ;
} else {
pi . type = Variant : : PLANE ;
}
} break ;
case ShaderLanguage : : TYPE_MAT2 : pi . type = Variant : : TRANSFORM2D ; break ;
case ShaderLanguage : : TYPE_MAT3 : pi . type = Variant : : BASIS ; break ;
case ShaderLanguage : : TYPE_MAT4 : pi . type = Variant : : TRANSFORM ; break ;
case ShaderLanguage : : TYPE_SAMPLER2D :
case ShaderLanguage : : TYPE_ISAMPLER2D :
case ShaderLanguage : : TYPE_USAMPLER2D : {
pi . type = Variant : : OBJECT ;
pi . hint = PROPERTY_HINT_RESOURCE_TYPE ;
pi . hint_string = " Texture2D " ;
} break ;
case ShaderLanguage : : TYPE_SAMPLER2DARRAY :
case ShaderLanguage : : TYPE_ISAMPLER2DARRAY :
case ShaderLanguage : : TYPE_USAMPLER2DARRAY : {
pi . type = Variant : : OBJECT ;
pi . hint = PROPERTY_HINT_RESOURCE_TYPE ;
pi . hint_string = " TextureArray " ;
} break ;
case ShaderLanguage : : TYPE_SAMPLER3D :
case ShaderLanguage : : TYPE_ISAMPLER3D :
case ShaderLanguage : : TYPE_USAMPLER3D : {
pi . type = Variant : : OBJECT ;
pi . hint = PROPERTY_HINT_RESOURCE_TYPE ;
pi . hint_string = " Texture3D " ;
} break ;
case ShaderLanguage : : TYPE_SAMPLERCUBE : {
pi . type = Variant : : OBJECT ;
pi . hint = PROPERTY_HINT_RESOURCE_TYPE ;
pi . hint_string = " CubeMap " ;
} break ;
}
return pi ;
}
uint32_t ShaderLanguage : : get_type_size ( DataType p_type ) {
switch ( p_type ) {
case TYPE_BOOL :
case TYPE_INT :
case TYPE_UINT :
case TYPE_FLOAT : return 4 ;
case TYPE_BVEC2 :
case TYPE_IVEC2 :
case TYPE_UVEC2 :
case TYPE_VEC2 : return 8 ;
case TYPE_BVEC3 :
case TYPE_IVEC3 :
case TYPE_UVEC3 :
case TYPE_VEC3 : return 12 ;
case TYPE_BVEC4 :
case TYPE_IVEC4 :
case TYPE_UVEC4 :
case TYPE_VEC4 : return 16 ;
case TYPE_MAT2 : return 8 ;
case TYPE_MAT3 : return 12 ;
case TYPE_MAT4 : return 16 ;
case TYPE_SAMPLER2D :
case TYPE_ISAMPLER2D :
case TYPE_USAMPLER2D :
case TYPE_SAMPLER2DARRAY :
case TYPE_ISAMPLER2DARRAY :
case TYPE_USAMPLER2DARRAY :
case TYPE_SAMPLER3D :
case TYPE_ISAMPLER3D :
case TYPE_USAMPLER3D :
case TYPE_SAMPLERCUBE : return 4 ; //not really, but useful for indices
}
return 0 ;
}
2016-10-07 16:31:18 +02:00
void ShaderLanguage : : get_keyword_list ( List < String > * r_keywords ) {
Set < String > kws ;
2017-03-05 16:44:50 +01:00
int idx = 0 ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
while ( keyword_list [ idx ] . text ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
kws . insert ( keyword_list [ idx ] . text ) ;
2014-02-10 02:10:30 +01:00
idx + + ;
}
2017-03-05 16:44:50 +01:00
idx = 0 ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
while ( builtin_func_defs [ idx ] . name ) {
kws . insert ( builtin_func_defs [ idx ] . name ) ;
idx + + ;
}
2017-03-05 16:44:50 +01:00
for ( Set < String > : : Element * E = kws . front ( ) ; E ; E = E - > next ( ) ) {
2016-10-07 16:31:18 +02:00
r_keywords - > push_back ( E - > get ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
}
2016-10-10 23:31:01 +02:00
void ShaderLanguage : : get_builtin_funcs ( List < String > * r_keywords ) {
Set < String > kws ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int idx = 0 ;
2016-10-10 23:31:01 +02:00
while ( builtin_func_defs [ idx ] . name ) {
kws . insert ( builtin_func_defs [ idx ] . name ) ;
idx + + ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( Set < String > : : Element * E = kws . front ( ) ; E ; E = E - > next ( ) ) {
2016-10-10 23:31:01 +02:00
r_keywords - > push_back ( E - > get ( ) ) ;
}
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
ShaderLanguage : : DataType ShaderLanguage : : get_scalar_type ( DataType p_type ) {
2017-03-05 16:44:50 +01:00
static const DataType scalar_types [ ] = {
2016-10-07 16:31:18 +02:00
TYPE_VOID ,
TYPE_BOOL ,
TYPE_BOOL ,
TYPE_BOOL ,
TYPE_BOOL ,
TYPE_INT ,
TYPE_INT ,
TYPE_INT ,
TYPE_INT ,
TYPE_UINT ,
TYPE_UINT ,
TYPE_UINT ,
TYPE_UINT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_FLOAT ,
TYPE_INT ,
TYPE_UINT ,
TYPE_FLOAT ,
} ;
return scalar_types [ p_type ] ;
2014-02-10 02:10:30 +01:00
}
2018-04-29 20:58:42 +02:00
int ShaderLanguage : : get_cardinality ( DataType p_type ) {
static const int cardinality_table [ ] = {
0 ,
1 ,
2 ,
3 ,
4 ,
1 ,
2 ,
3 ,
4 ,
1 ,
2 ,
3 ,
4 ,
1 ,
2 ,
3 ,
4 ,
4 ,
2018-08-31 13:11:13 +02:00
9 ,
16 ,
2018-04-29 20:58:42 +02:00
1 ,
1 ,
1 ,
1 ,
} ;
return cardinality_table [ p_type ] ;
}
2017-03-05 16:44:50 +01:00
bool ShaderLanguage : : _get_completable_identifier ( BlockNode * p_block , CompletionType p_type , StringName & identifier ) {
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
identifier = StringName ( ) ;
2016-10-07 16:31:18 +02:00
2018-10-24 22:20:05 +02:00
TkPos pos = { 0 , 0 } ;
2016-10-07 16:31:18 +02:00
Token tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_IDENTIFIER ) {
identifier = tk . text ;
pos = _get_tkpos ( ) ;
2016-10-07 16:31:18 +02:00
tk = _get_token ( ) ;
}
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_CURSOR ) {
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
completion_type = p_type ;
completion_line = tk_line ;
completion_block = p_block ;
2016-10-07 16:31:18 +02:00
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_IDENTIFIER ) {
identifier = identifier . operator String ( ) + tk . text . operator String ( ) ;
2016-10-07 16:31:18 +02:00
} else {
_set_tkpos ( pos ) ;
}
return true ;
2017-03-05 16:44:50 +01:00
} else if ( identifier ! = StringName ( ) ) {
2016-10-07 16:31:18 +02:00
_set_tkpos ( pos ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
return false ;
2014-02-10 02:10:30 +01:00
}
2017-12-15 22:23:16 +01:00
bool ShaderLanguage : : _is_operator_assign ( Operator p_op ) const {
switch ( p_op ) {
case OP_ASSIGN :
case OP_ASSIGN_ADD :
case OP_ASSIGN_SUB :
case OP_ASSIGN_MUL :
case OP_ASSIGN_DIV :
case OP_ASSIGN_MOD :
case OP_ASSIGN_SHIFT_LEFT :
case OP_ASSIGN_SHIFT_RIGHT :
case OP_ASSIGN_BIT_AND :
case OP_ASSIGN_BIT_OR :
case OP_ASSIGN_BIT_XOR :
return true ;
default :
return false ;
}
return false ;
}
2018-07-29 17:17:45 +02:00
bool ShaderLanguage : : _validate_assign ( Node * p_node , const Map < StringName , BuiltInInfo > & p_builtin_types , String * r_message ) {
2017-12-15 22:23:16 +01:00
if ( p_node - > type = = Node : : TYPE_OPERATOR ) {
OperatorNode * op = static_cast < OperatorNode * > ( p_node ) ;
2018-07-29 17:17:45 +02:00
2018-05-16 21:28:12 +02:00
if ( op - > op = = OP_INDEX ) {
2018-07-29 17:17:45 +02:00
return _validate_assign ( op - > arguments [ 0 ] , p_builtin_types , r_message ) ;
} else if ( _is_operator_assign ( op - > op ) ) {
//chained assignment
return _validate_assign ( op - > arguments [ 1 ] , p_builtin_types , r_message ) ;
} else if ( op - > op = = OP_CALL ) {
if ( r_message )
* r_message = RTR ( " Assignment to function. " ) ;
return false ;
2017-12-15 22:23:16 +01:00
}
2018-07-29 17:17:45 +02:00
} else if ( p_node - > type = = Node : : TYPE_MEMBER ) {
MemberNode * member = static_cast < MemberNode * > ( p_node ) ;
2020-02-13 15:50:20 +01:00
if ( member - > has_swizzling_duplicates ) {
if ( r_message )
* r_message = RTR ( " Swizzling assignment contains duplicates. " ) ;
return false ;
}
2018-07-29 17:17:45 +02:00
return _validate_assign ( member - > owner , p_builtin_types , r_message ) ;
} else if ( p_node - > type = = Node : : TYPE_VARIABLE ) {
2017-12-15 22:23:16 +01:00
VariableNode * var = static_cast < VariableNode * > ( p_node ) ;
2018-07-29 17:17:45 +02:00
if ( shader - > uniforms . has ( var - > name ) ) {
if ( r_message )
* r_message = RTR ( " Assignment to uniform. " ) ;
return false ;
}
if ( shader - > varyings . has ( var - > name ) & & current_function ! = String ( " vertex " ) ) {
if ( r_message )
* r_message = RTR ( " Varyings can only be assigned in vertex function. " ) ;
return false ;
}
2019-08-05 09:35:53 +02:00
if ( shader - > constants . has ( var - > name ) | | var - > is_const ) {
2019-05-30 16:19:24 +02:00
if ( r_message )
* r_message = RTR ( " Constants cannot be modified. " ) ;
return false ;
}
2018-07-29 17:17:45 +02:00
if ( ! ( p_builtin_types . has ( var - > name ) & & p_builtin_types [ var - > name ] . constant ) ) {
return true ;
2017-12-15 22:23:16 +01:00
}
2019-07-10 18:52:50 +02:00
} else if ( p_node - > type = = Node : : TYPE_ARRAY ) {
2019-08-05 09:35:53 +02:00
ArrayNode * arr = static_cast < ArrayNode * > ( p_node ) ;
if ( arr - > is_const ) {
if ( r_message )
* r_message = RTR ( " Constants cannot be modified. " ) ;
return false ;
}
2019-07-29 16:08:25 +02:00
if ( shader - > varyings . has ( arr - > name ) & & current_function ! = String ( " vertex " ) ) {
if ( r_message )
* r_message = RTR ( " Varyings can only be assigned in vertex function. " ) ;
return false ;
}
2019-07-10 18:52:50 +02:00
return true ;
2017-12-15 22:23:16 +01:00
}
2018-07-29 17:17:45 +02:00
if ( r_message )
* r_message = " Assignment to constant expression. " ;
return false ;
2017-12-15 22:23:16 +01:00
}
2019-07-21 16:31:30 +02:00
bool ShaderLanguage : : _propagate_function_call_sampler_uniform_settings ( StringName p_name , int p_argument , TextureFilter p_filter , TextureRepeat p_repeat ) {
for ( int i = 0 ; shader - > functions . size ( ) ; i + + ) {
if ( shader - > functions [ i ] . name = = p_name ) {
ERR_FAIL_INDEX_V ( p_argument , shader - > functions [ i ] . function - > arguments . size ( ) , false ) ;
FunctionNode : : Argument * arg = & shader - > functions [ i ] . function - > arguments . write [ p_argument ] ;
if ( arg - > tex_builtin_check ) {
_set_error ( " Sampler argument # " + itos ( p_argument ) + " of function ' " + String ( p_name ) + " ' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other). " ) ;
return false ;
} else if ( arg - > tex_argument_check ) {
//was checked, verify that filter and repeat are the same
if ( arg - > tex_argument_filter = = p_filter & & arg - > tex_argument_repeat = = p_repeat ) {
return true ;
} else {
_set_error ( " Sampler argument # " + itos ( p_argument ) + " of function ' " + String ( p_name ) + " ' called more than once using textures that differ in either filter or repeat setting. " ) ;
return false ;
}
} else {
arg - > tex_argument_check = true ;
arg - > tex_argument_filter = p_filter ;
arg - > tex_argument_repeat = p_repeat ;
for ( Map < StringName , Set < int > > : : Element * E = arg - > tex_argument_connect . front ( ) ; E ; E = E - > next ( ) ) {
for ( Set < int > : : Element * F = E - > get ( ) . front ( ) ; F ; F = F - > next ( ) ) {
if ( ! _propagate_function_call_sampler_uniform_settings ( E - > key ( ) , F - > get ( ) , p_filter , p_repeat ) ) {
return false ;
}
}
}
return true ;
}
}
}
ERR_FAIL_V ( false ) ; //bug? function not found
}
bool ShaderLanguage : : _propagate_function_call_sampler_builtin_reference ( StringName p_name , int p_argument , const StringName & p_builtin ) {
for ( int i = 0 ; shader - > functions . size ( ) ; i + + ) {
if ( shader - > functions [ i ] . name = = p_name ) {
ERR_FAIL_INDEX_V ( p_argument , shader - > functions [ i ] . function - > arguments . size ( ) , false ) ;
FunctionNode : : Argument * arg = & shader - > functions [ i ] . function - > arguments . write [ p_argument ] ;
if ( arg - > tex_argument_check ) {
_set_error ( " Sampler argument # " + itos ( p_argument ) + " of function ' " + String ( p_name ) + " ' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other). " ) ;
return false ;
} else if ( arg - > tex_builtin_check ) {
//was checked, verify that the built-in is the same
if ( arg - > tex_builtin = = p_builtin ) {
return true ;
} else {
_set_error ( " Sampler argument # " + itos ( p_argument ) + " of function ' " + String ( p_name ) + " ' called more than once using different built-ins. Only calling with the same built-in is supported. " ) ;
return false ;
}
} else {
arg - > tex_builtin_check = true ;
arg - > tex_builtin = p_builtin ;
for ( Map < StringName , Set < int > > : : Element * E = arg - > tex_argument_connect . front ( ) ; E ; E = E - > next ( ) ) {
for ( Set < int > : : Element * F = E - > get ( ) . front ( ) ; F ; F = F - > next ( ) ) {
if ( ! _propagate_function_call_sampler_builtin_reference ( E - > key ( ) , F - > get ( ) , p_builtin ) ) {
return false ;
}
}
}
return true ;
}
}
}
ERR_FAIL_V ( false ) ; //bug? function not found
}
2017-12-15 22:23:16 +01:00
ShaderLanguage : : Node * ShaderLanguage : : _parse_expression ( BlockNode * p_block , const Map < StringName , BuiltInInfo > & p_builtin_types ) {
2014-02-10 02:10:30 +01:00
2014-09-18 04:23:42 +02:00
Vector < Expression > expression ;
2019-07-10 18:52:50 +02:00
2014-09-18 04:23:42 +02:00
//Vector<TokenType> operators;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Node * expr = NULL ;
2016-10-07 16:31:18 +02:00
TkPos prepos = _get_tkpos ( ) ;
2016-10-03 21:33:42 +02:00
Token tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
TkPos pos = _get_tkpos ( ) ;
2014-02-10 02:10:30 +01:00
2020-02-12 21:16:47 +01:00
bool is_const = false ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_PARENTHESIS_OPEN ) {
2014-02-10 02:10:30 +01:00
//handle subexpression
2017-03-05 16:44:50 +01:00
expr = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2016-10-03 21:33:42 +02:00
if ( ! expr )
return NULL ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
_set_error ( " Expected ')' in expression " ) ;
return NULL ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_REAL_CONSTANT ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
ConstantNode * constant = alloc_node < ConstantNode > ( ) ;
2016-10-07 16:31:18 +02:00
ConstantNode : : Value v ;
2017-03-05 16:44:50 +01:00
v . real = tk . constant ;
2016-10-07 16:31:18 +02:00
constant - > values . push_back ( v ) ;
2017-03-05 16:44:50 +01:00
constant - > datatype = TYPE_FLOAT ;
expr = constant ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_INT_CONSTANT ) {
2016-10-03 21:33:42 +02:00
ConstantNode * constant = alloc_node < ConstantNode > ( ) ;
2016-10-07 16:31:18 +02:00
ConstantNode : : Value v ;
2017-03-05 16:44:50 +01:00
v . sint = tk . constant ;
2016-10-07 16:31:18 +02:00
constant - > values . push_back ( v ) ;
2017-03-05 16:44:50 +01:00
constant - > datatype = TYPE_INT ;
expr = constant ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_TRUE ) {
2014-02-10 02:10:30 +01:00
//handle true constant
2016-10-03 21:33:42 +02:00
ConstantNode * constant = alloc_node < ConstantNode > ( ) ;
2016-10-07 16:31:18 +02:00
ConstantNode : : Value v ;
2017-03-05 16:44:50 +01:00
v . boolean = true ;
2016-10-07 16:31:18 +02:00
constant - > values . push_back ( v ) ;
2017-03-05 16:44:50 +01:00
constant - > datatype = TYPE_BOOL ;
expr = constant ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_FALSE ) {
2014-02-10 02:10:30 +01:00
//handle false constant
2016-10-03 21:33:42 +02:00
ConstantNode * constant = alloc_node < ConstantNode > ( ) ;
2016-10-07 16:31:18 +02:00
ConstantNode : : Value v ;
2017-03-05 16:44:50 +01:00
v . boolean = false ;
2016-10-07 16:31:18 +02:00
constant - > values . push_back ( v ) ;
2017-03-05 16:44:50 +01:00
constant - > datatype = TYPE_BOOL ;
expr = constant ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_TYPE_VOID ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
//make sure void is not used in expression
_set_error ( " Void value not allowed in Expression " ) ;
return NULL ;
2016-10-07 16:31:18 +02:00
} else if ( is_token_nonvoid_datatype ( tk . type ) ) {
2016-10-03 21:33:42 +02:00
//basic type constructor
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
OperatorNode * func = alloc_node < OperatorNode > ( ) ;
2017-03-05 16:44:50 +01:00
func - > op = OP_CONSTRUCT ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( is_token_precision ( tk . type ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
func - > return_precision_cache = get_token_precision ( tk . type ) ;
tk = _get_token ( ) ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
VariableNode * funcname = alloc_node < VariableNode > ( ) ;
2017-03-05 16:44:50 +01:00
funcname - > name = get_datatype_name ( get_token_datatype ( tk . type ) ) ;
2014-02-10 02:10:30 +01:00
func - > arguments . push_back ( funcname ) ;
2017-03-05 16:44:50 +01:00
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected '(' after type name " ) ;
return NULL ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int carg = - 1 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool ok = _parse_function_arguments ( p_block , p_builtin_types , func , & carg ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( carg > = 0 ) {
completion_type = COMPLETION_CALL_ARGUMENTS ;
completion_line = tk_line ;
completion_block = p_block ;
completion_function = funcname - > name ;
completion_argument = carg ;
2016-10-07 16:31:18 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
if ( ! ok )
return NULL ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( ! _validate_function_call ( p_block , func , & func - > return_cache , & func - > struct_name ) ) {
2017-03-05 16:44:50 +01:00
_set_error ( " No matching constructor found for: ' " + String ( funcname - > name ) + " ' " ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
expr = _reduce_expression ( p_block , func ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_IDENTIFIER ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
_set_tkpos ( prepos ) ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
StringName identifier ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
StructNode * pstruct = NULL ;
bool struct_init = false ;
2017-03-05 16:44:50 +01:00
_get_completable_identifier ( p_block , COMPLETION_IDENTIFIER , identifier ) ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( shader - > structs . has ( identifier ) ) {
pstruct = shader - > structs [ identifier ] . shader_struct ;
struct_init = true ;
}
2017-03-05 16:44:50 +01:00
tk = _get_token ( ) ;
if ( tk . type = = TK_PARENTHESIS_OPEN ) {
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( struct_init ) { //a struct constructor
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
const StringName & name = identifier ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
OperatorNode * func = alloc_node < OperatorNode > ( ) ;
func - > op = OP_STRUCT ;
func - > struct_name = name ;
func - > return_cache = TYPE_STRUCT ;
VariableNode * funcname = alloc_node < VariableNode > ( ) ;
funcname - > name = name ;
func - > arguments . push_back ( funcname ) ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
for ( int i = 0 ; i < pstruct - > members . size ( ) ; i + + ) {
2020-02-11 20:03:04 +01:00
Node * nexpr ;
2019-10-06 19:35:41 +02:00
2020-02-11 20:03:04 +01:00
if ( pstruct - > members [ i ] - > array_size ! = 0 ) {
DataType type = pstruct - > members [ i ] - > get_datatype ( ) ;
String struct_name = pstruct - > members [ i ] - > struct_name ;
int array_size = pstruct - > members [ i ] - > array_size ;
DataType type2 ;
String struct_name2 = " " ;
int array_size2 = 0 ;
bool auto_size = false ;
tk = _get_token ( ) ;
if ( tk . type = = TK_CURLY_BRACKET_OPEN ) {
auto_size = true ;
} else {
if ( shader - > structs . has ( tk . text ) ) {
type2 = TYPE_STRUCT ;
struct_name2 = tk . text ;
} else {
if ( ! is_token_variable_datatype ( tk . type ) ) {
_set_error ( " Invalid data type for array " ) ;
return NULL ;
}
type2 = get_token_datatype ( tk . type ) ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_OPEN ) {
TkPos pos2 = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
array_size2 = array_size ;
tk = _get_token ( ) ;
} else {
_set_tkpos ( pos2 ) ;
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! n | | n - > type ! = Node : : TYPE_CONSTANT | | n - > get_datatype ( ) ! = TYPE_INT ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return NULL ;
}
ConstantNode * cnode = ( ConstantNode * ) n ;
if ( cnode - > values . size ( ) = = 1 ) {
array_size2 = cnode - > values [ 0 ] . sint ;
if ( array_size2 < = 0 ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return NULL ;
}
} else {
_set_error ( " Expected single integer constant > 0 " ) ;
return NULL ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return NULL ;
} else {
tk = _get_token ( ) ;
}
}
} else {
_set_error ( " Expected '[' " ) ;
return NULL ;
}
if ( type ! = type2 | | struct_name ! = struct_name2 | | array_size ! = array_size2 ) {
String error_str = " Cannot convert from ' " ;
if ( type2 = = TYPE_STRUCT ) {
error_str + = struct_name2 ;
} else {
error_str + = get_datatype_name ( type2 ) ;
}
error_str + = " [ " ;
error_str + = itos ( array_size2 ) ;
error_str + = " ]' " ;
error_str + = " to ' " ;
if ( type = = TYPE_STRUCT ) {
error_str + = struct_name ;
} else {
error_str + = get_datatype_name ( type ) ;
}
error_str + = " [ " ;
error_str + = itos ( array_size ) ;
error_str + = " ]' " ;
_set_error ( error_str ) ;
return NULL ;
}
}
ArrayConstructNode * an = alloc_node < ArrayConstructNode > ( ) ;
an - > datatype = type ;
an - > struct_name = struct_name ;
if ( tk . type = = TK_PARENTHESIS_OPEN | | auto_size ) { // initialization
while ( true ) {
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! n ) {
return NULL ;
}
if ( type ! = n - > get_datatype ( ) | | struct_name ! = n - > get_datatype_name ( ) ) {
_set_error ( " Invalid assignment of ' " + ( n - > get_datatype ( ) = = TYPE_STRUCT ? n - > get_datatype_name ( ) : get_datatype_name ( n - > get_datatype ( ) ) ) + " ' to ' " + ( type = = TYPE_STRUCT ? struct_name : get_datatype_name ( type ) ) + " ' " ) ;
return NULL ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_COMMA ) {
an - > initializer . push_back ( n ) ;
continue ;
} else if ( ! auto_size & & tk . type = = TK_PARENTHESIS_CLOSE ) {
an - > initializer . push_back ( n ) ;
break ;
} else if ( auto_size & & tk . type = = TK_CURLY_BRACKET_CLOSE ) {
an - > initializer . push_back ( n ) ;
break ;
} else {
if ( auto_size )
_set_error ( " Expected '}' or ',' " ) ;
else
_set_error ( " Expected ')' or ',' " ) ;
return NULL ;
}
}
if ( an - > initializer . size ( ) ! = array_size ) {
_set_error ( " Array size mismatch " ) ;
return NULL ;
}
} else {
_set_error ( " Expected array initialization! " ) ;
return NULL ;
}
nexpr = an ;
} else {
nexpr = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! nexpr ) {
return NULL ;
}
Node * node = pstruct - > members [ i ] ;
if ( ! _compare_datatypes_in_nodes ( pstruct - > members [ i ] , nexpr ) ) {
String type_name = nexpr - > get_datatype ( ) = = TYPE_STRUCT ? nexpr - > get_datatype_name ( ) : get_datatype_name ( nexpr - > get_datatype ( ) ) ;
String type_name2 = node - > get_datatype ( ) = = TYPE_STRUCT ? node - > get_datatype_name ( ) : get_datatype_name ( node - > get_datatype ( ) ) ;
_set_error ( " Invalid assignment of ' " + type_name + " ' to ' " + type_name2 + " ' " ) ;
return NULL ;
}
2017-04-07 04:36:37 +02:00
}
2019-07-21 16:31:30 +02:00
2020-01-17 20:35:22 +01:00
if ( i + 1 < pstruct - > members . size ( ) ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_COMMA ) {
_set_error ( " Expected ',' " ) ;
return NULL ;
}
}
func - > arguments . push_back ( nexpr ) ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
_set_error ( " Expected ')' " ) ;
return NULL ;
2016-10-10 23:31:01 +02:00
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
expr = func ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
} else { //a function
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
const StringName & name = identifier ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
OperatorNode * func = alloc_node < OperatorNode > ( ) ;
func - > op = OP_CALL ;
VariableNode * funcname = alloc_node < VariableNode > ( ) ;
funcname - > name = name ;
func - > arguments . push_back ( funcname ) ;
2019-07-21 16:31:30 +02:00
2020-01-17 20:35:22 +01:00
int carg = - 1 ;
2019-07-21 16:31:30 +02:00
2020-01-17 20:35:22 +01:00
bool ok = _parse_function_arguments ( p_block , p_builtin_types , func , & carg ) ;
2019-07-21 16:31:30 +02:00
2020-01-17 20:35:22 +01:00
// Check if block has a variable with the same name as function to prevent shader crash.
ShaderLanguage : : BlockNode * bnode = p_block ;
while ( bnode ) {
if ( bnode - > variables . has ( name ) ) {
_set_error ( " Expected function name " ) ;
return NULL ;
}
bnode = bnode - > parent_block ;
}
2019-07-21 16:31:30 +02:00
2020-01-17 20:35:22 +01:00
//test if function was parsed first
int function_index = - 1 ;
for ( int i = 0 ; i < shader - > functions . size ( ) ; i + + ) {
if ( shader - > functions [ i ] . name = = name ) {
//add to current function as dependency
for ( int j = 0 ; j < shader - > functions . size ( ) ; j + + ) {
if ( shader - > functions [ j ] . name = = current_function ) {
shader - > functions . write [ j ] . uses_function . insert ( name ) ;
2019-07-21 16:31:30 +02:00
break ;
}
}
2020-01-17 20:35:22 +01:00
//see if texture arguments must connect
function_index = i ;
break ;
2019-07-21 16:31:30 +02:00
}
2020-01-17 20:35:22 +01:00
}
2019-07-21 16:31:30 +02:00
2020-01-17 20:35:22 +01:00
if ( carg > = 0 ) {
completion_type = COMPLETION_CALL_ARGUMENTS ;
completion_line = tk_line ;
completion_block = p_block ;
completion_function = funcname - > name ;
completion_argument = carg ;
}
if ( ! ok )
return NULL ;
if ( ! _validate_function_call ( p_block , func , & func - > return_cache , & func - > struct_name ) ) {
_set_error ( " No matching function found for: ' " + String ( funcname - > name ) + " ' " ) ;
return NULL ;
}
completion_class = TAG_GLOBAL ; // reset sub-class
if ( function_index > = 0 ) {
//connect texture arguments, so we can cache in the
//argument what type of filter and repeat to use
FunctionNode * call_function = shader - > functions [ function_index ] . function ;
if ( call_function ) {
//get current base function
FunctionNode * base_function = NULL ;
{
BlockNode * b = p_block ;
while ( b ) {
if ( b - > parent_function ) {
base_function = b - > parent_function ;
break ;
} else {
b = b - > parent_block ;
2019-07-21 16:31:30 +02:00
}
2020-01-17 20:35:22 +01:00
}
}
ERR_FAIL_COND_V ( ! base_function , NULL ) ; //bug, wtf
for ( int i = 0 ; i < call_function - > arguments . size ( ) ; i + + ) {
int argidx = i + 1 ;
2020-02-12 21:16:47 +01:00
if ( argidx < func - > arguments . size ( ) ) {
if ( call_function - > arguments [ i ] . qualifier = = ArgumentQualifier : : ARGUMENT_QUALIFIER_OUT | | call_function - > arguments [ i ] . qualifier = = ArgumentQualifier : : ARGUMENT_QUALIFIER_INOUT ) {
bool error = false ;
Node * n = func - > arguments [ argidx ] ;
if ( n - > type = = Node : : TYPE_CONSTANT | | n - > type = = Node : : TYPE_OPERATOR ) {
error = true ;
} else if ( n - > type = = Node : : TYPE_ARRAY ) {
ArrayNode * an = static_cast < ArrayNode * > ( n ) ;
if ( an - > call_expression ! = NULL ) {
error = true ;
}
} else if ( n - > type = = Node : : TYPE_VARIABLE ) {
VariableNode * vn = static_cast < VariableNode * > ( n ) ;
if ( vn - > is_const ) {
error = true ;
} else {
StringName varname = vn - > name ;
if ( shader - > uniforms . has ( varname ) ) {
error = true ;
} else {
if ( p_builtin_types . has ( varname ) ) {
BuiltInInfo info = p_builtin_types [ varname ] ;
if ( info . constant ) {
error = true ;
}
}
}
}
} else if ( n - > type = = Node : : TYPE_MEMBER ) {
MemberNode * mn = static_cast < MemberNode * > ( n ) ;
if ( mn - > basetype_const ) {
error = true ;
}
2020-01-17 20:35:22 +01:00
}
2020-02-12 21:16:47 +01:00
if ( error ) {
_set_error ( vformat ( " Constant value cannot be passed for '%s' parameter! " , _get_qualifier_str ( call_function - > arguments [ i ] . qualifier ) ) ) ;
2020-01-17 20:35:22 +01:00
return NULL ;
}
2020-02-12 21:16:47 +01:00
}
if ( is_sampler_type ( call_function - > arguments [ i ] . type ) ) {
//let's see where our argument comes from
Node * n = func - > arguments [ argidx ] ;
ERR_CONTINUE ( n - > type ! = Node : : TYPE_VARIABLE ) ; //bug? this should always be a variable
VariableNode * vn = static_cast < VariableNode * > ( n ) ;
StringName varname = vn - > name ;
if ( shader - > uniforms . has ( varname ) ) {
//being sampler, this either comes from a uniform
ShaderNode : : Uniform * u = & shader - > uniforms [ varname ] ;
ERR_CONTINUE ( u - > type ! = call_function - > arguments [ i ] . type ) ; //this should have been validated previously
//propagate
if ( ! _propagate_function_call_sampler_uniform_settings ( name , i , u - > filter , u - > repeat ) ) {
return NULL ;
}
} else if ( p_builtin_types . has ( varname ) ) {
//a built-in
if ( ! _propagate_function_call_sampler_builtin_reference ( name , i , varname ) ) {
return NULL ;
}
} else {
//or this comes from an argument, but nothing else can be a sampler
bool found = false ;
for ( int j = 0 ; j < base_function - > arguments . size ( ) ; j + + ) {
if ( base_function - > arguments [ j ] . name = = varname ) {
if ( ! base_function - > arguments [ j ] . tex_argument_connect . has ( call_function - > name ) ) {
base_function - > arguments . write [ j ] . tex_argument_connect [ call_function - > name ] = Set < int > ( ) ;
}
base_function - > arguments . write [ j ] . tex_argument_connect [ call_function - > name ] . insert ( i ) ;
found = true ;
break ;
2020-01-17 20:35:22 +01:00
}
2019-07-21 16:31:30 +02:00
}
2020-02-12 21:16:47 +01:00
ERR_CONTINUE ( ! found ) ;
2019-07-21 16:31:30 +02:00
}
}
2020-02-12 21:16:47 +01:00
} else {
break ;
2019-07-21 16:31:30 +02:00
}
}
}
}
2020-01-17 20:35:22 +01:00
expr = func ;
2019-07-21 16:31:30 +02:00
}
2016-10-03 21:33:42 +02:00
} else {
//an identifier
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
_set_tkpos ( pos ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
DataType data_type ;
IdentifierType ident_type ;
2019-07-10 18:52:50 +02:00
int array_size = 0 ;
2020-01-17 20:35:22 +01:00
StringName struct_name ;
2014-02-10 02:10:30 +01:00
2020-02-07 12:50:11 +01:00
if ( p_block & & p_block - > block_tag ! = SubClassTag : : TAG_GLOBAL ) {
int idx = 0 ;
bool found = false ;
2014-02-10 02:10:30 +01:00
2020-02-07 12:50:11 +01:00
while ( builtin_func_defs [ idx ] . name ) {
if ( builtin_func_defs [ idx ] . tag = = p_block - > block_tag & & builtin_func_defs [ idx ] . name = = identifier ) {
found = true ;
break ;
}
idx + + ;
}
if ( ! found ) {
_set_error ( " Unknown identifier in expression: " + String ( identifier ) ) ;
return NULL ;
}
} else {
2020-01-17 20:35:22 +01:00
if ( ! _find_identifier ( p_block , p_builtin_types , identifier , & data_type , & ident_type , & is_const , & array_size , & struct_name ) ) {
2020-02-07 12:50:11 +01:00
_set_error ( " Unknown identifier in expression: " + String ( identifier ) ) ;
return NULL ;
}
if ( ident_type = = IDENTIFIER_FUNCTION ) {
_set_error ( " Can't use function as identifier: " + String ( identifier ) ) ;
return NULL ;
}
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2019-07-10 18:52:50 +02:00
Node * index_expression = NULL ;
Node * call_expression = NULL ;
if ( array_size > 0 ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_OPEN & & tk . type ! = TK_PERIOD ) {
_set_error ( " Expected '[' or '.' " ) ;
return NULL ;
}
if ( tk . type = = TK_PERIOD ) {
completion_class = TAG_ARRAY ;
2020-02-07 12:50:11 +01:00
p_block - > block_tag = SubClassTag : : TAG_ARRAY ;
2019-07-10 18:52:50 +02:00
call_expression = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2020-02-07 12:50:11 +01:00
p_block - > block_tag = SubClassTag : : TAG_GLOBAL ;
2019-07-10 18:52:50 +02:00
if ( ! call_expression )
return NULL ;
data_type = call_expression - > get_datatype ( ) ;
} else { // indexing
index_expression = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! index_expression )
return NULL ;
if ( index_expression - > get_datatype ( ) ! = TYPE_INT & & index_expression - > get_datatype ( ) ! = TYPE_UINT ) {
_set_error ( " Only integer expressions are allowed for indexing " ) ;
return NULL ;
}
if ( index_expression - > type = = Node : : TYPE_CONSTANT ) {
ConstantNode * cnode = ( ConstantNode * ) index_expression ;
if ( cnode ) {
if ( ! cnode - > values . empty ( ) ) {
int value = cnode - > values [ 0 ] . sint ;
if ( value < 0 | | value > = array_size ) {
_set_error ( vformat ( " Index [%s] out of range [%s..%s] " , value , 0 , array_size - 1 ) ) ;
return NULL ;
}
}
}
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return NULL ;
}
}
ArrayNode * arrname = alloc_node < ArrayNode > ( ) ;
arrname - > name = identifier ;
arrname - > datatype_cache = data_type ;
2020-01-17 20:35:22 +01:00
arrname - > struct_name = struct_name ;
2019-07-10 18:52:50 +02:00
arrname - > index_expression = index_expression ;
arrname - > call_expression = call_expression ;
2019-08-05 09:35:53 +02:00
arrname - > is_const = is_const ;
2019-07-10 18:52:50 +02:00
expr = arrname ;
} else {
VariableNode * varname = alloc_node < VariableNode > ( ) ;
varname - > name = identifier ;
varname - > datatype_cache = data_type ;
2019-08-05 09:35:53 +02:00
varname - > is_const = is_const ;
2020-01-17 20:35:22 +01:00
varname - > struct_name = struct_name ;
2019-07-10 18:52:50 +02:00
expr = varname ;
}
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_OP_ADD ) {
2016-10-03 21:33:42 +02:00
continue ; //this one does nothing
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_OP_SUB | | tk . type = = TK_OP_NOT | | tk . type = = TK_OP_BIT_INVERT | | tk . type = = TK_OP_INCREMENT | | tk . type = = TK_OP_DECREMENT ) {
2014-09-18 04:23:42 +02:00
Expression e ;
2017-03-05 16:44:50 +01:00
e . is_op = true ;
switch ( tk . type ) {
case TK_OP_SUB : e . op = OP_NEGATE ; break ;
case TK_OP_NOT : e . op = OP_NOT ; break ;
case TK_OP_BIT_INVERT : e . op = OP_BIT_INVERT ; break ;
case TK_OP_INCREMENT : e . op = OP_INCREMENT ; break ;
case TK_OP_DECREMENT : e . op = OP_DECREMENT ; break ;
2016-10-03 21:33:42 +02:00
default : ERR_FAIL_V ( NULL ) ;
2014-02-10 02:10:30 +01:00
}
2014-09-18 04:23:42 +02:00
expression . push_back ( e ) ;
continue ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
_set_error ( " Expected expression, found: " + get_token_text ( tk ) ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
2014-02-10 02:10:30 +01:00
//nothing
}
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! expr , NULL ) ;
2014-02-10 02:10:30 +01:00
/* OK now see what's NEXT to the operator.. */
/* OK now see what's NEXT to the operator.. */
/* OK now see what's NEXT to the operator.. */
2017-03-05 16:44:50 +01:00
while ( true ) {
2019-02-12 21:10:08 +01:00
TkPos pos2 = _get_tkpos ( ) ;
2017-03-05 16:44:50 +01:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2018-07-14 19:59:11 +02:00
if ( tk . type = = TK_CURSOR ) {
//do nothing
2020-01-17 20:35:22 +01:00
} else if ( tk . type = = TK_IDENTIFIER ) {
2018-07-14 19:59:11 +02:00
} else if ( tk . type = = TK_PERIOD ) {
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
DataType dt = expr - > get_datatype ( ) ;
String st = expr - > get_datatype_name ( ) ;
2016-10-07 16:31:18 +02:00
StringName identifier ;
2020-01-17 20:35:22 +01:00
if ( _get_completable_identifier ( p_block , dt = = TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX , identifier ) ) {
if ( dt = = TYPE_STRUCT ) {
completion_struct = st ;
} else {
completion_base = dt ;
}
2016-10-07 16:31:18 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( identifier = = StringName ( ) ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected identifier as member " ) ;
return NULL ;
}
2016-10-07 16:31:18 +02:00
String ident = identifier ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
bool ok = true ;
2020-02-13 15:50:20 +01:00
bool repeated = false ;
2019-07-23 09:14:31 +02:00
DataType member_type = TYPE_VOID ;
2020-01-17 20:35:22 +01:00
StringName member_struct_name = " " ;
2020-02-11 20:03:04 +01:00
int array_size = 0 ;
2020-02-13 15:50:20 +01:00
Set < char > position_symbols ;
Set < char > color_symbols ;
Set < char > texture_symbols ;
bool mix_error = false ;
2017-03-05 16:44:50 +01:00
switch ( dt ) {
2020-01-17 20:35:22 +01:00
case TYPE_STRUCT : {
ok = false ;
String member_name = String ( ident . ptr ( ) ) ;
if ( shader - > structs . has ( st ) ) {
StructNode * n = shader - > structs [ st ] . shader_struct ;
for ( List < MemberNode * > : : Element * E = n - > members . front ( ) ; E ; E = E - > next ( ) ) {
if ( String ( E - > get ( ) - > name ) = = member_name ) {
member_type = E - > get ( ) - > datatype ;
2020-02-11 20:03:04 +01:00
array_size = E - > get ( ) - > array_size ;
2020-01-17 20:35:22 +01:00
if ( member_type = = TYPE_STRUCT ) {
member_struct_name = E - > get ( ) - > struct_name ;
}
ok = true ;
break ;
}
}
}
} break ;
2016-10-03 21:33:42 +02:00
case TYPE_BVEC2 :
case TYPE_IVEC2 :
case TYPE_UVEC2 :
case TYPE_VEC2 : {
int l = ident . length ( ) ;
2017-03-05 16:44:50 +01:00
if ( l = = 1 ) {
member_type = DataType ( dt - 1 ) ;
} else if ( l = = 2 ) {
member_type = dt ;
2019-05-11 19:41:13 +02:00
} else if ( l = = 3 ) {
member_type = DataType ( dt + 1 ) ;
} else if ( l = = 4 ) {
member_type = DataType ( dt + 2 ) ;
2016-10-03 21:33:42 +02:00
} else {
2017-03-05 16:44:50 +01:00
ok = false ;
2016-10-03 21:33:42 +02:00
break ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const CharType * c = ident . ptr ( ) ;
for ( int i = 0 ; i < l ; i + + ) {
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
switch ( c [ i ] ) {
2016-10-03 21:33:42 +02:00
case ' r ' :
case ' g ' :
2020-02-13 15:50:20 +01:00
if ( position_symbols . size ( ) > 0 | | texture_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! color_symbols . has ( c [ i ] ) ) {
color_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
break ;
2016-10-03 21:33:42 +02:00
case ' x ' :
case ' y ' :
2020-02-13 15:50:20 +01:00
if ( color_symbols . size ( ) > 0 | | texture_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! position_symbols . has ( c [ i ] ) ) {
position_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
break ;
case ' s ' :
case ' t ' :
if ( color_symbols . size ( ) > 0 | | position_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! texture_symbols . has ( c [ i ] ) ) {
texture_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
2016-10-03 21:33:42 +02:00
break ;
default :
2017-03-05 16:44:50 +01:00
ok = false ;
2016-10-03 21:33:42 +02:00
break ;
}
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
case TYPE_BVEC3 :
case TYPE_IVEC3 :
case TYPE_UVEC3 :
case TYPE_VEC3 : {
int l = ident . length ( ) ;
2017-03-05 16:44:50 +01:00
if ( l = = 1 ) {
member_type = DataType ( dt - 2 ) ;
} else if ( l = = 2 ) {
member_type = DataType ( dt - 1 ) ;
} else if ( l = = 3 ) {
member_type = dt ;
2019-05-11 19:41:13 +02:00
} else if ( l = = 4 ) {
member_type = DataType ( dt + 1 ) ;
2016-10-03 21:33:42 +02:00
} else {
2017-03-05 16:44:50 +01:00
ok = false ;
2016-10-03 21:33:42 +02:00
break ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
const CharType * c = ident . ptr ( ) ;
for ( int i = 0 ; i < l ; i + + ) {
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
switch ( c [ i ] ) {
2016-10-03 21:33:42 +02:00
case ' r ' :
case ' g ' :
case ' b ' :
2020-02-13 15:50:20 +01:00
if ( position_symbols . size ( ) > 0 | | texture_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! color_symbols . has ( c [ i ] ) ) {
color_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
break ;
2016-10-03 21:33:42 +02:00
case ' x ' :
case ' y ' :
case ' z ' :
2020-02-13 15:50:20 +01:00
if ( color_symbols . size ( ) > 0 | | texture_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! position_symbols . has ( c [ i ] ) ) {
position_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
break ;
case ' s ' :
case ' t ' :
case ' p ' :
if ( color_symbols . size ( ) > 0 | | position_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! texture_symbols . has ( c [ i ] ) ) {
texture_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
2016-10-03 21:33:42 +02:00
break ;
default :
2017-03-05 16:44:50 +01:00
ok = false ;
2016-10-03 21:33:42 +02:00
break ;
}
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
} break ;
case TYPE_BVEC4 :
case TYPE_IVEC4 :
case TYPE_UVEC4 :
case TYPE_VEC4 : {
int l = ident . length ( ) ;
2017-03-05 16:44:50 +01:00
if ( l = = 1 ) {
member_type = DataType ( dt - 3 ) ;
} else if ( l = = 2 ) {
member_type = DataType ( dt - 2 ) ;
} else if ( l = = 3 ) {
member_type = DataType ( dt - 1 ) ;
} else if ( l = = 4 ) {
member_type = dt ;
2016-10-03 21:33:42 +02:00
} else {
2017-03-05 16:44:50 +01:00
ok = false ;
2016-10-03 21:33:42 +02:00
break ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
const CharType * c = ident . ptr ( ) ;
for ( int i = 0 ; i < l ; i + + ) {
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
switch ( c [ i ] ) {
2016-10-03 21:33:42 +02:00
case ' r ' :
case ' g ' :
case ' b ' :
case ' a ' :
2020-02-13 15:50:20 +01:00
if ( position_symbols . size ( ) > 0 | | texture_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! color_symbols . has ( c [ i ] ) ) {
color_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
break ;
2016-10-03 21:33:42 +02:00
case ' x ' :
case ' y ' :
case ' z ' :
case ' w ' :
2020-02-13 15:50:20 +01:00
if ( color_symbols . size ( ) > 0 | | texture_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! position_symbols . has ( c [ i ] ) ) {
position_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
break ;
case ' s ' :
case ' t ' :
case ' p ' :
case ' q ' :
if ( color_symbols . size ( ) > 0 | | position_symbols . size ( ) > 0 ) {
mix_error = true ;
break ;
}
if ( ! texture_symbols . has ( c [ i ] ) ) {
texture_symbols . insert ( c [ i ] ) ;
} else {
repeated = true ;
}
2016-10-03 21:33:42 +02:00
break ;
default :
2017-03-05 16:44:50 +01:00
ok = false ;
2016-10-03 21:33:42 +02:00
break ;
}
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
} break ;
2017-04-07 04:36:37 +02:00
2017-06-17 16:03:48 +02:00
default : {
ok = false ;
}
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2020-02-13 15:50:20 +01:00
if ( mix_error ) {
_set_error ( " Cannot combine symbols from different sets in expression . " + ident ) ;
return NULL ;
}
2014-02-10 02:10:30 +01:00
2020-02-13 15:50:20 +01:00
if ( ! ok ) {
2020-01-17 20:35:22 +01:00
_set_error ( " Invalid member for " + ( dt = = TYPE_STRUCT ? st : get_datatype_name ( dt ) ) + " expression: . " + ident ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
MemberNode * mn = alloc_node < MemberNode > ( ) ;
2017-03-05 16:44:50 +01:00
mn - > basetype = dt ;
2020-02-12 21:16:47 +01:00
mn - > basetype_const = is_const ;
2017-03-05 16:44:50 +01:00
mn - > datatype = member_type ;
2020-01-17 20:35:22 +01:00
mn - > base_struct_name = st ;
mn - > struct_name = member_struct_name ;
2020-02-11 20:03:04 +01:00
mn - > array_size = array_size ;
2017-03-05 16:44:50 +01:00
mn - > name = ident ;
mn - > owner = expr ;
2020-02-13 15:50:20 +01:00
mn - > has_swizzling_duplicates = repeated ;
2020-02-11 20:03:04 +01:00
if ( array_size > 0 ) {
tk = _get_token ( ) ;
if ( tk . type = = TK_PERIOD ) {
_set_error ( " Nested array length() is not yet implemented " ) ;
return NULL ;
} else if ( tk . type = = TK_BRACKET_OPEN ) {
Node * index_expression = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! index_expression )
return NULL ;
if ( index_expression - > get_datatype ( ) ! = TYPE_INT & & index_expression - > get_datatype ( ) ! = TYPE_UINT ) {
_set_error ( " Only integer expressions are allowed for indexing " ) ;
return NULL ;
}
if ( index_expression - > type = = Node : : TYPE_CONSTANT ) {
ConstantNode * cnode = ( ConstantNode * ) index_expression ;
if ( cnode ) {
if ( ! cnode - > values . empty ( ) ) {
int value = cnode - > values [ 0 ] . sint ;
if ( value < 0 | | value > = array_size ) {
_set_error ( vformat ( " Index [%s] out of range [%s..%s] " , value , 0 , array_size - 1 ) ) ;
return NULL ;
}
}
}
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return NULL ;
}
mn - > index_expression = index_expression ;
} else {
_set_error ( " Expected '[' or '.' " ) ;
return NULL ;
}
}
2017-03-05 16:44:50 +01:00
expr = mn ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
//todo
//member (period) has priority over any operator
//creates a subindexing expression in place
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
/*} else if (tk.type==TK_BRACKET_OPEN) {
2016-10-03 21:33:42 +02:00
//todo
//subindexing has priority over any operator
//creates a subindexing expression in place
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
*/
2017-04-07 04:36:37 +02:00
} else if ( tk . type = = TK_BRACKET_OPEN ) {
Node * index = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2017-10-16 21:55:42 +02:00
if ( ! index )
return NULL ;
2017-04-07 04:36:37 +02:00
if ( index - > get_datatype ( ) ! = TYPE_INT & & index - > get_datatype ( ) ! = TYPE_UINT ) {
_set_error ( " Only integer datatypes are allowed for indexing " ) ;
return NULL ;
}
2017-09-01 22:33:39 +02:00
DataType member_type = TYPE_VOID ;
2017-04-07 04:36:37 +02:00
switch ( expr - > get_datatype ( ) ) {
case TYPE_BVEC2 :
case TYPE_VEC2 :
case TYPE_IVEC2 :
case TYPE_UVEC2 :
case TYPE_MAT2 :
if ( index - > type = = Node : : TYPE_CONSTANT ) {
uint32_t index_constant = static_cast < ConstantNode * > ( index ) - > values [ 0 ] . uint ;
if ( index_constant > = 2 ) {
_set_error ( " Index out of range (0-1) " ) ;
return NULL ;
}
}
2018-04-21 16:35:23 +02:00
2017-04-07 04:36:37 +02:00
switch ( expr - > get_datatype ( ) ) {
case TYPE_BVEC2 : member_type = TYPE_BOOL ; break ;
case TYPE_VEC2 : member_type = TYPE_FLOAT ; break ;
case TYPE_IVEC2 : member_type = TYPE_INT ; break ;
case TYPE_UVEC2 : member_type = TYPE_UINT ; break ;
case TYPE_MAT2 : member_type = TYPE_VEC2 ; break ;
2018-09-26 13:13:56 +02:00
default : break ;
2017-04-07 04:36:37 +02:00
}
break ;
case TYPE_BVEC3 :
case TYPE_VEC3 :
case TYPE_IVEC3 :
case TYPE_UVEC3 :
case TYPE_MAT3 :
if ( index - > type = = Node : : TYPE_CONSTANT ) {
uint32_t index_constant = static_cast < ConstantNode * > ( index ) - > values [ 0 ] . uint ;
if ( index_constant > = 3 ) {
_set_error ( " Index out of range (0-2) " ) ;
return NULL ;
}
}
2018-04-21 16:35:23 +02:00
2017-04-07 04:36:37 +02:00
switch ( expr - > get_datatype ( ) ) {
case TYPE_BVEC3 : member_type = TYPE_BOOL ; break ;
case TYPE_VEC3 : member_type = TYPE_FLOAT ; break ;
case TYPE_IVEC3 : member_type = TYPE_INT ; break ;
case TYPE_UVEC3 : member_type = TYPE_UINT ; break ;
case TYPE_MAT3 : member_type = TYPE_VEC3 ; break ;
2018-09-26 13:13:56 +02:00
default : break ;
2017-04-07 04:36:37 +02:00
}
break ;
case TYPE_BVEC4 :
case TYPE_VEC4 :
case TYPE_IVEC4 :
case TYPE_UVEC4 :
case TYPE_MAT4 :
if ( index - > type = = Node : : TYPE_CONSTANT ) {
uint32_t index_constant = static_cast < ConstantNode * > ( index ) - > values [ 0 ] . uint ;
if ( index_constant > = 4 ) {
_set_error ( " Index out of range (0-3) " ) ;
return NULL ;
}
}
2018-04-21 16:35:23 +02:00
2017-04-07 04:36:37 +02:00
switch ( expr - > get_datatype ( ) ) {
case TYPE_BVEC4 : member_type = TYPE_BOOL ; break ;
case TYPE_VEC4 : member_type = TYPE_FLOAT ; break ;
case TYPE_IVEC4 : member_type = TYPE_INT ; break ;
case TYPE_UVEC4 : member_type = TYPE_UINT ; break ;
case TYPE_MAT4 : member_type = TYPE_VEC4 ; break ;
2018-09-26 13:13:56 +02:00
default : break ;
2017-04-07 04:36:37 +02:00
}
break ;
default : {
2020-02-11 20:03:04 +01:00
_set_error ( " Object of type ' " + ( expr - > get_datatype ( ) = = TYPE_STRUCT ? expr - > get_datatype_name ( ) : get_datatype_name ( expr - > get_datatype ( ) ) ) + " ' can't be indexed " ) ;
2017-04-07 04:36:37 +02:00
return NULL ;
}
}
OperatorNode * op = alloc_node < OperatorNode > ( ) ;
op - > op = OP_INDEX ;
op - > return_cache = member_type ;
op - > arguments . push_back ( expr ) ;
op - > arguments . push_back ( index ) ;
expr = op ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' after indexing expression " ) ;
return NULL ;
}
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_OP_INCREMENT | | tk . type = = TK_OP_DECREMENT ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
OperatorNode * op = alloc_node < OperatorNode > ( ) ;
2017-03-05 16:44:50 +01:00
op - > op = tk . type = = TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT ;
2016-10-03 21:33:42 +02:00
op - > arguments . push_back ( expr ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( ! _validate_operator ( op , & op - > return_cache ) ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Invalid base type for increment/decrement operator " ) ;
return NULL ;
}
2017-12-15 22:23:16 +01:00
if ( ! _validate_assign ( expr , p_builtin_types ) ) {
_set_error ( " Invalid use of increment/decrement operator in constant expression. " ) ;
return NULL ;
}
2017-03-05 16:44:50 +01:00
expr = op ;
} else {
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
_set_tkpos ( pos2 ) ;
2016-10-03 21:33:42 +02:00
break ;
}
}
2014-02-10 02:10:30 +01:00
2014-09-18 04:23:42 +02:00
Expression e ;
2017-03-05 16:44:50 +01:00
e . is_op = false ;
e . node = expr ;
2014-09-18 04:23:42 +02:00
expression . push_back ( e ) ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
pos = _get_tkpos ( ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( is_token_operator ( tk . type ) ) {
2014-02-10 02:10:30 +01:00
2014-09-18 04:23:42 +02:00
Expression o ;
2017-03-05 16:44:50 +01:00
o . is_op = true ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
switch ( tk . type ) {
2016-10-03 21:33:42 +02:00
case TK_OP_EQUAL : o . op = OP_EQUAL ; break ;
case TK_OP_NOT_EQUAL : o . op = OP_NOT_EQUAL ; break ;
case TK_OP_LESS : o . op = OP_LESS ; break ;
case TK_OP_LESS_EQUAL : o . op = OP_LESS_EQUAL ; break ;
case TK_OP_GREATER : o . op = OP_GREATER ; break ;
case TK_OP_GREATER_EQUAL : o . op = OP_GREATER_EQUAL ; break ;
case TK_OP_AND : o . op = OP_AND ; break ;
case TK_OP_OR : o . op = OP_OR ; break ;
case TK_OP_ADD : o . op = OP_ADD ; break ;
case TK_OP_SUB : o . op = OP_SUB ; break ;
case TK_OP_MUL : o . op = OP_MUL ; break ;
case TK_OP_DIV : o . op = OP_DIV ; break ;
case TK_OP_MOD : o . op = OP_MOD ; break ;
case TK_OP_SHIFT_LEFT : o . op = OP_SHIFT_LEFT ; break ;
case TK_OP_SHIFT_RIGHT : o . op = OP_SHIFT_RIGHT ; break ;
case TK_OP_ASSIGN : o . op = OP_ASSIGN ; break ;
case TK_OP_ASSIGN_ADD : o . op = OP_ASSIGN_ADD ; break ;
case TK_OP_ASSIGN_SUB : o . op = OP_ASSIGN_SUB ; break ;
case TK_OP_ASSIGN_MUL : o . op = OP_ASSIGN_MUL ; break ;
case TK_OP_ASSIGN_DIV : o . op = OP_ASSIGN_DIV ; break ;
case TK_OP_ASSIGN_MOD : o . op = OP_ASSIGN_MOD ; break ;
case TK_OP_ASSIGN_SHIFT_LEFT : o . op = OP_ASSIGN_SHIFT_LEFT ; break ;
case TK_OP_ASSIGN_SHIFT_RIGHT : o . op = OP_ASSIGN_SHIFT_RIGHT ; break ;
case TK_OP_ASSIGN_BIT_AND : o . op = OP_ASSIGN_BIT_AND ; break ;
case TK_OP_ASSIGN_BIT_OR : o . op = OP_ASSIGN_BIT_OR ; break ;
case TK_OP_ASSIGN_BIT_XOR : o . op = OP_ASSIGN_BIT_XOR ; break ;
case TK_OP_BIT_AND : o . op = OP_BIT_AND ; break ;
2017-03-05 16:44:50 +01:00
case TK_OP_BIT_OR : o . op = OP_BIT_OR ; break ;
2016-10-03 21:33:42 +02:00
case TK_OP_BIT_XOR : o . op = OP_BIT_XOR ; break ;
case TK_QUESTION : o . op = OP_SELECT_IF ; break ;
case TK_COLON : o . op = OP_SELECT_ELSE ; break ;
default : {
2017-03-05 16:44:50 +01:00
_set_error ( " Invalid token for operator: " + get_token_text ( tk ) ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
}
2016-10-07 16:31:18 +02:00
}
2016-10-03 21:33:42 +02:00
2014-09-18 04:23:42 +02:00
expression . push_back ( o ) ;
2016-10-03 21:33:42 +02:00
2014-02-10 02:10:30 +01:00
} else {
2016-10-07 16:31:18 +02:00
_set_tkpos ( pos ) ; //something else, so rollback and end
2014-02-10 02:10:30 +01:00
break ;
}
}
/* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
2017-03-05 16:44:50 +01:00
while ( expression . size ( ) > 1 ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int next_op = - 1 ;
int min_priority = 0xFFFFF ;
bool is_unary = false ;
bool is_ternary = false ;
2014-09-18 04:23:42 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < expression . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2014-09-18 04:23:42 +02:00
if ( ! expression [ i ] . is_op ) {
continue ;
}
2017-03-05 16:44:50 +01:00
bool unary = false ;
bool ternary = false ;
2014-02-10 02:10:30 +01:00
int priority ;
2017-03-05 16:44:50 +01:00
switch ( expression [ i ] . op ) {
case OP_EQUAL : priority = 8 ; break ;
case OP_NOT_EQUAL : priority = 8 ; break ;
case OP_LESS : priority = 7 ; break ;
case OP_LESS_EQUAL : priority = 7 ; break ;
case OP_GREATER : priority = 7 ; break ;
case OP_GREATER_EQUAL : priority = 7 ; break ;
case OP_AND : priority = 12 ; break ;
case OP_OR : priority = 14 ; break ;
case OP_NOT :
priority = 3 ;
unary = true ;
break ;
case OP_NEGATE :
priority = 3 ;
unary = true ;
break ;
case OP_ADD : priority = 5 ; break ;
case OP_SUB : priority = 5 ; break ;
case OP_MUL : priority = 4 ; break ;
case OP_DIV : priority = 4 ; break ;
case OP_MOD : priority = 4 ; break ;
case OP_SHIFT_LEFT : priority = 6 ; break ;
case OP_SHIFT_RIGHT : priority = 6 ; break ;
case OP_ASSIGN : priority = 16 ; break ;
case OP_ASSIGN_ADD : priority = 16 ; break ;
case OP_ASSIGN_SUB : priority = 16 ; break ;
case OP_ASSIGN_MUL : priority = 16 ; break ;
case OP_ASSIGN_DIV : priority = 16 ; break ;
case OP_ASSIGN_MOD : priority = 16 ; break ;
case OP_ASSIGN_SHIFT_LEFT : priority = 16 ; break ;
case OP_ASSIGN_SHIFT_RIGHT : priority = 16 ; break ;
case OP_ASSIGN_BIT_AND : priority = 16 ; break ;
case OP_ASSIGN_BIT_OR : priority = 16 ; break ;
case OP_ASSIGN_BIT_XOR : priority = 16 ; break ;
case OP_BIT_AND : priority = 9 ; break ;
case OP_BIT_OR : priority = 11 ; break ;
case OP_BIT_XOR : priority = 10 ; break ;
case OP_BIT_INVERT :
priority = 3 ;
unary = true ;
break ;
case OP_INCREMENT :
priority = 3 ;
unary = true ;
break ;
case OP_DECREMENT :
priority = 3 ;
unary = true ;
break ;
case OP_SELECT_IF :
priority = 15 ;
ternary = true ;
break ;
case OP_SELECT_ELSE :
priority = 15 ;
ternary = true ;
break ;
default :
ERR_FAIL_V ( NULL ) ; //unexpected operator
}
if ( priority < min_priority ) {
2014-02-10 02:10:30 +01:00
// < is used for left to right (default)
// <= is used for right to left
2017-03-05 16:44:50 +01:00
next_op = i ;
min_priority = priority ;
is_unary = unary ;
is_ternary = ternary ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( next_op = = - 1 , NULL ) ;
2014-02-10 02:10:30 +01:00
// OK! create operator..
2014-09-18 04:23:42 +02:00
// OK! create operator..
if ( is_unary ) {
2017-03-05 16:44:50 +01:00
int expr_pos = next_op ;
while ( expression [ expr_pos ] . is_op ) {
2014-09-18 04:23:42 +02:00
expr_pos + + ;
2017-03-05 16:44:50 +01:00
if ( expr_pos = = expression . size ( ) ) {
2014-09-18 04:23:42 +02:00
//can happen..
2018-04-22 19:36:01 +02:00
_set_error ( " Unexpected end of expression... " ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
2014-09-18 04:23:42 +02:00
}
}
//consecutively do unary opeators
2017-03-05 16:44:50 +01:00
for ( int i = expr_pos - 1 ; i > = next_op ; i - - ) {
2014-09-18 04:23:42 +02:00
2016-10-03 21:33:42 +02:00
OperatorNode * op = alloc_node < OperatorNode > ( ) ;
2017-03-05 16:44:50 +01:00
op - > op = expression [ i ] . op ;
2017-12-15 22:23:16 +01:00
if ( ( op - > op = = OP_INCREMENT | | op - > op = = OP_DECREMENT ) & & ! _validate_assign ( expression [ i + 1 ] . node , p_builtin_types ) ) {
_set_error ( " Can't use increment/decrement operator in constant expression. " ) ;
return NULL ;
}
2017-03-05 16:44:50 +01:00
op - > arguments . push_back ( expression [ i + 1 ] . node ) ;
2016-10-03 21:33:42 +02:00
2018-07-25 03:11:03 +02:00
expression . write [ i ] . is_op = false ;
expression . write [ i ] . node = op ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
if ( ! _validate_operator ( op , & op - > return_cache ) ) {
2014-09-18 04:23:42 +02:00
String at ;
2019-02-12 21:10:08 +01:00
for ( int j = 0 ; j < op - > arguments . size ( ) ; j + + ) {
if ( j > 0 )
2017-03-05 16:44:50 +01:00
at + = " and " ;
2019-02-12 21:10:08 +01:00
at + = get_datatype_name ( op - > arguments [ j ] - > get_datatype ( ) ) ;
2014-09-18 04:23:42 +02:00
}
2017-03-05 16:44:50 +01:00
_set_error ( " Invalid arguments to unary operator ' " + get_operator_text ( op - > op ) + " ' : " + at ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
2014-09-18 04:23:42 +02:00
}
2017-03-05 16:44:50 +01:00
expression . remove ( i + 1 ) ;
2014-09-18 04:23:42 +02:00
}
2016-10-03 21:33:42 +02:00
} else if ( is_ternary ) {
2014-09-18 04:23:42 +02:00
2017-03-05 16:44:50 +01:00
if ( next_op < 1 | | next_op > = ( expression . size ( ) - 1 ) ) {
2018-04-22 19:36:01 +02:00
_set_error ( " Parser bug... " ) ;
2016-10-03 21:33:42 +02:00
ERR_FAIL_V ( NULL ) ;
2014-09-18 04:23:42 +02:00
}
2017-03-05 16:44:50 +01:00
if ( next_op + 2 > = expression . size ( ) | | ! expression [ next_op + 2 ] . is_op | | expression [ next_op + 2 ] . op ! = OP_SELECT_ELSE ) {
2018-04-17 14:20:26 +02:00
_set_error ( " Missing matching ':' for select operator " ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
}
2014-09-18 04:23:42 +02:00
2016-10-03 21:33:42 +02:00
OperatorNode * op = alloc_node < OperatorNode > ( ) ;
2017-03-05 16:44:50 +01:00
op - > op = expression [ next_op ] . op ;
op - > arguments . push_back ( expression [ next_op - 1 ] . node ) ;
op - > arguments . push_back ( expression [ next_op + 1 ] . node ) ;
op - > arguments . push_back ( expression [ next_op + 3 ] . node ) ;
2016-10-03 21:33:42 +02:00
2018-07-25 03:11:03 +02:00
expression . write [ next_op - 1 ] . is_op = false ;
expression . write [ next_op - 1 ] . node = op ;
2017-03-05 16:44:50 +01:00
if ( ! _validate_operator ( op , & op - > return_cache ) ) {
2016-10-03 21:33:42 +02:00
String at ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < op - > arguments . size ( ) ; i + + ) {
if ( i > 0 )
at + = " and " ;
at + = get_datatype_name ( op - > arguments [ i ] - > get_datatype ( ) ) ;
2016-10-03 21:33:42 +02:00
}
2017-03-05 16:44:50 +01:00
_set_error ( " Invalid argument to ternary ?: operator: " + at ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 4 ; i + + ) {
2016-10-03 21:33:42 +02:00
expression . remove ( next_op ) ;
}
2014-09-18 04:23:42 +02:00
} else {
2017-03-05 16:44:50 +01:00
if ( next_op < 1 | | next_op > = ( expression . size ( ) - 1 ) ) {
2018-04-22 19:36:01 +02:00
_set_error ( " Parser bug... " ) ;
2016-10-03 21:33:42 +02:00
ERR_FAIL_V ( NULL ) ;
2014-09-18 04:23:42 +02:00
}
2016-10-03 21:33:42 +02:00
OperatorNode * op = alloc_node < OperatorNode > ( ) ;
2017-03-05 16:44:50 +01:00
op - > op = expression [ next_op ] . op ;
2014-09-18 04:23:42 +02:00
2017-03-05 16:44:50 +01:00
if ( expression [ next_op - 1 ] . is_op ) {
2014-09-18 04:23:42 +02:00
2018-04-22 19:36:01 +02:00
_set_error ( " Parser bug... " ) ;
2016-10-03 21:33:42 +02:00
ERR_FAIL_V ( NULL ) ;
2014-09-18 04:23:42 +02:00
}
2018-07-29 17:17:45 +02:00
if ( _is_operator_assign ( op - > op ) ) {
2017-12-15 22:23:16 +01:00
2018-07-29 17:17:45 +02:00
String assign_message ;
if ( ! _validate_assign ( expression [ next_op - 1 ] . node , p_builtin_types , & assign_message ) ) {
_set_error ( assign_message ) ;
return NULL ;
}
2017-12-15 22:23:16 +01:00
}
2017-03-05 16:44:50 +01:00
if ( expression [ next_op + 1 ] . is_op ) {
2014-09-18 04:23:42 +02:00
// this is not invalid and can really appear
// but it becomes invalid anyway because no binary op
2017-09-02 16:19:06 +02:00
// can be followed by a unary op in a valid combination,
2017-03-24 21:45:31 +01:00
// due to how precedence works, unaries will always disappear first
2014-09-18 04:23:42 +02:00
2018-04-22 19:36:01 +02:00
_set_error ( " Parser bug... " ) ;
2014-09-18 04:23:42 +02:00
}
2017-03-05 16:44:50 +01:00
op - > arguments . push_back ( expression [ next_op - 1 ] . node ) ; //expression goes as left
op - > arguments . push_back ( expression [ next_op + 1 ] . node ) ; //next expression goes as right
2018-07-25 03:11:03 +02:00
expression . write [ next_op - 1 ] . node = op ;
2014-09-18 04:23:42 +02:00
//replace all 3 nodes by this operator and make it an expression
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
if ( ! _validate_operator ( op , & op - > return_cache ) ) {
2014-09-18 04:23:42 +02:00
String at ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < op - > arguments . size ( ) ; i + + ) {
if ( i > 0 )
at + = " and " ;
2020-01-17 20:35:22 +01:00
if ( op - > arguments [ i ] - > get_datatype ( ) = = TYPE_STRUCT ) {
at + = op - > arguments [ i ] - > get_datatype_name ( ) ;
} else {
at + = get_datatype_name ( op - > arguments [ i ] - > get_datatype ( ) ) ;
}
2014-09-18 04:23:42 +02:00
}
2017-03-05 16:44:50 +01:00
_set_error ( " Invalid arguments to operator ' " + get_operator_text ( op - > op ) + " ' : " + at ) ;
2016-10-03 21:33:42 +02:00
return NULL ;
2014-09-18 04:23:42 +02:00
}
2016-10-03 21:33:42 +02:00
2014-09-18 04:23:42 +02:00
expression . remove ( next_op ) ;
expression . remove ( next_op ) ;
}
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return expression [ 0 ] . node ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ShaderLanguage : : Node * ShaderLanguage : : _reduce_expression ( BlockNode * p_block , ShaderLanguage : : Node * p_node ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_node - > type ! = Node : : TYPE_OPERATOR )
2016-10-03 21:33:42 +02:00
return p_node ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
//for now only reduce simple constructors
2017-03-05 16:44:50 +01:00
OperatorNode * op = static_cast < OperatorNode * > ( p_node ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( op - > op = = OP_CONSTRUCT ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( op - > arguments [ 0 ] - > type ! = Node : : TYPE_VARIABLE , p_node ) ;
2016-10-07 16:31:18 +02:00
2018-08-31 13:11:13 +02:00
DataType type = op - > get_datatype ( ) ;
DataType base = get_scalar_type ( type ) ;
int cardinality = get_cardinality ( type ) ;
2016-10-07 16:31:18 +02:00
Vector < ConstantNode : : Value > values ;
2017-03-05 16:44:50 +01:00
for ( int i = 1 ; i < op - > arguments . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
op - > arguments . write [ i ] = _reduce_expression ( p_block , op - > arguments [ i ] ) ;
2017-03-05 16:44:50 +01:00
if ( op - > arguments [ i ] - > type = = Node : : TYPE_CONSTANT ) {
ConstantNode * cn = static_cast < ConstantNode * > ( op - > arguments [ i ] ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( get_scalar_type ( cn - > datatype ) = = base ) {
2018-08-31 13:11:13 +02:00
for ( int j = 0 ; j < cn - > values . size ( ) ; j + + ) {
values . push_back ( cn - > values [ j ] ) ;
}
2017-03-05 16:44:50 +01:00
} else if ( get_scalar_type ( cn - > datatype ) = = cn - > datatype ) {
2016-10-07 16:31:18 +02:00
ConstantNode : : Value v ;
2017-03-05 16:44:50 +01:00
if ( ! convert_constant ( cn , base , & v ) ) {
2016-10-07 16:31:18 +02:00
return p_node ;
}
values . push_back ( v ) ;
2016-10-03 21:33:42 +02:00
} else {
2016-10-07 16:31:18 +02:00
return p_node ;
2016-10-03 21:33:42 +02:00
}
2016-10-07 16:31:18 +02:00
} else {
return p_node ;
2014-02-10 02:10:30 +01:00
}
}
2018-08-31 13:11:13 +02:00
if ( values . size ( ) = = 1 ) {
if ( type > = TYPE_MAT2 & & type < = TYPE_MAT4 ) {
ConstantNode : : Value value = values [ 0 ] ;
ConstantNode : : Value zero ;
zero . real = 0.0f ;
int size = 2 + ( type - TYPE_MAT2 ) ;
values . clear ( ) ;
for ( int i = 0 ; i < size ; i + + ) {
for ( int j = 0 ; j < size ; j + + ) {
values . push_back ( i = = j ? value : zero ) ;
}
}
} else {
2018-09-19 15:28:19 +02:00
ConstantNode : : Value value = values [ 0 ] ;
2018-08-31 13:11:13 +02:00
for ( int i = 1 ; i < cardinality ; i + + ) {
2018-09-19 15:28:19 +02:00
values . push_back ( value ) ;
2018-08-31 13:11:13 +02:00
}
}
} else if ( values . size ( ) ! = cardinality ) {
ERR_PRINT ( " Failed to reduce expression, values and cardinality mismatch. " ) ;
return p_node ;
}
2017-03-05 16:44:50 +01:00
ConstantNode * cn = alloc_node < ConstantNode > ( ) ;
cn - > datatype = op - > get_datatype ( ) ;
cn - > values = values ;
2016-10-07 16:31:18 +02:00
return cn ;
2017-03-05 16:44:50 +01:00
} else if ( op - > op = = OP_NEGATE ) {
2014-02-10 02:10:30 +01:00
2018-07-25 03:11:03 +02:00
op - > arguments . write [ 0 ] = _reduce_expression ( p_block , op - > arguments [ 0 ] ) ;
2017-03-05 16:44:50 +01:00
if ( op - > arguments [ 0 ] - > type = = Node : : TYPE_CONSTANT ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ConstantNode * cn = static_cast < ConstantNode * > ( op - > arguments [ 0 ] ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
DataType base = get_scalar_type ( cn - > datatype ) ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
Vector < ConstantNode : : Value > values ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < cn - > values . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
ConstantNode : : Value nv ;
2017-03-05 16:44:50 +01:00
switch ( base ) {
2016-10-07 16:31:18 +02:00
case TYPE_BOOL : {
2017-03-05 16:44:50 +01:00
nv . boolean = ! cn - > values [ i ] . boolean ;
2016-10-07 16:31:18 +02:00
} break ;
case TYPE_INT : {
2017-03-05 16:44:50 +01:00
nv . sint = - cn - > values [ i ] . sint ;
2016-10-07 16:31:18 +02:00
} break ;
case TYPE_UINT : {
2019-11-18 13:45:01 +01:00
// Intentionally wrap the unsigned int value, because GLSL does.
nv . uint = 0 - cn - > values [ i ] . uint ;
2016-10-07 16:31:18 +02:00
} break ;
case TYPE_FLOAT : {
2017-03-05 16:44:50 +01:00
nv . real = - cn - > values [ i ] . real ;
2016-10-07 16:31:18 +02:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-10-07 16:31:18 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
values . push_back ( nv ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
cn - > values = values ;
2016-10-03 21:33:42 +02:00
return cn ;
}
}
return p_node ;
2014-02-10 02:10:30 +01:00
}
2017-12-15 22:23:16 +01:00
ShaderLanguage : : Node * ShaderLanguage : : _parse_and_reduce_expression ( BlockNode * p_block , const Map < StringName , BuiltInInfo > & p_builtin_types ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ShaderLanguage : : Node * expr = _parse_expression ( p_block , p_builtin_types ) ;
2016-10-07 16:31:18 +02:00
if ( ! expr ) //errored
return NULL ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
expr = _reduce_expression ( p_block , expr ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return expr ;
}
2014-02-10 02:10:30 +01:00
2017-12-15 22:23:16 +01:00
Error ShaderLanguage : : _parse_block ( BlockNode * p_block , const Map < StringName , BuiltInInfo > & p_builtin_types , bool p_just_one , bool p_can_break , bool p_can_continue ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
TkPos pos = _get_tkpos ( ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
Token tk = _get_token ( ) ;
2019-08-14 13:22:25 +02:00
if ( p_block & & p_block - > block_type = = BlockNode : : BLOCK_TYPE_SWITCH ) {
if ( tk . type ! = TK_CF_CASE & & tk . type ! = TK_CF_DEFAULT & & tk . type ! = TK_CURLY_BRACKET_CLOSE ) {
_set_error ( " Switch may contains only case and default blocks " ) ;
return ERR_PARSE_ERROR ;
}
}
2020-01-17 20:35:22 +01:00
bool is_struct = shader - > structs . has ( tk . text ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_CURLY_BRACKET_CLOSE ) { //end of block
2016-10-03 21:33:42 +02:00
if ( p_just_one ) {
_set_error ( " Unexpected '}' " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return OK ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
} else if ( tk . type = = TK_CONST | | is_token_precision ( tk . type ) | | is_token_nonvoid_datatype ( tk . type ) | | is_struct ) {
String struct_name = " " ;
if ( is_struct ) {
struct_name = tk . text ;
}
2019-08-05 09:35:53 +02:00
bool is_const = false ;
if ( tk . type = = TK_CONST ) {
is_const = true ;
tk = _get_token ( ) ;
2020-01-17 20:35:22 +01:00
if ( ! is_struct ) {
is_struct = shader - > structs . has ( tk . text ) ; // check again.
struct_name = tk . text ;
}
2019-08-05 09:35:53 +02:00
}
2017-03-05 16:44:50 +01:00
DataPrecision precision = PRECISION_DEFAULT ;
2016-10-03 21:33:42 +02:00
if ( is_token_precision ( tk . type ) ) {
2017-03-05 16:44:50 +01:00
precision = get_token_precision ( tk . type ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2020-01-17 20:35:22 +01:00
if ( ! is_struct ) {
is_struct = shader - > structs . has ( tk . text ) ; // check again.
}
if ( is_struct & & precision ! = PRECISION_DEFAULT ) {
_set_error ( " Precision modifier cannot be used on structs. " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
if ( ! is_token_nonvoid_datatype ( tk . type ) ) {
2018-04-17 14:20:26 +02:00
_set_error ( " Expected datatype after precision " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( ! is_struct ) {
if ( ! is_token_variable_datatype ( tk . type ) ) {
_set_error ( " Invalid data type for variable (samplers not allowed) " ) ;
return ERR_PARSE_ERROR ;
}
2018-11-12 12:36:26 +01:00
}
2020-01-17 20:35:22 +01:00
DataType type = is_struct ? TYPE_STRUCT : get_token_datatype ( tk . type ) ;
2014-02-10 02:10:30 +01:00
2020-01-20 13:34:25 +01:00
if ( _validate_datatype ( type ) ! = OK ) {
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2019-07-10 18:52:50 +02:00
Node * vardecl = NULL ;
2017-09-05 20:22:33 +02:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_IDENTIFIER ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected identifier after type " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
StringName name = tk . text ;
2019-10-06 16:24:30 +02:00
ShaderLanguage : : IdentifierType itype ;
if ( _find_identifier ( p_block , p_builtin_types , name , ( ShaderLanguage : : DataType * ) 0 , & itype ) ) {
if ( itype ! = IDENTIFIER_FUNCTION ) {
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
BlockNode : : Variable var ;
2017-03-05 16:44:50 +01:00
var . type = type ;
var . precision = precision ;
var . line = tk_line ;
2019-07-10 18:52:50 +02:00
var . array_size = 0 ;
2019-08-05 09:35:53 +02:00
var . is_const = is_const ;
2020-01-17 20:35:22 +01:00
var . struct_name = struct_name ;
2017-09-05 20:22:33 +02:00
2019-07-10 18:52:50 +02:00
tk = _get_token ( ) ;
2017-09-05 20:22:33 +02:00
2019-07-10 18:52:50 +02:00
if ( tk . type = = TK_BRACKET_OPEN ) {
2019-07-15 17:47:22 +02:00
bool unknown_size = false ;
2017-09-05 20:22:33 +02:00
2020-01-16 09:46:11 +01:00
if ( VisualServer : : get_singleton ( ) - > is_low_end ( ) & & is_const ) {
_set_error ( " Local const arrays are supported only on high-end platform! " ) ;
return ERR_PARSE_ERROR ;
}
2019-07-10 18:52:50 +02:00
ArrayDeclarationNode * node = alloc_node < ArrayDeclarationNode > ( ) ;
2020-01-17 20:35:22 +01:00
if ( is_struct ) {
node - > struct_name = struct_name ;
node - > datatype = TYPE_STRUCT ;
} else {
node - > datatype = type ;
}
2019-07-10 18:52:50 +02:00
node - > precision = precision ;
2019-08-05 09:35:53 +02:00
node - > is_const = is_const ;
2019-07-10 18:52:50 +02:00
vardecl = ( Node * ) node ;
ArrayDeclarationNode : : Declaration decl ;
decl . name = name ;
decl . size = 0U ;
tk = _get_token ( ) ;
2019-07-15 17:47:22 +02:00
if ( tk . type = = TK_BRACKET_CLOSE ) {
unknown_size = true ;
} else {
2019-07-10 18:52:50 +02:00
2019-07-15 17:47:22 +02:00
if ( tk . type ! = TK_INT_CONSTANT | | ( ( int ) tk . constant ) < = 0 ) {
_set_error ( " Expected integer constant > 0 or ']' " ) ;
return ERR_PARSE_ERROR ;
}
2019-07-10 18:52:50 +02:00
2019-08-13 15:19:14 +02:00
decl . size = ( ( uint32_t ) tk . constant ) ;
2019-07-15 17:47:22 +02:00
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return ERR_PARSE_ERROR ;
}
var . array_size = decl . size ;
2019-07-10 18:52:50 +02:00
}
2019-07-15 17:47:22 +02:00
bool full_def = false ;
2019-07-10 18:52:50 +02:00
tk = _get_token ( ) ;
2019-07-15 17:47:22 +02:00
if ( tk . type = = TK_OP_ASSIGN ) {
2020-01-16 09:46:11 +01:00
if ( VisualServer : : get_singleton ( ) - > is_low_end ( ) ) {
_set_error ( " Array initialization is supported only on high-end platform! " ) ;
return ERR_PARSE_ERROR ;
}
2019-07-15 17:47:22 +02:00
tk = _get_token ( ) ;
if ( tk . type ! = TK_CURLY_BRACKET_OPEN ) {
if ( unknown_size ) {
_set_error ( " Expected '{' " ) ;
return ERR_PARSE_ERROR ;
}
full_def = true ;
DataPrecision precision2 = PRECISION_DEFAULT ;
if ( is_token_precision ( tk . type ) ) {
precision2 = get_token_precision ( tk . type ) ;
tk = _get_token ( ) ;
2020-01-17 20:35:22 +01:00
if ( shader - > structs . has ( tk . text ) ) {
_set_error ( " Precision modifier cannot be used on structs. " ) ;
return ERR_PARSE_ERROR ;
}
2019-07-15 17:47:22 +02:00
if ( ! is_token_nonvoid_datatype ( tk . type ) ) {
_set_error ( " Expected datatype after precision " ) ;
return ERR_PARSE_ERROR ;
}
}
2020-01-17 20:35:22 +01:00
DataType type2 ;
String struct_name2 = " " ;
if ( shader - > structs . has ( tk . text ) ) {
type2 = TYPE_STRUCT ;
struct_name2 = tk . text ;
} else {
if ( ! is_token_variable_datatype ( tk . type ) ) {
_set_error ( " Invalid data type for array " ) ;
return ERR_PARSE_ERROR ;
}
type2 = get_token_datatype ( tk . type ) ;
2019-07-15 17:47:22 +02:00
}
int array_size2 = 0 ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_OPEN ) {
2020-01-18 09:41:55 +01:00
TkPos pos2 = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
array_size2 = var . array_size ;
tk = _get_token ( ) ;
} else {
_set_tkpos ( pos2 ) ;
2019-07-15 17:47:22 +02:00
2020-01-18 09:41:55 +01:00
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! n | | n - > type ! = Node : : TYPE_CONSTANT | | n - > get_datatype ( ) ! = TYPE_INT ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return ERR_PARSE_ERROR ;
}
ConstantNode * cnode = ( ConstantNode * ) n ;
if ( cnode - > values . size ( ) = = 1 ) {
array_size2 = cnode - > values [ 0 ] . sint ;
if ( array_size2 < = 0 ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return ERR_PARSE_ERROR ;
}
} else {
2019-07-15 17:47:22 +02:00
_set_error ( " Expected single integer constant > 0 " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
2020-01-18 09:41:55 +01:00
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return ERR_PARSE_ERROR ;
} else {
tk = _get_token ( ) ;
}
2019-07-15 17:47:22 +02:00
}
} else {
2020-01-18 09:41:55 +01:00
_set_error ( " Expected '[' " ) ;
2019-07-15 17:47:22 +02:00
return ERR_PARSE_ERROR ;
}
2020-01-17 20:35:22 +01:00
if ( precision ! = precision2 | | type ! = type2 | | struct_name ! = struct_name2 | | var . array_size ! = array_size2 ) {
2019-07-15 17:47:22 +02:00
String error_str = " Cannot convert from ' " ;
if ( precision2 ! = PRECISION_DEFAULT ) {
error_str + = get_precision_name ( precision2 ) ;
error_str + = " " ;
}
2020-01-17 20:35:22 +01:00
if ( type2 = = TYPE_STRUCT ) {
error_str + = struct_name2 ;
} else {
error_str + = get_datatype_name ( type2 ) ;
}
2019-07-15 17:47:22 +02:00
error_str + = " [ " ;
error_str + = itos ( array_size2 ) ;
error_str + = " ]' " ;
error_str + = " to ' " ;
if ( precision ! = PRECISION_DEFAULT ) {
error_str + = get_precision_name ( precision ) ;
error_str + = " " ;
}
2020-01-17 20:35:22 +01:00
if ( type = = TYPE_STRUCT ) {
error_str + = struct_name ;
} else {
error_str + = get_datatype_name ( type ) ;
}
2019-07-15 17:47:22 +02:00
error_str + = " [ " ;
error_str + = itos ( var . array_size ) ;
error_str + = " ]' " ;
_set_error ( error_str ) ;
return ERR_PARSE_ERROR ;
}
}
bool curly = tk . type = = TK_CURLY_BRACKET_OPEN ;
if ( unknown_size ) {
if ( ! curly ) {
_set_error ( " Expected '{' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
if ( full_def ) {
if ( curly ) {
_set_error ( " Expected '(' " ) ;
return ERR_PARSE_ERROR ;
}
}
}
if ( tk . type = = TK_PARENTHESIS_OPEN | | curly ) { // initialization
while ( true ) {
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! n ) {
return ERR_PARSE_ERROR ;
}
2019-10-06 17:05:44 +02:00
if ( node - > is_const & & n - > type = = Node : : TYPE_OPERATOR & & ( ( OperatorNode * ) n ) - > op = = OP_CALL ) {
_set_error ( " Expected constant expression " ) ;
return ERR_PARSE_ERROR ;
}
2020-01-17 20:35:22 +01:00
if ( var . type ! = n - > get_datatype ( ) | | struct_name ! = n - > get_datatype_name ( ) ) {
_set_error ( " Invalid assignment of ' " + ( n - > get_datatype ( ) = = TYPE_STRUCT ? n - > get_datatype_name ( ) : get_datatype_name ( n - > get_datatype ( ) ) ) + " ' to ' " + ( var . type = = TYPE_STRUCT ? struct_name : get_datatype_name ( var . type ) ) + " ' " ) ;
2019-07-15 17:47:22 +02:00
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_COMMA ) {
decl . initializer . push_back ( n ) ;
continue ;
} else if ( ! curly & & tk . type = = TK_PARENTHESIS_CLOSE ) {
decl . initializer . push_back ( n ) ;
break ;
} else if ( curly & & tk . type = = TK_CURLY_BRACKET_CLOSE ) {
decl . initializer . push_back ( n ) ;
break ;
} else {
if ( curly )
_set_error ( " Expected '}' or ',' " ) ;
else
_set_error ( " Expected ')' or ',' " ) ;
return ERR_PARSE_ERROR ;
}
}
if ( unknown_size ) {
decl . size = decl . initializer . size ( ) ;
var . array_size = decl . initializer . size ( ) ;
} else if ( decl . initializer . size ( ) ! = var . array_size ) {
_set_error ( " Array size mismatch " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
}
} else {
if ( unknown_size ) {
_set_error ( " Expected array initialization " ) ;
return ERR_PARSE_ERROR ;
}
2019-08-13 08:55:43 +02:00
if ( is_const ) {
_set_error ( " Expected initialization of constant " ) ;
return ERR_PARSE_ERROR ;
}
2019-07-15 17:47:22 +02:00
}
2019-07-10 18:52:50 +02:00
node - > declarations . push_back ( decl ) ;
} else if ( tk . type = = TK_OP_ASSIGN ) {
VariableDeclarationNode * node = alloc_node < VariableDeclarationNode > ( ) ;
2020-01-17 20:35:22 +01:00
if ( is_struct ) {
node - > struct_name = struct_name ;
node - > datatype = TYPE_STRUCT ;
} else {
node - > datatype = type ;
}
2019-07-10 18:52:50 +02:00
node - > precision = precision ;
2019-08-05 09:35:53 +02:00
node - > is_const = is_const ;
2019-07-10 18:52:50 +02:00
vardecl = ( Node * ) node ;
VariableDeclarationNode : : Declaration decl ;
decl . name = name ;
decl . initializer = NULL ;
2014-02-10 02:10:30 +01:00
2018-01-01 19:56:44 +01:00
//variable created with assignment! must parse an expression
2017-03-05 16:44:50 +01:00
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2016-10-03 21:33:42 +02:00
if ( ! n )
return ERR_PARSE_ERROR ;
2019-10-06 17:05:44 +02:00
if ( node - > is_const & & n - > type = = Node : : TYPE_OPERATOR & & ( ( OperatorNode * ) n ) - > op = = OP_CALL ) {
_set_error ( " Expected constant expression after '=' " ) ;
return ERR_PARSE_ERROR ;
}
2017-09-05 20:22:33 +02:00
decl . initializer = n ;
2017-08-20 21:15:08 +02:00
2020-01-17 20:35:22 +01:00
if ( var . type = = TYPE_STRUCT ? ( var . struct_name ! = n - > get_datatype_name ( ) ) : ( var . type ! = n - > get_datatype ( ) ) ) {
_set_error ( " Invalid assignment of ' " + ( n - > get_datatype ( ) = = TYPE_STRUCT ? n - > get_datatype_name ( ) : get_datatype_name ( n - > get_datatype ( ) ) ) + " ' to ' " + ( var . type = = TYPE_STRUCT ? String ( var . struct_name ) : get_datatype_name ( var . type ) ) + " ' " ) ;
2017-08-20 21:15:08 +02:00
return ERR_PARSE_ERROR ;
}
2017-09-05 20:22:33 +02:00
tk = _get_token ( ) ;
2019-07-10 18:52:50 +02:00
node - > declarations . push_back ( decl ) ;
} else {
2019-08-13 08:55:43 +02:00
if ( is_const ) {
_set_error ( " Expected initialization of constant " ) ;
return ERR_PARSE_ERROR ;
}
2019-07-10 18:52:50 +02:00
VariableDeclarationNode * node = alloc_node < VariableDeclarationNode > ( ) ;
2020-01-17 20:35:22 +01:00
if ( is_struct ) {
node - > struct_name = struct_name ;
node - > datatype = TYPE_STRUCT ;
} else {
node - > datatype = type ;
}
2019-07-10 18:52:50 +02:00
node - > precision = precision ;
vardecl = ( Node * ) node ;
VariableDeclarationNode : : Declaration decl ;
decl . name = name ;
decl . initializer = NULL ;
node - > declarations . push_back ( decl ) ;
2014-02-10 02:10:30 +01:00
}
2019-07-10 18:52:50 +02:00
p_block - > statements . push_back ( vardecl ) ;
2018-01-01 19:56:44 +01:00
2019-07-10 18:52:50 +02:00
p_block - > variables [ name ] = var ;
2017-09-05 20:22:33 +02:00
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_COMMA ) {
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
//another variable
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_SEMICOLON ) {
2016-10-03 21:33:42 +02:00
break ;
} else {
2019-07-15 17:47:22 +02:00
_set_error ( " Expected ',' or ';' after variable " ) ;
2014-02-10 02:10:30 +01:00
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
}
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_CURLY_BRACKET_OPEN ) {
2016-10-03 21:33:42 +02:00
//a sub block, just because..
2017-03-05 16:44:50 +01:00
BlockNode * block = alloc_node < BlockNode > ( ) ;
block - > parent_block = p_block ;
_parse_block ( block , p_builtin_types , false , p_can_break , p_can_continue ) ;
2016-10-07 16:31:18 +02:00
p_block - > statements . push_back ( block ) ;
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_CF_IF ) {
2016-10-03 21:33:42 +02:00
//if () {}
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected '(' after if " ) ;
return ERR_PARSE_ERROR ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
ControlFlowNode * cf = alloc_node < ControlFlowNode > ( ) ;
2017-03-05 16:44:50 +01:00
cf - > flow_op = FLOW_OP_IF ;
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2016-10-03 21:33:42 +02:00
if ( ! n )
return ERR_PARSE_ERROR ;
2019-10-28 06:35:33 +01:00
if ( n - > get_datatype ( ) ! = TYPE_BOOL ) {
_set_error ( " Expected boolean expression " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
2017-06-04 23:08:06 +02:00
_set_error ( " Expected ')' after expression " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
BlockNode * block = alloc_node < BlockNode > ( ) ;
block - > parent_block = p_block ;
2016-10-07 16:31:18 +02:00
cf - > expressions . push_back ( n ) ;
2016-10-03 21:33:42 +02:00
cf - > blocks . push_back ( block ) ;
2016-10-07 16:31:18 +02:00
p_block - > statements . push_back ( cf ) ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
Error err = _parse_block ( block , p_builtin_types , true , p_can_break , p_can_continue ) ;
2017-06-04 23:08:06 +02:00
if ( err )
return err ;
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
pos = _get_tkpos ( ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_CF_ELSE ) {
2016-10-03 21:33:42 +02:00
block = alloc_node < BlockNode > ( ) ;
2017-03-05 16:44:50 +01:00
block - > parent_block = p_block ;
2016-10-03 21:33:42 +02:00
cf - > blocks . push_back ( block ) ;
2017-03-05 16:44:50 +01:00
err = _parse_block ( block , p_builtin_types , true , p_can_break , p_can_continue ) ;
2014-02-10 02:10:30 +01:00
} else {
2016-10-07 16:31:18 +02:00
_set_tkpos ( pos ) ; //rollback
2014-02-10 02:10:30 +01:00
}
2019-08-14 13:22:25 +02:00
} else if ( tk . type = = TK_CF_SWITCH ) {
2019-11-02 10:36:43 +01:00
if ( VisualServer : : get_singleton ( ) - > is_low_end ( ) ) {
_set_error ( " \" switch \" operator is supported only on high-end platform! " ) ;
return ERR_PARSE_ERROR ;
}
2019-08-14 13:22:25 +02:00
// switch() {}
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
_set_error ( " Expected '(' after switch " ) ;
return ERR_PARSE_ERROR ;
}
ControlFlowNode * cf = alloc_node < ControlFlowNode > ( ) ;
cf - > flow_op = FLOW_OP_SWITCH ;
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! n )
return ERR_PARSE_ERROR ;
if ( n - > get_datatype ( ) ! = TYPE_INT ) {
_set_error ( " Expected integer expression " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
_set_error ( " Expected ')' after expression " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_CURLY_BRACKET_OPEN ) {
_set_error ( " Expected '{' after switch statement " ) ;
return ERR_PARSE_ERROR ;
}
BlockNode * switch_block = alloc_node < BlockNode > ( ) ;
switch_block - > block_type = BlockNode : : BLOCK_TYPE_SWITCH ;
switch_block - > parent_block = p_block ;
cf - > expressions . push_back ( n ) ;
cf - > blocks . push_back ( switch_block ) ;
p_block - > statements . push_back ( cf ) ;
int prev_type = TK_CF_CASE ;
while ( true ) { // Go-through multiple cases.
if ( _parse_block ( switch_block , p_builtin_types , true , true , false ) ! = OK ) {
return ERR_PARSE_ERROR ;
}
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_CF_CASE | | tk . type = = TK_CF_DEFAULT ) {
if ( prev_type = = TK_CF_DEFAULT ) {
if ( tk . type = = TK_CF_CASE ) {
_set_error ( " Cases must be defined before default case. " ) ;
return ERR_PARSE_ERROR ;
} else if ( prev_type = = TK_CF_DEFAULT ) {
_set_error ( " Default case must be defined only once. " ) ;
return ERR_PARSE_ERROR ;
}
}
prev_type = tk . type ;
_set_tkpos ( pos ) ;
continue ;
} else {
Set < int > constants ;
for ( int i = 0 ; i < switch_block - > statements . size ( ) ; i + + ) { // Checks for duplicates.
ControlFlowNode * flow = ( ControlFlowNode * ) switch_block - > statements [ i ] ;
if ( flow ) {
if ( flow - > flow_op = = FLOW_OP_CASE ) {
ConstantNode * n2 = static_cast < ConstantNode * > ( flow - > expressions [ 0 ] ) ;
if ( ! n2 ) {
return ERR_PARSE_ERROR ;
}
if ( n2 - > values . empty ( ) ) {
return ERR_PARSE_ERROR ;
}
if ( constants . has ( n2 - > values [ 0 ] . sint ) ) {
_set_error ( " Duplicated case label: ' " + itos ( n2 - > values [ 0 ] . sint ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
constants . insert ( n2 - > values [ 0 ] . sint ) ;
} else if ( flow - > flow_op = = FLOW_OP_DEFAULT ) {
continue ;
} else {
return ERR_PARSE_ERROR ;
}
} else {
return ERR_PARSE_ERROR ;
}
}
break ;
}
}
} else if ( tk . type = = TK_CF_CASE ) {
// case x : break; | return;
if ( p_block & & p_block - > block_type = = BlockNode : : BLOCK_TYPE_CASE ) {
_set_tkpos ( pos ) ;
return OK ;
}
if ( ! p_block | | ( p_block - > block_type ! = BlockNode : : BLOCK_TYPE_SWITCH ) ) {
_set_error ( " case must be placed within switch block " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
int sign = 1 ;
if ( tk . type = = TK_OP_SUB ) {
sign = - 1 ;
tk = _get_token ( ) ;
}
if ( tk . type ! = TK_INT_CONSTANT ) {
_set_error ( " Expected integer constant " ) ;
return ERR_PARSE_ERROR ;
}
int constant = ( int ) tk . constant * sign ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_COLON ) {
_set_error ( " Expected ':' " ) ;
return ERR_PARSE_ERROR ;
}
ControlFlowNode * cf = alloc_node < ControlFlowNode > ( ) ;
cf - > flow_op = FLOW_OP_CASE ;
ConstantNode * n = alloc_node < ConstantNode > ( ) ;
ConstantNode : : Value v ;
v . sint = constant ;
n - > values . push_back ( v ) ;
n - > datatype = TYPE_INT ;
BlockNode * case_block = alloc_node < BlockNode > ( ) ;
case_block - > block_type = BlockNode : : BLOCK_TYPE_CASE ;
case_block - > parent_block = p_block ;
cf - > expressions . push_back ( n ) ;
cf - > blocks . push_back ( case_block ) ;
p_block - > statements . push_back ( cf ) ;
Error err = _parse_block ( case_block , p_builtin_types , false , true , false ) ;
if ( err )
return err ;
return OK ;
} else if ( tk . type = = TK_CF_DEFAULT ) {
if ( p_block & & p_block - > block_type = = BlockNode : : BLOCK_TYPE_CASE ) {
_set_tkpos ( pos ) ;
return OK ;
}
if ( ! p_block | | ( p_block - > block_type ! = BlockNode : : BLOCK_TYPE_SWITCH ) ) {
_set_error ( " default must be placed within switch block " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_COLON ) {
_set_error ( " Expected ':' " ) ;
return ERR_PARSE_ERROR ;
}
ControlFlowNode * cf = alloc_node < ControlFlowNode > ( ) ;
cf - > flow_op = FLOW_OP_DEFAULT ;
BlockNode * default_block = alloc_node < BlockNode > ( ) ;
default_block - > block_type = BlockNode : : BLOCK_TYPE_DEFAULT ;
default_block - > parent_block = p_block ;
cf - > blocks . push_back ( default_block ) ;
p_block - > statements . push_back ( cf ) ;
Error err = _parse_block ( default_block , p_builtin_types , false , true , false ) ;
if ( err )
return err ;
return OK ;
2019-08-13 15:19:14 +02:00
} else if ( tk . type = = TK_CF_DO | | tk . type = = TK_CF_WHILE ) {
// do {} while()
// while() {}
bool is_do = tk . type = = TK_CF_DO ;
BlockNode * do_block = NULL ;
if ( is_do ) {
do_block = alloc_node < BlockNode > ( ) ;
do_block - > parent_block = p_block ;
Error err = _parse_block ( do_block , p_builtin_types , true , true , true ) ;
if ( err )
return err ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_CF_WHILE ) {
_set_error ( " Expected while after do " ) ;
return ERR_PARSE_ERROR ;
}
}
2017-06-04 23:08:06 +02:00
tk = _get_token ( ) ;
2019-08-13 15:19:14 +02:00
2017-06-04 23:08:06 +02:00
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
2017-09-05 20:22:33 +02:00
_set_error ( " Expected '(' after while " ) ;
2017-06-04 23:08:06 +02:00
return ERR_PARSE_ERROR ;
}
ControlFlowNode * cf = alloc_node < ControlFlowNode > ( ) ;
2019-08-13 15:19:14 +02:00
if ( is_do ) {
cf - > flow_op = FLOW_OP_DO ;
} else {
cf - > flow_op = FLOW_OP_WHILE ;
}
2017-06-04 23:08:06 +02:00
Node * n = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! n )
return ERR_PARSE_ERROR ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
_set_error ( " Expected ')' after expression " ) ;
return ERR_PARSE_ERROR ;
}
2019-08-13 15:19:14 +02:00
if ( ! is_do ) {
BlockNode * block = alloc_node < BlockNode > ( ) ;
block - > parent_block = p_block ;
cf - > expressions . push_back ( n ) ;
cf - > blocks . push_back ( block ) ;
p_block - > statements . push_back ( cf ) ;
2017-06-04 23:08:06 +02:00
2019-08-13 15:19:14 +02:00
Error err = _parse_block ( block , p_builtin_types , true , true , true ) ;
if ( err )
return err ;
} else {
2017-06-04 23:08:06 +02:00
2019-08-13 15:19:14 +02:00
cf - > expressions . push_back ( n ) ;
cf - > blocks . push_back ( do_block ) ;
p_block - > statements . push_back ( cf ) ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' " ) ;
return ERR_PARSE_ERROR ;
}
}
2017-09-05 20:22:33 +02:00
} else if ( tk . type = = TK_CF_FOR ) {
2019-08-13 15:19:14 +02:00
// for() {}
2017-09-05 20:22:33 +02:00
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
_set_error ( " Expected '(' after for " ) ;
return ERR_PARSE_ERROR ;
}
ControlFlowNode * cf = alloc_node < ControlFlowNode > ( ) ;
cf - > flow_op = FLOW_OP_FOR ;
BlockNode * init_block = alloc_node < BlockNode > ( ) ;
init_block - > parent_block = p_block ;
2017-09-02 22:32:31 +02:00
init_block - > single_statement = true ;
2017-09-05 20:22:33 +02:00
cf - > blocks . push_back ( init_block ) ;
2017-09-02 22:32:31 +02:00
if ( _parse_block ( init_block , p_builtin_types , true , false , false ) ! = OK ) {
2017-09-05 20:22:33 +02:00
return ERR_PARSE_ERROR ;
}
Node * n = _parse_and_reduce_expression ( init_block , p_builtin_types ) ;
if ( ! n )
return ERR_PARSE_ERROR ;
2017-09-02 22:32:31 +02:00
if ( n - > get_datatype ( ) ! = TYPE_BOOL ) {
2017-09-05 20:22:33 +02:00
_set_error ( " Middle expression is expected to be boolean. " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' after middle expression " ) ;
return ERR_PARSE_ERROR ;
}
cf - > expressions . push_back ( n ) ;
n = _parse_and_reduce_expression ( init_block , p_builtin_types ) ;
if ( ! n )
return ERR_PARSE_ERROR ;
cf - > expressions . push_back ( n ) ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
_set_error ( " Expected ')' after third expression " ) ;
return ERR_PARSE_ERROR ;
}
BlockNode * block = alloc_node < BlockNode > ( ) ;
2017-12-17 01:43:59 +01:00
block - > parent_block = init_block ;
2017-09-05 20:22:33 +02:00
cf - > blocks . push_back ( block ) ;
p_block - > statements . push_back ( cf ) ;
Error err = _parse_block ( block , p_builtin_types , true , true , true ) ;
2017-06-04 23:08:06 +02:00
if ( err )
return err ;
2014-02-10 02:10:30 +01:00
2017-04-07 04:36:37 +02:00
} else if ( tk . type = = TK_CF_RETURN ) {
//check return type
BlockNode * b = p_block ;
while ( b & & ! b - > parent_function ) {
b = b - > parent_block ;
}
if ( ! b ) {
_set_error ( " Bug " ) ;
return ERR_BUG ;
}
ControlFlowNode * flow = alloc_node < ControlFlowNode > ( ) ;
flow - > flow_op = FLOW_OP_RETURN ;
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_SEMICOLON ) {
//all is good
if ( b - > parent_function - > return_type ! = TYPE_VOID ) {
_set_error ( " Expected return with expression of type ' " + get_datatype_name ( b - > parent_function - > return_type ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
_set_tkpos ( pos ) ; //rollback, wants expression
Node * expr = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
if ( ! expr )
return ERR_PARSE_ERROR ;
if ( b - > parent_function - > return_type ! = expr - > get_datatype ( ) ) {
_set_error ( " Expected return expression of type ' " + get_datatype_name ( b - > parent_function - > return_type ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' after return expression " ) ;
return ERR_PARSE_ERROR ;
}
flow - > expressions . push_back ( expr ) ;
}
2017-08-29 15:14:07 +02:00
p_block - > statements . push_back ( flow ) ;
2020-01-10 09:57:56 +01:00
BlockNode * block = p_block ;
while ( block ) {
if ( block - > block_type = = BlockNode : : BLOCK_TYPE_CASE | | block - > block_type = = BlockNode : : BLOCK_TYPE_DEFAULT ) {
return OK ;
}
block = block - > parent_block ;
2019-08-14 13:22:25 +02:00
}
2017-08-29 15:14:07 +02:00
} else if ( tk . type = = TK_CF_DISCARD ) {
//check return type
BlockNode * b = p_block ;
while ( b & & ! b - > parent_function ) {
b = b - > parent_block ;
}
if ( ! b ) {
_set_error ( " Bug " ) ;
return ERR_BUG ;
}
if ( ! b - > parent_function - > can_discard ) {
_set_error ( " Use of 'discard' is not allowed here. " ) ;
return ERR_PARSE_ERROR ;
}
ControlFlowNode * flow = alloc_node < ControlFlowNode > ( ) ;
flow - > flow_op = FLOW_OP_DISCARD ;
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
//all is good
_set_error ( " Expected ';' after discard " ) ;
}
2017-09-05 20:22:33 +02:00
p_block - > statements . push_back ( flow ) ;
} else if ( tk . type = = TK_CF_BREAK ) {
if ( ! p_can_break ) {
//all is good
_set_error ( " Breaking is not allowed here " ) ;
}
ControlFlowNode * flow = alloc_node < ControlFlowNode > ( ) ;
flow - > flow_op = FLOW_OP_BREAK ;
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
//all is good
_set_error ( " Expected ';' after break " ) ;
}
p_block - > statements . push_back ( flow ) ;
2020-01-10 09:57:56 +01:00
BlockNode * block = p_block ;
while ( block ) {
if ( block - > block_type = = BlockNode : : BLOCK_TYPE_CASE | | block - > block_type = = BlockNode : : BLOCK_TYPE_DEFAULT ) {
return OK ;
}
block = block - > parent_block ;
2019-08-14 13:22:25 +02:00
}
2017-09-05 20:22:33 +02:00
} else if ( tk . type = = TK_CF_CONTINUE ) {
2019-08-14 13:22:25 +02:00
if ( ! p_can_continue ) {
2017-09-05 20:22:33 +02:00
//all is good
2018-04-17 14:20:26 +02:00
_set_error ( " Continuing is not allowed here " ) ;
2017-09-05 20:22:33 +02:00
}
ControlFlowNode * flow = alloc_node < ControlFlowNode > ( ) ;
flow - > flow_op = FLOW_OP_CONTINUE ;
pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
//all is good
_set_error ( " Expected ';' after continue " ) ;
}
2017-04-07 04:36:37 +02:00
p_block - > statements . push_back ( flow ) ;
2016-10-03 21:33:42 +02:00
} else {
2014-02-10 02:10:30 +01:00
2019-05-30 16:19:24 +02:00
//nothing else, so expression
2016-10-07 16:31:18 +02:00
_set_tkpos ( pos ) ; //rollback
2017-03-05 16:44:50 +01:00
Node * expr = _parse_and_reduce_expression ( p_block , p_builtin_types ) ;
2016-10-07 16:31:18 +02:00
if ( ! expr )
return ERR_PARSE_ERROR ;
p_block - > statements . push_back ( expr ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_SEMICOLON ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected ';' after statement " ) ;
return ERR_PARSE_ERROR ;
}
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( p_just_one )
break ;
2014-02-10 02:10:30 +01:00
}
return OK ;
}
2019-10-26 17:41:47 +02:00
String ShaderLanguage : : _get_shader_type_list ( const Set < String > & p_shader_types ) const {
// Return a list of shader types as an human-readable string
String valid_types ;
for ( const Set < String > : : Element * E = p_shader_types . front ( ) ; E ; E = E - > next ( ) ) {
if ( valid_types ! = String ( ) ) {
valid_types + = " , " ;
}
valid_types + = " ' " + E - > get ( ) + " ' " ;
}
return valid_types ;
}
2020-02-12 21:16:47 +01:00
String ShaderLanguage : : _get_qualifier_str ( ArgumentQualifier p_qualifier ) const {
switch ( p_qualifier ) {
case ArgumentQualifier : : ARGUMENT_QUALIFIER_IN :
return " in " ;
case ArgumentQualifier : : ARGUMENT_QUALIFIER_OUT :
return " out " ;
case ArgumentQualifier : : ARGUMENT_QUALIFIER_INOUT :
return " inout " ;
}
return " " ;
}
2019-11-03 11:28:29 +01:00
Error ShaderLanguage : : _validate_datatype ( DataType p_type ) {
if ( VisualServer : : get_singleton ( ) - > is_low_end ( ) ) {
bool invalid_type = false ;
switch ( p_type ) {
2020-01-20 13:34:25 +01:00
case TYPE_UINT :
case TYPE_UVEC2 :
case TYPE_UVEC3 :
case TYPE_UVEC4 :
2019-11-03 11:28:29 +01:00
case TYPE_ISAMPLER2D :
case TYPE_USAMPLER2D :
case TYPE_ISAMPLER3D :
case TYPE_USAMPLER3D :
case TYPE_USAMPLER2DARRAY :
case TYPE_ISAMPLER2DARRAY :
invalid_type = true ;
break ;
default :
break ;
}
if ( invalid_type ) {
_set_error ( vformat ( " \" %s \" type is supported only on high-end platform! " , get_datatype_name ( p_type ) ) ) ;
return ERR_UNAVAILABLE ;
}
}
return OK ;
}
2018-07-14 23:15:42 +02:00
Error ShaderLanguage : : _parse_shader ( const Map < StringName , FunctionInfo > & p_functions , const Vector < StringName > & p_render_modes , const Set < String > & p_shader_types ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
Token tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2017-04-07 04:36:37 +02:00
if ( tk . type ! = TK_SHADER_TYPE ) {
2019-10-26 17:41:47 +02:00
_set_error ( " Expected 'shader_type' at the beginning of shader. Valid types are: " + _get_shader_type_list ( p_shader_types ) ) ;
2017-04-07 04:36:37 +02:00
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_IDENTIFIER ) {
2019-10-26 17:41:47 +02:00
_set_error ( " Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list ( p_shader_types ) ) ;
2017-04-07 04:36:37 +02:00
return ERR_PARSE_ERROR ;
}
String shader_type_identifier ;
shader_type_identifier = tk . text ;
if ( ! p_shader_types . has ( shader_type_identifier ) ) {
2019-10-26 17:41:47 +02:00
_set_error ( " Invalid shader type. Valid types are: " + _get_shader_type_list ( p_shader_types ) ) ;
2017-04-07 04:36:37 +02:00
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' after 'shader_type <type>'. " ) ;
}
tk = _get_token ( ) ;
2016-10-10 23:31:01 +02:00
int texture_uniforms = 0 ;
2017-03-05 16:44:50 +01:00
int uniforms = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( tk . type ! = TK_EOF ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( tk . type ) {
2016-10-03 21:33:42 +02:00
case TK_RENDER_MODE : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
StringName mode ;
2017-03-05 16:44:50 +01:00
_get_completable_identifier ( NULL , COMPLETION_RENDER_MODE , mode ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( mode = = StringName ( ) ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected identifier for render mode " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2018-07-14 23:15:42 +02:00
if ( p_render_modes . find ( mode ) = = - 1 ) {
2017-03-05 16:44:50 +01:00
_set_error ( " Invalid render mode: ' " + String ( mode ) + " ' " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( shader - > render_modes . find ( mode ) ! = - 1 ) {
_set_error ( " Duplicate render mode: ' " + String ( mode ) + " ' " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2015-11-22 06:49:58 +01:00
2016-10-27 16:50:26 +02:00
shader - > render_modes . push_back ( mode ) ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_COMMA ) {
2016-10-03 21:33:42 +02:00
//all good, do nothing
2017-03-05 16:44:50 +01:00
} else if ( tk . type = = TK_SEMICOLON ) {
2016-10-03 21:33:42 +02:00
break ; //done
} else {
2017-03-05 16:44:50 +01:00
_set_error ( " Unexpected token: " + get_token_text ( tk ) ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
}
} break ;
2020-01-17 20:35:22 +01:00
case TK_STRUCT : {
ShaderNode : : Struct st ;
DataType type ;
tk = _get_token ( ) ;
if ( tk . type = = TK_IDENTIFIER ) {
st . name = tk . text ;
tk = _get_token ( ) ;
if ( tk . type ! = TK_CURLY_BRACKET_OPEN ) {
_set_error ( " Expected '{' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
_set_error ( " Expected struct identifier! " ) ;
return ERR_PARSE_ERROR ;
}
StructNode * st_node = alloc_node < StructNode > ( ) ;
st . shader_struct = st_node ;
int member_count = 0 ;
while ( true ) { // variables list
tk = _get_token ( ) ;
if ( tk . type = = TK_CURLY_BRACKET_CLOSE ) {
break ;
}
StringName struct_name = " " ;
bool struct_dt = false ;
bool use_precision = false ;
DataPrecision precision = DataPrecision : : PRECISION_DEFAULT ;
if ( tk . type = = TK_STRUCT ) {
_set_error ( " nested structs are not allowed! " ) ;
return ERR_PARSE_ERROR ;
}
if ( is_token_precision ( tk . type ) ) {
precision = get_token_precision ( tk . type ) ;
use_precision = true ;
tk = _get_token ( ) ;
}
if ( shader - > structs . has ( tk . text ) ) {
struct_name = tk . text ;
struct_dt = true ;
if ( use_precision ) {
_set_error ( " Precision modifier cannot be used on structs. " ) ;
return ERR_PARSE_ERROR ;
}
}
if ( ! is_token_datatype ( tk . type ) & & ! struct_dt ) {
_set_error ( " Expected datatype. " ) ;
return ERR_PARSE_ERROR ;
} else {
type = struct_dt ? TYPE_STRUCT : get_token_datatype ( tk . type ) ;
if ( is_sampler_type ( type ) ) {
_set_error ( " sampler datatype not allowed here " ) ;
return ERR_PARSE_ERROR ;
} else if ( type = = TYPE_VOID ) {
_set_error ( " void datatype not allowed here " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_IDENTIFIER ) {
_set_error ( " Expected identifier! " ) ;
return ERR_PARSE_ERROR ;
}
MemberNode * member = alloc_node < MemberNode > ( ) ;
member - > precision = precision ;
member - > datatype = type ;
member - > struct_name = struct_name ;
member - > name = tk . text ;
tk = _get_token ( ) ;
2020-02-11 20:03:04 +01:00
if ( tk . type = = TK_BRACKET_OPEN ) {
tk = _get_token ( ) ;
if ( tk . type = = TK_INT_CONSTANT & & tk . constant > 0 ) {
member - > array_size = ( int ) tk . constant ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
_set_error ( " Expected ']' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
_set_error ( " Expected single integer constant > 0 " ) ;
return ERR_PARSE_ERROR ;
}
}
st_node - > members . push_back ( member ) ;
2020-01-17 20:35:22 +01:00
if ( tk . type ! = TK_SEMICOLON ) {
2020-02-11 20:03:04 +01:00
_set_error ( " Expected ']' or ';' " ) ;
2020-01-17 20:35:22 +01:00
return ERR_PARSE_ERROR ;
}
member_count + + ;
}
}
if ( member_count = = 0 ) {
_set_error ( " Empty structs are not allowed! " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' " ) ;
return ERR_PARSE_ERROR ;
}
shader - > structs [ st . name ] = st ;
shader - > vstructs . push_back ( st ) ; // struct's order is important!
} break ;
2016-10-03 21:33:42 +02:00
case TK_UNIFORM :
case TK_VARYING : {
2017-03-05 16:44:50 +01:00
bool uniform = tk . type = = TK_UNIFORM ;
2016-10-03 21:33:42 +02:00
DataPrecision precision = PRECISION_DEFAULT ;
2017-11-27 16:47:46 +01:00
DataInterpolation interpolation = INTERPOLATION_SMOOTH ;
2016-10-03 21:33:42 +02:00
DataType type ;
StringName name ;
tk = _get_token ( ) ;
2017-11-27 16:47:46 +01:00
if ( is_token_interpolation ( tk . type ) ) {
interpolation = get_token_interpolation ( tk . type ) ;
tk = _get_token ( ) ;
}
2016-10-03 21:33:42 +02:00
if ( is_token_precision ( tk . type ) ) {
2017-03-05 16:44:50 +01:00
precision = get_token_precision ( tk . type ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( ! is_token_datatype ( tk . type ) ) {
_set_error ( " Expected datatype. " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
type = get_token_datatype ( tk . type ) ;
2015-11-22 06:49:58 +01:00
2017-03-05 16:44:50 +01:00
if ( type = = TYPE_VOID ) {
2016-10-03 21:33:42 +02:00
_set_error ( " void datatype not allowed here " ) ;
return ERR_PARSE_ERROR ;
}
2018-04-21 16:35:23 +02:00
2018-08-19 14:16:54 +02:00
if ( ! uniform & & ( type < TYPE_FLOAT | | type > TYPE_MAT4 ) ) {
2019-07-29 16:08:25 +02:00
_set_error ( " Invalid type for varying, only float,vec2,vec3,vec4,mat2,mat3,mat4 or array of these types allowed. " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2015-11-22 06:49:58 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_IDENTIFIER ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected identifier! " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
name = tk . text ;
2014-02-10 02:10:30 +01:00
2017-12-15 22:23:16 +01:00
if ( _find_identifier ( NULL , Map < StringName , BuiltInInfo > ( ) , name ) ) {
2017-03-05 16:44:50 +01:00
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-10-29 12:36:11 +01:00
if ( has_builtin ( p_functions , name ) ) {
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
if ( uniform ) {
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
ShaderNode : : Uniform uniform2 ;
2014-02-10 02:10:30 +01:00
2016-10-10 23:31:01 +02:00
if ( is_sampler_type ( type ) ) {
2019-02-12 21:10:08 +01:00
uniform2 . texture_order = texture_uniforms + + ;
uniform2 . order = - 1 ;
2019-11-03 11:28:29 +01:00
if ( _validate_datatype ( type ) ! = OK ) {
return ERR_PARSE_ERROR ;
}
2016-10-10 23:31:01 +02:00
} else {
2019-02-12 21:10:08 +01:00
uniform2 . texture_order = - 1 ;
uniform2 . order = uniforms + + ;
2016-10-10 23:31:01 +02:00
}
2019-02-12 21:10:08 +01:00
uniform2 . type = type ;
uniform2 . precision = precision ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
//todo parse default value
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_COLON ) {
2016-10-03 21:33:42 +02:00
//hint
2019-09-15 06:01:52 +02:00
do {
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2019-09-15 06:01:52 +02:00
if ( tk . type = = TK_HINT_WHITE_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_WHITE ;
} else if ( tk . type = = TK_HINT_BLACK_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_BLACK ;
} else if ( tk . type = = TK_HINT_NORMAL_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_NORMAL ;
} else if ( tk . type = = TK_HINT_ROUGHNESS_NORMAL_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ROUGHNESS_NORMAL ;
} else if ( tk . type = = TK_HINT_ROUGHNESS_R ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ROUGHNESS_R ;
} else if ( tk . type = = TK_HINT_ROUGHNESS_G ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ROUGHNESS_G ;
} else if ( tk . type = = TK_HINT_ROUGHNESS_B ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ROUGHNESS_B ;
} else if ( tk . type = = TK_HINT_ROUGHNESS_A ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ROUGHNESS_A ;
} else if ( tk . type = = TK_HINT_ROUGHNESS_GRAY ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ROUGHNESS_GRAY ;
} else if ( tk . type = = TK_HINT_ANISO_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ANISO ;
} else if ( tk . type = = TK_HINT_ALBEDO_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_ALBEDO ;
} else if ( tk . type = = TK_HINT_BLACK_ALBEDO_TEXTURE ) {
uniform2 . hint = ShaderNode : : Uniform : : HINT_BLACK_ALBEDO ;
} else if ( tk . type = = TK_HINT_COLOR ) {
if ( type ! = TYPE_VEC4 ) {
_set_error ( " Color hint is for vec4 only " ) ;
return ERR_PARSE_ERROR ;
}
uniform2 . hint = ShaderNode : : Uniform : : HINT_COLOR ;
} else if ( tk . type = = TK_HINT_RANGE ) {
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
uniform2 . hint = ShaderNode : : Uniform : : HINT_RANGE ;
if ( type ! = TYPE_FLOAT & & type ! = TYPE_INT ) {
_set_error ( " Range hint is for float and int only " ) ;
return ERR_PARSE_ERROR ;
}
2016-11-21 02:49:53 +01:00
tk = _get_token ( ) ;
2019-09-15 06:01:52 +02:00
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
_set_error ( " Expected '(' after hint_range " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
float sign = 1.0 ;
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
if ( tk . type = = TK_OP_SUB ) {
sign = - 1.0 ;
tk = _get_token ( ) ;
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
if ( tk . type ! = TK_REAL_CONSTANT & & tk . type ! = TK_INT_CONSTANT ) {
_set_error ( " Expected integer constant " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
uniform2 . hint_range [ 0 ] = tk . constant ;
uniform2 . hint_range [ 0 ] * = sign ;
2016-11-21 02:49:53 +01:00
tk = _get_token ( ) ;
2019-09-15 06:01:52 +02:00
if ( tk . type ! = TK_COMMA ) {
_set_error ( " Expected ',' after integer constant " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
sign = 1.0 ;
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
if ( tk . type = = TK_OP_SUB ) {
sign = - 1.0 ;
tk = _get_token ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_REAL_CONSTANT & & tk . type ! = TK_INT_CONSTANT ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected integer constant after ',' " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
uniform2 . hint_range [ 1 ] = tk . constant ;
uniform2 . hint_range [ 1 ] * = sign ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2019-09-15 06:01:52 +02:00
if ( tk . type = = TK_COMMA ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_REAL_CONSTANT & & tk . type ! = TK_INT_CONSTANT ) {
_set_error ( " Expected integer constant after ',' " ) ;
return ERR_PARSE_ERROR ;
}
uniform2 . hint_range [ 2 ] = tk . constant ;
tk = _get_token ( ) ;
2016-10-03 21:33:42 +02:00
} else {
2019-09-15 06:01:52 +02:00
if ( type = = TYPE_INT ) {
uniform2 . hint_range [ 2 ] = 1 ;
} else {
uniform2 . hint_range [ 2 ] = 0.001 ;
}
}
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
_set_error ( " Expected ',' " ) ;
return ERR_PARSE_ERROR ;
2016-10-03 21:33:42 +02:00
}
2019-09-15 06:01:52 +02:00
} else if ( tk . type = = TK_FILTER_LINEAR ) {
uniform2 . filter = FILTER_LINEAR ;
} else if ( tk . type = = TK_FILTER_NEAREST ) {
uniform2 . filter = FILTER_NEAREST ;
} else if ( tk . type = = TK_FILTER_NEAREST_MIPMAP ) {
uniform2 . filter = FILTER_NEAREST_MIPMAP ;
} else if ( tk . type = = TK_FILTER_LINEAR_MIPMAP ) {
uniform2 . filter = FILTER_LINEAR_MIPMAP ;
} else if ( tk . type = = TK_FILTER_NEAREST_MIPMAP_ANISO ) {
uniform2 . filter = FILTER_NEAREST_MIPMAP_ANISO ;
} else if ( tk . type = = TK_FILTER_LINEAR_MIPMAP_ANISO ) {
uniform2 . filter = FILTER_LINEAR_MIPMAP_ANISO ;
} else if ( tk . type = = TK_REPEAT_DISABLE ) {
uniform2 . repeat = REPEAT_DISABLE ;
} else if ( tk . type = = TK_REPEAT_ENABLE ) {
uniform2 . repeat = REPEAT_ENABLE ;
} else {
_set_error ( " Expected valid type hint after ':'. " ) ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
if ( uniform2 . hint ! = ShaderNode : : Uniform : : HINT_RANGE & & uniform2 . hint ! = ShaderNode : : Uniform : : HINT_NONE & & uniform2 . hint ! = ShaderNode : : Uniform : : HINT_COLOR & & type < = TYPE_MAT4 ) {
_set_error ( " This hint is only for sampler types " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2019-09-15 06:01:52 +02:00
} while ( tk . type = = TK_COMMA ) ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2018-03-15 15:23:40 +01:00
if ( tk . type = = TK_OP_ASSIGN ) {
Node * expr = _parse_and_reduce_expression ( NULL , Map < StringName , BuiltInInfo > ( ) ) ;
if ( ! expr )
return ERR_PARSE_ERROR ;
if ( expr - > type ! = Node : : TYPE_CONSTANT ) {
_set_error ( " Expected constant expression after '=' " ) ;
return ERR_PARSE_ERROR ;
}
ConstantNode * cn = static_cast < ConstantNode * > ( expr ) ;
2019-02-12 21:10:08 +01:00
uniform2 . default_value . resize ( cn - > values . size ( ) ) ;
2018-03-15 15:23:40 +01:00
2019-02-12 21:10:08 +01:00
if ( ! convert_constant ( cn , uniform2 . type , uniform2 . default_value . ptrw ( ) ) ) {
_set_error ( " Can't convert constant to " + get_datatype_name ( uniform2 . type ) ) ;
2018-03-15 15:23:40 +01:00
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
}
2019-02-12 21:10:08 +01:00
shader - > uniforms [ name ] = uniform2 ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_SEMICOLON ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected ';' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
ShaderNode : : Varying varying ;
2017-03-05 16:44:50 +01:00
varying . type = type ;
2019-01-30 02:12:41 +01:00
varying . precision = precision ;
2017-11-27 16:47:46 +01:00
varying . interpolation = interpolation ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2019-07-29 16:08:25 +02:00
if ( tk . type ! = TK_SEMICOLON & & tk . type ! = TK_BRACKET_OPEN ) {
_set_error ( " Expected ';' or '[' " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2019-07-29 16:08:25 +02:00
if ( tk . type = = TK_BRACKET_OPEN ) {
tk = _get_token ( ) ;
if ( tk . type = = TK_INT_CONSTANT & & tk . constant > 0 ) {
varying . array_size = ( int ) tk . constant ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_SEMICOLON ) {
_set_error ( " Expected ';' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
_set_error ( " Expected ']' " ) ;
return ERR_PARSE_ERROR ;
}
} else {
_set_error ( " Expected single integer constant > 0 " ) ;
return ERR_PARSE_ERROR ;
}
}
shader - > varyings [ name ] = varying ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
} break ;
default : {
2019-05-30 16:19:24 +02:00
//function or constant variable
2014-02-10 02:10:30 +01:00
2019-05-30 16:19:24 +02:00
bool is_constant = false ;
2020-01-17 20:35:22 +01:00
bool is_struct = false ;
StringName struct_name ;
2016-10-03 21:33:42 +02:00
DataPrecision precision = PRECISION_DEFAULT ;
DataType type ;
StringName name ;
2014-02-10 02:10:30 +01:00
2019-05-30 16:19:24 +02:00
if ( tk . type = = TK_CONST ) {
is_constant = true ;
tk = _get_token ( ) ;
}
2016-10-03 21:33:42 +02:00
if ( is_token_precision ( tk . type ) ) {
2017-03-05 16:44:50 +01:00
precision = get_token_precision ( tk . type ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( shader - > structs . has ( tk . text ) ) {
if ( precision ! = PRECISION_DEFAULT ) {
_set_error ( " Precision modifier cannot be used on structs. " ) ;
return ERR_PARSE_ERROR ;
}
is_struct = true ;
struct_name = tk . text ;
} else {
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( ! is_token_datatype ( tk . type ) ) {
_set_error ( " Expected constant, function, uniform or varying " ) ;
return ERR_PARSE_ERROR ;
}
2018-11-12 12:36:26 +01:00
2020-01-17 20:35:22 +01:00
if ( ! is_token_variable_datatype ( tk . type ) ) {
_set_error ( " Invalid data type for constants or function return (samplers not allowed) " ) ;
return ERR_PARSE_ERROR ;
}
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( is_struct ) {
type = TYPE_STRUCT ;
} else {
type = get_token_datatype ( tk . type ) ;
}
2019-07-10 18:52:50 +02:00
TkPos prev_pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_OPEN ) {
_set_error ( " Cannot use arrays as return types " ) ;
return ERR_PARSE_ERROR ;
}
_set_tkpos ( prev_pos ) ;
2017-03-05 16:44:50 +01:00
_get_completable_identifier ( NULL , COMPLETION_MAIN_FUNCTION , name ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( name = = StringName ( ) ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected function name after datatype " ) ;
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2017-12-15 22:23:16 +01:00
if ( _find_identifier ( NULL , Map < StringName , BuiltInInfo > ( ) , name ) ) {
2017-03-05 16:44:50 +01:00
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2014-02-10 02:10:30 +01:00
2019-10-29 12:36:11 +01:00
if ( has_builtin ( p_functions , name ) ) {
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
2019-05-30 16:19:24 +02:00
if ( type = = TYPE_VOID ) {
_set_error ( " Expected '(' after function identifier " ) ;
return ERR_PARSE_ERROR ;
}
//variable
while ( true ) {
ShaderNode : : Constant constant ;
2020-01-17 20:35:22 +01:00
constant . type = is_struct ? TYPE_STRUCT : type ;
constant . type_str = struct_name ;
2019-05-30 16:19:24 +02:00
constant . precision = precision ;
constant . initializer = NULL ;
if ( tk . type = = TK_OP_ASSIGN ) {
if ( ! is_constant ) {
_set_error ( " Expected 'const' keyword before constant definition " ) ;
return ERR_PARSE_ERROR ;
}
//variable created with assignment! must parse an expression
Node * expr = _parse_and_reduce_expression ( NULL , Map < StringName , BuiltInInfo > ( ) ) ;
if ( ! expr )
return ERR_PARSE_ERROR ;
2019-12-02 17:00:21 +01:00
if ( expr - > type = = Node : : TYPE_OPERATOR & & ( ( OperatorNode * ) expr ) - > op = = OP_CALL ) {
2019-05-30 16:19:24 +02:00
_set_error ( " Expected constant expression after '=' " ) ;
return ERR_PARSE_ERROR ;
}
constant . initializer = static_cast < ConstantNode * > ( expr ) ;
2020-01-17 20:35:22 +01:00
if ( is_struct ) {
if ( expr - > get_datatype_name ( ) ! = struct_name ) {
_set_error ( " Invalid assignment of ' " + ( expr - > get_datatype ( ) = = TYPE_STRUCT ? expr - > get_datatype_name ( ) : get_datatype_name ( expr - > get_datatype ( ) ) ) + " ' to ' " + struct_name + " ' " ) ;
return ERR_PARSE_ERROR ;
}
} else if ( type ! = expr - > get_datatype ( ) ) {
2019-05-30 16:19:24 +02:00
_set_error ( " Invalid assignment of ' " + get_datatype_name ( expr - > get_datatype ( ) ) + " ' to ' " + get_datatype_name ( type ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
tk = _get_token ( ) ;
} else {
_set_error ( " Expected initialization of constant " ) ;
return ERR_PARSE_ERROR ;
}
shader - > constants [ name ] = constant ;
if ( tk . type = = TK_COMMA ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_IDENTIFIER ) {
_set_error ( " Expected identifier after type " ) ;
return ERR_PARSE_ERROR ;
}
name = tk . text ;
if ( _find_identifier ( NULL , Map < StringName , BuiltInInfo > ( ) , name ) ) {
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2019-10-29 12:36:11 +01:00
if ( has_builtin ( p_functions , name ) ) {
_set_error ( " Redefinition of ' " + String ( name ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2019-05-30 16:19:24 +02:00
tk = _get_token ( ) ;
} else if ( tk . type = = TK_SEMICOLON ) {
break ;
} else {
_set_error ( " Expected ',' or ';' after constant " ) ;
return ERR_PARSE_ERROR ;
}
}
break ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2017-12-15 22:23:16 +01:00
Map < StringName , BuiltInInfo > builtin_types ;
2016-10-03 21:33:42 +02:00
if ( p_functions . has ( name ) ) {
2017-08-29 15:14:07 +02:00
builtin_types = p_functions [ name ] . built_ins ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
ShaderNode : : Function function ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
function . callable = ! p_functions . has ( name ) ;
function . name = name ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
FunctionNode * func_node = alloc_node < FunctionNode > ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
function . function = func_node ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
shader - > functions . push_back ( function ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
func_node - > name = name ;
func_node - > return_type = type ;
2020-01-17 20:35:22 +01:00
func_node - > return_struct_name = struct_name ;
2017-03-05 16:44:50 +01:00
func_node - > return_precision = precision ;
2014-02-10 02:10:30 +01:00
2017-09-24 09:27:12 +02:00
if ( p_functions . has ( name ) ) {
func_node - > can_discard = p_functions [ name ] . can_discard ;
}
2016-10-03 21:33:42 +02:00
func_node - > body = alloc_node < BlockNode > ( ) ;
2017-03-05 16:44:50 +01:00
func_node - > body - > parent_function = func_node ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( true ) {
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
2016-10-03 21:33:42 +02:00
break ;
}
2014-02-10 02:10:30 +01:00
2017-04-07 04:36:37 +02:00
ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN ;
if ( tk . type = = TK_ARG_IN ) {
qualifier = ARGUMENT_QUALIFIER_IN ;
tk = _get_token ( ) ;
} else if ( tk . type = = TK_ARG_OUT ) {
qualifier = ARGUMENT_QUALIFIER_OUT ;
tk = _get_token ( ) ;
} else if ( tk . type = = TK_ARG_INOUT ) {
qualifier = ARGUMENT_QUALIFIER_INOUT ;
tk = _get_token ( ) ;
}
2016-10-03 21:33:42 +02:00
DataType ptype ;
StringName pname ;
2020-01-17 20:35:22 +01:00
StringName param_struct_name ;
2016-10-03 21:33:42 +02:00
DataPrecision pprecision = PRECISION_DEFAULT ;
2020-01-17 20:35:22 +01:00
bool use_precision = false ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
if ( is_token_precision ( tk . type ) ) {
2017-03-05 16:44:50 +01:00
pprecision = get_token_precision ( tk . type ) ;
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2020-01-17 20:35:22 +01:00
use_precision = true ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
is_struct = false ;
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( shader - > structs . has ( tk . text ) ) {
is_struct = true ;
param_struct_name = tk . text ;
if ( use_precision ) {
_set_error ( " Precision modifier cannot be used on structs. " ) ;
return ERR_PARSE_ERROR ;
}
}
2014-02-10 02:10:30 +01:00
2020-01-17 20:35:22 +01:00
if ( ! is_struct & & ! is_token_datatype ( tk . type ) ) {
_set_error ( " Expected a valid datatype for argument " ) ;
2019-11-03 11:28:29 +01:00
return ERR_PARSE_ERROR ;
}
2020-02-13 19:02:47 +01:00
if ( qualifier = = ARGUMENT_QUALIFIER_OUT | | qualifier = = ARGUMENT_QUALIFIER_INOUT ) {
if ( is_sampler_type ( get_token_datatype ( tk . type ) ) ) {
_set_error ( " Opaque types cannot be output parameters. " ) ;
return ERR_PARSE_ERROR ;
}
}
2020-01-17 20:35:22 +01:00
if ( is_struct ) {
ptype = TYPE_STRUCT ;
} else {
ptype = get_token_datatype ( tk . type ) ;
if ( _validate_datatype ( ptype ) ! = OK ) {
return ERR_PARSE_ERROR ;
}
if ( ptype = = TYPE_VOID ) {
_set_error ( " void not allowed in argument " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
}
tk = _get_token ( ) ;
2019-07-10 18:52:50 +02:00
if ( tk . type = = TK_BRACKET_OPEN ) {
_set_error ( " Arrays as parameters are not implemented yet " ) ;
return ERR_PARSE_ERROR ;
}
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_IDENTIFIER ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected identifier for argument name " ) ;
return ERR_PARSE_ERROR ;
}
pname = tk . text ;
2019-10-06 16:24:30 +02:00
ShaderLanguage : : IdentifierType itype ;
if ( _find_identifier ( func_node - > body , builtin_types , pname , ( ShaderLanguage : : DataType * ) 0 , & itype ) ) {
if ( itype ! = IDENTIFIER_FUNCTION ) {
_set_error ( " Redefinition of ' " + String ( pname ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
}
2019-10-29 12:36:11 +01:00
if ( has_builtin ( p_functions , pname ) ) {
_set_error ( " Redefinition of ' " + String ( pname ) + " ' " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
FunctionNode : : Argument arg ;
2017-03-05 16:44:50 +01:00
arg . type = ptype ;
arg . name = pname ;
2020-01-17 20:35:22 +01:00
arg . type_str = param_struct_name ;
2017-03-05 16:44:50 +01:00
arg . precision = pprecision ;
2017-04-07 04:36:37 +02:00
arg . qualifier = qualifier ;
2019-07-21 16:31:30 +02:00
arg . tex_argument_check = false ;
arg . tex_builtin_check = false ;
arg . tex_argument_filter = FILTER_DEFAULT ;
arg . tex_argument_repeat = REPEAT_DEFAULT ;
2016-10-03 21:33:42 +02:00
func_node - > arguments . push_back ( arg ) ;
tk = _get_token ( ) ;
2019-07-10 18:52:50 +02:00
if ( tk . type = = TK_BRACKET_OPEN ) {
_set_error ( " Arrays as parameters are not implemented yet " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
2017-03-05 16:44:50 +01:00
if ( tk . type = = TK_COMMA ) {
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
//do none and go on
2017-03-05 16:44:50 +01:00
} else if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected ',' or ')' after identifier " ) ;
return ERR_PARSE_ERROR ;
}
}
if ( p_functions . has ( name ) ) {
//if one of the core functions, make sure they are of the correct form
if ( func_node - > arguments . size ( ) > 0 ) {
2017-03-05 16:44:50 +01:00
_set_error ( " Function ' " + String ( name ) + " ' expects no arguments. " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
2017-03-05 16:44:50 +01:00
if ( func_node - > return_type ! = TYPE_VOID ) {
_set_error ( " Function ' " + String ( name ) + " ' must be of void return type. " ) ;
2016-10-03 21:33:42 +02:00
return ERR_PARSE_ERROR ;
}
}
2017-03-24 21:45:31 +01:00
//all good let's parse inside the function!
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2017-03-05 16:44:50 +01:00
if ( tk . type ! = TK_CURLY_BRACKET_OPEN ) {
2016-10-03 21:33:42 +02:00
_set_error ( " Expected '{' to begin function " ) ;
return ERR_PARSE_ERROR ;
}
2016-10-10 23:31:01 +02:00
current_function = name ;
2017-03-05 16:44:50 +01:00
Error err = _parse_block ( func_node - > body , builtin_types ) ;
2016-10-03 21:33:42 +02:00
if ( err )
return err ;
2016-10-10 23:31:01 +02:00
2019-08-23 14:40:42 +02:00
if ( func_node - > return_type ! = DataType : : TYPE_VOID ) {
BlockNode * block = func_node - > body ;
if ( _find_last_flow_op_in_block ( block , FlowOperation : : FLOW_OP_RETURN ) ! = OK ) {
_set_error ( " Expected at least one return statement in a non-void function. " ) ;
return ERR_PARSE_ERROR ;
}
}
2017-03-05 16:44:50 +01:00
current_function = StringName ( ) ;
2016-10-03 21:33:42 +02:00
}
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
tk = _get_token ( ) ;
2014-02-10 02:10:30 +01:00
}
return OK ;
}
2019-10-29 12:36:11 +01:00
bool ShaderLanguage : : has_builtin ( const Map < StringName , ShaderLanguage : : FunctionInfo > & p_functions , const StringName & p_name ) {
if ( p_functions . has ( " vertex " ) ) {
if ( p_functions [ " vertex " ] . built_ins . has ( p_name ) ) {
return true ;
}
}
if ( p_functions . has ( " fragment " ) ) {
if ( p_functions [ " fragment " ] . built_ins . has ( p_name ) ) {
return true ;
}
}
if ( p_functions . has ( " light " ) ) {
if ( p_functions [ " light " ] . built_ins . has ( p_name ) ) {
return true ;
}
}
return false ;
}
2019-08-23 14:40:42 +02:00
Error ShaderLanguage : : _find_last_flow_op_in_op ( ControlFlowNode * p_flow , FlowOperation p_op ) {
bool found = false ;
for ( int i = p_flow - > blocks . size ( ) - 1 ; i > = 0 ; i - - ) {
if ( p_flow - > blocks [ i ] - > type = = Node : : TYPE_BLOCK ) {
BlockNode * last_block = ( BlockNode * ) p_flow - > blocks [ i ] ;
if ( _find_last_flow_op_in_block ( last_block , p_op ) = = OK ) {
found = true ;
break ;
}
}
}
if ( found ) {
return OK ;
}
return FAILED ;
}
Error ShaderLanguage : : _find_last_flow_op_in_block ( BlockNode * p_block , FlowOperation p_op ) {
bool found = false ;
for ( int i = p_block - > statements . size ( ) - 1 ; i > = 0 ; i - - ) {
if ( p_block - > statements [ i ] - > type = = Node : : TYPE_CONTROL_FLOW ) {
ControlFlowNode * flow = ( ControlFlowNode * ) p_block - > statements [ i ] ;
if ( flow - > flow_op = = p_op ) {
found = true ;
break ;
} else {
if ( _find_last_flow_op_in_op ( flow , p_op ) = = OK ) {
found = true ;
break ;
}
}
} else if ( p_block - > statements [ i ] - > type = = Node : : TYPE_BLOCK ) {
BlockNode * block = ( BlockNode * ) p_block - > statements [ i ] ;
if ( _find_last_flow_op_in_block ( block , p_op ) = = OK ) {
found = true ;
break ;
}
}
}
if ( found ) {
return OK ;
}
return FAILED ;
}
2018-01-25 02:00:51 +01:00
// skips over whitespace and /* */ and // comments
static int _get_first_ident_pos ( const String & p_code ) {
int idx = 0 ;
# define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0))
while ( true ) {
if ( GETCHAR ( 0 ) = = ' / ' & & GETCHAR ( 1 ) = = ' / ' ) {
idx + = 2 ;
while ( true ) {
if ( GETCHAR ( 0 ) = = 0 ) return 0 ;
if ( GETCHAR ( 0 ) = = ' \n ' ) {
idx + + ;
break ; // loop
}
idx + + ;
}
} else if ( GETCHAR ( 0 ) = = ' / ' & & GETCHAR ( 1 ) = = ' * ' ) {
idx + = 2 ;
while ( true ) {
if ( GETCHAR ( 0 ) = = 0 ) return 0 ;
if ( GETCHAR ( 0 ) = = ' * ' & & GETCHAR ( 1 ) = = ' / ' ) {
idx + = 2 ;
break ; // loop
}
idx + + ;
}
} else {
switch ( GETCHAR ( 0 ) ) {
case ' ' :
case ' \t ' :
case ' \r ' :
case ' \n ' : {
idx + + ;
} break ; // switch
default :
return idx ;
}
}
}
# undef GETCHAR
}
2017-04-07 04:36:37 +02:00
String ShaderLanguage : : get_shader_type ( const String & p_code ) {
bool reading_type = false ;
String cur_identifier ;
2018-01-25 02:00:51 +01:00
for ( int i = _get_first_ident_pos ( p_code ) ; i < p_code . length ( ) ; i + + ) {
2017-04-07 04:36:37 +02:00
if ( p_code [ i ] = = ' ; ' ) {
break ;
} else if ( p_code [ i ] < = 32 ) {
if ( cur_identifier ! = String ( ) ) {
if ( ! reading_type ) {
if ( cur_identifier ! = " shader_type " ) {
return String ( ) ;
}
reading_type = true ;
cur_identifier = String ( ) ;
} else {
return cur_identifier ;
}
}
} else {
cur_identifier + = String : : chr ( p_code [ i ] ) ;
}
}
if ( reading_type )
return cur_identifier ;
return String ( ) ;
}
2018-07-14 23:15:42 +02:00
Error ShaderLanguage : : compile ( const String & p_code , const Map < StringName , FunctionInfo > & p_functions , const Vector < StringName > & p_render_modes , const Set < String > & p_shader_types ) {
2016-10-03 21:33:42 +02:00
clear ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
code = p_code ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
nodes = NULL ;
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
shader = alloc_node < ShaderNode > ( ) ;
2017-04-07 04:36:37 +02:00
Error err = _parse_shader ( p_functions , p_render_modes , p_shader_types ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( err ! = OK ) {
2016-10-03 21:33:42 +02:00
return err ;
2014-02-10 02:10:30 +01:00
}
2016-10-03 21:33:42 +02:00
return OK ;
}
2014-02-10 02:10:30 +01:00
2019-07-06 06:03:17 +02:00
Error ShaderLanguage : : complete ( const String & p_code , const Map < StringName , FunctionInfo > & p_functions , const Vector < StringName > & p_render_modes , const Set < String > & p_shader_types , List < ScriptCodeCompletionOption > * r_options , String & r_call_hint ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
clear ( ) ;
2017-03-05 16:44:50 +01:00
code = p_code ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
nodes = NULL ;
2016-10-07 16:31:18 +02:00
shader = alloc_node < ShaderNode > ( ) ;
2019-10-02 09:50:22 +02:00
_parse_shader ( p_functions , p_render_modes , p_shader_types ) ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
switch ( completion_type ) {
2016-10-07 16:31:18 +02:00
case COMPLETION_NONE : {
2018-07-14 19:59:11 +02:00
//do nothing
return OK ;
2014-02-10 02:10:30 +01:00
} break ;
2016-10-07 16:31:18 +02:00
case COMPLETION_RENDER_MODE : {
2018-07-14 23:15:42 +02:00
for ( int i = 0 ; i < p_render_modes . size ( ) ; i + + ) {
2019-07-06 06:03:17 +02:00
ScriptCodeCompletionOption option ( p_render_modes [ i ] , ScriptCodeCompletionOption : : KIND_ENUM ) ;
r_options - > push_back ( option ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
return OK ;
2014-02-10 02:10:30 +01:00
} break ;
2020-01-17 20:35:22 +01:00
case COMPLETION_STRUCT : {
if ( shader - > structs . has ( completion_struct ) ) {
StructNode * node = shader - > structs [ completion_struct ] . shader_struct ;
for ( int i = 0 ; i < node - > members . size ( ) ; i + + ) {
ScriptCodeCompletionOption option ( node - > members [ i ] - > name , ScriptCodeCompletionOption : : KIND_MEMBER ) ;
r_options - > push_back ( option ) ;
}
}
return OK ;
} break ;
2016-10-07 16:31:18 +02:00
case COMPLETION_MAIN_FUNCTION : {
2016-10-27 16:50:26 +02:00
2017-08-29 15:14:07 +02:00
for ( const Map < StringName , FunctionInfo > : : Element * E = p_functions . front ( ) ; E ; E = E - > next ( ) ) {
2019-07-06 06:03:17 +02:00
ScriptCodeCompletionOption option ( E - > key ( ) , ScriptCodeCompletionOption : : KIND_FUNCTION ) ;
r_options - > push_back ( option ) ;
2014-06-28 04:21:45 +02:00
}
2016-10-07 16:31:18 +02:00
return OK ;
2014-06-28 04:21:45 +02:00
} break ;
2016-10-07 16:31:18 +02:00
case COMPLETION_IDENTIFIER :
case COMPLETION_FUNCTION_CALL : {
2017-03-05 16:44:50 +01:00
bool comp_ident = completion_type = = COMPLETION_IDENTIFIER ;
2019-07-06 06:03:17 +02:00
Map < String , ScriptCodeCompletionOption : : Kind > matches ;
2016-10-07 16:31:18 +02:00
StringName skip_function ;
2017-03-05 16:44:50 +01:00
BlockNode * block = completion_block ;
2016-10-07 16:31:18 +02:00
2019-07-10 18:52:50 +02:00
if ( completion_class = = TAG_GLOBAL ) {
while ( block ) {
if ( comp_ident ) {
for ( const Map < StringName , BlockNode : : Variable > : : Element * E = block - > variables . front ( ) ; E ; E = E - > next ( ) ) {
2016-10-07 16:31:18 +02:00
2019-07-10 18:52:50 +02:00
if ( E - > get ( ) . line < completion_line ) {
matches . insert ( E - > key ( ) , ScriptCodeCompletionOption : : KIND_VARIABLE ) ;
}
2016-10-07 16:31:18 +02:00
}
}
2019-07-10 18:52:50 +02:00
if ( block - > parent_function ) {
if ( comp_ident ) {
for ( int i = 0 ; i < block - > parent_function - > arguments . size ( ) ; i + + ) {
2019-10-08 17:33:22 +02:00
matches . insert ( block - > parent_function - > arguments [ i ] . name , ScriptCodeCompletionOption : : KIND_VARIABLE ) ;
2019-07-10 18:52:50 +02:00
}
2016-10-07 16:31:18 +02:00
}
2019-07-10 18:52:50 +02:00
skip_function = block - > parent_function - > name ;
2016-10-07 16:31:18 +02:00
}
2019-07-10 18:52:50 +02:00
block = block - > parent_block ;
2016-10-07 16:31:18 +02:00
}
2019-07-10 18:52:50 +02:00
if ( comp_ident & & skip_function ! = StringName ( ) & & p_functions . has ( skip_function ) ) {
2016-10-07 16:31:18 +02:00
2019-07-10 18:52:50 +02:00
for ( Map < StringName , BuiltInInfo > : : Element * E = p_functions [ skip_function ] . built_ins . front ( ) ; E ; E = E - > next ( ) ) {
ScriptCodeCompletionOption : : Kind kind = ScriptCodeCompletionOption : : KIND_MEMBER ;
if ( E - > get ( ) . constant ) {
kind = ScriptCodeCompletionOption : : KIND_CONSTANT ;
}
matches . insert ( E - > key ( ) , kind ) ;
2019-07-06 06:03:17 +02:00
}
2016-10-07 16:31:18 +02:00
}
2019-07-10 18:52:50 +02:00
if ( comp_ident ) {
for ( const Map < StringName , ShaderNode : : Varying > : : Element * E = shader - > varyings . front ( ) ; E ; E = E - > next ( ) ) {
matches . insert ( E - > key ( ) , ScriptCodeCompletionOption : : KIND_VARIABLE ) ;
}
for ( const Map < StringName , ShaderNode : : Uniform > : : Element * E = shader - > uniforms . front ( ) ; E ; E = E - > next ( ) ) {
matches . insert ( E - > key ( ) , ScriptCodeCompletionOption : : KIND_MEMBER ) ;
}
2016-10-07 16:31:18 +02:00
}
2019-07-10 18:52:50 +02:00
for ( int i = 0 ; i < shader - > functions . size ( ) ; i + + ) {
if ( ! shader - > functions [ i ] . callable | | shader - > functions [ i ] . name = = skip_function )
continue ;
matches . insert ( String ( shader - > functions [ i ] . name ) , ScriptCodeCompletionOption : : KIND_FUNCTION ) ;
2016-10-07 16:31:18 +02:00
}
2019-07-10 18:52:50 +02:00
int idx = 0 ;
2020-01-23 10:41:21 +01:00
bool low_end = VisualServer : : get_singleton ( ) - > is_low_end ( ) ;
2016-10-07 16:31:18 +02:00
2019-07-10 18:52:50 +02:00
while ( builtin_func_defs [ idx ] . name ) {
2020-01-23 10:41:21 +01:00
if ( low_end & & builtin_func_defs [ idx ] . high_end ) {
idx + + ;
continue ;
}
2019-07-10 18:52:50 +02:00
matches . insert ( String ( builtin_func_defs [ idx ] . name ) , ScriptCodeCompletionOption : : KIND_FUNCTION ) ;
idx + + ;
}
2016-10-07 16:31:18 +02:00
2019-07-10 18:52:50 +02:00
} else { // sub-class
int idx = 0 ;
2020-01-23 10:41:21 +01:00
bool low_end = VisualServer : : get_singleton ( ) - > is_low_end ( ) ;
2019-07-10 18:52:50 +02:00
while ( builtin_func_defs [ idx ] . name ) {
2020-01-23 10:41:21 +01:00
if ( low_end & & builtin_func_defs [ idx ] . high_end ) {
idx + + ;
continue ;
}
2019-07-10 18:52:50 +02:00
if ( builtin_func_defs [ idx ] . tag = = completion_class ) {
matches . insert ( String ( builtin_func_defs [ idx ] . name ) , ScriptCodeCompletionOption : : KIND_FUNCTION ) ;
}
idx + + ;
}
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
2019-07-06 06:03:17 +02:00
for ( Map < String , ScriptCodeCompletionOption : : Kind > : : Element * E = matches . front ( ) ; E ; E = E - > next ( ) ) {
ScriptCodeCompletionOption option ( E - > key ( ) , E - > value ( ) ) ;
if ( E - > value ( ) = = ScriptCodeCompletionOption : : KIND_FUNCTION ) {
option . insert_text + = " ( " ;
}
r_options - > push_back ( option ) ;
2016-10-07 16:31:18 +02:00
}
return OK ;
2014-02-10 02:10:30 +01:00
} break ;
2016-10-07 16:31:18 +02:00
case COMPLETION_CALL_ARGUMENTS : {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < shader - > functions . size ( ) ; i + + ) {
2016-10-07 16:31:18 +02:00
if ( ! shader - > functions [ i ] . callable )
continue ;
2017-03-05 16:44:50 +01:00
if ( shader - > functions [ i ] . name = = completion_function ) {
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
String calltip ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
calltip + = get_datatype_name ( shader - > functions [ i ] . function - > return_type ) ;
calltip + = " " ;
calltip + = shader - > functions [ i ] . name ;
calltip + = " ( " ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < shader - > functions [ i ] . function - > arguments . size ( ) ; j + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( j > 0 )
calltip + = " , " ;
2016-10-07 16:31:18 +02:00
else
2017-03-05 16:44:50 +01:00
calltip + = " " ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( j = = completion_argument ) {
calltip + = CharType ( 0xFFFF ) ;
2016-10-07 16:31:18 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
calltip + = get_datatype_name ( shader - > functions [ i ] . function - > arguments [ j ] . type ) ;
calltip + = " " ;
calltip + = shader - > functions [ i ] . function - > arguments [ j ] . name ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( j = = completion_argument ) {
calltip + = CharType ( 0xFFFF ) ;
2016-10-07 16:31:18 +02:00
}
}
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
if ( shader - > functions [ i ] . function - > arguments . size ( ) )
2017-03-05 16:44:50 +01:00
calltip + = " " ;
calltip + = " ) " ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
r_call_hint = calltip ;
2016-10-07 16:31:18 +02:00
return OK ;
}
}
2015-03-10 04:53:09 +01:00
2017-03-05 16:44:50 +01:00
int idx = 0 ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
String calltip ;
2020-01-23 10:41:21 +01:00
bool low_end = VisualServer : : get_singleton ( ) - > is_low_end ( ) ;
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
while ( builtin_func_defs [ idx ] . name ) {
2015-03-10 04:53:09 +01:00
2020-01-23 10:41:21 +01:00
if ( low_end & & builtin_func_defs [ idx ] . high_end ) {
idx + + ;
continue ;
}
2017-03-05 16:44:50 +01:00
if ( completion_function = = builtin_func_defs [ idx ] . name ) {
2016-10-07 16:31:18 +02:00
2019-07-10 18:52:50 +02:00
if ( builtin_func_defs [ idx ] . tag ! = completion_class ) {
idx + + ;
continue ;
}
2016-10-07 16:31:18 +02:00
if ( calltip . length ( ) )
2017-03-05 16:44:50 +01:00
calltip + = " \n " ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
calltip + = get_datatype_name ( builtin_func_defs [ idx ] . rettype ) ;
calltip + = " " ;
calltip + = builtin_func_defs [ idx ] . name ;
calltip + = " ( " ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
bool found_arg = false ;
for ( int i = 0 ; i < 4 ; i + + ) {
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
if ( builtin_func_defs [ idx ] . args [ i ] = = TYPE_VOID )
2016-10-07 16:31:18 +02:00
break ;
2017-03-05 16:44:50 +01:00
if ( i > 0 )
calltip + = " , " ;
2016-10-07 16:31:18 +02:00
else
2017-03-05 16:44:50 +01:00
calltip + = " " ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
if ( i = = completion_argument ) {
calltip + = CharType ( 0xFFFF ) ;
2016-10-07 16:31:18 +02:00
}
2017-03-05 16:44:50 +01:00
calltip + = get_datatype_name ( builtin_func_defs [ idx ] . args [ i ] ) ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
if ( i = = completion_argument ) {
calltip + = CharType ( 0xFFFF ) ;
2016-10-07 16:31:18 +02:00
}
2017-03-05 16:44:50 +01:00
found_arg = true ;
2016-10-07 16:31:18 +02:00
}
if ( found_arg )
2017-03-05 16:44:50 +01:00
calltip + = " " ;
calltip + = " ) " ;
2016-10-07 16:31:18 +02:00
}
2015-01-12 00:52:42 +01:00
idx + + ;
}
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
r_call_hint = calltip ;
2016-10-07 16:31:18 +02:00
return OK ;
2015-01-12 00:52:42 +01:00
} break ;
2016-10-07 16:31:18 +02:00
case COMPLETION_INDEX : {
2017-03-05 16:44:50 +01:00
const char colv [ 4 ] = { ' r ' , ' g ' , ' b ' , ' a ' } ;
const char coordv [ 4 ] = { ' x ' , ' y ' , ' z ' , ' w ' } ;
2020-02-13 15:50:20 +01:00
const char coordt [ 4 ] = { ' s ' , ' t ' , ' p ' , ' q ' } ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
int limit = 0 ;
2016-10-07 16:31:18 +02:00
2017-03-05 16:44:50 +01:00
switch ( completion_base ) {
2016-10-07 16:31:18 +02:00
case TYPE_BVEC2 :
case TYPE_IVEC2 :
case TYPE_UVEC2 :
case TYPE_VEC2 : {
2017-03-05 16:44:50 +01:00
limit = 2 ;
2016-10-07 16:31:18 +02:00
} break ;
case TYPE_BVEC3 :
case TYPE_IVEC3 :
case TYPE_UVEC3 :
case TYPE_VEC3 : {
2017-03-05 16:44:50 +01:00
limit = 3 ;
2016-10-07 16:31:18 +02:00
} break ;
case TYPE_BVEC4 :
case TYPE_IVEC4 :
case TYPE_UVEC4 :
case TYPE_VEC4 : {
2017-03-05 16:44:50 +01:00
limit = 4 ;
2016-10-07 16:31:18 +02:00
} break ;
2017-03-05 16:44:50 +01:00
case TYPE_MAT2 : limit = 2 ; break ;
case TYPE_MAT3 : limit = 3 ; break ;
case TYPE_MAT4 : limit = 4 ; break ;
2019-04-09 17:08:36 +02:00
default : {
}
2015-01-12 00:52:42 +01:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < limit ; i + + ) {
2019-07-06 06:03:17 +02:00
r_options - > push_back ( ScriptCodeCompletionOption ( String : : chr ( colv [ i ] ) , ScriptCodeCompletionOption : : KIND_PLAIN_TEXT ) ) ;
r_options - > push_back ( ScriptCodeCompletionOption ( String : : chr ( coordv [ i ] ) , ScriptCodeCompletionOption : : KIND_PLAIN_TEXT ) ) ;
2020-02-13 15:50:20 +01:00
r_options - > push_back ( ScriptCodeCompletionOption ( String : : chr ( coordt [ i ] ) , ScriptCodeCompletionOption : : KIND_PLAIN_TEXT ) ) ;
2014-02-10 02:10:30 +01:00
}
2016-10-07 16:31:18 +02:00
2014-02-10 02:10:30 +01:00
} break ;
}
2016-10-07 16:31:18 +02:00
return ERR_PARSE_ERROR ;
}
2016-10-03 21:33:42 +02:00
String ShaderLanguage : : get_error_text ( ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
return error_str ;
2014-02-10 02:10:30 +01:00
}
2015-03-10 04:53:09 +01:00
2016-10-03 21:33:42 +02:00
int ShaderLanguage : : get_error_line ( ) {
2015-01-12 00:52:42 +01:00
2016-10-03 21:33:42 +02:00
return error_line ;
}
2014-02-10 02:10:30 +01:00
2016-10-07 16:31:18 +02:00
ShaderLanguage : : ShaderNode * ShaderLanguage : : get_shader ( ) {
return shader ;
}
2016-10-03 21:33:42 +02:00
ShaderLanguage : : ShaderLanguage ( ) {
2017-03-05 16:44:50 +01:00
nodes = NULL ;
2019-07-10 18:52:50 +02:00
completion_class = TAG_GLOBAL ;
2016-10-03 21:33:42 +02:00
}
ShaderLanguage : : ~ ShaderLanguage ( ) {
2014-02-10 02:10:30 +01:00
2016-10-03 21:33:42 +02:00
clear ( ) ;
2014-02-10 02:10:30 +01:00
}