Q&A- Texture

QA1 Processing textures which can't be placed in TMEM
QA2 What is G_TEXTURE_GEN?
QA3 YUV format
QA4 Is it absolutely impossible to paste a texture that exceeds the TMEM size?
QA5 What is the TLUT method for a CI texture?
QA6 Garbage line around texture
QA7 Loading a texture to a specific location
QA8 What are a texture's s and t coordinates in the vertex data?
QA9 Priority of texture mapped "transparent" polygons when using the Z-buffer
QA10 Can I use translucence with "rectangle" in Palette mode?
QA11 How do I make Texture translucent?
QA12 How do I past texture data greater than 32x32 pixels?
QA13 How do I handle multiple TLUT?
QA14 How do I display a texture whose IA16 Tlut has been stored in 4bitCI?
QA15 How do I display a texture that has been made "invisible"?
QA16 What size textures can be stored in TMEM?
QA17 About linking textures...
QA18 The difference between the maximum number of lines that is the limit to the number of lines in LoadBlock and the absolute maximum number of lines...


Q1 When pasting a single texture which is too large to be placed in TMEM, e.g., 256x256, etc., onto a 4-sided polygon, I would have think that one would split the texture up with gDPLoadTexture(), or something, and paste it, but how should I specify the texture coordinates if I am not dividing up the polygon?

A1 There is no other way to do this but to split up the polygon.

top


Q2 When I set G_TEXTURE_GEN_LENEAR in gSPSetGeometryMode(), does the texture's linear mode become tri-linear? Or does it become bi-linear?

A2 This is setting is unrelated to bi-linear or tri-linear.

G_TEXTURE_GEN_LENEAR and G_TEXTURE_GEN specify whether a polygon surface is flat or if it is spherical. If it is spherical, it is calculated from the normal vector of the polygon.

Specify bi-linear or tri-linear with gDPSetTextureFilter.

top


Q3 What kind of format is the 16-bit YUV texel format?

A3 The YUV format is explained in detail in the "Texture Memory" section of the N64 Online Programming Manual. YUV is a color designation method made up of Y = brilliance, U = U axis component of the hue saturation, and V = V axis component of the hue saturation. It is used with CD-I and JPEG, etc. It is a convenient format for displaying video images compressed by JPEG or MPEG, etc. However, operation of this format is not currently guaranteed on the N64.

top


Q4 When the texture in a polygon or rectangle doesn't use wrapping or clamping, is it impossible to paste a texture which is too large to fit into TMEM?

A4 A texture which is too large to fit into TMEM cannot be pasted onto a single triangle polygon or rectangle. The size of one triangular polygon or rectangle onto which this texture can be pasted is determined by the size of TMEM. If you wish to paste a texture which is larger than TMEM, it can be pasted by dividing up the polygon or rectangle. Large textures are handled by only the size which can fit into TMEM being loaded and the texture being partially rendered. In the case of a rectangle, it is probably best to split the rectangle along the horizontal length. Polygons should be split into nearly right triangles.

Are you possibly using a texture which is too detailed? How about trying to decrease the intricacy of the texture and adjust the enlargement ratio?

Trying making it a 4bitCi texture. Double (4096 texels) the size of a 16 bit texture can be fit into TMEM.

top


Q5 When using LoadTlut with a CI texture, what is the best way of doing this?

A5 A sample is given below.

/* a 32x32 8-bit CI Texture */

#incldue "CI8mario.h"

Gfx textri_dl[] = {
    gsDPSetCycleType(G_CYC_1CYCLE),
    gsDPSetTextureFilter(G_TF_POINT),
    gsDPSetTexturePersp(G_TP_NONE),
    gsDPSetRenderMode(G_RM_OPA_SURF, G_RM_OPA_SURF2),
    gsDPSetCombineMode(G_CC_DECALRGB, G_CC_DECALRGB),
    gsDPLoadTLUT_pal256(CI8mariotlut),
    gsDPSetTextureLUT(G_TT_RGBA16),
    gsDPLoadTextureBlock(CI8mario, G_IM_FMT_CI, G_IM_SIZ_8b,
            32, 32, 0,
            G_TX_WRAP | G_TX_NOMIRROR,
            G_TX_WRAP | G_TX_NOMIRROR,
            G_TX_NOMASK, G_TX_NOMASK
            G_TX_NOLOD, G_TX_NOLOD),
    gsDPPipeSync(),

#define MAG_LOG    1

/* 1 or 2 works. anything bigger gets scissored */

#define SZ_X    (32 << MAG_LOG)
#define SZ_Y    (32 << MAG_LOG)
#define POS_X   (160 - (SZ_X / 2))
#define POS_Y   (120 - (SZ_Y / 2))

    gsSPTextureRectangle((POS_X) << 2, (POS_Y) << 2,
            (POS_X + SZ_X - 1) << 2, (POS_Y + SZ_Y -1) << 2,
            G_TX_RENDERTILE, 0, 0,
            1 << (10 - MAG_LOG), 1 << (10 - MAG_LOG)),

    gsSPEndDisplayList(),
};

top


Q6 When using gsDPSetTextureFilter(G_TF_BILERP), a white line of garbage appears at the edges of the texture. How do I get rid of this garbage?

A6 This symptom is not peculiar to this function, but it is associated with bilinear interpolation. To put it simply, when bilinear interpolation is applied to one texel, if the texel information for the 4 texels surrounding the target texel is not used as a reference value in the very end texels, then garbage data will appear. For more details, refer to the "Bilinear Filter" section and the "Bilinear Filtering and Point Sampling" section in the Programming Manual.

top


Q7 Whenever I see the gDPLoadTextureBlock or gDPLoadTextureTile command, it seems that I don't see anything in the argument for where in the TMEM to load data. For example, what should I do when I want to place two different types of texture data in TMEM at the same time?

A7 First, a portion of /usr/include/PR/gbi.h is excerpted below.

<Definition statement for gDPSetTile >
#define gDPSetTile(pkt, fmt, siz, line, tmem, tile, palette, cmt,f       \
        maskt, shiftt, cms, masks, shifts)                               \
{                                                                        \
    Gfx *_g = (Gfx *)(pkt);                                              \
                                                                         \
    _g->words.w0 = _SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) |     \
               _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) |               \
               _SHIFTL(tmem, 0, 9);                                      \
    _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) |      \
               _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) |             \
               _SHIFTL(shiftt, 10, 4) |_SHIFTL(cms, 8, 2) |              \
               _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4);             \
}

<Definition statement for gDPLoadTextureBlock>
#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)                        \
}

<Definition statement for _gDPLoadTextureBlock>
#define _gDPLoadTextureBlock(pkt, timg, tmem, 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, tmem, 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,       \
            tmem, 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)                        \
}

<Definition statement for gDPLoadTextureTile>
#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)                                 \
}

<Definition statement for gDPLoadMultiTile>
#define gDPLoadMultiTile(pkt, timg, tmem, rtile, 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), tmem,         \
            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), tmem,         \
            rtile, pal, cmt, maskt, shiftt, cms, masks,                  \
            shifts);                                                     \
    gDPSetTileSize(pkt, rtile,                                           \
            (uls)<<G_TEXTURE_IMAGE_FRAC,                                 \
            (ult)<<G_TEXTURE_IMAGE_FRAC,                                 \
            (lrs)<<G_TEXTURE_IMAGE_FRAC,                                 \
            (lrt)<<G_TEXTURE_IMAGE_FRAC)                                 \
}

As shown above, 0 [zero] is substituted for tmem at the point where gDPLoadTextureTile() or gDPLoadTextureBlock() are defining a macro. Now a macro is also partially prepared, as shown by gDPLoadTextureTile(), which can directly define tmem. If the features of _gDPLoadTexture are given as an example, the advantage of using this function is that, as much as possible, small textures are stored in TMEM only once, saving the time required for switching TMEMs. However, it was determined that the frequency that small textures are used is generally not very high, and it was set apart with a "_". Macros with "_" in gbi.h can be used the same as normal macros without any problems.

top


Q8 Please explain the "texture coordinates"

((0<<6) or (127<<6), etc.)
in the texture data
static Vtx tex_vtx{........};

used with onetri, etc. I don't understand the significance of including this in vertex data. In addition, I understand fixed point numbers, but why is there a 6 bit shift?

A8 The texture coordinates show at which coordinates in the texture image the vertex should be placed. Try changing these coordinates and see what happens. The way the texture is pasted should change.

Incidentally, various special effects can be obtained by dynamically changing these coordinates.

As for the significance of the 6 bit shift, please refer to another sample. There are a variety of samples showing 5 bit shift and no shift. Since these texture coordinates are given in s10.5 format, an whole number value is expressed by a 5 bit shift. Subsequently, the value of the shift changes according to the precision and pasting method, etc.

top


Q9 Priority of texture mapped "transparent" polygons when using the Z-buffer

When rendering translucent polygons, rendering doesn't seem to update the Z-buffer. (Consequently, this is good since, once a translucent polygon in the foreground has been drawn, even if a more distant translucent polygon is drawn later, it will still be displayed.)

It says in the Nintendo 64 Programming Manual that "billboard objects with tree outlines" can be created, but it seems that it would be necessary to set the function as follows, for example, making the rendering mode for the tree object polygons so that it is translucent, in order to determine which texels to eliminate.

gsDPSetRenderMode(G_RM_ZB_XLU_SURF, G_RM_ZB_XLU_SURF2),

However, when you do this, the priority is followed with respect to the polygons that were previously rendered, but since the Z-buffer is not updated, when the distant trees are subsequently rendered, the display priority per the Z-buffer does not function.

Does this mean simply that, even when rendering only the "transparent" and translucent objects, e.g., polygons with their wire frame truss structure mapped, they must be registered in the display list after a Z-sort in order to be rendered in the correct display order? In addition, is it possible to set the mode for updating the Z-buffer when displaying "billboard objects with tree outlines" (which updates the Z-buffer values of pixels with an alpha value which is greater than the THRESHOLD value set by gDPSetBlendColor(), etc.)?

A9 This problem can probably be resolved with the gsDPSetRenderMode settings. gDPSetRenderMode specifies the parameters which are defined by the macro, but the following kind of definition can be created by changing the existing parameters to create and specify original parameters

G_RM_ZB_XLU_SURF is defined as follows.

#define RM_ZB_XLU_SURF(clk) Z_CMP | IM_RD | CVG_DST_FILL | FORCE_BL | Z_MODE_XLU 
                        | GBL_c##clk(G_BL_CLR_IN, G_BLA_IN, G_BLCLR_MEM, G_BL_IMA)
#define G_RM_ZB_XLU_SURF RM_ZB_XLU_SURF(1)
#define G_RM_ZB_XLU_SURF2 RM_ZB_XLU_SURF(2)

By adding Z_UPD to this,

#define RM_ZB_XLU_SURF(clk) Z_CMP | Z_UPD | IM_RD | CVG_DST_FILL | FORCE_BL | ZMODE_XLU 
                        | GBL_c##clk(G_BL_CLR_IN, G_BLA_IN, G_BLCLR_MEM, G_BL_IMA) 
#define G_RM_ZB_XLU_SURF RM_ZB_XLU_SURF(1)
#define G_RM_ZB_XLU_SURF2 RM_ZB_XLU_SURF(2)

the Z-buffer will be updated even when rendring translucent polygons.

In addition, G_RM_ZB_OPA_SURF is defined as follows.

#define RM_ZB_OPA_SURF(clk) Z_CMP | Z_UPD | CVG_DST_FILL | ALPHA_CVG_SEL | ZMODE_OPA 
                        | GBL_c##clk(G_BL_CLR_IN, G_BLA_IN, G_BLCLR_MEM, G_BL_A_MEM)
#define G_RM_ZB_OPA_SURF RM_ZB_OPA_SURF(1)
#define G_RM_ZB_OPA_SURF2 RM_ZB_OPA_SURF(2)

By deleting ALPHA_SVG_SEL from this,

#define RM_ZB_OPA_SURF(clk) Z_CMP | Z_UPD | CVG_DST_FILL | ZMODE_OPA
                        | GBL_c##clk(G_BL_CLR_IN, G_BLA_IN, G_BLCLR_MEM, G_BL_A_MEM)
#define G_RM_ZB_OPA_SURF RM_ZB_OPA_SURF(1)
#define G_RM_ZB_OPA_SURF2 RM_ZB_OPA_SURF(2)

and combining it with gsDPSetAlphaCompare (G_AC_THRESHOLD) a "transparency" can be created in a translucent polygon.

Refer to the gbi.h file regarding macro parameters.

In addition, refer to the detailed explanation of these macros in the Render Mode section of the Programming Manual.

top


Q10 Can I use translucence with "rectangle" in Palette mode?

A10 The palette contents are 21-bit color, so you cannot achieve translucent effects. To use translucence, you need 32-bit color or IA mode.

top


Q11 How do I make Texture translucent?

A11 Translucency cannot be realized with only the texture unless the texture is an RGBA32 texture or an IA texture. However, besides textures such as primitives, all sorts of translucent textures can be realized by combining alpha values and the alpha combiner.

top


Q12 I am currently using the gDPLoadTextureBlock() function to past texture data which is larger than 32x32 texels, but I can't use it to paste up to 32x64 data.

A12 Using gDPLoadTextureTile allows you to paste larger textures. However, since, naturally, only one texture can be pasted onto a polygon per 1 cycle, textures which are too large to fit into TMEM must be pasted by dividing the polygon accordingly. (It is preferable to do this on the data level.) The TMEM capacity is as follows.

With CI, the front 2K of TMEM are used for pixels, while the back 2K are used for the color table. When the CI format is used, a single, large texture can be pasted if the polygon is divided so that it can fit in TMEM (at least, it will appear to be pasted). gDPLoadTextureTile allows you to transfer part of a large image to TMEM as a texture. Therefore, the surface area of the texture of the model data can divided into polygons of a size which can fit into TMEM, or a converter can be used to do that.

Example
Texture image: 256x256 pixel
+------------+
|            |
|            |
|  texture   |
|            |
|            |
+------------+
Pasted on the entire polygon below (s,t are tex coord)
(s,t)=(0,0)
+------------+
|            |
|            |
|  polygon   |
|            |
|            |
+------------+
(s,t)=(255,255)
With 32 bit RGBA, the TMEM size which can be handled at once is 32x32 (256x4 is also possible)

The above is
(s,t)=(0,0)
  . 
  (s,t)=(31,31)
The above is
(s,t)=(63,31)
such that the image is divided into a total of 8x8=64 polygons. The display list is as follows.
gsDPLoadTextureTile(tex_image,
G_IM_FMT_RGBA,
G_IM_SIZ_32b,
256,256,
0,0,31,31,
0,G_TX_CLAMP,G_TX_CLAMP,
6,6,G_TX_NOLOD,G_TX_NOLOD),
gsSP1Triangle(0,1,2,0),
gsSP1Triangle(2,3,0,0),
gsDPLoadTextureTile(tex_image,G_IM_FMT_RGBA,
G_IM_SIZ_32b,
256,256,
32,0,63,31,
0,G_TX_CLAMP,G_TX_CLAMP,
6,6,G_TX_NOLOD,G_TX_NOLOD),
gsSP1Triangle(4,5,6,0),
gsSP1Triangle(6,7,4,0),
:
:
(Of course, it is necessary to align the tex coord(s,t) of the Vtx.)

top


Q13 How do I handle multiple TLUT?

A13 Normally, when there are multiple TLUT, they are loaded separately. When two CI textures are being used at the same time, and they each have a different TLUT, a technique is needed such as decreasing their colors 128 colors each, and using the TLUT one half at a time.

top


Q14 What settings do I use to be able to display a texture whose IA16 Tlut has been stored in 4bitC.

A14 After preparing texture data and the CI palette, you can display the texture by setting "G_TT_IA16" with gDPSetTextureLUT and the specifying "G_IM_FMT_C" where a texture is loaded, such as at gDPTextureLoadBlock. Use a translucent setting such as XLU_SURF or CLD_SURF for the RenderMode.

top


Q15 I would like to display a polygon with an "invisible" texture. The texture data are 4bitCI texture.

A15 As for 4bitCI textures, RGBA16 format color textures or IA16 format intensity alpha textures are stored in 16 palettes. Let's continue the discussion supposing that you wish to use the RGBA16 format. THe RGBA16 mode consists of R:5, G:5, B:5, alpha:1bit. Therefore, create a texture in which a color (e.g., 0xfffe) with "alpha-0" is placed in one of the 16 palettes, while the pixels of that color are placed in the location that you wish to be transparent. If rendered with RenderMode set to TEX_EDGE or XLU_SURF and CombineMode set to DECALRGBA, the alpha will be removed. It is also possible to remove the alpha in the OPA_SURF mode if alpha compare is used.

top


Q16 I am transferring texture data to TMEM using gDPLoadTextureTile_4b, but when transferring 64x32 texture, will processing automatically switch to transferring two 32x32 textures? With respect to the size of TMEM, it seems that 4-bit texture data can be transferred as one 64x32 piece. Or is there a limit on the texture size of 32x32?

A16 The size of TMEM is 4Kbyte. As long as it within that range, a texture can be loaded all at one time. Since 4Kbyte=32768 bits, it is possible to load up to 2047 texels, i.e., 32x64, of texture as long as it is a 16bit RGBA texture. Of course, 16x128 is OK, too. Therefore, there is not need particularly to process textures in 32x32 units. However, please note that even TLUT must be loaded into the 4Kbyte when in the color index mode.

top


Q17 Is it possible in the 2CYCLE mode to link a 4bitI texture as an alpha source to a 4bitCI texture?

A17 Unfortunately, you cannot link a CI texture to any other type in the 2 cycle mode. This is because the format in MEM is prepared for LUT (See Chapter 13 page 30 in the Programming Manual).

top


Q18 In Chapter 13 "Texture Mapping," Appendix A, of the N64 Programming Manual, there is mention of "limits on the number of lines that can be set with the LoadBlock command." What is the difference between the maximum number of lines and the absolute maximum number of lines? In addition, when using other 4-bit and 8-bit texture, how should the maximum number of lines be calculated?

A18 As explained on page 39 in Chapter 13 of the of the Programming Manual, the line counter is incremented using the dxt parameter in LoadBlock. If this dxt value is not a multiple of 2, the program will crash due to the counter accumulating errors. That limit value is the "maximum number of lines", while the "absolute maximum number of lines" is the TMEM capacity divided by the width of the texture as a logical value. In addition, when other 4-bit and 8-bit textures are used, consider the following.

4b   View the list as 1/4 the width
8b   View the list as 1/2 the width
32b  View the list as double the width

top