diff --git a/src/fgt/filter_hqrender/filter_hqrender.h b/src/fgt/filter_hqrender/filter_hqrender.h index 8102a5a67..4d9085f46 100644 --- a/src/fgt/filter_hqrender/filter_hqrender.h +++ b/src/fgt/filter_hqrender/filter_hqrender.h @@ -93,16 +93,22 @@ private: //parser_rib.cpp int numberOfDummies, numOfObject; - struct ObjValues { + /*struct ObjValues { vcg::Matrix44f objectMatrix; float objectBound[6]; // xmin, xmax, ymin, ymax, zmin, zmax QStringList objectShader; QString objectId; QString objectDisplacementbound; - }; + };*/ + QStack transfMatrix; + QStack surfaceShader; + float objectBound[6]; // xmin, xmax, ymin, ymax, zmin, zmax + bool makeScene(MeshModel* m, QStringList* textureList, RichParameterSet &par, QString templatePath, QString destDirString, QStringList* shaderDirs, QStringList* textureDirs, QStringList* proceduralDirs, QStringList* imagesRendered); - QString parseObject(RibFileStack* files, QString destDir, int currentFrame, MeshModel* m, RichParameterSet &par, QStringList* textureList); - bool convertObject(FILE* fout, QString destDir, MeshModel* m, RichParameterSet &par, QStringList* textureList, ObjValues* dummyValues); + //QString parseObject(RibFileStack* files, QString destDir, int currentFrame, MeshModel* m, RichParameterSet &par, QStringList* textureList); + QString convertObject(int currentFrame, QString destDir, MeshModel* m, RichParameterSet &par, QStringList* textureList); + bool resetBound(); + bool resetGraphicsState(); int writeMatrix(FILE* fout, const vcg::Matrix44f* matrix, bool transposed = true); vcg::Matrix44f getMatrix(const QString* matrixString) const; enum searchType{ ERR, ARCHIVE, SHADER, TEXTURE, PROCEDURAL }; diff --git a/src/fgt/filter_hqrender/parser_rib.cpp b/src/fgt/filter_hqrender/parser_rib.cpp index 995c87c15..24e12f466 100644 --- a/src/fgt/filter_hqrender/parser_rib.cpp +++ b/src/fgt/filter_hqrender/parser_rib.cpp @@ -3,7 +3,302 @@ using namespace UtilitiesHQR; +bool FilterHighQualityRender::resetBound() { + // xmin, xmax, ymin, ymax, zmin, zmax + //default RIS bound is infinite + for(int i=0; i< 6; i=i+2) + objectBound[i] = std::numeric_limits::min(); + for(int i=1; i<6; i=i+2) + objectBound[i] = std::numeric_limits::max(); + return true; +} + +bool FilterHighQualityRender::resetGraphicsState() { + //graphics state initialization (only interesting things) + transfMatrix = QStack(); + transfMatrix << vcg::Matrix44f::Identity(); + surfaceShader = QStack(); + surfaceShader << ""; //nothing to set implementation-dependent default surface shader + resetBound(); + return true; +} + + +//read source files and write to destination file +//if it's found the attribute name with value "dummy", the following geometry statement +//are replaced with a current mesh conversion bool FilterHighQualityRender::makeScene(MeshModel* m, + QStringList* textureList, + RichParameterSet &par, + QString templatePath, + QString destDirString, + QStringList* shaderDirs, + QStringList* textureDirs, + QStringList* proceduralDirs, + QStringList* imagesRendered) +{ + + //rib file structure + RibFileStack files(getDirFromPath(&templatePath)); //constructor + //open file and stream + if(!files.pushFile(&templatePath)) { + this->errorMessage = "Template path is wrong: " + templatePath; + return false; + } + + //output file + FILE* fout; + fout = fopen(qPrintable(destDirString + QDir::separator() + mainFileName()),"wb"); + if(fout==NULL) { + this->errorMessage = "Impossible to create file: " + destDirString + QDir::separator() + mainFileName(); + return false; + } + qDebug("Starting to write rib file into %s",qPrintable(destDirString + QDir::separator() + mainFileName())); + + FILE* fmain = fout; //if change the output file, the main is saved here + convertedGeometry = false; //if the mesh is already converted + int currentFrame = 0; //frame counter + + bool stop = false; + bool currentDisplayTypeIsFile = false; + bool anyOtherDisplayType = false; + numberOfDummies = 0; //the dummy object could be than one (e.g. for ambient occlusion passes) + QString newFormat = "Format " + + QString::number(par.getInt("FormatX")) + " " + + QString::number(par.getInt("FormatY")) + " " + + QString::number(par.getFloat("PixelAspectRatio")); + numOfWorldBegin = 0; //the number of world begin statement found (for progress bar) + numOfObject = 0; + bool foundDummy = false; + bool solidBegin = false; //true only if define a dummy object + bool writeLine = true; //true if the line has to be write to final file + resetGraphicsState(); //transformation matrix, bound, surface shader + //reading cycle + while(!files.hasNext() && !stop) { + if(!solidBegin) + writeLine = true; + int statementType = 0; //type of statement + QString line = files.nextStatement(&statementType); //current line + + switch(statementType) { + //declare other directory for the template + case ribParser::OPTION: { + QStringList token = ribParser::splitStatement(&line); + if(token[2] == "searchpath") { + int type = 0; + QStringList dirList = readSearchPath(&token,&type); + switch(type) { + case FilterHighQualityRender::ARCHIVE: + files.addSubDirs(dirList); + break; + case FilterHighQualityRender::SHADER: + *shaderDirs = dirList; + break; + case FilterHighQualityRender::TEXTURE: + *textureDirs = dirList; + break; + case FilterHighQualityRender::PROCEDURAL: + *proceduralDirs = dirList; + break; + case FilterHighQualityRender::ERR: + //ignore: maybe an error or another searchpath type (not in RISpec3.2) + break; + } + } + break; + } + //make a map (create the path if needed) + case ribParser::MAKE: + case ribParser::MAKECUBEFACEENVIRONMENT: + { + QStringList token = ribParser::splitStatement(&line); + QString path = token[2]; //for MakeTexture, MakeShadow, MakeLatLongEnvironment + if(statementType == ribParser::MAKECUBEFACEENVIRONMENT) + path = token[7]; + path = getDirFromPath(&path); + //qDebug("check dir! line: %s\npath: %s",qPrintable(line),qPrintable(path)); + checkDir(&destDirString,&path); + break; + } + //begin a new frame + case ribParser::FRAMEBEGIN: + { + QStringList token = ribParser::splitStatement(&line); + bool isNum; + int i = token[1].toInt(&isNum); + if(isNum) + currentFrame = i; + break; + } + //set output type (create the path if needed) + case ribParser::DISPLAY: + { + //if output is not a file the format must be the same!! framebuffer is ignored and commented + QStringList token = ribParser::splitStatement(&line); + //create the path if needed + QString path = token[2]; + path = getDirFromPath(&path); + //qDebug("check dir! line: %s\npath: %s",qPrintable(line),qPrintable(path)); + checkDir(&destDirString,&path); + + //if there's more "Display" statement with one that's "file" is not considered a final image + if(token[5] != "framebuffer") + if (!anyOtherDisplayType && token[5] == "file") { + currentDisplayTypeIsFile = true; + QString img = token[2]; + if(img.startsWith('+')) + img = img.mid(1,img.size()); + *imagesRendered << img; + } + else + anyOtherDisplayType = true; + else + line = "#" + line; //if there's a framebuffer will be open pqsl automatically + break; + } + //a new world description (reset graphics state) + case ribParser::WORLDBEGIN: + { + numOfWorldBegin++; + //if there's another type of display the format is not change + if(!anyOtherDisplayType && currentDisplayTypeIsFile) { + fprintf(fout,"%s\n", qPrintable(newFormat)); + } + currentDisplayTypeIsFile = false; + anyOtherDisplayType = false; + //is right?yes,because before the next WorldBegin will there be a new Display statement + resetGraphicsState(); //reset the graphics state + break; + } + //set transform in graphics state + case ribParser::TRANSFORM: + { + transfMatrix.pop(); + transfMatrix.push(getMatrix(&line)); + break; + } + //set surface in graphics state + case ribParser::SURFACE: + { + //the surface shader remain the same of template + surfaceShader.pop(); + surfaceShader.push(line); + break; + } + //set bound in graphics state + case ribParser::BOUND: + { + //take the transformation bound + QStringList token = ribParser::splitStatement(&line); + int index = 1; + if(token[index] == "[") + index++; + for(int i=0; i<6; i++) { + bool isNumber; + float number = token[index+i].toFloat(&isNumber); + if(isNumber) + objectBound[i] = number; + } + break; + } + //looking for a dummy + case ribParser::ATTRIBUTE: + { + QStringList token = ribParser::splitStatement(&line); + //RISpec3.2 not specify what and how many attributes are there in renderman + //we take care of name only + if(token[2] == "identifier") { + //Attribute "identifier" "string name" [ "object name" ] + if(token[5] == "string name" || token[5] == "name") { + int index = 7; + if(token[index] == "[") + index++; + if(token[index] == "\"") + index++; + if(token[index].trimmed().toLower() == "dummy") {//found a dummy object? + foundDummy = true; + } + } + } + break; + } + //the begin of a set of statement to define a solid + case ribParser::SOLIDBEGIN: { + if(foundDummy) { + solidBegin = true; + writeLine = false; + } + } + //the end of solid definition + case ribParser::SOLIDEND: { + if(solidBegin) { + QString filename = convertObject(currentFrame, destDirString, m, par, textureList); + qDebug("dummy conversion, filename: %s",qPrintable(filename)); + if(filename == "") { //error in parseObject + fclose(fmain); + return false; + } + fprintf(fout,"ReadArchive \"%s\"\n",qPrintable(filename)); + + solidBegin = false; + foundDummy = false; + } + //reset bound (and surface?) + resetBound(); + break; + } + //there's a geometric statement...if there was a dummy too, replace geometry + case ribParser::GEOMETRIC: { + if(foundDummy) { + QString filename = convertObject(currentFrame, destDirString, m, par, textureList); + qDebug("dummy conversion, filename: %s",qPrintable(filename)); + if(filename == "") { //error in parseObject + fclose(fmain); + return false; + } + fprintf(fout,"ReadArchive \"%s\"\n",qPrintable(filename)); + + writeLine = false; + foundDummy = false; + } + //reset bound (and surface?) + resetBound(); + break; + } + //add a new graphics state "level" + case ribParser::ATTRIBUTEBEGIN: + { + transfMatrix.push(transfMatrix.top()); + surfaceShader.push(surfaceShader.top()); + break; + } + //remove a "level" to graphics state stack + case ribParser::ATTRIBUTEEND: + { + transfMatrix.pop(); + surfaceShader.pop(); + break; + } + //the end of scene is reached + case ribParser::NOMORESTATEMENT: + { + qDebug("Stack empty"); + stop = true; + writeLine = false; + } + } + + if(writeLine) { + //copy the same line in file + fprintf(fout,"%s\n",qPrintable(line)); + } + } + fclose(fout); + return true; +} + + +/*bool FilterHighQualityRender::makeScene(MeshModel* m, QStringList* textureList, RichParameterSet &par, QString templatePath, @@ -32,7 +327,7 @@ bool FilterHighQualityRender::makeScene(MeshModel* m, FILE* fmain = fout; //if change the output file, save the main convertedGeometry = false; //if the mesh is already converted int currentFrame = 0; - vcg::Matrix44f transfCamera = vcg::Matrix44f::Identity(); + vcg::Matrix44f transfObject = vcg::Matrix44f::Identity(); bool stop = false; bool currentDisplayTypeIsFile = false; bool anyOtherDisplayType = false; @@ -100,10 +395,10 @@ bool FilterHighQualityRender::makeScene(MeshModel* m, currentFrame = i; break; } - case ribParser::FRAMEEND: - { - break; - } + //case ribParser::FRAMEEND: + //{ + // break; + //} case ribParser::DISPLAY: { //if output is not a file the format must be the same!! framebuffer is ignored and commented @@ -131,8 +426,9 @@ bool FilterHighQualityRender::makeScene(MeshModel* m, } case ribParser::TRANSFORM: { + transfObject = getMatrix(&line); break; - } + } case ribParser::WORLDBEGIN: { numOfWorldBegin++; @@ -143,15 +439,16 @@ bool FilterHighQualityRender::makeScene(MeshModel* m, currentDisplayTypeIsFile = false; anyOtherDisplayType = false; //is right?yes,because before the next WorldBegin will there be a new Display statement + transfObject = vcg::Matrix44f::Identity(); //reset the graphics state break; } - case ribParser::WORLDEND: - { - break; - } + //case ribParser::WORLDEND: + //{ + // break; + //} case ribParser::ATTRIBUTEBEGIN: { - //is an object + //is an object (peraphs) //write it (o convert it if it's named dummy) to another file QString filename = parseObject(&files, destDirString, currentFrame, m, par, textureList); qDebug("fuori: %s",qPrintable(filename)); @@ -178,9 +475,10 @@ bool FilterHighQualityRender::makeScene(MeshModel* m, } fclose(fout); return true; -} +}*/ //object is a sequence beetwen the statement AttributeBegin and AttributeEnd +/* QString FilterHighQualityRender::parseObject(RibFileStack* files, QString destDirString, int currentFrame, MeshModel* m, RichParameterSet &par, QStringList* textureList) { QString name = "object" + QString::number(numOfObject) + ".rib"; FILE* fout = fopen(qPrintable(destDirString + QDir::separator() + name),"wb"); @@ -308,22 +606,30 @@ QString FilterHighQualityRender::parseObject(RibFileStack* files, QString destDi delete current; return name; } +*/ +//write to an opened file the attribute of object entity -//write on a opened file the attribute of object entity -bool FilterHighQualityRender::convertObject(FILE* fout, QString destDir, MeshModel* m, RichParameterSet &par, QStringList* textureList, ObjValues* dummyValues) +QString FilterHighQualityRender::convertObject(int currentFrame, QString destDir, MeshModel* m, RichParameterSet &par, QStringList* textureList)//, ObjValues* dummyValues) { - fprintf(fout,"AttributeBegin\n"); + QString name = "meshF" + QString::number(currentFrame) + "O" + QString::number(numberOfDummies) + ".rib"; + numberOfDummies++; + FILE *fout = fopen(qPrintable(destDir + QDir::separator() + name),"wb"); + if(fout == NULL) { + this->errorMessage = "Impossible to create the file: " + destDir + QDir::separator() + name; + return ""; + } + fprintf(fout,"AttributeBegin\n"); //name - fprintf(fout,"Attribute \"identifier\" \"string name\" [ \"dummy\" ]\n"); + fprintf(fout,"Attribute \"identifier\" \"string name\" [ \"meshlabMesh\" ]\n"); //id - if(dummyValues->objectId != "") + /*if(dummyValues->objectId != "") fprintf(fout,"%s\n",qPrintable(dummyValues->objectId.trimmed())); - + */ //modify the transformation matrix vcg::Matrix44f scaleMatrix = vcg::Matrix44f::Identity(); - float dummyX = dummyValues->objectBound[1] - dummyValues->objectBound[0]; - float dummyY = dummyValues->objectBound[3] - dummyValues->objectBound[2]; - float dummyZ = dummyValues->objectBound[5] - dummyValues->objectBound[4]; + float dummyX = objectBound[1] - objectBound[0]; + float dummyY = objectBound[3] - objectBound[2]; + float dummyZ = objectBound[5] - objectBound[4]; //autoscale float scale = 1.0; @@ -365,14 +671,14 @@ bool FilterHighQualityRender::convertObject(FILE* fout, QString destDir, MeshMod } vcg::Matrix44f alignMatrix; alignMatrix = alignMatrix.SetTranslate(dx,dy,dz); - vcg::Matrix44f templateMatrix = dummyValues->objectMatrix; //by default is identity + vcg::Matrix44f templateMatrix = transfMatrix.top(); //by default is identity vcg::Matrix44f result = templateMatrix * alignMatrix * scaleMatrix * translateBBMatrix; //write transformation matrix (after transpose it) writeMatrix(fout, &result); QString bound = "Bound"; for(int i=0; i<6; i++) - bound += " " + QString::number(dummyValues->objectBound[i]); + bound += " " + QString::number(objectBound[i]); /*fprintf(fout,"Bound %g %g %g %g %g %g", m.cm.trBB().min.X(), m.cm.trBB().max.X(), m.cm.trBB().min.Y(), m.cm.trBB().max.Y(), @@ -384,12 +690,10 @@ bool FilterHighQualityRender::convertObject(FILE* fout, QString destDir, MeshMod //force the shading interpolation to smooth fprintf(fout,"ShadingInterpolation \"smooth\"\n"); //displacementBound - if(dummyValues->objectDisplacementbound != "") - fprintf(fout,"%s\n",qPrintable(dummyValues->objectDisplacementbound.trimmed())); + /*if(dummyValues->objectDisplacementbound != "") + fprintf(fout,"%s\n",qPrintable(dummyValues->objectDisplacementbound.trimmed()));*/ //shader - foreach(QString line, dummyValues->objectShader) { - fprintf(fout,"%s\n",qPrintable(line.trimmed())); - } + fprintf(fout,"%s\n",qPrintable(surfaceShader.top())); //texture mapping (are TexCoord needed for texture mapping?) if(!textureList->empty() > 0 && (m->cm.HasPerWedgeTexCoord() || m->cm.HasPerVertexTexCoord())) { //multi-texture don't work!I need ad-hoc shader and to read the texture index for vertex.. @@ -410,14 +714,14 @@ bool FilterHighQualityRender::convertObject(FILE* fout, QString destDir, MeshMod if(res != vcg::tri::io::ExporterRIB::E_NOERROR) { fclose(fout); this->errorMessage = QString(vcg::tri::io::ExporterRIB::ErrorMsg(res)); - return false; + return ""; } else Log(GLLogStream::FILTER,"Successfully converted mesh"); } fprintf(fout,"AttributeEnd\n"); fclose(fout); - return true; + return name; } //return an a list of directory (separated by ':' character) diff --git a/src/fgt/filter_hqrender/ribProcedure.h b/src/fgt/filter_hqrender/ribProcedure.h index d8c43f0c4..4d391b2e4 100644 --- a/src/fgt/filter_hqrender/ribProcedure.h +++ b/src/fgt/filter_hqrender/ribProcedure.h @@ -12,10 +12,13 @@ public: DISPLAY, FRAMEBEGIN, FRAMEEND, + GEOMETRIC, //Pag. 201 RISpec3.2 MAKE, MAKECUBEFACEENVIRONMENT, OPTION, READARCHIVE, + SOLIDBEGIN, + SOLIDEND, SURFACE, TRANSFORM, WORLDBEGIN, @@ -35,25 +38,25 @@ public: proc->insert("AttributeEnd", ribParser::ATTRIBUTEEND); proc->insert("Basis", ribParser::OTHER); proc->insert("Begin", ribParser::OTHER); - proc->insert("Blobby", ribParser::OTHER); + proc->insert("Blobby", ribParser::GEOMETRIC); proc->insert("Bound", ribParser::BOUND); proc->insert("Clipping", ribParser::OTHER); proc->insert("ClippingPlane", ribParser::OTHER); proc->insert("Color", ribParser::OTHER); proc->insert("ColorSamples", ribParser::OTHER); proc->insert("ConcatTransform", ribParser::OTHER); - proc->insert("Cone", ribParser::OTHER); + proc->insert("Cone", ribParser::GEOMETRIC); proc->insert("Context", ribParser::OTHER); proc->insert("CoordinateSystem", ribParser::OTHER); proc->insert("CoordSysTransform", ribParser::OTHER); proc->insert("CropWindow", ribParser::OTHER); - proc->insert("Curves", ribParser::OTHER); - proc->insert("Cylinder", ribParser::OTHER); + proc->insert("Curves", ribParser::GEOMETRIC); + proc->insert("Cylinder", ribParser::GEOMETRIC); proc->insert("Declare", ribParser::OTHER); proc->insert("DepthOfField", ribParser::OTHER); proc->insert("Detail", ribParser::OTHER); proc->insert("DetailRange", ribParser::OTHER); - proc->insert("Disk", ribParser::OTHER); + proc->insert("Disk", ribParser::GEOMETRIC); proc->insert("Displacement", ribParser::OTHER); proc->insert("Display", ribParser::DISPLAY); proc->insert("End", ribParser::OTHER); @@ -64,12 +67,12 @@ public: proc->insert("FrameAspectRatio", ribParser::OTHER); proc->insert("FrameBegin", ribParser::FRAMEBEGIN); proc->insert("FrameEnd", ribParser::FRAMEEND); - proc->insert("GeneralPolygon", ribParser::OTHER); + proc->insert("GeneralPolygon", ribParser::GEOMETRIC); proc->insert("GeometricApproximation", ribParser::OTHER); - proc->insert("Geometry", ribParser::OTHER); + proc->insert("Geometry", ribParser::GEOMETRIC); proc->insert("GetContext", ribParser::OTHER); proc->insert("Hider", ribParser::OTHER); - proc->insert("Hyperboloid", ribParser::OTHER); + proc->insert("Hyperboloid", ribParser::GEOMETRIC); proc->insert("Identity", ribParser::OTHER); proc->insert("Illuminate", ribParser::OTHER); proc->insert("Imager", ribParser::OTHER); @@ -82,24 +85,24 @@ public: proc->insert("Matte", ribParser::OTHER); proc->insert("MotionBegin", ribParser::OTHER); proc->insert("MotionEnd", ribParser::OTHER); - proc->insert("NuPatch", ribParser::OTHER); + proc->insert("NuPatch", ribParser::GEOMETRIC); proc->insert("ObjectBegin", ribParser::OTHER); proc->insert("ObjectEnd", ribParser::OTHER); proc->insert("ObjectInstance", ribParser::OTHER); proc->insert("Opacity", ribParser::OTHER); proc->insert("Option", ribParser::OPTION); proc->insert("Orientation", ribParser::OTHER); - proc->insert("Paraboloid", ribParser::OTHER); - proc->insert("Patch", ribParser::OTHER); - proc->insert("PatchMesh", ribParser::OTHER); + proc->insert("Paraboloid", ribParser::GEOMETRIC); + proc->insert("Patch", ribParser::GEOMETRIC); + proc->insert("PatchMesh", ribParser::GEOMETRIC); proc->insert("Perspective", ribParser::OTHER); proc->insert("PixelFilter", ribParser::OTHER); proc->insert("PixelSamples", ribParser::OTHER); proc->insert("PixelVariance", ribParser::OTHER); - proc->insert("Points", ribParser::OTHER); - proc->insert("PointsGeneralPolygons", ribParser::OTHER); - proc->insert("PointsPolygons", ribParser::OTHER); - proc->insert("Polygon", ribParser::OTHER); + proc->insert("Points", ribParser::GEOMETRIC); + proc->insert("PointsGeneralPolygons", ribParser::GEOMETRIC); + proc->insert("PointsPolygons", ribParser::GEOMETRIC); + proc->insert("Polygon", ribParser::GEOMETRIC); proc->insert("Procedural", ribParser::OTHER); proc->insert("Projection", ribParser::OTHER); proc->insert("Quantize", ribParser::OTHER); @@ -114,19 +117,19 @@ public: proc->insert("Shutter", ribParser::OTHER); proc->insert("Sides", ribParser::OTHER); proc->insert("Skew", ribParser::OTHER); - proc->insert("SolidBegin", ribParser::OTHER); - proc->insert("SolidEnd", ribParser::OTHER); - proc->insert("Sphere", ribParser::OTHER); - proc->insert("SubdivisionMesh", ribParser::OTHER); + proc->insert("SolidBegin", ribParser::SOLIDBEGIN); + proc->insert("SolidEnd", ribParser::SOLIDEND); + proc->insert("Sphere", ribParser::GEOMETRIC); + proc->insert("SubdivisionMesh", ribParser::GEOMETRIC); proc->insert("Surface", ribParser::SURFACE); proc->insert("TextureCoordinates", ribParser::OTHER); - proc->insert("Torus", ribParser::OTHER); + proc->insert("Torus", ribParser::GEOMETRIC); proc->insert("Transform", ribParser::TRANSFORM); proc->insert("TransformBegin", ribParser::OTHER); proc->insert("TransformEnd", ribParser::OTHER); proc->insert("TransformPoints", ribParser::OTHER); proc->insert("Translate", ribParser::OTHER); - proc->insert("TrimCurve", ribParser::OTHER); + proc->insert("TrimCurve", ribParser::GEOMETRIC); proc->insert("version", ribParser::OTHER); //not a procedure, but a keyword proc->insert("WorldBegin", ribParser::WORLDBEGIN); proc->insert("WorldEnd", ribParser::WORLDEND);