libdragon
Data Structures | Macros | Functions

RDP Command queue: high-level texture/surface loading and blitting. More...

Go to the source code of this file.

Data Structures

struct  rdpq_texparms_t
 Texture sampling parameters for rdpq_tex_upload. More...
 
struct  rdpq_blitparms_t
 Blitting parameters for rdpq_tex_blit. More...
 
struct  rdpq_texparms_t.s
 
struct  rdpq_texparms_t.t
 

Macros

#define MIRROR_REPEAT   true
 Enable mirroring when wrapping the texture, used in rdpq_texparms_t.
 
#define MIRROR_NONE   false
 Disable mirroring when wrapping the texture, used in rdpq_texparms_t.
 
#define REPEAT_INFINITE   2048
 Enable infinite repeat for the texture, used in rdpq_texparms_t.
 

Functions

int rdpq_tex_upload (rdpq_tile_t tile, const surface_t *tex, const rdpq_texparms_t *parms)
 Load a texture into TMEM. More...
 
int rdpq_tex_upload_sub (rdpq_tile_t tile, const surface_t *tex, const rdpq_texparms_t *parms, int s0, int t0, int s1, int t1)
 Load a portion of texture into TMEM. More...
 
void rdpq_tex_upload_tlut (uint16_t *tlut, int color_idx, int num_colors)
 Load one or more palettes into TMEM. More...
 
int rdpq_tex_reuse_sub (rdpq_tile_t tile, const rdpq_texparms_t *parms, int s0, int t0, int s1, int t1)
 Reuse a portion of the previously uploaded texture to TMEM. More...
 
int rdpq_tex_reuse (rdpq_tile_t tile, const rdpq_texparms_t *parms)
 Reuse the previously uploaded texture to TMEM. More...
 
void rdpq_tex_multi_begin (void)
 Begin a multi-texture upload. More...
 
int rdpq_tex_multi_end (void)
 Finish a multi-texture upload. More...
 
void rdpq_tex_blit (const surface_t *surf, float x0, float y0, const rdpq_blitparms_t *parms)
 Blit a surface to the active framebuffer. More...
 

Detailed Description

RDP Command queue: high-level texture/surface loading and blitting.


Data Structure Documentation

◆ rdpq_texparms_t

struct rdpq_texparms_t

Texture sampling parameters for rdpq_tex_upload.

This structure contains all possible parameters for rdpq_tex_upload. All fields have been made so that the 0 value is always the most reasonable default. This means that you can simply initialize the structure to 0 and then change only the fields you need (for instance, through a compound literal).

Data Fields
int tmem_addr TMEM address where to load the texture (default: 0)
int palette Palette number where TLUT is stored (used only for CI4 textures)
struct rdpq_texparms_t.s s
struct rdpq_texparms_t.t t

◆ rdpq_blitparms_t

struct rdpq_blitparms_t

Blitting parameters for rdpq_tex_blit.

This structure contains all possible parameters for rdpq_tex_blit. The various fields have been designed so that the 0 value is always the most reasonable default. This means that you can simply initialize the structure to 0 and then change only the fields you need (for instance, through a compound literal).

See rdpq_tex_blit for several examples.

Data Fields
rdpq_tile_t tile Base tile descriptor to use (default: TILE_0); notice that two tiles will often be used to do the upload (tile and tile+1).
int s0 Source sub-rect top-left X coordinate.
int t0 Source sub-rect top-left Y coordinate.
int width Source sub-rect width. If 0, the width of the surface is used.
int height Source sub-rect height. If 0, the height of the surface is used.
bool flip_x Flip horizontally. If true, the source sub-rect is treated as horizontally flipped (so flipping is performed before all other transformations)
bool flip_y Flip vertically. If true, the source sub-rect is treated as vertically flipped (so flipping is performed before all other transformations)
int cx Transformation center (aka "hotspot") X coordinate, relative to (s0, t0). Used for all transformations.
int cy Transformation center (aka "hotspot") X coordinate, relative to (s0, t0). Used for all transformations.
float scale_x Horizontal scale factor to apply to the surface. If 0, no scaling is performed (the same as 1.0f)
float scale_y Vertical scale factor to apply to the surface. If 0, no scaling is performed (the same as 1.0f)
float theta Rotation angle in radians.
bool filtering True if texture filtering is enabled (activates workaround for filtering artifacts when splitting textures in chunks)
int nx Texture horizontal repeat count. If 0, no repetition is performed (the same as 1)
int ny Texture vertical repeat count. If 0, no repetition is performed (the same as 1)

◆ rdpq_texparms_t.s

struct rdpq_texparms_t.s
Data Fields
float translate Translation of the texture (in pixels)
int scale_log Power of 2 scale modifier of the texture (default: 0). Eg: -2 = make the texture 4 times smaller.
float repeats Number of repetitions before the texture clamps (default: 1). Use REPEAT_INFINITE for infinite repetitions (wrapping)
bool mirror Repetition mode (default: MIRROR_NONE). If true (MIRROR_REPEAT), the texture mirrors at each repetition.

◆ rdpq_texparms_t.t

struct rdpq_texparms_t.t
Data Fields
float translate Translation of the texture (in pixels)
int scale_log Power of 2 scale modifier of the texture (default: 0). Eg: -2 = make the texture 4 times smaller.
float repeats Number of repetitions before the texture clamps (default: 1). Use REPEAT_INFINITE for infinite repetitions (wrapping)
bool mirror Repetition mode (default: MIRROR_NONE). If true (MIRROR_REPEAT), the texture mirrors at each repetition.

Function Documentation

◆ rdpq_tex_upload()

int rdpq_tex_upload ( rdpq_tile_t  tile,
const surface_t tex,
const rdpq_texparms_t parms 
)

Load a texture into TMEM.

This function helps loading a texture into TMEM, which normally involves:

After calling this function, the specified tile descriptor will be ready to be used in drawing primitives like rdpq_triangle or rdpq_texture_rectangle.

If the texture uses a palette (FMT_CI8 or FMT_CI4), the tile descriptor will be by default pointing to palette 0. In the case of FMT_CI4, this might not be the correct palette; to specify a different palette number, add .palette = X to the tex parms. Before drawing a texture with palette, remember to call rdpq_mode_tlut to activate palette mode.

If you want to load a portion of a texture rather than the full texture, use rdpq_tex_upload_sub, or alternatively create a sub-surface using surface_make_sub and pass it to rdpq_tex_upload. See rdpq_tex_upload_sub for an example of both techniques.

Parameters
tileTile descriptor that will be initialized with this texture
texSurface containing the texture to load
parmsAll optional parameters on where to load the texture and how to sample it. Refer to rdpq_texparms_t for more information.
Returns
Number of bytes used in TMEM for this texture
See also
rdpq_tex_upload_sub
surface_make_sub

◆ rdpq_tex_upload_sub()

int rdpq_tex_upload_sub ( rdpq_tile_t  tile,
const surface_t tex,
const rdpq_texparms_t parms,
int  s0,
int  t0,
int  s1,
int  t1 
)

Load a portion of texture into TMEM.

This function is similar to rdpq_tex_upload, but only loads a portion of a texture in TMEM. The portion is specified as a rectangle (with exclusive bounds) that must be contained within the original texture.

Notice that, after calling this function, you must draw the polygon using texture coordinates that are contained within the loaded ones. For instance:

// Load a 32x32 sprite starting at position (100,100) in the
// "spritemap" surface.
rdpq_tex_upload_sub(TILE2, spritemap, 0, 100, 100, 132, 132);
// Draw the sprite. Notice that we must refer to it using the
// original texture coordinates, even if just that portion is in TMEM.
pos_x, pos_y, pos_x+32, pos_y+32, // screen coordinates of the sprite
100, 100, // texture coordinates
1.0, 1.0); // texture increments (= no scaling)
@ TILE2
Tile #2 (for code readability)
Definition: rdpq.h:252
#define rdpq_texture_rectangle(tile, x0, y0, x1, y1, s, t)
Draw a textured rectangle (RDP command: TEXTURE_RECTANGLE)
Definition: rdpq_rect.h:307
int rdpq_tex_upload_sub(rdpq_tile_t tile, const surface_t *tex, const rdpq_texparms_t *parms, int s0, int t0, int s1, int t1)
Load a portion of texture into TMEM.
Definition: rdpq_tex.c:365

An alternative to this function is to call surface_make_sub on the texture to create a sub-surface, and then call rdpq_tex_upload on the sub-surface. The same data will be loaded into TMEM but this time the RDP ignores that you are loading a portion of a larger texture:

// Create a sub-surface of spritemap texture. No memory allocations
// or pixel copies are performed, this is just a rectangular "window"
// into the original texture.
surface_t hero = surface_make_sub(spritemap, 100, 100, 32, 32);
// Load the sub-surface. Notice that the RDP is unaware that it is
// a sub-surface; it will think that it is a whole texture.
// Draw the sprite. Notice that we must refer to it using
// texture coordinates (0,0).
pos_x, pos_y, pos_x+32, pos_y+32, // screen coordinates of the sprite
0, 0, // texture coordinates
1.0, 1.0); // texture increments (= no scaling)
int rdpq_tex_upload(rdpq_tile_t tile, const surface_t *tex, const rdpq_texparms_t *parms)
Load a texture into TMEM.
Definition: rdpq_tex.c:398
surface_t surface_make_sub(surface_t *parent, uint16_t x0, uint16_t y0, uint16_t width, uint16_t height)
Initialize a surface_t structure, pointing to a rectangular portion of another surface.
Definition: surface.c:57
A surface buffer for graphics.
Definition: surface.h:138

The only limit of this second solution is that the sub-surface pointer must be 8-byte aligned (like all RDP textures), so it can only be used if the rectangle that needs to be loaded respects such constraint as well.

Parameters
tileTile descriptor that will be initialized with this texture
texSurface containing the texture to load
parmsAll optional parameters on where to load the texture and how to sample it. Refer to rdpq_texparms_t for more information.
s0Top-left X coordinate of the rectangle to load
t0Top-left Y coordinate of the rectangle to load
s1Bottom-right exclusive X coordinate of the rectangle
t1Bottom-right exclusive Y coordinate of the rectangle
Returns
int Number of bytes used in TMEM for this texture
See also
rdpq_tex_upload
surface_make_sub

◆ rdpq_tex_upload_tlut()

void rdpq_tex_upload_tlut ( uint16_t *  tlut,
int  color_idx,
int  num_colors 
)

Load one or more palettes into TMEM.

This function allows to load one or more palettes into TMEM.

When using palettes, the upper half of TMEM is allocated to them. There is room for 256 colors in total, which allows for one palette for a CI8 texture, or up to 16 palettes for CI4 textures.

Parameters
tlutPointer to the color entries to load
color_idxFirst color entry in TMEM that will be written to (0-255)
num_colorsNumber of color entries to load (1-256)

◆ rdpq_tex_reuse_sub()

int rdpq_tex_reuse_sub ( rdpq_tile_t  tile,
const rdpq_texparms_t parms,
int  s0,
int  t0,
int  s1,
int  t1 
)

Reuse a portion of the previously uploaded texture to TMEM.

When a texture has been uploaded, its possible to reuse it for multiple tiles without increasing TMEM usage. This function provides a way to achieve this while also configuring your own texture parameters for the reused texture.

This sub-variant also allows to specify what part of the uploaded texture must be reused. For example, after uploading a 64x64 texture (or a 64x64 sub texture of a larger surface), you can reuse an existing portion of it, like (16,16)-(48,48) or (0,0)-(8,32). Restrictions of rdpq_texparms_t apply just when reusing just as well as for uploading a texture.

Sub-rectangle must be within the bounds of the texture reused and be 8-byte aligned, not all starting positions are valid for different formats.

Starting horizontal position s0 must be 8-byte aligned, meaning for different image formats you can use TEX_FORMAT_BYTES2PIX(fmt, bytes) with bytes being in multiples of 8. Starting vertical position t0 must be in multiples of 2 pixels due to TMEM arrangement.

Leaving parms to NULL will copy the previous' texture texparms. Note: This function must be executed in a multi-upload block right after the reused texture has been uploaded.

Parameters
tileTile descriptor that will be initialized with reused texture
parmsAll optional parameters on how to sample reused texture. Refer to rdpq_texparms_t for more information.
s0Top-left X coordinate of the rectangle to reuse
t0Top-left Y coordinate of the rectangle to reuse
s1Bottom-right exclusive X coordinate of the rectangle
t1Bottom-right exclusive Y coordinate of the rectangle
Returns
int Number of bytes used in TMEM for this texture (always 0)

◆ rdpq_tex_reuse()

int rdpq_tex_reuse ( rdpq_tile_t  tile,
const rdpq_texparms_t parms 
)

Reuse the previously uploaded texture to TMEM.

When a texture has been uploaded, its possible to reuse it for multiple tiles without increasing TMEM usage. This function provides a way to achieve this while also configuring your own texture parameters for the reused texture.

This full-variant will use the whole texture that was previously uploaded. Leaving parms to NULL will copy the previous' texture texparms.

Note: This function must be executed in a multi-upload block right after the reused texture has been uploaded.

Parameters
tileTile descriptor that will be initialized with reused texture
parmsAll optional parameters on how to sample reused texture. Refer to rdpq_texparms_t for more information.
Returns
int Number of bytes used in TMEM for this texture (always 0)

◆ rdpq_tex_multi_begin()

void rdpq_tex_multi_begin ( void  )

Begin a multi-texture upload.

This function begins a multi-texture upload, with automatic TMEM layout. There are two main cases where you may want to squeeze multiple textures within TMEM: when loading mipmaps, and when using multi-texturing.

After calling rdpq_tex_multi_begin, you can call rdpq_tex_upload multiple times in sequence, without manually specifying a TMEM address. The functions will start filling TMEM from the beginning, in sequence.

If the TMEM becomes full and is unable to fullfil a load, an assertion will be issued.

Note
When calling rdpq_tex_upload or rdpq_tex_upload_sub in this mode, do not specify a TMEM address in the parms structure, as the actual address is automatically calculated.
See also
rdpq_tex_upload
rdpq_tex_upload_sub
rdpq_tex_multi_end

◆ rdpq_tex_multi_end()

int rdpq_tex_multi_end ( void  )

Finish a multi-texture upload.

This function finishes a multi-texture upload. See rdpq_tex_multi_begin for more information.

Returns
The number of bytes used in TMEM for this multi-texture upload
See also
rdpq_tex_multi_begin.

◆ rdpq_tex_blit()

void rdpq_tex_blit ( const surface_t surf,
float  x0,
float  y0,
const rdpq_blitparms_t parms 
)

Blit a surface to the active framebuffer.

This is the highest level function for drawing an arbitrary-sized surface to the screen, possibly scaling and rotating it.

It handles all the required steps to blit the entire contents of a surface to the framebuffer, that is:

Note that this function only performs the actual blits, it does not configure the rendering mode or handle palettes. Before calling this function, make sure to configure the render mode via rdpq_set_mode_standard (or rdpq_set_mode_copy if no scaling and pixel format conversion is required). If the surface uses a palette, you also need to load the palette using rdpq_tex_upload_tlut.

This function is able to perform many different complex transformations. The implementation has been tuned to try to be as fast as possible for simple blits, but it scales up nicely for more complex operations.

The parameters that describe the transformations to perform are passed in the parms structure. The structure contains a lot of fields, but it has been designed so that most of them can be simply initalized to zero to disable advanced behaviors (and thus simply left unmentioned in an inline initialization).

For instance, this blits a large image to the screen, aligning it to the top-left corner (eg: a splashscreen).

rdpq_tex_blit(splashscreen, 0, 0, NULL);
void rdpq_tex_blit(const surface_t *surf, float x0, float y0, const rdpq_blitparms_t *parms)
Blit a surface to the active framebuffer.
Definition: rdpq_tex.c:667

This is the same, but the image will be centered on the screen. To do this, we specify the center of the screen as position, and then we set the hotspost of the image ("cx" and "cy" fields) to its center:

rdpq_tex_blit(splashscreen, 320/2, 160/2, &(rdpq_blitparms_t){
.cx = splashscreen->width / 2,
.cy = splashscreen->height / 2,
});
Blitting parameters for rdpq_tex_blit.
Definition: rdpq_tex.h:300

This examples scales a 64x64 image to 256x256, putting its center near the top-left of the screen (so part of resulting image will be offscreen):

rdpq_tex_blit(splashscreen, 20, 20, &(rdpq_blitparms_t){
.cx = splashscreen->width / 2, .cy = splashscreen->height / 2,
.scale_x = 4.0f, .scale_y = 4.0f,
});

This example assumes that the surface is a spritemap with frames of size 32x32. It selects the sprite at row 4, column 2, and draws it centered at position 100,100 on the screen applying a rotation of 45 degrees around its center:

rdpq_tex_blit(splashscreen, 100, 100, &(rdpq_blitparms_t){
.s0 = 32*2, .t0 = 32*4,
.width = 32, .height = 32,
.cx = 16, .cy = 16,
.theta = M_PI/4,
});
Parameters
surfSurface to draw
x0X coordinate on the framebuffer where to draw the surface
y0Y coordinate on the framebuffer where to draw the surface
parmsParameters for the blit operation (or NULL for default)