...
 
Commits (4)
......@@ -128,6 +128,8 @@ TARGET_LINK_LIBRARIES(campvis-application-lib ${CampvisMainLibs} ${CampvisGlobal
# the code to export DLL symbols
SET_TARGET_PROPERTIES(campvis-application-lib PROPERTIES DEFINE_SYMBOL "CAMPVIS_APPLICATION_BUILD_DLL")
target_compile_definitions(campvis-application-lib PUBLIC ${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${CampvisApplicationDefinitions})
target_include_directories(campvis-application-lib PUBLIC ${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs})
IF(CAMPVIS_GROUP_SOURCE_FILES)
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationSources ${CampvisHome} "")
......
# modules/cppcourse/cppcourse.cmake
# CMake file for the Module for the Cpp Course in WS 17
# Set module status (valid values are STABLE, TESTING and EXPERIMENTAL)
SET(ThisModStatus EXPERIMENTAL)
# Set whether this module has external dependencies that are not shipped with CAMPVis.
SET(ThisModExternalDependencies TRUE)
# The files and assignments need only to be parsed if the module is enabled
IF(ModuleEnabled)
# Source files:
FILE(GLOB ThisModSources RELATIVE ${ModulesDir}
modules/cppcourse/pipelines/*.cpp
modules/cppcourse/processors/*.cpp
modules/cppcourse/datastructures/*.cpp
modules/cppcourse/properties/*.cpp
modules/cppcourse/*.cpp
)
# Header files (including GLSL files so that they'll appear in VS projects)
FILE(GLOB ThisModHeaders RELATIVE ${ModulesDir}
modules/cppcourse/glsl/*.frag
modules/cppcourse/glsl/*.geom
modules/cppcourse/glsl/*.vert
modules/cppcourse/pipelines/*.h
modules/cppcourse/processors/*.h
modules/cppcourse/datastructures/*.h
modules/cppcourse/properties/*.h
)
# Define the GLSL shader path, so that all needed shaders will be deployed to target directory
SET(ThisModShaderDirectories "modules/cppcourse/glsl")
# Define dependency modules (the pipelines in the vis modules use processors from io)
#SET(ThisModDependencies io)
ENDIF(ModuleEnabled)
#include "core/pipeline/pipelinefactory.h"
#include "core/pipeline/processorfactory.h"
#include "modules/cppcourse/pipelines/cppcoursepipeline.h"
#include "modules/cppcourse/processors/verysimpleraycaster.h"
namespace campvis {
// explicitly instantiate templates to register the pipelines to make them available in the prototyping GUI
//template class PipelineRegistrar<CPPCoursePipeline>;
template class SmartProcessorRegistrar<VerySimpleRaycaster>;
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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.
//
// ================================================================================================
layout(location = 0) out vec4 FragData0; ///< outgoing fragment color
#include "tools/gradient.frag"
#include "tools/raycasting.frag"
#include "tools/shading.frag"
#include "tools/texture2d.frag"
#include "tools/texture3d.frag"
#include "tools/transferfunction.frag"
uniform vec2 _viewportSizeRCP;
uniform float _jitterStepSizeMultiplier;
// ray entry points
uniform sampler2D _entryPoints;
uniform sampler2D _entryPointsDepth;
uniform TextureParameters2D _entryParams;
// ray exit points
uniform sampler2D _exitPoints;
uniform sampler2D _exitPointsDepth;
uniform TextureParameters2D _exitParams;
// DVR volume
uniform sampler3D _volume;
uniform TextureParameters3D _volumeTextureParams;
// Transfer function
uniform sampler1D _transferFunction;
uniform TFParameters1D _transferFunctionParams;
uniform LightSource _lightSource;
uniform vec3 _cameraPosition;
uniform float _samplingStepSize;
const float SAMPLING_BASE_INTERVAL_RCP = 200.0;
// The compositing mode that gets passed through from the p_compositingMode property
uniform int _compositingMode;
/**
* Performs the raycasting and returns the final fragment color.
*/
vec4 performRaycasting(in vec3 entryPoint, in vec3 exitPoint, in vec2 texCoords) {
vec4 result = vec4(0.0);
float firstHitT = -1.0;
// calculate ray start and endpoint
vec3 direction = exitPoint.rgb - entryPoint.rgb;
float t = 0.0;
float tend = length(direction);
direction = normalize(direction);
// This applies a small random offset to avoid banding artifacts
// Uncomment to see the effect ;)
jitterEntryPoint(entryPoint, direction, _samplingStepSize * _jitterStepSizeMultiplier);
while (t < tend) {
// compute sample position - next step
vec3 samplePosition = entryPoint.rgb + t * direction;
// get the intensity of our sample from the volume
float intensity = texture(_volume, samplePosition).r;
// use the transfer function to transform from
vec4 color = lookupTF(_transferFunction, _transferFunctionParams, intensity);
if (_compositingMode == 0) {
// accomodate for variable sampling rates
color.a = 1.0 - pow(1.0 - color.a, _samplingStepSize * SAMPLING_BASE_INTERVAL_RCP);
// perform compositing
// Alpha-blend the new sample with the color accumulated so far
blendUnder(result, color);
}
else if (_compositingMode == 1) {
//TODO
result = vec4(entryPoint, 1.0);
}
// else if...
// save first hit ray parameter for depth value calculation
if (firstHitT < 0.0 && result.a > 0.0) {
firstHitT = t;
}
// advance to the next evaluation point along the ray
t += _samplingStepSize;
}
// calculate depth value from ray parameter
gl_FragDepth = 1.0;
if (firstHitT >= 0.0) {
float depthEntry = texture(_entryPointsDepth, texCoords).z;
float depthExit = texture(_exitPointsDepth, texCoords).z;
gl_FragDepth = calculateDepthValue(firstHitT/tend, depthEntry, depthExit);
}
return result;
}
/***
* The main method.
***/
void main() {
vec2 p = gl_FragCoord.xy * _viewportSizeRCP;
vec3 frontPos = texture(_entryPoints, p).rgb;
vec3 backPos = texture(_exitPoints, p).rgb;
//determine whether the ray has to be casted
if (frontPos == backPos) {
//background needs no raycasting
discard;
} else {
//fragCoords are lying inside the boundingbox
FragData0 = performRaycasting(frontPos, backPos, p);
}
}
#include "cppcoursepipeline.h"
// TODO
#include "EDFhandler.h"
#include <fstream>
#include <map>
#include <exception>
#include "IOutilities.h"
Volume EDFHandler::read(const std::string& filename)
{
// open the file
std::ifstream file(filename, std::ios::binary);
if (!file.good())
throw std::invalid_argument("EDFHandler::read: error opening " + filename + " for reading");
// read a single character and make sure that a header is opened
if (file.eof() || file.get() != '{')
throw std::invalid_argument("EDFHandler::read: failed reading header opening marker");
std::map<std::string, std::string> attributes;
// --- read header data
while (!file.eof()) {
// skip whitespace
while (!file.eof()) {
const int chr = file.peek();
if (chr != '\r' && chr != '\n' && chr != ' ' && chr != '\t')
break;
file.ignore(1);
}
// abort if the header is closed
if (file.eof() || file.peek() == '}')
break;
// extract the attribute assignment
bool quotesSingle = false, quotesDouble = false;
std::string assignment = "";
while (!file.eof()) {
const int chr = file.get();
// abort on end-of-assignment
if (chr == ';' && !(quotesSingle || quotesDouble))
break;
// check for quote characters
if (chr == '\'') quotesSingle = !quotesSingle;
if (chr == '\"') quotesDouble = !quotesDouble;
assignment += chr;
}
// split the assignment, and remove quotes (if they exist)
auto delim = assignment.find('=');
if (delim == std::string::npos)
throw std::invalid_argument("EDFHandler::read: failed reading name/value delimiter");
std::string name = assignment.substr(0, delim);
StringUtils::trim(name);
std::string value = assignment.substr(delim+1);
StringUtils::trim(value);
if (value[0] == value[value.size()-1] && (value[0] == '\'' || value[0] == '\"'))
value = value.substr(1, value.size() - 2);
StringUtils::tolower(name);
attributes[name] = value;
}
file.ignore(2); // end of header marker
// --- now parse the header data
// read the dimensions
std::vector<int> dim;
for (int i = 1; ; ++i) {
// assemble the attribute name
std::stringstream aux;
aux << "dim_" << i;
// try to find the attribute
auto dimIt = attributes.find(aux.str());
if (dimIt == attributes.end())
break;
dim.push_back(StringUtils::parseString<int>(dimIt->second));
}
const int nDims = dim.size();
if (!nDims)
throw std::runtime_error("EDFHandler::read: dimension information not found");
// parse the (non-standard) spacing tag
std::vector<float> spacing;
auto spacingIt = attributes.find("spacing");
if (spacingIt != attributes.end())
StringUtils::parseString<float>(spacingIt->second, spacing);
// check for a byte order tag, but fall back to the default value
ByteOrder::ByteOrderEnum byteorder = ByteOrder::DEFAULT;
auto byteorderIt = attributes.find("byteorder");
if (byteorderIt != attributes.end()) {
std::string byteorderValue = byteorderIt->second;
StringUtils::tolower(byteorderValue);
if (byteorderValue == "highbytefirst")
byteorder = ByteOrder::HIGH_BYTE_FIRST;
else if (byteorderValue == "lowbytefirst")
byteorder = ByteOrder::LOW_BYTE_FIRST;
else
throw std::runtime_error("invalid byte order value");
}
// check for the 'element type' value
DataTypes::DataTypeEnum datatype;
auto datatypeIt = attributes.find("datatype");
if (datatypeIt != attributes.end()) {
std::string datatypeValue = datatypeIt->second;
StringUtils::tolower(datatypeValue);
if (datatypeValue == "signedbyte")
datatype = DataTypes::INT8;
else if (datatypeValue == "unsignedbyte")
datatype = DataTypes::UINT8;
else if (datatypeValue == "signedshort")
datatype = DataTypes::INT16;
else if (datatypeValue == "unsignedshort")
datatype = DataTypes::UINT16;
else if (datatypeValue == "float" || datatypeValue == "floatvalue" || datatypeValue == "real")
datatype = DataTypes::FLOAT32;
else if (datatypeValue == "double" || datatypeValue == "doublevalue")
datatype = DataTypes::FLOAT64;
// todo: add further data types
else
throw std::runtime_error("EDFHandler::read: invalid/unsupported data type");
}
else
throw std::runtime_error("EDFHandler::read: data type not found");
auto compressionIt = attributes.find("compression");
if (compressionIt != attributes.end())
throw std::runtime_error("compression not supported");
int size = 0;
auto sizeIt = attributes.find("size");
if (sizeIt != attributes.end())
size = StringUtils::parseString<int>(sizeIt->second);
auto imageIt = attributes.find("image");
if (imageIt != attributes.end() && StringUtils::parseString<int>(imageIt->second) != 1)
throw std::runtime_error("EDFHandler::read: image not set to 1");
// convert size
Eigen::VectorXi dimSizes(nDims);
for (int i = 0; i < nDims; ++i)
dimSizes[i] = dim[i];
if (dimSizes.prod() * DataTypes::getSizeForType(datatype) != size)
throw std::runtime_error("EDFHandler::read: size inconsistency");
// convert spacing
Eigen::VectorXf dimSpacing = Eigen::VectorXf::Ones(nDims);
if (spacing.size() > 0) {
if (spacing.size() != nDims)
throw std::runtime_error("EDFHandler::read: spacing inconsistency");
for (int i = 0; i < nDims; ++i)
dimSpacing[i] = spacing[i];
}
// compute the byte shuffling flag
const bool byteShuffle = (byteorder != ByteOrder::DEFAULT);
// --- read in the image data
Eigen::VectorXf data = DataTypes::parseData<float>(file, datatype, dimSizes.prod(), byteShuffle);
file.close();
// --- setup the volume
Eigen::Vector3f lowerLeft = Eigen::Vector3f::Zero();
Eigen::Vector3f upperRight = lowerLeft + (dimSizes.cast<float>().array() * dimSpacing.array() ).matrix();
Volume vol(lowerLeft, upperRight, dimSpacing);
vol.setContent(data);
return vol;
}
void EDFHandler::write(const std::string& filename, const Volume& vol)
{
// open the EDF file
std::ofstream file(filename, std::ios::binary);
if (!file.good())
throw std::invalid_argument("EDFHandler::write: cannot open " + filename + " for writing");
// open the header
file << "{\n";
file << "HeaderID = EH:000001:000000:000000;\n";
file << "Image = " << 1 << ";\n";
if (ByteOrder::DEFAULT == ByteOrder::HIGH_BYTE_FIRST)
file << "ByteOrder = HighByteFirst;\n";
else
file << "ByteOrder = LowByteFirst;\n";
file << "DataType = " << TYPE_FLOAT << ";\n";
// write dimension and size
for (int i = 0; i < 3; ++i)
file << "Dim_" << (i+1) << " = " << vol.getNumVoxels()[i] << ";\n";
file << "Size = " << vol.getNumVoxels().prod() * sizeof(float) << ";\n";
// write spacing
file << "Spacing =";
for (int i = 0; i < 3; ++i)
file << ' ' << vol.getSpacing()[i];
file << ";\n";
// pad the header by adding spaces such that the header ends on a kilobyte boundary
std::size_t n = 1024;
while (n < (static_cast<std::size_t>(file.tellp()) + 3))
n += 1024;
n -= static_cast<std::size_t>(file.tellp()) + 3;
while (n > 0) {
file.put(' ');
n--;
}
// close the header
file << "\n}\n";
// write the volume data
file.write(reinterpret_cast<const char*>(vol.getContent().data()), vol.getNumVoxels().prod() * sizeof(float) );
file.close();
}
#ifndef EDFHANDLER_H
#define EDFHANDLER_H
#include <string>
#include "volume.h"
/**
* \brief EDFHandler reads and writes EDF files.
*/
class EDFHandler {
public:
/* \brief read an EDF file into a Volume
* \param[in] filename - filename of the EDF file to be read
* \return volume containing the data
*/
static Volume read(const std::string& filename);
/* \brief write out a Volume into an EDF file
* \param[in] filename - filename of the EDF file to be written
* \param[in] vol - volume to be written
*/
static void write(const std::string& filename, const Volume& vol);
private:
static constexpr auto TYPE_FLOAT = "FloatValue";
};
#endif // EDFHANDLER_H
#ifndef IOUTILITIES_H
#define IOUTILITIES_H
#include <algorithm>
#include <regex>
#include <string>
#include <vector>
#include <Eigen/Dense>
/**
* \brief StringUtils provides common string utilities for file parsing.
*/
struct StringUtils {
/* \brief remove whitespace at front and back of string
* \param[in,out] str - string to be trimmed
*/
static void trim(std::string& str);
/* \brief convert string to lower case
* \param[in,out] str - string to be converted
*/
static void tolower(std::string& str);
/* \brief convert string to upper case
* \param[in,out] str - string to be converted
*/
static void toupper(std::string& str);
/* \brief convert string to arbitrary datatype using stringstream
* \param[in] str - string to be converted
* \return converted datatype
*/
template<typename Type>
static Type parseString(const std::string& str);
/* \brief convert string to vector of arbitrary data type using stringstream
* \param[in] str - string to be converted
* \param[out] vec - vector of converted datatypes
* \return number of converted datatypes
*/
template<typename Type>
static int parseString(const std::string& str, std::vector<Type>& vec);
};
/**
* \brief ByteOrder supplies helper routines to cope with byte order conversions.
*/
struct ByteOrder {
/// byte order enum
enum ByteOrderEnum {
LOW_BYTE_FIRST, // little endian (e.g. x86)
HIGH_BYTE_FIRST // big endian (e.g. PowerPC)
};
/// attempt to determine endianness (works on Mac at least..), default to little endian
static const ByteOrderEnum DEFAULT =
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
HIGH_BYTE_FIRST;
#else
LOW_BYTE_FIRST;
#endif
/* \brief shuffle the bytes of the data pointed to by ptr to switch endianness
* \tparam _DataType - data type underlying the pointer
* \param[in,out] ptr - pointer to the data
* \param[in] elements - number of elements of _DataType
*/
template<typename _DataType>
static void shuffleBytes(void* ptr, long elements);
};
/**
* \brief DataTypes supplies helper enums and routines for type conversions.
*/
struct DataTypes {
/// data type enum
enum DataTypeEnum {
INT8, UINT8,
INT16, UINT16,
INT32, UINT32,
FLOAT32,
FLOAT64
};
/* \brief return the size in bytes for the specified data type
* \param[in] dataType - type for which to return the size in bytes
* \return size of dataType in bytes
*/
static int getSizeForType(const DataTypeEnum& dataType);
/* \brief parse data of type dataType from stream in into an Eigen::Vector
* (dispatches to parseData<_DataType, _Scalar> internally)
* \tparam _Scalar - scalar type of Eigen::Vector to return
* \param[in] in - stream from which to read
* \param[in] dataType - dataType of elements to be read from stream
* \param[in] sizeInElements - number of elements (of type dataType) to read from stream
* \param[in] shuffleBytes - flag whether to shuffle bytes around to account for endianness change
* \return vector of _Scalar containing the read in values
*/
template<typename _Scalar>
static Eigen::Matrix<_Scalar, Eigen::Dynamic, 1> parseData(std::istream& in, const DataTypeEnum& dataType, long sizeInElements, bool shuffleBytes);
private:
/* \brief parse data of type _DataType from stream in into an Eigen::Vector
* \tparam _DataType - data type of elements to be read from stream
* \tparam _Scalar - scalar type of Eigen::Vector to return
* \param[in] in - stream from which to read
* \param[in] sizeInElements - number of elements (of type _DataType) to read from stream
* \param[in] shuffleBytes - flag whether to shuffle bytes around to account for endianness change
* \return vector of _Scalar containing the read in values
*/
template<typename _DataType, typename _Scalar>
static Eigen::Matrix<_Scalar, Eigen::Dynamic, 1> parseData(std::istream& in, long sizeInElements, bool shuffleBytes);
};
// --------- Implementations -----------
inline void StringUtils::trim(std::string& str)
{
str = std::regex_replace(str, std::regex("^\\s+|\\s+$"), std::string(""));
}
inline void StringUtils::tolower(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
}
inline void StringUtils::toupper(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
template<typename Type>
inline Type StringUtils::parseString(const std::string& str)
{
Type value;
std::stringstream convert(str);
convert >> value;
if ( convert.fail() )
throw std::runtime_error("parseString: string conversion failed");
return value;
}
template<typename Type>
inline int StringUtils::parseString(const std::string& str, std::vector<Type>& vec)
{
int count = 0;
Type value;
std::stringstream convert(str);
while (!convert.eof())
{
convert >> value;
if (convert.fail())
throw std::runtime_error("parseString: string conversion failed");
vec.push_back(value);
count++;
}
return count;
}
template<>
inline void ByteOrder::shuffleBytes<uint8_t>(void* ptr, long elements) {}
template<>
inline void ByteOrder::shuffleBytes<int8_t>(void* ptr, long elements) {}
template<>
inline void ByteOrder::shuffleBytes<uint16_t>(void* ptr, long elements)
{
uint16_t* ptr16 = static_cast<uint16_t*>(ptr);
for (long index = 0; index < elements; ++index)
ptr16[index] = ((ptr16[index] & 0xff) << 8) | ((ptr16[index] & 0xff00) >> 8);
}
template<>
inline void ByteOrder::shuffleBytes<int16_t>(void* ptr, long elements)
{
shuffleBytes<uint16_t>(ptr, elements);
}
template<>
inline void ByteOrder::shuffleBytes<uint32_t>(void* ptr, long elements)
{
uint32_t* ptr32 = static_cast<uint32_t*>(ptr);
for (long index = 0; index < elements; ++index)
#ifdef _MSC_VER // dumb version for stupid compilers
ptr32[index] = ((ptr32[index] & 0xff) << 24) | ((ptr32[index] & 0xff00) << 8) | ((ptr32[index] & 0xff0000) >> 8) | ((ptr32[index] & 0xff000000) >> 24);
#else
ptr32[index] = __builtin_bswap32(ptr32[index]);
#endif
}
template<>
inline void ByteOrder::shuffleBytes<int32_t>(void* ptr, long elements)
{
shuffleBytes<uint32_t>(ptr, elements);
}
template<>
inline void ByteOrder::shuffleBytes<float>(void* ptr, long elements)
{
shuffleBytes<uint32_t>(ptr, elements);
}
template<>
inline void ByteOrder::shuffleBytes<double>(void* ptr, long elements)
{
uint64_t* ptr64 = static_cast<uint64_t*>(ptr);
for (long index = 0; index < elements; ++index)
#ifdef _MSC_VER // dumb version for stupid compilers
ptr64[index] = ((ptr64[index] & 0xffl) << 56l) | ((ptr64[index] & 0xff00l) << 40l) | ((ptr64[index] & 0xff0000l) << 24l) | ((ptr64[index] & 0xff000000l) << 8l) | ((ptr64[index] & 0xff00000000l) >> 8l) | ((ptr64[index] & 0xff0000000000l) >> 24l) | ((ptr64[index] & 0xff000000000000l) << 40l) | ((ptr64[index] & 0xff00000000000000l) >> 56l);
#else
ptr64[index] = __builtin_bswap64(ptr64[index]);
#endif
}
inline int DataTypes::getSizeForType(const DataTypeEnum& dataType)
{
switch (dataType) {
case INT8:
case UINT8:
return 1;
case INT16:
case UINT16:
return 2;
case INT32:
case UINT32:
case FLOAT32:
return 4;
case FLOAT64:
return 8;
default:
throw std::invalid_argument("getSizeForType: unsupported data type.");
}
}
template<typename _Scalar>
inline Eigen::Matrix<_Scalar, Eigen::Dynamic, 1> DataTypes::parseData(std::istream& in, const DataTypeEnum& dataType, long sizeInElements, bool shuffleBytes)
{
switch (dataType) {
case UINT8:
return parseData<uint8_t, _Scalar>(in, sizeInElements, shuffleBytes);
case INT8:
return parseData<int8_t, _Scalar>(in, sizeInElements, shuffleBytes);
case UINT16:
return parseData<uint16_t, _Scalar>(in, sizeInElements, shuffleBytes);
case INT16:
return parseData<int16_t, _Scalar>(in, sizeInElements, shuffleBytes);
case UINT32:
return parseData<uint32_t, _Scalar>(in, sizeInElements, shuffleBytes);
case INT32:
return parseData<int32_t, _Scalar>(in, sizeInElements, shuffleBytes);
case FLOAT32:
return parseData<float, _Scalar>(in, sizeInElements, shuffleBytes);
case FLOAT64:
return parseData<double, _Scalar>(in, sizeInElements, shuffleBytes);
default:
throw std::runtime_error("parseData: unsupported data type.");
}
}
template<typename _DataType, typename _Scalar>
inline Eigen::Matrix<_Scalar, Eigen::Dynamic, 1> DataTypes::parseData(std::istream& in, long sizeInElements, bool shuffleBytes)
{
long sizeInBytes = sizeInElements * sizeof(_DataType);
// parse data into temporary buffer
std::vector<_DataType> tempBuffer(sizeInElements);
in.read(reinterpret_cast<char*>(&tempBuffer[0]), sizeInBytes);
if (in.gcount() != sizeInBytes)
throw std::runtime_error("parseData: failed to read the expected amount of data.");
// perform byte shuffling to correct endianness
if (shuffleBytes)
ByteOrder::shuffleBytes<_DataType>(&tempBuffer[0], sizeInElements);
// create result vector
Eigen::Matrix<_Scalar, Eigen::Dynamic, 1> result(sizeInElements);
for (long i = 0; i < sizeInElements; ++i)
result(i) = static_cast<_Scalar>(tempBuffer[i]);
return result;
}
#endif // IOUTILITIES_H
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2015, 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 "verysimpleraycaster.h"
#include "core/tools/quadrenderer.h"
#include "core/datastructures/lightsourcedata.h"
#include "core/datastructures/cameradata.h"
#include "core/datastructures/renderdata.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/datastructures/facegeometry.h"
#include "core/pipeline/processordecoratorgradient.h"
#include <tbb/tbb.h>
namespace campvis {
const std::string VerySimpleRaycaster::loggerCat_ = "CAMPVis.modules.cppcourse.VerySimpleRaycaster";
VerySimpleRaycaster::VerySimpleRaycaster(IVec2Property* viewportSizeProp)
: RaycastingProcessor(viewportSizeProp, "modules/cppcourse/glsl/verysimpleraycaster.frag", true)
, p_compositingMode("CompositingMode", "Compositing Mode", 0, 0, 3)
{
addProperty(p_compositingMode);
}
VerySimpleRaycaster::~VerySimpleRaycaster() {
}
void VerySimpleRaycaster::init() {
RaycastingProcessor::init();
}
void VerySimpleRaycaster::deinit() {
RaycastingProcessor::deinit();
}
void VerySimpleRaycaster::processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image) {
// acquire handles to the data inside the container
ScopedTypedData<RenderData, true> outputImage(data, p_targetImageID.getValue(), true);
if (image) {
FramebufferActivationGuard fag(this);
// allocate the color and depth buffer for rendering
createAndAttachTexture(GL_RGBA8, &outputImage);
createAndAttachDepthTexture(&outputImage);
// define a color buffer for output
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, buffers);
// apply some rendering parameters
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// read the property value and pass it to the GPU shader
_shader->setUniform("_compositingMode", p_compositingMode.getValue());
// render a screen-filling quad to perform the raycasting
QuadRdr.renderQuad();
// restore OpenGL state
glDrawBuffers(1, buffers);
glDisable(GL_DEPTH_TEST);
LGL_ERROR;
// Put the rendered image into the data container
data.addData(p_targetImageID.getValue(), new RenderData(_fbo));
}
else {
LDEBUG("Could not load light source from DataContainer.");
}
}
std::string VerySimpleRaycaster::generateHeader() const {
std::string toReturn = RaycastingProcessor::generateHeader();
return toReturn;
}
}
#pragma once
#include "core/pipeline/raycastingprocessor.h"
#include "modules/modulesapi.h"
#include <string>
namespace cgt {
class Shader;
}
namespace campvis {
/**
* Simplified volume raycasting
*/
class CAMPVIS_MODULES_API VerySimpleRaycaster : public RaycastingProcessor {
public:
/**
* Constructs a new VerySimpleRaycaster Processor
**/
explicit VerySimpleRaycaster(IVec2Property* viewportSizeProp);
/**
* Destructor
**/
virtual ~VerySimpleRaycaster();
/**
* To be used in ProcessorFactory static methods
*/
static const std::string getId() { return "VerySimpleRaycaster"; };
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return getId(); };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Greatly simplified raycaster for experimentation."; };
/// \see AbstractProcessor::getAuthor()
virtual const std::string getAuthor() const { return "Jakob Weiss <jakob.weiss@tum.de>"; };
/// \see AbstractProcessor::getProcessorState()
virtual ProcessorState getProcessorState() const { return AbstractProcessor::EXPERIMENTAL; };
// Property to control the compositing mode of the shader
IntProperty p_compositingMode;
/// \see AbstractProcessor::init
virtual void init();
/// \see AbstractProcessor::deinit
virtual void deinit();
protected:
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data, ImageRepresentationGL::ScopedRepresentation& image);
/// \see RaycastingProcessor::generateHeader()
virtual std::string generateHeader() const;
static const std::string loggerCat_;
};
}
#include "volume.h"
Volume::Volume(Eigen::Vector3f lowerLeft, Eigen::Vector3f upperRight, Eigen::Vector3f spacing) : boundingBox(Eigen::AlignedBox3f(lowerLeft, upperRight)), spacing(spacing) {}
Eigen::AlignedBox3f Volume::getBoundingBox() const {
return boundingBox;
}
Eigen::Vector3f Volume::getSpacing() const {
return spacing;
}
Eigen::Vector3i Volume::getNumVoxels() const {
Eigen::Vector3f sizes = boundingBox.sizes();
Eigen::Vector3i numVoxels;
for (int i = 0; i < 3; i++) {
numVoxels[i] = ceil(sizes[i] / spacing[i]);
}
return numVoxels;
}
Eigen::VectorXf Volume::getContent() const {
return content;
}
void Volume::setContent(const Eigen::VectorXf& c) {
content = c;
}
#ifndef VOLUME_H
#define VOLUME_H
#include <Eigen/Geometry>
#include <string>
class Volume {
public:
Volume(Eigen::Vector3f lowerLeft, Eigen::Vector3f upperRight, Eigen::Vector3f sp);
Eigen::AlignedBox3f getBoundingBox() const;
Eigen::Vector3f getSpacing() const;
Eigen::Vector3i getNumVoxels() const;
Eigen::VectorXf getContent() const;
void setContent(const Eigen::VectorXf& c);
// ... other useful methods ...
private:
Eigen::AlignedBox3f boundingBox;
Eigen::Vector3f spacing;
Eigen::VectorXf content;
};
#endif // VOLUME_H