// // Copyright (c) 2008-2017 the Urho3D project. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #pragma once #include "../Container/Ptr.h" #include "../Graphics/Drawable.h" #include "../Graphics/Material.h" #include "../Math/MathDefs.h" #include "../Math/Matrix3x4.h" #include "../Math/Rect.h" namespace Atomic { class Camera; class Drawable; class Geometry; class Light; class Material; class Matrix3x4; class Pass; class ShaderVariation; class Texture2D; class VertexBuffer; class View; class Zone; struct LightBatchQueue; /// Queued 3D geometry draw call. struct Batch { /// Construct with defaults. Batch() : isBase_(false), lightQueue_(0) { } /// Construct from a drawable's source batch. Batch(const SourceBatch& rhs) : distance_(rhs.distance_), renderOrder_(rhs.material_ ? rhs.material_->GetRenderOrder() : DEFAULT_RENDER_ORDER), isBase_(false), geometry_(rhs.geometry_), material_(rhs.material_), worldTransform_(rhs.worldTransform_), numWorldTransforms_(rhs.numWorldTransforms_), instancingData_(rhs.instancingData_), lightQueue_(0), geometryType_(rhs.geometryType_) { } /// Calculate state sorting key, which consists of base pass flag, light, pass and geometry. void CalculateSortKey(); /// Prepare for rendering. void Prepare(View* view, Camera* camera, bool setModelTransform, bool allowDepthWrite) const; /// Prepare and draw. void Draw(View* view, Camera* camera, bool allowDepthWrite) const; /// State sorting key. unsigned long long sortKey_; /// Distance from camera. float distance_; /// 8-bit render order modifier from material. unsigned char renderOrder_; /// 8-bit light mask for stencil marking in deferred rendering. unsigned char lightMask_; /// Base batch flag. This tells to draw the object fully without light optimizations. bool isBase_; /// Geometry. Geometry* geometry_; /// Material. Material* material_; /// World transform(s). For a skinned model, these are the bone transforms. const Matrix3x4* worldTransform_; /// Number of world transforms. unsigned numWorldTransforms_; /// Per-instance data. If not null, must contain enough data to fill instancing buffer. void* instancingData_; /// Zone. Zone* zone_; /// Light properties. LightBatchQueue* lightQueue_; /// Material pass. Pass* pass_; /// Vertex shader. ShaderVariation* vertexShader_; /// Pixel shader. ShaderVariation* pixelShader_; /// %Geometry type. GeometryType geometryType_; }; /// Data for one geometry instance. struct InstanceData { /// Construct undefined. InstanceData() { } /// Construct with transform, instancing data and distance. InstanceData(const Matrix3x4* worldTransform, const void* instancingData, float distance) : worldTransform_(worldTransform), instancingData_(instancingData), distance_(distance) { } /// World transform. const Matrix3x4* worldTransform_; /// Instancing data buffer. const void* instancingData_; /// Distance from camera. float distance_; }; /// Instanced 3D geometry draw call. struct BatchGroup : public Batch { /// Construct with defaults. BatchGroup() : startIndex_(M_MAX_UNSIGNED) { } /// Construct from a batch. BatchGroup(const Batch& batch) : Batch(batch), startIndex_(M_MAX_UNSIGNED) { } /// Destruct. ~BatchGroup() { } /// Add world transform(s) from a batch. void AddTransforms(const Batch& batch) { InstanceData newInstance; newInstance.distance_ = batch.distance_; newInstance.instancingData_ = batch.instancingData_; for (unsigned i = 0; i < batch.numWorldTransforms_; ++i) { newInstance.worldTransform_ = &batch.worldTransform_[i]; instances_.Push(newInstance); } } /// Pre-set the instance data. Buffer must be big enough to hold all data. void SetInstancingData(void* lockedData, unsigned stride, unsigned& freeIndex); /// Prepare and draw. void Draw(View* view, Camera* camera, bool allowDepthWrite) const; /// Instance data. PODVector instances_; /// Instance stream start index, or M_MAX_UNSIGNED if transforms not pre-set. unsigned startIndex_; }; /// Instanced draw call grouping key. struct BatchGroupKey { /// Construct undefined. BatchGroupKey() { } /// Construct from a batch. BatchGroupKey(const Batch& batch) : zone_(batch.zone_), lightQueue_(batch.lightQueue_), pass_(batch.pass_), material_(batch.material_), geometry_(batch.geometry_), renderOrder_(batch.renderOrder_) { } /// Zone. Zone* zone_; /// Light properties. LightBatchQueue* lightQueue_; /// Material pass. Pass* pass_; /// Material. Material* material_; /// Geometry. Geometry* geometry_; /// 8-bit render order modifier from material. unsigned char renderOrder_; /// Test for equality with another batch group key. bool operator ==(const BatchGroupKey& rhs) const { return zone_ == rhs.zone_ && lightQueue_ == rhs.lightQueue_ && pass_ == rhs.pass_ && material_ == rhs.material_ && geometry_ == rhs.geometry_ && renderOrder_ == rhs.renderOrder_; } /// Test for inequality with another batch group key. bool operator !=(const BatchGroupKey& rhs) const { return zone_ != rhs.zone_ || lightQueue_ != rhs.lightQueue_ || pass_ != rhs.pass_ || material_ != rhs.material_ || geometry_ != rhs.geometry_ || renderOrder_ != rhs.renderOrder_; } /// Return hash value. unsigned ToHash() const; }; /// Queue that contains both instanced and non-instanced draw calls. struct BatchQueue { public: /// Clear for new frame by clearing all groups and batches. void Clear(int maxSortedInstances); /// Sort non-instanced draw calls back to front. void SortBackToFront(); /// Sort instanced and non-instanced draw calls front to back. void SortFrontToBack(); /// Sort batches front to back while also maintaining state sorting. void SortFrontToBack2Pass(PODVector& batches); /// Pre-set instance data of all groups. The vertex buffer must be big enough to hold all data. void SetInstancingData(void* lockedData, unsigned stride, unsigned& freeIndex); /// Draw. void Draw(View* view, Camera* camera, bool markToStencil, bool usingLightOptimization, bool allowDepthWrite) const; /// Return the combined amount of instances. unsigned GetNumInstances() const; /// Return whether the batch group is empty. bool IsEmpty() const { return batches_.Empty() && batchGroups_.Empty(); } /// Instanced draw calls. HashMap batchGroups_; /// Shader remapping table for 2-pass state and distance sort. HashMap shaderRemapping_; /// Material remapping table for 2-pass state and distance sort. HashMap materialRemapping_; /// Geometry remapping table for 2-pass state and distance sort. HashMap geometryRemapping_; /// Unsorted non-instanced draw calls. PODVector batches_; /// Sorted non-instanced draw calls. PODVector sortedBatches_; /// Sorted instanced draw calls. PODVector sortedBatchGroups_; /// Maximum sorted instances. unsigned maxSortedInstances_; /// Whether the pass command contains extra shader defines. bool hasExtraDefines_; /// Vertex shader extra defines. String vsExtraDefines_; /// Pixel shader extra defines. String psExtraDefines_; /// Hash for vertex shader extra defines. StringHash vsExtraDefinesHash_; /// Hash for pixel shader extra defines. StringHash psExtraDefinesHash_; }; /// Queue for shadow map draw calls struct ShadowBatchQueue { /// Shadow map camera. Camera* shadowCamera_; /// Shadow map viewport. IntRect shadowViewport_; /// Shadow caster draw calls. BatchQueue shadowBatches_; /// Directional light cascade near split distance. float nearSplit_; /// Directional light cascade far split distance. float farSplit_; }; /// Queue for light related draw calls. struct LightBatchQueue { /// Per-pixel light. Light* light_; /// Light negative flag. bool negative_; /// Shadow map depth texture. Texture2D* shadowMap_; /// Lit geometry draw calls, base (replace blend mode) BatchQueue litBaseBatches_; /// Lit geometry draw calls, non-base (additive) BatchQueue litBatches_; /// Shadow map split queues. Vector shadowSplits_; /// Per-vertex lights. PODVector vertexLights_; /// Light volume draw calls. PODVector volumeBatches_; }; }