removed ImageRepresentationRenderTarget interface

parent 75668c09
......@@ -45,7 +45,6 @@
#include "application/campvispainter.h"
#include "application/gui/mainwindow.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/simplejobprocessor.h"
#include "core/tools/quadrenderer.h"
......
......@@ -31,14 +31,16 @@
#include "tgt/assert.h"
#include "tgt/camera.h"
#include "tgt/quadric.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "tgt/qt/qtthreadedcanvas.h"
#include "tgt/qt/qtglcontext.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/quadric.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/visualizationpipeline.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
......@@ -95,9 +97,9 @@ namespace campvis {
glViewport(0, 0, size.x, size.y);
// try get Data
ImageRepresentationRenderTarget::ScopedRepresentation image(_pipeline->getDataContainer(), _pipeline->getRenderTargetID());
DataContainer::ScopedTypedData<RenderData> rd(_pipeline->getDataContainer(), _pipeline->getRenderTargetID());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (image != 0) {
if (rd != 0) {
// activate shader
_copyShader->activate();
_copyShader->setIgnoreUniformLocationError(true);
......@@ -107,7 +109,7 @@ namespace campvis {
// bind input textures
tgt::TextureUnit colorUnit, depthUnit;
image->bind(_copyShader, colorUnit, depthUnit);
rd->bind(_copyShader, colorUnit, depthUnit);
LGL_ERROR;
// execute the shader
......
......@@ -35,7 +35,7 @@
#include "core/datastructures/datacontainer.h"
#include "core/datastructures/datahandle.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/facegeometry.h"
#include "core/tools/job.h"
......@@ -283,16 +283,24 @@ namespace campvis {
int maxSlices = 1;
for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) {
if (const ImageData* img = dynamic_cast<const ImageData*>(it->second.getData())) {
if (const ImageRepresentationRenderTarget* imgRT = img->getRepresentation<ImageRepresentationRenderTarget>(false)) {
for (size_t i = 0; i < imgRT->getNumColorTextures(); ++i)
_textures.push_back(imgRT->getColorTexture(i));
_textures.push_back(imgRT->getDepthTexture());
}
else if (const ImageRepresentationGL* imgGL = img->getRepresentation<ImageRepresentationGL>()) {
if (const ImageRepresentationGL* imgGL = img->getRepresentation<ImageRepresentationGL>()) {
_textures.push_back(imgGL->getTexture());
maxSlices = std::max(maxSlices, imgGL->getTexture()->getDimensions().z);
}
}
else if (const RenderData* rd = dynamic_cast<const RenderData*>(it->second.getData())) {
for (size_t i = 0; i < rd->getNumColorTextures(); ++i) {
const ImageRepresentationGL* imgGL = rd->getColorTexture(i)->getRepresentation<ImageRepresentationGL>();
if (imgGL)
_textures.push_back(imgGL->getTexture());
}
if (rd->hasDepthTexture()) {
const ImageRepresentationGL* imgGL = rd->getDepthTexture()->getRepresentation<ImageRepresentationGL>();
if (imgGL)
_textures.push_back(imgGL->getTexture());
}
}
}
if (maxSlices == 1)
......
......@@ -30,6 +30,7 @@
#include "datacontainerinspectorwidget.h"
#include "tgt/assert.h"
#include "tgt/logmanager.h"
#include "tgt/filesystem.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
......@@ -49,7 +50,7 @@
#include "core/datastructures/facegeometry.h"
#include "core/datastructures/geometrydata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#ifdef CAMPVIS_HAS_MODULE_COLUMBIA
#include "modules/columbia/datastructures/fiberdata.h"
......@@ -62,6 +63,8 @@
namespace campvis {
const std::string DataContainerInspectorWidget::loggerCat_ = "CAMPVis.application.DataContainerInspectorWidget";
DataContainerInspectorWidget::DataContainerInspectorWidget(QWidget* parent)
: QWidget(parent)
, _inited(false)
......@@ -308,21 +311,19 @@ namespace campvis {
// only consider non-empty DataHandles that are ImageData and have render target representations
if (handle.getData() != 0) {
if (const ImageData* tester = dynamic_cast<const ImageData*>(handle.getData())) {
if (const ImageRepresentationRenderTarget* repRT = tester->getRepresentation<ImageRepresentationRenderTarget>(false)) {
QString dialogCaption = "Export " + idxName.data(Qt::DisplayRole).toString() + " as Image";
QString directory = tr("");
const QString fileFilter = tr("*.png;;PNG images (*.png)");
QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter);
if (! filename.isEmpty()) {
// Texture access needs OpenGL context - dispatch method call:
GLJobProc.enqueueJob(
_canvas,
makeJobOnHeap(&DataContainerInspectorWidget::saveToFile, handle, filename.toStdString()),
OpenGLJobProcessor::SerialJob);
}
if (dynamic_cast<const ImageData*>(handle.getData()) || dynamic_cast<const RenderData*>(handle.getData())) {
QString dialogCaption = "Export " + idxName.data(Qt::DisplayRole).toString() + " as Image";
QString directory = tr("");
const QString fileFilter = tr("*.png;;PNG images (*.png)");
QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter);
if (! filename.isEmpty()) {
// Texture access needs OpenGL context - dispatch method call:
GLJobProc.enqueueJob(
_canvas,
makeJobOnHeap(&DataContainerInspectorWidget::saveToFile, handle, filename.toStdString()),
OpenGLJobProcessor::SerialJob);
}
}
}
......@@ -336,13 +337,35 @@ namespace campvis {
return;
}
// we did the test before, hence, static_cast ist safe
const ImageRepresentationRenderTarget* repRT = static_cast<const ImageData*>(handle.getData())->getRepresentation<ImageRepresentationRenderTarget>(false);
tgtAssert(repRT != 0, "DataHandle must be of type ImageData having an ImageRepresentationRenderTarget inside - otherwise you're not allowed to call this method!");
// get the ImageData object (either directly or from the RenderData)
const ImageData* id = 0;
if (const RenderData* tester = dynamic_cast<const RenderData*>(handle.getData())) {
id = tester->getColorTexture(0);
}
else if (const ImageData* tester = dynamic_cast<const ImageData*>(handle.getData())) {
id = tester;
}
else {
LERROR("Could not extract image to save.");
return;
}
// extract the data
WeaklyTypedPointer wtp(WeaklyTypedPointer::UINT8, 1, 0);
const ImageRepresentationGL* repGL = id->getRepresentation<ImageRepresentationGL>(false);
if (repGL != 0) // if it's a GL texture, download it (we do not want to use the automatic conversion method here)
wtp = repGL->getWeaklyTypedPointer();
else {
const ImageRepresentationLocal* repLocal = id->getRepresentation<ImageRepresentationLocal>(true);
if (repLocal != 0)
wtp = repLocal->getWeaklyTypedPointer();
}
if (wtp._pointer == 0) {
LERROR("Could not extract image to save.");
return;
}
// get color buffer content
GLubyte* colorBuffer = repRT->getColorTexture()->downloadTextureToBuffer(GL_RGBA, GL_UNSIGNED_SHORT);
tgt::ivec2 size = repRT->getSize().xy();
// create Devil image from image data and write it to file
ILuint img;
......@@ -350,14 +373,13 @@ namespace campvis {
ilBindImage(img);
// put pixels into IL-Image
ilTexImage(size.x, size.y, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, colorBuffer);
tgt::ivec2 size = id->getSize().xy();
ilTexImage(size.x, size.y, 1, static_cast<ILubyte>(wtp._numChannels), wtp.getIlFormat(), wtp.getIlDataType(), wtp._pointer);
ilEnable(IL_FILE_OVERWRITE);
ilResetWrite();
ILboolean success = ilSaveImage(filename.c_str());
ilDeleteImages(1, &img);
delete[] colorBuffer;
if (!success) {
LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Could not save image to file: " << ilGetError());
}
......
......@@ -138,7 +138,7 @@ namespace campvis {
/**
* Saves the Image in \a handle to the file \a filename.
* \note This method must be called with a valid OpenGL context!
* \param handle DataHandle containing the image to save. Must be of type ImageData having an ImageRepresentationRenderTarget inside!
* \param handle DataHandle containing the image to save. Must contain ImageData or RenderData!
* \param filename Filename for the file to save.
*/
static void saveToFile(DataHandle handle, std::string filename);
......@@ -169,6 +169,8 @@ namespace campvis {
QLabel* _lblSize;
QLabel* _lblBounds;
QPushButton* _btnSaveToFile;
static const std::string loggerCat_;
};
}
......
......@@ -40,7 +40,6 @@
#include "core/datastructures/meshgeometry.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/imagerepresentationlocal.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/imagerepresentationgl.h"
#include <QHeaderView>
......
......@@ -37,7 +37,6 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/imagerepresentationlocal.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#ifdef CAMPVIS_HAS_MODULE_ITK
#include "modules/itk/core/genericimagerepresentationitk.h"
#endif
......
......@@ -125,6 +125,7 @@ namespace campvis {
return convertToGenericLocal(tester, tester->getImageData());
}
else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) {
// FIXME: this here deadlocks, if called from OpenGL context (GLJobProc)!!!
tgt::GLCanvas* context = GLJobProc.iKnowWhatImDoingGetArbitraryContext();
ImageRepresentationLocal* toReturn = 0;
GLJobProc.pause();
......
This diff is collapsed.
......@@ -31,7 +31,6 @@
#include "tgt/tgt_gl.h"
#include "tgt/glcanvas.h"
#include "tgt/glcontext.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
......
......@@ -60,7 +60,7 @@ namespace campvis {
if (_applyMask.getValue()) {
shader->setUniform("_maskColor", _maskColor.getValue());
_maskImage = new ImageRepresentationRenderTarget::ScopedRepresentation(dataContainer, _maskID.getValue());
_maskImage = new DataContainer::ScopedTypedData<RenderData>(dataContainer, _maskID.getValue());
if (*_maskImage != 0) {
(*_maskImage)->bindColorTexture(shader, *_texUnit, "_maskImage", "_maskTexParams");
}
......
......@@ -32,7 +32,7 @@
#include "tgt/textureunit.h"
#include "core/datastructures/datacontainer.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/genericproperty.h"
......@@ -59,7 +59,7 @@ namespace campvis {
Vec4Property _maskColor; ///< Mask color
tgt::TextureUnit* _texUnit;
ImageRepresentationRenderTarget::ScopedRepresentation* _maskImage;
DataContainer::ScopedTypedData<RenderData>* _maskImage;
};
}
......
......@@ -31,8 +31,6 @@
#define PROCESSORDECORATORSHADING_H__
#include "tgt/textureunit.h"
#include "core/datastructures/datacontainer.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/pipeline/abstractprocessordecorator.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/genericproperty.h"
......
......@@ -35,8 +35,6 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/renderdata.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/classification/simpletransferfunction.h"
......
......@@ -31,7 +31,6 @@
#include "tgt/tgt_gl.h"
#include "tgt/glcanvas.h"
#include "tgt/glcontext.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
......
......@@ -46,8 +46,6 @@ namespace tgt {
}
namespace campvis {
class ImageRepresentationRenderTarget;
/**
* Abstract base class for CAMPVis Pipelines.
*
......
......@@ -31,7 +31,6 @@
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
namespace campvis {
......@@ -164,10 +163,4 @@ namespace campvis {
createAndAttachTexture(GL_DEPTH_COMPONENT24);
}
ImageData* VisualizationProcessor::createImageDataFromFbo() const {
ImageData* toReturn = new ImageData(2, getRenderTargetSize(), 4);
ImageRepresentationRenderTarget::create(toReturn, _fbo);
return toReturn;
}
}
......@@ -128,12 +128,6 @@ namespace campvis {
void createAndAttachDepthTexture();
// protected:
/**
* Creates an ImageData object from the textures currently attached to the FBO.
* \note The caller takes ownership of the returned pointer.
* \return A pointer to the created ImageData object.
*/
ImageData* createImageDataFromFbo() const;
tgt::ivec3 getRenderTargetSize() const;
......
......@@ -274,4 +274,44 @@ namespace campvis {
}
#endif
#ifdef CAMPVIS_HAS_MODULE_DEVIL
ILenum WeaklyTypedPointer::getIlFormat() const {
switch (_numChannels) {
case 1:
return IL_ALPHA;
case 2:
return IL_LUMINANCE_ALPHA;
case 3:
return IL_RGB;
case 4:
return IL_RGBA;
default:
tgtAssert(false, "Should not reach this, wrong number of channels!");
return IL_ALPHA;
}
}
ILenum WeaklyTypedPointer::getIlDataType() const {
switch (_baseType) {
case WeaklyTypedPointer::UINT8:
return IL_UNSIGNED_BYTE;
case WeaklyTypedPointer::INT8:
return IL_BYTE;
case WeaklyTypedPointer::UINT16:
return IL_UNSIGNED_SHORT;
case WeaklyTypedPointer::INT16:
return IL_SHORT;
case WeaklyTypedPointer::UINT32:
return IL_UNSIGNED_INT;
case WeaklyTypedPointer::INT32:
return IL_INT;
case WeaklyTypedPointer::FLOAT:
return IL_FLOAT;
default:
tgtAssert(false, "Should not reach this - wrong base data type!");
return GL_BYTE;
}
}
#endif
}
......@@ -40,6 +40,11 @@
#include "kisscl/kisscl.h"
#endif
#ifdef CAMPVIS_HAS_MODULE_DEVIL
#include <IL/il.h>
#include <IL/ilu.h>
#endif
namespace campvis {
/**
......@@ -124,6 +129,12 @@ namespace campvis {
bool isSigned() const;
#ifdef CAMPVIS_HAS_MODULE_DEVIL
ILenum getIlFormat() const;
ILenum getIlDataType() const;
#endif
#ifdef HAS_KISSCL
cl_channel_type getClChannelType() const;
......
......@@ -34,7 +34,8 @@
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/renderdata.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/simplejobprocessor.h"
#include "core/tools/job.h"
......@@ -176,8 +177,9 @@ namespace campvis {
void CmBatchGeneration::save(int path, const std::string& basePath) {
// get result
ImageRepresentationRenderTarget::ScopedRepresentation repRT(_data, _usFusion.p_targetImageID.getValue());
if (repRT != 0) {
DataContainer::ScopedTypedData<RenderData> rd(_data, _usFusion.p_targetImageID.getValue());
const ImageRepresentationGL* rep = rd->getColorTexture()->getRepresentation<ImageRepresentationGL>(false);
if (rep != 0) {
#ifdef CAMPVIS_HAS_MODULE_DEVIL
if (! tgt::FileSystem::dirExists(basePath))
tgt::FileSystem::createDirectory(basePath);
......@@ -191,8 +193,8 @@ namespace campvis {
}
// get color buffer content
GLubyte* colorBuffer = repRT->getColorTexture()->downloadTextureToBuffer(GL_RGBA, GL_UNSIGNED_SHORT);
tgt::ivec2 size = repRT->getSize().xy();
GLubyte* colorBuffer = rep->getTexture()->downloadTextureToBuffer(GL_RGBA, GL_UNSIGNED_SHORT);
tgt::ivec2 size = rep->getSize().xy();
// create Devil image from image data and write it to file
ILuint img;
......
......@@ -34,7 +34,7 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorbackground.h"
#include "core/classification/simpletransferfunction.h"
......@@ -129,7 +129,7 @@ namespace campvis {
//_shader->rebuild();
}
std::pair<ImageData*, ImageRepresentationRenderTarget*> rt = ImageRepresentationRenderTarget::createWithImageData(_renderTargetSize.getValue());
FramebufferActivationGuard fag(this);
_shader->activate();
decorateRenderProlog(data, _shader);
......@@ -147,16 +147,14 @@ namespace campvis {
p_transferFunction.getTF()->bind(_shader, tfUnit);
p_confidenceTF.getTF()->bind(_shader, tf2Unit, "_confidenceTF", "_confidenceTFParams");
rt.second->activate();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
rt.second->deactivate();
decorateRenderEpilog(_shader);
_shader->deactivate();
tgt::TextureUnit::setZeroUnit();
data.addData(p_targetImageID.getValue(), rt.first);
data.addData(p_targetImageID.getValue(), new RenderData(_fbo));
p_targetImageID.issueWrite();
}
else {
......
......@@ -36,7 +36,7 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/datastructures/meshgeometry.h"
#include "core/pipeline/processordecoratorshading.h"
......@@ -92,6 +92,7 @@ namespace campvis {
}
// set modelview and projection matrices
FramebufferActivationGuard fag(this);
_shader->activate();
decorateRenderProlog(data, _shader);
_shader->setUniform("_projectionMatrix", p_camera.getValue().getProjectionMatrix());
......@@ -101,23 +102,18 @@ namespace campvis {
tgt::TextureUnit strainUnit;
strainData->bind(_shader, strainUnit, "_strainTexture");
// create entry points texture
std::pair<ImageData*, ImageRepresentationRenderTarget*> rt = ImageRepresentationRenderTarget::createWithImageData(_renderTargetSize.getValue(), GL_RGBA16);
rt.second->activate();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
proxyGeometry->render();
rt.second->deactivate();
decorateRenderEpilog(_shader);
_shader->deactivate();
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
data.addData(p_renderTargetID.getValue(), rt.first);
data.addData(p_renderTargetID.getValue(), new RenderData(_fbo));
p_renderTargetID.issueWrite();
}
else {
......
......@@ -36,9 +36,7 @@
#include "modules/columbia/datastructures/fiberdata.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/datastructures/meshgeometry.h"
#include "core/pipeline/processordecoratorshading.h"
......@@ -105,6 +103,7 @@ namespace campvis {
const tgt::Camera& camera = p_camera.getValue();
// set modelview and projection matrices
FramebufferActivationGuard fag(this);
_shader->activate();
_shader->setIgnoreUniformLocationError(true);
decorateRenderProlog(data, _shader);
......@@ -115,9 +114,6 @@ namespace campvis {
_shader->setIgnoreUniformLocationError(false);
// create entry points texture
std::pair<ImageData*, ImageRepresentationRenderTarget*> rt = ImageRepresentationRenderTarget::createWithImageData(_renderTargetSize.getValue(), GL_RGBA16);
rt.second->activate();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearDepth(1.0f);
......@@ -127,13 +123,12 @@ namespace campvis {
strainData->render();
glLineWidth(1.f);
rt.second->deactivate();
decorateRenderEpilog(_shader);
_shader->deactivate();
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
data.addData(p_renderTargetID.getValue(), rt.first);
data.addData(p_renderTargetID.getValue(), new RenderData(_fbo));
p_renderTargetID.issueWrite();
}
else {
......
......@@ -30,7 +30,7 @@
#include "strainraycaster.h"
#include "core/tools/quadrenderer.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorshading.h"
namespace campvis {
......@@ -58,15 +58,13 @@ namespace campvis {
void StrainRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
if (image.getImageData()->getNumChannels() == 3 || image.getImageData()->getNumChannels() == 4) {
std::pair<ImageData*, ImageRepresentationRenderTarget*> output = ImageRepresentationRenderTarget::createWithImageData(_renderTargetSize.getValue());
output.second->activate();
FramebufferActivationGuard fag(this);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
LGL_ERROR;
output.second->deactivate();
data.addData(p_targetImageID.getValue(), output.first);
data.addData(p_targetImageID.getValue(), new RenderData(_fbo));
p_targetImageID.issueWrite();
}
else {
......
......@@ -6,8 +6,8 @@ LIST(APPEND ThisModDefinitions -DTGT_HAS_DEVIL)
IF(UNIX)
# Unix-like systems have their DevIL lib via their package manager
FIND_PACKAGE(DevIL REQUIRED)
SET(ThisModIncludeDirs ${IL_INCLUDE_DIR})
SET(ThisModExternalLibs ${IL_LIBRARIES} ${ILU_LIBRARIES})
LIST(APPEND CampvisGlobalIncludeDirs ${IL_INCLUDE_DIR})
LIST(APPEND CampvisGlobalExternalLibs ${IL_LIBRARIES} ${ILU_LIBRARIES})
IF(IL_FOUND)