Unit CastleGLImages

DescriptionUsesClasses, Interfaces, Objects and RecordsFunctions and ProceduresTypesConstantsVariables

Description

Using images in OpenGL (as textures and as normal images).

For non-OpenGL image management, see CastleImages and CastleTextureImages units. They contain functions and classes to load, save and process images.

This unit has functions and classes to:

  • Load images as OpenGL textures. You usually do not use these directly, instead TCastleScene automatically uses these to load and render textures as part of 3D models.

    A lot of utilities included: for 2D textures (see LoadGLTexture), cube maps (see glTextureCubeMap), 3D textures (see glTextureImage3D). These functions wrap OpenGL calls like glTexImage2D to handle our images (TEncodedImage (and descendant TCastleImage), TDDSImage), and to automatically set texture parameters, mipmaps and such.

  • Load and draw images in 2D. This is useful to implement various 2D controls. See TGLImage class and friends.

  • Save the current OpenGL screen contents to our TCastleImage. You usually use this through TCastleWindowCustom.SaveScreen or TCastleControl.SaveScreen, based on SaveScreen_NoFlush in this unit.

  • Render to texture, see TGLRenderToTexture class. This is our abstraction over OpenGL framebuffer (or glCopyTexSubImage for ancient GPUs).

This unit hides from your some details about OpenGL images handling. For example, you don't have to worry about "pixel store alignment", we handle it here internally when transferring images between memory and GPU. You also don't have to worry about texture sizes being power of 2, or about maximum texture sizes — we will resize textures if necessary.

Routines in this unit that take TCastleImage or TEncodedImage parameter are limited to TextureImageClassesAll (for routines dealing with textures) or PixelsImageClasses (for routines dealing with images drawn on 2D screen).

Uses

Overview

Classes, Interfaces, Objects and Records

Name Description
Class ETextureLoadError  
Class EImageClassNotSupportedForOpenGL  
Class ECannotLoadCompressedTexture  
Class EInvalidImageForOpenGLTexture  
Object TTextureFilter  
Class EGenerateMipmapNotAvailable Part of CastleGLImages unit: mipmaps utils.
Class TGLImage Image ready to be drawn on 2D screen.
Class EFramebufferError Part of CastleGLImages unit: rendering to texture (TGLRenderToTexture).
Class EFramebufferSizeTooLow  
Class EFramebufferInvalid  
Class TGLRenderToTexture Rendering to texture with OpenGL.
Class TTextureMemoryProfiler Part of CastleGLImages unit: texture memory profiler (TextureMemoryProfiler).
Class TGLVideo Video as a sequence of OpenGL textures that can be easily played.
Class TGLVideo3D Video expressed as a series of textures, to play as texture on any 3D object.
Class TGLVideo2D Video expressed as a series of TGLImage, to play as 2D GUI control.

Functions and Procedures

function ImageGLFormat(const Img: TCastleImage): TGLenum;
function ImageGLInternalFormat(const Img: TEncodedImage): TGLenum;
function ImageGLType(const Img: TCastleImage): TGLenum;
procedure glFreeTexture(var Tex: TGLTextureId);
procedure TexParameterMaxAnisotropy(const target: TGLenum; const Anisotropy: TGLfloat);
operator = (const V1, V2: TTextureFilter): boolean;
function TextureFilter(const Minification: TMinificationFilter; const Magnification: TMagnificationFilter): TTextureFilter;
procedure SetTextureFilter(const Target: TGLenum; const Filter: TTextureFilter);
operator = (const W1, W2: TTextureWrap2D): boolean;
operator = (const W1, W2: TTextureWrap3D): boolean;
function Texture2DClampToEdge: TTextureWrap2D;
function HasGenerateMipmap: boolean;
procedure GenerateMipmap(target: TGLenum);
procedure ImageDraw(const Image: TCastleImage); deprecated;
procedure ResizeForTextureSize(var r: TCastleImage; const Sizing: TTextureSizing);
function ResizeToTextureSize(const r: TCastleImage; const Sizing: TTextureSizing): TCastleImage;
function ResizeToTextureSize(const Size: Cardinal; const Sizing: TTextureSizing): Cardinal;
function IsTextureSized(const r: TEncodedImage; const Sizing: TTextureSizing): boolean;
function IsTextureSized(const Width, Height: Cardinal; const Sizing: TTextureSizing): boolean;
function LoadGLTexture(const image: TEncodedImage; const Filter: TTextureFilter; const Wrap: TTextureWrap2D; const DDSForMipmaps: TDDSImage = nil; const GUITexture: boolean = false): TGLTextureId; overload;
function LoadGLTexture(const URL: string; const Filter: TTextureFilter; const Wrap: TTextureWrap2D; const DDSForMipmaps: TDDSImage = nil; const GUITexture: boolean = false): TGLTextureId; overload;
procedure LoadGLGeneratedTexture(const TextureId: TGLTextureId; const image: TEncodedImage; Filter: TTextureFilter; const Wrap: TTextureWrap2D; const DDSForMipmaps: TDDSImage = nil; const GUITexture: boolean = false); overload;
function GLDecompressTexture(Image: TGPUCompressedImage): TCastleImage;
procedure glTextureImage3D(const TextureIdForProfiler: TGLTextureId; const Image: TEncodedImage; Filter: TTextureFilter; DDSForMipmaps: TDDSImage);
function IsCubeMapTextureSized(const Size: Cardinal): boolean;
function ResizeToCubeMapTextureSize(const Size: Cardinal): Cardinal;
procedure glTextureCubeMap(const TextureIdForProfiler: TGLTextureId; PositiveX, NegativeX, PositiveY, NegativeY, PositiveZ, NegativeZ: TEncodedImage; DDSForMipmaps: TDDSImage; Mipmaps: boolean);
function SaveScreen_NoFlush( const Rect: TRectangle; const ReadBuffer: TColorBuffer): TRGBImage; overload;
function SaveScreen_NoFlush(const ImageClass: TCastleImageClass; const Rect: TRectangle; const ReadBuffer: TColorBuffer): TCastleImage; overload;
procedure SaveScreen_NoFlush(const Image: TCastleImage; const Left, Bottom: Integer; const ReadBuffer: TColorBuffer); overload;
function SaveScreenToGL_NoFlush(const Rect: TRectangle; const ReadBuffer: TColorBuffer; const ScalingPossible: boolean = false): TGLImage;
function TextureMemoryProfiler: TTextureMemoryProfiler;

Types

TGLTextureId = TGLuint;
TMinificationFilter = (...);
TMagnificationFilter = (...);
TTextureWrap2D = array [0..1] of TGLenum;
TTextureWrap3D = array [0..2] of TGLenum;
TTextureSizing = (...);
TColorBuffer = (...);
TGLRenderToTextureBuffer = (...);

Constants

PixelsImageClasses: array [0..3] of TEncodedImageClass = ( TRGBImage, TRGBAlphaImage, TGrayscaleImage, TGrayscaleAlphaImage);
Texture2DRepeat: TTextureWrap2D = (GL_REPEAT, GL_REPEAT);

Variables

GLTextureScale: Cardinal = 1;
GLTextureMinSize: Cardinal = 16;

Description

Functions and Procedures

function ImageGLFormat(const Img: TCastleImage): TGLenum;

Return appropriate OpenGL format and type constants for given TCastleImage descendant. If you will pass here Img that is not a descendant of one of TextureImageClassesAll or PixelsImageClasses, they will raise EImageClassNotSupportedForOpenGL.

ImageGLInternalFormat works with TGPUCompressedImage classes also, returning appropriate enum, suitable for glCompressedTexImage2D.

Exceptions raised
EImageClassNotSupportedForOpenGL
When Img class is not supported by OpenGL.
function ImageGLInternalFormat(const Img: TEncodedImage): TGLenum;
 
function ImageGLType(const Img: TCastleImage): TGLenum;
 
procedure glFreeTexture(var Tex: TGLTextureId);

If Tex <> 0 then it does glDeleteTextures on Tex and sets Tex to 0. In other words, this is a simple wrapper over glDeleteTextures that

  1. checks if Tex really should be deleted

  2. sets Tex to 0 to not free it once again

procedure TexParameterMaxAnisotropy(const target: TGLenum; const Anisotropy: TGLfloat);

Call glTexParameterf to set GL_TEXTURE_MAX_ANISOTROPY_EXT on given texture target.

Takes care to check for appropriate OpenGL extension (if not present, does nothing), and to query OpenGL limit for Anisotropy (eventually clamping provided Anisotropy down).

operator = (const V1, V2: TTextureFilter): boolean;
 
function TextureFilter(const Minification: TMinificationFilter; const Magnification: TMagnificationFilter): TTextureFilter;
 
procedure SetTextureFilter(const Target: TGLenum; const Filter: TTextureFilter);

Set current texture minification and magnification filter.

This is just a thin wrapper for calling

  glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, ...);
  glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, ...);

operator = (const W1, W2: TTextureWrap2D): boolean;
 
operator = (const W1, W2: TTextureWrap3D): boolean;
 
function Texture2DClampToEdge: TTextureWrap2D;

Return wrap GL_CLAMP_TO_EDGE in both directions.

function HasGenerateMipmap: boolean;

Is GenerateMipmap avaiable. This checks some GL extensions/versions that give us glGenerateMipmap or glGenerateMipmapEXT call, used by GenerateMipmap.

procedure GenerateMipmap(target: TGLenum);

Call glGenerateMipmap (or analogous function from some OpenGL extension).

Exceptions raised
EGenerateMipmapNotAvailable
If no glGenerateMipmap version is available on this OpenGL version. If you don't want to get this exception, you can always check HasGenerateMipmap before calling this.
procedure ImageDraw(const Image: TCastleImage); deprecated;

Warning: this symbol is deprecated.

Draw the image on 2D screen. Note that if you want to use this many times, it will be much faster to create TGLImage instance.

Deprecated, always use TGLImage to draw 2D images.

Exceptions raised
EImageClassNotSupportedForOpenGL
When Image class is not supported by OpenGL.
procedure ResizeForTextureSize(var r: TCastleImage; const Sizing: TTextureSizing);

Resize the image to a size accepted as GL_TEXTURE_2D texture size for OpenGL. It tries to resize to a larger size, not smaller, to avoid losing image information.

It also makes texture have power-of-two size, if Sizing <> tsAny (or if GLFeatures.TextureNonPowerOfTwo = False). This is a must for normal textures, used for 3D rendering (with mipmapping and such). Using OpenGL non-power-of-2 textures is not good for such usage case, some OpenGLs crash (ATI), some are ultra slow (NVidia), some cause artifacts (Mesa). OpenGL ES explicitly limits what you can do with non-power-of-2. Sample model using non-power-of-2 is in inlined_textures.wrl.

Use Sizing = tsAny only for textures that you plan to use for drawing GUI images by TGLImage.

function ResizeToTextureSize(const r: TCastleImage; const Sizing: TTextureSizing): TCastleImage;
 
function ResizeToTextureSize(const Size: Cardinal; const Sizing: TTextureSizing): Cardinal;
 
function IsTextureSized(const r: TEncodedImage; const Sizing: TTextureSizing): boolean;

Does image have proper size for 2D OpenGL texture. See ResizeForTextureSize. Note that this checks glGet(GL_MAX_TEXTURE_SIZE), so requires initialized OpenGL context.

function IsTextureSized(const Width, Height: Cardinal; const Sizing: TTextureSizing): boolean;
 
function LoadGLTexture(const image: TEncodedImage; const Filter: TTextureFilter; const Wrap: TTextureWrap2D; const DDSForMipmaps: TDDSImage = nil; const GUITexture: boolean = false): TGLTextureId; overload;

Load new texture to OpenGL. Generates new texture number by glGenTextures, then binds this texture, and loads it's data.

Takes care of UNPACK_ALIGNMENT inside (if needed, we'll change it and later revert back, so that the texture is correctly loaded).

Sets texture minification, magnification filters and wrap parameters.

Changes currently bound texture to this one (returned).

If mipmaps will be needed (this is decided looking at Filter.Minification) we will load them too.

  1. As a first try, if DDSForMipmaps is non-nil and has mipmaps (DDSForMipmaps.Mipmaps), we will load these mipmaps. DDSForMipmaps must be a normal 2D texture (DDSType = dtTexture).

    Otherwise, we'll try to generate mipmaps, using various OpenGL mechanisms.

  2. We will try using GenerateMipmap functionality to generate mipmaps on GPU. If not available, for uncompressed textures, we will generate mipmaps on CPU. For compressed textures, we will change minification filter to simple minLinear and make OnWarning.

Parameters
GUITexture
If True, the texture is not forced to have sizes as power-of-two. For TTextureSizing, it is like tsAny instead of tsScalablePowerOf2. Also, mipmaps are always disabled, regardless of requested Filter value, since mipmaps cannot work without power-of-two.
Exceptions raised
ETextureLoadError
If texture cannot be loaded for whatever reason. This includes ECannotLoadCompressedTexture if the compressed texture cannot be loaded for whatever reason. This includes EInvalidImageForOpenGLTexture if Image class is invalid for an OpenGL texture.
EImageClassNotSupportedForOpenGL
When Image class is not supported by OpenGL.
function LoadGLTexture(const URL: string; const Filter: TTextureFilter; const Wrap: TTextureWrap2D; const DDSForMipmaps: TDDSImage = nil; const GUITexture: boolean = false): TGLTextureId; overload;
 
procedure LoadGLGeneratedTexture(const TextureId: TGLTextureId; const image: TEncodedImage; Filter: TTextureFilter; const Wrap: TTextureWrap2D; const DDSForMipmaps: TDDSImage = nil; const GUITexture: boolean = false); overload;

Load OpenGL texture into already reserved texture number. It uses existing OpenGL texture number (TextureId). Everything else works exactly the same as LoadGLTexture.

You can also use this to set "default unnamed OpenGL texture" parameters by passing TextureId = 0.

Exceptions raised
ETextureLoadError
Raised in the same situations as LoadGLTexture.
EImageClassNotSupportedForOpenGL
When Image class is not supported by OpenGL.
function GLDecompressTexture(Image: TGPUCompressedImage): TCastleImage;

Decompress texture image by loading it to temporary OpenGL texture and reading back. So this internally uses current OpenGL context.

Exceptions raised
ECannotLoadCompressedTexture
If cannot decompress S3TC, for example because we cannot load to OpenGL this compressed texture (for example because appropriate OpenGL extensions are not available, or such).
procedure glTextureImage3D(const TextureIdForProfiler: TGLTextureId; const Image: TEncodedImage; Filter: TTextureFilter; DDSForMipmaps: TDDSImage);

Comfortably load a 3D texture. Think about this as doing glTexImage3D(...) for you. It also sets texture minification, magnification filters and creates mipmaps if necessary.

It checks OpenGL 3D texture size requirements, and throws exceptions if not satisfied.

It takes care about OpenGL unpack parameters. Just don't worry about it.

If Filter uses mipmaps, then all mipmap levels will be loaded.

  1. As a first try, if DDSForMipmaps is non-nil and has mipmaps (DDSForMipmaps.Mipmaps), we will load these mipmaps. DDSForMipmaps must be a 3D texture (DDSType = dtVolume).

  2. Otherwise, we'll generate mipmaps.

    GenerateMipmap functionality will be required for this. When it is not available on this OpenGL implementation, we will change minification filter to simple linear and make OnWarning. So usually you just don't have to worry about this.

Pass TextureIdForProfiler only for profiling purposes (for TextureMemoryProfiler). This procedure assumes that the texture is already bound.

Exceptions raised
ETextureLoadError
If texture cannot be loaded for whatever reason, for example it's size is not correct for OpenGL 3D texture (we cannot automatically resize 3D textures, at least for now). Or it's compressed (although we support here TEncodedImage, OpenGL doesn't have any 3D texture compression available.)
EImageClassNotSupportedForOpenGL
When Image class is not supported by OpenGL.
function IsCubeMapTextureSized(const Size: Cardinal): boolean;

Part of CastleGLImages unit: cubemaps sizing and loading.

function ResizeToCubeMapTextureSize(const Size: Cardinal): Cardinal;
 
procedure glTextureCubeMap(const TextureIdForProfiler: TGLTextureId; PositiveX, NegativeX, PositiveY, NegativeY, PositiveZ, NegativeZ: TEncodedImage; DDSForMipmaps: TDDSImage; Mipmaps: boolean);

Comfortably load all six cube map texture images. Think about this as doing glTexImage2D(Side, ...) for each cube side. It takes care of (almost?) everything you need to prepare OpenGL cube map texture.

It automatically takes care to adjust the texture size to appropriate size, honoring the "power of two" requirement and the GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB limit of OpenGL. So texture image may be resized (preferably up) internally before loading. Although, if texture is compressed, we cannot resize it — so ECannotLoadCompressedTexture will be raised if texture is not appropriate size.

It takes care about OpenGL unpack parameters. Just don't worry about it.

Pass TextureIdForProfiler only for profiling purposes (for TextureMemoryProfiler). This procedure assumes that the texture is already bound.

If mipmaps are requested:

  1. First of all, if DDSForMipmaps is non-nil and has mipmaps defined, we will load them from this DDS image. DDSForMipmaps must have DDSType = dtCubeMap.

  2. Otherwise, we'll try to generate images using OpenGL GenerateMipmap.

  3. As a last resort, if GenerateMipmap is not available, we will fallback to generating mipmaps on CPU by good old gluBuild2DMipmaps call.

Exceptions raised
ETextureLoadError
If texture cannot be loaded for whatever reason. This includes ECannotLoadCompressedTexture if the compressed texture cannot be loaded for whatever reason (not availble appropriate extension, not correct texture size, mipmaps requested and DDSForMipmaps/glGenerateMipmap not available). This includes EInvalidImageForOpenGLTexture if Image class is invalid for an OpenGL texture.
EImageClassNotSupportedForOpenGL
When Image class is not supported by OpenGL.
function SaveScreen_NoFlush( const Rect: TRectangle; const ReadBuffer: TColorBuffer): TRGBImage; overload;

Save the current color buffer contents to image.

The suffix "NoFlush" is there to remind you that this function grabs the current buffer contents. Usually you want to redraw the screen to the back buffer, and call this function to capture back buffer before swapping, since this is the only reliable way to capture OpenGL screen. Just use TCastleWindowCustom.SaveScreen to do it automatically.

Version with ImageClass can save to any image format from PixelsImageClasses.

Version with TCastleImage instance just uses this instance to save the image. You must pass here already created TCastleImage instance, it's class, Width and Height will be used when saving.

Exceptions raised
EImageClassNotSupportedForOpenGL
When Image class is not supported by OpenGL.
function SaveScreen_NoFlush(const ImageClass: TCastleImageClass; const Rect: TRectangle; const ReadBuffer: TColorBuffer): TCastleImage; overload;
 
procedure SaveScreen_NoFlush(const Image: TCastleImage; const Left, Bottom: Integer; const ReadBuffer: TColorBuffer); overload;
 
function SaveScreenToGL_NoFlush(const Rect: TRectangle; const ReadBuffer: TColorBuffer; const ScalingPossible: boolean = false): TGLImage;

Captures current screen as a TGLImage instance, ready to be drawn on 2D screen.

function TextureMemoryProfiler: TTextureMemoryProfiler;

OpenGL texture memory profiler, to detect which textures use up the GPU texture memory. Especially useful on mobile devices, where texture memory is limited and your application must really optimize texture usage. Also useful to detect texture memory leaks.

Simply enable it (TextureMemoryProfiler.Enabled := true), load your game, then query texture usage by TTextureMemoryProfiler.UsageOverview, e.g. show it by WritelnLog('Textures', TextureMemoryProfiler.UsageOverview).

Types

TGLTextureId = TGLuint;
 
TMinificationFilter = (...);

Texture minification filter (what happens when many texture pixels are squeezed in one screen pixel).

Values
  • minNearest:  
  • minLinear:  
  • minNearestMipmapNearest:  
  • minNearestMipmapLinear:  
  • minLinearMipmapNearest:  
  • minLinearMipmapLinear:  
TMagnificationFilter = (...);

Texture magnification filter (what happens when a single texture pixel in stretched over many screen pixels).

Values
  • magNearest:  
  • magLinear:  
TTextureWrap2D = array [0..1] of TGLenum;
 
TTextureWrap3D = array [0..2] of TGLenum;
 
TTextureSizing = (...);

———————————————————————- Adjusting image sizes to load them as textures. Usually you don't need these functions, LoadGLTexture* and TGLImage and such call it automatically when needed.

Values
  • tsAny: Texture size does not have to be a power of two (unless GLFeatures.TextureNonPowerOfTwo = False, in which case all textures must have power-of-two, and then tsAny may be scaled to satisfy it (but it still will not be scaled for GLTextureScale)). It is not affected by GLTextureScale.
  • tsRequiredPowerOf2: Texture size must be a power of two. It is not affected by GLTextureScale, because we cannot scale it.
  • tsScalablePowerOf2: Texture size must be a power of two. It is affected by GLTextureScale, we can scale it.
TColorBuffer = (...);

Part of CastleGLImages unit: saving screen.

Values
  • cbFront:  
  • cbBack:  
  • cbColorAttachment0:  
TGLRenderToTextureBuffer = (...);
 
Values
  • tbColor:  
  • tbDepth:  
  • tbColorAndDepth:  
  • tbNone:  

Constants

PixelsImageClasses: array [0..3] of TEncodedImageClass = ( TRGBImage, TRGBAlphaImage, TGrayscaleImage, TGrayscaleAlphaImage);
 
Texture2DRepeat: TTextureWrap2D = (GL_REPEAT, GL_REPEAT);
 

Variables

GLTextureScale: Cardinal = 1;

Scaling for all textures loaded to OpenGL. This allows you to conserve GPU memory. Each size (width, height, and (for 3D textures) depth) is scaled by 1 / 2ˆGLTextureScale. So value = 1 means no scaling, value = 2 means that each size is 1/2 (texture area is 1/4), value = 3 means that each size is 1/4 and so on.

Note that textures used for GUI, by TGLImage (more precisely: all non-power-of-2 textures) avoid this scaling entirely.

GLTextureMinSize: Cardinal = 16;

Contraints the scaling done by GLTextureScale. Scaling caused by GLTextureScale cannot scale texture to something less than GLTextureMinSize. If texture size was already < GLTextureMinSize, it is not scaled at all by GLTextureScale. This must be a power of two.


Generated by PasDoc 0.14.0.