10.3 Large Texture Rectangles

Besides displaying the small texture rectangle, the gfx10.c sample program is also designed by default to display an animation of a wide picture scrolling from left to right in the background. At a size of 720x240, this background image is way too large to fit into the 4KB of TMEM. The image must be divided up for repeated loading and texture rectangle rendering.

List 10-4

  for(i = 0; i < (BACK_HT / ROWS); i++)
  {
    gDPLoadTextureTile(glistp++,
                      panorama,
                      G_IM_FMT_RGBA,
                      G_IM_SIZ_16b,
                      BACK_WD,
                      BACK_HT,
                      posx,
                      i * ROWS,
                      posx + (SCREEN_WD - 1),
                      i * ROWS + (ROWS - 1),
                      0,
                      G_TX_WRAP, G_TX_WRAP,
                      0, 0,
                      G_TX_NOLOD, G_TX_NOLOD);
    gSPTextureRectangle(glistp++,
                      0 << 2,
                      (i * ROWS) << 2,
                      (SCREEN_WD - 1) << 2,
                      (i * ROWS + (ROWS - 1)) << 2,
                      G_TX_RENDERTILE,
                      posx << 5, (i * ROWS) << 5,
                      4 << 10, 1 << 10);
  }

In this example, ROWS number of rows (the default is 2) are loaded at a time for texture rectangle rendering within the "for" loop. The cycle type is the high-speed Copy mode. In Copy mode, 4 pixels are transferred in every 1 cycle, so we recommend this mode when all you are going to do is render without changing the image. However, you need to be aware that in order to copy 4 pixels in 1 cycle, the change in S value in every cycle is four times larger. That is why the second to the last argument in the gSPTextureRectangle command gets [4 << 10] and not [1 <<< 10].

When you repeatedly load and render as shown here, the number of commands becomes extremely large and sometimes the display list is not big enough to accommodate them all. In fact, the display list becomes much larger than you might think, because the load commands gDPLoadTextureBlock and gDPLoadTextureTile are actually combinations of a number of lower-level commands. If you get in a situation where the last half of the texture rectangle is not rendered, we suggest you try increasing the size of the display list.

List 10-5

#define gDPLoadTextureBlock(pkt, timg, fmt, siz, width, height,         \
                   pal, cms, cmt, masks, maskt, shifts, shiftt)         \
{                                                                       \
        gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg);        \
        gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE,     \
                0 , cmt, maskt, shiftt, cms, masks, shifts);            \
        gDPLoadSync(pkt);                                               \
        gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0,                          \
                (((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1,    \
                CALC_DXT(width, siz##_BYTES));                          \
        gDPPipeSync(pkt);                                               \
        gDPSetTile(pkt, fmt, siz,                                       \
                (((width) * siz##_LINE_BYTES)+7)>>3, 0,                 \
                G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,   \
                shifts);                                                \
        gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0,                      \
                ((width)-1) << G_TEXTURE_IMAGE_FRAC,                    \
                ((height)-1) << G_TEXTURE_IMAGE_FRAC)                   \
}
#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height,          \
                uls, ult, lrs, lrt, pal,                                \
                cms, cmt, masks, maskt, shifts, shiftt)                 \
{                                                                       \
        gDPSetTextureImage(pkt, fmt, siz, width, timg);                 \
        gDPSetTile(pkt, fmt, siz,                                       \
                (((((lrs)-(uls)+1) * siz##_TILE_BYTES)+7)>>3), 0,       \
                G_TX_LOADTILE, 0 , cmt, maskt, shiftt, cms, masks,      \
                shifts);                                                \
        gDPLoadSync(pkt);                                               \
        gDPLoadTile(pkt, G_TX_LOADTILE,                                 \
                        (uls)<<G_TEXTURE_IMAGE_FRAC,                    \
                        (ult)<<G_TEXTURE_IMAGE_FRAC,                    \
                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                    \
                        (lrt)<<G_TEXTURE_IMAGE_FRAC);                   \
        gDPPipeSync(pkt);                                               \
        gDPSetTile(pkt, fmt, siz,                                       \
              (((((lrs)-(uls)+1) * siz##_LINE_BYTES)+7)>>3), 0,         \
              G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks,     \
              shifts);                                                  \
        gDPSetTileSize(pkt, G_TX_RENDERTILE,                            \
                        (uls)<<G_TEXTURE_IMAGE_FRAC,                    \
                        (ult)<<G_TEXTURE_IMAGE_FRAC,                    \
                        (lrs)<<G_TEXTURE_IMAGE_FRAC,                    \
                        (lrt)<<G_TEXTURE_IMAGE_FRAC)                    \
}