Annotation of quakeworld/client/r_sprite.c, revision 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.