/* * Copyright 1995, Silicon Graphics, Inc. * ALL RIGHTS RESERVED * UNPUBLISHED -- Rights reserved under the copyright laws of the United * States. Use of a copyright notice is precautionary only and does not * imply publication or disclosure. * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND: * Use, duplication or disclosure by the Government is subject to restrictions * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or * in similar or successor clauses in the FAR, or the DOD or NASA FAR * Supplement. Contractor/manufacturer is Silicon Graphics, Inc., * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311. * * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION, * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON * GRAPHICS, INC. */ #include #include #include // TODO: this comes from a header #ident "$Revision: 1.17 $" /* * spSetZ() * */ void spSetZ (Sprite *sp, s32 z) { #ifdef DEBUG emPrintf("spSetZ (Sprite 0x%08x, (%d))\n", sp, z ); #endif sp->zdepth = (s16)z; } /* * spMove() * * Moves a sprite on the screen. */ void spMove (Sprite *sp, s32 x, s32 y) { #ifdef DEBUG emPrintf("spMove (Sprite 0x%08x, (%d,%d))\n", sp, x, y ); #endif sp->x = (s16)x; sp->y = (s16)y; } static s32 scissor_xmax; static s32 scissor_ymax; static s32 scissor_xmin; static s32 scissor_ymin; /* * spScissor() * * Sets the scissoring box to be used for subsequent Sprite Drawing */ void spScissor (s32 xmin, s32 xmax, s32 ymin, s32 ymax ) { scissor_xmin = xmin; scissor_ymin = ymin; scissor_xmax = xmax; scissor_ymax = ymax; } static int *prev_bmbuf = NULL; /* * drawbitmap() * * Draws a bitmap from a sprite at a location on the screen. If the * "usevert" flag is set, then the routine will use vertices and triangles * to draw the bitmap. Otherwise, the texture rectangle instruction * will be used. */ static void drawbitmap (Gfx **glp, Sprite *s, Bitmap *b, s32 x, s32 y, s32 xx, s32 yy, s32 fs, s32 ft, s32 sx, s32 sy) { s32 rs, rt; s32 rxh, ryh; s32 rxl, ryl; Gfx *gl; s32 tex_width, tex_height; Gtexrect gt, *g; s32 s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod; g = > tex_width = b->width_img; tex_height= s->bmHreal; #ifdef rmDEBUG rmonPrintf("\tdrawbitmap (buf= 0x%08x; x,y= %d,%d; w,h= %d,%d )\n", b->buf, x, y, b->width, s->bmheight ); #endif gl = *glp; /* Scissoring */ if( (x >= scissor_xmax) || (y >= scissor_ymax) ) { #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: Upper Left corner (%d,%d) beyond range (%d,%d)\n", x, y, scissor_xmax, scissor_ymax ); #endif return; } if( (xx < scissor_xmin) || (yy < scissor_ymin) ) { #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: Lower Right corner (%d,%d) not in range (%d,%d)\n", xx, yy, scissor_xmin, scissor_ymin ); #endif return; } if (x < scissor_xmin) { rxh = scissor_xmin*4; rs = (b->s<<5) + fs + (((scissor_xmin - x)*sx)>>5); #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: Left Edge (%d) not in range (%d,%d)\n", x, scissor_xmin, scissor_xmax ); #endif } else { rxh = x*4; rs = (b->s<<5) + fs; }; if (y < scissor_ymin) { ryh = scissor_ymin*4; rt = (b->t<<5) + ft + (((scissor_ymin-y)*sy)>>5); #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: Top Edge (%d) not in range (%d,%d)\n", y, scissor_ymin, scissor_ymax ); #endif } else { ryh = y*4; rt = (b->t<<5) + ft; } if( xx >= scissor_xmax ) { rxl = scissor_xmax*4; #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: Right Edge (%d) not in range (%d,%d)\n", xx, scissor_xmin, scissor_xmax ); #endif } else { rxl = xx*4; }; if( yy >= scissor_ymax ) { ryl = scissor_ymax*4; #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: Bottom Edge (%d) not in range (%d,%d)\n", yy, scissor_ymin, scissor_ymax ); #endif } else { ryl = yy*4; }; s_clamp = G_TX_CLAMP; t_clamp = G_TX_CLAMP; s_mask = G_TX_NOMASK; t_mask = G_TX_NOMASK; s_lod = G_TX_NOLOD; t_lod = G_TX_NOLOD; #define LOAD_TEX #ifdef LOAD_TEX if( b->buf != prev_bmbuf ) { switch(s->bmsiz) { #if BUILD_VERSION >= VERSION_J case G_IM_SIZ_DD: gDPLoadTextureTile_4b(gl++, b->buf, s->bmfmt, tex_width, tex_height, b->s, b->t, b->s + b->width,b->t + b->actualHeight, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); break; #endif case G_IM_SIZ_4b: if (s->attr & SP_TEXSHUF) { gDPLoadTextureBlock_4bS(gl++, b->buf, s->bmfmt, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); } else { gDPLoadTextureBlock_4b(gl++, b->buf, s->bmfmt, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); }; break; case G_IM_SIZ_8b: if (s->attr & SP_TEXSHUF) { gDPLoadTextureBlockS(gl++, b->buf, s->bmfmt, G_IM_SIZ_8b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); } else { gDPLoadTextureBlock(gl++, b->buf, s->bmfmt, G_IM_SIZ_8b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); }; break; case G_IM_SIZ_16b: if (s->bmfmt == G_IM_FMT_YUV ) { if (s->attr & SP_TEXSHUF) { gDPLoadTextureBlockYuvS(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); } else { if( b->LUToffset != 0 ) { /* Split Y and UV areas */ unsigned char *uv, *addr; int j; s32 tmem, siz; gDPSetTextureImage( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 1, b->buf); gDPSetTile( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 0, 256, G_TX_LOADTILE, 0, t_clamp, t_mask, t_lod, s_clamp, s_mask, s_lod ); gDPLoadSync( gl++ ); gDPLoadBlock( gl++, G_TX_LOADTILE, 0,0, tex_width*tex_height -1, CALC_DXT(tex_width,1) ); gDPLoadSync( gl++ ); uv = ((unsigned char *)b->buf) + ((tex_width*tex_height)/2)*b->LUToffset; for( j=0; j<=(tex_height/2); j++ ) { addr = uv + ((tex_height/2) -2 -j)*tex_width; siz = 3*tex_width; tmem = (tex_width/8)*(tex_height - 2 - 2*j); if( tmem < 0 ) { addr += (-tmem)*8; siz -= (-tmem)*8; tmem = 0; }; if( j == 0 ) siz = 2*tex_width; gDPSetTextureImage( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 1, addr); gDPSetTile( gl++, G_IM_FMT_I, G_IM_SIZ_8b, 0, tmem, G_TX_LOADTILE, 0, t_clamp, t_mask, t_lod, s_clamp, s_mask, s_lod ); gDPLoadSync( gl++ ); gDPLoadBlock( gl++, G_TX_LOADTILE, 0,0, siz -1, CALC_DXT(tex_width,1) ); gDPLoadSync( gl++ ); }; gDPSetTile( gl++, s->bmfmt, G_IM_SIZ_16b, (((tex_width) * 1)+7)>>3, 0, G_TX_RENDERTILE, 0, t_clamp, t_mask, t_lod, s_clamp, s_mask, s_lod ); gDPSetTileSize( gl++, G_TX_RENDERTILE, 0, 0, ((tex_width)-1) << G_TEXTURE_IMAGE_FRAC, ((tex_height)-1) << G_TEXTURE_IMAGE_FRAC ); } else { gDPLoadTextureBlockYuv(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); }; }; } else { if (s->attr & SP_TEXSHUF) { gDPLoadTextureBlockS(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); } else { gDPLoadTextureBlock(gl++, b->buf, s->bmfmt, G_IM_SIZ_16b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); }; }; break; case G_IM_SIZ_32b: if (s->attr & SP_TEXSHUF) { gDPLoadTextureBlockS(gl++, b->buf, s->bmfmt, G_IM_SIZ_32b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); } else { gDPLoadTextureBlock(gl++, b->buf, s->bmfmt, G_IM_SIZ_32b, tex_width, tex_height, 0, s_clamp, t_clamp, s_mask, t_mask, s_lod, t_lod); }; break; } prev_bmbuf = b->buf; } #endif /* LOAD_TEX */ g->cmd = G_TEXRECT; g->tile = 0; g->xh = rxh; g->xl = rxl; g->yh = ryh; g->yl = ryl; g->s = rs; g->t = rt; if ((s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) ) g->dsdx = sx * 4; else g->dsdx = sx; g->dtdy = sy; #ifdef rmDEBUG rmonPrintf("\trect (xh,l= %d,%d, yh,l= %d,%d, s,t= %d,%d, dsdx=%d, dtdy=%d )\n", rxh,rxl,ryh,ryl,rs,rt,g->dsdx,sy ); #endif gSPTextureRectangle(gl++,g->xh,g->yh,g->xl,g->yl,g->tile,g->s,g->t,g->dsdx,g->dtdy); gDPPipeSync(gl++); *glp = gl; } static u16 sp_attr = 0; void spInit( Gfx **glistp ) { Gfx *gl; gl = *glistp; #ifdef DEBUG emPrintf("spInit ()\n" ); #endif sp_attr = 0; scissor_xmin = 0; scissor_ymin = 0; scissor_xmax = 320; scissor_ymax = 240; /* Turn on texturing */ gDPPipeSync ( gl++ ); gDPSetCycleType ( gl++, G_CYC_1CYCLE); gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON); gDPSetAlphaCompare ( gl++, G_AC_NONE ); gDPSetTexturePersp ( gl++, G_TP_NONE ); gDPSetTextureFilter ( gl++, G_TF_BILERP ); gDPSetTextureConvert( gl++, G_TC_FILT ); gDPSetTextureDetail ( gl++, G_TD_CLAMP ); gDPSetTextureLOD ( gl++, G_TL_TILE ); gDPSetTextureLUT ( gl++, G_TT_NONE ); #define SPRITE_SURF G_RM_TEX_EDGE #define SPRITE_SURF2 G_RM_TEX_EDGE2 gDPSetRenderMode( gl++, SPRITE_SURF, SPRITE_SURF2); *glistp = gl; } /* * spDraw() * * Draws all of the sprites that are associated with bitmaps and that * are supposed to be drawn (spDraw()). They are drawn from 0 to maxsp, * so sprites with higher numbers will overwrite lower-numbered sprites. * */ Gfx * spDraw ( Sprite *s ) { int i; s32 x, y; float sx, sy; Bitmap *b; Gfx *gl; #ifndef NDEBUG Gfx *ogl; #endif Gfx *dl_start; s32 isx, isy; s32 tx, ty; s32 tx2, ty2; s32 x2, y2; float ftx, fty; s32 fs, ft; s32 ex, ey; #ifdef rmDEBUG rmonPrintf("spDraw (Sprite 0x%08x )\n", s ); #endif if (s->attr & SP_HIDDEN) return(NULL); prev_bmbuf = NULL; gl = s->rsp_dl_next; if( gl == NULL ) gl = s->rsp_dl; dl_start = gl; #ifndef NDEBUG ogl = gl; #endif b = s->bitmap; ex = 0; ey = 0; if (sp_attr & SP_EXTERN) /* previous attr was extern? */ sp_attr = ~s->attr; /* Assume previous modes are all different from new ones */ if (s->attr & SP_EXTERN) /* current attr is extern? */ sp_attr = s->attr; /* Assume all settings should remain the same */ if (s->attr != sp_attr) { if ((s->attr & SP_TRANSPARENT) && !(sp_attr & SP_TRANSPARENT)) { gDPSetRenderMode( gl++, G_RM_XLU_SURF, G_RM_XLU_SURF2); } else if (!(s->attr & SP_TRANSPARENT) && (sp_attr & SP_TRANSPARENT)) { gDPSetRenderMode( gl++, SPRITE_SURF, SPRITE_SURF2); } if ((s->attr & SP_CUTOUT) && !(sp_attr & SP_CUTOUT)) { gDPSetBlendColor ( gl++, 0xff, 0xff, 0xff, 0x01); gDPSetAlphaCompare ( gl++, G_AC_THRESHOLD) ; } else if (!(s->attr & SP_CUTOUT) && (sp_attr & SP_CUTOUT)) { gDPSetAlphaCompare ( gl++, G_AC_NONE) ; } if( (s->attr & SP_TEXSHIFT) && !(sp_attr & SP_TEXSHIFT) ) { gDPSetTextureFilter( gl++, G_TF_AVERAGE ); } else if( !(s->attr & SP_TEXSHIFT) && (sp_attr & SP_TEXSHIFT) ) { gDPSetTextureFilter( gl++, G_TF_BILERP ); }; }; sp_attr = s->attr; if( sp_attr & SP_Z ) { gDPSetPrimDepth(gl++, s->zdepth, 0); }; gDPSetPrimColor( gl++, 0, 0, s->red, s->green, s->blue, s->alpha); if (s->bmfmt == G_IM_FMT_IA || s->bmfmt == G_IM_FMT_I) { if( s->alpha == 255 ) { gDPSetCombineMode ( gl++, G_CC_MODULATEIDECALA_PRIM, G_CC_MODULATEIDECALA_PRIM); } else { gDPSetCombineMode ( gl++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); }; } else { if( s->alpha == 255 ) { gDPSetCombineMode ( gl++, G_CC_MODULATEIDECALA_PRIM, G_CC_MODULATEIDECALA_PRIM); } else { gDPSetCombineMode ( gl++, G_CC_MODULATERGBA_PRIM, G_CC_MODULATERGBA_PRIM); }; } if( s->bmfmt == G_IM_FMT_CI ) { gDPSetTextureLUT( gl++, G_TT_RGBA16); gDPLoadTLUT( gl++, s->nTLUT, 256+s->startTLUT, s->LUT ); gDPLoadSync( gl++ ); }; #define MY_K0 (175 & 0x1ff) #define MY_K1 (-43 & 0x1ff) #define MY_K2 (-89 & 0x1ff) #define MY_K3 (222 & 0x1ff) #define MY_K4 (114 & 0x1ff) #define MY_K5 (42 & 0x1ff) if( (s->bmfmt == G_IM_FMT_YUV) && (s->attr & SP_FASTCOPY) ) { gDPSetTextureConvert( gl++, G_TC_CONV); gDPSetTextureFilter( gl++, G_TF_POINT); gDPSetCombineMode( gl++, G_CC_1CYUV2RGB, G_CC_1CYUV2RGB); gDPSetConvert( gl++, MY_K0, MY_K1, MY_K2, MY_K3, MY_K4, MY_K5); } else if(s->bmfmt == G_IM_FMT_YUV) { gDPSetCycleType( gl++, G_CYC_2CYCLE ); gDPSetTextureFilter( gl++, G_TF_BILERP); gDPSetTextureConvert( gl++, G_TC_FILTCONV); gDPSetConvert( gl++, MY_K0, MY_K1, MY_K2, MY_K3, MY_K4, MY_K5); gDPSetCombineMode( gl++, G_CC_YUV2RGB, G_CC_PASS2); } if (s->attr & SP_SCALE) { sx = s->scalex; sy = s->scaley; } else { sx = 1.0F; sy = 1.0F; } isx = (int) ((1<<10) / sx + 0.5F); isy = (int) ((1<<10) / sy + 0.5F); if( b ) { if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) ) gDPSetCycleType( gl++, G_CYC_COPY); x = 0.0F; y = 0.0F; fty = s->y+y*sy; ty = (int) ( fty + 0.99999F); ft = (int) (isy * (ty - fty)); ft = (ft + 16)>>5; if( s->attr & SP_TEXSHIFT ) ft += 16; /* 1/2 Texel for AntiAliasing */ if( s->attr & SP_FRACPOS ) ft += s->frac_t; /* Micro-positioning */ y2 = y + s->bmheight; ty2 = (int) (s->y+y2*sy + 0.99999F); if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) ) ty2--; #ifdef rmDEBUG rmonPrintf("\tiscale=(%d,%d), %d bitmaps, sprite_size=(%d,%d)\n", isx, isy, s->nbitmaps, s->width, s->height ); #endif for( i=0; (i < s->nbitmaps) && (b->width > 0); i++, b++ ) { if( (x+b->width) > s->width ) { /* Next bitmap hits edge? */ int bh; x = 0; fs = 0; ex = 0; ey += s->expy; y += s->bmheight; /* Wrap to next line */ y2 = y + s->bmheight; /* Wrap to next line */ fty = s->y+y*sy; ty = (int) ( fty + 0.9999F); ft = (int) (isy * (ty - fty)); ft = (ft + 16)>>5; if( s->attr & SP_TEXSHIFT ) ft += 16; /* 1/2 Texel for AntiAliasing */ if( s->attr & SP_FRACPOS ) ft += s->frac_t; /* Micro-positioning */ ty2 = (int) (s->y+y2*sy + 0.9999F); ty += ey; ty2 += ey; if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) ) ty2--; /* Fill out to rect. bdy? */ if( (b->actualHeight != 0) ) bh = b->actualHeight; else bh = s->bmheight; if( (y + bh) > s->height ) /* Can't wrap any more? */ break; }; #ifdef rmDEBUG rmonPrintf("bm# %d, x,y=(%d,%d) width=%d \n", i, x, y, b->width ); #endif ftx = s->x+x*sx; tx = (s32) (ftx + 0.9999F); fs = (s32) (isx * (tx - ftx)); fs = (fs + 16)>>5; if( s->attr & SP_TEXSHIFT ) fs += 16; /* 1/2 Texel for AntiAliasing */ if( s->attr & SP_FRACPOS ) fs += s->frac_s; /* Micro-positioning */ x2 = x + b->width; tx2 = (int) (s->x+x2*sx + 0.9999F); if( (b->actualHeight != 0) ) { y2 = y + b->actualHeight; ty2 = (s32) (s->y+y2*sy + 0.9999F); ty2 += ey; if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) ) ty2--; }; #ifdef rmDEBUG rmonPrintf("\tfull(%g,%g) = int(%d,%d) + frac(%d,%d)\n", ftx, fty, tx,ty, fs,ft ); #endif tx += ex; tx2 += ex; if( (s->attr & SP_FASTCOPY) && (s->bmfmt != G_IM_FMT_YUV) ) tx2--; if( b->buf != NULL ) /* Skip over null bitmaps (blanks) */ drawbitmap ( &gl, s, b, tx, ty, tx2, ty2, fs, ft, isx, isy); x += b->width; ex += s->expx; } if (s->attr & SP_FASTCOPY) gDPSetCycleType( gl++, G_CYC_1CYCLE); if(s->bmfmt == G_IM_FMT_YUV) { gDPSetCycleType( gl++, G_CYC_1CYCLE); gDPSetTextureFilter ( gl++, G_TF_BILERP ); gDPSetTextureConvert( gl++, G_TC_FILT ); }; } else { int rgba; x = (s32)s->x; y = (s32)s->y; x2 = s->x + (s->width*sx)-1; y2 = s->y + (s->height*sy)-1; if( ( x >= scissor_xmax) || (y >= scissor_ymax) ) { #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: FILL Upper Left corner (%d,%d) beyond range (%d,%d)\n", x, y, scissor_xmax, scissor_ymax ); #endif } else if( ( x2 < scissor_xmin) || (y2 < scissor_ymin) ) { #ifdef DEBUG_SCISSOR emPrintf("Sprite Scissoring: FILL Lower Right corner (%d,%d) below range (%d,%d)\n", x2, y2, scissor_xmin, scissor_ymin ); #endif } else { if( x < scissor_xmin ) x = scissor_xmin; if( x2 >= scissor_xmax ) x2 = scissor_xmax - 1; if( y < scissor_ymin ) y = scissor_ymin; if( y2 >= scissor_ymax ) y2 = scissor_ymax - 1; rgba = GPACK_RGBA5551((s->red), (s->green), (s->blue), (s->alpha>>7)); gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF); gDPSetCycleType( gl++, G_CYC_FILL); gDPSetFillColor( gl++, (rgba << 16) | (rgba) ); gDPFillRectangle( gl++, x,y, x2,y2 ); gDPSetCycleType( gl++, G_CYC_1CYCLE); gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_ON); } } if( s->bmfmt == G_IM_FMT_CI ) { gDPSetTextureLUT( gl++, G_TT_NONE); }; gSPEndDisplayList ( gl++ ); #if BUILD_VERSION >= VERSION_J #line 722 #else #line 714 #endif assert((gl - ogl) < s->ndisplist); s->rsp_dl_next = gl; return( dl_start ); } void spFinish( Gfx **glistp ) { Gfx *gl; gl = *glistp; /* Turn off texturing */ gSPTexture ( gl++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF); gDPSetCombineMode ( gl++, G_CC_SHADE, G_CC_SHADE); if (sp_attr & SP_TRANSPARENT) { /* Turn off transparency */ gDPSetRenderMode( gl++, G_RM_OPA_SURF, G_RM_OPA_SURF2); } if (sp_attr & SP_CUTOUT) { /* Turn off Alpha write enable */ gDPSetAlphaCompare ( gl++, G_AC_NONE) ; } gSPEndDisplayList ( gl++ ); *glistp = gl; }