From dfaa8beb7bab9052acfb6498fc9275b9fe84af16 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Wed, 12 Sep 2007 15:38:01 +0000 Subject: [PATCH] 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. --- .../render_rm/glstateholder.cpp | 394 +++++++++++++++ src/meshlabplugins/render_rm/glstateholder.h | 133 +++++ src/meshlabplugins/render_rm/parser/GlState.h | 40 ++ src/meshlabplugins/render_rm/parser/Makefile | 137 ++++++ .../render_rm/parser/Makefile.Debug | 155 ++++++ .../render_rm/parser/Makefile.Release | 155 ++++++ .../render_rm/parser/RmEffect.h | 32 ++ .../render_rm/parser/RmPass.cpp | 36 ++ src/meshlabplugins/render_rm/parser/RmPass.h | 115 +++++ .../render_rm/parser/RmXmlParser.cpp | 247 ++++++++++ .../render_rm/parser/RmXmlParser.h | 80 +++ .../render_rm/parser/UniformVar.cpp | 454 ++++++++++++++++++ .../render_rm/parser/UniformVar.h | 114 +++++ src/meshlabplugins/render_rm/parser/main.cpp | 53 ++ .../render_rm/parser/parserxml.pro | 20 + src/meshlabplugins/render_rm/render_rm.pro | 42 ++ .../render_rm/rmShadowDialog.ui | 249 ++++++++++ src/meshlabplugins/render_rm/rmmeshrender.cpp | 103 ++++ src/meshlabplugins/render_rm/rmmeshrender.h | 53 ++ .../render_rm/rmshaderdialog.cpp | 384 +++++++++++++++ src/meshlabplugins/render_rm/rmshaderdialog.h | 63 +++ 21 files changed, 3059 insertions(+) create mode 100644 src/meshlabplugins/render_rm/glstateholder.cpp create mode 100644 src/meshlabplugins/render_rm/glstateholder.h create mode 100644 src/meshlabplugins/render_rm/parser/GlState.h create mode 100644 src/meshlabplugins/render_rm/parser/Makefile create mode 100644 src/meshlabplugins/render_rm/parser/Makefile.Debug create mode 100644 src/meshlabplugins/render_rm/parser/Makefile.Release create mode 100644 src/meshlabplugins/render_rm/parser/RmEffect.h create mode 100644 src/meshlabplugins/render_rm/parser/RmPass.cpp create mode 100644 src/meshlabplugins/render_rm/parser/RmPass.h create mode 100644 src/meshlabplugins/render_rm/parser/RmXmlParser.cpp create mode 100644 src/meshlabplugins/render_rm/parser/RmXmlParser.h create mode 100644 src/meshlabplugins/render_rm/parser/UniformVar.cpp create mode 100644 src/meshlabplugins/render_rm/parser/UniformVar.h create mode 100644 src/meshlabplugins/render_rm/parser/main.cpp create mode 100644 src/meshlabplugins/render_rm/parser/parserxml.pro create mode 100644 src/meshlabplugins/render_rm/render_rm.pro create mode 100644 src/meshlabplugins/render_rm/rmShadowDialog.ui create mode 100644 src/meshlabplugins/render_rm/rmmeshrender.cpp create mode 100644 src/meshlabplugins/render_rm/rmmeshrender.h create mode 100644 src/meshlabplugins/render_rm/rmshaderdialog.cpp create mode 100644 src/meshlabplugins/render_rm/rmshaderdialog.h diff --git a/src/meshlabplugins/render_rm/glstateholder.cpp b/src/meshlabplugins/render_rm/glstateholder.cpp new file mode 100644 index 000000000..b490e47fa --- /dev/null +++ b/src/meshlabplugins/render_rm/glstateholder.cpp @@ -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 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 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 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 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 & _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(); +} + diff --git a/src/meshlabplugins/render_rm/glstateholder.h b/src/meshlabplugins/render_rm/glstateholder.h new file mode 100644 index 000000000..cf55f46f1 --- /dev/null +++ b/src/meshlabplugins/render_rm/glstateholder.h @@ -0,0 +1,133 @@ +#ifndef __GLSTATEHOLDER_H__ +#define __GLSTATEHOLDER_H__ + +#include "parser/RmPass.h" +#include "parser/UniformVar.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#include + + + +// * 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 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 passes; + QString lastError; + bool supported; + + public: + + bool needUpdateInGLMemory; + + GLStateHolder( ) {needUpdateInGLMemory = true; supported = false;} + GLStateHolder( QList & passes ) { setPasses(passes); needUpdateInGLMemory = true; supported = false; } + ~GLStateHolder( ); + + void setPasses( QList & 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 + diff --git a/src/meshlabplugins/render_rm/parser/GlState.h b/src/meshlabplugins/render_rm/parser/GlState.h new file mode 100644 index 000000000..6fff3212a --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/GlState.h @@ -0,0 +1,40 @@ +#ifndef __GLSTATE_H__ +#define __GLSTATE_H__ + +#include +#include + +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 + diff --git a/src/meshlabplugins/render_rm/parser/Makefile b/src/meshlabplugins/render_rm/parser/Makefile new file mode 100644 index 000000000..9eecc5838 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/Makefile @@ -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 diff --git a/src/meshlabplugins/render_rm/parser/Makefile.Debug b/src/meshlabplugins/render_rm/parser/Makefile.Debug new file mode 100644 index 000000000..facd48835 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/Makefile.Debug @@ -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: + diff --git a/src/meshlabplugins/render_rm/parser/Makefile.Release b/src/meshlabplugins/render_rm/parser/Makefile.Release new file mode 100644 index 000000000..3e2fcc259 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/Makefile.Release @@ -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: + diff --git a/src/meshlabplugins/render_rm/parser/RmEffect.h b/src/meshlabplugins/render_rm/parser/RmEffect.h new file mode 100644 index 000000000..b51dfc9ac --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/RmEffect.h @@ -0,0 +1,32 @@ +#ifndef __RMEFFECT_H__ +#define __RMEFFECT_H__ + +#include +#include + +#include "RmPass.h" + +class RmEffect +{ + QString name; + QList 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 & getPassList() { return passlist; } + + void addPass( RmPass pass ) { passlist.append(pass); } + QString & getName() { return name; } + + void sortPasses() { qSort( passlist.begin(), passlist.end() ); } +}; + +#endif + diff --git a/src/meshlabplugins/render_rm/parser/RmPass.cpp b/src/meshlabplugins/render_rm/parser/RmPass.cpp new file mode 100644 index 000000000..27dc8ac44 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/RmPass.cpp @@ -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(); +} + + diff --git a/src/meshlabplugins/render_rm/parser/RmPass.h b/src/meshlabplugins/render_rm/parser/RmPass.h new file mode 100644 index 000000000..d991633a2 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/RmPass.h @@ -0,0 +1,115 @@ +#ifndef __RMPASS_H__ +#define __RMPASS_H__ + +#include +#include +#include +#include + + +#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 fragmentUniform; + QList vertexUniform; + + QString modelReference; + QString modelReferenceFileName; + QList 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 + diff --git a/src/meshlabplugins/render_rm/parser/RmXmlParser.cpp b/src/meshlabplugins/render_rm/parser/RmXmlParser.cpp new file mode 100644 index 000000000..73a0605a7 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/RmXmlParser.cpp @@ -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 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.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(); +} + diff --git a/src/meshlabplugins/render_rm/parser/RmXmlParser.h b/src/meshlabplugins/render_rm/parser/RmXmlParser.h new file mode 100644 index 000000000..8107c0c91 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/RmXmlParser.h @@ -0,0 +1,80 @@ +#ifndef __RMXMLPARSER_H__ +#define __RMXMLPARSER_H__ + +#include +#include +#include +#include +#include + +#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 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 + diff --git a/src/meshlabplugins/render_rm/parser/UniformVar.cpp b/src/meshlabplugins/render_rm/parser/UniformVar.cpp new file mode 100644 index 000000000..030b6af90 --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/UniformVar.cpp @@ -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["<" << 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["< 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["< +#include +#include +#include +#include + +#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 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 + diff --git a/src/meshlabplugins/render_rm/parser/main.cpp b/src/meshlabplugins/render_rm/parser/main.cpp new file mode 100644 index 000000000..90dfa4e8c --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/main.cpp @@ -0,0 +1,53 @@ +#include "RmXmlParser.h" + +#include +#include +#include +#include + + +#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; +} + diff --git a/src/meshlabplugins/render_rm/parser/parserxml.pro b/src/meshlabplugins/render_rm/parser/parserxml.pro new file mode 100644 index 000000000..9278c563c --- /dev/null +++ b/src/meshlabplugins/render_rm/parser/parserxml.pro @@ -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 diff --git a/src/meshlabplugins/render_rm/render_rm.pro b/src/meshlabplugins/render_rm/render_rm.pro new file mode 100644 index 000000000..1e13c6a52 --- /dev/null +++ b/src/meshlabplugins/render_rm/render_rm.pro @@ -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 diff --git a/src/meshlabplugins/render_rm/rmShadowDialog.ui b/src/meshlabplugins/render_rm/rmShadowDialog.ui new file mode 100644 index 000000000..7820284c6 --- /dev/null +++ b/src/meshlabplugins/render_rm/rmShadowDialog.ui @@ -0,0 +1,249 @@ + + RmShaderDialogClass + + + + 0 + 0 + 499 + 381 + + + + Qt::StrongFocus + + + RmShaderDialog + + + ../../../../../meshlab/src/meshlab/images/eye16.png + + + true + + + + + 10 + 40 + 481 + 331 + + + + Passes + + + + + 10 + 20 + 461 + 22 + + + + + + + 10 + 50 + 461 + 271 + + + + 0 + + + + Uniform + + + + + 10 + 10 + 441 + 231 + + + + QFrame::Box + + + QFrame::Raised + + + 1 + + + 0 + + + + + 10 + 10 + 421 + 211 + + + + + + + + + Textures + + + + + 10 + 10 + 441 + 231 + + + + QFrame::Box + + + QFrame::Raised + + + + + 10 + 10 + 421 + 211 + + + + + + + + + OpenGL + + + + + 10 + 10 + 441 + 231 + + + + QFrame::Box + + + QFrame::Raised + + + + + 10 + 10 + 421 + 211 + + + + + + + + + Vertex + + + + + 0 + 0 + 451 + 241 + + + + QTextEdit::NoWrap + + + true + + + false + + + + + + Fragment + + + + + 0 + 0 + 451 + 241 + + + + QTextEdit::NoWrap + + + true + + + false + + + + + + + + + 10 + 10 + 81 + 21 + + + + Effect Selection + + + + + + 90 + 10 + 181 + 22 + + + + + + + 280 + 10 + 75 + 23 + + + + Ok + + + + + + diff --git a/src/meshlabplugins/render_rm/rmmeshrender.cpp b/src/meshlabplugins/render_rm/rmmeshrender.cpp new file mode 100644 index 000000000..4a9633f31 --- /dev/null +++ b/src/meshlabplugins/render_rm/rmmeshrender.cpp @@ -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) + diff --git a/src/meshlabplugins/render_rm/rmmeshrender.h b/src/meshlabplugins/render_rm/rmmeshrender.h new file mode 100644 index 000000000..ac01efb38 --- /dev/null +++ b/src/meshlabplugins/render_rm/rmmeshrender.h @@ -0,0 +1,53 @@ +#ifndef RMSHADERRENDERPLUGIN_H +#define RMSHADERRENDERPLUGIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 rmsources; + + QList actionList; + + RmShaderDialog * dialog; + GLStateHolder holder; + + private: + + void initActionList(); + + public: + RmMeshShaderRenderPlugin() { dialog = NULL; } + ~RmMeshShaderRenderPlugin() { QMapIterator i(rmsources); while( i.hasNext() ) { i.next(); delete i.value();} } + + QList 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 + diff --git a/src/meshlabplugins/render_rm/rmshaderdialog.cpp b/src/meshlabplugins/render_rm/rmshaderdialog.cpp new file mode 100644 index 000000000..d80722091 --- /dev/null +++ b/src/meshlabplugins/render_rm/rmshaderdialog.cpp @@ -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 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( "See texture tab" ); + 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 + "
"; + varname += "Filename: " + finfo.fileName() + (f.exists() ? "" : " [not found]"); + + for( int k = 0; k < v.textureGLStates.size(); k++ ) + varname += "
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(shown[i]); + if( dinp ) { val = QVariant(dinp -> value()); } + QSpinBox * sinp = dynamic_cast(shown[i]); + if( sinp ) { val = QVariant(sinp -> value()); } + QCheckBox * cinp = dynamic_cast(shown[i]); + if( cinp ) { val = QVariant(cinp -> checkState() == Qt::Checked); } + QLineEdit * linp = dynamic_cast(shown[i]); + if( linp ) { val = QVariant(linp -> text()); isTextureFileEdit = true; } + QPushButton * binp = dynamic_cast(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(shown[i])) && lbl -> objectName().left(len-2) != varname ) lbl = NULL; + if( !txt && (txt = dynamic_cast(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() + " [ok" + label.mid(statusEnd) ); + else lbl -> setText( label.mid(0,statusStart) + "Filename: " + finfo.fileName() + " [not found" + label.mid(statusEnd) ); + } + + holder -> updateUniformVariableValuesFromDialog( pass_selected -> getName(), varname, rowIdx, colIdx, val ); + + glarea -> updateGL(); +} + + diff --git a/src/meshlabplugins/render_rm/rmshaderdialog.h b/src/meshlabplugins/render_rm/rmshaderdialog.h new file mode 100644 index 000000000..23d8fe34d --- /dev/null +++ b/src/meshlabplugins/render_rm/rmshaderdialog.h @@ -0,0 +1,63 @@ +#ifndef RMSHADERDIALOG_H +#define RMSHADERDIALOG_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 shown; + GLStateHolder * holder; + + QSignalMapper * signaler; + + public slots: + void fillDialogWithEffect( int index ); + void fillTabsWithPass( int index ); + void clearTabs(); + + void valuesChanged(const QString & varNameAndIndex ); + +}; + +#endif +