Annotation of quakeworld/client/r_sprite.c, revision 1.1.1.1

1.1       root        1: /*
                      2: Copyright (C) 1996-1997 Id Software, Inc.
                      3: 
                      4: This program is free software; you can redistribute it and/or
                      5: modify it under the terms of the GNU General Public License
                      6: as published by the Free Software Foundation; either version 2
                      7: of the License, or (at your option) any later version.
                      8: 
                      9: This program is distributed in the hope that it will be useful,
                     10: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
                     12: 
                     13: See the GNU General Public License for more details.
                     14: 
                     15: You should have received a copy of the GNU General Public License
                     16: along with this program; if not, write to the Free Software
                     17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
                     18: 
                     19: */
                     20: // r_sprite.c
                     21: 
                     22: #include "quakedef.h"
                     23: #include "r_local.h"
                     24: 
                     25: static int                             clip_current;
                     26: static vec5_t                  clip_verts[2][MAXWORKINGVERTS];
                     27: static int                             sprite_width, sprite_height;
                     28: 
                     29: spritedesc_t                   r_spritedesc;
                     30:        
                     31: 
                     32: /*
                     33: ================
                     34: R_RotateSprite
                     35: ================
                     36: */
                     37: void R_RotateSprite (float beamlength)
                     38: {
                     39:        vec3_t  vec;
                     40:        
                     41:        if (beamlength == 0.0)
                     42:                return;
                     43: 
                     44:        VectorScale (r_spritedesc.vpn, -beamlength, vec);
                     45:        VectorAdd (r_entorigin, vec, r_entorigin);
                     46:        VectorSubtract (modelorg, vec, modelorg);
                     47: }
                     48: 
                     49: 
                     50: /*
                     51: =============
                     52: R_ClipSpriteFace
                     53: 
                     54: Clips the winding at clip_verts[clip_current] and changes clip_current
                     55: Throws out the back side
                     56: ==============
                     57: */
                     58: int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
                     59: {
                     60:        int             i, outcount;
                     61:        float   dists[MAXWORKINGVERTS+1];
                     62:        float   frac, clipdist, *pclipnormal;
                     63:        float   *in, *instep, *outstep, *vert2;
                     64: 
                     65:        clipdist = pclipplane->dist;
                     66:        pclipnormal = pclipplane->normal;
                     67:        
                     68: // calc dists
                     69:        if (clip_current)
                     70:        {
                     71:                in = clip_verts[1][0];
                     72:                outstep = clip_verts[0][0];
                     73:                clip_current = 0;
                     74:        }
                     75:        else
                     76:        {
                     77:                in = clip_verts[0][0];
                     78:                outstep = clip_verts[1][0];
                     79:                clip_current = 1;
                     80:        }
                     81:        
                     82:        instep = in;
                     83:        for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
                     84:        {
                     85:                dists[i] = DotProduct (instep, pclipnormal) - clipdist;
                     86:        }
                     87:        
                     88: // handle wraparound case
                     89:        dists[nump] = dists[0];
                     90:        Q_memcpy (instep, in, sizeof (vec5_t));
                     91: 
                     92: 
                     93: // clip the winding
                     94:        instep = in;
                     95:        outcount = 0;
                     96: 
                     97:        for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
                     98:        {
                     99:                if (dists[i] >= 0)
                    100:                {
                    101:                        Q_memcpy (outstep, instep, sizeof (vec5_t));
                    102:                        outstep += sizeof (vec5_t) / sizeof (float);
                    103:                        outcount++;
                    104:                }
                    105: 
                    106:                if (dists[i] == 0 || dists[i+1] == 0)
                    107:                        continue;
                    108: 
                    109:                if ( (dists[i] > 0) == (dists[i+1] > 0) )
                    110:                        continue;
                    111:                        
                    112:        // split it into a new vertex
                    113:                frac = dists[i] / (dists[i] - dists[i+1]);
                    114:                        
                    115:                vert2 = instep + sizeof (vec5_t) / sizeof (float);
                    116:                
                    117:                outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
                    118:                outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
                    119:                outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
                    120:                outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
                    121:                outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
                    122: 
                    123:                outstep += sizeof (vec5_t) / sizeof (float);
                    124:                outcount++;
                    125:        }       
                    126:        
                    127:        return outcount;
                    128: }
                    129: 
                    130: 
                    131: /*
                    132: ================
                    133: R_SetupAndDrawSprite
                    134: ================
                    135: */
                    136: void R_SetupAndDrawSprite ()
                    137: {
                    138:        int                     i, nump;
                    139:        float           dot, scale, *pv;
                    140:        vec5_t          *pverts;
                    141:        vec3_t          left, up, right, down, transformed, local;
                    142:        emitpoint_t     outverts[MAXWORKINGVERTS+1], *pout;
                    143: 
                    144:        dot = DotProduct (r_spritedesc.vpn, modelorg);
                    145: 
                    146: // backface cull
                    147:        if (dot >= 0)
                    148:                return;
                    149: 
                    150: // build the sprite poster in worldspace
                    151:        VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
                    152:        VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
                    153:        VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
                    154:        VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
                    155: 
                    156:        pverts = clip_verts[0];
                    157: 
                    158:        pverts[0][0] = r_entorigin[0] + up[0] + left[0];
                    159:        pverts[0][1] = r_entorigin[1] + up[1] + left[1];
                    160:        pverts[0][2] = r_entorigin[2] + up[2] + left[2];
                    161:        pverts[0][3] = 0;
                    162:        pverts[0][4] = 0;
                    163: 
                    164:        pverts[1][0] = r_entorigin[0] + up[0] + right[0];
                    165:        pverts[1][1] = r_entorigin[1] + up[1] + right[1];
                    166:        pverts[1][2] = r_entorigin[2] + up[2] + right[2];
                    167:        pverts[1][3] = sprite_width;
                    168:        pverts[1][4] = 0;
                    169: 
                    170:        pverts[2][0] = r_entorigin[0] + down[0] + right[0];
                    171:        pverts[2][1] = r_entorigin[1] + down[1] + right[1];
                    172:        pverts[2][2] = r_entorigin[2] + down[2] + right[2];
                    173:        pverts[2][3] = sprite_width;
                    174:        pverts[2][4] = sprite_height;
                    175: 
                    176:        pverts[3][0] = r_entorigin[0] + down[0] + left[0];
                    177:        pverts[3][1] = r_entorigin[1] + down[1] + left[1];
                    178:        pverts[3][2] = r_entorigin[2] + down[2] + left[2];
                    179:        pverts[3][3] = 0;
                    180:        pverts[3][4] = sprite_height;
                    181: 
                    182: // clip to the frustum in worldspace
                    183:        nump = 4;
                    184:        clip_current = 0;
                    185: 
                    186:        for (i=0 ; i<4 ; i++)
                    187:        {
                    188:                nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
                    189:                if (nump < 3)
                    190:                        return;
                    191:                if (nump >= MAXWORKINGVERTS)
                    192:                        Sys_Error("R_SetupAndDrawSprite: too many points");
                    193:        }
                    194: 
                    195: // transform vertices into viewspace and project
                    196:        pv = &clip_verts[clip_current][0][0];
                    197:        r_spritedesc.nearzi = -999999;
                    198: 
                    199:        for (i=0 ; i<nump ; i++)
                    200:        {
                    201:                VectorSubtract (pv, r_origin, local);
                    202:                TransformVector (local, transformed);
                    203: 
                    204:                if (transformed[2] < NEAR_CLIP)
                    205:                        transformed[2] = NEAR_CLIP;
                    206: 
                    207:                pout = &outverts[i];
                    208:                pout->zi = 1.0 / transformed[2];
                    209:                if (pout->zi > r_spritedesc.nearzi)
                    210:                        r_spritedesc.nearzi = pout->zi;
                    211: 
                    212:                pout->s = pv[3];
                    213:                pout->t = pv[4];
                    214:                
                    215:                scale = xscale * pout->zi;
                    216:                pout->u = (xcenter + scale * transformed[0]);
                    217: 
                    218:                scale = yscale * pout->zi;
                    219:                pout->v = (ycenter - scale * transformed[1]);
                    220: 
                    221:                pv += sizeof (vec5_t) / sizeof (pv);
                    222:        }
                    223: 
                    224: // draw it
                    225:        r_spritedesc.nump = nump;
                    226:        r_spritedesc.pverts = outverts;
                    227:        D_DrawSprite ();
                    228: }
                    229: 
                    230: 
                    231: /*
                    232: ================
                    233: R_GetSpriteframe
                    234: ================
                    235: */
                    236: mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
                    237: {
                    238:        mspritegroup_t  *pspritegroup;
                    239:        mspriteframe_t  *pspriteframe;
                    240:        int                             i, numframes, frame;
                    241:        float                   *pintervals, fullinterval, targettime, time;
                    242: 
                    243:        frame = currententity->frame;
                    244: 
                    245:        if ((frame >= psprite->numframes) || (frame < 0))
                    246:        {
                    247:                Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
                    248:                frame = 0;
                    249:        }
                    250: 
                    251:        if (psprite->frames[frame].type == SPR_SINGLE)
                    252:        {
                    253:                pspriteframe = psprite->frames[frame].frameptr;
                    254:        }
                    255:        else
                    256:        {
                    257:                pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
                    258:                pintervals = pspritegroup->intervals;
                    259:                numframes = pspritegroup->numframes;
                    260:                fullinterval = pintervals[numframes-1];
                    261: 
                    262:                time = cl.time + currententity->syncbase;
                    263: 
                    264:        // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
                    265:        // are positive, so we don't have to worry about division by 0
                    266:                targettime = time - ((int)(time / fullinterval)) * fullinterval;
                    267: 
                    268:                for (i=0 ; i<(numframes-1) ; i++)
                    269:                {
                    270:                        if (pintervals[i] > targettime)
                    271:                                break;
                    272:                }
                    273: 
                    274:                pspriteframe = pspritegroup->frames[i];
                    275:        }
                    276: 
                    277:        return pspriteframe;
                    278: }
                    279: 
                    280: 
                    281: /*
                    282: ================
                    283: R_DrawSprite
                    284: ================
                    285: */
                    286: void R_DrawSprite (void)
                    287: {
                    288:        int                             i;
                    289:        msprite_t               *psprite;
                    290:        vec3_t                  tvec;
                    291:        float                   dot, angle, sr, cr;
                    292: 
                    293:        psprite = currententity->model->cache.data;
                    294: 
                    295:        r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
                    296: 
                    297:        sprite_width = r_spritedesc.pspriteframe->width;
                    298:        sprite_height = r_spritedesc.pspriteframe->height;
                    299: 
                    300: // TODO: make this caller-selectable
                    301:        if (psprite->type == SPR_FACING_UPRIGHT)
                    302:        {
                    303:        // generate the sprite's axes, with vup straight up in worldspace, and
                    304:        // r_spritedesc.vright perpendicular to modelorg.
                    305:        // This will not work if the view direction is very close to straight up or
                    306:        // down, because the cross product will be between two nearly parallel
                    307:        // vectors and starts to approach an undefined state, so we don't draw if
                    308:        // the two vectors are less than 1 degree apart
                    309:                tvec[0] = -modelorg[0];
                    310:                tvec[1] = -modelorg[1];
                    311:                tvec[2] = -modelorg[2];
                    312:                VectorNormalize (tvec);
                    313:                dot = tvec[2];  // same as DotProduct (tvec, r_spritedesc.vup) because
                    314:                                                //  r_spritedesc.vup is 0, 0, 1
                    315:                if ((dot > 0.999848) || (dot < -0.999848))      // cos(1 degree) = 0.999848
                    316:                        return;
                    317:                r_spritedesc.vup[0] = 0;
                    318:                r_spritedesc.vup[1] = 0;
                    319:                r_spritedesc.vup[2] = 1;
                    320:                r_spritedesc.vright[0] = tvec[1];
                    321:                                                                // CrossProduct(r_spritedesc.vup, -modelorg,
                    322:                r_spritedesc.vright[1] = -tvec[0];
                    323:                                                                //              r_spritedesc.vright)
                    324:                r_spritedesc.vright[2] = 0;
                    325:                VectorNormalize (r_spritedesc.vright);
                    326:                r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
                    327:                r_spritedesc.vpn[1] = r_spritedesc.vright[0];
                    328:                r_spritedesc.vpn[2] = 0;
                    329:                                        // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
                    330:                                        //  r_spritedesc.vpn)
                    331:        }
                    332:        else if (psprite->type == SPR_VP_PARALLEL)
                    333:        {
                    334:        // generate the sprite's axes, completely parallel to the viewplane. There
                    335:        // are no problem situations, because the sprite is always in the same
                    336:        // position relative to the viewer
                    337:                for (i=0 ; i<3 ; i++)
                    338:                {
                    339:                        r_spritedesc.vup[i] = vup[i];
                    340:                        r_spritedesc.vright[i] = vright[i];
                    341:                        r_spritedesc.vpn[i] = vpn[i];
                    342:                }
                    343:        }
                    344:        else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
                    345:        {
                    346:        // generate the sprite's axes, with vup straight up in worldspace, and
                    347:        // r_spritedesc.vright parallel to the viewplane.
                    348:        // This will not work if the view direction is very close to straight up or
                    349:        // down, because the cross product will be between two nearly parallel
                    350:        // vectors and starts to approach an undefined state, so we don't draw if
                    351:        // the two vectors are less than 1 degree apart
                    352:                dot = vpn[2];   // same as DotProduct (vpn, r_spritedesc.vup) because
                    353:                                                //  r_spritedesc.vup is 0, 0, 1
                    354:                if ((dot > 0.999848) || (dot < -0.999848))      // cos(1 degree) = 0.999848
                    355:                        return;
                    356:                r_spritedesc.vup[0] = 0;
                    357:                r_spritedesc.vup[1] = 0;
                    358:                r_spritedesc.vup[2] = 1;
                    359:                r_spritedesc.vright[0] = vpn[1];
                    360:                                                                                // CrossProduct (r_spritedesc.vup, vpn,
                    361:                r_spritedesc.vright[1] = -vpn[0];       //  r_spritedesc.vright)
                    362:                r_spritedesc.vright[2] = 0;
                    363:                VectorNormalize (r_spritedesc.vright);
                    364:                r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
                    365:                r_spritedesc.vpn[1] = r_spritedesc.vright[0];
                    366:                r_spritedesc.vpn[2] = 0;
                    367:                                        // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
                    368:                                        //  r_spritedesc.vpn)
                    369:        }
                    370:        else if (psprite->type == SPR_ORIENTED)
                    371:        {
                    372:        // generate the sprite's axes, according to the sprite's world orientation
                    373:                AngleVectors (currententity->angles, r_spritedesc.vpn,
                    374:                                          r_spritedesc.vright, r_spritedesc.vup);
                    375:        }
                    376:        else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
                    377:        {
                    378:        // generate the sprite's axes, parallel to the viewplane, but rotated in
                    379:        // that plane around the center according to the sprite entity's roll
                    380:        // angle. So vpn stays the same, but vright and vup rotate
                    381:                angle = currententity->angles[ROLL] * (M_PI*2 / 360);
                    382:                sr = sin(angle);
                    383:                cr = cos(angle);
                    384: 
                    385:                for (i=0 ; i<3 ; i++)
                    386:                {
                    387:                        r_spritedesc.vpn[i] = vpn[i];
                    388:                        r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
                    389:                        r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
                    390:                }
                    391:        }
                    392:        else
                    393:        {
                    394:                Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
                    395:        }
                    396: 
                    397:        R_RotateSprite (psprite->beamlength);
                    398: 
                    399:        R_SetupAndDrawSprite ();
                    400: }
                    401: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.