CathodeRetro::Internal::RGBToCRT
This is an internal class used by CathodeRetro::
to take an RGB image and draw it to a render target to look like it is on a CRT TV.
If you are using the CathodeRetro::
class, you should not need to use this class directly.
Public Members
Public Methods
Public Methods
- (constructor)
-
RGBToCRT( IGraphicsDevice *deviceIn, uint32_t originalInputImageWidthIn, uint32_t processedRGBTextureWidthIn, uint32_t scanlineCountIn, float pixelAspectIn)
Description
Construct a new instance of the Internal::
class.RGBToCRT Parameters
deviceIn
-
Type:
IGraphicsDevice *
Pointer to the graphics device instance that this instance should use for all of its drawing-related functionality. This pointer will be cached so the lifetime of
deviceIn
must extend past the lifetime of theInternal::
instance being created.RGBToCRT originalInputImageWidthIn
-
Type:
uint32_t
The width of the original input image (the one passed to
CathodeRetro::
), before running through the generator and decoder.Render processedRGBTextureWidthIn
-
Type:
uint32_t
The width of the input texture that
Render
will be provided. scanlineCountIn
-
Type:
uint32_t
The height of the input texture that
Render
will be provided. pixelAspectIn
-
Type:
float
The pixel aspect ratio of the input signal (relative to the original input). This value comes from the
SignalProperties
given to theCathodeRetro
class.
- SetSettings
-
void SetSettings( const OverscanSettings &overscan, const ScreenSettings &screen)
Description
Set the settings that describe how the screen should appear. Parameters
overscan
-
Type:
const OverscanSettings &
A description of how much the various edges of the input image are cut off by the "bevel" of the TV.
screen
-
Type:
const ScreenSettings &
Information about the properties of the screen itself.
- SetOutputSize
-
void SetOutputSize( uint32_t outputWidth, uint32_t outputHeight)
Description
Set the size of the final output render target that
CathodeRetro::
will be given.Render If the width or height change from what they were before, this will reallocate a render target.
Parameters
outputWidth
-
Type:
uint32_t
The expected width of the final output render target that
CathodeRetro::
will be given.Render outputHeight
-
Type:
uint32_t
The expected height of the final output render target that
CathodeRetro::
will be given.Render
- Render
-
void Render( const ITexture *currentFrameRGBInput, IRenderTarget *outputTexture, ScanlineType scanType)
Description
Render a CRT TV emulation pass using the input texture as what is on-screen. Parameters
currentFrameRGBInput
-
Type:
const ITexture *
The input RGB frame data, representing what is "on-screen."
Its dimensions are expected to match the
processedRGBTextureWidthIn
(width) andscanlineCountIn
(height) values that were passed to the constructor. outputTexture
-
Type:
IRenderTarget *
The texture that the result of this rendering will be rendered to.
Its dimensions are expected to match the
outputWidth
andoutputHeight
values passed to the most-recent call toSetOutputSize
. scanType
-
Type:
ScanlineType
Which type of scanlines to render for this frame (even or odd).
Private Members
Private Constants
Private Structures
Private Methods
Private Fields
Private Constants
- k_maskSize
-
static constexpr uint32_t k_maskSize = 512
Description
The horizontal resolution of maskTexture
, the
texture that the CRT mask is rendered to.
The vertical resolution of the texture is half this value.
Given the small scale of the mask in the render output, this value is - in practice - wildly overkill, but
it downsamples to the mipmaps very well.
Private Structures
- AspectData
-
Description
Information generated by CalculateAspectData
with some
commonly-calculated aspect-related values.
Fields
overscanSize
-
Type: Vec2
This contains (as an x, y vector) the width and height of the original (pre-generation/decode) image (the original
source RGB image), minus the amount of overscan specified by overscanSettings
.
aspect
-
Type: float
This value represents the actual aspect ratio (width / height) of the screen, taking into account both the above
overscanSize
value and pixelAspect
.
- CommonConstants
-
Description
This contains the initial values for both ScreenTextureConstants
and RGBToScreenConstants
.
These values correspond to the initial four input constant values in the crt-generate-screen-texture
and crt-rgb-to-crt shaders. Refer to those pages for documentation of the fields.
- ScreenTextureConstants
-
Description
This structure maps to the constant buffer input to the crt-generate-screen-texture
shader. Refer to its page for documentation of the fields.
- RGBToScreenConstants
-
Description
This structure maps to the constant buffer input to the crt-rgb-to-crt
shader. Refer to its page for documentation of the fields.
- GaussianBlurConstants
-
Description
This structure maps to the constant buffer input to the util-gaussian-blur
shader. Refer to its page for documentation of the fields.
- ToneMapConstants
-
Description
This structure maps to the constant buffer input to the util-tonemap-and-downsample
shader. Refer to its page for documentation of the fields.
Private Methods
- CalculateAspectData
-
AspectData CalculateAspectData()
Description
Calculates the dimensions of the original (pre-generation/decode) input texture would have
after overscan is applied, as well as the aspect ratio of the full image.
Called by
CalculateCommonConstants
,
RenderScreenTexture
,
and UpdateBlurTextures
.
Return Value
Type: RGBToCRT::AspectData
The calculated data.
- CalculateCommonConstants
-
CommonConstants CalculateCommonConstants(
const AspectData &aspectData)
Description
Calculate some values that are common to both
RGBToCRT::ScreenTextureConstants
and
RGBToCRT::RGBToScreenConstants
.
Called by
Render
and RenderScreenTexture
.
Parameters
aspectData
-
Type: const RGBToCRT::AspectData &
The output of a call to CalculateAspectData
.
Return Value
Type: RGBToCRT::CommonConstants
The calculated constants.
- RenderScreenTexture
-
void RenderScreenTexture()
Description
Renders to screenTexture
, which contains an image that
has the CRT mask (with proper curvature applied) in the RGB channels and a mask of what is or is not
visible on the screen in the alpha channel.
It's worth noting that the shader that renders this does a very expensive 64-tap sample of the mask
texture to alleviate aliasing,
so the RGBToCRT
does a fair amount of work to only do this when necessary (after a call to
SetSettings
or SetOutputSize
in which the values were changed).
Called by Render
.
- UpdateBlurTextures
-
void UpdateBlurTextures()
Description
Calculates the required sizes for
toneMapTexture
,
blurTexture
,
and blurScratchTexture
.
Then, if the sizes are different from the existing versions of those textures,
will create new textures at the proper size.
Called by the constructor and SetSettings
.
- RenderMaskTexture
-
void RenderMaskTexture()
Description
Renders a mask to maskTexture
, given the
MaskType
value
stored in screenSettings
.
This uses a lanczos downsample pass to generate the mipmap levels.
This is only called after a call to
SetSettings
or SetOutputSize
in which the values were changed.
Called by Render
.
- RenderBlur
-
void RenderBlur(
const ITexture *inputTexture)
Description
Does a tonemap and blur of the given input texture, which is used as an approximation of CRT diffusion
(the scattering of photons as they pass through the glass front of the CRT screen).
Called by Render
.
Parameters
inputTexture
-
Type: const ITexture *
The texture to tonemap and then blur.
Private Fields
- device
-
IGraphicsDevice *device
Type
IGraphicsDevice *
Description
Pointer to the graphics device that should be used to create graphics objects and render.
- originalInputImageWidth
-
uint32_t originalInputImageWidth
Type
uint32_t
Description
The width of the original image (before the generator/decoder process).
- processedRGBTextureWidth
-
uint32_t processedRGBTextureWidth
Type
uint32_t
Description
The expected width of the texture that will be passed in to Render
.
If no generator/decoder process is being used (i.e. if the CathodeRetro
class
is being used in RGB mode, this will be the same value as
originalInputImageWidth
.
- scanlineCount
-
uint32_t scanlineCount
Type
uint32_t
Description
The number of scanlines per input image (i.e. the height of the input texture).
- pixelAspect
-
float pixelAspect
Type
float
Description
The aspect ratio (width/height) of an input pixel (pre-generator/decoder) on the screen.
This allows for emulation of non-square-pixel video modes.
For example:
- On the NES, pixels were slightly stretched horizontally and have an 8:7 (8/7) aspect ratio.
-
Old mode 13h
modes had slightly tall pixels on 4x3 monitors, resulting in pixels that are 5:6.
- isFirstFrame
-
bool isFirstFrame = true
Type
bool
Description
This is true before Render
is called the first time,
and false afterward.
Because this class keeps a copy of the previous frame (in prevRGBInput
)
and uses that to handle phosphor persistence, on the very first call to Render
this flag is used
to initialize prevRGBInput
so that it can be used.
- screenTextureConstantBuffer
-
std::unique_ptr<IConstantBuffer> screenTextureConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderScreenTexture
as an input to the
crt-generate-screen-texture
shader.
- rgbToScreenConstantBuffer
-
std::unique_ptr<IConstantBuffer> rgbToScreenConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in Render
as an input to the
crt-rgb-to-crt
shader.
- toneMapConstantBuffer
-
std::unique_ptr<IConstantBuffer> toneMapConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderBlur
as an input to the
util-tonemap-and-downsample
shader.
- blurDownsampleConstantBuffer
-
std::unique_ptr<IConstantBuffer> blurDownsampleConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderBlur
as an input to the
util-downsample-2x
shader, to do a horizontal downsample before the blurring.
- gaussianBlurConstantBufferH
-
std::unique_ptr<IConstantBuffer> gaussianBlurConstantBufferH
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderBlur
as an input to the
util-gaussian-blur
shader, to do the horizontal blur pass.
- gaussianBlurConstantBufferV
-
std::unique_ptr<IConstantBuffer> gaussianBlurConstantBufferV
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderBlur
as an input to the
util-gaussian-blur
shader, to do the vertical blur pass.
- generateMaskConstantBuffer
-
std::unique_ptr<IConstantBuffer> generateMaskConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderMaskTexture
as an input to one of the
crt-generate-shadow-mask,
crt-generate-slot-mask,
or crt-generate-aperture-grille
shaders (depending on the value of screenSettings.maskType
)
to generate the largest mip level of maskTexture
.
- maskDownsampleConstantBufferH
-
std::unique_ptr<IConstantBuffer> maskDownsampleConstantBufferH
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderMaskTexture
as an input to the util-downsample-2x
shader to do the horizontal downsample into a scratch texture (halfWidthMaskTexture
)
during the generation of the mipmaps of maskTexture
.
- maskDownsampleConstantBufferV
-
std::unique_ptr<IConstantBuffer> maskDownsampleConstantBufferV
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used in RenderMaskTexture
as an input to the util-downsample-2x
shader to do the vertical downsample from the scratch texture (halfWidthMaskTexture
),
during the generation of the mipmaps of maskTexture
.
- prevRGBInput
-
std::unique_ptr<IRenderTarget> prevRGBInput
Type
std::unique_ptr<IRenderTarget>
Description
This texture is a copy of the currentFrameRGBInput
parameter that was passed to the previous call
to Render
, and is used to emulate phosphor persistence (where a little of the previous frame
is still visible).
- maskTexture
-
std::unique_ptr<IRenderTarget> maskTexture
Type
std::unique_ptr<IRenderTarget>
Description
This is a mipmapped texture, which holds the CRT mask texture that we use to generate the screen texture.
It is generated by RenderMaskTexture
whenever
the value of value of screenSettings.maskType
changes.
- halfWidthMaskTexture
-
std::unique_ptr<IRenderTarget> halfWidthMaskTexture
Type
std::unique_ptr<IRenderTarget>
Description
This is an intermediate texture used during the generation of mipmap levels in RenderMaskTexture
.
It has the same height as maskTexture
but has half the width, and is used as
the target for the horizontal pass of the downsample.
- screenTexture
-
std::unique_ptr<IRenderTarget> screenTexture
Type
std::unique_ptr<IRenderTarget>
Description
This texture has an image that has the CRT mask (with proper curvature applied) in the RGB channels and a
mask of what is or is not visible on the screen in the alpha channel. It is generated by
RenderScreenTexture
. It has the same width and height as
the final output texture of the Render
method.
- toneMapTexture
-
std::unique_ptr<IRenderTarget> toneMapTexture
Type
std::unique_ptr<IRenderTarget>
Description
This texture is the target of the first pass of RenderBlur
,
which does the tonemapping (and also a resize to get closer to the desired blur resolution).
- blurScratchTexture
-
std::unique_ptr<IRenderTarget> blurScratchTexture
Type
std::unique_ptr<IRenderTarget>
Description
This texture is the target of the second and fourth passes of RenderBlur
(and is the ultimate result of that method), and ultimately contains the blurred version of the input texture
that is used to emulate CRT diffusion (the scattering of photons as they pass through the glass front of the CRT screen).
- blurTexture
-
std::unique_ptr<IRenderTarget> blurTexture
Type
std::unique_ptr<IRenderTarget>
Description
This texture is the target of the third pass of RenderBlur
,
which is the horizontal gaussian blur pass. It is then used in the final pass to do the vertical blur
to get the final result.
- screenSettings
-
ScreenSettings screenSettings
Type
ScreenSettings
Description
The screen settings that were applied by SetSettings
.
- overscanSettings
-
OverscanSettings overscanSettings
Type
OverscanSettings
Description
The overscan settings that were applied by SetSettings
.
- needsRenderScreenTexture
-
bool needsRenderScreenTexture = false
Type
bool
Description
This value is set to true by SetSettings
or SetOutputSize
when there is a change to
the way the screen texture appears (including a change to the output resolution),
so that Render
will
call RenderScreenTexture
.
- needsRenderMaskTexture
-
bool needsRenderMaskTexture = false
Type
bool
Description
This value is set to true by SetSettings
when
the value of screenSettings.maskType
changes, so that Render
will
call RenderMaskTexture
.
- prevScanlineType
-
ScanlineType prevScanlineType
= ScanlineType::Progressive
Type
ScanlineType
Description
The scanline type from the previous call to Render
.
This is used by Render
to ensure that the scanlines from the previous frame are
rendered with the correct even/odd parity to handle both progressive and interlacing modes
when phosphor persistence emulation is enabled.
- downsampleDirX
-
float downsampleDirX
Type
float
Description
The x component of the direction of the downsample during the tonemap pass in
RenderBlur
. This and downsampleDirY
are set to do either a horizontal or vertical blur depending on which blur gets us closer to the desired
aspect ratio for the final blurred texture.
- downsampleDirY
-
float downsampleDirY
Type
float
Description
The y component of the direction of the downsample during the tonemap pass in
RenderBlur
. This and downsampleDirX
are set to do either a horizontal or vertical blur depending on which blur gets us closer to the desired
aspect ratio for the final blurred texture.
Private Constants
Private Structures
Private Methods
Private Fields
static constexpr uint32_t k_maskSize = 512
Description
The horizontal resolution of maskTexture
, the
texture that the CRT mask is rendered to.
The vertical resolution of the texture is half this value.
Given the small scale of the mask in the render output, this value is - in practice - wildly overkill, but it downsamples to the mipmaps very well.
Description
CalculateAspectData
with some
commonly-calculated aspect-related values.
Fields
overscanSize
-
Type:
Vec2
This contains (as an x, y vector) the width and height of the original (pre-generation/decode) image (the original source RGB image), minus the amount of overscan specified by
overscanSettings
. aspect
-
Type:
float
This value represents the actual aspect ratio (width / height) of the screen, taking into account both the above
overscanSize
value andpixelAspect
.
Description
This contains the initial values for both ScreenTextureConstants
and RGBToScreenConstants
.
These values correspond to the initial four input constant values in the crt-generate-screen-texture and crt-rgb-to-crt shaders. Refer to those pages for documentation of the fields.
Description
Description
Description
Description
AspectData CalculateAspectData()
Description
Calculates the dimensions of the original (pre-generation/decode) input texture would have after overscan is applied, as well as the aspect ratio of the full image.
Called by
CalculateCommonConstants
,
RenderScreenTexture
,
and UpdateBlurTextures
.
Return Value
RGBToCRT::AspectData
The calculated data.
CommonConstants CalculateCommonConstants( const AspectData &aspectData)
Description
Calculate some values that are common to both
RGBToCRT::
and
RGBToCRT::
.
Called by
Render
and RenderScreenTexture
.
Parameters
aspectData
-
Type:
const RGBToCRT::
AspectData &The output of a call to
CalculateAspectData
.
Return Value
Type: RGBToCRT::
The calculated constants.
void RenderScreenTexture()
Description
Renders to screenTexture
, which contains an image that
has the CRT mask (with proper curvature applied) in the RGB channels and a mask of what is or is not
visible on the screen in the alpha channel.
It's worth noting that the shader that renders this does a very expensive 64-tap sample of the mask
texture to alleviate aliasing,
so the RGBToCRT
does a fair amount of work to only do this when necessary (after a call to
SetSettings
or SetOutputSize
in which the values were changed).
Called by Render
.
void UpdateBlurTextures()
Description
Calculates the required sizes for
toneMapTexture
,
blurTexture
,
and blurScratchTexture
.
Then, if the sizes are different from the existing versions of those textures,
will create new textures at the proper size.
Called by the constructor and SetSettings
.
void RenderMaskTexture()
Description
Renders a mask to maskTexture
, given the
MaskType
value
stored in screenSettings
.
This uses a lanczos downsample pass to generate the mipmap levels.
This is only called after a call to
SetSettings
or SetOutputSize
in which the values were changed.
Called by Render
.
void RenderBlur( const ITexture *inputTexture)
Description
Does a tonemap and blur of the given input texture, which is used as an approximation of CRT diffusion (the scattering of photons as they pass through the glass front of the CRT screen).
Called by Render
.
Parameters
inputTexture
-
Type:
const ITexture *
The texture to tonemap and then blur.
IGraphicsDevice *device
Type
IGraphicsDevice *
Description
uint32_t originalInputImageWidth
Type
uint32_t
Description
uint32_t processedRGBTextureWidth
Type
uint32_t
Description
The expected width of the texture that will be passed in to Render
.
If no generator/decoder process is being used (i.e. if the CathodeRetro
class
is being used in RGB mode, this will be the same value as
originalInputImageWidth
.
uint32_t scanlineCount
Type
uint32_t
Description
The number of scanlines per input image (i.e. the height of the input texture).
float pixelAspect
Type
float
Description
The aspect ratio (width/height) of an input pixel (pre-generator/decoder) on the screen. This allows for emulation of non-square-pixel video modes.
For example:
- On the NES, pixels were slightly stretched horizontally and have an 8:7 (8/7) aspect ratio.
- Old mode 13h modes had slightly tall pixels on 4x3 monitors, resulting in pixels that are 5:6.
bool isFirstFrame = true
Type
bool
Description
This is true before Render
is called the first time,
and false afterward.
Because this class keeps a copy of the previous frame (in prevRGBInput
)
and uses that to handle phosphor persistence, on the very first call to Render
this flag is used
to initialize prevRGBInput
so that it can be used.
std::unique_ptr<IConstantBuffer> screenTextureConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
RenderScreenTexture
as an input to the
crt-generate-screen-texture
shader.
std::unique_ptr<IConstantBuffer> rgbToScreenConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
Render
as an input to the
crt-rgb-to-crt
shader.
std::unique_ptr<IConstantBuffer> toneMapConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
RenderBlur
as an input to the
util-tonemap-and-downsample
shader.
std::unique_ptr<IConstantBuffer> blurDownsampleConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
RenderBlur
as an input to the
util-downsample-2x
shader, to do a horizontal downsample before the blurring.
std::unique_ptr<IConstantBuffer> gaussianBlurConstantBufferH
Type
std::unique_ptr<IConstantBuffer>
Description
RenderBlur
as an input to the
util-gaussian-blur
shader, to do the horizontal blur pass.
std::unique_ptr<IConstantBuffer> gaussianBlurConstantBufferV
Type
std::unique_ptr<IConstantBuffer>
Description
The constant buffer that is used inRenderBlur
as an input to the
util-gaussian-blur
shader, to do the vertical blur pass.
std::unique_ptr<IConstantBuffer> generateMaskConstantBuffer
Type
std::unique_ptr<IConstantBuffer>
Description
RenderMaskTexture
as an input to one of the
crt-generate-shadow-mask,
crt-generate-slot-mask,
or crt-generate-aperture-grille
shaders (depending on the value of screenSettings.maskType
)
to generate the largest mip level of maskTexture
.
std::unique_ptr<IConstantBuffer> maskDownsampleConstantBufferH
Type
std::unique_ptr<IConstantBuffer>
Description
RenderMaskTexture
as an input to the util-downsample-2x
shader to do the horizontal downsample into a scratch texture (halfWidthMaskTexture
)
during the generation of the mipmaps of maskTexture
.
std::unique_ptr<IConstantBuffer> maskDownsampleConstantBufferV
Type
std::unique_ptr<IConstantBuffer>
Description
RenderMaskTexture
as an input to the util-downsample-2x
shader to do the vertical downsample from the scratch texture (halfWidthMaskTexture
),
during the generation of the mipmaps of maskTexture
.
std::unique_ptr<IRenderTarget> prevRGBInput
Type
std::unique_ptr<IRenderTarget>
Description
currentFrameRGBInput
parameter that was passed to the previous call
to Render
, and is used to emulate phosphor persistence (where a little of the previous frame
is still visible).
std::unique_ptr<IRenderTarget> maskTexture
Type
std::unique_ptr<IRenderTarget>
Description
RenderMaskTexture
whenever
the value of value of screenSettings.maskType
changes.
std::unique_ptr<IRenderTarget> halfWidthMaskTexture
Type
std::unique_ptr<IRenderTarget>
Description
RenderMaskTexture
.
It has the same height as maskTexture
but has half the width, and is used as
the target for the horizontal pass of the downsample.
std::unique_ptr<IRenderTarget> screenTexture
Type
std::unique_ptr<IRenderTarget>
Description
RenderScreenTexture
. It has the same width and height as
the final output texture of the Render
method.
std::unique_ptr<IRenderTarget> toneMapTexture
Type
std::unique_ptr<IRenderTarget>
Description
RenderBlur
,
which does the tonemapping (and also a resize to get closer to the desired blur resolution).
std::unique_ptr<IRenderTarget> blurScratchTexture
Type
std::unique_ptr<IRenderTarget>
Description
RenderBlur
(and is the ultimate result of that method), and ultimately contains the blurred version of the input texture
that is used to emulate CRT diffusion (the scattering of photons as they pass through the glass front of the CRT screen).
std::unique_ptr<IRenderTarget> blurTexture
Type
std::unique_ptr<IRenderTarget>
Description
RenderBlur
,
which is the horizontal gaussian blur pass. It is then used in the final pass to do the vertical blur
to get the final result.
ScreenSettings screenSettings
Type
ScreenSettings
Description
SetSettings
.
OverscanSettings overscanSettings
Type
OverscanSettings
Description
SetSettings
.
bool needsRenderScreenTexture = false
Type
bool
Description
SetSettings
or SetOutputSize
when there is a change to
the way the screen texture appears (including a change to the output resolution),
so that Render
will
call RenderScreenTexture
.
bool needsRenderMaskTexture = false
Type
bool
Description
SetSettings
when
the value of screenSettings.maskType
changes, so that Render
will
call RenderMaskTexture
.
ScanlineType prevScanlineType = ScanlineType::Progressive
Type
ScanlineType
Description
Render
.
This is used by Render
to ensure that the scanlines from the previous frame are
rendered with the correct even/odd parity to handle both progressive and interlacing modes
when phosphor persistence emulation is enabled.
float downsampleDirX
Type
float
Description
RenderBlur
. This and downsampleDirY
are set to do either a horizontal or vertical blur depending on which blur gets us closer to the desired
aspect ratio for the final blurred texture.
float downsampleDirY
Type
float
Description
RenderBlur
. This and downsampleDirX
are set to do either a horizontal or vertical blur depending on which blur gets us closer to the desired
aspect ratio for the final blurred texture.