#include "WolfDef.h" #include Word *src1,*src2,*dest; /* Used by the sort */ /********************************** Merges src1/size1 and src2/size2 to dest Both Size1 and Size2 MUST be non-zero **********************************/ void Merge(Word Size1, Word Size2) { Word *XDest,*XSrc1,*XSrc2; /* merge two parts of the unsorted array to the sorted array */ XDest = dest; dest = &XDest[Size1+Size2]; XSrc1 = src1; src1 = &XSrc1[Size1]; XSrc2 = src2; src2 = &XSrc2[Size2]; if (XSrc1[0] < XSrc2[0]) { /* Which sort to use? */ mergefrom1: do { XDest[0] = XSrc1[0]; /* Copy one entry */ ++XDest; ++XSrc1; if (!--Size1) { /* Any more? */ do { /* Dump the rest */ XDest[0] = XSrc2[0]; /* Copy the rest of data */ ++XDest; ++XSrc2; } while (--Size2); return; } } while (XSrc1[0] < XSrc2[0]); } do { XDest[0] = XSrc2[0]; ++XDest; ++XSrc2; if (!--Size2) { do { XDest[0] = XSrc1[0]; ++XDest; ++XSrc1; } while (--Size1); return; } } while (XSrc1[0] >= XSrc2[0]); goto mergefrom1; } /********************************** Sorts the events from xevents[0] to xevent_p firstevent will be set to the first sorted event (either xevents[0] or sortbuffer[0]) **********************************/ void SortEvents(void) { Word count; /* Number of members to sort */ Word size; /* Entry size to sort with */ Word sort; /* Sort count */ Word remaining; /* Temp merge count */ Word *sorted,*unsorted,*temp; count = numvisspr; /* How many entries are there? */ if (count<2) { firstevent = xevents; /* Just return the 0 or 1 entries */ return; /* Leave now */ } size = 1; /* source size (<<1 / loop)*/ sort = 1; /* iteration number (+1 / loop)*/ sorted = xevents; unsorted = sortbuffer; do { remaining = count>>sort; /* How many times to try */ /* pointers incremented by the merge */ src1 = sorted; /* Sorted array */ src2 = &sorted[remaining<<(sort-1)]; /* Half point */ dest = unsorted; /* Dest array */ /* merge paired blocks*/ if (remaining) { /* Any to sort? */ do { Merge(size,size); /* All groups equal size */ } while (--remaining); } /* copy or merge the leftovers */ remaining = count&((size<<1)-1); /* Create mask (1 bit higher) */ if (remaining > size) { /* one complete block and one fragment */ src1 = &src2[size]; Merge(remaining-size,size); } else if (remaining) { /* just a single sorted fragment */ memcpy(dest,src2,remaining*sizeof(Word)); /* Copy it */ } /* get ready to sort back to the other array */ size <<= 1; /* Double the entry size */ ++sort; /* Increase the shift size */ temp = sorted; /* Swap the pointers */ sorted = unsorted; unsorted = temp; } while (sizeclipscale; /* Get the size of the sprite */ column = 0; /* Start at the first column */ if ((int) x1 > VisPtr->x1) { /* Clip the left? */ column = (x1-VisPtr->x1)*VisPtr->columnstep; /* Start here instead */ } /* calculate and draw each column */ do { if (xscale[x1] <= scaler) { /* Visible? */ IO_ScaleMaskedColumn(x1,scaler,VisPtr->pos,column>>FRACBITS); } column+=VisPtr->columnstep; /* Next column (Fraction) */ } while (++x1<=x2); } /********************************** Add a sprite entry to the render list **********************************/ void AddSprite (thing_t *thing,Word actornum) { fixed_t tx; /* New X coord */ fixed_t tz; /* New z coord (Size) */ Word scale; /* Scaled size */ int px; /* Center X coord */ unsigned short *patch; /* Pointer to sprite data */ int x1, x2; /* Left,Right x */ Word width; /* Width of sprite */ fixed_t trx,try; /* x,y from the camera */ vissprite_t *VisPtr; /* Local pointer to visible sprite record */ /* transform the origin point */ if (numvisspr>=(MAXVISSPRITES-1)) { return; } trx = thing->x - viewx; /* Adjust from the camera view */ try = viewy - thing->y; /* Adjust from the camera view */ tz = R_TransformZ(trx,try); /* Get the distance */ if (tz < MINZ) { /* Too close? */ return; } if (tz>=MAXZ) { /* Force smallest */ tz = MAXZ-1; } scale = scaleatzptr[tz]; /* Get the scale at the z coord */ tx = R_TransformX(trx,try); /* Get the screen x coord */ px = ((tx*(long)scale)>>7) + CENTERX; /* Use 32 bit precision! */ /* calculate edges of the shape */ patch = SpriteArray[thing->sprite]; /* Pointer to the sprite info */ width =((LongWord)patch[0]*scale)>>6; /* Get the width of the shape */ if (!width) { return; /* too far away*/ } x1 = px - (width>>1); /* Get the left edge */ if (x1 >= (int) SCREENWIDTH) { return; /* off the right side */ } x2 = x1 + width - 1; /* Get the right edge */ if (x2 < 0) { return; /* off the left side*/ } VisPtr = &vissprites[numvisspr]; VisPtr->pos = &patch[0]; /* Sprite info offset */ VisPtr->x1 = x1; /* Min x */ VisPtr->x2 = x2; /* Max x */ VisPtr->clipscale = scale; /* Size to draw */ VisPtr->columnstep = (patch[0]<<8)/width; /* Step for width scale */ VisPtr->actornum = actornum; /* Actor who this is (0 for static) */ /* pack the vissprite number into the low 6 bits of the scale for sorting */ xevents[numvisspr] = (scale<<6) | numvisspr; /* Pass the scale in the upper 10 bits */ ++numvisspr; /* 1 more valid record */ } /********************************** Draw a scaling game over sprite on top of everything **********************************/ void DrawTopSprite(void) { unsigned short *patch; int x1, x2; Word width; vissprite_t VisRecord; if (topspritescale) { /* Is there a top sprite? */ /* calculate edges of the shape */ patch = SpriteArray[topspritenum]; /* Get the info on the shape */ width = (patch[0]*topspritescale)>>7; /* Adjust the width */ if (!width) { return; /* Too far away */ } x1 = CENTERX - (width>>1); /* Use the center to get the left edge */ if (x1 >= SCREENWIDTH) { return; /* off the right side*/ } x2 = x1 + width - 1; /* Get the right edge */ if (x2 < 0) { return; /* off the left side*/ } VisRecord.pos = patch; /* Index to the shape record */ VisRecord.x1 = x1; /* Left edge */ VisRecord.x2 = x2; /* Right edge */ VisRecord.clipscale = topspritescale; /* Size */ VisRecord.columnstep = (patch[0]<<8)/(x2-x1+1); /* Width step */ /* Make sure it is sorted to be drawn last */ memset(xscale,0,sizeof(xscale)); /* don't clip behind anything */ if (x1<0) { x1 = 0; /* Clip the left */ } if (x2>=SCREENWIDTH) { x2 = SCREENWIDTH-1; /* Clip the right */ } RenderSprite(x1,x2,&VisRecord); /* Draw the sprite */ } } /********************************** Draw all the character sprites **********************************/ void DrawSprites(void) { vissprite_t *dseg; /* Pointer to visible sprite record */ int x1,x2; /* Left x, Right x */ Word i; /* Index */ static_t *stat; /* Pointer to static sprite record */ actor_t *actor; /* Pointer to active actor record */ missile_t *MissilePtr; /* Pointer to active missile record */ Word *xe; /* Pointer to sort value */ numvisspr = 0; /* Init the sprite count */ /* add all sprites in visareas*/ if (numstatics) { /* Any statics? */ i = numstatics; stat = statics; /* Init my pointer */ do { if (areavis[stat->areanumber]) { /* Is it in a visible area? */ AddSprite((thing_t *) stat,0); /* Add to my list */ } ++stat; /* Next index */ } while (--i); /* Count down */ } if (numactors>1) { /* Any actors? */ i = 1; /* Index to the first NON-PLAYER actor */ actor = &actors[1]; /* Init pointer */ do { if (areavis[actor->areanumber]) { /* Visible? */ AddSprite ((thing_t *)actor, i); /* Add it */ } ++actor; /* Next actor */ } while (++iareanumber]) { /* Visible? */ AddSprite((thing_t *)MissilePtr,0); /* Show it */ } ++MissilePtr; /* Next missile */ } while (--i); /* Count down */ } i = numvisspr; if (i) { /* Any sprites? */ /* sort sprites from back to front*/ SortEvents(); /* draw from smallest scale to largest */ xe=firstevent; do { dseg = &vissprites[xe[0]&(MAXVISSPRITES-1)]; /* Which one? */ x1 = dseg->x1; if (x1<0) { /* Clip the left? */ x1 = 0; } x2 = dseg->x2; if (x2>= (int)SCREENWIDTH) { /* Clip the right? */ x2 = SCREENWIDTH-1; } RenderSprite(x1,x2,dseg); /* Draw the sprite */ ++xe; } while (--i); } }