Initial commit of the Render Monkey Shaders render plugin. At the moment the plugin is able to parse and load any "rfx" (render monkey save file) file that is present under the directory "src/meshlab/shadersrm/" at startup time. The files which are correctly parsed will be displayed under the menu "Render" -> "Shaders". For each shader found in this directory a window dialog is popuped to ask the user some setting: you can select any effect declared in the file, and for each effect you can custom the uniform variables and the textures of each pass. For each pass the vertex program and the fragment program are correcty loaded in memory and the uniform variable (at startup and when modified) are correctly updated in memory (at their right location) as well as the declared textures. The multi pass rendering is still missing, and at the moment the plugin wont interfere the render routine at all.

This commit is contained in:
Paolo Cignoni cignoni 2007-09-12 15:38:01 +00:00
parent b8e483dd16
commit dfaa8beb7b
21 changed files with 3059 additions and 0 deletions

View File

@ -0,0 +1,394 @@
#include "glstateholder.h"
int UniformValue::textureUnit = 0;
UniformValue::UniformValue( UniformVar & v )
{
type = v.type;
name = v.name;
typeString = v.typeString;
memcpy( mat4, v.mat4, 4*4*sizeof(int));
representerTagName = v.representerTagName;
textureName = v.textureName;
QFileInfo finfo(v.textureFilename);
textureFilename = finfo.fileName();
textureGLStates = v.textureGLStates;
textureLoaded = false;
// * if it's a texture, try to load it from the standard path
if( textureFilename != "" ) {
QDir textureDir = QDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
if (textureDir.dirName() == "debug" || textureDir.dirName() == "release" || textureDir.dirName() == "plugins" ) textureDir.cdUp();
#elif defined(Q_OS_MAC)
if (textureDir.dirName() == "MacOS") { for(int i=0;i<4;++i){ textureDir.cdUp(); if(textureDir.exists("textures")) break; } }
#endif
textureDir.cd("textures");
updateUniformVariableValuesFromDialog( 0, 0, QVariant( textureDir.absoluteFilePath(textureFilename)));
}
}
UniformValue::~UniformValue()
{
if( textureLoaded )
glDeleteTextures(1, &textureId);
}
void UniformValue::updateUniformVariableValuesFromDialog( int rowIdx, int colIdx, QVariant newValue )
{
switch( type ) {
case INT: ivalue = newValue.toInt(); break;
case FLOAT: fvalue = newValue.toDouble(); break;
case BOOL: bvalue = newValue.toBool() != 0; break;
case VEC2: case VEC3: case VEC4: vec4[colIdx] = newValue.toDouble(); break;
case IVEC2: case IVEC3: case IVEC4: ivec4[colIdx] = newValue.toInt(); break;
case BVEC2: case BVEC3: case BVEC4: bvec4[colIdx] = newValue.toBool() != 0; break;
case MAT2: mat2[rowIdx][colIdx] = newValue.toDouble(); break;
case MAT3: mat3[rowIdx][colIdx] = newValue.toDouble(); break;
case MAT4: mat4[rowIdx][colIdx] = newValue.toDouble(); break;
case SAMPLER1D: case SAMPLER2D: case SAMPLER3D:
case SAMPLERCUBE: case SAMPLER1DSHADOW: case SAMPLER2DSHADOW:
{
QString newPath;
// * choose the filename with a dialog (55 by convention)
if( rowIdx == 5 && colIdx == 5 ) {
QFileDialog fd(0,"Choose new texture");
QDir texturesDir = QDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
if (texturesDir.dirName() == "debug" || texturesDir.dirName() == "release") texturesDir.cdUp();
#elif defined(Q_OS_MAC)
if (texturesDir.dirName() == "MacOS") { for(int i=0;i<4;++i){ texturesDir.cdUp(); if(texturesDir.exists("textures")) break; } }
#endif
texturesDir.cd("textures");
fd.setDirectory(texturesDir);
fd.move(500, 100);
if (fd.exec())
{
QStringList sels = fd.selectedFiles();
newPath = sels[0];
}
} else
newPath = newValue.toString();
// * Load the new texture from given file
if( textureLoaded )
glDeleteTextures( 1, &textureId);
QImage img, imgScaled, imgGL;
QFileInfo finfo(newPath);
if( finfo.exists() == false ) {
qDebug() << "Texture" << name << "in" << newPath << ": file do not exists";
} else
if( img.load(newPath) == false ) {
QMessageBox::critical(0, "Meshlab", newPath + ": Unsupported texture format.. implement me!");
}
glEnable( GL_TEXTURE_2D );
// image has to be scaled to a 2^n size. We choose the first 2^N <= picture size.
int bestW=pow(2.0,floor(::log(double(img.width() ))/::log(2.0)));
int bestH=pow(2.0,floor(::log(double(img.height()))/::log(2.0)));
if( !img.isNull() ) imgScaled=img.scaled(bestW,bestH,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
imgGL=QGLWidget::convertToGLFormat(imgScaled);
glGenTextures( 1, &textureId );
glBindTexture( GL_TEXTURE_2D, textureId );
glTexImage2D( GL_TEXTURE_2D, 0, 3, imgGL.width(), imgGL.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, imgGL.bits() );
textureLoaded = true;
break;
}
case OTHER:
assert(0);
}
}
bool UniformValue::updateValueInGLMemory()
{
switch(type) {
case INT: glUniform1iARB(location, ivalue); break;
case FLOAT: glUniform1fARB(location, fvalue); break;
case BOOL: glUniform1iARB(location, bvalue); break;
case VEC2: glUniform2fARB(location, vec2[0], vec2[1] ); break;
case VEC3: glUniform3fARB(location, vec3[0], vec3[1], vec3[2] ); break;
case VEC4: glUniform4fARB(location, vec4[0], vec4[1], vec4[2], vec4[3] ); break;
case IVEC2: glUniform2iARB(location, ivec2[0], ivec2[1] ); break;
case IVEC3: glUniform3iARB(location, ivec3[0], ivec3[1], ivec3[2] ); break;
case IVEC4: glUniform4iARB(location, ivec4[0], ivec4[1], ivec4[2], ivec4[3] ); break;
case BVEC2: glUniform2iARB(location, bvec2[0], bvec2[1] ); break;
case BVEC3: glUniform3iARB(location, bvec3[0], bvec3[1], bvec3[2] ); break;
case BVEC4: glUniform4iARB(location, bvec4[0], bvec4[1], bvec4[2], bvec4[3] ); break;
case MAT2: glUniformMatrix2fvARB( location, 1, GL_FALSE, (GLfloat*)mat2 ); break;
case MAT3: glUniformMatrix3fvARB( location, 1, GL_FALSE, (GLfloat*)mat3 ); break;
case MAT4: glUniformMatrix4fvARB( location, 1, GL_FALSE, (GLfloat*)mat4 ); break;
case SAMPLER1D: case SAMPLER2D: case SAMPLER3D: case SAMPLERCUBE: case SAMPLER1DSHADOW: case SAMPLER2DSHADOW:
{
if( textureLoaded == false )
return false;
if( UniformValue::textureUnit >= GL_MAX_TEXTURE_UNITS ) {
QMessageBox::critical(0, "Meshlab", "Number of active texture is greater than max number supported (which is" + QString().setNum(GL_MAX_TEXTURE_UNITS) + ")" );
return false;
}
glActiveTexture( GL_TEXTURE0 + UniformValue::textureUnit );
glBindTexture( GL_TEXTURE_2D, textureId );
glUniform1iARB( location, UniformValue::textureUnit++ );
break;
}
case OTHER:
qDebug() << "Type " << UniformVar::getStringFromUniformType(type) << " not updated in arb memory";
return false;
}
// int err = glGetError();
// if( !err ) qDebug() << "Update done correctly";
// else qDebug() << "Error occurred while updating: " << err;
return true;
}
void UniformValue::VarDump()
{
switch(type) {
case INT: qDebug() << " " << name << "(" << location << "): " << ivalue; break;
case FLOAT: qDebug() << " " << name << "(" << location << "): " << fvalue; break;
case BOOL: qDebug() << " " << name << "(" << location << "): " << bvalue; break;
case OTHER: qDebug() << " " << name << "(" << location << "): OTHER"; break;
case SAMPLER1D: case SAMPLER2D: case SAMPLER3D: case SAMPLERCUBE: case SAMPLER1DSHADOW: case SAMPLER2DSHADOW: if( representerTagName == "RmRenderTarget" ) qDebug() << " " << name << "(" << location << "): RENDER TARGET"; else qDebug() << " " << name << "(" << location << "): " << textureFilename; break;
case VEC2: case VEC3: case VEC4: { int n = type == VEC2 ? 2 : (type == VEC3 ? 3 : 4 ); QString val; for( int i = 0; i < n; i++ ) val += " " + QString().setNum(vec4[i]) + (i+1==n?" ":","); qDebug() << " " << name << "(" << location << "): {" << val.toLatin1().data() << "}"; break; }
case IVEC2: case IVEC3: case IVEC4: { int n = type == IVEC2 ? 2 : (type == IVEC3 ? 3 : 4 ); QString val; for( int i = 0; i < n; i++ ) val += " " + QString().setNum(ivec4[i]) + (i+1==n?" ":","); qDebug() << " " << name << "(" << location << "): {" << val.toLatin1().data() << "}"; break; }
case BVEC2: case BVEC3: case BVEC4: { int n = type == BVEC2 ? 2 : (type == BVEC3 ? 3 : 4 ); QString val; for( int i = 0; i < n; i++ ) val += " " + QString().setNum(bvec4[i]) + (i+1==n?" ":","); qDebug() << " " << name << "(" << location << "): {" << val.toLatin1().data() << "}"; break; }
case MAT2: case MAT3: case MAT4: { int n = type == MAT2 ? 2 : (type == MAT3 ? 3 : 4 ); QString val; for( int i = 0; i < n; i++ ) { val += "["; for( int j = 0; j < n; j++ ) val += " " + QString().setNum(vec4[i*n+j]) + (j+1==n?" ":","); val += "]"; } qDebug() << " " << name << "(" << location << "): { " << val.toLatin1().data() << " }"; break; }
}
}
// ************** GL STATE PASS HOLDER *************** //
GLStatePassHolder::GLStatePassHolder( RmPass & pass )
{
passName = pass.getName();
QString & vprog = pass.getVertex();
QString & fprog = pass.getFragment();
if( vprog.isNull() ) {
setVertexProgram = false;
} else {
setVertexProgram = true;
vhandler = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
const char * vvv = vprog.toLocal8Bit().data();
glShaderSourceARB(vhandler, 1, ((const char **)&vvv), NULL);
}
if( fprog.isNull() ) {
setFragmentProgram = false;
} else {
setFragmentProgram = true;
fhandler = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
const char * fff = fprog.toLocal8Bit().data();
glShaderSourceARB(fhandler, 1, ((const char **)&fff), NULL);
}
for( int i = 0; i < 2; i++ )
for( int j = 0; j < (i == 0 ? pass.vertexUniformVariableSize() : pass.fragmentUniformVariableSize() ); j++ ) {
UniformVar v = pass.getUniformVariable( j, i == 0 ? RmPass::VERTEX : RmPass::FRAGMENT );
if( !uniformValues.contains(v.name) )
uniformValues.insert( v.name, new UniformValue(v));
}
program = glCreateProgramObjectARB();
}
GLStatePassHolder::~GLStatePassHolder()
{
glDeleteObjectARB(program);
glDeleteObjectARB(vhandler);
glDeleteObjectARB(fhandler);
QMapIterator<QString, UniformValue*> it(uniformValues);
while( it.hasNext() ) {
it.next();
delete it.value();
}
}
bool GLStatePassHolder::compile()
{
GLint statusV = 1;
GLint statusF = 1;
if( hasVertexProgram() ) {
glCompileShaderARB(vhandler);
glGetObjectParameterivARB(vhandler, GL_OBJECT_COMPILE_STATUS_ARB, &statusV);
}
if( hasFragmentProgram() ) {
glCompileShaderARB(fhandler);
glGetObjectParameterivARB(fhandler, GL_OBJECT_COMPILE_STATUS_ARB, &statusF);
}
GLsizei length;
if( !statusV ) {
char shlog[2048];
glGetShaderInfoLog(vhandler, 2048, &length, shlog);
lastError = "Pass \"" + passName + "\" Vertex Compiling Error (" + QString().setNum(glGetError()) + "):\n" + QString(shlog);
return false;
}
if( !statusF ) {
char shlog[2048];
glGetShaderInfoLog(fhandler, 2048, &length, shlog);
lastError = "Pass \"" + passName + "\" Fragment Compiling Error (" + QString().setNum(glGetError()) + "):\n" + QString(shlog);
return false;
}
return true;
}
bool GLStatePassHolder::link()
{
if( hasVertexProgram() ) glAttachObjectARB( program, vhandler );
if( hasFragmentProgram() ) glAttachObjectARB( program, fhandler );
glLinkProgramARB(program);
GLint linkStatus;
glGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linkStatus);
if( !linkStatus ) {
GLsizei length;
char shlog[2048];
glGetInfoLogARB(program, 2048, &length, shlog);
lastError = "Pass \"" + passName + "\" Linking Error (" + QString().setNum(glGetError()) + "):\n" + QString(shlog);
return false;
}
QMapIterator<QString, UniformValue*> it(uniformValues);
while( it.hasNext() ) {
it.next();
if( (it.value() -> location = glGetUniformLocationARB( program, it.key().toLocal8Bit().data())) == -1 ) {
lastError = "Pass \"" + passName + "\" Linking Error (" + QString().setNum(glGetError()) + "): Unknown memory location for some variable";
return false;
}
}
return true;
}
void GLStatePassHolder::updateUniformVariableValuesFromDialog( QString varname, int rowIdx, int colIdx, QVariant newValue )
{
UniformValue * var = uniformValues[varname];
if( var )
var -> updateUniformVariableValuesFromDialog( rowIdx, colIdx, newValue );
}
bool GLStatePassHolder::updateUniformVariableValuesInGLMemory()
{
bool ret = true;
UniformValue::textureUnit = 0;
glUseProgramObjectARB(program);
QMapIterator<QString,UniformValue*> it( uniformValues );
while( it.hasNext() ) {
it.next();
if( !it.value() -> updateValueInGLMemory() ) ret = false;
}
return ret;
}
void GLStatePassHolder::VarDump()
{
qDebug() << " Pass:" << passName << "with" << uniformValues.size() << "uniform values";
QMapIterator<QString,UniformValue*> it( uniformValues );
while( it.hasNext() ) {
it.next();
it.value() -> VarDump();
}
}
// ***************** GL STATE HOLDER ****************** //
GLStateHolder::~GLStateHolder( )
{
for( int i = 0; i < passes.size(); i++ )
delete passes[i];
}
void GLStateHolder::setPasses( QList<RmPass> & _passes )
{
for( int i = 0; i < passes.size(); i++ )
delete passes[i];
passes.clear();
for( int i = 0; i < _passes.size(); i++ )
passes.append( new GLStatePassHolder(_passes[i]));
}
bool GLStateHolder::compile()
{
for( int i = 0; i < passes.size(); i++ )
if( passes[i] -> compile() == false ) {
lastError = passes[i] -> getLastError();
supported = false;
return false;
}
return true;
}
bool GLStateHolder::link()
{
for( int i = 0; i < passes.size(); i++ )
if( passes[i] -> link() == false ) {
lastError = passes[i] -> getLastError();
supported = false;
return false;
}
supported = true;
return true;
}
void GLStateHolder::updateUniformVariableValuesFromDialog( QString passname, QString varname, int rowIdx, int colIdx, QVariant newValue )
{
needUpdateInGLMemory = true;
for( int i = 0; i < passes.size(); i++ )
if( passes[i] -> passName == passname ) {
passes[i] -> updateUniformVariableValuesFromDialog( varname, rowIdx, colIdx, newValue );
break;
}
}
bool GLStateHolder::updateUniformVariableValuesInGLMemory()
{
bool ret = true;
needUpdateInGLMemory = false;
for( int i = 0; i < passes.size(); i++ )
if( !passes[i] -> updateUniformVariableValuesInGLMemory() )
ret = false;
glUseProgramObjectARB(0);
return ret;
}
void GLStateHolder::VarDump()
{
qDebug() << "Passes:" << passes.size();
for( int i = 0; i < passes.size(); i++ )
passes[i] -> VarDump();
}

View File

@ -0,0 +1,133 @@
#ifndef __GLSTATEHOLDER_H__
#define __GLSTATEHOLDER_H__
#include "parser/RmPass.h"
#include "parser/UniformVar.h"
#include <QString>
#include <QList>
#include <QMap>
#include <QMapIterator>
#include <QVariant>
#include <QFileDialog>
#include <QApplication>
#include <QImage>
#include <QMessageBox>
#include <GL/glew.h>
#include <QGLWidget>
#include <meshlab/meshmodel.h>
#include <assert.h>
// * Extends the uniform variable class of the RM Parser
// * to add information such as memory location and
// * actual value
class UniformValue : public UniformVar
{
public:
static int textureUnit;
UniformValue( UniformVar & var );
virtual ~UniformValue();
// * the arb memory location
int location;
// * texture mappings
bool textureLoaded;
GLuint textureId;
void updateUniformVariableValuesFromDialog( int rowIdx, int colIdx, QVariant newValue );
bool updateValueInGLMemory();
void VarDump();
};
// * It's the descriptor of a pass: it has the list
// * of uniform variable with their value and memory
// * location, and the ARB program handler
class GLStatePassHolder : public QObject
{
Q_OBJECT
public:
QString passName;
private:
GLhandleARB vhandler;
GLhandleARB fhandler;
bool setVertexProgram;
bool setFragmentProgram;
QString lastError;
GLhandleARB program;
QMap<QString, UniformValue*> uniformValues;
public:
GLStatePassHolder( RmPass & pass );
~GLStatePassHolder( );
bool compile();
bool link();
bool hasVertexProgram() { return setVertexProgram; }
bool hasFragmentProgram() { return setFragmentProgram; }
QString & getLastError() { return lastError; }
void updateUniformVariableValuesFromDialog( QString varname, int rowIdx, int colIdx, QVariant newValue );
bool updateUniformVariableValuesInGLMemory();
void VarDump();
void useProgram() { glUseProgramObjectARB( program ); }
};
// * This class hold the state of the rmshader render:
// * it has e list of passes and for each pass it keeps the
// * list of uniform variable with their memory location and
// * actual value, and the ARB program handler
class GLStateHolder : public QObject
{
Q_OBJECT
QList<GLStatePassHolder*> passes;
QString lastError;
bool supported;
public:
bool needUpdateInGLMemory;
GLStateHolder( ) {needUpdateInGLMemory = true; supported = false;}
GLStateHolder( QList<RmPass> & passes ) { setPasses(passes); needUpdateInGLMemory = true; supported = false; }
~GLStateHolder( );
void setPasses( QList<RmPass> & passes );
bool compile();
bool link();
QString & getLastError() { return lastError; }
void updateUniformVariableValuesFromDialog( QString passname, QString varname, int rowIdx, int colIdx, QVariant newValue );
bool isSupported() { return supported; }
bool updateUniformVariableValuesInGLMemory();
void VarDump();
int passNumber() { return passes.size(); }
void usePassProgram( int i ) { passes[i] -> useProgram(); }
};
#endif

View File

@ -0,0 +1,40 @@
#ifndef __GLSTATE_H__
#define __GLSTATE_H__
#include <QString>
#include <QDomElement>
class GlState
{
public:
QString name;
int state;
int value;
bool valid;
GlState( QString & _name, int _state, int _value ) {
name = _name;
state = _state;
value = _value;
valid = true;
}
GlState( QDomElement xml ) {
bool ok1,ok2;
name = xml.attribute("NAME");
state = xml.attribute("STATE").toUInt( &ok1 );
value = xml.attribute("VALUE").toUInt( &ok2 );
valid = ( xml.tagName() == "RmState" && xml.attribute("API") == "OpenGL" && ok1 && ok2 );
}
bool isValid() { return valid; }
int getValue() { return value; }
int getState() { return state; }
QString & getName() { return name; }
};
#endif

View File

@ -0,0 +1,137 @@
#############################################################################
# Makefile for building: ParserXml
# Generated by qmake (2.01a) (Qt 4.3.1) on: mer 5. set 15:35:24 2007
# Project: ParserXml.pro
# Template: app
# Command: c:\Qt\4.3.1\bin\qmake.exe -win32 -o Makefile ParserXml.pro
#############################################################################
first: debug
install: debug-install
uninstall: debug-uninstall
MAKEFILE = Makefile
QMAKE = c:\Qt\4.3.1\bin\qmake.exe
DEL_FILE = del
CHK_DIR_EXISTS= if not exist
MKDIR = mkdir
COPY = copy /y
COPY_FILE = $(COPY)
COPY_DIR = xcopy /s /q /y /i
INSTALL_FILE = $(COPY_FILE)
INSTALL_PROGRAM = $(COPY_FILE)
INSTALL_DIR = $(COPY_DIR)
DEL_FILE = del
SYMLINK =
DEL_DIR = rmdir
MOVE = move
CHK_DIR_EXISTS= if not exist
MKDIR = mkdir
SUBTARGETS = \
debug \
release
debug: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug
debug-make_default: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug
debug-make_first: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug first
debug-all: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug all
debug-clean: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug clean
debug-distclean: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug distclean
debug-install: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug install
debug-uninstall: $(MAKEFILE).Debug FORCE
$(MAKE) -f $(MAKEFILE).Debug uninstall
release: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release
release-make_default: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release
release-make_first: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release first
release-all: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release all
release-clean: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release clean
release-distclean: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release distclean
release-install: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release install
release-uninstall: $(MAKEFILE).Release FORCE
$(MAKE) -f $(MAKEFILE).Release uninstall
Makefile: ParserXml.pro c:\Qt\4.3.1\mkspecs\win32-g++\qmake.conf c:\Qt\4.3.1\mkspecs\qconfig.pri \
c:\Qt\4.3.1\mkspecs\features\qt_functions.prf \
c:\Qt\4.3.1\mkspecs\features\qt_config.prf \
c:\Qt\4.3.1\mkspecs\features\exclusive_builds.prf \
c:\Qt\4.3.1\mkspecs\features\default_pre.prf \
c:\Qt\4.3.1\mkspecs\features\win32\default_pre.prf \
c:\Qt\4.3.1\mkspecs\features\debug.prf \
c:\Qt\4.3.1\mkspecs\features\debug_and_release.prf \
c:\Qt\4.3.1\mkspecs\features\default_post.prf \
c:\Qt\4.3.1\mkspecs\features\win32\console.prf \
c:\Qt\4.3.1\mkspecs\features\qt.prf \
c:\Qt\4.3.1\mkspecs\features\win32\thread.prf \
c:\Qt\4.3.1\mkspecs\features\moc.prf \
c:\Qt\4.3.1\mkspecs\features\win32\rtti.prf \
c:\Qt\4.3.1\mkspecs\features\win32\exceptions.prf \
c:\Qt\4.3.1\mkspecs\features\win32\stl.prf \
c:\Qt\4.3.1\mkspecs\features\shared.prf \
c:\Qt\4.3.1\mkspecs\features\warn_on.prf \
c:\Qt\4.3.1\mkspecs\features\resources.prf \
c:\Qt\4.3.1\mkspecs\features\uic.prf \
c:\Qt\4.3.1\mkspecs\features\yacc.prf \
c:\Qt\4.3.1\mkspecs\features\lex.prf
$(QMAKE) -win32 -o Makefile ParserXml.pro
c:\Qt\4.3.1\mkspecs\qconfig.pri:
c:\Qt\4.3.1\mkspecs\features\qt_functions.prf:
c:\Qt\4.3.1\mkspecs\features\qt_config.prf:
c:\Qt\4.3.1\mkspecs\features\exclusive_builds.prf:
c:\Qt\4.3.1\mkspecs\features\default_pre.prf:
c:\Qt\4.3.1\mkspecs\features\win32\default_pre.prf:
c:\Qt\4.3.1\mkspecs\features\debug.prf:
c:\Qt\4.3.1\mkspecs\features\debug_and_release.prf:
c:\Qt\4.3.1\mkspecs\features\default_post.prf:
c:\Qt\4.3.1\mkspecs\features\win32\console.prf:
c:\Qt\4.3.1\mkspecs\features\qt.prf:
c:\Qt\4.3.1\mkspecs\features\win32\thread.prf:
c:\Qt\4.3.1\mkspecs\features\moc.prf:
c:\Qt\4.3.1\mkspecs\features\win32\rtti.prf:
c:\Qt\4.3.1\mkspecs\features\win32\exceptions.prf:
c:\Qt\4.3.1\mkspecs\features\win32\stl.prf:
c:\Qt\4.3.1\mkspecs\features\shared.prf:
c:\Qt\4.3.1\mkspecs\features\warn_on.prf:
c:\Qt\4.3.1\mkspecs\features\resources.prf:
c:\Qt\4.3.1\mkspecs\features\uic.prf:
c:\Qt\4.3.1\mkspecs\features\yacc.prf:
c:\Qt\4.3.1\mkspecs\features\lex.prf:
qmake: qmake_all FORCE
@$(QMAKE) -win32 -o Makefile ParserXml.pro
qmake_all: FORCE
make_default: debug-make_default release-make_default FORCE
make_first: debug-make_first release-make_first FORCE
all: debug-all release-all FORCE
clean: debug-clean release-clean FORCE
distclean: debug-distclean release-distclean FORCE
-$(DEL_FILE) Makefile
debug-mocclean: $(MAKEFILE).Debug
$(MAKE) -f $(MAKEFILE).Debug mocclean
release-mocclean: $(MAKEFILE).Release
$(MAKE) -f $(MAKEFILE).Release mocclean
mocclean: debug-mocclean release-mocclean
debug-mocables: $(MAKEFILE).Debug
$(MAKE) -f $(MAKEFILE).Debug mocables
release-mocables: $(MAKEFILE).Release
$(MAKE) -f $(MAKEFILE).Release mocables
mocables: debug-mocables release-mocables
FORCE:
$(MAKEFILE).Debug: Makefile
$(MAKEFILE).Release: Makefile

View File

@ -0,0 +1,155 @@
#############################################################################
# Makefile for building: ParserXml
# Generated by qmake (2.01a) (Qt 4.3.1) on: mer 5. set 15:35:24 2007
# Project: ParserXml.pro
# Template: app
#############################################################################
####### Compiler, tools and options
CC = gcc
CXX = g++
DEFINES = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT
CFLAGS = -g -Wall $(DEFINES)
CXXFLAGS = -g -frtti -fexceptions -mthreads -Wall $(DEFINES)
INCPATH = -I"c:\Qt\4.3.1\include\QtCore" -I"c:\Qt\4.3.1\include\QtCore" -I"c:\Qt\4.3.1\include\QtGui" -I"c:\Qt\4.3.1\include\QtGui" -I"c:\Qt\4.3.1\include\QtXml" -I"c:\Qt\4.3.1\include\QtXml" -I"c:\Qt\4.3.1\include" -I"c:\Qt\4.3.1\include\ActiveQt" -I"debug" -I"." -I"c:\Qt\4.3.1\mkspecs\win32-g++"
LINK = g++
LFLAGS = -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -Wl,-subsystem,console -mthreads -Wl
LIBS = -L"c:\Qt\4.3.1\lib" -lQtXmld4 -lQtGuid4 -lQtCored4
QMAKE = c:\Qt\4.3.1\bin\qmake.exe
IDC = c:\Qt\4.3.1\bin\idc.exe
IDL = midl
ZIP = zip -r -9
DEF_FILE =
RES_FILE =
COPY = copy /y
COPY_FILE = $(COPY)
COPY_DIR = xcopy /s /q /y /i
DEL_FILE = del
DEL_DIR = rmdir
MOVE = move
CHK_DIR_EXISTS= if not exist
MKDIR = mkdir
INSTALL_FILE = $(COPY_FILE)
INSTALL_PROGRAM = $(COPY_FILE)
INSTALL_DIR = $(COPY_DIR)
####### Output directory
OBJECTS_DIR = debug
####### Files
SOURCES = main.cpp \
RmXmlParser.cpp \
RmPass.cpp \
UniformVar.cpp
OBJECTS = debug\main.o \
debug\RmXmlParser.o \
debug\RmPass.o \
debug\UniformVar.o
DIST =
QMAKE_TARGET = ParserXml
DESTDIR = debug\ #avoid trailing-slash linebreak
TARGET = ParserXml.exe
DESTDIR_TARGET = debug\ParserXml.exe
####### Implicit rules
.SUFFIXES: .cpp .cc .cxx .c
.cpp.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.cc.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.cxx.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.c.o:
$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
####### Build rules
first: all
all: Makefile.Debug $(DESTDIR_TARGET)
$(DESTDIR_TARGET): $(OBJECTS)
$(LINK) $(LFLAGS) -o "$(DESTDIR_TARGET)" $(OBJECTS) $(LIBS)
qmake: FORCE
@$(QMAKE) -win32 -o Makefile.Debug ParserXml.pro
dist:
$(ZIP) ParserXml.zip $(SOURCES) $(DIST) ParserXml.pro c:\Qt\4.3.1\mkspecs\qconfig.pri c:\Qt\4.3.1\mkspecs\features\qt_functions.prf c:\Qt\4.3.1\mkspecs\features\qt_config.prf c:\Qt\4.3.1\mkspecs\features\exclusive_builds.prf c:\Qt\4.3.1\mkspecs\features\default_pre.prf c:\Qt\4.3.1\mkspecs\features\win32\default_pre.prf c:\Qt\4.3.1\mkspecs\features\debug.prf c:\Qt\4.3.1\mkspecs\features\debug_and_release.prf c:\Qt\4.3.1\mkspecs\features\default_post.prf c:\Qt\4.3.1\mkspecs\features\build_pass.prf c:\Qt\4.3.1\mkspecs\features\win32\console.prf c:\Qt\4.3.1\mkspecs\features\qt.prf c:\Qt\4.3.1\mkspecs\features\win32\thread.prf c:\Qt\4.3.1\mkspecs\features\moc.prf c:\Qt\4.3.1\mkspecs\features\win32\rtti.prf c:\Qt\4.3.1\mkspecs\features\win32\exceptions.prf c:\Qt\4.3.1\mkspecs\features\win32\stl.prf c:\Qt\4.3.1\mkspecs\features\shared.prf c:\Qt\4.3.1\mkspecs\features\warn_on.prf c:\Qt\4.3.1\mkspecs\features\resources.prf c:\Qt\4.3.1\mkspecs\features\uic.prf c:\Qt\4.3.1\mkspecs\features\yacc.prf c:\Qt\4.3.1\mkspecs\features\lex.prf HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES
clean: compiler_clean
-$(DEL_FILE) debug\main.o debug\RmXmlParser.o debug\RmPass.o debug\UniformVar.o
distclean: clean
-$(DEL_FILE) $(DESTDIR_TARGET)
-$(DEL_FILE) Makefile.Debug
mocclean: compiler_moc_header_clean compiler_moc_source_clean
mocables: compiler_moc_header_make_all compiler_moc_source_make_all
compiler_moc_header_make_all:
compiler_moc_header_clean:
compiler_rcc_make_all:
compiler_rcc_clean:
compiler_image_collection_make_all: qmake_image_collection.cpp
compiler_image_collection_clean:
-$(DEL_FILE) qmake_image_collection.cpp
compiler_moc_source_make_all:
compiler_moc_source_clean:
compiler_uic_make_all:
compiler_uic_clean:
compiler_yacc_decl_make_all:
compiler_yacc_decl_clean:
compiler_yacc_impl_make_all:
compiler_yacc_impl_clean:
compiler_lex_make_all:
compiler_lex_clean:
compiler_clean:
####### Compile
debug\main.o: main.cpp RmXmlParser.h \
RmEffect.h \
RmPass.h \
GlState.h \
UniformVar.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\main.o main.cpp
debug\RmXmlParser.o: RmXmlParser.cpp RmXmlParser.h \
RmEffect.h \
RmPass.h \
GlState.h \
UniformVar.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\RmXmlParser.o RmXmlParser.cpp
debug\RmPass.o: RmPass.cpp RmPass.h \
GlState.h \
UniformVar.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\RmPass.o RmPass.cpp
debug\UniformVar.o: UniformVar.cpp UniformVar.h \
GlState.h \
RmXmlParser.h \
RmEffect.h \
RmPass.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\UniformVar.o UniformVar.cpp
####### Install
install: FORCE
uninstall: FORCE
FORCE:

View File

@ -0,0 +1,155 @@
#############################################################################
# Makefile for building: ParserXml
# Generated by qmake (2.01a) (Qt 4.3.1) on: mer 5. set 15:35:24 2007
# Project: ParserXml.pro
# Template: app
#############################################################################
####### Compiler, tools and options
CC = gcc
CXX = g++
DEFINES = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT
CFLAGS = -O2 -Wall $(DEFINES)
CXXFLAGS = -O2 -frtti -fexceptions -mthreads -Wall $(DEFINES)
INCPATH = -I"c:\Qt\4.3.1\include\QtCore" -I"c:\Qt\4.3.1\include\QtCore" -I"c:\Qt\4.3.1\include\QtGui" -I"c:\Qt\4.3.1\include\QtGui" -I"c:\Qt\4.3.1\include\QtXml" -I"c:\Qt\4.3.1\include\QtXml" -I"c:\Qt\4.3.1\include" -I"c:\Qt\4.3.1\include\ActiveQt" -I"release" -I"." -I"c:\Qt\4.3.1\mkspecs\win32-g++"
LINK = g++
LFLAGS = -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -Wl,-s -Wl,-subsystem,console -mthreads -Wl
LIBS = -L"c:\Qt\4.3.1\lib" -lQtXml4 -lQtGui4 -lQtCore4
QMAKE = c:\Qt\4.3.1\bin\qmake.exe
IDC = c:\Qt\4.3.1\bin\idc.exe
IDL = midl
ZIP = zip -r -9
DEF_FILE =
RES_FILE =
COPY = copy /y
COPY_FILE = $(COPY)
COPY_DIR = xcopy /s /q /y /i
DEL_FILE = del
DEL_DIR = rmdir
MOVE = move
CHK_DIR_EXISTS= if not exist
MKDIR = mkdir
INSTALL_FILE = $(COPY_FILE)
INSTALL_PROGRAM = $(COPY_FILE)
INSTALL_DIR = $(COPY_DIR)
####### Output directory
OBJECTS_DIR = release
####### Files
SOURCES = main.cpp \
RmXmlParser.cpp \
RmPass.cpp \
UniformVar.cpp
OBJECTS = release\main.o \
release\RmXmlParser.o \
release\RmPass.o \
release\UniformVar.o
DIST =
QMAKE_TARGET = ParserXml
DESTDIR = release\ #avoid trailing-slash linebreak
TARGET = ParserXml.exe
DESTDIR_TARGET = release\ParserXml.exe
####### Implicit rules
.SUFFIXES: .cpp .cc .cxx .c
.cpp.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.cc.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.cxx.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
.c.o:
$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
####### Build rules
first: all
all: Makefile.Release $(DESTDIR_TARGET)
$(DESTDIR_TARGET): $(OBJECTS)
$(LINK) $(LFLAGS) -o "$(DESTDIR_TARGET)" $(OBJECTS) $(LIBS)
qmake: FORCE
@$(QMAKE) -win32 -o Makefile.Release ParserXml.pro
dist:
$(ZIP) ParserXml.zip $(SOURCES) $(DIST) ParserXml.pro c:\Qt\4.3.1\mkspecs\qconfig.pri c:\Qt\4.3.1\mkspecs\features\qt_functions.prf c:\Qt\4.3.1\mkspecs\features\qt_config.prf c:\Qt\4.3.1\mkspecs\features\exclusive_builds.prf c:\Qt\4.3.1\mkspecs\features\default_pre.prf c:\Qt\4.3.1\mkspecs\features\win32\default_pre.prf c:\Qt\4.3.1\mkspecs\features\release.prf c:\Qt\4.3.1\mkspecs\features\debug_and_release.prf c:\Qt\4.3.1\mkspecs\features\default_post.prf c:\Qt\4.3.1\mkspecs\features\build_pass.prf c:\Qt\4.3.1\mkspecs\features\win32\console.prf c:\Qt\4.3.1\mkspecs\features\qt.prf c:\Qt\4.3.1\mkspecs\features\win32\thread.prf c:\Qt\4.3.1\mkspecs\features\moc.prf c:\Qt\4.3.1\mkspecs\features\win32\rtti.prf c:\Qt\4.3.1\mkspecs\features\win32\exceptions.prf c:\Qt\4.3.1\mkspecs\features\win32\stl.prf c:\Qt\4.3.1\mkspecs\features\shared.prf c:\Qt\4.3.1\mkspecs\features\warn_on.prf c:\Qt\4.3.1\mkspecs\features\resources.prf c:\Qt\4.3.1\mkspecs\features\uic.prf c:\Qt\4.3.1\mkspecs\features\yacc.prf c:\Qt\4.3.1\mkspecs\features\lex.prf HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES
clean: compiler_clean
-$(DEL_FILE) release\main.o release\RmXmlParser.o release\RmPass.o release\UniformVar.o
distclean: clean
-$(DEL_FILE) $(DESTDIR_TARGET)
-$(DEL_FILE) Makefile.Release
mocclean: compiler_moc_header_clean compiler_moc_source_clean
mocables: compiler_moc_header_make_all compiler_moc_source_make_all
compiler_moc_header_make_all:
compiler_moc_header_clean:
compiler_rcc_make_all:
compiler_rcc_clean:
compiler_image_collection_make_all: qmake_image_collection.cpp
compiler_image_collection_clean:
-$(DEL_FILE) qmake_image_collection.cpp
compiler_moc_source_make_all:
compiler_moc_source_clean:
compiler_uic_make_all:
compiler_uic_clean:
compiler_yacc_decl_make_all:
compiler_yacc_decl_clean:
compiler_yacc_impl_make_all:
compiler_yacc_impl_clean:
compiler_lex_make_all:
compiler_lex_clean:
compiler_clean:
####### Compile
release\main.o: main.cpp RmXmlParser.h \
RmEffect.h \
RmPass.h \
GlState.h \
UniformVar.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\main.o main.cpp
release\RmXmlParser.o: RmXmlParser.cpp RmXmlParser.h \
RmEffect.h \
RmPass.h \
GlState.h \
UniformVar.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\RmXmlParser.o RmXmlParser.cpp
release\RmPass.o: RmPass.cpp RmPass.h \
GlState.h \
UniformVar.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\RmPass.o RmPass.cpp
release\UniformVar.o: UniformVar.cpp UniformVar.h \
GlState.h \
RmXmlParser.h \
RmEffect.h \
RmPass.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\UniformVar.o UniformVar.cpp
####### Install
install: FORCE
uninstall: FORCE
FORCE:

View File

@ -0,0 +1,32 @@
#ifndef __RMEFFECT_H__
#define __RMEFFECT_H__
#include <QString>
#include <QList>
#include "RmPass.h"
class RmEffect
{
QString name;
QList<RmPass> passlist;
public:
RmEffect( QString _name ) { name = _name; }
int size() { return passlist.size(); }
RmPass & at( int idx ) { return passlist[idx]; }
RmPass & operator[] (int idx) {return passlist[idx]; }
QList<RmPass> & getPassList() { return passlist; }
void addPass( RmPass pass ) { passlist.append(pass); }
QString & getName() { return name; }
void sortPasses() { qSort( passlist.begin(), passlist.end() ); }
};
#endif

View File

@ -0,0 +1,36 @@
#include "RmPass.h"
UniformVar RmPass::searchFragmentUniformVariable( QString & name) {
return searchUniformVariable( name, RmPass::FRAGMENT);
}
UniformVar RmPass::searchVertexUniformVariable( QString & name) {
return searchUniformVariable( name, RmPass::VERTEX);
}
UniformVar RmPass::searchUniformVariable( QString & name, enum CodeType codetype )
{
QString & source = codetype == RmPass::FRAGMENT ? fragment : vertex;
int namelen = name.length();
int start = 0;
int pos_name, pos_unif;
while( (pos_name = source.indexOf( name, start )) != -1)
{
start += namelen;
if(( pos_unif = source.lastIndexOf( "uniform", pos_name)) == -1 ) continue;
QString declaration = source.mid( pos_unif, pos_name - pos_unif + namelen + 1);
QStringList list = declaration.split(QRegExp("\\s+"));
if( list.size() != 3 ) continue;
if( list[0] != "uniform" ) continue;
if( list[2] != name && list[2] != name + QString(";") ) continue;
return UniformVar( name, list[1], UniformVar::getTypeFromString( list[1] ) );
}
return UniformVar();
}

View File

@ -0,0 +1,115 @@
#ifndef __RMPASS_H__
#define __RMPASS_H__
#include <QList>
#include <QString>
#include <QStringList>
#include <qDebug>
#include "GlState.h"
#include "UniformVar.h"
class RenderTarget {
public:
QString name;
bool renderToScreen;
bool colorClear;
bool depthClear;
float clearColorValue;
float depthClearValue;
RenderTarget(QString _name = QString(), bool _renderToScreen = false, bool _colorClear = false, bool _depthClear = false, float _clearColorValue = 0, float _depthClearValue = 0) {
name = _name;
renderToScreen = _renderToScreen;
colorClear = _colorClear;
depthClear = _depthClear;
clearColorValue = _clearColorValue;
depthClearValue = _depthClearValue;
}
};
class RmPass
{
public:
enum CodeType {
FRAGMENT,
VERTEX
};
private:
QString name;
int index;
QString fragment;
QString vertex;
QList<UniformVar> fragmentUniform;
QList<UniformVar> vertexUniform;
QString modelReference;
QString modelReferenceFileName;
QList<GlState> states;
RenderTarget renderTarget;
// * we look for a variable declared as uniform in a specific
// * source code (fragment or vertex's one) and check for its type
UniformVar searchUniformVariable( QString & name, enum CodeType codetype);
public:
RmPass( QString _name = QString(), int _index = -1) { name = _name; index = _index; }
virtual ~RmPass( ){}
UniformVar searchFragmentUniformVariable( QString & name);
UniformVar searchVertexUniformVariable( QString & name );
void addOpenGLState( GlState & state ) { states.append(state); }
// * Setter and Getter
bool hasIndex() { return index != -1; }
int getIndex() { return index; }
void setModelReference( QString _modelReference ) { modelReference = _modelReference; }
QString & getModelReference( ) { return modelReference; }
void setModelReferenceFileName( QString _modelReferenceFileName ) { modelReferenceFileName = _modelReferenceFileName; }
QString & getModelReferenceFileName( ) { return modelReferenceFileName; }
void setFragment( QString _fragment ) { fragment = _fragment; }
QString & getFragment( ) { return fragment; }
void setVertex( QString _vertex ) { vertex = _vertex; }
QString & getVertex( ) { return vertex; }
QString & getName() { return name; }
void setRenderTarget( RenderTarget rt ) { renderTarget = rt; }
RenderTarget & getRenderTarget() { return renderTarget; }
bool hasRenderTarget() { return !renderTarget.name.isNull(); }
void addFragmentUniformVariable( UniformVar & var ) { fragmentUniform.append(var); }
void addVertexUniformVariable( UniformVar & var ) { vertexUniform.append(var); }
int fragmentUniformVariableSize() { return fragmentUniform.size(); }
int vertexUniformVariableSize() { return vertexUniform.size(); }
UniformVar & getFragmentUniformVariable( int idx ) { return getUniformVariable( idx, RmPass::FRAGMENT ); }
UniformVar & getVertexUniformVariable( int idx ) { return getUniformVariable( idx, RmPass::VERTEX ); }
UniformVar & getUniformVariable( int idx, enum CodeType codetype ) {
if( codetype == RmPass::FRAGMENT ) return fragmentUniform[idx];
return vertexUniform[idx];
}
int openGLStatesSize() { return states.size(); }
GlState & getOpenGLState( int idx ) { return states[idx]; }
bool operator< (const RmPass & p) const { return index < p.index; }
};
#endif

View File

@ -0,0 +1,247 @@
#include "RmXmlParser.h"
bool RmXmlParser::parse( QString _filename )
{
if( !_filename.isNull() ) setFileName( _filename );
QFile file( filename );
effects.clear();
// * open the file..
if( !file.open( QIODevice::ReadOnly | QIODevice::Text )) {
error = "Impossible to open the specified file: ";
error += filename;
return false;
}
QString errorMsg;
int errorLine, errorColumn;
// * .. and parse the xml document
if( !doc.setContent( &file, &errorMsg, &errorLine, &errorColumn ) ) {
error = QString( "Xml Parse Error ") + filename;
error += QString("(") + QString().setNum(errorLine) + QString(",") + QString().setNum(errorColumn) + QString("): ") + errorMsg;
return false;
}
QDomElement root = doc.documentElement();
// * This is what i understood and what this parser does.
// * the xml looks like to have one or more RmOpenGLEffect, and each one can
// * contain one or more RmGLPass. The uniform variables are tagged inside the
// * RmGLPass as RmShaderConstant or RmSampler. They are a RmShaderConstant when
// * the type is a "primitive" one (float int vec2, mat4 ..); if they are
// * a RmSampler then they probably refers to a texture. In this case inside the
// * RmGLPass is specified a tag RmTextureObject with the name of variable.
// * This tag tells us the opengl state for the texture and a texture reference.
// * Note, it can happend that in the source code is specified a uniform variable
// * that is not used: in this case no RmShaderConstant neither a RmSampler will
// * appear in RmGLPass.
// *
// * The values of the uniform variable (such as default value, min and max value
// * for RmShaderConstant, and the file name for the RmSampler) are kept in tags
// * at the top level of the xml tree, and they have as tagname something like
// * RmMatrixVariable, RmVectorVariable, RmFloatVariable, Rm2DTextureVariable,
// * RmCubemapVariable etc.. according to the variable type
// *
// * we look for RmOpenGLEffect xml tag
QDomNodeList list = root.elementsByTagName("RmOpenGLEffect");
for( int i = 0; i < list.size(); i++ ) {
QDomElement effectElement = list.at(i).toElement();
RmEffect eff(effectElement.attribute("NAME", "name not set" ));
// * each effect has a number (0-n) of RmGLPass. We search for them
QDomNodeList passlist = effectElement.elementsByTagName( "RmGLPass" );
for( int j = 0; j < passlist.size(); j++ ) {
// * get the name of pass
QDomNode passNode = passlist.at(j);
QDomElement elp = passNode.toElement();
bool ok;
int index = elp.attribute("PASS_INDEX").toInt(&ok);
RmPass pass( elp.attribute("NAME", "name not set" ), (ok ? index : -1));
// * get the name of model reference and its filename
QDomElement modelRefEl = passNode.firstChildElement( "RmModelReference");
if( modelRefEl.isNull() == false ) {
pass.setModelReference( modelRefEl.attribute("NAME"));
QDomElement modelDataEl = RmXmlParser::getDomElement( root, "RmModelData", pass.getModelReference() );
if( modelDataEl.isNull() == false )
pass.setModelReferenceFileName( modelDataEl.attribute("FILE_NAME"));
}
// * openGL state
QDomElement stateEl = passNode.firstChildElement( "RmRenderStateBlock");
if( stateEl.isNull() == false ) {
QDomNodeList statelist = stateEl.elementsByTagName( "RmState" );
for( int k = 0; k < statelist.size(); k++ ) {
GlState s( statelist.at(k).toElement() );
if( s.valid )
pass.addOpenGLState( s );
}
}
// * get the render target
QDomElement renderEl = passNode.firstChildElement( "RmRenderTarget" );
if( renderEl.isNull() == false ) {
RenderTarget rt( renderEl.attribute("NAME"));
rt.renderToScreen = renderEl.attribute("RENDER_TO_SCREEN") == "TRUE";
rt.colorClear = renderEl.attribute("COLOR_CLEAR") == "TRUE";
rt.depthClear = renderEl.attribute("DEPTH_CLEAR") == "TRUE";
rt.clearColorValue = renderEl.attribute("CLEAR_COLOR_VALUE").toDouble();
rt.depthClearValue = renderEl.attribute("DEPTH_CLEAR_VALUE").toDouble();
pass.setRenderTarget(rt);
}
// * get the source code of fragment and vertex program
QDomNodeList sourcelist = elp.elementsByTagName( "RmGLShader" );
for( int k = 0; k < sourcelist.size(); k++ ) {
QDomNode elnode = sourcelist.at(k);
QDomElement elsource = elnode.toElement();
QString name = elsource.attribute("NAME");
if( name == "Fragment Program" || name == "Fragment Shader" ) {
pass.setFragment( elsource.text() );
} else
if( name == "Vertex Program" || name == "Vertex Shader" ) {
pass.setVertex( elsource.text() );
}
}
// * get the name of constant uniform variables and search
// * in the whole document for their values
QDomNodeList constlist = elp.elementsByTagName( "RmShaderConstant" );
for( int k = 0; k < constlist.size(); k++ ) {
QString name = constlist.at(k).toElement().attribute("NAME");
UniformVar var = pass.searchFragmentUniformVariable( name );
if( var.isNull() == false ) {
var.getValueFromXmlDocument(root, effectElement);
pass.addFragmentUniformVariable(var);
}
var = pass.searchVertexUniformVariable(name);
if( var.isNull() == false ) {
var.getValueFromXmlDocument(root, effectElement);
pass.addVertexUniformVariable(var);
}
}
// * and texture uniform variables
QDomNodeList textureObjectList = elp.elementsByTagName( "RmTextureObject" );
QDomNodeList samplerlist = elp.elementsByTagName( "RmSampler" );
for( int k = 0; k < samplerlist.size(); k++ ) {
QString name = samplerlist.at(k).toElement().attribute("NAME");
QString textureName;
QList<GlState> GLstates;
// * First get the textureObject xml tag relative to this texture
for( int q = 0; q < textureObjectList.size(); q++ ) {
QDomElement textEl = textureObjectList.at(q).toElement();
QString toName = textEl.attribute("NAME");
if( toName == name ) {
QDomElement trEl = textEl.firstChildElement( "RmTextureReference");
if( !trEl.isNull() )
textureName = trEl.attribute("NAME");
// * save the GlStates
QDomNodeList statesList = textEl.elementsByTagName( "RmState" );
for( int w = 0; w < statesList.size(); w++ ) // * LOL! i,j,k,q,w used !
GLstates.append( statesList.at(w).toElement() );
break;
}
}
// * then search the variable in the source code
UniformVar var = pass.searchFragmentUniformVariable( name );
if( var.isNull() == false ) {
var.textureName = textureName;
var.textureGLStates = GLstates;
var.getValueFromXmlDocument(root, effectElement);
pass.addFragmentUniformVariable(var);
}
var = pass.searchVertexUniformVariable(name);
if( var.isNull() == false ) {
var.textureName = textureName;
var.textureGLStates = GLstates;
var.getValueFromXmlDocument(root, effectElement);
pass.addVertexUniformVariable(var);
}
}
eff.addPass( pass );
}
eff.sortPasses();
effects.append(eff);
}
return true;
}
void RmXmlParser::VarDump( bool extendedDump )
{
qDebug() << "";
qDebug() << "Dumping:" << filename;
qDebug() << "Found" << effects.size() << "RmOpenGLEffect:";
for( int i = 0; i < effects.size(); i++ ) {
RmEffect eff = effects[i];
qDebug() << " RmEffect" << eff.getName() << "with" << eff.size() << "pass";
for( int j = 0; j < eff.size(); j++ ) {
RmPass pass = eff[j];
qDebug() << " " << (pass.hasIndex()? QString(QString().setNum(pass.getIndex()) + "'").toLatin1().data() : QString("").toLatin1().data()) << "Pass" << pass.getName() << "on model"<< pass.getModelReference() << "("<<pass.getModelReferenceFileName().toLatin1().data() <<")";
if( pass.hasRenderTarget() ) {
RenderTarget rt = pass.getRenderTarget();
qDebug() << " Render Target:" << rt.name << (rt.colorClear ? " (with color clear: " + QString().setNum(rt.clearColorValue) + ")" : "") << (rt.colorClear ? " (with depth clear: " + QString().setNum(rt.depthClearValue) + ")" : "");
}
if( pass.openGLStatesSize() == 0 )
qDebug() << " with no opengl states set";
else {
qDebug() << " with" << pass.openGLStatesSize() << "opengl states set";
for( int k = 0; k < pass.openGLStatesSize(); k++ )
qDebug() << " " << pass.getOpenGLState(k).name << " (" << QString().setNum(pass.getOpenGLState(k).state).toLatin1().data() << ") =>" << pass.getOpenGLState(k).value;
}
qDebug() << " - Fragment (" << pass.getFragment().length() << "bytes ): " << pass.getFragment().mid(0, 50).replace( "\n", " " ).replace("\r","") << "...";
qDebug() << " There are" << pass.fragmentUniformVariableSize() << "uniform variables";
for( int k = 0; k < pass.fragmentUniformVariableSize(); k++ )
pass.getFragmentUniformVariable( k ).VarDump(12, extendedDump);
qDebug() << " - Vertex (" << pass.getVertex().length() << "bytes ): " << pass.getVertex().mid(0, 50).replace( "\n", " " ).replace("\r","") << "...";
qDebug() << " There are" << pass.vertexUniformVariableSize() << "uniform variables";
for( int k = 0; k < pass.vertexUniformVariableSize(); k++ )
pass.getVertexUniformVariable( k ).VarDump(12, extendedDump);
}
}
qDebug() << "";
}
QDomElement RmXmlParser::getDomElement( QDomElement & root, QString tagname, QString name )
{
QDomNodeList list = root.elementsByTagName( tagname );
for( int i = 0; i < list.size(); i++ ) {
QString elName = list.at(i).toElement().attribute("NAME");
if( name == elName )
return list.at(i).toElement();
}
return QDomElement();
}

View File

@ -0,0 +1,80 @@
#ifndef __RMXMLPARSER_H__
#define __RMXMLPARSER_H__
#include <QString>
#include <QFile>
#include <QDomDocument>
#include <qDebug>
#include <QList>
#include "RmEffect.h"
#include "RmPass.h"
#include "UniformVar.h"
#include "GlState.h"
/*
* This is the main class for RenderMonkey file (.rfx) Xml Parser.
* A RenderMonkey file can contain any number of RmOpenGLEffect, each of which can
* contain any number of RmGLPass. Not all the pass have a fragment or vertex
* program, so we ignore the one that do not have them
* It works on a file corresponding to the given file name and the parsing
* is invoked by calling parse(). On success, this is the tree of class
* collected by the parser:
*
* RmXmlParser:
* - List< RmEffect >, each RmEffect has:
* - List< RmPass >, each RmPass has:
* - the fragment program source code
* - the vertex program source code
* - the uniform variable used in the fragment program
* - the uniform variable used in the vertex program
* - other infos such as openGL state and model reference
*
* Any class that is a container of List< other class > has these three methods:
* - int size() to know the list size
* - T & at(int idx) to get the idx-th element of the list
* - T & operator[] (int idx) as above
*
*
*/
class RmXmlParser
{
QString error;
QString filename;
QDomDocument doc;
QList<RmEffect> effects;
public:
RmXmlParser( ) {}
RmXmlParser( QString filename ) { setFileName(filename); }
virtual ~RmXmlParser( ){}
// * start the parsing
// * return true on success
// * return false on failing, then use getError()
bool parse( QString filename = QString() );
QString & getFileName() { return filename; }
QString & errorString() { return error; }
void setFileName( QString _filename ) { filename = _filename; }
// * These are to manipulate the list of effects
int size() { return effects.size(); }
RmEffect & at(int idx) { return effects[idx]; }
RmEffect & operator[] (int idx) { return effects[idx]; }
// * debug purpose
void VarDump( bool extendedDump = false );
static QDomElement getDomElement( QDomElement & root, QString tagname, QString name );
};
#endif

View File

@ -0,0 +1,454 @@
#include "UniformVar.h"
#include "RmXmlParser.h"
UniformVar::UniformVar( QString & _name, QString & _typeString, enum UniformType _type )
{
name = _name;
typeString = _typeString;
type = _type;
valid = true;
minSet = false;
maxSet = false;
realminSet = false;
realmaxSet = false;
}
bool UniformVar::getUniformKnownButUnimplementedTag( QDomElement & root, QString tag, QString tagname )
{
if( RmXmlParser::getDomElement(root, tag, tagname ).isNull() == false ) {
representerTagName = tag;
return true;
}
return false;
}
// * ************************** * //
// * 3 Common Methods for * //
// * xml variable value mining * //
// * [boolean][number][texture] * //
// * ************************** * //
bool UniformVar::getUniformBooleanVectorFromTag( QDomElement & root, QString tag, int vecsize, bool * vec, bool * found )
{
QDomElement el = RmXmlParser::getDomElement( root, tag, name );
if( !el.isNull() ) {
if( found ) *found = true;
representerTagName = tag;
return UniformVar::getUniformBooleanVectorFromXmlTag( el, vecsize, vec );
}
if( found ) *found = false;
return false;
}
bool UniformVar::getUniformNumberVectorFromTag( QDomElement & root, QString tag, int vecsize, void * vec, bool intOrFloat, bool * found )
{
QDomElement el = RmXmlParser::getDomElement( root, tag, name );
if( !el.isNull() ) {
if( found ) *found = true;
representerTagName = tag;
return UniformVar::getUniformNumberVectorFromXmlTag( el, vecsize, vec, intOrFloat, this );
}
if( found ) *found = false;
return false;
}
bool UniformVar::getUniformTextureFromTag( QDomElement & root, QString tag, bool * found )
{
QDomElement el = RmXmlParser::getDomElement( root, tag, textureName );
if( !el.isNull() ) {
if( found ) *found = true;
representerTagName = tag;
textureFilename = el.attribute("FILE_NAME");
return true;
}
if( found ) *found = false;
return false;
}
bool UniformVar::getValueFromXmlDocument( QDomElement & root, bool echoNotFound )
{
bool fnd;
switch( type )
{
case BOOL:
{
bool ok = getUniformBooleanVectorFromTag( root, "RmBooleanVariable", 1, &bvalue, &fnd );
if( fnd ) return ok;
break;
}
case INT:
{
bool ok = getUniformNumberVectorFromTag( root, "RmIntegerVariable", 1, &ivalue, &fnd );
if( fnd ) return ok;
break;
}
case FLOAT:
{
bool ok = getUniformNumberVectorFromTag( root, "RmFloatVariable", 1, &fvalue, &fnd );
if( fnd ) return ok;
break;
}
case IVEC2: {
bool ok = getUniformNumberVectorFromTag( root, "RmVectorVariable", 2, ivec2, &fnd );
if( fnd ) return ok; break;
}
case IVEC3: {
bool ok = getUniformNumberVectorFromTag( root, "RmVectorVariable", 3, ivec3, &fnd );
if( fnd ) return ok; break;
}
case IVEC4: {
bool ok = getUniformNumberVectorFromTag( root, "RmVectorVariable", 4, ivec4, &fnd );
if( fnd ) return ok; break;
}
case BVEC2: {
bool ok = getUniformBooleanVectorFromTag( root, "RmVectorVariable", 2, bvec2, &fnd );
if( fnd ) return ok; break;
}
case BVEC3: {
bool ok = getUniformBooleanVectorFromTag( root, "RmVectorVariable", 3, bvec3, &fnd );
if( fnd ) return ok; break;
}
case BVEC4: {
bool ok = getUniformBooleanVectorFromTag( root, "RmVectorVariable", 4, bvec4, &fnd );
if( fnd ) return ok; break;
}
case VEC2: {
bool ok = getUniformNumberVectorFromTag( root, "RmVectorVariable", 2, vec2, &fnd );
if( fnd ) return ok; break;
}
case VEC3: {
bool ok = getUniformNumberVectorFromTag( root, "RmVectorVariable", 3, vec3, &fnd );
if( fnd ) return ok; break;
}
case VEC4: {
// * a vec4 can be RmVectorVariable or RmColorVariable
bool ok = getUniformNumberVectorFromTag( root, "RmVectorVariable", 4, vec4, &fnd );
if( fnd ) return ok;
ok = getUniformNumberVectorFromTag( root, "RmColorVariable", 4, vec4, &fnd );
if( fnd ) return ok;
break;
}
case MAT2:
{
bool ok = getUniformNumberVectorFromTag( root, "RmMatrixVariable", 4, (float*)mat2, &fnd );
if( fnd ) return ok;
break;
}
case MAT3:
{
bool ok = getUniformNumberVectorFromTag( root, "RmMatrixVariable", 8, (float*)mat3, &fnd );
if( fnd ) return ok;
break;
}
case MAT4:
{
bool ok = getUniformNumberVectorFromTag( root, "RmMatrixVariable", 16, (float*)mat4, &fnd );
if( fnd ) return ok;
break;
}
case SAMPLER2D:
{
// * sampler 2d can be Rm2DTextureVariable or not come from a texture file but
// * found in a RmRenderTarget xml tag
bool ok = getUniformTextureFromTag( root, "Rm2DTextureVariable", &fnd );
if( fnd ) return ok;
if( getUniformKnownButUnimplementedTag( root, "RmRenderTarget", textureName ))
return true;
break;
}
case SAMPLER3D:
{
bool ok = getUniformTextureFromTag( root, "Rm3DTextureVariable", &fnd );
if( fnd ) return ok;
break;
}
case SAMPLERCUBE:
{
bool ok = getUniformTextureFromTag( root, "RmCubemapVariable", &fnd );
if( fnd ) return ok;
break;
}
default:
qDebug() << "RmXmlParser for uniform variable" << name << "of type" << UniformVar::getStringFromUniformType(type);
qDebug() << "I don't know how to read my default value.. please implement me !";
return false;
};
// * any variable can be defined as RmDynamicVariable
if( getUniformKnownButUnimplementedTag( root, "RmDynamicVariable", name ))
return true;
if( echoNotFound ) {
qDebug() << "RmXmlParser for uniform variable" << name << "of type" << UniformVar::getStringFromUniformType(type);
qDebug() << "Default value not found";
}
return false;
}
enum UniformVar::UniformType UniformVar::getTypeFromString( QString & type )
{
QString typeList[] = {
"int", "float", "bool",
"vec2", "vec3", "vec4",
"ivec2", "ivec3", "ivec4",
"bvec2", "bvec3", "bvec4",
"mat2", "mat3", "mat4",
"sampler1D", "sampler2D", "sampler3D",
"samplerCube",
"sampler1Dshadow", "sampler2Dshadow"
};
enum UniformType enumList[] = {
INT, FLOAT, BOOL,
VEC2, VEC3, VEC4,
IVEC2, IVEC3, IVEC4,
BVEC2, BVEC3, BVEC4,
MAT2, MAT3, MAT4,
SAMPLER1D, SAMPLER2D, SAMPLER3D,
SAMPLERCUBE,
SAMPLER1DSHADOW, SAMPLER2DSHADOW,
};
for( int i = 0; i < 21; i++ )
if( type == typeList[i] )
return enumList[i];
return OTHER;
}
QString UniformVar::getStringFromUniformType( enum UniformType type )
{
switch(type) {
case INT: return "int";
case FLOAT: return "float";
case BOOL: return "bool";
case VEC2: return "vec2";
case VEC3: return "vec3";
case VEC4: return "vec4";
case IVEC2: return "ivec2";
case IVEC3: return "ivec3";
case IVEC4: return "ivec4";
case BVEC2: return "bvec2";
case BVEC3: return "bvec3";
case BVEC4: return "bvec4";
case MAT2: return "mat2";
case MAT3: return "mat3";
case MAT4: return "mat4";
case SAMPLER1D: return "sampler1d";
case SAMPLER2D: return "sampler2d";
case SAMPLER3D: return "sampler3d";
case SAMPLERCUBE: return "samplercube";
case SAMPLER1DSHADOW: return "sampler1dshadow";
case SAMPLER2DSHADOW: return "sampler2dshadow";
default: return "other";
}
return "I love vim 'q' macroing";
}
void UniformVar::VarDump( int indent, bool extendedVarDump )
{
QString ret = "";
for( int i = 0; i < indent; i++ )
ret += " ";
ret += typeString + QString(" ") + name;
switch( type ) {
case INT:
ret += " = " + QString().setNum(ivalue);
if( minSet || maxSet ) ret += " (";
if( minSet ) ret += "from " + QString().setNum(imin) + " ";
if( maxSet ) ret += "to "+ QString().setNum(imax);
if( minSet || maxSet ) ret += ")";
break;
case FLOAT:
ret += " = " + QString().setNum(fvalue);
if( minSet || maxSet ) ret += " (";
if( minSet ) ret += "from " + QString().setNum(fmin) + " ";
if( maxSet ) ret += "to "+ QString().setNum(fmax);
if( minSet || maxSet ) ret += ")";
break;
case BOOL: ret += bvalue ? " = true" : " = false"; break;
case IVEC2:
ret += " = [ "; for( int i = 0; i < 2; i++ ) ret += QString().setNum( ivec2[i] ) + " "; ret += "]"; break;
case IVEC3:
ret += " = [ "; for( int i = 0; i < 3; i++ ) ret += QString().setNum( ivec3[i] ) + " "; ret += "]"; break;
case IVEC4:
ret += " = [ "; for( int i = 0; i < 4; i++ ) ret += QString().setNum( ivec4[i] ) + " "; ret += "]"; break;
case BVEC2:
ret += " = [ "; for( int i = 0; i < 2; i++ ) ret += bvec2[i] ? "true " : "false "; ret += "]"; break;
case BVEC3:
ret += " = [ "; for( int i = 0; i < 3; i++ ) ret += bvec3[i] ? "true " : "false "; ret += "]"; break;
case BVEC4:
ret += " = [ "; for( int i = 0; i < 4; i++ ) ret += bvec4[i] ? "true " : "false "; ret += "]"; break;
case VEC2:
ret += " = [ "; for( int i = 0; i < 2; i++ ) ret += QString().setNum( vec2[i] ) + " "; ret += "]"; break;
case VEC3:
ret += " = [ "; for( int i = 0; i < 3; i++ ) ret += QString().setNum( vec3[i] ) + " "; ret += "]"; break;
case VEC4:
ret += " = [ "; for( int i = 0; i < 4; i++ ) ret += QString().setNum( vec3[i] ) + " "; ret += "]"; break;
case MAT2:
case MAT3:
case MAT4:
ret += " [matrix]";
if( extendedVarDump ) {
int n = type == MAT2 ? 2 : (type == MAT3 ? 3 : 4);
float * mat = type == MAT2 ? (float*)mat2 : (type == MAT3 ? (float*)mat3 : (float*)mat4);
ret += "\n";
for( int i = 0; i < n; i++ ) {
for( int k = 0; k < indent+2; k++ )
ret += " ";
ret += "[ ";
for( int j = 0; j < n; j++ ) ret += QString().setNum( mat[i*n+j] ) + " ";
ret += "]";
if( i+1 < n ) ret += "\n";
}
}
break;
case SAMPLER1DSHADOW:
case SAMPLER2DSHADOW:
case SAMPLERCUBE:
case SAMPLER1D:
case SAMPLER2D:
case SAMPLER3D:
{
if( textureFilename.isEmpty() )
ret += " = no filename, textureName = " + textureName;
else
ret += " = " + textureFilename;
if( representerTagName == "RmRenderTarget" )
ret += " [RmRenderTarget]";
if( extendedVarDump ) {
if( textureGLStates.size() == 0 )
ret += " [with no openGL states]";
else
{
ret += "\n";
for( int i = 0; i < textureGLStates.size(); i++ ) {
for( int j = 0; j < indent+2; j++ )
ret += " ";
ret += "\"" + textureGLStates[i].getName() + "\" (" + QString().setNum(textureGLStates[i].state).toLatin1().data() + ") => " + QString().setNum(textureGLStates[i].getValue());
if( i+1 < textureGLStates.size() ) ret += "\n";
}
}
} else
ret += " [openGL states: " + QString().setNum(textureGLStates.size()) + "]";
break;
}
default:
ret += " [implement me]";
}
qDebug() << ret.toLatin1().data();
}
bool UniformVar::getUniformNumberVectorFromXmlTag( QDomElement & el, int values, void * narr, bool intOrFloat, UniformVar * ptr )
{
int * iarr = (int*)narr;
float * farr = (float*)narr;
bool ok1=true,ok2=true;
for( int i = 0; i < values; i++ )
{
QString attrname = "VALUE";
if( values > 1 )
attrname += "_" + QString().setNum(i);
QString attrvalue = el.attribute(attrname);
if( intOrFloat ) {
int val = attrvalue.toInt(&ok1);
if( ok1 ) {
iarr[i] = val;
ptr -> testRealMin(val);
ptr -> testRealMax(val);
}
} else {
float val = attrvalue.toFloat(&ok1);
if( ok1 ) {
farr[i] = val;
ptr -> testRealMin(val);
ptr -> testRealMax(val);
}
}
if( !ok1 ) {
qDebug() << "RmXmlParser: error while reading default value for " << (intOrFloat ? "int" : "float" )<< " vector["<<values<<"]" << el.attribute("NAME") << ":" << attrname << "=>" << attrvalue;
return false;
}
}
if( !el.attribute( "MIN" ).isEmpty() ) {
if( intOrFloat ) {
int min = el.attribute("MIN").toInt(&ok1);
if( ok1 ) ptr -> setMin(min);
} else {
float min = el.attribute("MIN").toFloat(&ok1);
if( ok1 ) ptr -> setMin(min);
}
}
if( !el.attribute( "MAX" ).isEmpty() ) {
if( intOrFloat ) {
int max = el.attribute("MAX").toInt(&ok2);
if( ok2 ) ptr -> setMax(max);
} else {
float max = el.attribute("MAX").toFloat(&ok2);
if( ok2 ) ptr -> setMax(max);
}
}
if( !ok1 || !ok2 ) {
qDebug() << "RmXmlParser: error while reading default value for float vector["<<values<<"]" << el.attribute("NAME");
qDebug() << "Min_ok("<<ok1<<") Max_ok("<<ok2<<")";
}
return true;
}
bool UniformVar::getUniformBooleanVectorFromXmlTag( QDomElement & el, int values, bool * barr )
{
for( int i = 0; i < values; i++ )
{
QString attrname = "VALUE";
if( values > 1 )
attrname += "_" + QString().setNum(i);
QString attrvalue = el.attribute(attrname);
if( attrvalue != "TRUE" && attrvalue != "FALSE ") {
qDebug() << "RmXmlParser: error while reading default value for boolean vector["<<values<<"]" << el.attribute("NAME");
qDebug() << attrvalue << "is not TRUE neither FALSE";
return false;
}
barr[i] = attrvalue == "TRUE";
}
return true;
}

View File

@ -0,0 +1,114 @@
#ifndef __UNIFORMVAR_H__
#define __UNIFORMVAR_H__
#include <QList>
#include <QString>
#include <QStringList>
#include <QDomElement>
#include <qDebug>
#include "GlState.h"
class UniformVar
{
public:
enum UniformType {
INT, // * type integer
FLOAT, // * type float
BOOL, // * type bool
VEC2, VEC3, VEC4, // * vector of float
IVEC2, IVEC3, IVEC4, // * vector of int
BVEC2, BVEC3, BVEC4, // * vector of bool
MAT2, MAT3, MAT4, // * 2x2 3x3 4x4 float
SAMPLER1D, SAMPLER2D, SAMPLER3D, // * 1D, 2D and 3D texture
SAMPLERCUBE, // * Cube Map texture
SAMPLER1DSHADOW, SAMPLER2DSHADOW, // * 1D and 2D depth-component texture
OTHER
};
enum UniformType type;
QString name;
QString typeString;
union {
int ivalue;
float fvalue;
bool bvalue;
float vec2[2], vec3[3], vec4[4];
int ivec2[2], ivec3[3], ivec4[4];
bool bvec2[2], bvec3[3], bvec4[4];
float mat2[2][2], mat3[3][3], mat4[4][4];
};
QString representerTagName;
QString textureName;
QString textureFilename;
QList<GlState> textureGLStates;
union { int imin; float fmin; };
union { int imax; float fmax; };
union { int irealmin; float frealmin; };
union { int irealmax; float frealmax; };
bool minSet;
bool maxSet;
bool realminSet;
bool realmaxSet;
void setMin( int min ) { if( (realminSet && min <= irealmin) || !realminSet) { imin = min; minSet = true; } }
void setMin( float min ) { if( (realminSet && min <= frealmin) || !realminSet) { fmin = min; minSet = true;} }
void setMax( int max ) { if( (realmaxSet && max >= irealmax) || !realmaxSet ) { imax = max; maxSet = true; } }
void setMax( float max ) { if( (realmaxSet && max >= frealmax) || !realmaxSet ) { fmax = max; maxSet = true; } }
void testRealMin( int min ) { if( !realminSet || min < irealmin ) { realminSet = true; irealmin = min; if( minSet && imin > irealmin ) minSet = false; } }
void testRealMin( float min ) { if( !realminSet || min < frealmin ) { realminSet = true; frealmin = min; if( minSet && fmin > frealmin ) minSet = false; } }
void testRealMax( int max ) { if( !realmaxSet || max > irealmax ) { realmaxSet = true; irealmax = max; if( maxSet && imax < irealmax ) maxSet = false; } }
void testRealMax( float max ) { if( !realmaxSet || max > irealmax ) { realmaxSet = true; frealmax = max; if( maxSet && fmax < frealmax ) maxSet = false; } }
bool valid;
UniformVar() { valid = false; }
UniformVar( QString & _name, QString & _typeString, enum UniformType _type );
virtual ~UniformVar(){}
bool isNull() { return !valid; }
// * we search the xml tag element that has the default value of a uniform
// * variable. It can happend a multiple declaration, so first we search
// * in the same RmOpenGLEffect (effectElement), and then in the global document root
bool getValueFromXmlDocument( QDomElement & root, bool echoNotFound = true );
bool getValueFromXmlDocument( QDomElement & root, QDomElement & effectElement ) {
if( getValueFromXmlDocument( effectElement, false ) ) return true;
return getValueFromXmlDocument( root );
}
bool getUniformKnownButUnimplementedTag( QDomElement & root, QString tag, QString tagname);
bool getUniformBooleanVectorFromTag( QDomElement & root, QString tag, int vecsize, bool * vec, bool * found = NULL);
bool getUniformNumberVectorFromTag( QDomElement & root, QString tag, int vecsize, void * vec, bool intOrFloat, bool * found = NULL );
bool getUniformNumberVectorFromTag( QDomElement & root, QString tag, int vecsize, int * vec, bool * found = NULL ) {
return getUniformNumberVectorFromTag( root, tag, vecsize, (void*)vec, true, found );
}
bool getUniformNumberVectorFromTag( QDomElement & root, QString tag, int vecsize, float * vec, bool * found = NULL ) {
return getUniformNumberVectorFromTag( root, tag, vecsize, (void*)vec, false, found );
}
bool getUniformTextureFromTag( QDomElement & root, QString tag, bool * found = NULL );
static enum UniformType getTypeFromString( QString & type );
static QString getXmlTagRomUniformType( enum UniformType type );
static QString getStringFromUniformType( enum UniformType type );
static bool getUniformNumberVectorFromXmlTag( QDomElement & el, int values, void * farr, bool intOrFloat, UniformVar * ptr );
static bool getUniformBooleanVectorFromXmlTag( QDomElement & el, int values, bool * barr);
void VarDump(int indent = 0, bool extendedVarDump = false);
};
#endif

View File

@ -0,0 +1,53 @@
#include "RmXmlParser.h"
#include <QString>
#include <QDir>
#include <QFileInfoList>
#include <QCoreApplication>
#define DIRECTORY_ESEMPI "C:/Program Files/ATI Research Inc/RenderMonkey 1.62/Examples/GL2/"
int main(int argc, char ** argv )
{
QCoreApplication qapp( argc, argv );
RmXmlParser par;
QDir dir( DIRECTORY_ESEMPI );
if( dir.exists() == false ) {
qDebug() << "Ciao.. edita main.cpp e mettici la directory dove hai gli esempi e ricompila";
qDebug() << "Mica ti aspettavi che scrivessi un parser di argomenti passati da linea di comando.. vero ?";
return 1;
}
if( argc == 1 ){
QFileInfoList filelist = dir.entryInfoList();
for( int i = 0; i < filelist.size(); i++ )
if( filelist[i].fileName().endsWith( ".rfx" )) {
qDebug() << "Reading" << filelist[i].fileName();
if( !par.parse( filelist[i].filePath() ) ) {
qDebug() << par.getError();
return 1;
}
par.VarDump( true );
}
} else {
QString filename = QString(DIRECTORY_ESEMPI) + "/" + argv[1];
if( !par.parse( filename ) ) {
qDebug() << par.getError();
return 1;
}
par.VarDump();
}
return 0;
}

View File

@ -0,0 +1,20 @@
TEMPLATE = app
CONFIG += QT
QT += xml
win32 {
CONFIG += console
}
SOURCES += main.cpp \
RmXmlParser.cpp \
RmPass.cpp \
UniformVar.cpp
HEADERS += RmXmlParser.h \
RmEffect.h \
RmPass.h \
UniformVar.h \
GlState.h

View File

@ -0,0 +1,42 @@
TEMPLATE = lib
CONFIG += plugin
INCLUDEPATH += ../.. ../../../../sf ../../../../code/lib/glew/include
#LIBPATH += ../../../../code/lib/glew/lib/
HEADERS += rmmeshrender.h \
rmshaderdialog.h \
glstateholder.h \
parser/GlState.h \
parser/RmEffect.h \
parser/RmPass.h \
parser/RmXmlParser.h \
parser/UniformVar.h
SOURCES += rmmeshrender.cpp \
rmshaderdialog.cpp \
glstateholder.cpp \
parser/RmPass.cpp \
parser/RmXmlParser.cpp \
parser/UniformVar.cpp \
../../../../code/lib/glew/src/glew.c
TARGET = render_rm
DESTDIR = ../../meshlab/plugins
# the following line is needed to avoid mismatch between
# the awful min/max macros of windows and the limits max
win32:DEFINES += NOMINMAX
//win32:LIBS += QtXml4.lib
FORMS = rmShadowDialog.ui
DEFINES += GLEW_STATIC
CONFIG += debug_and_release
mac:CONFIG += x86 ppc
contains(TEMPLATE,lib) {
CONFIG(debug, debug|release) {
unix:TARGET = $$member(TARGET, 0)_debug
else:TARGET = $$member(TARGET, 0)d
}
}
QT += opengl xml moc

View File

@ -0,0 +1,249 @@
<ui version="4.0" >
<class>RmShaderDialogClass</class>
<widget class="QDialog" name="RmShaderDialogClass" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>499</width>
<height>381</height>
</rect>
</property>
<property name="focusPolicy" >
<enum>Qt::StrongFocus</enum>
</property>
<property name="windowTitle" >
<string>RmShaderDialog</string>
</property>
<property name="windowIcon" >
<iconset>../../../../../meshlab/src/meshlab/images/eye16.png</iconset>
</property>
<property name="sizeGripEnabled" >
<bool>true</bool>
</property>
<widget class="QGroupBox" name="groupBox" >
<property name="geometry" >
<rect>
<x>10</x>
<y>40</y>
<width>481</width>
<height>331</height>
</rect>
</property>
<property name="title" >
<string>Passes</string>
</property>
<widget class="QComboBox" name="cmbPassSelection" >
<property name="geometry" >
<rect>
<x>10</x>
<y>20</y>
<width>461</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QTabWidget" name="tabWidget" >
<property name="geometry" >
<rect>
<x>10</x>
<y>50</y>
<width>461</width>
<height>271</height>
</rect>
</property>
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="tab1_Uniform" >
<attribute name="title" >
<string>Uniform</string>
</attribute>
<widget class="QFrame" name="frame1" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>441</width>
<height>231</height>
</rect>
</property>
<property name="frameShape" >
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth" >
<number>1</number>
</property>
<property name="midLineWidth" >
<number>0</number>
</property>
<widget class="QWidget" name="gridLayout" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>421</width>
<height>211</height>
</rect>
</property>
<layout class="QGridLayout" />
</widget>
</widget>
</widget>
<widget class="QWidget" name="tab2_Texture" >
<attribute name="title" >
<string>Textures</string>
</attribute>
<widget class="QFrame" name="frame" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>441</width>
<height>231</height>
</rect>
</property>
<property name="frameShape" >
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<widget class="QWidget" name="gridLayout_2" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>421</width>
<height>211</height>
</rect>
</property>
<layout class="QGridLayout" />
</widget>
</widget>
</widget>
<widget class="QWidget" name="tab3_OpenGl" >
<attribute name="title" >
<string>OpenGL</string>
</attribute>
<widget class="QFrame" name="frame_2" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>441</width>
<height>231</height>
</rect>
</property>
<property name="frameShape" >
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<widget class="QWidget" name="gridLayout_3" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>421</width>
<height>211</height>
</rect>
</property>
<layout class="QGridLayout" />
</widget>
</widget>
</widget>
<widget class="QWidget" name="tab4_Vertex" >
<attribute name="title" >
<string>Vertex</string>
</attribute>
<widget class="QTextEdit" name="textVertex" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>451</width>
<height>241</height>
</rect>
</property>
<property name="lineWrapMode" >
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="readOnly" >
<bool>true</bool>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab5_Fragment" >
<attribute name="title" >
<string>Fragment</string>
</attribute>
<widget class="QTextEdit" name="textFragment" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>451</width>
<height>241</height>
</rect>
</property>
<property name="lineWrapMode" >
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="readOnly" >
<bool>true</bool>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</widget>
</widget>
</widget>
<widget class="QLabel" name="lblEffectSelection" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>81</width>
<height>21</height>
</rect>
</property>
<property name="text" >
<string>Effect Selection</string>
</property>
</widget>
<widget class="QComboBox" name="cmbEffectSelection" >
<property name="geometry" >
<rect>
<x>90</x>
<y>10</y>
<width>181</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="btnOk" >
<property name="geometry" >
<rect>
<x>280</x>
<y>10</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text" >
<string>Ok</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,103 @@
#include "rmmeshrender.h"
const PluginInfo& RmMeshShaderRenderPlugin::Info() {
static PluginInfo ai;
ai.Date=tr("September 2007");
ai.Version = "1.0";
ai.Author = "Giacomo Galilei";
return ai;
}
void RmMeshShaderRenderPlugin::initActionList() {
QDir shadersDir = QDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
if (shadersDir.dirName() == "debug" || shadersDir.dirName() == "release" || shadersDir.dirName() == "plugins" )
shadersDir.cdUp();
#elif defined(Q_OS_MAC)
if (shadersDir.dirName() == "MacOS") {
for(int i=0;i<4;++i){
shadersDir.cdUp();
if(shadersDir.exists("shadersrm")) break;
}
}
#endif
if(!shadersDir.cd("shadersrm")) {
QMessageBox::information(0, "MeshLAb", "Unable to find the render monkey shaders directory.\n" "No shaders will be loaded.");
return;
}
int errors = 0;
int successes = 0;
foreach (QString fileName, shadersDir.entryList(QDir::Files)) {
if (fileName.endsWith(".rfx")) {
RmXmlParser * parser = new RmXmlParser( shadersDir.absoluteFilePath(fileName) );
if( parser -> parse() == false ) {
qDebug() << "Unable to load RmShader from" << shadersDir.absoluteFilePath(fileName) << ": " << parser -> errorString();
delete parser;
errors += 1;
continue;
}
rmsources.insert(fileName, parser);
successes += 1;
QAction * qa = new QAction(fileName, this);
qa->setCheckable(false);
actionList << qa;
}
}
//qDebug() << (successes+errors) << "RmShaders parsed. Opened correctly" << successes << "rmshaders, and get" << errors <<"errors";
}
void RmMeshShaderRenderPlugin::Init(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla)
{
if( dialog ) {
dialog->close();
delete dialog;
}
RmXmlParser * parser = rmsources.value(a->text());
assert(parser);
gla->makeCurrent();
GLenum err = glewInit();
if (GLEW_OK == err) {
if (GLEW_ARB_vertex_program && GLEW_ARB_fragment_program) {
dialog = new RmShaderDialog(&holder, parser, gla, rm);
dialog->move(10,100);
dialog->show();
}
}
// * clear errors, if any
glGetError();
}
void RmMeshShaderRenderPlugin::Render(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla)
{
if( holder.needUpdateInGLMemory )
holder.updateUniformVariableValuesInGLMemory();
if( holder.isSupported() ) {
qDebug() << "Render: " << a;
//holder.usePassProgram(0);
}
// * clear errors, if any
glGetError();
}
Q_EXPORT_PLUGIN(RmMeshShaderRenderPlugin)

View File

@ -0,0 +1,53 @@
#ifndef RMSHADERRENDERPLUGIN_H
#define RMSHADERRENDERPLUGIN_H
#include <QDir>
#include <QObject>
#include <QAction>
#include <QList>
#include <QFile>
#include <QString>
#include <QApplication>
#include <QMap>
#include <QMessageBox>
#include <GL/glew.h>
#include <meshlab/meshmodel.h>
#include <meshlab/interfaces.h>
#include "parser/RmXmlParser.h"
#include "rmshaderdialog.h"
#include "glstateholder.h"
class RmMeshShaderRenderPlugin : public QObject, public MeshRenderInterface
{
Q_OBJECT
Q_INTERFACES(MeshRenderInterface)
// * map between the filename and its parser
QMap<QString, RmXmlParser*> rmsources;
QList <QAction *> actionList;
RmShaderDialog * dialog;
GLStateHolder holder;
private:
void initActionList();
public:
RmMeshShaderRenderPlugin() { dialog = NULL; }
~RmMeshShaderRenderPlugin() { QMapIterator<QString, RmXmlParser*> i(rmsources); while( i.hasNext() ) { i.next(); delete i.value();} }
QList<QAction *> actions () { if(actionList.isEmpty()) initActionList(); return actionList; }
virtual const PluginInfo &Info();
virtual bool isSupported() {return holder.isSupported();}
virtual void Init(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla);
virtual void Render(QAction *a, MeshModel &m, RenderMode &rm, QGLWidget *gla);
};
#endif

View File

@ -0,0 +1,384 @@
#include "rmshaderdialog.h"
// * we create the dialog with all the proper contents
RmShaderDialog::RmShaderDialog(GLStateHolder * _holder, RmXmlParser * _parser, QGLWidget* gla, RenderMode &rm, QWidget *parent) : QDialog(parent)
{
ui.setupUi(this);
parser = _parser;
holder = _holder;
glarea = gla;
rendMode = &rm;
eff_selected = NULL;
pass_selected = NULL;
if( parser -> size() == 0 ) {
QMessageBox::critical(0, "Meshlab", QString("This RmShader seems to have no suitable effects"));
return;
}
// * fill the effect combo
for( int i = 0; i < parser -> size(); i++ )
ui.cmbEffectSelection -> addItem( parser -> at(i).getName() );
connect( ui.cmbEffectSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(fillDialogWithEffect(int)));
connect( ui.cmbPassSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(fillTabsWithPass(int)));
this->setWindowFlags(Qt::WindowStaysOnTopHint);
connect(ui.btnOk, SIGNAL(clicked()), this, SLOT(accept()));
signaler = NULL;
fillDialogWithEffect(0);
}
RmShaderDialog::~RmShaderDialog()
{
for( int i = 0; i < shown.size(); i++ )
delete shown[i];
delete signaler;
}
void RmShaderDialog::fillDialogWithEffect( int index ) {
if( index < 0 || index >= parser -> size() ) return;
eff_selected = &(parser -> at( index ));
ui.cmbPassSelection -> clear();
for( int i = 0; i < eff_selected -> size(); i++ )
ui.cmbPassSelection -> addItem( eff_selected -> at(i).getName() );
holder -> setPasses(eff_selected -> getPassList());
fillTabsWithPass(0);
if(!holder->compile()) {
QMessageBox::critical(0, "Meshlab", "An error occurred during shader compiling.\n" + holder->getLastError() );
} else
if(!holder->link()) {
QMessageBox::critical(0, "Meshlab", "An error occurred during shader linking.\n" + holder->getLastError() );
}
}
void RmShaderDialog::fillTabsWithPass( int index ) {
clearTabs();
if( index < 0 || eff_selected == NULL || index >= eff_selected -> size() ) return;
pass_selected = &(eff_selected -> at( index ));
ui.textVertex -> setText( pass_selected -> getVertex() );
ui.textFragment -> setText( pass_selected -> getFragment() );
// * General Info in the first tab
QString info = "Model reference: " + pass_selected -> getModelReference() + "\n";
if( pass_selected -> hasRenderTarget() )
info += "Render Target: " + pass_selected -> getRenderTarget().name + "\n";
for( int i = 0; i < 2; i++ )
for( int j = 0; j < ( i == 0 ? pass_selected -> vertexUniformVariableSize() : pass_selected -> fragmentUniformVariableSize()); j++ ) {
UniformVar v = pass_selected -> getUniformVariable( j, i == 0 ? RmPass::VERTEX : RmPass::FRAGMENT );
if( v.representerTagName == "RmRenderTarget" ) {
if( i == 0 ) info += "Vertex"; else info += "Fragment";
info += " render Input: " + v.name;
for( int k = 0; k < eff_selected -> size(); k++ )
if( eff_selected -> at(k).getRenderTarget().name == v.textureName ) {
info += " (from pass: " + eff_selected -> at(k).getName() + ")";
break;
}
info += "\n";
}
}
QLabel * lblinfo = new QLabel( info );
ui.gridLayout1 -> addWidget(lblinfo, 0, 0, 1, 5 );
shown.append(lblinfo);
// * any value change is sent to the state holder with this mapper
// * Signal are send from signaler in the form "varnameNM" where
// * NM is the index of row and column in case of matrix. (00 if
// * it is a simple variable).
delete signaler;
signaler = new QSignalMapper();
connect(signaler, SIGNAL(mapped(const QString &)), this, SLOT(valuesChanged(const QString &)));
// * Uniform Variables in the first Tab
QList<QString> usedVarables; // * parser can give same variable twice in the vertex and fragment
int row = 1;
for( int ii = 0; ii < 2; ii++ )
for( int jj = 0; jj < ( ii == 0 ? pass_selected -> vertexUniformVariableSize() : pass_selected -> fragmentUniformVariableSize()); jj++ ) {
UniformVar v = pass_selected -> getUniformVariable( jj, ii == 0 ? RmPass::VERTEX : RmPass::FRAGMENT );
if( v.representerTagName == "RmRenderTarget" || usedVarables.contains(v.name))
continue;
usedVarables.append(v.name);
QString varname = ( ii == 0 ? "Vertex: " : "Fragment: ");
varname += UniformVar::getStringFromUniformType(v.type) + " " + v.name + ( v.minSet || v.maxSet ? "\n" : "" );
switch( v.type ) {
case UniformVar::INT:
case UniformVar::IVEC2:
case UniformVar::IVEC3:
case UniformVar::IVEC4:
{
int n = v.type == UniformVar::INT ? 1 : (v.type == UniformVar::IVEC2 ? 2 : (v.type == UniformVar::IVEC3 ? 3 : 4 ));
for( int i = 0; i < n; i++ ) {
QSpinBox * input = new QSpinBox();
input -> setObjectName( v.name + "0" + QString().setNum(i) );
if( v.minSet ) input -> setMinimum( v.fmin ); else input -> setMinimum( -1000 );
if( v.maxSet ) input -> setMaximum( v.fmax ); else input -> setMaximum( 1000 );
input -> setSingleStep( (v.minSet && v.maxSet ) ? max(( v.imax - v.imin )/10, 1) : 1 );
input -> setValue( v.ivec4[i] );
ui.gridLayout1 -> addWidget( input, row, 1+i, 1, ((i+1)==n ? 5-n : 1) );
shown.append(input);
connect(input, SIGNAL(valueChanged(int)), signaler, SLOT(map()));
signaler->setMapping(input, v.name + "0" + QString().setNum(i) );
}
if( v.minSet ) { varname += "min: " + QString().setNum(v.imin) + " "; }
if( v.maxSet ) { varname += " max: " + QString().setNum(v.imax); }
break;
}
case UniformVar::BOOL:
case UniformVar::BVEC2:
case UniformVar::BVEC3:
case UniformVar::BVEC4:
{
int n = v.type == UniformVar::BOOL ? 1 : (v.type == UniformVar::BVEC2 ? 2 : (v.type == UniformVar::BVEC3 ? 3 : 4 ));
for( int i = 0; i < n; i++ ) {
QCheckBox * input = new QCheckBox();
input -> setObjectName( v.name + "0" + QString().setNum(i) );
input -> setCheckState( v.bvec4[i] ? Qt::Checked : Qt::Unchecked );
ui.gridLayout1 -> addWidget( input, row, 1+i, 1, ((i+1)==n ? 5-n : 1) );
shown.append(input);
connect(input, SIGNAL(stateChanged(int)), signaler, SLOT(map()));
signaler->setMapping(input, v.name + "0" + QString().setNum(i) );
}
break;
}
case UniformVar::FLOAT:
case UniformVar::VEC2:
case UniformVar::VEC3:
case UniformVar::VEC4:
{
int n = v.type == UniformVar::FLOAT ? 1 : (v.type == UniformVar::VEC2 ? 2 : (v.type == UniformVar::VEC3 ? 3 : 4 ));
for( int i = 0; i < n; i++ ) {
QDoubleSpinBox * input = new QDoubleSpinBox();
input -> setObjectName( v.name + "0" + QString().setNum(i) );
input -> setDecimals(4);
if( v.minSet ) input -> setMinimum( v.fmin ); else input -> setMinimum( -1000 );
if( v.maxSet ) input -> setMaximum( v.fmax ); else input -> setMaximum( 1000 );
input -> setSingleStep( (v.minSet && v.maxSet ) ? fmax(( v.fmax - v.fmin )/10., 0.0001) : 0.0001 );
input -> setValue( v.vec4[i] );
ui.gridLayout1 -> addWidget( input, row, 1+i, 1, ((i+1)==n ? 5-n : 1) );
shown.append(input);
connect(input, SIGNAL(valueChanged(double)), signaler, SLOT(map()));
signaler->setMapping(input, v.name + "0" + QString().setNum(i) );
}
if( v.minSet ) { varname += "min: " + QString().setNum(v.fmin) + " "; }
if( v.maxSet ) { varname += " max: " + QString().setNum(v.fmax); }
break;
}
case UniformVar::MAT2:
case UniformVar::MAT3:
case UniformVar::MAT4:
{
int n = v.type == UniformVar::MAT2 ? 2 : (v.type == UniformVar::MAT3 ? 3 : 4 );
for( int i = 0; i < n; i++ ) {
for( int j = 0; j < n; j++ ) {
QDoubleSpinBox * input = new QDoubleSpinBox();
input -> setObjectName( v.name + QString().setNum(i) + QString().setNum(j));
input -> setDecimals(4);
if( v.minSet ) input -> setMinimum( v.fmin ); else input -> setMinimum( -1000 );
if( v.maxSet ) input -> setMaximum( v.fmax ); else input -> setMaximum( 1000 );
input -> setSingleStep( (v.minSet && v.maxSet ) ? fmax(( v.fmax - v.fmin )/10., 0.0001) : 0.0001 );
input -> setValue( v.vec4[(i*n)+j] );
ui.gridLayout1 -> addWidget( input, row, 1+j, 1, ((j+1)==n ? 5-n : 1) );
shown.append(input);
connect(input, SIGNAL(valueChanged(double)), signaler, SLOT(map()));
signaler->setMapping(input, v.name + QString().setNum(i) + QString().setNum(j));
}
if( (i+1) < n ) row += 1;
}
if( v.minSet ) { varname += "min: " + QString().setNum(v.fmin) + " "; }
if( v.maxSet ) { varname += " max: " + QString().setNum(v.fmax); }
break;
}
case UniformVar::SAMPLER1D: case UniformVar::SAMPLER2D: case UniformVar::SAMPLER3D: case UniformVar::SAMPLERCUBE: case UniformVar::SAMPLER1DSHADOW: case UniformVar::SAMPLER2DSHADOW:
{
QLabel * link = new QLabel( "<font color=\"blue\">See texture tab</font>" );
ui.gridLayout1 -> addWidget( link, row, 1, 1, 4 );
shown.append(link);
break;
}
case UniformVar::OTHER:
{
QLabel * unimpl = new QLabel( "[Unimplemented mask]" );
ui.gridLayout1 -> addWidget( unimpl, row, 1, 1, 4);
shown.append(unimpl);
}
}
QLabel * lblvar = new QLabel(varname);
ui.gridLayout1 -> addWidget( lblvar, row, 0 );
shown.append(lblvar);
row += 1;
}
// * Texture in the second tab
for( int ii = 0, row = 0; ii < 2; ii++ )
for( int jj = 0; jj < ( ii == 0 ? pass_selected -> vertexUniformVariableSize() : pass_selected -> fragmentUniformVariableSize()); jj++ ) {
UniformVar v = pass_selected -> getUniformVariable( jj, ii == 0 ? RmPass::VERTEX : RmPass::FRAGMENT );
if( v.textureFilename.isNull() ) continue;
QFileInfo finfo(v.textureFilename);
QDir textureDir = QDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
if (textureDir.dirName() == "debug" || textureDir.dirName() == "release" || textureDir.dirName() == "plugins" ) textureDir.cdUp();
#elif defined(Q_OS_MAC)
if (textureDir.dirName() == "MacOS") { for(int i=0;i<4;++i){ textureDir.cdUp(); if(textureDir.exists("textures")) break; } }
#endif
textureDir.cd("textures");
QFile f( textureDir.absoluteFilePath(finfo.fileName()));
QString varname = ( ii == 0 ? "Vertex texture: " : "Fragment texture: ");
varname += UniformVar::getStringFromUniformType(v.type) + " " + v.name + "<br>";
varname += "Filename: " + finfo.fileName() + (f.exists() ? "" : " [<font color=\"red\">not found</font>]");
for( int k = 0; k < v.textureGLStates.size(); k++ )
varname += "<br>OpenGL state: " + v.textureGLStates[k].name + " (" + QString().setNum(v.textureGLStates[k].state) + "): " + QString().setNum(v.textureGLStates[k].value);
QLabel * lblvar = new QLabel(varname);
lblvar -> setTextFormat( Qt::RichText );
lblvar -> setObjectName( v.name + "00" );
ui.gridLayout2 -> addWidget( lblvar, row++, 0, 1, 2 );
shown.append(lblvar);
QLineEdit * txtChoose = new QLineEdit( textureDir.absoluteFilePath(finfo.fileName()) );
txtChoose -> setObjectName( v.name + "11" );
ui.gridLayout2 -> addWidget( txtChoose, row, 0 );
shown.append(txtChoose);
connect(txtChoose, SIGNAL(editingFinished()), signaler, SLOT(map()));
signaler->setMapping(txtChoose, v.name + "11");
QPushButton * btnChoose = new QPushButton( "Browse" );
btnChoose -> setObjectName( v.name + "22" );
ui.gridLayout2 -> addWidget( btnChoose, row, 1 );
shown.append(btnChoose);
connect(btnChoose, SIGNAL(clicked()), signaler, SLOT(map()));
signaler->setMapping(btnChoose, v.name + "22");
row++;
}
// * Open Gl Status in the third tab
if( pass_selected -> openGLStatesSize() == 0 ) {
QLabel * lblgl = new QLabel( "No openGL states set" );
ui.gridLayout3 -> addWidget( lblgl, row, 0 );
shown.append(lblgl);
} else
for( int i = 0, row = 0; i < pass_selected -> openGLStatesSize(); i++ ) {
QString str = "OpenGL state: " + pass_selected -> getOpenGLState(i).name;
str += " (" + QString().setNum(pass_selected -> getOpenGLState(i).state) + "): " + QString().setNum(pass_selected -> getOpenGLState(i).value);
QLabel * lblgl = new QLabel(str);
ui.gridLayout3 -> addWidget( lblgl, row++, 0 );
shown.append(lblgl);
}
}
void RmShaderDialog::clearTabs() {
for( int i = 0; i < shown.size(); i++ ) {
shown[i] -> hide();
shown[i] -> close();
delete shown[i];
}
shown.clear();
ui.textVertex -> clear();
ui.textFragment -> clear();
}
void RmShaderDialog::valuesChanged(const QString & varNameAndIndex )
{
int len = varNameAndIndex.length();
int colIdx = QString(varNameAndIndex[ len - 1 ]).toInt();
int rowIdx = QString(varNameAndIndex[ len - 2 ]).toInt();
QString varname = varNameAndIndex.left(len-2);
QLabel * lbl = NULL;
QLineEdit * txt = NULL;
bool isTextureFileEdit = false;
QVariant val;
for( int i = 0; val.isNull() && !isTextureFileEdit && i < shown.size(); i++ ) {
if( shown[i] -> objectName() == varNameAndIndex ) {
QDoubleSpinBox * dinp = dynamic_cast<QDoubleSpinBox*>(shown[i]);
if( dinp ) { val = QVariant(dinp -> value()); }
QSpinBox * sinp = dynamic_cast<QSpinBox*>(shown[i]);
if( sinp ) { val = QVariant(sinp -> value()); }
QCheckBox * cinp = dynamic_cast<QCheckBox*>(shown[i]);
if( cinp ) { val = QVariant(cinp -> checkState() == Qt::Checked); }
QLineEdit * linp = dynamic_cast<QLineEdit*>(shown[i]);
if( linp ) { val = QVariant(linp -> text()); isTextureFileEdit = true; }
QPushButton * binp = dynamic_cast<QPushButton*>(shown[i]);
if( binp ) {
isTextureFileEdit = true;
// * choose the filename with a dialog
QFileDialog fd(0,"Choose new texture");
QDir texturesDir = QDir(qApp->applicationDirPath());
#if defined(Q_OS_WIN)
if (texturesDir.dirName() == "debug" || texturesDir.dirName() == "release") texturesDir.cdUp();
#elif defined(Q_OS_MAC)
if (texturesDir.dirName() == "MacOS") { for(int i=0;i<4;++i){ texturesDir.cdUp(); if(texturesDir.exists("textures")) break; } }
#endif
texturesDir.cd("textures");
fd.setDirectory(texturesDir);
fd.move(500, 100);
if (fd.exec())
val = fd.selectedFiles().at(0);
else
return;
}
}
if( !lbl && (lbl = dynamic_cast<QLabel*>(shown[i])) && lbl -> objectName().left(len-2) != varname ) lbl = NULL;
if( !txt && (txt = dynamic_cast<QLineEdit*>(shown[i])) && txt -> objectName().left(len-2) != varname ) txt = NULL;
}
if( val.isNull() ) {
qWarning( "Uniform Variable changed in the dialog, but no valid input found.. fix me! (no change done)");
return;
}
// * if it's a texture file update the info shown in the dialog
if( isTextureFileEdit ) {
txt -> setText( val.toString() );
QString label = lbl -> text();
int statusStart = label.indexOf("Filename: ");
int statusEnd = label.indexOf(']');
QFileInfo finfo(val.toString());
if( finfo.exists() ) lbl -> setText( label.mid(0,statusStart) + "Filename: " + finfo.fileName() + " [<font color=\"blue\">ok</font>" + label.mid(statusEnd) );
else lbl -> setText( label.mid(0,statusStart) + "Filename: " + finfo.fileName() + " [<font color=\"red\">not found</font>" + label.mid(statusEnd) );
}
holder -> updateUniformVariableValuesFromDialog( pass_selected -> getName(), varname, rowIdx, colIdx, val );
glarea -> updateGL();
}

View File

@ -0,0 +1,63 @@
#ifndef RMSHADERDIALOG_H
#define RMSHADERDIALOG_H
#include <QDialog>
#include <QVBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <QList>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QSignalMapper>
#include <QCheckBox>
#include <QPushButton>
#include <QLineEdit>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <GL/glew.h>
#include <QGLWidget>
#include <meshlab/meshmodel.h>
#include "parser/RmXmlParser.h"
#include "parser/RmEffect.h"
#include "parser/RmPass.h"
#include "ui_rmShadowDialog.h"
#include "glstateholder.h"
class RmShaderDialog : public QDialog
{
Q_OBJECT
public:
RmShaderDialog( GLStateHolder * holder, RmXmlParser * parser, QGLWidget* gla, RenderMode &rm, QWidget *parent = NULL );
~RmShaderDialog();
private:
Ui_RmShaderDialogClass ui;
QGLWidget* glarea;
RenderMode * rendMode;
RmXmlParser * parser;
RmEffect * eff_selected;
RmPass * pass_selected;
QList<QWidget*> shown;
GLStateHolder * holder;
QSignalMapper * signaler;
public slots:
void fillDialogWithEffect( int index );
void fillTabsWithPass( int index );
void clearTabs();
void valuesChanged(const QString & varNameAndIndex );
};
#endif