2020-01-03 20:05:16 +01:00
|
|
|
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
|
|
|
// This file is part of the "Irrlicht Engine".
|
|
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
|
2021-08-27 21:20:42 +02:00
|
|
|
#ifndef S_MATERIAL_LAYER_H_INCLUDED
|
|
|
|
#define S_MATERIAL_LAYER_H_INCLUDED
|
2020-01-03 20:05:16 +01:00
|
|
|
|
|
|
|
#include "matrix4.h"
|
|
|
|
#include "irrAllocator.h"
|
|
|
|
|
|
|
|
namespace irr
|
|
|
|
{
|
|
|
|
namespace video
|
|
|
|
{
|
|
|
|
class ITexture;
|
|
|
|
|
|
|
|
//! Texture coord clamp mode outside [0.0, 1.0]
|
|
|
|
enum E_TEXTURE_CLAMP
|
|
|
|
{
|
|
|
|
//! Texture repeats
|
|
|
|
ETC_REPEAT = 0,
|
|
|
|
//! Texture is clamped to the last pixel
|
|
|
|
ETC_CLAMP,
|
|
|
|
//! Texture is clamped to the edge pixel
|
|
|
|
ETC_CLAMP_TO_EDGE,
|
|
|
|
//! Texture is clamped to the border pixel (if exists)
|
|
|
|
ETC_CLAMP_TO_BORDER,
|
|
|
|
//! Texture is alternatingly mirrored (0..1..0..1..0..)
|
|
|
|
ETC_MIRROR,
|
|
|
|
//! Texture is mirrored once and then clamped (0..1..0)
|
|
|
|
ETC_MIRROR_CLAMP,
|
|
|
|
//! Texture is mirrored once and then clamped to edge
|
|
|
|
ETC_MIRROR_CLAMP_TO_EDGE,
|
|
|
|
//! Texture is mirrored once and then clamped to border
|
|
|
|
ETC_MIRROR_CLAMP_TO_BORDER
|
|
|
|
};
|
|
|
|
static const char* const aTextureClampNames[] = {
|
|
|
|
"texture_clamp_repeat",
|
|
|
|
"texture_clamp_clamp",
|
|
|
|
"texture_clamp_clamp_to_edge",
|
|
|
|
"texture_clamp_clamp_to_border",
|
|
|
|
"texture_clamp_mirror",
|
|
|
|
"texture_clamp_mirror_clamp",
|
|
|
|
"texture_clamp_mirror_clamp_to_edge",
|
|
|
|
"texture_clamp_mirror_clamp_to_border", 0};
|
|
|
|
|
|
|
|
//! Struct for holding material parameters which exist per texture layer
|
2023-05-05 21:28:40 +02:00
|
|
|
// Note for implementers: Serialization is in CNullDriver
|
2020-01-03 20:05:16 +01:00
|
|
|
class SMaterialLayer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
//! Default constructor
|
|
|
|
SMaterialLayer() : Texture(0), TextureWrapU(ETC_REPEAT), TextureWrapV(ETC_REPEAT), TextureWrapW(ETC_REPEAT),
|
2023-05-13 14:25:10 +02:00
|
|
|
BilinearFilter(true), TrilinearFilter(false), AnisotropicFilter(0), LODBias(0),
|
|
|
|
TextureMatrix(0), TextureMatrixUsed(false)
|
2020-01-03 20:05:16 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Copy constructor
|
|
|
|
/** \param other Material layer to copy from. */
|
|
|
|
SMaterialLayer(const SMaterialLayer& other)
|
|
|
|
{
|
|
|
|
// This pointer is checked during assignment
|
|
|
|
TextureMatrix = 0;
|
|
|
|
*this = other;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Destructor
|
|
|
|
~SMaterialLayer()
|
|
|
|
{
|
|
|
|
if ( TextureMatrix )
|
|
|
|
{
|
|
|
|
MatrixAllocator.destruct(TextureMatrix);
|
|
|
|
MatrixAllocator.deallocate(TextureMatrix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Assignment operator
|
|
|
|
/** \param other Material layer to copy from.
|
|
|
|
\return This material layer, updated. */
|
|
|
|
SMaterialLayer& operator=(const SMaterialLayer& other)
|
|
|
|
{
|
|
|
|
// Check for self-assignment!
|
|
|
|
if (this == &other)
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
Texture = other.Texture;
|
2023-05-13 14:25:10 +02:00
|
|
|
if (other.TextureMatrixUsed)
|
2020-01-03 20:05:16 +01:00
|
|
|
{
|
2023-05-13 14:25:10 +02:00
|
|
|
if (TextureMatrix)
|
|
|
|
{
|
2020-01-03 20:05:16 +01:00
|
|
|
*TextureMatrix = *other.TextureMatrix;
|
2023-05-13 14:25:10 +02:00
|
|
|
}
|
2020-01-03 20:05:16 +01:00
|
|
|
else
|
|
|
|
{
|
2023-05-13 14:25:10 +02:00
|
|
|
TextureMatrix = MatrixAllocator.allocate(1);
|
|
|
|
MatrixAllocator.construct(TextureMatrix,*other.TextureMatrix);
|
2020-01-03 20:05:16 +01:00
|
|
|
}
|
2023-05-13 14:25:10 +02:00
|
|
|
TextureMatrixUsed = true;
|
2020-01-03 20:05:16 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-05-13 14:25:10 +02:00
|
|
|
TextureMatrixUsed = false;
|
2020-01-03 20:05:16 +01:00
|
|
|
}
|
|
|
|
TextureWrapU = other.TextureWrapU;
|
|
|
|
TextureWrapV = other.TextureWrapV;
|
|
|
|
TextureWrapW = other.TextureWrapW;
|
|
|
|
BilinearFilter = other.BilinearFilter;
|
|
|
|
TrilinearFilter = other.TrilinearFilter;
|
|
|
|
AnisotropicFilter = other.AnisotropicFilter;
|
|
|
|
LODBias = other.LODBias;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Gets the texture transformation matrix
|
|
|
|
/** \return Texture matrix of this layer. */
|
|
|
|
core::matrix4& getTextureMatrix()
|
|
|
|
{
|
|
|
|
if (!TextureMatrix)
|
|
|
|
{
|
|
|
|
TextureMatrix = MatrixAllocator.allocate(1);
|
|
|
|
MatrixAllocator.construct(TextureMatrix,core::IdentityMatrix);
|
2023-05-13 14:25:10 +02:00
|
|
|
TextureMatrixUsed = true;
|
|
|
|
}
|
|
|
|
else if ( !TextureMatrixUsed )
|
|
|
|
{
|
|
|
|
*TextureMatrix = core::IdentityMatrix;
|
|
|
|
TextureMatrixUsed = true;
|
2020-01-03 20:05:16 +01:00
|
|
|
}
|
|
|
|
return *TextureMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Gets the immutable texture transformation matrix
|
|
|
|
/** \return Texture matrix of this layer. */
|
|
|
|
const core::matrix4& getTextureMatrix() const
|
|
|
|
{
|
2023-05-13 14:25:10 +02:00
|
|
|
if (TextureMatrixUsed)
|
2020-01-03 20:05:16 +01:00
|
|
|
return *TextureMatrix;
|
|
|
|
else
|
|
|
|
return core::IdentityMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Sets the texture transformation matrix to mat
|
|
|
|
/** NOTE: Pipelines can ignore this matrix when the
|
|
|
|
texture is 0.
|
|
|
|
\param mat New texture matrix for this layer. */
|
|
|
|
void setTextureMatrix(const core::matrix4& mat)
|
|
|
|
{
|
|
|
|
if (!TextureMatrix)
|
|
|
|
{
|
|
|
|
TextureMatrix = MatrixAllocator.allocate(1);
|
|
|
|
MatrixAllocator.construct(TextureMatrix,mat);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*TextureMatrix = mat;
|
2023-05-13 14:25:10 +02:00
|
|
|
TextureMatrixUsed = true;
|
2020-01-03 20:05:16 +01:00
|
|
|
}
|
|
|
|
|
2023-05-05 21:28:40 +02:00
|
|
|
//! Check if we have set a custom texture matrix
|
|
|
|
//! Note that otherwise we get an IdentityMatrix as default
|
|
|
|
inline bool hasSetTextureMatrix() const
|
|
|
|
{
|
2023-05-13 14:25:10 +02:00
|
|
|
return TextureMatrixUsed;
|
2023-05-05 21:28:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Reset texture matrix to identity matrix
|
2023-05-13 14:25:10 +02:00
|
|
|
/** \param releaseMemory Releases also texture memory. Otherwise done in destructor */
|
|
|
|
void resetTextureMatrix(bool releaseMemory=true)
|
2023-05-05 21:28:40 +02:00
|
|
|
{
|
2023-05-13 14:25:10 +02:00
|
|
|
if ( TextureMatrix && releaseMemory)
|
2023-05-05 21:28:40 +02:00
|
|
|
{
|
|
|
|
MatrixAllocator.destruct(TextureMatrix);
|
|
|
|
MatrixAllocator.deallocate(TextureMatrix);
|
|
|
|
TextureMatrix = 0;
|
|
|
|
}
|
2023-05-13 14:25:10 +02:00
|
|
|
TextureMatrixUsed = false;
|
2023-05-05 21:28:40 +02:00
|
|
|
}
|
|
|
|
|
2020-01-03 20:05:16 +01:00
|
|
|
//! Inequality operator
|
|
|
|
/** \param b Layer to compare to.
|
|
|
|
\return True if layers are different, else false. */
|
|
|
|
inline bool operator!=(const SMaterialLayer& b) const
|
|
|
|
{
|
|
|
|
bool different =
|
|
|
|
Texture != b.Texture ||
|
|
|
|
TextureWrapU != b.TextureWrapU ||
|
|
|
|
TextureWrapV != b.TextureWrapV ||
|
|
|
|
TextureWrapW != b.TextureWrapW ||
|
|
|
|
BilinearFilter != b.BilinearFilter ||
|
|
|
|
TrilinearFilter != b.TrilinearFilter ||
|
|
|
|
AnisotropicFilter != b.AnisotropicFilter ||
|
|
|
|
LODBias != b.LODBias;
|
|
|
|
if (different)
|
|
|
|
return true;
|
|
|
|
else
|
2023-05-13 14:25:10 +02:00
|
|
|
{
|
|
|
|
different = (TextureMatrixUsed && b.TextureMatrixUsed && (*TextureMatrix != *b.TextureMatrix))
|
|
|
|
|| (TextureMatrixUsed && !b.TextureMatrixUsed && (*TextureMatrix != core::IdentityMatrix))
|
|
|
|
|| (!TextureMatrixUsed && b.TextureMatrixUsed && (core::IdentityMatrix != *b.TextureMatrix));
|
|
|
|
}
|
2020-01-03 20:05:16 +01:00
|
|
|
return different;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Equality operator
|
|
|
|
/** \param b Layer to compare to.
|
|
|
|
\return True if layers are equal, else false. */
|
|
|
|
inline bool operator==(const SMaterialLayer& b) const
|
|
|
|
{ return !(b!=*this); }
|
|
|
|
|
|
|
|
//! Texture
|
|
|
|
ITexture* Texture;
|
|
|
|
|
|
|
|
//! Texture Clamp Mode
|
|
|
|
/** Values are taken from E_TEXTURE_CLAMP. */
|
|
|
|
u8 TextureWrapU:4;
|
|
|
|
u8 TextureWrapV:4;
|
|
|
|
u8 TextureWrapW:4;
|
|
|
|
|
|
|
|
//! Is bilinear filtering enabled? Default: true
|
|
|
|
bool BilinearFilter:1;
|
|
|
|
|
|
|
|
//! Is trilinear filtering enabled? Default: false
|
|
|
|
/** If the trilinear filter flag is enabled,
|
|
|
|
the bilinear filtering flag is ignored. */
|
|
|
|
bool TrilinearFilter:1;
|
|
|
|
|
|
|
|
//! Is anisotropic filtering enabled? Default: 0, disabled
|
|
|
|
/** In Irrlicht you can use anisotropic texture filtering
|
|
|
|
in conjunction with bilinear or trilinear texture
|
|
|
|
filtering to improve rendering results. Primitives
|
|
|
|
will look less blurry with this flag switched on. The number gives
|
|
|
|
the maximal anisotropy degree, and is often in the range 2-16.
|
|
|
|
Value 1 is equivalent to 0, but should be avoided. */
|
|
|
|
u8 AnisotropicFilter;
|
|
|
|
|
|
|
|
//! Bias for the mipmap choosing decision.
|
|
|
|
/** This value can make the textures more or less blurry than with the
|
|
|
|
default value of 0. The value (divided by 8.f) is added to the mipmap level
|
|
|
|
chosen initially, and thus takes a smaller mipmap for a region
|
|
|
|
if the value is positive. */
|
|
|
|
s8 LODBias;
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class SMaterial;
|
|
|
|
irr::core::irrAllocator<irr::core::matrix4> MatrixAllocator;
|
|
|
|
|
|
|
|
//! Texture Matrix
|
|
|
|
/** Do not access this element directly as the internal
|
|
|
|
resource management has to cope with Null pointers etc. */
|
|
|
|
core::matrix4* TextureMatrix;
|
2023-05-13 14:25:10 +02:00
|
|
|
bool TextureMatrixUsed; // TextureMatrix memory stays until destructor even when unused to avoid unnecessary allocation/de-allocations
|
2020-01-03 20:05:16 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // end namespace video
|
|
|
|
} // end namespace irr
|
|
|
|
|
2021-08-27 21:20:42 +02:00
|
|
|
#endif // S_MATERIAL_LAYER_H_INCLUDED
|