RAMSES Documentation  27.0.130
Information for RAMSES users and developers
ramses-example-data-buffers-texture/src/main.cpp

Basic Texture Buffer Example

// -------------------------------------------------------------------------
// Copyright (C) 2017 BMW Car IT GmbH
// -------------------------------------------------------------------------
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
// -------------------------------------------------------------------------
#include "ramses-client.h"
#include "ramses-utils.h"
#include <thread>
#include <chrono>
#include <array>
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
class IndexIterator
{
static_assert(TotalWidth >= RegionOffsetX + RegionWidth, "Subregion exceeds TotalWidth");
static_assert(TotalHeight >= RegionOffsetY + RegionHeight, "Subregion exceeds TotalHeight");
public:
IndexIterator& operator++();
bool isAtEnd();
uint32_t getIndexLocal();
uint32_t getIndexGlobal();
float getPositionXLocal(float cycleOffset=0.f);
float getPositionXGlobal(float cycleOffset=0.f);
float getPositionYLocal(float cycleOffset=0.f);
float getPositionYGlobal(float cycleOffset=0.f);
private:
uint32_t x = 0u;
uint32_t y = 0u;
};
int main(int argc, char* argv[])
{
// register at RAMSES daemon
ramses::RamsesFramework framework(argc, argv);
ramses::RamsesClient& ramses(*framework.createClient("ramses-example-data-buffers-texture"));
framework.connect();
// create a scene for distributing content
ramses::Scene* scene = ramses.createScene(ramses::sceneId_t(123u), ramses::SceneConfig(), "basic texturing scene");
// every scene needs a render pass with camera
auto* camera = scene->createPerspectiveCamera("my camera");
camera->setViewport(0, 0, 1280u, 480u);
camera->setFrustum(19.f, 1280.f / 480.f, 0.1f, 1500.f);
camera->setTranslation(0.0f, 0.0f, 8.0f);
ramses::RenderPass* renderPass = scene->createRenderPass("my render pass");
renderPass->setCamera(*camera);
ramses::RenderGroup* renderGroup = scene->createRenderGroup();
renderPass->addRenderGroup(*renderGroup);
// prepare quad geometry: vertex position array and index array
// Two different vertex arrays, to show two different mipmap levels of the texture
// The ...Near quad will show mipmap level 0, the ...Far quad will show mipmap level 1
float vertexPositionsNearArray[] = { -1.f, -1.f, -1.f, 1.f, -1.f, -1.f, -1.f, 1.f, -1.f, 1.f, 1.f, -1.f };
ramses::ArrayResource* vertexPositionsNear = scene->createArrayResource(ramses::EDataType::Vector3F, 4, vertexPositionsNearArray);
float vertexPositionsFarArray[] = { -5.f, -1.f, -5.f, -3.f, -1.f, -5.f, -5.f, 1.f, -5.f, -3.f, 1.f, -5.f };
ramses::ArrayResource* vertexPositionsFar = scene->createArrayResource(ramses::EDataType::Vector3F, 4, vertexPositionsFarArray);
float textureCoordsArray[] = { 0.f, 1.f, 1.f, 1.f, 0.f, 0.f, 1.f, 0.f};
ramses::ArrayResource* textureCoords = scene->createArrayResource(ramses::EDataType::Vector2F, 4, textureCoordsArray);
uint16_t indicesArray[] = { 0, 1, 2, 2, 1, 3 };
// The texture will show different color gradients in the different mipmap levels
// The gradients will then be cycled inside a region whithin the texture itself
// First all the dimensions for these different layers and regions are defined
const uint32_t numChannels = 3;
const uint32_t textureWidthLevel0 = 32;
const uint32_t textureHeightLevel0 = 12;
const uint32_t textureWidthLevel1 = textureWidthLevel0 / 2;
const uint32_t textureHeightLevel1 = textureHeightLevel0 / 2;
const uint32_t regionOffsetXLevel0 = 5;
const uint32_t regionOffsetYLevel0 = 4;
const uint32_t regionWidthLevel0 = 10;
const uint32_t regionHeightLevel0 = 6;
const uint32_t regionOffsetXLevel1 = 8;
const uint32_t regionOffsetYLevel1 = 1;
const uint32_t regionWidthLevel1 = 5;
const uint32_t regionHeightLevel1 = 4;
const uint32_t dataSizeLevel0 = textureWidthLevel0 * textureHeightLevel0 * numChannels;
const uint32_t dataSizeLevel1 = textureWidthLevel1 * textureHeightLevel1 * numChannels;
const uint32_t regionDataSizeLevel0 = regionWidthLevel0 * regionHeightLevel0 * numChannels;
const uint32_t regionDataSizeLevel1 = regionWidthLevel1 * regionHeightLevel1 * numChannels;
std::array<uint8_t, dataSizeLevel0> textureDataLevel0;
std::array<uint8_t, dataSizeLevel1> textureDataLevel1;
std::array<uint8_t, regionDataSizeLevel0> regionDataLevel0;
std::array<uint8_t, regionDataSizeLevel1> regionDataLevel1;
// A helper function to cast and map a float value [0.f, 1.f[ to uint8 [0,255]
auto convertToUInt8 = [](float value)->uint8_t
{
// by substracting the integer part, we just keep
// the fractional part [0.f,1.f[
value -= static_cast<uint32_t>(value);
return static_cast<uint8_t>(value * 255.f);
};
// Fill the texture mipmap level 0 whith a red-green gradient
IndexIterator<textureWidthLevel0, textureHeightLevel0, 0, 0, textureWidthLevel0, textureHeightLevel0> fullTextureIndicesLevel0;
for(; !fullTextureIndicesLevel0.isAtEnd(); ++fullTextureIndicesLevel0)
{
const uint32_t index = fullTextureIndicesLevel0.getIndexGlobal() * 3;
textureDataLevel0.begin()[index+0] = convertToUInt8(fullTextureIndicesLevel0.getPositionXGlobal());
textureDataLevel0.begin()[index+1] = convertToUInt8(fullTextureIndicesLevel0.getPositionYGlobal());
textureDataLevel0.begin()[index+2] = 0;
}
// Fill the texture mipmap level 1 with a red-blue gradient
IndexIterator<textureWidthLevel1, textureHeightLevel1, 0, 0, textureWidthLevel1, textureHeightLevel1> fullTextureIndicesLevel1;
for(; !fullTextureIndicesLevel1.isAtEnd(); ++fullTextureIndicesLevel1)
{
const uint32_t index = fullTextureIndicesLevel1.getIndexGlobal() * 3;
textureDataLevel1.begin()[index+0] = convertToUInt8(fullTextureIndicesLevel1.getPositionXGlobal());
textureDataLevel1.begin()[index+1] = 0;
textureDataLevel1.begin()[index+2] = convertToUInt8(fullTextureIndicesLevel1.getPositionYGlobal());
}
// IMPORTANT NOTE: For simplicity and readability the example code does not check return values from API calls.
// This should not be the case for real applications.
// Create the Texture2DBuffer via the scene
ramses::Texture2DBuffer* texture = scene->createTexture2DBuffer(format, textureWidthLevel0, textureHeightLevel0, 2u, "A varying texture");
// Whith Texture2DBuffer::setData you can pass a buffer for a specific mipmap level
texture->updateData(0, 0, 0, textureWidthLevel0, textureHeightLevel0, textureDataLevel0.data());
texture->updateData(1, 0, 0, textureWidthLevel1, textureHeightLevel1, textureDataLevel1.data());
// Just like resources or render buffers you add it via createTextureSampler
*texture);
effectDesc.setVertexShaderFromFile("res/ramses-example-data-buffers-texture.vert");
effectDesc.setFragmentShaderFromFile("res/ramses-example-data-buffers-texture.frag");
ramses::Effect* effectTex = scene->createEffect(effectDesc, ramses::ResourceCacheFlag_DoNotCache, "glsl shader");
ramses::Appearance* appearanceNear = scene->createAppearance(*effectTex, "quad appearance (near)");
ramses::Appearance* appearanceFar = scene->createAppearance(*effectTex, "quad appearance (far)");
// set vertex positions directly in geometry
ramses::AttributeInput positionsInput;
ramses::AttributeInput texcoordsInput;
ramses::UniformInput mipmapLevelInput;
effectTex->findAttributeInput("a_position", positionsInput);
effectTex->findAttributeInput("a_texcoord", texcoordsInput);
// for sake of showing the different mipmap levels explicitly, a uniform selecting
// a specific mipmap level has been added to the fragment shader
effectTex->findUniformInput("mipmapLevel", mipmapLevelInput);
ramses::GeometryBinding* geometryNear = scene->createGeometryBinding(*effectTex, "quad geometry (near)");
geometryNear->setInputBuffer(positionsInput, *vertexPositionsNear);
geometryNear->setInputBuffer(texcoordsInput, *textureCoords);
geometryNear->setIndices(*indices);
ramses::GeometryBinding* geometryFar = scene->createGeometryBinding(*effectTex, "quad geometry (far)");
geometryFar->setInputBuffer(positionsInput, *vertexPositionsFar);
geometryFar->setInputBuffer(texcoordsInput, *textureCoords);
geometryFar->setIndices(*indices);
ramses::UniformInput textureInput;
effectTex->findUniformInput("textureSampler", textureInput);
appearanceNear->setInputTexture(textureInput, *sampler);
appearanceFar->setInputTexture(textureInput, *sampler);
appearanceNear->setInputValueInt32(mipmapLevelInput, 0);
appearanceFar->setInputValueInt32(mipmapLevelInput, 1);
// create a mesh node to define the quad with chosen appearance
ramses::MeshNode* meshNodeNear = scene->createMeshNode("textured quad mesh node (near)");
meshNodeNear->setAppearance(*appearanceNear);
meshNodeNear->setGeometryBinding(*geometryNear);
ramses::MeshNode* meshNodeFar = scene->createMeshNode("textured quad mesh node (far)");
meshNodeFar->setAppearance(*appearanceFar);
meshNodeFar->setGeometryBinding(*geometryFar);
// mesh needs to be added to a render group that belongs to a render pass with camera in order to be rendered
renderGroup->addMeshNode(*meshNodeNear);
renderGroup->addMeshNode(*meshNodeFar);
// signal the scene it is in a state that can be rendered
scene->flush();
// distribute the scene to RAMSES
scene->publish();
// application logic
for(uint32_t i=0; i < 100; ++i)
{
// The IndexIterator is just a helper class calculating the needed indices and positions
// With regard to the example it's not important how these values are calculated.
IndexIterator<textureWidthLevel0, textureHeightLevel0, regionOffsetXLevel0, regionOffsetYLevel0, regionWidthLevel0, regionHeightLevel0> regionIndicesLevel0;
IndexIterator<textureWidthLevel1, textureHeightLevel1, regionOffsetXLevel1, regionOffsetYLevel1, regionWidthLevel1, regionHeightLevel1> regionIndicesLevel1;
// cycleOffset is used to shift the calculated positions, thus creating the cycle effect
const float cycleOffset = static_cast<float>(i) / 10.f;
// iterate over the values you want to update in mipmap level 0
for(; !regionIndicesLevel0.isAtEnd(); ++regionIndicesLevel0)
{
const uint32_t index = regionIndicesLevel0.getIndexLocal() * 3;
// calculate new color values for the updated texture
// these values can be stored in some new array, which is not necessarily the original
// data array. This new array has to have the correct dimensions for the updated region
// (i.e. might be just as small as the region you need to update)
regionDataLevel0.begin()[index+0] = convertToUInt8(regionIndicesLevel0.getPositionXLocal(cycleOffset));
regionDataLevel0.begin()[index+1] = 0;
regionDataLevel0.begin()[index+2] = convertToUInt8(regionIndicesLevel0.getPositionYLocal(cycleOffset));
}
// iterate over the values you want to update in mipmap level 1
for(; !regionIndicesLevel1.isAtEnd(); ++regionIndicesLevel1)
{
const uint32_t index = regionIndicesLevel1.getIndexLocal() * 3;
regionDataLevel1.begin()[index+0] = 0;
regionDataLevel1.begin()[index+1] = convertToUInt8(regionIndicesLevel1.getPositionXLocal(cycleOffset+0.5f));
regionDataLevel1.begin()[index+2] = convertToUInt8(regionIndicesLevel1.getPositionYLocal(cycleOffset+0.3f));
}
// with Texture2DBuffer::setData you can pass the updated array data to the data buffer
texture->updateData(0, regionOffsetXLevel0, regionOffsetYLevel0, regionWidthLevel0, regionHeightLevel0, regionDataLevel0.data());
texture->updateData(1, regionOffsetXLevel1, regionOffsetYLevel1, regionWidthLevel1, regionHeightLevel1, regionDataLevel1.data());
scene->flush();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// shutdown: stop distribution, free resources, unregister
scene->unpublish();
scene->destroy(*vertexPositionsNear);
scene->destroy(*vertexPositionsFar);
scene->destroy(*textureCoords);
scene->destroy(*indices);
ramses.destroy(*scene);
framework.disconnect();
return 0;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>& IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::operator++()
{
if( !isAtEnd() )
{
++x;
if(x == RegionWidth && y+1 < RegionHeight)
{
x = 0u;
++y;
}
}
return *this;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
bool IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::isAtEnd()
{
return (x == RegionWidth && y+1 == RegionHeight);
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
uint32_t IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::getIndexLocal()
{
const uint32_t indexRow = y * RegionWidth;
const uint32_t indexColumn = x;
return indexRow + indexColumn;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
uint32_t IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::getIndexGlobal()
{
const uint32_t indexRow = (y+RegionOffsetY) * TotalWidth;
const uint32_t indexColumn = (x+RegionOffsetX);
return indexRow + indexColumn;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
float IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::getPositionXLocal(float cycleOffset)
{
const float shiftedPosition = (static_cast<float>(x) / static_cast<float>(RegionWidth)) + cycleOffset;
const float positionFractionalPart = shiftedPosition - static_cast<uint32_t>(shiftedPosition);
return positionFractionalPart;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
float IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::getPositionXGlobal(float cycleOffset)
{
const float scaleFactor = static_cast<float>(RegionWidth) / static_cast<float>(TotalWidth);
const float offset = static_cast<float>(RegionOffsetX) / static_cast<float>(TotalWidth);
const float position = offset + scaleFactor * getPositionXLocal(cycleOffset);
return position;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
float IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::getPositionYLocal(float cycleOffset)
{
const float shiftedPosition = (static_cast<float>(y) / static_cast<float>(RegionHeight)) + cycleOffset;
const float positionFractionalPart = shiftedPosition - static_cast<uint32_t>(shiftedPosition);
return positionFractionalPart;
}
template< uint32_t TotalWidth, uint32_t TotalHeight,
uint32_t RegionOffsetX, uint32_t RegionOffsetY,
uint32_t RegionWidth, uint32_t RegionHeight >
float IndexIterator<TotalWidth, TotalHeight, RegionOffsetX, RegionOffsetY, RegionWidth, RegionHeight>::getPositionYGlobal(float cycleOffset)
{
const float scaleFactor = static_cast<float>(RegionHeight) / static_cast<float>(TotalHeight);
const float offset = static_cast<float>(RegionOffsetY) / static_cast<float>(TotalHeight);
const float position = offset + scaleFactor * getPositionYLocal(cycleOffset);
return position;
}
The Appearance describes how an object should look like. This includes GLSL uniform values,...
Definition: Appearance.h:34
status_t setInputValueInt32(const UniformInput &input, int32_t i)
Sets value of the input.
status_t setInputTexture(const UniformInput &input, const TextureSampler &textureSampler)
Sets texture sampler to the input.
The ArrayResource stores a data array of a given type. The data is immutable. The resource can be use...
Definition: ArrayResource.h:26
The AttributeInput is a description of an attribute effect input.
Definition: AttributeInput.h:22
status_t setViewport(int32_t x, int32_t y, uint32_t width, uint32_t height)
Sets the viewport to be used when rendering with this camera.
An effect description holds all necessary information for an effect to be created.
Definition: EffectDescription.h:21
status_t setVertexShaderFromFile(const char *shaderSourceFileName)
Reads and sets vertex shader source from file.
status_t setUniformSemantic(const char *inputName, EEffectUniformSemantic semanticType)
Sets an uniform semantic. Used for uniforms which are not locally available on the client,...
status_t setFragmentShaderFromFile(const char *shaderSourceFileName)
Reads and sets fragment shader source from file.
An effect describes how an object will be rendered to the screen.
Definition: Effect.h:26
status_t findUniformInput(const char *inputName, UniformInput &uniformInput) const
Finds uniform input by input name.
status_t findAttributeInput(const char *inputName, AttributeInput &attributeInput) const
Finds attribute input by input name.
A geometry binding together with an appearance describe how an object will be rendered to the screen.
Definition: GeometryBinding.h:25
status_t setIndices(const ArrayResource &indicesResource)
Assign a data array with data type UInt16 or UInt32 to be used when accessing vertex data.
status_t setInputBuffer(const AttributeInput &attributeInput, const ArrayResource &arrayResource, uint32_t instancingDivisor=0)
Assign a data array resource to a given effect attribute input.
The MeshNode holds all information which is needed to render an object to the screen.
Definition: MeshNode.h:25
status_t setAppearance(Appearance &appearance)
Sets the Appearance of the MeshNode.
status_t setGeometryBinding(GeometryBinding &geometry)
Sets the GeometryBinding of the MeshNode.
Entry point of RAMSES client API.
Definition: RamsesClient.h:34
Class representing ramses framework components that are needed to initialize an instance of ramses cl...
Definition: RamsesFramework.h:35
The RenderGroup is a container used to collect renderables which are supposed to be rendered together...
Definition: RenderGroup.h:31
status_t addMeshNode(const MeshNode &mesh, int32_t orderWithinGroup=0)
Add a mesh to this RenderGroup. If a mesh is already contained in this RenderGroup only its render or...
The RenderPass is a container used to collect meshes which are supposed to be rendered together.
Definition: RenderPass.h:31
status_t setCamera(const Camera &camera)
Set the camera to use for rendering the objects of this renderpass.
status_t setClearFlags(uint32_t clearFlags)
Set the clear flags which enable/disable the clearing of the render target assigned to this RenderPas...
status_t addRenderGroup(const RenderGroup &renderGroup, int32_t orderWithinPass=0)
Add a RenderGroup to this RenderPass for rendering.
The SceneConfig holds a set of parameters to be used when creating a scene.
Definition: SceneConfig.h:22
The Scene holds a scene graph. It is the essential class for distributing content to the ramses syste...
Definition: Scene.h:83
MeshNode * createMeshNode(const char *name=nullptr)
Creates a scene graph MeshNode. MeshNode is a Node with additional properties and bindings that repre...
Effect * createEffect(const EffectDescription &effectDesc, resourceCacheFlag_t cacheFlag=ResourceCacheFlag_DoNotCache, const char *name=nullptr)
Create a new Effect by parsing a GLSL shader described by an EffectDescription instance....
status_t unpublish()
Unpublish the scene from the ramses system.
Texture2DBuffer * createTexture2DBuffer(ETextureFormat textureFormat, uint32_t width, uint32_t height, uint32_t mipLevelCount, const char *name=nullptr)
Create a new Texture2DBuffer. The created object is a mutable buffer object that can be used as a tex...
GeometryBinding * createGeometryBinding(const Effect &effect, const char *name=nullptr)
Creates a new GeometryBinding.
ArrayResource * createArrayResource(EDataType type, uint32_t numElements, const void *arrayData, resourceCacheFlag_t cacheFlag=ResourceCacheFlag_DoNotCache, const char *name=nullptr)
Create a new ArrayResource. It makes a copy of the given data of a certain type as a resource,...
status_t publish(EScenePublicationMode publicationMode=EScenePublicationMode_LocalAndRemote)
Publishes the scene to the ramses system.
RenderPass * createRenderPass(const char *name=nullptr)
Create a render pass in the scene.
Appearance * createAppearance(const Effect &effect, const char *name=nullptr)
Creates a new Appearance.
status_t destroy(SceneObject &object)
Destroys a previously created object using this scene The object must be owned by this scene in order...
RenderGroup * createRenderGroup(const char *name=nullptr)
Create a RenderGroup instance in the scene.
PerspectiveCamera * createPerspectiveCamera(const char *name=nullptr)
Creates a Perspective Camera in this Scene.
status_t flush(sceneVersionTag_t sceneVersionTag=InvalidSceneVersionTag)
Commits all changes done to the scene since the last flush or since scene creation....
TextureSampler * createTextureSampler(ETextureAddressMode wrapUMode, ETextureAddressMode wrapVMode, ETextureSamplingMethod minSamplingMethod, ETextureSamplingMethod magSamplingMethod, const Texture2D &texture, uint32_t anisotropyLevel=1, const char *name=nullptr)
Creates a texture sampler object.
Helper class to create strongly typed values out of various types.
Definition: StronglyTypedValue.h:23
The Texture2DBuffer is a mutable texture buffer used to hold texture data with the possibility to per...
Definition: Texture2DBuffer.h:26
status_t updateData(uint32_t mipLevel, uint32_t offsetX, uint32_t offsetY, uint32_t width, uint32_t height, const void *data)
Update a subregion of the data of Texture2DBuffer. The caller is responsible to check that the data h...
The TextureSampler holds a texture and its sampling parameters.
Definition: TextureSampler.h:29
The UniformInput is a description of an uniform effect input.
Definition: UniformInput.h:22
The RAMSES namespace contains all client side objects and functions used to implement RAMSES applicat...
Definition: AnimatedProperty.h:15
ETextureFormat
Texture data format.
Definition: TextureEnums.h:40
@ ETextureSamplingMethod_Nearest
Definition: TextureEnums.h:20
@ ETextureAddressMode_Clamp
Definition: TextureEnums.h:32
@ EClearFlags_None
Definition: RamsesFrameworkTypes.h:257
@ ModelViewProjectionMatrix
Model-view-projection matrix 4x4.
@ Vector2F
two components of type float per data element
@ UInt16
one component of type uint16_t per data element
@ Vector3F
three components of type float per data element
constexpr const resourceCacheFlag_t ResourceCacheFlag_DoNotCache
Requests the render to not cache a resource. This is the default value.
Definition: RamsesFrameworkTypes.h:212
int main(int argc, char *argv[])
Definition: main.cpp:21