2012-05-02 13 views
5

Questo è un doozy. Per motivi di corretta spiegazione lasciatemi spiegare cosa sto cercando di fare. Seguirò un elenco di codici e quindi spiegherò il codice dopo.Analisi di una stringa shader GLSL per trovare i nomi delle variabili nell'NDK Android

L'obiettivo

sto cercando di ottenere i nomi delle variabili in ogni file GLSL dello shader che ho. In questo momento, ho solo un singolo vertex shader, insieme a un framment shader per completarlo. Lo scopo di questo è che posso legare dinamicamente i valori agli shader senza dover immettere ogni singolo nome di variabile.

Codice

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; 
    } 

Prendendo la pillola rossa

Così, l'idea è che ci sia una chiave di tabella di ricerca che contiene i più comunemente utilizzati variabili tipi. Prima di tutto, lo Shader ricevuto è una classe che contiene informazioni sui dati, come il suo manico, il suo tipo (Fragment, Vertex, Texture, ecc.), E ovviamente la sua fonte. Sto analizzando tutto da file shader e non stringhe.

Quello che succede è un ciclo di nonno che scorre su ogni riga analizzata nel file shader. In ogni singola riga, se c'è una corrispondenza nella tabella di ricerca della chiave, il secondo ciclo che itera su keyLookupTable[] si interromperà con un valore di indice che assume il valore di iKey (cioè l'indice nell'array, dove viene trovata la corrispondenza) . Il ciclo quindi si rompe.

Se viene trovata una corrispondenza, viene presa la posizione nella riga in cui è stata trovata la corrispondenza (ad esempio vec4 o mat3). Da lì, utilizzando la posizione memorizzata in pos, utilizziamo pos per agire come base per la lunghezza del nome della variabile, operazione che viene eseguita specificando la quantità richiesta di caratteri in un array di caratteri. L'importo richiesto è la lunghezza della linea, meno la posizione.

Da lì una terza ed ultima anello poi itera la linea, utilizzando un char* farvi riferimento, prendendo i valori in line e copia nel allocato var array di caratteri.

Infine, i tasti std::vector inseriscono var e continuano nel ciclo, ripetendo il processo.

preoccupazioni notevoli

  • Sto utilizzando la JNI per ottenere le corde dello shader, come gli shaders stessi vengono analizzati tramite Java, e quindi inviato attraverso il JNI per C++.
  • Unicode può essere di una preoccupazione, come sto ottenendo le uscite di questo tipo: Shader Variable Found is: |uԯ|uԯ/
  • Lo src shader è passata in un const char * dalla JNI attraverso env->GetStringUTFChars()

Conclusione

Sono sicuro che c'è un modo migliore per farlo, magari usando std::stringstream o qualcosa del genere, ma non ho molta familiarità con esso e vorrei che questo algoritmo funzionasse in qualche modo o in qualche modo. Tuttavia, se questo è il modo "ingenuo" per farlo, sono aperto al suggerimento.

La questione

Qual è il modo migliore per raggiungere questo per ottenere il parsing di lavorare?

risposta

9

Sei sicuro di doverlo fare da solo? GLSL esegue già questa analisi per te e, se desideri un elenco di tutte le variabili di input, puoi ottenerle tramite glGetActiveAttrib/glGetActiveUniform.

Basta interrogare il numero di attributi/uniformi attivi di uno shader collegato e quindi scorrere su ciascun indice interrogando il nome della variabile di input.

http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveAttrib.xml

http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml

+1

dispiace, mi sento un po 'confuso qui: quando si dice interrogare il numero di attribs/uniformi di uno shader legata attivi, cosa si intende per utilizzando uno dei due funzioni avete suggerito o utilizzando una funzione diversa? – zeboidlund

+1

Se leggete la documentazione è spiegato nel primo paragrafo nella sezione "Descrizione": "glGetActiveAttrib restituisce informazioni \t su una variabile attributo attivo nel oggetto programma \t specificato dal programma Il numero di \t attributi attivi può essere ottenuto chiamando. \t glGetProgram \t con il valore GL_ACTIVE_ATTRIBUTES. " – Tim

+1

Ok, fantastico. Grazie. – zeboidlund

Problemi correlati