Разбор строки шейдера GLSL для поиска имен переменных в Android NDK

Это офигенно. Для правильного объяснения позвольте мне объяснить, что я пытаюсь сделать. Я продолжу с листингом кода, а затем объясню код.

Цель

Я пытаюсь получить имена переменных в каждом файле шейдера 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и продолжают цикл, повторяя процесс.

Важные проблемы

  • Я использую JNI для получения строк шейдеров, поскольку сами шейдеры анализируются с помощью Java, а затем отправляются через JNI на C++.
  • Unicode может вызывать беспокойство, так как я получаю такие результаты: Shader Variable Found is: |uԯ|uԯ/
  • Shader src передается в const char *из JNI черезenv->GetStringUTFChars()

Заключение

Я уверен есть лучший способ сделать это, возможно, используя std::stringstreamили что-то в этом роде, но я не очень хорошо знаком с этим и хотел бы, чтобы этот алгоритм работал так или иначе. Однако, если это «наивный» способ сделать это, я открыт для предложений.

Вопрос

Как лучше всего добиться этого, чтобы синтаксический анализ заработал?

5
задан zeboidlund 2 May 2012 в 19:15
поделиться