Render Filter Implementation

About

Based on maxon::FilterContextInterface, maxon::FilterImageInterface and maxon::FilterInterface one can implement custom render filters.

FilterContex

A filter context is the central class to create queues, images and filters. A real-world implementation would initialize a library or a framework such as CUDA or OpenCL.

// This example shows the declaration of a FilterContext implementation.
namespace FilterContextClasses
{
MAXON_DECLARATION(maxon::FilterContextClasses::EntryType, EXAMPLECONTEXT, "net.maxonexample.render_filter.context.example");
} // FilterContextClasses
// This example shows a simple implementation of FilterContextInterface.
class FilterContextImpl : public maxon::Component<FilterContextImpl, maxon::FilterContextInterface>
{
public:
MAXON_METHOD maxon::Result<maxon::FilterImageRef> CreateImage(const maxon::DataDictionary& imageDesc);
MAXON_METHOD maxon::Result<void> ExecuteCommandQueue(maxon::FilterCommandQueueRef commandQueue);
};
{
// Initialize the FilterContext with optional parameters provided by the DataDictionary (e.g. the type of context)
return maxon::OK;
}
maxon::Result<maxon::FilterRef> FilterContextImpl::CreateFilter(const maxon::LiteralId& filterType)
{
// Create the filter of type 'filterType'.
// In a real world example the context would create some internal object and provide the FilterRef with the object, for instance.
maxon::FilterRef filter = maxon::FilterClasses::Get(filterType.Get()).Create() iferr_return;
return filter;
}
maxon::Result<maxon::FilterImageRef> FilterContextImpl::CreateImage(const maxon::DataDictionary& imageDesc)
{
// Create an image using the imageDesc DataDictionary
maxon::FilterImageRef image = maxon::FilterImageClasses::EXAMPLEIMAGE().Create() iferr_return;
// Get Image parameters...
const maxon::UInt32 width = imageDesc.Get(maxon::FilterImageDescriptionParameters::WIDTH) iferr_return;
const maxon::UInt32 height = imageDesc.Get(maxon::FilterImageDescriptionParameters::HEIGHT) iferr_return;
// ... and do sanity checking!
CheckState(width > 0 && height > 0, "Invalid Image Size!"_s);
// Get the actual implementation of our FilterImage
FilterImageImpl* imageImpl = FilterImageImpl::GetOrNull(image);
CheckState(imageImpl);
imageImpl->Init(width, height) iferr_return;
return image;
}
maxon::Result<maxon::FilterCommandQueueRef> FilterContextImpl::CreateCommandQueue()
{
// A command queue is optional and not needed in this case.
return maxon::FunctionNotImplementedError(MAXON_SOURCE_LOCATION, "No command queue support"_s);
}
maxon::Result<void> FilterContextImpl::ExecuteCommandQueue(maxon::FilterCommandQueueRef commandQueue)
{
// A command queue is optional and not supported in this case.
return maxon::FunctionNotImplementedError(MAXON_SOURCE_LOCATION, "No command queue support"_s);
}
// register implementation
MAXON_COMPONENT_CLASS_REGISTER(FilterContextImpl, maxon::FilterContextClasses::EXAMPLECONTEXT);

FilterImage

A filter image stores the given image data. Internally it might represent a data structure related to the underlying library or framework.

// This example shows the declaration of a FilterImage implementation.
namespace FilterImageClasses
{
MAXON_DECLARATION(maxon::FilterImageClasses::EntryType, EXAMPLEIMAGE, "net.maxonexample.render_filter.image.example");
} // FilterImageClasses
// This example shows a simple implementation of FilterImageInterface wrapping around a maxon::BaseArray.
class FilterImageImpl : public maxon::Component<FilterImageImpl, maxon::FilterImageInterface>
{
public:
MAXON_METHOD maxon::Result<void> WriteToFile(const maxon::Url& url);
maxon::Result<void> Init(const maxon::UInt32 width, const maxon::UInt32 height);
const maxon::BaseArray<maxon::Vector4d32>& GetImageData() const;
private:
// Here, the FilterImage just holds a BaseArray of Vector Data to represent and image.
};
maxon::Result<void> FilterImageImpl::WriteToBuffer(maxon::BaseArray<maxon::Vector4d32>& buffer)
{
return buffer.CopyFrom(_imgData);
}
maxon::Result<void> FilterImageImpl::ReadFromCPUMemory(const maxon::BaseArray<maxon::Vector4d32>& data)
{
return _imgData.CopyFrom(data);
}
maxon::Result<void> FilterImageImpl::WriteToFile(const maxon::Url& url)
{
return maxon::FunctionNotImplementedError(MAXON_SOURCE_LOCATION, "Function not implemented"_s);
}
maxon::Result<void> FilterImageImpl::Init(const maxon::UInt32 width, const maxon::UInt32 height)
{
return _imgData.Resize(width * height);
}
const maxon::BaseArray<maxon::Vector4d32>& FilterImageImpl::GetImageData() const
{
return _imgData;
}
maxon::BaseArray<maxon::Vector4d32>& FilterImageImpl::GetImageData()
{
return _imgData;
}
// register implementation
MAXON_COMPONENT_CLASS_REGISTER(FilterImageImpl, maxon::FilterImageClasses::EXAMPLEIMAGE);

Filter

The actual filter is based on maxon::FilterInterface. It can store various parameters and operates on the given data set.

// This example shows the declaration of a Filter implementation.
namespace FilterClasses
{
MAXON_DECLARATION(FilterClasses::EntryType, EXAMPLEINVERT, "net.maxonexample.render_filter.filter.example.invert");
MAXON_DECLARATION(FilterClasses::EntryType, EXAMPLEPOWER, "net.maxonexample.render_filter.filter.example.power");
} // FilterClasses
// This example shows two simple implementations of FilterInterface. Both share functionality using a ComponentRoot.
//-------------------------------------------------------------------------------------
// A custom ComponentRoot that provides a base implementation for all our filters
//-------------------------------------------------------------------------------------
class FilterComponentRoot : public maxon::ComponentRoot
{
public:
// shared implementation of Execute()
maxon::Result<void> Execute(const maxon::FilterImageRef& input, maxon::FilterImageRef output);
protected:
};
maxon::Result<void> FilterComponentRoot::Execute(const maxon::FilterImageRef& input, maxon::FilterImageRef output)
{
// Get the actual implementation of our FilterImage
FilterImageImpl* inputImpl = FilterImageImpl::GetOrNull(input);
FilterImageImpl* outputImpl = FilterImageImpl::GetOrNull(output);
CheckState(inputImpl && outputImpl);
const maxon::BaseArray<maxon::Vector4d32>& inputData = inputImpl->GetImageData();
maxon::BaseArray<maxon::Vector4d32>& outputData = outputImpl->GetImageData();
CheckState(inputData.GetCount() == outputData.GetCount(), "Input and Output image sizes do not match!"_s);
ExecuteImpl(inputData, outputData) iferr_return;
return maxon::OK;
}
//-------------------------------------------------------------------------------------
// Filter Examples
// Represents a filter that can be executed or attached to a filter command queue.
// Use the Set() function to apply settings.
//-------------------------------------------------------------------------------------
class InvertFilterImpl : public maxon::ComponentWithBase<InvertFilterImpl, FilterComponentRoot, maxon::FilterInterface>
{
public:
MAXON_METHOD maxon::Result<void> Set(const maxon::InternedId& parameter, const maxon::Data& data);
MAXON_METHOD maxon::Result<void> SetProgressMonitor(const maxon::FilterProgressMonitorFunction progressMonitor, void* userPtr);
private:
virtual maxon::Result<void> ExecuteImpl(const maxon::BaseArray<maxon::Vector4d32>& inputData, maxon::BaseArray<maxon::Vector4d32>& outputData) override;
maxon::Bool _everyPixel = true;
};
class PowerFilterImpl : public maxon::ComponentWithBase<PowerFilterImpl, FilterComponentRoot, maxon::FilterInterface>
{
public:
MAXON_METHOD maxon::Result<void> Set(const maxon::InternedId& parameter, const maxon::Data& data);
MAXON_METHOD maxon::Result<void> SetProgressMonitor(const maxon::FilterProgressMonitorFunction progressMonitor, void* userPtr);
private:
virtual maxon::Result<void> ExecuteImpl(const maxon::BaseArray<maxon::Vector4d32>& inputData, maxon::BaseArray<maxon::Vector4d32>& outputData) override;
maxon::Float32 _exponent = 1.0f;
};
maxon::Result<void> InvertFilterImpl::Set(const maxon::InternedId& parameter, const maxon::Data& data)
{
// Switch on the parameter ID
switch (ID_SWITCH(parameter))
{
case ID_CASE(maxonexample::FilterExampleParameter::EVERYPIXEL):
{
_everyPixel = data.GetOrNull<maxon::Bool>();
break;
}
}
return maxon::OK;
}
maxon::Result<void> InvertFilterImpl::SetProgressMonitor(const maxon::FilterProgressMonitorFunction progressMonitor, void* userPtr)
{
return maxon::OK;
}
maxon::Result<void> InvertFilterImpl::ExecuteImpl(const maxon::BaseArray<maxon::Vector4d32>& inputData, maxon::BaseArray<maxon::Vector4d32>& outputData)
{
for (maxon::UInt32 i = 0; i < outputData.GetCount(); ++i)
{
const maxon::Bool skip = _everyPixel == false && i % 2 == 0;
outputData[i] = skip ? inputData[i] : maxon::Vector4d32(1.0f) - inputData[i];
}
return maxon::OK;
}
maxon::Result<void> PowerFilterImpl::Set(const maxon::InternedId& parameter, const maxon::Data& data)
{
// Switch on the parameter ID
switch (ID_SWITCH(parameter))
{
case ID_CASE(maxonexample::FilterExampleParameter::EXPONENT):
{
_exponent = data.GetOrNull<maxon::Float32>();
break;
}
}
return maxon::OK;
}
maxon::Result<void> PowerFilterImpl::SetProgressMonitor(const maxon::FilterProgressMonitorFunction progressMonitor, void* userPtr)
{
return maxon::OK;
}
maxon::Result<void> PowerFilterImpl::ExecuteImpl(const maxon::BaseArray<maxon::Vector4d32>& inputData, maxon::BaseArray<maxon::Vector4d32>& outputData)
{
for (maxon::UInt32 i = 0; i < outputData.GetCount(); ++i)
{
const maxon::Vector4d32& input = inputData[i];
maxon::Vector4d32& output = outputData[i];
for (maxon::UInt32 c = 0; c < 4; ++c)
{
output[c] = maxon::Pow(input[c], _exponent);
}
}
return maxon::OK;
}
// register implementations
MAXON_COMPONENT_CLASS_REGISTER(InvertFilterImpl, maxon::FilterClasses::EXAMPLEINVERT);
MAXON_COMPONENT_CLASS_REGISTER(PowerFilterImpl, maxon::FilterClasses::EXAMPLEPOWER);

Usage

Custom filter can be used as presented:

// Create example context
maxon::FilterContextRef filterContext = maxon::FilterContextClasses::EXAMPLECONTEXT().Create() iferr_return;
filterContext.Init() iferr_return;
// Create filter
maxon::FilterRef filterInvert = filterContext.CreateFilter(maxon::FilterClasses::EXAMPLEINVERT.GetId()) iferr_return;
filterInvert.Set(maxonexample::FilterExampleParameter::EVERYPIXEL, maxon::Data(false)) iferr_return;
maxon::FilterRef filterPower = filterContext.CreateFilter(maxon::FilterClasses::EXAMPLEPOWER.GetId()) iferr_return;
filterPower.Set(maxonexample::FilterExampleParameter::EXPONENT, maxon::Data(0.42f)) iferr_return;
// Create images
maxon::DataDictionary imgDesc;
imgDesc.Set(maxon::FilterImageDescriptionParameters::WIDTH, static_cast<maxon::UInt32>(width)) iferr_return;
imgDesc.Set(maxon::FilterImageDescriptionParameters::HEIGHT, static_cast<maxon::UInt32>(height)) iferr_return;
maxon::FilterImageRef input = filterContext.CreateImage(imgDesc) iferr_return;
maxon::FilterImageRef output = filterContext.CreateImage(imgDesc) iferr_return;
// Load image data
input.ReadFromCPUMemory(bufferColor) iferr_return;
// Execute the filters
filterInvert.Execute(input, output) iferr_return;
filterPower.Execute(output, input) iferr_return;
// Get result image
input.WriteToBuffer(bufferFiltered) iferr_return;

Further Reading

maxon::ComponentWithBase
Definition: objectbase.h:2439
maxon::Vector4d32
Vec4< Float32, 1 > Vector4d32
Definition: vector4d.h:28
MAXON_COMPONENT
#define MAXON_COMPONENT(KIND,...)
Definition: objectbase.h:2014
maxon::Float32
float Float32
32 bit floating point value (float)
Definition: apibase.h:178
maxon::Data
Definition: datatypebase.h:1086
maxon::OK
return OK
Definition: apibase.h:2490
maxon::Bool
bool Bool
boolean type, possible values are only false/true, 8 bit
Definition: apibase.h:177
maxon::Vec4
A vector consisting of four components X, Y, Z and W.
Definition: vec4.h:14
iferr_return
#define iferr_return
Definition: resultbase.h:1434
MAXON_COMPONENT_CLASS_REGISTER
#define MAXON_COMPONENT_CLASS_REGISTER(C,...)
Definition: objectbase.h:2208
MAXON_SOURCE_LOCATION
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:66
maxon::BaseArray
Definition: basearray.h:366
maxon::Url
Definition: url.h:819
maxon::Result< void >
MAXON_METHOD
#define MAXON_METHOD
Definition: interfacebase.h:845
maxon::BaseArray::GetCount
MAXON_ATTRIBUTE_FORCE_INLINE Int GetCount() const
Definition: basearray.h:527
maxon::Opt
Definition: datatype.h:622
MAXON_DECLARATION
#define MAXON_DECLARATION(T, Name, id)
Definition: module.h:791
maxon::Classes::Get
const Class< R > & Get(const Id &cls)
Definition: objectbase.h:1881
iferr_scope
#define iferr_scope
Definition: resultbase.h:1343
maxon::UInt32
uint32_t UInt32
32 bit unsigned integer datatype.
Definition: apibase.h:173
maxon::Pow
MAXON_ATTRIBUTE_FORCE_INLINE Float32 Pow(Float32 v1, Float32 v2)
Calculates v1^v2.
Definition: apibasemath.h:304
maxon::InternedId
Definition: datatypelib.h:26
CheckState
#define CheckState(condition,...)
Definition: errorbase.h:532
ID_SWITCH
#define ID_SWITCH(key)
Definition: fid.h:331
maxon::FilterProgressMonitorFunction
Bool(*)(void *userPtr, Float progress) FilterProgressMonitorFunction
Definition: filter.h:10
maxon::Data::GetOrNull
ByValueParam< T >::type GetOrNull() const
Definition: datatypebase.h:1306
ID_CASE
#define ID_CASE(key)
Definition: fid.h:344
maxon::LiteralId
Definition: apibaseid.h:53
maxon::BaseCollection< BaseArray< T, BASEARRAY_DEFAULT_CHUNK_SIZE, BASEARRAYFLAGS::NONE, DefaultAllocator >, BaseArrayData< T, DefaultAllocator, STD_IS_REPLACEMENT(empty, DefaultAllocator)> >::CopyFrom
MAXON_ATTRIBUTE_FORCE_INLINE Result< void > CopyFrom(COLLECTION2 &&other, COLLECTION_RESIZE_FLAGS resizeFlags=COLLECTION_RESIZE_FLAGS::FIT_TO_SIZE)
Definition: collection.h:252
maxon::LiteralId::Get
const Id & Get() const
Definition: apibaseid.h:183