Plugins are extensions to the HQR software which serve a particular user purpose but may not be needed by everybody. For this reason plugins are particularly suitable to those who want to beneficiate from the core of the program to test additional algorithm but without any modification of the base component of HQR. One example is calculation of local radiance fields: the user needs to be able to select a light path (see at right) and extend it to a local set of lines. This set is based on the loaded scene geometry and should be drawn somehow into the graphical window. For this, an interface is needed to make the plugin communicate with HQR. |
|
The interface for developing plugins works like this:
.so
library. Pieces of HQR code
required by the lib do not need to be compiled, and do no raise any link
error because the lib is not an executable.HQR::DataManager
class.
Existing entry-points are listed in the table below:
Name of entry-point | Parameters | Use |
void HQR_BUNDLE_draw() | void | called after drawing the rest of the scene. Used for drawing some data specific to the plugin |
void HQR_BUNDLE_select() | const HQR::GlobalIntersectionStructure& P |
called when selecting an object. |
void HQR_BUNDLE_click() | const HQR::Point3& P, |
called when the mouse clicks in the drawing window. P is the point corresponding to the eye and d the direction of the ray. |
QWidget *HQR_BUNDLE_buildInterface() | void | called at interface creation. The supplied widget will be added in the main panel. Use it to create your own interface functionalities. One widget per plugin is allowed. |
bool HQR_BUNDLE_takesJob() | const HQR::Config& C | This function is provided for the HQR command-line use of the plugin. It is passed the Config structure corresponding to the job file passed as argument to the executable, and should only return true or false depending if it accepts to perform the job described by the JOB_TYPE variable. See Base/Config.h for how to get variable values in Config structures. Use this function to have your plugin take priority over the default job. |
void HQR_BUNDLE_performJob() | const HQR::Config& C | Also provided for the HQR command-line use of the plugin. This function should contain the actions the plugin may want to do on a scene in replacement of the classical photon mapping computation. Its own variables are to be accessed in the passed Config structure. |
void HQR_BUNDLE_nonPrehemptiveJob() | const HQR::Config& C | This function is provided for anyone who wants to read configuration values in the config file, but still letting HQR perform its regular job. This happens e.g. if you modify a structure in the program (e.g. the Global Intersector) and want to setup parameters accordingly. |
bool HQR_BUNDLE_saveConfig() | std::ofstream& file |
For saving a config file, the plugin may either call Interface::saveConfig(const char *job_type) , passing the name of the
job the plugin is made for (if one wants to setup a specific job name for the output .hqr file) or let HQR call Interface::saveConfig("STILL_IMAGE") which is the default. This name will figure in
the JOBE_TYPE variable of the config file and will allow the plugin to
handle this config file correctly (see the HQR_BUNDLE_takesJob() function above).
After saving its own variables into the config file file , Interface::saveConfig() calls
HQR_BUNDLE_saveConfig() , passing the file ofstream to the plugin so that it can add its own variables to the
config file. As output, true must be returned if no error were encountered while saving, false otherwise.
|
unsigned int HQR_BUNDLE_disableInterfaces() | void | Should return an ORed value of HQR::Interface::InterfaceType values for preventing the corresponding interface panels to be added to the usual control panel. |
HQR::RayTracer *HQR_BUNDLE_allocateRayTracer() | void | Called for replacing the default raytracer |
HQR::PhotonMapCreator *HQR_BUNDLE_allocatePhotonMapCreator() | void | Called for replacing the default photonmap creator |
HQR::PhotonMap *HQR_BUNDLE_allocatePhotonMap() | void | Called for replacing the default photonmap |
HQR::GlobalIntersectionStructure *HQR_BUNDLE_allocateGlobalIntersectionStructure() | void | Called for replacing the default global intersection structure |
.cpp
file.Of course, not all possible entry points have been coded up to now, but adding a new one on request will not take long.
The SurfaceLightField plugin which can be found in the HQR/Plugins/SurfaceLightField
directory, has been implemented that way.
The goal of the plugin is to be able to compute the 4D incident or reflected lightfield attached to an object with texture coordinates.
The plugin thus needs:
SLFBundle.cpp
file:
#include <iostream> #include <qwidget.h> #include <GL/gl.h> // -======================================================- // // References to HQR headers // // -======================================================- // #include <Base/Config.h> #include <Geometry/Point3.h> #include <Geometry/NVector3.h> #include <Geometry/Ray.h> #include <Geometry/GPIndexedFaceSet.h> #include <Kernel/DataManager.h> #include <RayTracer/RayTracer.h> #include <HQR/ttyRasterCallback.h> #include <GUI/Interface.h> namespace HQR { class Point3 ; class NVector3 ; class SNObject ; } // -======================================================- // // Local headers // // -======================================================- // #include "SLFBundle.h" #include "SLFCreator.h" #include "SLF_Wimpl.h" // -======================================================- // // Interface for dynamic loading into the GUI // // -======================================================- // QWidget *HQR_BUNDLE_buildInterface() { return SLFBundle::getInterface() ; } unsigned int HQR_BUNDLE_suppressInterfaces() { return Interface::Interface_StillImageCreator ; } void HQR_BUNDLE_select(const HQR::Point3&,const HQR::NVector3&,const HQR::NVector3&,const HQR::NVector3&,const HQR::SNObject *sno) { SLFBundle::getInterface()->updateSelectedObject(sno) ; } bool HQR_BUNDLE_saveConfig(const char *job_type,ofstream& file) { if(!strcmp(job_type,"SLF")) { SLFBundle::getInterface()->saveConfig(file) ; return true ; } else return false ; } bool HQR_BUNDLE_takesJob(const HQR::Config& C) { if(!strcmp(C.getStringValue("JOB_TYPE",""),"SLF")) return true ; else return false ; } void HQR_BUNDLE_performJob(const HQR::Config& C) { try { const char *name = C.getStringValue("SLF_NAME_TEMPLATE","") ; if(strlen(name) == 0) { name = "no_name" ; SWARNING << "No name supplied for output slf (SLF_NAME_TEMPLATE variable). \"no_name\" will be used." << endl ; } DataManager::preparePhotonMaps() ; DataManager::getRayTracer()->setEpsilon(DataManager::getGlobalEpsilon()) ; const char *obj_name = C.getStringValue("SLF_OBJECT_NAME","") ; if(strlen(obj_name) == 0) throw runtime_error("No name given for object to treat. Use the SLF_OBJECT_NAME variable.") ; const SNObject *sno = DataManager::findObjectInSceneGraph(obj_name) ; if(sno == NULL) throw runtime_error(string("No object called '")+obj_name+"'. Giving up.") ; const GPIndexedFaceSet *gpi = dynamic_cast<const GPIndexedFaceSet *>(sno->getPrimitive()) ; if(gpi == NULL) throw runtime_error(string("Object called '")+obj_name+"' is not an indexed face set. Giving up.") ; if(gpi->getTexCoord().empty()) throw runtime_error(string("Object called '")+obj_name+"' does not have texture coordinates. Giving up.") ; int W = C.getIntValue("SLF_WIDTH",100) ; int H = C.getIntValue("SLF_HEIGHT",100) ; int T = C.getIntValue("SLF_NTHETA",50) ; int P = C.getIntValue("SLF_NPHI",100) ; bool incident = (!strcmp(C.getStringValue("SLF_DIRECTION","INCIDENT"),"INCIDENT"))?1:0; int nb_proc = C.getIntValue("NUMBER_OF_CONCURRENT_JOBS",1) ; DataManager::getRayTracer()->shutUpOnSkippedPixels(true) ; ttyRasterCallback rstb ; SLFCreator::computeAndSaveSLF(name,nb_proc,gpi,W,H,T,P,&rstb,incident) ; } catch(exception& e) { cout << "Job raised an exception: " << e.what() << endl ; return ; } } // -======================================================- // // Storage of variables of the plugin // // -======================================================- // SLF_Wimpl *SLFBundle::getInterface() { static SLF_Wimpl *_int = NULL ; if(_int == NULL) _int = new SLF_Wimpl() ; return _int ; }
This file mainly contains the entry points to link the HQR software to the SurfaLightField extension.
Because entry points can not be class members, they themselves call static members of a
class (the SLFBundle
class) which contains the very functionalities of the plugin.
The complete source of the plugin is in the Plugins/SurfaceLightField
directory.
It is possible to test it using:
GUI Build/i686-linux-g++/plugins/libSLF.so
The HQR exe should output a line which reads:
[INFO] Loaded bundle Build/i686-linux-g++/plugins/libSLF.so
Note: do not forget to put the absolute path of the lib, or at least a leading './' before it. Otherwise
you get an error like:
[ERROR] libSLFBundle.so: cannot open shared object file: No such file or directory
The interface should know contain the added widget:
The use of plugins in the current state of the program has some limits however. Functionalities which touch the very core of the algorithm may not be easy to implement using the provided interface. For instance building a plugin to treat BRDF's would need to register many functionalities in the parsing library as well as in the core of the rendering algorithm. However, such a functionality may be considered to be included in the core of HQR for the same reasons. Some easy-to implement plugins include: