/
OgreHlmsDatablock.h
527 lines (462 loc) · 25.9 KB
/
OgreHlmsDatablock.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2014 Torus Knot Software Ltd
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.
-----------------------------------------------------------------------------
*/
#ifndef _OgreHlmsDatablock_H_
#define _OgreHlmsDatablock_H_
#include "OgreStringVector.h"
#include "OgreHlmsCommon.h"
#include "OgreHeaderPrefix.h"
namespace Ogre
{
/** \addtogroup Core
* @{
*/
/** \addtogroup Resources
* @{
*/
enum HlmsBasicBlock
{
BLOCK_MACRO,
BLOCK_BLEND,
BLOCK_SAMPLER,
NUM_BASIC_BLOCKS,
};
struct _OgreExport BasicBlock
{
void *mRsData; /// Render-System specific data
uint16 mRefCount;
/// The mId is only valid while mRefCount > 0; which means mRsData
/// may contain valid data, else it's null.
uint16 mId;
/// Except for HlmsSamplerblocks, mLifetimeId is valid throghout the entire life of
/// HlmsManager. This guarantees HlmsMacroblock & HlmsBlendblock pointers are always
/// valid, although they may be inactive (i.e. mId invalid, mRefCount = 0 and mRsData = 0)
uint16 mLifetimeId;
uint8 mBlockType; /// @see HlmsBasicBlock
/// When zero, HlmsManager cannot override the block's values with
/// enforced global settings. (such as lower quality texture filtering or
/// turning off depth checks for debugging)
uint8 mAllowGlobalDefaults;
BasicBlock( uint8 blockType );
};
/** A macro block contains settings that will rarely change, and thus are common to many materials.
This is very analogous to D3D11_RASTERIZER_DESC. See HlmsDatablock
Up to 32 different blocks are allowed!
*/
struct _OgreExport HlmsMacroblock : public BasicBlock
{
bool mScissorTestEnabled;
bool mDepthClamp;
bool mDepthCheck;
bool mDepthWrite;
CompareFunction mDepthFunc;
/// When polygons are coplanar, you can get problems with 'depth fighting' where
/// the pixels from the two polys compete for the same screen pixel. This is particularly
/// a problem for decals (polys attached to another surface to represent details such as
/// bulletholes etc.).
///
/// A way to combat this problem is to use a depth bias to adjust the depth buffer value
/// used for the decal such that it is slightly higher than the true value, ensuring that
/// the decal appears on top. There are two aspects to the biasing, a constant
/// bias value and a slope-relative biasing value, which varies according to the
/// maximum depth slope relative to the camera, ie:
/// <pre>finalBias = maxSlope * slopeScaleBias + constantBias</pre>
/// Note that slope scale bias, whilst more accurate, may be ignored by old hardware.
///
/// The constant bias value, expressed as a factor of the minimum observable depth
float mDepthBiasConstant;
/// The slope-relative bias value, expressed as a factor of the depth slope
float mDepthBiasSlopeScale;
/// Culling mode based on the 'vertex winding'.
/// A typical way for the rendering engine to cull triangles is based on the
/// 'vertex winding' of triangles. Vertex winding refers to the direction in
/// which the vertices are passed or indexed to in the rendering operation as viewed
/// from the camera, and will wither be clockwise or anticlockwise (that's 'counterclockwise' for
/// you Americans out there ;) The default is CULL_CLOCKWISE i.e. that only triangles whose
/// vertices are passed/indexed in anticlockwise order are rendered - this is a common approach
/// and is used in 3D studio models for example. You can alter this culling mode if you wish
/// but it is not advised unless you know what you are doing.
/// You may wish to use the CULL_NONE option for mesh data that you cull yourself where the
/// vertex winding is uncertain.
CullingMode mCullMode;
PolygonMode mPolygonMode;
HlmsMacroblock();
bool operator == ( const HlmsMacroblock &_r ) const
{
return !(*this != _r);
}
bool operator != ( const HlmsMacroblock &_r ) const
{
//Don't include the ID in the comparision
return mAllowGlobalDefaults != _r.mAllowGlobalDefaults ||
mScissorTestEnabled != _r.mScissorTestEnabled ||
mDepthClamp != _r.mDepthClamp ||
mDepthCheck != _r.mDepthCheck ||
mDepthWrite != _r.mDepthWrite ||
mDepthFunc != _r.mDepthFunc ||
mDepthBiasConstant != _r.mDepthBiasConstant ||
mDepthBiasSlopeScale != _r.mDepthBiasSlopeScale ||
mCullMode != _r.mCullMode ||
mPolygonMode != _r.mPolygonMode;
}
};
/** A blend block contains settings that rarely change, and thus are common to many materials.
The reasons this structure isn't joined with HlmsMacroblock is that:
* The D3D11 API makes this distinction (much higher API overhead if we
change i.e. depth settings) due to D3D11_RASTERIZER_DESC.
* This block contains information of whether the material is transparent.
Transparent materials are sorted differently than opaque ones.
Up to 32 different blocks are allowed!
*/
struct _OgreExport HlmsBlendblock : public BasicBlock
{
enum BlendChannelMasks
{
BlendChannelRed = 0x01,
BlendChannelGreen = 0x02,
BlendChannelBlue = 0x04,
BlendChannelAlpha = 0x08,
BlendChannelAll = BlendChannelRed | BlendChannelGreen |
BlendChannelBlue | BlendChannelAlpha,
/// Setting mBlendChannelMask = 0 will skip all channels (i.e. only depth and stencil)
/// But pixel shader may still run due to side effects (e.g. pixel discard/alpha testing
/// UAV outputs). Some drivers may not optimize this case due to the amount of checks
/// needed to see if the PS has side effects or not.
///
/// When force-disabled, we will not set a pixel shader, thus you can be certain
/// it's running as optimized as it can be. However beware if you rely on
/// discard/alpha testing or any other side effect, it will not render correctly
///
/// Note: BlendChannelForceDisabled will be ignored if any of the other flags are set
BlendChannelForceDisabled= 0x10
};
bool mAlphaToCoverageEnabled;
/// Masks which colour channels will be writing to. Default: BlendChannelAll
/// For some advanced effects, you may wish to turn off the writing of certain colour
/// channels, or even all of the colour channels so that only the depth buffer is updated
/// in a rendering pass (if depth writes are on; may be you want to only update the
/// stencil buffer).
uint8 mBlendChannelMask;
/// This value calculated by HlmsManager::getBlendblock
/// mIsTransparent = 0 -> Not transparent
/// mIsTransparent |= 1 -> Automatically determined as transparent
/// mIsTransparent |= 2 -> Forced to be considered as transparent by RenderQueue for render order
/// mIsTransparent = 3 -> Forced & also automatically determined as transparent
uint8 mIsTransparent;
/// Used to determine if separate alpha blending should be used for color and alpha channels
bool mSeparateBlend;
SceneBlendFactor mSourceBlendFactor;
SceneBlendFactor mDestBlendFactor;
SceneBlendFactor mSourceBlendFactorAlpha;
SceneBlendFactor mDestBlendFactorAlpha;
// Blending operations
SceneBlendOperation mBlendOperation;
SceneBlendOperation mBlendOperationAlpha;
HlmsBlendblock();
/// Shortcut to set the blend factors to common blending operations.
/// Sets both blend and alpha to the same value and mSeparateBlend is
/// turned off.
void setBlendType( SceneBlendType blendType );
/// Shortcut to set the blend factors to common blending operations.
/// Sets colour and alpha individually, turns mSeparateBlend on.
void setBlendType( SceneBlendType colour, SceneBlendType alpha );
/// Sets mSeparateBlend to true or false based on current settings
void calculateSeparateBlendMode();
/** Sometimes you want to force the RenderQueue to render back to front even if
the object isn't alpha blended (e.g. you're rendering refractive materials)
@param bForceTransparent
True to always render back to front, like any transparent.
False for default behavior (opaque objects are rendered front to back, alpha
blended objects are rendered back to front)
*/
void setForceTransparentRenderOrder( bool bForceTransparent );
bool isAutoTransparent( void ) const { return ( mIsTransparent & 0x01u ) != 0u; }
bool isForcedTransparent( void ) const { return ( mIsTransparent & 0x02u ) != 0u; }
bool operator == ( const HlmsBlendblock &_r ) const
{
return !(*this != _r);
}
bool operator != ( const HlmsBlendblock &_r ) const
{
// Don't include the ID in the comparision
// AND ignore alpha blend factors when not doing separate blends
// AND don't include mIsTransparent's first bit, which is filled
// automatically only for some managed objects.
return mAllowGlobalDefaults != _r.mAllowGlobalDefaults ||
mSeparateBlend != _r.mSeparateBlend ||
mSourceBlendFactor != _r.mSourceBlendFactor ||
mDestBlendFactor != _r.mDestBlendFactor ||
( mSeparateBlend &&
( mSourceBlendFactorAlpha != _r.mSourceBlendFactorAlpha ||
mDestBlendFactorAlpha != _r.mDestBlendFactorAlpha ) ) ||
mBlendOperation != _r.mBlendOperation ||
mBlendOperationAlpha != _r.mBlendOperationAlpha ||
mAlphaToCoverageEnabled != _r.mAlphaToCoverageEnabled ||
mBlendChannelMask != _r.mBlendChannelMask ||
(mIsTransparent & 0x02u) != (_r.mIsTransparent & 0x02u);
}
};
class _OgreExport HlmsTextureExportListener
{
public:
/// Gives you a chance to completely change the name of the texture when saving a material
virtual void savingChangeTextureNameOriginal( const String &aliasName,
String &inOutResourceName,
String &inOutFilename ) {}
virtual void savingChangeTextureNameOitd( String &inOutFilename, TextureGpu *texture ) {}
};
/** An hlms datablock contains individual information about a specific material. It consists of:
* A const pointer to an @HlmsMacroblock we do not own and may be shared by other datablocks.
* A const pointer to an @HlmsBlendblock we do not own and may be shared by other datablocks.
* The original properties from which this datablock was constructed.
* This type may be derived to contain additional information.
Derived types can cache information present in mOriginalProperties as strings, like diffuse
colour values, etc.
A datablock is the internal representation of the surface parameters (depth settings,
textures to be used, diffuse colour, specular colour, etc).
The notion of a datablock is the closest you'll get to a "material"
@remarks
Macro- & Blendblocks are immutable, hence const pointers. Trying to const cast these
pointers in order to modify them may work on certain RenderSystems (i.e. GLES2) but
will seriously break on other RenderSystems (i.e. D3D11).
@par
If you need to change a macroblock, create a new one (HlmsManager keeps them cached
if already created) and change the entire pointer.
@par
Each datablock has a pair of macroblocks and blendblocks. One of is for the regular passes,
the other is for shadow mapping passes, since often you don't want them to be the same.
Shadow mapping often wants to reverse culling (@see HlmsManager::setShadowMappingUseBackFaces)
or use some depth bias. As for blendblocks, with transparent objects you may want to
turn off alpha blending, but enable alpha testing instead.
*/
class _OgreExport HlmsDatablock : public PassAlloc
{
friend class RenderQueue;
protected:
//Non-hot variables first (can't put them last as HlmsDatablock may be derived and
//it's better if mShadowConstantBias is together with the derived type's variables
/// List of renderables currently using this datablock
vector<Renderable*>::type mLinkedRenderables;
Hlms *mCreator;
IdString mName;
/** Updates the mHlmsHash & mHlmsCasterHash for all linked renderables, which may have
if a sensitive setting has changed that would need a different shader to be created
@remarks
The operation itself isn't expensive, but the need to call this function indicates
that another shader will be created (unless already cached too). If so, doing that
will be slow.
@param onlyNullHashes
When true, we will only flush those that had null Hlms hash, which means
calculateHashFor was never called on this Datablock, or more likely calculateHashFor
delayed the calculation for later.
This can happen if an object was delayed for later due to the textures not being
ready, but when they are, turns out nothing needs to be changed, yet the hashes
are null and thus those renderables need to be flushed.
*/
void flushRenderables( bool onlyNullHashes=false );
void updateMacroblockHash( bool casterPass );
public:
uint32 mTextureHash; //TextureHash comes before macroblock for alignment reasons
uint16 mMacroblockHash[2]; //Not all bits are used
uint8 mType; /// @See HlmsTypes
protected:
HlmsMacroblock const *mMacroblock[2];
HlmsBlendblock const *mBlendblock[2];
public:
/// When false, we won't try to have Textures become resident
bool mAllowTextureResidencyChange;
protected:
bool mIgnoreFlushRenderables;
uint8 mAlphaTestCmp; /// @see CompareFunction
bool mAlphaTestShadowCasterOnly;
float mAlphaTestThreshold;
public:
float mShadowConstantBias;
public:
HlmsDatablock( IdString name, Hlms *creator,
const HlmsMacroblock *macroblock,
const HlmsBlendblock *blendblock,
const HlmsParamVec ¶ms );
virtual ~HlmsDatablock();
/** Creates a copy of this datablock with the same settings, but a different name.
@param name
Name of the cloned datablock.
*/
HlmsDatablock* clone( String name ) const;
/// Calculates the hashes needed for sorting by the RenderQueue (i.e. mTextureHash)
virtual void calculateHash() {}
IdString getName(void) const { return mName; }
Hlms* getCreator(void) const { return mCreator; }
/** Sets a new macroblock that matches the same parameter as the input.
Decreases the reference count of the previously set one.
Runs an O(N) search to get the right block.
Calling this function triggers a HlmsDatablock::flushRenderables
@param macroblock
@See HlmsManager::getMacroblock
@param casterBlock
True to directly set the macroblock to be used during the shadow mapping's caster pass.
Note that when false, it will automatically reset the caster's block according to
HlmsManager::setShadowMappingUseBackFaces setting.
*/
void setMacroblock( const HlmsMacroblock ¯oblock, bool casterBlock = false );
/** Sets the macroblock from the given pointer that was already
retrieved from the HlmsManager. Unlike the other overload,
this operation is O(1).
Calling this function triggers a HlmsDatablock::flushRenderables
@param macroblock
A valid block. The reference count is increased inside this function.
@param casterBlock
True to directly set the macroblock to be used during the shadow mapping's caster pass.
Note that when false, it will automatically reset the caster's block according to
HlmsManager::setShadowMappingUseBackFaces setting.
*/
void setMacroblock( const HlmsMacroblock *macroblock, bool casterBlock = false );
/** Sets a new blendblock that matches the same parameter as the input.
Decreases the reference count of the previous mBlendblock.
Runs an O(N) search to get the right block.
Calling this function triggers a HlmsDatablock::flushRenderables
@param blendblock
@See HlmsManager::getBlendblock
@param casterBlock
True to directly set the blendblock to be used during the shadow mapping's caster pass.
Note that when false, it will reset the caster block to the same as the regular one.
*/
void setBlendblock( const HlmsBlendblock &blendblock, bool casterBlock = false );
/** Sets the blendblock from the given pointer that was already
retrieved from the HlmsManager. Unlike the other overload,
this operation is O(1).
Calling this function triggers a HlmsDatablock::flushRenderables
@param blendblock
A valid block. The reference count is increased inside this function.
@param casterBlock
True to directly set the blendblock to be used during the shadow mapping's caster pass.
Note that when false, it will reset the caster block to the same as the regular one.
*/
void setBlendblock( const HlmsBlendblock *blendblock, bool casterBlock = false );
const HlmsMacroblock* getMacroblock( bool casterBlock=false ) const
{ return mMacroblock[casterBlock]; }
const HlmsBlendblock* getBlendblock( bool casterBlock=false ) const
{ return mBlendblock[casterBlock]; }
/** Sets the alpha test to the given compare function. CMPF_ALWAYS_PASS means disabled.
@see mAlphaTestThreshold.
Calling this function triggers a HlmsDatablock::flushRenderables
@remarks
It is to the derived implementation to actually implement the alpha test.
@param compareFunction
Compare function to use. Default is CMPF_ALWAYS_PASS, which means disabled.
Note: CMPF_ALWAYS_FAIL is not supported. Set a negative threshold to
workaround this issue.
@param shadowCasterOnly
When true, only the caster should use alpha testing.
Useful if you want alpha blending (i.e. transparency) while rendering normally,
but want semi-transparent shadows.
@param useAlphaFromTextures
Whether you want the diffuse texture's alpha to influence the alpha test
Most likely you want this to be true, unless you're customizing the
shader and have special use for alpha testing
*/
virtual void setAlphaTest( CompareFunction compareFunction, bool shadowCasterOnly = false,
bool useAlphaFromTextures = true );
CompareFunction getAlphaTest(void) const;
bool getAlphaTestShadowCasterOnly(void) const;
/** Alpha test's threshold. @see setAlphaTest
@param threshold
Value typically in the range [0; 1)
*/
virtual void setAlphaTestThreshold( float threshold );
float getAlphaTestThreshold(void) const { return mAlphaTestThreshold; }
/// @see Hlms::getNameStr. This operations is NOT fast. Might return null
/// (if the datablock was removed from the Hlms but somehow is still alive)
const String* getNameStr(void) const;
/// @see Hlms::getFilenameAndResourceGroup. This operations is NOT fast. Might return
/// null (if the datablock was removed from the Hlms but somehow is still alive)
/// Usage:
/// String const *filename;
/// String const *resourceGroup;
/// datablock->getFilenameAndResourceGroup( &filename, &resourceGroup );
/// if( filename && resourceGroup && !filename->empty() && !resourceGroup->empty() )
/// {
/// //Valid filename & resource group.
/// }
void getFilenameAndResourceGroup( String const * *outFilename,
String const * *outResourceGroup ) const;
void _linkRenderable( Renderable *renderable );
void _unlinkRenderable( Renderable *renderable );
const vector<Renderable*>::type& getLinkedRenderables(void) const { return mLinkedRenderables; }
/// Tells datablock to start loading all of its textures (if not loaded already)
/// and any other resource it may need.
///
/// Useful to cut loading times by anticipating what the user will do.
///
/// Do not call this function aggressively (e.g. for lots of material every frame)
virtual void preload();
virtual bool hasCustomShadowMacroblock(void) const;
/// Returns the closest match for a diffuse colour,
/// if applicable by the actual implementation.
///
/// Note that Unlit implementation returns 0 as diffuse, since it's considered
/// emissive instead due to being bright even in the absence lights.
virtual ColourValue getDiffuseColour(void) const;
/// Returns the closest match for a emissive colour,
/// if applicable by the actual implementation.
/// See HlmsDatablock::getDiffuseColour
virtual ColourValue getEmissiveColour(void) const;
/// Returns the closest match for a diffuse texture,
/// if applicable by the actual implementation.
/// See HlmsDatablock::getDiffuseColour
virtual TextureGpu* getDiffuseTexture(void) const;
/// Returns the closest match for a emissive texture,
/// if applicable by the actual implementation.
/// See HlmsDatablock::getDiffuseColour
virtual TextureGpu* getEmissiveTexture(void) const;
/**
@remarks
It's possible to set both saveOitd & saveOriginal to true, but will likely double
storage requirements (2x as many textures). Setting both to true is useful
for troubleshooting obscure Ogre bugs.
@param folderPath
Folder where to dump the textures.
@param savedTextures [in/out]
Set of texture names. Textures whose name is already in the set won't be saved again.
Textures that were saved will be inserted into the set.
@param saveOitd
When true, we will download the texture from GPU and save it in OITD format.
OITD is faster to load as it's stored in Ogre's native format it understands,
but it cannot be opened by traditional image editors; also OITD is not backwards
compatible with older versions of Ogre.
@param saveOriginal
When true, we will attempt to read the raw filestream of the original texture
and save it (i.e. copy the original png/dds/etc file).
*/
virtual void saveTextures( const String &folderPath, set<String>::type &savedTextures,
bool saveOitd, bool saveOriginal,
HlmsTextureExportListener *listener );
static const char* getCmpString( CompareFunction compareFunction );
protected:
virtual void cloneImpl( HlmsDatablock *datablock ) const {};
};
/** @} */
/** @} */
}
#include "OgreHeaderSuffix.h"
#endif