libdragon
Data Structures | Macros | Functions | Variables

RDP Command queue: texture loading. More...

Data Structures

struct  rdpq_multi_upload_t
 Non-zero if we are doing a multi-texture upload. More...
 

Macros

#define TMEM_PALETTE_ADDR   0x800
 Address in TMEM where the palettes must be loaded.
 

Functions

int integer_to_pow2 (int x)
 Calculates the first power of 2 that is equal or larger than size. 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...
 
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_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_blit (const surface_t *surf, float x0, float y0, const rdpq_blitparms_t *parms, large_tex_draw ltd)
 Internal implementation of rdpq_tex_blit, using a custom large tex loader callback function.
 
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...
 
void rdpq_tex_upload_tlut (uint16_t *tlut, int color_idx, int num_colors)
 Load one or more palettes into 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...
 

Variables

tex_loader_t last_tload
 Information on last image uploaded we are doing a multi-texture upload.
 

Detailed Description

RDP Command queue: texture loading.


Data Structure Documentation

◆ rdpq_multi_upload_t

struct rdpq_multi_upload_t

Non-zero if we are doing a multi-texture upload.

Data Fields
int used
int bytes
int limit

Function Documentation

◆ integer_to_pow2()

int integer_to_pow2 ( int  x)

Calculates the first power of 2 that is equal or larger than size.

Parameters
xinput in units
Returns
Power of 2 that is equal or larger than x

◆ 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:293
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, uint32_t x0, uint32_t y0, uint32_t width, uint32_t height)
Initialize a surface_t structure, pointing to a rectangular portion of another surface.
Definition: surface.c:56
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()

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_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_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)

◆ 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_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.