/* * Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved. * * NVIDIA CORPORATION and its licensors retain all intellectual property * and proprietary rights in and to this software, related documentation * and any modifications thereto. Any use, reproduction, disclosure or * distribution of this software and related documentation without an express * license agreement from NVIDIA CORPORATION is strictly prohibited. */ #ifndef IOFX_RENDER_CALLBACK_H #define IOFX_RENDER_CALLBACK_H #include "foundation/Px.h" #include "UserRenderCallback.h" namespace nvidia { namespace apex { PX_PUSH_PACK_DEFAULT class IofxRenderable; class IofxSpriteRenderable; class IofxMeshRenderable; /** \brief Enumerates the potential IOFX render semantics */ struct IofxRenderSemantic { /** \brief Enum of IOFX render semantics */ enum Enum { POSITION = 0, //!< Position of particle COLOR, //!< Color of particle VELOCITY, //!< Linear velocity of particle SCALE, //!< Scale of particle LIFE_REMAIN, //!< 1.0 (new) .. 0.0 (dead) DENSITY, //!< Particle density SUBTEXTURE, //!< Sub-texture index of particle ORIENTATION, //!< 2D particle orientation (angle in radians, CCW in screen plane) ROTATION, //!< 3D particle rotation USER_DATA, //!< User data - 32 bits (passed from Emitter) NUM_SEMANTICS //!< Count of semantics, not a valid semantic. }; }; /** \brief Enumerates the potential IOFX mesh render layout elements */ struct IofxSpriteRenderLayoutElement { /** \brief Enum of IOFX sprite render layout elements */ enum Enum { POSITION_FLOAT3, COLOR_RGBA8, COLOR_BGRA8, COLOR_FLOAT4, VELOCITY_FLOAT3, SCALE_FLOAT2, LIFE_REMAIN_FLOAT1, DENSITY_FLOAT1, SUBTEXTURE_FLOAT1, ORIENTATION_FLOAT1, USER_DATA_UINT1, MAX_COUNT }; /** \brief Get layout element format */ static PX_INLINE RenderDataFormat::Enum getFormat(Enum element) { switch (element) { case POSITION_FLOAT3: return RenderDataFormat::FLOAT3; case COLOR_RGBA8: return RenderDataFormat::R8G8B8A8; case COLOR_BGRA8: return RenderDataFormat::B8G8R8A8; case COLOR_FLOAT4: return RenderDataFormat::FLOAT4; case VELOCITY_FLOAT3: return RenderDataFormat::FLOAT3; case SCALE_FLOAT2: return RenderDataFormat::FLOAT2; case LIFE_REMAIN_FLOAT1: return RenderDataFormat::FLOAT1; case DENSITY_FLOAT1: return RenderDataFormat::FLOAT1; case SUBTEXTURE_FLOAT1: return RenderDataFormat::FLOAT1; case ORIENTATION_FLOAT1: return RenderDataFormat::FLOAT1; case USER_DATA_UINT1: return RenderDataFormat::UINT1; default: PX_ALWAYS_ASSERT(); return RenderDataFormat::NUM_FORMATS; } } }; /** \brief Enumerates the potential IOFX sprite render layout surface elements */ struct IofxSpriteRenderLayoutSurfaceElement { /** \brief Enum of IOFX sprite render layout surface elements */ enum Enum { POSITION_FLOAT4, //!< float4(POSITION.x, POSITION.y, POSITION.z, 1) SCALE_ORIENT_SUBTEX_FLOAT4, //!< float4(SCALE.x, SCALE.y, ORIENTATION, SUBTEXTURE) COLOR_RGBA8, //(-1)) { numFailed += (offsets[i] >= stride); numFailed += ((offsets[i] & 0x03) != 0); } } for (uint32_t i= 0; i < surfaceCount; ++i) { numFailed += (surfaceElements[i] >= IofxSpriteRenderLayoutSurfaceElement::MAX_COUNT); numFailed += !surfaceDescs[i].isValid(); numFailed += (surfaceDescs[i].width == 0) || (surfaceDescs[i].height == 0); numFailed += (IofxSpriteRenderLayoutSurfaceElement::getFormat(surfaceElements[i]) != surfaceDescs[i].format); } return (numFailed == 0); } /** \brief Check if this object is the same as other */ bool isTheSameAs(const IofxSpriteRenderLayout& other) const { if (surfaceCount != other.surfaceCount) return false; if (surfaceCount == 0) { if (!bufferDesc.isTheSameAs(other.bufferDesc)) return false; if (stride != other.stride) return false; for (uint32_t i = 0; i < IofxSpriteRenderLayoutElement::MAX_COUNT; i++) { if (offsets[i] != other.offsets[i]) return false; } } else { for (uint32_t i = 0; i < surfaceCount; ++i) { if (surfaceElements[i] != other.surfaceElements[i]) return false; if (!surfaceDescs[i].isTheSameAs(other.surfaceDescs[i])) return false; } } return true; } public: UserRenderBufferDesc bufferDesc; //!< Render buffer desc. /** \brief Array of the corresponding offsets (in bytes) for each layout element. */ uint32_t offsets[IofxSpriteRenderLayoutElement::MAX_COUNT]; uint32_t stride; //!< The stride between objects in render buffer. uint32_t surfaceCount; //!< Number of render surfaces (if zero render buffer is used) /** \brief Max number of supported render surfaces */ static const uint32_t MAX_SURFACE_COUNT = 4; /** \brief Layout element for each render surface (should be valid for all indices < surfaceCount) */ IofxSpriteRenderLayoutSurfaceElement::Enum surfaceElements[MAX_SURFACE_COUNT]; /** \brief Description for each render surface (should be valid for all indices < surfaceCount) */ UserRenderSurfaceDesc surfaceDescs[MAX_SURFACE_COUNT]; }; /** \brief Enumerates the potential IOFX mesh render layout elements */ struct IofxMeshRenderLayoutElement { /** \brief Enum of IOFX mesh render layout elements */ enum Enum { POSITION_FLOAT3, ROTATION_SCALE_FLOAT3x3, POSE_FLOAT3x4, VELOCITY_LIFE_FLOAT4, DENSITY_FLOAT1, COLOR_RGBA8, COLOR_BGRA8, COLOR_FLOAT4, USER_DATA_UINT1, MAX_COUNT }; /** \brief Get layout element format */ static PX_INLINE RenderDataFormat::Enum getFormat(Enum element) { switch (element) { case POSITION_FLOAT3: return RenderDataFormat::FLOAT3; case ROTATION_SCALE_FLOAT3x3: return RenderDataFormat::FLOAT3x3; case POSE_FLOAT3x4: return RenderDataFormat::FLOAT3x4; case VELOCITY_LIFE_FLOAT4: return RenderDataFormat::FLOAT4; case DENSITY_FLOAT1: return RenderDataFormat::FLOAT1; case COLOR_RGBA8: return RenderDataFormat::R8G8B8A8; case COLOR_BGRA8: return RenderDataFormat::B8G8R8A8; case COLOR_FLOAT4: return RenderDataFormat::FLOAT4; case USER_DATA_UINT1: return RenderDataFormat::UINT1; default: PX_ALWAYS_ASSERT(); return RenderDataFormat::NUM_FORMATS; } } }; /** \brief Describes the layout for mesh rendering */ struct IofxMeshRenderLayout { IofxMeshRenderLayout(void) { setDefaults(); } /** \brief Reset to default values */ void setDefaults() { bufferDesc.setDefaults(); for (uint32_t i = 0; i < IofxMeshRenderLayoutElement::MAX_COUNT; i++) { offsets[i] = uint32_t(-1); } stride = 0; } /** \brief Check if parameter's values are correct */ bool isValid(void) const { uint32_t numFailed = 0; numFailed += !bufferDesc.isValid(); numFailed += (stride == 0); numFailed += (offsets[IofxMeshRenderLayoutElement::POSITION_FLOAT3] == uint32_t(-1)) && (offsets[IofxMeshRenderLayoutElement::POSE_FLOAT3x4] == uint32_t(-1)); numFailed += ((stride & 0x03) != 0); for (uint32_t i = 0; i < IofxMeshRenderLayoutElement::MAX_COUNT; i++) { if (offsets[i] != static_cast(-1)) { numFailed += (offsets[i] >= stride); numFailed += ((offsets[i] & 0x03) != 0); } } return (numFailed == 0); } /** \brief Check if this object is the same as other */ bool isTheSameAs(const IofxMeshRenderLayout& other) const { if (!bufferDesc.isTheSameAs(other.bufferDesc)) return false; if (stride != other.stride) return false; for (uint32_t i = 0; i < IofxMeshRenderLayoutElement::MAX_COUNT; i++) { if (offsets[i] != other.offsets[i]) return false; } return true; } public: UserRenderBufferDesc bufferDesc; //!< Render buffer desc. /** \brief Array of the corresponding offsets (in bytes) for each layout element. */ uint32_t offsets[IofxMeshRenderLayoutElement::MAX_COUNT]; uint32_t stride; //!< The stride between objects in render buffer. }; /** \brief User defined callback for IOFX rendering */ class IofxRenderCallback : public UserRenderCallback { public: /** \brief Called just after a new IOFX renderable was created */ virtual void onCreatedIofxRenderable(IofxRenderable& ) {} /** \brief Called just after an IOFX renderable was updated */ virtual void onUpdatedIofxRenderable(IofxRenderable& ) {} /** \brief Called just before an IOFX renderable is going to be released */ virtual void onReleasingIofxRenderable(IofxRenderable& ) {} /** \brief Called by the IOFX module to query layout for sprite rendering. Should return true in case IofxSpriteRenderLayout is properly filled, and then IOFX will pass this layout to createRender[Buffer|Surface] method(s) to create needed render resources. In case this method is not implemented and returns false the IOFX module will create a layout to hold all input semantics. Also in case this method is not implemented or/and createRender[Buffer|Surface] method is not implemented, then the IOFX module will create its own render buffer/surfaces which user can map to access rendering content. */ virtual bool getIofxSpriteRenderLayout(IofxSpriteRenderLayout& spriteRenderLayout, uint32_t spriteCount, uint32_t spriteSemanticsBitmap, RenderInteropFlags::Enum interopFlags) { PX_UNUSED(spriteRenderLayout); PX_UNUSED(spriteCount); PX_UNUSED(spriteSemanticsBitmap); PX_UNUSED(interopFlags); return false; } /** \brief Called by the IOFX module to query layout for mesh rendering. Should return true in case IofxMeshRenderLayout is properly filled, and then IOFX will pass this layout to createRenderBuffer method to create needed render resources. In case this method is not implemented and returns false the IOFX module will create a layout to hold all input semantics. Also in case this method is not implemented or/and createRenderBuffer method is not implemented, then the IOFX module will create its own render buffer which user can map to access rendering content. */ virtual bool getIofxMeshRenderLayout(IofxMeshRenderLayout& meshRenderLayout, uint32_t meshCount, uint32_t meshSemanticsBitmap, RenderInteropFlags::Enum interopFlags) { PX_UNUSED(meshRenderLayout); PX_UNUSED(meshCount); PX_UNUSED(meshSemanticsBitmap); PX_UNUSED(interopFlags); return false; } }; PX_POP_PACK } } // end namespace nvidia #endif // IOFX_RENDER_CALLBACK_H