The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 36ab435a authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Streamlined AbstractProcessor API:

INVALID_RESULT, INVALID_PROPERTIES, INVALID_SHADER is validated automatically by AbstractProcessor::process(). Hence, there is finally no need anymore to validate these three different levels in each processor.
parent 35f624c6
......@@ -132,26 +132,31 @@ namespace campvis {
void AbstractProcessor::process(DataContainer& data, bool unlockInExtraThread) {
if (hasInvalidShader()) {
updateShader();
validate(INVALID_SHADER);
}
if (hasInvalidProperties()) {
updateProperties(data);
validate(INVALID_PROPERTIES);
}
// use a scoped lock for exception safety
AbstractProcessor::ScopedLock lock(this, unlockInExtraThread);
tgtAssert(_locked == true, "Processor not locked, this should not happen!");
if (hasInvalidShader())
updateShader();
if (hasInvalidProperties())
updateProperties(data);
if (hasInvalidResult())
if (hasInvalidResult()) {
updateResult(data);
validate(INVALID_RESULT);
}
}
void AbstractProcessor::updateShader() {
LDEBUG("Called non-overriden updateShader() in " << getName() << ". Did you forget to override your method?");
validate(INVALID_SHADER);
}
void AbstractProcessor::updateProperties(DataContainer& dc) {
LDEBUG("Called non-overriden updateProperties() in " << getName() << ". Did you forget to override your method?");
validate(INVALID_PROPERTIES);
}
void AbstractProcessor::addProperty(AbstractProperty& prop) {
......
......@@ -171,8 +171,6 @@ namespace campvis {
else {
LERROR("No suitable input image found.");
}
validate(INVALID_RESULT);
}
std::string RaycastingProcessor::generateHeader() const {
......@@ -183,15 +181,11 @@ namespace campvis {
void RaycastingProcessor::updateProperties(DataContainer& dc) {
ScopedTypedData<ImageData> img(dc, p_sourceImageID.getValue());
p_transferFunction.setImageHandle(img.getDataHandle());
validate(AbstractProcessor::INVALID_PROPERTIES);
}
void RaycastingProcessor::updateShader() {
_shader->setHeaders(generateHeader());
_shader->rebuild();
validate(AbstractProcessor::INVALID_SHADER);
}
}
......@@ -151,8 +151,6 @@ namespace campvis {
else {
LERROR("No suitable input image found.");
}
validate(INVALID_RESULT);
}
void AdvancedUsFusion::updateProperties(DataContainer dc) {
......@@ -164,8 +162,6 @@ namespace campvis {
p_sliceNumber.setMaxValue(static_cast<int>(imgSize.z) - 1);
}
p_use3DTexture.setValue(img->getDimensionality() == 3);
validate(AbstractProcessor::INVALID_PROPERTIES);
}
std::string AdvancedUsFusion::generateHeader() const {
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "pointpredicateevaluator.h"
#include "tgt/logmanager.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorbackground.h"
#include "core/classification/simpletransferfunction.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/tools/quadrenderer.h"
namespace campvis {
const std::string PointPredicateEvaluator::loggerCat_ = "CAMPVis.modules.vis.PointPredicateEvaluator";
PointPredicateEvaluator::PointPredicateEvaluator(IVec2Property* viewportSizeProp)
: VisualizationProcessor(viewportSizeProp)
, p_inputImage("InputImage", "Input Image", "", DataNameProperty::READ)
, p_inputLabels("InputLabels", "Input Label Image", "", DataNameProperty::READ)
, p_inputSnr("InputSnr", "Input SNR", "", DataNameProperty::READ)
, p_inputVesselness("InputVesselness", "Input Vesselness", "", DataNameProperty::READ)
, p_inputConfidence("InputConfidence", "Input Confidence", "", DataNameProperty::READ)
, p_outputImage("OutputImage", "Output Image", "predicatemask", DataNameProperty::WRITE)
, p_camera("Camera", "Camera", tgt::Camera())
, p_histogram("PredicateHistogram", "Point Predicate Histogram")
, _shader(0)
{
addProperty(p_inputImage, INVALID_PROPERTIES | INVALID_RESULT);
addProperty(p_inputLabels, INVALID_PROPERTIES | INVALID_RESULT);
addProperty(p_inputSnr);
addProperty(p_inputVesselness);
addProperty(p_inputConfidence);
addProperty(p_outputImage);
addProperty(p_camera);
addProperty(p_histogram);
}
PointPredicateEvaluator::~PointPredicateEvaluator() {
}
void PointPredicateEvaluator::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.loadWithCustomGlslVersion("core/glsl/passthrough.vert", "", "modules/advancedusvis/glsl/pointpredicateevaluator.frag", generateHeader(), "400");
_shader->setAttributeLocation(0, "in_Position");
_shader->setAttributeLocation(1, "in_TexCoord");
p_histogram.s_headerChanged.connect(this, &PointPredicateEvaluator::onHistogramHeaderChanged);
}
void PointPredicateEvaluator::deinit() {
p_histogram.s_headerChanged.disconnect(this);
ShdrMgr.dispose(_shader);
VisualizationProcessor::deinit();
}
void PointPredicateEvaluator::updateResult(DataContainer& dataContainer) {
ImageRepresentationGL::ScopedRepresentation img(dataContainer, p_inputImage.getValue());
ImageRepresentationGL::ScopedRepresentation labels(dataContainer, p_inputLabels.getValue());
ImageRepresentationGL::ScopedRepresentation snr(dataContainer, p_inputSnr.getValue());
ImageRepresentationGL::ScopedRepresentation vesselness(dataContainer, p_inputVesselness.getValue());
ImageRepresentationGL::ScopedRepresentation confidence(dataContainer, p_inputConfidence.getValue());
if (img && labels && snr && vesselness && confidence) {
const tgt::svec3& size = img->getSize();
tgt::ivec2 viewportSize = size.xy();
tgt::TextureUnit inputUnit, labelUnit, snrUnit, vesselnessUnit, confidenceUnit;
inputUnit.activate();
const tgt::Texture* tex = img->getTexture();
if (tex->getFilter() != tgt::Texture::MIPMAP) {
const_cast<tgt::Texture*>(tex)->setFilter(tgt::Texture::MIPMAP);
LGL_ERROR;
glGenerateMipmap(GL_TEXTURE_3D);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
LGL_ERROR;
}
// create texture for result
tgt::Texture* resultTexture = new tgt::Texture(0, tgt::ivec3(size), GL_RED_INTEGER, GL_R8UI, GL_UNSIGNED_BYTE, tgt::Texture::NEAREST);
resultTexture->uploadTexture();
resultTexture->setWrapping(tgt::Texture::CLAMP);
// activate shader and bind textures
_shader->activate();
_shader->setIgnoreUniformLocationError(true);
p_histogram.getPredicateHistogram()->setupRenderShader(_shader);
_shader->setIgnoreUniformLocationError(false);
img->bind(_shader, inputUnit);
labels->bind(_shader, labelUnit, "_labels", "_labelsParams");
snr->bind(_shader, snrUnit, "_snr", "_snrParams");
vesselness->bind(_shader, vesselnessUnit, "_vesselness", "_vesselnessParams");
confidence->bind(_shader, confidenceUnit, "_confidence", "_confidenceParams");
// activate FBO and attach texture
_fbo->activate();
glViewport(0, 0, static_cast<GLsizei>(viewportSize.x), static_cast<GLsizei>(viewportSize.y));
// render quad to compute difference measure by shader
for (int z = 0; z < static_cast<int>(size.z); ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
_shader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTexture, GL_COLOR_ATTACHMENT0, 0, z);
QuadRdr.renderQuad();
}
_fbo->detachAll();
_fbo->deactivate();
_shader->deactivate();
// put resulting image into DataContainer
ImageData* id = new ImageData(3, size, 1);
ImageRepresentationGL::create(id, resultTexture);
id->setMappingInformation(img->getParent()->getMappingInformation());
dataContainer.addData(p_outputImage.getValue(), id);
tgt::TextureUnit::setZeroUnit();
LGL_ERROR;
}
else {
LERROR("No suitable input image found.");
}
validate(INVALID_RESULT);
}
void PointPredicateEvaluator::updateProperties(DataContainer dataContainer) {
validate(AbstractProcessor::INVALID_PROPERTIES);
}
std::string PointPredicateEvaluator::generateHeader() const {
std::string toReturn = p_histogram.getPredicateHistogram()->getGlslHeader();
return toReturn;
}
void PointPredicateEvaluator::onHistogramHeaderChanged() {
invalidate(INVALID_SHADER);
}
void PointPredicateEvaluator::updateShader() {
_shader->setHeaders(generateHeader());
_shader->rebuild();
validate(INVALID_SHADER);
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "pointpredicateevaluator.h"
#include "tgt/logmanager.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorbackground.h"
#include "core/classification/simpletransferfunction.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "core/classification/tfgeometry1d.h"
#include "core/tools/quadrenderer.h"
namespace campvis {
const std::string PointPredicateEvaluator::loggerCat_ = "CAMPVis.modules.vis.PointPredicateEvaluator";
PointPredicateEvaluator::PointPredicateEvaluator(IVec2Property* viewportSizeProp)
: VisualizationProcessor(viewportSizeProp)
, p_inputImage("InputImage", "Input Image", "", DataNameProperty::READ)
, p_inputLabels("InputLabels", "Input Label Image", "", DataNameProperty::READ)
, p_inputSnr("InputSnr", "Input SNR", "", DataNameProperty::READ)
, p_inputVesselness("InputVesselness", "Input Vesselness", "", DataNameProperty::READ)
, p_inputConfidence("InputConfidence", "Input Confidence", "", DataNameProperty::READ)
, p_outputImage("OutputImage", "Output Image", "predicatemask", DataNameProperty::WRITE)
, p_camera("Camera", "Camera", tgt::Camera())
, p_histogram("PredicateHistogram", "Point Predicate Histogram")
, _shader(0)
{
addProperty(p_inputImage, INVALID_PROPERTIES | INVALID_RESULT);
addProperty(p_inputLabels, INVALID_PROPERTIES | INVALID_RESULT);
addProperty(p_inputSnr);
addProperty(p_inputVesselness);
addProperty(p_inputConfidence);
addProperty(p_outputImage);
addProperty(p_camera);
addProperty(p_histogram);
}
PointPredicateEvaluator::~PointPredicateEvaluator() {
}
void PointPredicateEvaluator::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.loadWithCustomGlslVersion("core/glsl/passthrough.vert", "", "modules/advancedusvis/glsl/pointpredicateevaluator.frag", generateHeader(), "400");
_shader->setAttributeLocation(0, "in_Position");
_shader->setAttributeLocation(1, "in_TexCoord");
p_histogram.s_headerChanged.connect(this, &PointPredicateEvaluator::onHistogramHeaderChanged);
}
void PointPredicateEvaluator::deinit() {
p_histogram.s_headerChanged.disconnect(this);
ShdrMgr.dispose(_shader);
VisualizationProcessor::deinit();
}
void PointPredicateEvaluator::updateResult(DataContainer& dataContainer) {
ImageRepresentationGL::ScopedRepresentation img(dataContainer, p_inputImage.getValue());
ImageRepresentationGL::ScopedRepresentation labels(dataContainer, p_inputLabels.getValue());
ImageRepresentationGL::ScopedRepresentation snr(dataContainer, p_inputSnr.getValue());
ImageRepresentationGL::ScopedRepresentation vesselness(dataContainer, p_inputVesselness.getValue());
ImageRepresentationGL::ScopedRepresentation confidence(dataContainer, p_inputConfidence.getValue());
if (img && labels && snr && vesselness && confidence) {
const tgt::svec3& size = img->getSize();
tgt::ivec2 viewportSize = size.xy();
tgt::TextureUnit inputUnit, labelUnit, snrUnit, vesselnessUnit, confidenceUnit;
inputUnit.activate();
const tgt::Texture* tex = img->getTexture();
if (tex->getFilter() != tgt::Texture::MIPMAP) {
const_cast<tgt::Texture*>(tex)->setFilter(tgt::Texture::MIPMAP);
LGL_ERROR;
glGenerateMipmap(GL_TEXTURE_3D);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
LGL_ERROR;
}
// create texture for result
tgt::Texture* resultTexture = new tgt::Texture(0, tgt::ivec3(size), GL_RED_INTEGER, GL_R8UI, GL_UNSIGNED_BYTE, tgt::Texture::NEAREST);
resultTexture->uploadTexture();
resultTexture->setWrapping(tgt::Texture::CLAMP);
// activate shader and bind textures
_shader->activate();
_shader->setIgnoreUniformLocationError(true);
p_histogram.getPredicateHistogram()->setupRenderShader(_shader);
_shader->setIgnoreUniformLocationError(false);
img->bind(_shader, inputUnit);
labels->bind(_shader, labelUnit, "_labels", "_labelsParams");
snr->bind(_shader, snrUnit, "_snr", "_snrParams");
vesselness->bind(_shader, vesselnessUnit, "_vesselness", "_vesselnessParams");
confidence->bind(_shader, confidenceUnit, "_confidence", "_confidenceParams");
// activate FBO and attach texture
_fbo->activate();
glViewport(0, 0, static_cast<GLsizei>(viewportSize.x), static_cast<GLsizei>(viewportSize.y));
// render quad to compute difference measure by shader
for (int z = 0; z < static_cast<int>(size.z); ++z) {
float zTexCoord = static_cast<float>(z)/static_cast<float>(size.z) + .5f/static_cast<float>(size.z);
_shader->setUniform("_zTexCoord", zTexCoord);
_fbo->attachTexture(resultTexture, GL_COLOR_ATTACHMENT0, 0, z);
QuadRdr.renderQuad();
}
_fbo->detachAll();
_fbo->deactivate();
_shader->deactivate();
// put resulting image into DataContainer
ImageData* id = new ImageData(3, size, 1);
ImageRepresentationGL::create(id, resultTexture);
id->setMappingInformation(img->getParent()->getMappingInformation());
dataContainer.addData(p_outputImage.getValue(), id);
tgt::TextureUnit::setZeroUnit();
LGL_ERROR;
}
else {
LERROR("No suitable input image found.");
}
}
void PointPredicateEvaluator::updateProperties(DataContainer dataContainer) {
}
std::string PointPredicateEvaluator::generateHeader() const {
std::string toReturn = p_histogram.getPredicateHistogram()->getGlslHeader();
return toReturn;
}
void PointPredicateEvaluator::onHistogramHeaderChanged() {
invalidate(INVALID_SHADER);
}
void PointPredicateEvaluator::updateShader() {
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "pointpredicateraycaster.h"
#include "tgt/textureunit.h"
#include "core/tools/quadrenderer.h"
#include "core/datastructures/lightsourcedata.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/processordecoratorgradient.h"
namespace campvis {
const std::string PointPredicateRaycaster::loggerCat_ = "CAMPVis.modules.vis.PointPredicateRaycaster";
PointPredicateRaycaster::PointPredicateRaycaster(IVec2Property* viewportSizeProp)
: RaycastingProcessor(viewportSizeProp, "modules/advancedusvis/glsl/pointpredicateraycaster.frag", true, "400")
, p_inputLabels("InputLabels", "Input Label Image", "", DataNameProperty::READ)
, p_inputSnr("InputSnr", "Input SNR", "", DataNameProperty::READ)
, p_inputVesselness("InputVesselness", "Input Vesselness", "", DataNameProperty::READ)
, p_inputConfidence("InputConfidence", "Input Confidence", "", DataNameProperty::READ)
, p_enableShading("EnableShading", "Enable Shading", true)
, p_lightId("LightId", "Input Light Source", "lightsource", DataNameProperty::READ)
, p_predicateHistogram("PredicateSelection", "Voxel Predicate Selection")
{
addDecorator(new ProcessorDecoratorGradient());
addProperty(p_inputLabels, INVALID_RESULT | INVALID_PROPERTIES);
addProperty(p_inputSnr);
addProperty(p_inputVesselness);
addProperty(p_inputConfidence);
addProperty(p_enableShading, INVALID_RESULT | INVALID_PROPERTIES | INVALID_SHADER);
addProperty(p_lightId);
addProperty(p_predicateHistogram);
decoratePropertyCollection(this);
}
PointPredicateRaycaster::~PointPredicateRaycaster() {
}
void PointPredicateRaycaster::init() {
p_predicateHistogram.s_headerChanged.connect(this, &PointPredicateRaycaster::onHistogramHeaderChanged);
RaycastingProcessor::init();
}
void PointPredicateRaycaster::deinit() {
p_predicateHistogram.s_headerChanged.disconnect(this);
RaycastingProcessor::deinit();
}
void PointPredicateRaycaster::processImpl(DataContainer& dataContainer, ImageRepresentationGL::ScopedRepresentation& image) {
ImageRepresentationGL::ScopedRepresentation labels(dataContainer, p_inputLabels.getValue());
ImageRepresentationGL::ScopedRepresentation snr(dataContainer, p_inputSnr.getValue());
ImageRepresentationGL::ScopedRepresentation vesselness(dataContainer, p_inputVesselness.getValue());
ImageRepresentationGL::ScopedRepresentation confidence(dataContainer, p_inputConfidence.getValue());
if (labels && snr && vesselness && confidence) {
ScopedTypedData<LightSourceData> light(dataContainer, p_lightId.getValue());
if (p_enableShading.getValue() == false || light != nullptr) {
const tgt::Texture* lt = labels->getTexture();
if (lt->getFilter() != tgt::Texture::NEAREST) {
const_cast<tgt::Texture*>(lt)->setFilter(tgt::Texture::NEAREST);
}
const tgt::Texture* tex = image->getTexture();
if (tex->getFilter() != tgt::Texture::MIPMAP) {
const_cast<tgt::Texture*>(tex)->setFilter(tgt::Texture::MIPMAP);
LGL_ERROR;
glGenerateMipmap(GL_TEXTURE_3D);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
LGL_ERROR;
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
LGL_ERROR;
}
tgt::TextureUnit labelUnit, snrUnit, vesselnessUnit, confidenceUnit;
labels->bind(_shader, labelUnit, "_labels", "_labelsParams");
snr->bind(_shader, snrUnit, "_snr", "_snrParams");
vesselness->bind(_shader, vesselnessUnit, "_vesselness", "_vesselnessParams");
confidence->bind(_shader, confidenceUnit, "_confidence", "_confidenceParams");
if (p_enableShading.getValue() && light != nullptr) {
light->bind(_shader, "_lightSource");
}
_shader->setIgnoreUniformLocationError(true);
p_predicateHistogram.getPredicateHistogram()->setupRenderShader(_shader);
_shader->setIgnoreUniformLocationError(false);
LGL_ERROR;
FramebufferActivationGuard fag(this);
createAndAttachTexture(GL_RGBA8);
createAndAttachTexture(GL_RGBA32F);
createAndAttachTexture(GL_RGBA32F);
createAndAttachDepthTexture();
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, buffers);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QuadRdr.renderQuad();
// restore state
glDrawBuffers(1, buffers);
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
dataContainer.addData(p_targetImageID.getValue(), new RenderData(_fbo));
}
else {
LDEBUG("Could not load light source from DataContainer.");
}