//--------------------------------------------------------------------------- void gs_load_texture(u16 x, u16 y, u16 w, u16 h, u32 data_adr, u32 dest_adr, u16 dest_w) { u32 i; // DMA buffer loop counter u32 frac; // flag for whether to run a fractional buffer or not u32 current; // number of pixels to transfer in current DMA u32 qtotal; // total number of qwords of data to transfer BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, bitbltbuf, GS_BITBLTBUF(0, 0, 0, dest_adr/256, // frame buffer address dest_w/64, // frame buffer width 0)); GIF_DATA_AD(gs_dma_buf, trxpos, GS_TRXPOS( 0, 0, x, y, 0)); // left to right/top to bottom GIF_DATA_AD(gs_dma_buf, trxreg, GS_TRXREG(w, h)); GIF_DATA_AD(gs_dma_buf, trxdir, GS_TRXDIR(XDIR_EE_GS)); SEND_GS_PACKET(gs_dma_buf); qtotal = w*h/4; // total number of quadwords to transfer. current = qtotal % MAX_TRANSFER;// work out if a partial buffer transfer is needed. frac=1; // assume yes. if(!current) // if there is no need for partial buffer { current = MAX_TRANSFER; // start with a full buffer frac=0; // and don't do extra partial buffer first } for(i=0; i<(qtotal/MAX_TRANSFER)+frac; i++) { BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_IMG(gs_dma_buf, current); SEND_GS_PACKET(gs_dma_buf); SET_QWC(GIF_QWC, current); SET_MADR(GIF_MADR, data_adr, 0); SET_CHCR(GIF_CHCR, 1, 0, 0, 0, 0, 1, 0); DMA_WAIT(GIF_CHCR); data_adr += current*16; current = MAX_TRANSFER; // after the first one, all are full buffers } // Access the TEXFLUSH register with anything to flush the texture BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 1, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, texflush, 0x42); SEND_GS_PACKET(gs_dma_buf); }
//--------------------------------------------------------------------------- void g2_fill_rect(s16 x0, s16 y0, s16 x1, s16 y1) { x0 += gs_origin_x; y0 += gs_origin_y; x1 += gs_origin_x; y1 += gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(g2_fill_r, g2_fill_g, g2_fill_b, 0x80, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x0<<4, y0<<4, 0)); // It looks like the default operation for the SPRITE primitive is to // not draw the right and bottom 'lines' of the rectangle refined by // the parameters. Add +1 to change this. GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2((x1+1)<<4, (y1+1)<<4, 0)); SEND_GS_PACKET(gs_dma_buf); }
void gsKit_set_test(GSGLOBAL *gsGlobal, u8 Preset) { u64 *p_data; u64 *p_store; if(Preset == GS_ZTEST_OFF) gsGlobal->Test->ZTST = 1; else if (Preset == GS_ZTEST_ON) gsGlobal->Test->ZTST = 2; else if (Preset == GS_ATEST_OFF) gsGlobal->Test->ATE = 0; else if (Preset == GS_ATEST_ON) gsGlobal->Test->ATE = 1; else if (Preset == GS_D_ATEST_OFF) gsGlobal->Test->DATE = 0; else if (Preset == GS_D_ATEST_ON) gsGlobal->Test->DATE = 1; p_data = p_store = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; *p_data++ = GS_SETREG_TEST( gsGlobal->Test->ATE, gsGlobal->Test->ATST, gsGlobal->Test->AREF, gsGlobal->Test->AFAIL, gsGlobal->Test->DATE, gsGlobal->Test->DATM, gsGlobal->Test->ZTE, gsGlobal->Test->ZTST ); *p_data++ = GS_TEST_1+gsGlobal->PrimContext; }
//--------------------------------------------------------------------------- void g2_put_image(s16 x, s16 y, s16 w, s16 h, u32 *data) { x += gs_origin_x; y += gs_origin_y; // - Call this to copy the texture data from EE memory to GS memory. // - The g2_texbuf_addr variable holds the byte address of the // 'texture buffer' and is setup in g2_init() to be just after // the frame buffer(s). When only the standard resolutions are // used this buffer is guaranteed to be correctly aligned on 256 // bytes. gs_load_texture(0, 0, w, h, (u32)data, g2_texbuf_addr, g2_max_x+1); BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); // Setup the Texture Buffer register. Note the width and height! They // must both be a power of 2. GIF_DATA_AD(gs_dma_buf, tex0_1, GS_TEX0( g2_texbuf_addr/256, // base pointer (g2_max_x+1)/64, // width 0, // 32bit RGBA gs_texture_wh(w), // width gs_texture_wh(h), // height 1, // RGBA TEX_DECAL, // just overwrite existing pixels 0,0,0,0,0)); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_SPRITE, 0, // flat shading 1, // texture mapping ON 0, 0, 0, // no fog, alpha, or antialiasing 1, // use UV register for coordinates. 0, 0)); // Texture and vertex coordinates are specified consistently, with // the last four bits being the decimal part (always X.0 here). // Top/Left, texture coordinates (0, 0). GIF_DATA_AD(gs_dma_buf, uv, GS_UV(0, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x<<4, y<<4, 0)); // Bottom/Right, texture coordinates (w, h). GIF_DATA_AD(gs_dma_buf, uv, GS_UV(w<<4, h<<4)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2((x+w)<<4, (y+h)<<4, 0)); // Finally send the command buffer to the GIF. SEND_GS_PACKET(gs_dma_buf); }
void gsKit_set_texfilter(GSGLOBAL *gsGlobal, u8 FilterMode) { u64 *p_data; u64 *p_store; p_data = p_store = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; *p_data++ = GS_SETREG_TEX1(0, 0, FilterMode, FilterMode, 0, 0, 0); *p_data++ = GS_TEX1_1+gsGlobal->PrimContext; }
//--------------------------------------------------------------------------- void g2_set_viewport(u16 x0, u16 y0, u16 x1, u16 y1) { g2_view_x0 = x0; g2_view_x1 = x1; g2_view_y0 = y0; g2_view_y1 = y1; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 1, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, scissor_1, GS_SCISSOR(x0, x1, y0, y1)); SEND_GS_PACKET(gs_dma_buf); }
//--------------------------------------------------------------------------- void g2_set_active_frame(u8 frame) { BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 1, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( g2_frame_addr[frame]/8192, // FrameBuffer base pointer = Address/8192 cur_mode->width/64, // Frame buffer width (Pixels/64) cur_mode->psm, // Pixel Storage Format 0)); SEND_GS_PACKET(gs_dma_buf); g2_active_frame = frame; }
void gsKit_set_dither_matrix(GSGLOBAL *gsGlobal) { u64 *p_data; u64 *p_store; p_data = p_store = gsKit_heap_alloc(gsGlobal, 1 ,16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; *p_data++ = GS_SETREG_DIMX( gsGlobal->DitherMatrix[0], gsGlobal->DitherMatrix[1], gsGlobal->DitherMatrix[2], gsGlobal->DitherMatrix[3], gsGlobal->DitherMatrix[4], gsGlobal->DitherMatrix[5], gsGlobal->DitherMatrix[6], gsGlobal->DitherMatrix[7], gsGlobal->DitherMatrix[8], gsGlobal->DitherMatrix[9], gsGlobal->DitherMatrix[10], gsGlobal->DitherMatrix[11], gsGlobal->DitherMatrix[12], gsGlobal->DitherMatrix[13], gsGlobal->DitherMatrix[14], gsGlobal->DitherMatrix[15]); *p_data++ = GS_DIMX; }
/* // taken from libgraph void gsKit_set_drawfield(GSGLOBAL *gsGlobal, u8 field) { u64 *p_data; u64 *p_store; (u32)p_data = (u32)p_store = gsGlobal->dma_misc; *p_data++ = GIF_TAG( 1, 1, 0, 0, 0, 1); *p_data++ = GIF_AD; if (field == GS_FIELD_NORMAL) { //Draw both *p_data++ = GIF_TAG_SCANMSK(0); } else if (field == GS_FIELD_ODD) { // Draw only odd *p_data++ = GIF_TAG_SCANMSK(2); } else if (field == GS_FIELD_EVEN) { // Draw only even *p_data++ = GIF_TAG_SCANMSK(3); } *p_data++ = GS_SCANMSK; dmaKit_wait_fast(); dmaKit_send_ucab(DMA_CHANNEL_GIF, p_store, 2); } */ GSQUEUE gsKit_set_finish(GSGLOBAL *gsGlobal) { u64 *p_data; u64 *p_store; GSQUEUE oldQueue = *gsGlobal->CurQueue; p_data = p_store = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; *p_data++ = 0; *p_data++ = GS_FINISH; return oldQueue; }
void gsKit_set_dither(GSGLOBAL *gsGlobal) { u64 *p_data; u64 *p_store; p_data = p_store = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; if(gsGlobal->Dithering == GS_SETTING_ON) *p_data++ = 1; else *p_data++ = 0; *p_data++ = GS_DTHE; }
//--------------------------------------------------------------------------- void g2_set_font_color(u8 red, u8 green, u8 blue) { u64 x0; u64 y0; u64 x1; u64 y1; x0 = gs_origin_x-10; y0 = gs_origin_y-10; x1 = g2_fontbuf_w + gs_origin_x; y1 = g2_fontbuf_h + gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); // Restore the frame buffer to the current active frame buffer. GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( g2_fontbuf_addr/8192, cur_mode->width/64, cur_mode->psm, 0)); // Draw the colored rectangle over the entire Font Bitmap. GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_LINE, 0, 0, 0, 0, 0, 0, 0, 0)); // GS_PRIM(PRIM_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(red, green, blue, 0x80, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x0<<4, y0<<4, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x1<<4, y1<<4, 0)); // Restore the frame buffer to the current active frame buffer. GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( g2_frame_addr[g2_active_frame]/8192, cur_mode->width/64, cur_mode->psm, 0)); SEND_GS_PACKET(gs_dma_buf); }
void gsKit_set_primalpha(GSGLOBAL *gsGlobal, u64 AlphaMode, u8 PerPixel) { u64 *p_data; u64 *p_store; gsGlobal->PrimAlpha = AlphaMode; gsGlobal->PABE = PerPixel; p_data = p_store = gsKit_heap_alloc(gsGlobal, 2, 32, GIF_AD); *p_data++ = GIF_TAG_AD(2); *p_data++ = GIF_AD; *p_data++ = gsGlobal->PABE; *p_data++ = GS_PABE; *p_data++ = gsGlobal->PrimAlpha; *p_data++ = GS_ALPHA_1+gsGlobal->PrimContext; }
//--------------------------------------------------------------------------- void g2_line(s16 x0, s16 y0, s16 x1, s16 y1) { x0 += gs_origin_x; y0 += gs_origin_y; x1 += gs_origin_x; y1 += gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_LINE, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(g2_col_r, g2_col_g, g2_col_b, 0x80, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x0<<4, y0<<4, 0)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x1<<4, y1<<4, 0)); SEND_GS_PACKET(gs_dma_buf); }
//--------------------------------------------------------------------------- void g2_put_pixel(s16 x, s16 y) { x += gs_origin_x; y += gs_origin_y; BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 4, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_POINT, 0, 0, 0, 0, 0, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, rgbaq, GS_RGBAQ(g2_col_r, g2_col_g, g2_col_b, 0x80, 0)); // The XYZ coordinates are actually floating point numbers between // 0 and 4096 represented as unsigned integers where the lowest order // four bits are the fractional point. That's why all coordinates are // shifted left 4 bits. GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x<<4, y<<4, 0)); SEND_GS_PACKET(gs_dma_buf); }
// taken from libgraph void gsKit_set_drawfield(GSGLOBAL *gsGlobal, u8 field) { u64 *p_data; u64 *p_store; p_data = p_store = gsKit_heap_alloc(gsGlobal, 1 ,16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; if (field == GS_FIELD_NORMAL) { //Draw both *p_data++ = 0;; } else if (field == GS_FIELD_ODD) { // Draw only odd *p_data++ = 2; } else if (field == GS_FIELD_EVEN) { // Draw only even *p_data++ = 3; } *p_data++ = GS_SCANMSK; }
void gsKit_set_clamp(GSGLOBAL *gsGlobal, u8 Preset) { u64 *p_data; u64 *p_store; if(Preset == GS_CMODE_REPEAT) { gsGlobal->Clamp->WMS = GS_CMODE_REPEAT; gsGlobal->Clamp->WMT = GS_CMODE_REPEAT; } else if(Preset == GS_CMODE_CLAMP) { gsGlobal->Clamp->WMS = GS_CMODE_CLAMP; gsGlobal->Clamp->WMT = GS_CMODE_CLAMP; } else if(Preset == GS_CMODE_REGION_CLAMP) { gsGlobal->Clamp->WMS = GS_CMODE_REGION_CLAMP; gsGlobal->Clamp->WMT = GS_CMODE_REGION_CLAMP; } else if(Preset == GS_CMODE_REGION_REPEAT) { gsGlobal->Clamp->WMS = GS_CMODE_REGION_REPEAT; gsGlobal->Clamp->WMT = GS_CMODE_REGION_REPEAT; } p_data = p_store = gsKit_heap_alloc(gsGlobal, 1, 16, GIF_AD); *p_data++ = GIF_TAG_AD(1); *p_data++ = GIF_AD; *p_data++ = GS_SETREG_CLAMP(gsGlobal->Clamp->WMS, gsGlobal->Clamp->WMT, gsGlobal->Clamp->MINU, gsGlobal->Clamp->MAXU, gsGlobal->Clamp->MINV, gsGlobal->Clamp->MAXV); *p_data++ = GS_CLAMP_1+gsGlobal->PrimContext; }
//--------------------------------------------------------------------------- void g2_out_text(s16 x, s16 y, char *str) { char c; // current character u16 *tc; // current texture coordinates [4] u16 x0, y0, x1, y1; // rectangle for current character u16 w, h; // width and height of above rectangle x += gs_origin_x; y += gs_origin_y; c = *str; while(c) { // Read the texture coordinates for current character tc = &g2_font_tc[c*4]; x0 = *tc++; y0 = *tc++; x1 = *tc++; y1 = *tc++; w = x1-x0+1; h = y1-y0+1; // Draw a sprite with current character mapped onto it BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); GIF_DATA_AD(gs_dma_buf, tex0_1, GS_TEX0( g2_fontbuf_addr/256, // base pointer (g2_fontbuf_w)/64, // width 0, // 32bit RGBA gs_texture_wh(g2_fontbuf_w),// width gs_texture_wh(g2_fontbuf_w),// height 1, // RGBA TEX_DECAL, // just overwrite existing pixels 0,0,0,0,0)); /* GIF_DATA_AD(gs_dma_buf, tex1_1, GS_TEX1( 0, 0, FILTER_LINEAR, FILTER_LINEAR, 0, 0, 0)); GIF_DATA_AD(gs_dma_buf, clamp_1, 0x05); */ GIF_DATA_AD(gs_dma_buf, prim, GS_PRIM(PRIM_SPRITE, 0, // flat shading 1, // texture mapping ON 0, 1, 0, // no fog or antialiasing, but use alpha 1, // use UV register for coordinates. 0, 0)); GIF_DATA_AD(gs_dma_buf, uv, GS_UV(x0<<4, y0<<4)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2(x<<4, y<<4, 0)); GIF_DATA_AD(gs_dma_buf, uv, GS_UV((x1+1)<<4, (y1+1)<<4)); GIF_DATA_AD(gs_dma_buf, xyz2, GS_XYZ2( (x+w*g2_font_mag)<<4, (y+h*g2_font_mag)<<4, 0)); SEND_GS_PACKET(gs_dma_buf); // Advance drawing position x += (w + g2_font_spacing) * g2_font_mag; // Get next character str++; c = *str; } }
//--------------------------------------------------------------------------- int g2_init(g2_video_mode mode) { vmode_t *v; v = &(vmodes[mode]); cur_mode = v; g2_max_x = v->width - 1; g2_max_y = v->height - 1; g2_view_x0 = 0; g2_view_y0 = 0; g2_view_x1 = g2_max_x; g2_view_y1 = g2_max_y; gs_origin_x = 1024; gs_origin_y = 1024; gs_mem_current = 0; // nothing allocated yet g2_visible_frame = 0; // display frame 0 g2_active_frame = 0; // draw to frame 0 // - Initialize the DMA. // - Writes a 0 to most of the DMA registers. dma_reset(); // - Sets the RESET bit if the GS CSR register. GS_RESET(); #ifndef FLASH // - Can someone please tell me what the sync.p // instruction does. Synchronizes something :-) __asm__(" sync.p nop "); #endif // - Sets up the GS IMR register (i guess). // - The IMR register is used to mask and unmask certain interrupts, // for example VSync and HSync. We'll use this properly in Tutorial 2. // - Does anyone have code to do this without using the 0x71 syscall? // - I havn't gotten around to looking at any PS2 bios code yet. gs_set_imr(); // - Use syscall 0x02 to setup some video mode stuff. // - Pretty self explanatory I think. // - Does anyone have code to do this without using the syscall? It looks // like it should only set the SMODE2 register, but if I remove this syscall // and set the SMODE2 register myself, it donesn't work. What else does // syscall 0x02 do? gs_set_crtc(NON_INTERLACED, v->ntsc_pal, FRAME); // - I havn't attempted to understand what the Alpha parameters can do. They // have been blindly copied from the 3stars demo (although they don't seem // do have any impact in this simple 2D code. GS_SET_PMODE( 0, // ReadCircuit1 OFF 1, // ReadCircuit2 ON 1, // Use ALP register for Alpha Blending 1, // Alpha Value of ReadCircuit2 for output selection 0, // Blend Alpha with the output of ReadCircuit2 0xFF // Alpha Value = 1.0 ); /* // - Non needed if we use gs_set_crt() GS_SET_SMODE2( 0, // Non-Interlaced mode 1, // FRAME mode (read every line) 0 // VESA DPMS Mode = ON ??? please explain ??? ); */ GS_SET_DISPFB2( 0, // Frame Buffer base pointer = 0 (Address/8192) v->width/64, // Buffer Width (Pixels/64) v->psm, // Pixel Storage Format 0, // Upper Left X in Buffer = 0 0 // Upper Left Y in Buffer = 0 ); // Why doesn't (0, 0) equal the very top-left of the TV? GS_SET_DISPLAY2( 656, // X position in the display area (in VCK units) 36, // Y position in the display area (in Raster units) v->magh-1, // Horizontal Magnification - 1 0, // Vertical Magnification = 1x v->width*v->magh-1, // Display area width - 1 (in VCK units) (Width*HMag-1) v->height-1 // Display area height - 1 (in pixels) (Height-1) ); GS_SET_BGCOLOR( 0, // RED 0, // GREEN 0 // BLUE ); BEGIN_GS_PACKET(gs_dma_buf); GIF_TAG_AD(gs_dma_buf, 6, 1, 0, 0, 0); // Use drawing parameters from PRIM register GIF_DATA_AD(gs_dma_buf, prmodecont, 1); // Setup frame buffers. Point to 0 initially. GIF_DATA_AD(gs_dma_buf, frame_1, GS_FRAME( 0, // FrameBuffer base pointer = 0 (Address/8192) v->width/64, // Frame buffer width (Pixels/64) v->psm, // Pixel Storage Format 0)); // Save address and advance GS memory pointer by buffer size (in bytes) // Do this for both frame buffers. g2_frame_addr[0] = gs_mem_current; gs_mem_current += v->width * v->height * (v->bpp/8); g2_frame_addr[1] = gs_mem_current; gs_mem_current += v->width * v->height * (v->bpp/8); // Displacement between Primitive and Window coordinate systems. GIF_DATA_AD(gs_dma_buf, xyoffset_1, GS_XYOFFSET( gs_origin_x<<4, gs_origin_y<<4)); // Clip to frame buffer. GIF_DATA_AD(gs_dma_buf, scissor_1, GS_SCISSOR( 0, g2_max_x, 0, g2_max_y)); // Create a single 256x128 font buffer g2_fontbuf_addr = gs_mem_current; gs_mem_current += g2_fontbuf_w * g2_fontbuf_h * (v->bpp/8); // Create a texture buffer as big as the screen. // Just save the address advance GS memory pointer by buffer size (in bytes) // The TEX registers are set later, when drawing. g2_texbuf_addr = gs_mem_current; gs_mem_current += v->width * v->height * (v->bpp/8); // Setup test_1 register to allow transparent texture regions where A=0 GIF_DATA_AD(gs_dma_buf, test_1, GS_TEST( 1, // Alpha Test ON ATST_NOTEQUAL, 0x00, // Reject pixels with A=0 AFAIL_KEEP, // Don't update frame or Z buffers 0, 0, 0, 0)); // No Destination Alpha or Z-Buffer Tests // Setup the ALPHA_1 register to correctly blend edges of // pre-antialiased fonts using Alpha Blending stage. // The blending formula is // PIXEL=(SRC-FRAME)*SRC_ALPHA>>7+FRAME GIF_DATA_AD(gs_dma_buf, alpha_1, GS_ALPHA( 0, // A - source 1, // B - frame buffer 0, // C - alpha from source 1, // D - frame buffer 0)); // FIX - not needed SEND_GS_PACKET(gs_dma_buf); return(1); }