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 +