This page covers the CPU-side image data storage and manipulation system (Image), the GPU-side texture resource hierarchy (Texture, Texture2D, Texture3D, TextureLayered and their concrete subclasses), and the editor import pipeline that converts raw image files into engine-ready .ctex resources. For resource loading and caching in general, see Resource System. For how textures are uploaded to the GPU and used in rendering, see RenderingServer.
The image and texture system is split across two layers:
Image class holds raw pixel data in RAM and supports format conversion, resizing, compression, and I/O.Resource subclasses that wrap a GPU texture RID. They serve as the interface between the scene system and the RenderingServer.Image class hierarchy:
Texture class hierarchy:
Sources: scene/resources/texture.h scene/resources/image_texture.h core/io/image.h
Image ClassImage (core/io/image.h, core/io/image.cpp) is the primary CPU-side image container. It extends Resource and stores:
| Field | Type | Description |
|---|---|---|
data | Vector<uint8_t> | Raw pixel bytes (all mipmaps concatenated) |
format | Format | Pixel format enum value |
width | int | Image width in pixels |
height | int | Image height in pixels |
mipmaps | bool | Whether the data buffer includes mip chain |
The maximum supported image size is MAX_WIDTH × MAX_HEIGHT = 2^24 × 2^24 (but graphics hardware limits practical use to 16384 × 16384, or MAX_PIXELS = 268435456).
The Format enum defines all supported pixel layouts:
Uncompressed formats:
| Constant | Bytes/pixel | Description |
|---|---|---|
FORMAT_L8 | 1 | Luminance (grayscale) |
FORMAT_LA8 | 2 | Luminance + Alpha |
FORMAT_R8 | 1 | Red channel only |
FORMAT_RG8 | 2 | Red + Green |
FORMAT_RGB8 | 3 | Red + Green + Blue |
FORMAT_RGBA8 | 4 | Red + Green + Blue + Alpha |
FORMAT_RGBA4444 | 2 | 4 bits per channel |
FORMAT_RGB565 | 2 | 5-6-5 bit channel split |
FORMAT_RF/RGF/RGBF/RGBAF | 4–16 | 32-bit float channels |
FORMAT_RH/RGH/RGBH/RGBAH | 2–8 | 16-bit half-float channels |
FORMAT_RGBE9995 | 4 | Shared exponent HDR |
FORMAT_R16/RG16/RGB16/RGBA16 | 2–8 | 16-bit unsigned normalized |
FORMAT_R16I/RG16I/RGB16I/RGBA16I | 2–8 | 16-bit integer |
Block-compressed (VRAM) formats:
| Constant | Standard | Use Case |
|---|---|---|
FORMAT_DXT1 | BC1 | Opaque RGB |
FORMAT_DXT3 | BC2 | RGBA (sharp alpha) |
FORMAT_DXT5 | BC3 | RGBA (smooth alpha) |
FORMAT_RGTC_R | BC4 | Single channel |
FORMAT_RGTC_RG | BC5 | Two channels (normal maps) |
FORMAT_BPTC_RGBA | BC7 | High quality RGBA |
FORMAT_BPTC_RGBF | BC6H (signed) | HDR float RGB |
FORMAT_BPTC_RGBFU | BC6H (unsigned) | HDR float RGB |
FORMAT_ETC | ETC1 | Mobile RGB |
FORMAT_ETC2_* | ETC2 | Mobile RGBA and variants |
FORMAT_ASTC_4x4 | ASTC 4×4 | Adaptive scalable (LDR) |
FORMAT_ASTC_4x4_HDR | ASTC 4×4 | Adaptive scalable (HDR) |
FORMAT_ASTC_8x8 | ASTC 8×8 | Lower quality, higher compression |
FORMAT_ASTC_8x8_HDR | ASTC 8×8 | Lower quality HDR |
Block-compressed formats have a block size of 4×4 pixels (or 8×8 for ASTC_8x8), which is enforced by get_format_block_size() and get_format_min_pixel_size().
When mipmaps == true, the data buffer contains the full mip chain: the base level is stored first, followed by each successively halved level. The functions get_mipmap_offset(), get_mipmap_offset_and_size(), and _get_mipmap_offset_and_size() calculate byte offsets into data for each level.
Image::convert(Format p_new_format) converts between uncompressed formats. Conversion between compressed formats is not possible directly; use decompress() first. Internally, template functions _convert<> and _convert_fast<> handle channel reordering for byte, half-float, float, and 16-bit integer families.
Compression is invoked via compress(CompressMode, CompressSource, ASTCFormat) or compress_from_channels(CompressMode, UsedChannels, ASTCFormat). These delegate to static function pointers that are registered by optional modules:
Compression function pointers:
Sources: core/io/image.h224-241 modules/cvtt/image_compress_cvtt.cpp144-200
Decompression function pointers follow the same pattern: _image_decompress_bc, _image_decompress_bptc, _image_decompress_etc1, _image_decompress_etc2, _image_decompress_astc.
For uncompressed images, get_pixel(x, y) / set_pixel(x, y, color) provide per-pixel access. Compressed images cannot be read or written per-pixel until decompressed.
Internal helpers _put_pixelb() and _get_pixelb() handle the raw byte offset arithmetic, while _get_color_at_ofs() and _set_color_at_ofs() translate between the internal format and Color.
| Method | Description |
|---|---|
resize(w, h, Interpolation) | Resizes using nearest, bilinear, cubic, trilinear, or Lanczos filtering |
resize_to_po2() | Resizes to next power-of-two dimensions |
crop(w, h) | Crops or pads with black |
flip_x() / flip_y() | Mirrors the image |
rotate_90(dir) / rotate_180() | Rotates in-place |
generate_mipmaps(renormalize) | Builds a full mip chain |
Image supports loading from and saving to multiple formats via pluggable function pointers. The image loader core is at core/io/image_loader.h.
Supported load formats (via load_*_from_buffer methods):
| Method | Module dependency |
|---|---|
load_png_from_buffer | Built-in |
load_jpg_from_buffer | Built-in |
load_webp_from_buffer | Built-in |
load_bmp_from_buffer | module_bmp_enabled |
load_tga_from_buffer | module_tga_enabled |
load_dds_from_buffer | module_dds_enabled |
load_exr_from_buffer | module_tinyexr_enabled |
load_ktx_from_buffer | module_ktx_enabled |
load_svg_from_buffer | module_svg_enabled |
Supported save methods: save_png, save_jpg, save_webp, save_exr, save_dds (and _to_buffer variants for each).
Sources: core/io/image.h198-254 doc/classes/Image.xml340-430
All texture types are declared in scene/resources/texture.h. They are abstract resources with virtual methods implemented via GDVIRTUAL macros, which allows GDScript and C# subclasses to override them.
Texture2DThe base for all 2D textures. Key virtual methods:
| Virtual Method | Required | Default Behavior |
|---|---|---|
_get_width() | Yes | — |
_get_height() | Yes | — |
_get_image() | No | Returns null |
_get_format() | No | Returns FORMAT_MAX |
_get_mipmap_count() | No | Returns 0 |
_has_mipmaps() | No | Returns false |
_has_alpha() | No | Returns true |
_is_pixel_opaque(x, y) | No | Returns true |
_draw(canvas_item, pos, modulate, transpose) | No | Calls RenderingServer::canvas_item_add_texture_rect |
_draw_rect(...) | No | Calls RenderingServer::canvas_item_add_texture_rect |
_draw_rect_region(...) | No | Calls RenderingServer::canvas_item_add_texture_rect_region |
The draw* methods route to the RenderingServer singleton by default. Subclasses can override them for custom behavior (e.g., AtlasTexture overrides _draw_rect_region to apply region offsets).
scene/resources/texture.h41-84 scene/resources/texture.cpp89-114
Texture3DAbstract base for volumetric textures. Returns all mip slices as Vector<Ref<Image>> get_data(). Width, height, and depth are each separately queryable. create_placeholder() produces a PlaceholderTexture3D.
scene/resources/texture.h117-139
TextureLayeredAbstract base for array-style textures with a LayeredType enum:
| Constant | Meaning |
|---|---|
LAYERED_TYPE_2D_ARRAY | Array of 2D images |
LAYERED_TYPE_CUBEMAP | Six-face environment map |
LAYERED_TYPE_CUBEMAP_ARRAY | Array of cubemaps |
Access individual layers via get_layer_data(int layer).
scene/resources/texture.h86-115
ImageTextureImageTexture (scene/resources/image_texture.h scene/resources/image_texture.cpp) is the primary runtime-created texture. It:
RenderingServer::texture_2d_create(image).set_image(image) (reallocates GPU memory) and update(image) (updates data without reallocation, faster for frequently-updated textures).create_from_image(image).Typical runtime usage:
var img = Image.load_from_file("res://icon.svg")
var tex = ImageTexture.create_from_image(img)
$Sprite2D.texture = tex
The underlying GPU texture RID is stored as a private texture member and passed to the RenderingServer.
CompressedTexture2DCompressedTexture2D (scene/resources/compressed_texture.h) is the standard imported texture type. It is loaded from .ctex files (Godot Streamable Texture 2D) written by ResourceImporterTexture. The file header uses the magic bytes G, S, T, 2 followed by a format version.
Data within a .ctex file can be stored in one of these DataFormat modes:
DataFormat | Encoding |
|---|---|
DATA_FORMAT_IMAGE | Raw image bytes (VRAM-compressed or uncompressed) |
DATA_FORMAT_PNG | Per-mip PNG blobs |
DATA_FORMAT_WEBP | Per-mip WebP blobs |
DATA_FORMAT_BASIS_UNIVERSAL | Basis Universal blob |
scene/resources/compressed_texture.h
PortableCompressedTexture2DPortableCompressedTexture2D (scene/resources/portable_compressed_texture.h scene/resources/portable_compressed_texture.cpp) is intended for runtime-generated textures that need to be self-contained (not imported) while still supporting compression. It stores all data in a single PackedByteArray property with its own 20-byte header (compression mode, data format, image format, mipmap count, width, height).
CompressionMode options:
| Mode | Description |
|---|---|
COMPRESSION_MODE_LOSSLESS | PNG or WebP lossless |
COMPRESSION_MODE_LOSSY | WebP lossy |
COMPRESSION_MODE_BASIS_UNIVERSAL | Cross-platform GPU |
COMPRESSION_MODE_S3TC | Desktop (BC1–BC5) |
COMPRESSION_MODE_ETC2 | Mobile |
COMPRESSION_MODE_BPTC | Desktop (BC6H/BC7) |
COMPRESSION_MODE_ASTC | Adaptive (desktop + mobile) |
scene/resources/portable_compressed_texture.cpp56-125
AtlasTextureAtlasTexture (scene/resources/atlas_texture.h scene/resources/atlas_texture.cpp) wraps another Texture2D (atlas) and returns only the sub-region defined by region: Rect2. An optional margin property pads the logical size. The draw* methods adjust UV coordinates to sample only the sub-region.
DrawableTexture2DDrawableTexture2D (scene/resources/drawable_texture_2d.h) is a Texture2D that exposes blit operations so that code can draw to it at runtime (e.g., blit_rect). It maintains a GPU render target internally.
AnimatedTextureAnimatedTexture (deprecated) chains multiple Texture2D frames with per-frame durations, advancing based on speed_scale. It is not recommended for new projects and may be removed in a future version.
The following diagram shows how image data moves from file/memory into a GPU texture and ultimately onto the screen.
Image to GPU upload flow:
Sources: scene/resources/image_texture.cpp scene/resources/texture.cpp89-108
The editor's import pipeline converts raw image files into engine-native resource files. For the general import framework, see Resource Import System.
ResourceImporterTextureResourceImporterTexture (editor/import/resource_importer_texture.h editor/import/resource_importer_texture.cpp) handles standard 2D images. It:
ImageLoader..ctex (the CompressedTexture2D format)."CompressedTexture2D".Import presets:
| Preset | Default compress mode |
|---|---|
PRESET_DETECT | Lossless (2D detect auto-upgrades to VRAM when used in 3D) |
PRESET_2D | Lossless |
PRESET_3D | VRAM Compressed |
Compress modes available in import settings:
CompressMode | Description |
|---|---|
COMPRESS_LOSSLESS | PNG or WebP lossless per mip |
COMPRESS_LOSSY | WebP lossy per mip |
COMPRESS_VRAM_COMPRESSED | Platform-native BC/ETC2/ASTC |
COMPRESS_VRAM_UNCOMPRESSED | Raw bytes on GPU |
COMPRESS_BASIS_UNIVERSAL | Transcode-at-load cross-platform |
The save_to_ctex_format() static function writes the header and per-mode data:
Sources: editor/import/resource_importer_texture.cpp274-351
Auto-detection features:
_texture_reimport_3d(): When a texture is first used in a 3D context, schedules a reimport with mipmaps and VRAM compression enabled._texture_reimport_normal(): When a texture is detected as a normal map, schedules reimport with RG normal-map compression._texture_reimport_roughness(): When used as a roughness map, schedules reimport with roughness mipmap generation.editor/import/resource_importer_texture.cpp45-84
ResourceImporterLayeredTextureResourceImporterLayeredTexture (editor/import/resource_importer_layered_texture.h editor/import/resource_importer_layered_texture.cpp) handles cubemaps, 2D texture arrays, cubemap arrays, and 3D textures. A single source image is sliced into layers using slices/horizontal and slices/vertical parameters (or arrangement presets for cubemaps).
| Mode | Importer name | Save extension | Resource type |
|---|---|---|---|
MODE_CUBEMAP | cubemap_texture | .ccube | CompressedCubemap |
MODE_2D_ARRAY | 2d_array_texture | .ctexarray | CompressedTexture2DArray |
MODE_CUBEMAP_ARRAY | cubemap_array_texture | .ccubearray | CompressedCubemapArray |
MODE_3D | 3d_texture | .ctex3d | CompressedTexture3D |
The layered format uses the file header bytes G, S, T, L with its own version constant CompressedTextureLayered::FORMAT_VERSION.
Sources: editor/import/resource_importer_layered_texture.cpp42-102 editor/import/resource_importer_layered_texture.cpp269-300
The dds module (modules/dds/) provides:
TextureLoaderDDS: loads .dds files at runtime into ImageTexture, Texture2DArray, Cubemap, CubemapArray, or ImageTexture3D depending on the DDS header flags.ImageSaverDDS: saves Image objects to .dds files._dxgi_to_dds_format(): maps DXGI format codes to the internal DDSFormat enum, which in turn maps to Image::Format.modules/dds/texture_loader_dds.cpp39-484
The following static functions on Image are used extensively throughout the engine when computing buffer sizes and offsets:
| Function | Description |
|---|---|
get_format_pixel_size(Format) | Bytes per pixel (1 for block-compressed) |
get_format_block_size(Format) | Block size in pixels (4 or 8; 1 for uncompressed) |
get_format_pixel_rshift(Format) | Right-shift for sub-byte block ratios (ASTC 8x8 = 2) |
get_format_min_pixel_size(Format, &w, &h) | Minimum addressable block dimension |
get_image_data_size(w, h, Format, mipmaps) | Total byte size including optional mip chain |
get_image_required_mipmaps(w, h, Format) | Number of mip levels for a given resolution |
is_format_compressed(Format) | Whether the format is block-compressed |
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.