Это офигенно. Для правильного объяснения позвольте мне объяснить, что я пытаюсь сделать. Я продолжу с листингом кода, а затем объясню код.
Цель
Я пытаюсь получить имена переменных в каждом файле шейдера GLSL, который у меня есть. На данный момент у меня есть только один вершинный шейдер и дополняющий его фрагментный шейдер. Цель этого состоит в том, чтобы я мог динамически привязывать значения к шейдерам без необходимости вводить каждое имя переменной.
Код
std::vector< const char* > GetShaderVariableNames( const Shader& shader )
{
Config::Log::info( "Getting shader variable names." );
static const char* keyLookupTable[] =
{
"vec2", "vec3", "vec4",
"mat2", "mat3", "mat4",
"float", "int", "double"
};
std::vector< const char* > keys;
std::vector< std::string > lines;
SplitIntoLines( &lines, std::string( shader.shaderSrc ) );
for( int32_t iLines = 0; iLines < lines.size(); ++iLines )
{
const char* line = lines[ iLines ].c_str();
int32_t index = 0;
bool foundMatch = false;
for( int32_t iKey = 0; iKey < sizeof( keyLookupTable ) / sizeof( char ); ++iKey )
{
if( strContains( lines[ iLines ], keyLookupTable[ iKey ] ) )
{
index = iKey;
foundMatch = true;
break;
}
}
if( foundMatch )
{
const int32_t pos = lines[ iLines ].find( keyLookupTable[ index ] );
Config::Log::info( "Position found is %i", pos );
const int32_t lineLen = strlen( line );
char* var = new char[ lineLen - pos ];
int32_t iLine = pos + strlen( keyLookupTable[ index ] );
for( ; iLine < lineLen; ++iLine )
{
var[ iLine ] = line[ iLine ];
}
Config::Log::info( "Shader Variable Found is: %s", var );
keys.push_back( var );
}
}
return keys;
}
Принятие красной таблетки
Итак,идея состоит в том, что есть таблица поиска ключей, содержащая наиболее часто используемые типы переменных . Во-первых, полученный шейдер — это класс, который содержит информацию о данных, такую как его дескриптор, его тип (Фрагмент, Вершина, Текстура и т. д. )и, конечно же, его источник. Я анализирую все это из файлов шейдеров, а не из строк.
Что происходит, так это то, что существует большой -цикл папочки, который перебирает каждую строку, проанализированную в файле шейдера. В каждой строке, если есть совпадение в таблице поиска ключа, второй цикл, повторяющийся по keyLookupTable[]
, прервется со значением индекса, принимающим значение iKey
(, т. е. индекс в массиве, где находится совпадение. найден ). Затем петля обрывается.
Если совпадение найдено, позиция в строке, где найдено совпадение (, например. vec4
или mat3
). Оттуда, используя позицию, хранящуюся в pos
, мы используем pos
в качестве основы для длины имени переменной, что делается путем указания необходимого количества символов в массиве символов. Требуемая сумма — это длина строки минус позиция.
Оттуда третий и последний цикл перебирает строку, используя char*
для ссылки на нее, беря значения из line
и копируя их в выделенный массив символов var
.
Наконец, клавиши std::vector
вставляют var
и продолжают цикл, повторяя процесс.
Важные проблемы
Shader Variable Found is: |uԯ|uԯ/
env->GetStringUTFChars()
Заключение
Я уверен есть лучший способ сделать это, возможно, используя std::stringstream
или что-то в этом роде, но я не очень хорошо знаком с этим и хотел бы, чтобы этот алгоритм работал так или иначе. Однако, если это «наивный» способ сделать это, я открыт для предложений.
Вопрос
Как лучше всего добиться этого, чтобы синтаксический анализ заработал?