render.c

Go to the documentation of this file.
00001 
00025 #include "render.h"
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <assert.h>
00029 
00030 // An early test of the restrict keyword that doesn't compile on MSVC v7.1.
00031 // Tried to make it conditional based on the version, but the preprocessor
00032 // acted like (1300 > 1300) should evaluate to true.
00033 #if !defined(_MSC_VER) && !defined(DOXYGEN)
00034 #define _restrict_  __restrict
00035 #else
00036 #define _restrict_  
00037 #endif
00038 
00039 // externally accesible global data
00040 struct DisplayInfo_t  dInfo;
00041 Layer layers[MAX_LAYERS];
00042 
00050 static struct UpdateList_t {
00067     SDL_Rect *rects[BACK_STATES];
00074     Uint32    area[BACK_STATES];
00080     Uint16    numRects[BACK_STATES];
00084     Uint16    length;
00092     Sint8 dirty;
00097     Uint8     currState;
00102     Uint8     nextState;
00107     Uint8     totalStates;
00114     Bool renderAll;
00115 } updateList;
00116 
00117 Bool RenderInit(Uint16 numRects, Uint8 numStates) {
00118     // debug check for bad input
00119     assert((numRects > 0) && (numStates > 0) && (numStates <= BACK_STATES));
00120     // runtime check for bad input
00121     if ((numRects == 0) || (numStates == 0) || (numStates > BACK_STATES)) {
00122         // the renderer cannot initalize to the requested setup without causing
00123         // a segfault
00124         return FALSE;
00125     }
00126     // clear out the update list
00127     memset(&updateList, 0, sizeof(updateList));
00128     // clear out the contents of all the layers
00129     memset(layers, 0 , sizeof(layers));
00130     // store the number of states
00131     updateList.dirty = updateList.totalStates = numStates;
00132     updateList.nextState = 1;
00133     // force everything to be drawn for the next frame; skip all that logic
00134     // to draw just what changed for the first frame.
00135     updateList.renderAll = TRUE;
00136     // allocate space for the update lists
00137     do {
00138         // adjust state counter
00139         numStates--;
00140         // allocate memory
00141         if ((updateList.rects[numStates] = malloc(sizeof(SDL_Rect) * numRects))
00142         == NULL) {
00143             // allocation failed
00144             return FALSE;
00145         }
00146     } while (numStates > 0);
00147     // success!
00148     return TRUE;
00149 }
00150 
00151 void RenderClearStates(Uint8 numStates) {
00152     assert(FALSE);
00153 }
00154 
00155 void RenderUninit() {
00156     // loop through all the supported states
00157     do {
00158         // adjust the value to be the next/valid index
00159         updateList.totalStates--;
00160         // deallocate the rectangle list for this state
00161         free(updateList.rects[updateList.totalStates]);
00162         // no rects in it now
00163         updateList.numRects[updateList.totalStates] = 0;
00164     } while (updateList.totalStates > 0);
00165     // no rects in any list
00166     updateList.length = 0;
00167 }
00168 
00169 void ForceRenderAll() {
00170     updateList.renderAll = TRUE;
00171     updateList.dirty = updateList.totalStates;
00172 }
00173 
00174 Bool RenderWillRenderAll() {
00175     return updateList.renderAll;
00176 }
00177 
00178 void ForceDirtyFrame() {
00179     updateList.dirty = updateList.totalStates;
00180 }
00181 
00182 void AddRenderItem(RenderItem *item, int layer) {
00183     assert((layer >= 0) && (layer < MAX_LAYERS));
00184     assert(item->parent == NULL);
00185     assert(item->renderer != NULL);
00186     // check for an empty world list
00187     if (layers[layer].worldListLast == NULL) {
00188         // the wold list is empty, so add the new item as the first
00189         layers[layer].worldListLast = layers[layer].worldListFirst = item;
00190         // fix up the item's list pointers
00191         item->next = item->prev = NULL;
00192     }
00193     else {
00194         // set the mext & last list pointers of the new item
00195         item->next = NULL;
00196         item->prev = layers[layer].worldListLast;
00197         // fix the previous last item's next pointer
00198         layers[layer].worldListLast->next = item;
00199         // add the item to the end of the list
00200         layers[layer].worldListLast = item;
00201     }
00202     // set the item's parent pointer to the owning layer
00203     item->parent = &layers[layer];
00204     // prevent the item from being drawn
00205     item->enableDraw = FALSE;
00206     // initalize the source rect such that the whole item requires an update
00207     item->src.x = item->src.y = 0;
00208     item->src.w = item->loc.w;
00209     item->src.h = item->loc.h;
00210 }
00211 
00212 void RemoveRenderItem(RenderItem *item) {
00213     // check for first or only item in the list
00214     if (item->prev == NULL) {
00215         // replace the first item in the list with the second & check for
00216         // removing the last item
00217         if ((item->parent->worldListFirst = item->parent->worldListFirst->next)
00218         == NULL) {
00219             // clear the last item pointer
00220             item->parent->worldListLast = NULL;
00221         }
00222         else {
00223             // fix the previous pointer of the new first item
00224             item->parent->worldListFirst->prev = NULL;
00225         }
00226     }
00227     // check for last item in the list
00228     else if (item->next == NULL) {
00229         // replace the last item in the list with the one before the last and
00230         // fix the next pointer of the new last item
00231         (item->parent->worldListLast = item->parent->worldListLast->prev)->next
00232         = NULL;
00233     }
00234     // remove some item between the first and last in the list
00235     else {
00236         item->prev->next = item->next;
00237         item->next->prev = item->prev;
00238     }
00239     //#ifndef NDEBUG
00240     // clear the item's pointers
00241     item->parent = (Layer*)(item->next = item->prev = (RenderItem*)NULL);
00242     //#endif
00243 }
00244 
00256 static void AddToUpdateLists(RenderItem * _restrict_ item,
00257 SDL_Rect * _restrict_ rect) {
00258     int loop,     // loop counter
00259     state,        // update list state value; different than index
00260     stateInd,     // update list state index; 0 is the next state index to draw
00261     delta,        // used in collision detect & overlap code 
00262     area,         // temp area
00263     overlapArea,  // area of the overlap of two rects
00264     proposedArea, // area of the least enlarged rect in the update list
00265     proposedIndex = -1; // the index of the least enlarged rect
00266     SDL_Rect * _restrict_ updateRect, overlap, proposed;
00267     // loop through all the update lists for each display state
00268     #if (BACK_STATES > 2)
00269     #error This loop will fail with more than two display states
00270     #endif
00271     for (stateInd = 0, state = updateList.currState;
00272     stateInd < updateList.totalStates;
00273     stateInd++, state = *(((Uint8*)&(updateList.currState)) + stateInd)) {
00274         // find the first rectangle in the update list
00275         updateRect = updateList.rects[state];
00276         // check for collisions with rects already in the update list
00277         for (loop = 0; loop < updateList.numRects[state];
00278         loop++, updateRect++) {
00279             // -----------------------------------------------------------------
00280             // Check for a collision & find overlap.
00281             // find the delta between the Y coords and see if updateRect is lower
00282             if ((delta = updateRect->y - rect->y) > 0) {
00283                 // check for no vertical overlap and set overlap height
00284                 if ((delta > rect->h) || !(overlap.h =
00285                 (rect->h - delta) > updateRect->h ? updateRect->h :
00286                 rect->h - delta))
00287                     continue;
00288                 // set y starting position
00289                 overlap.y = updateRect->y;
00290             }
00291             else {
00292                 // check for no vertical overlap (rect is lower) and set height
00293                 if ((-delta > updateRect->h) || !(overlap.h =
00294                 (updateRect->h + delta) > rect->h ? rect->h :
00295                 updateRect->h + delta))
00296                     continue;
00297                 // set y starting position
00298                 overlap.y = rect->y;
00299             }
00300             // see if rect is further left
00301             if ((delta = updateRect->x - rect->x) > 0) {
00302                 // check for no horizontal overlap and set overlap width
00303                 if ((delta > rect->w) || !(overlap.w =
00304                 (rect->w - delta) > updateRect->w ? updateRect->w :
00305                 rect->w - delta))
00306                     continue;
00307                 // set x starting position
00308                 overlap.x = updateRect->x;
00309             }
00310             else {
00311                 // check for no horizontal overlap and set overlap width
00312                 if ((-delta > updateRect->w) || !(overlap.w =
00313                 (updateRect->w + delta) > rect->w ? rect->w :
00314                 updateRect->w + delta))
00315                     continue;
00316                 // set x starting position
00317                 overlap.x = rect->x;
00318             }
00319             // -----------------------------------------------------------------
00320             // if contained entirely, use this rect
00321             if ((overlap.x == rect->x) && (overlap.y == rect->y) &&
00322                 (overlap.w == rect->w) && (overlap.h == rect->h)) {
00323                 // use this rect
00324                 item->rectIndex[stateInd] = loop;
00325                 // quit searching
00326                 goto AddToUpdateLists_nextState;
00327             }
00328             // compute the area of the overlap
00329             overlapArea = overlap.h * overlap.w;
00330             // find the smallest rect that includes both the one in the update
00331             // list and the region that this item needs to updae
00332             if (rect->x < updateRect->x) { // x coordinate
00333                 overlap.x = rect->x;
00334             }
00335             else {
00336                 overlap.x = updateRect->x;
00337             }
00338             if ((rect->x + rect->w) >  // width
00339             (updateRect->x + updateRect->w)) {
00340                 overlap.w = rect->x + rect->w - overlap.x;
00341             }
00342             else {
00343                 overlap.w = updateRect->x + updateRect->w - overlap.x;
00344             }
00345             if (rect->y < updateRect->y) { // y coordinate
00346                 overlap.y = rect->y;
00347             }
00348             else {
00349                 overlap.y = updateRect->y;
00350             }
00351             if ((rect->y + rect->h) >  // height
00352             (updateRect->y + updateRect->h)) {
00353                 overlap.h = rect->y + rect->h - overlap.y;
00354             }
00355             else {
00356                 overlap.h = updateRect->y + updateRect->h - overlap.y;
00357             }
00358             // if overlap area is greater than growing this update rect . . .
00359             if ((overlapArea > (area = overlap.w * overlap.h - overlapArea)) &&
00360                 // previous found? Compare with this one
00361                 (((proposedIndex > -1) && (proposedArea > area)) || 
00362                 (proposedIndex == -1 ))) {
00363                     // remember this one and continue
00364                     proposedIndex = loop;
00365                     proposedArea = area;
00366                     proposed = overlap;
00367             }
00368         }
00369         // if too small overlap found or no collision . . .
00370         if (proposedIndex == -1) {
00371             // add a new rect to the update list
00372             *updateRect = *rect;     // updateRect already advanced to the
00373                                      // next rect
00374             item->rectIndex[stateInd] = updateList.numRects[state]++;
00375         }
00376         else {
00377             // store the index of the rect to use and enlarge
00378             item->rectIndex[stateInd] = proposedIndex;
00379             // modify the rect
00380             updateList.rects[state][proposedIndex] = proposed;
00381         }
00382         AddToUpdateLists_nextState: ;
00383         // The above label exists to break out of the inner for loop and
00384         // continue in the outer loop, skipping the above if-else statement.
00385         // It just speeds things up without the extra if check that would be
00386         // needed without a goto.
00387     }
00388 }
00389 
00390 void PlaceRenderItem(RenderItem * _restrict_ item) {
00391     SDL_Rect * _restrict_ prev;
00392     int loop;
00393     // flag the item as placed
00394     item->placed = item->enableDraw = TRUE;
00395     // compute the physical location of the portion of the item that needs to
00396     // be updated
00397     item->physLocX = item->loc.x + item->parent->offX;
00398     item->physLocY = item->loc.y + item->parent->offY;
00399     // see if the item's location is not in the viewable area
00400     if ((item->physLocX <= -item->loc.w) || (item->physLocX >= dInfo.pw)
00401     || (item->physLocY <= -item->loc.h) || (item->physLocY >= dInfo.ph)) {
00402         // mark the item as not visible
00403         item->visible = FALSE;
00404         // may have to update the old location if not everything is being drawn
00405         if (!updateList.renderAll) {
00406             // add the old location to the update list if it was visible
00407             #if (BACK_STATES > 2)
00408             #error This will fail with more than two display states
00409             #endif
00410             // loop from the last state
00411             for (prev = &(item->prevStates[updateList.totalStates - 1]),
00412             loop = updateList.totalStates; loop > 0; prev--, loop--) {
00413                 // check for invisibility
00414                 if ((prev->w == 0) || (prev->h == 0))
00415                     // no need to update something that isn't on the display
00416                     continue;
00417                 // redraw the location where the item was last seen
00418                 AddToUpdateLists(item, prev);
00419                 // flag the owning layer as dirty
00420                 item->parent->dirty = TRUE;
00421                 // flag the screen as dirty
00422                 updateList.dirty = updateList.totalStates;
00423             }
00424         }
00425         // all done!
00426         return;
00427     }
00428     // check for a request/need to draw everything
00429     if (updateList.renderAll) {
00430         // all done!
00431         return;
00432     }
00433     // check for bad width
00434     if (item->src.w == 0) {
00435         assert(item->loc.w > item->src.x);
00436         // set the width
00437         item->src.w = item->loc.w - item->src.x;
00438     }
00439     // check for bad height
00440     if (item->src.h == 0) {
00441         assert(item->loc.h > item->src.y);
00442         // set the width
00443         item->src.h = item->loc.h - item->src.y;
00444     }
00445     // compute the physical destination for the region marked as dirty
00446     item->physDest.x = item->physLocX + item->src.x;
00447     item->physDest.w = item->src.w;
00448     item->physDest.y = item->physLocY + item->src.y;
00449     item->physDest.h = item->src.h;
00450     // clip the physical destination to the display
00451     ClipRectToWH(&(item->physDest), dInfo.pw, dInfo.ph);
00452     // set the new source rect that accounts for clipping
00453     item->src.x = item->physDest.x - item->physLocX;
00454     item->src.y = item->physDest.y - item->physLocY;
00455     item->src.w = item->physDest.w;
00456     item->src.h = item->physDest.h;
00457     // check for an item with nothing to draw
00458     if ((item->physDest.w == 0) || (item->physDest.h == 0)) {
00459         // all done!
00460         return;
00461     }
00462     // this item may need to be drawn, so set the dirty flag
00463     item->dirty = TRUE;
00464     // the item is visible, so set that flag, too
00465     item->visible = TRUE;
00466     // flag the owning layer as dirty
00467     item->parent->dirty = TRUE;
00468     // flag the screen as dirty
00469     updateList.dirty = updateList.totalStates;
00470     // add the old location to the update list if it was visible
00471     #if (BACK_STATES > 2)
00472     #error This will fail with more than two display states
00473     #endif
00474     // loop from the last state to the current (physDest) state
00475     for (prev = &(item->prevStates[updateList.totalStates - 1]),
00476     loop = updateList.totalStates + 1; loop > 0; prev--, loop--) {
00477         // check for invisibility
00478         if ((prev->w == 0) || (prev->h == 0))
00479             // no need to update something that isn't on the display
00480             continue;
00481         // update the rect
00482         AddToUpdateLists(item, prev);
00483     }
00484     // add the new location to the update list
00485     //AddToUpdateLists(item, &(item->physDest));
00486 }
00487 
00488 void ClearRenderItem(RenderItem *item) {
00489     int loop, state;
00490     // flag the item as not visible
00491     item->dirty = item->visible = item->enableDraw = FALSE;
00492     // see if the item's location is not in the viewable area
00493     if ((item->physDest.x <= -item->loc.w) || (item->physDest.x >= dInfo.pw)
00494     || (item->physDest.y <= -item->loc.h) || (item->physDest.y >= dInfo.ph)) {
00495         // all done!
00496         return;
00497     }
00498     // flag the screen as dirty
00499     updateList.dirty = updateList.totalStates;
00500     // loop through the previous states
00501     #if (BACK_STATES > 2)
00502     #error This loop will fail with more than two display states
00503     #endif
00504     for (loop = 0, state = updateList.currState; loop < updateList.totalStates;
00505     loop++, state = *(((Uint8*)&(updateList.currState)) + loop)) {
00506         // check for visibility in a previous state
00507         if (item->prevStates[loop].w > 0) {
00508             // add this rect to the list
00509             updateList.rects[state][updateList.numRects[state]++] =
00510             item->prevStates[updateList.totalStates - loop - 1];
00511             // adding without checking what is already in the update list
00512             // can cause an inefficent draw, but so can spending time
00513             // figuring out the overlaps, and I'm finised worrying about it.
00514         }
00515     }
00516 }
00517 
00518 void SetLayerOffset(Layer * _restrict_ layer, Sint16 x, Sint16 y) {
00519     RenderItem * _restrict_ item;
00520     // first, record the new offsets
00521     layer->offX = x;
00522     layer->offY = y;
00523     // No need to set dirty flags -- that will happen as items are placed.
00524     // Loop through the layer's items
00525     for (item = layer->worldListFirst; item != NULL; item = item->next) {
00526         // check for a drawable item
00527         if (item->enableDraw) {
00528             // place the item
00529             PlaceRenderItem(item);
00530         }
00531     }
00532 }
00533 
00547 static Bool FindNextCollision(RenderItem * _restrict_ item) {
00548     int loop, delta;
00549     SDL_Rect * _restrict_ rect;
00550     // loop through the remaining rects in the update list
00551     for (rect = &(updateList.rects[updateList.currState][(loop = item->rectIndex[0] + 1)]);
00552     loop < updateList.numRects[updateList.currState]; loop++, rect++) {
00553         // Check for a collision while computing the overlap.
00554         // find the delta between the Y coords and see if rect is lower
00555         if ((delta = rect->y - item->physLocY) > 0) {
00556             // check for no vertical overlap and set the overlap height
00557             if ((delta > item->loc.h) || !(item->physDest.h =
00558             (item->loc.h - delta) > rect->h ? rect->h :
00559             item->loc.h - delta))
00560                 continue;
00561             // set y starting position
00562             item->physDest.y = rect->y;
00563         }
00564         else {
00565             // check for no vertical overlap (rect is higher) and set height
00566             if ((-delta > rect->h) || !(item->physDest.h =
00567             (rect->h + delta) > item->loc.h ? item->loc.h :
00568             rect->h + delta))
00569                 continue;
00570             // set y starting position
00571             item->physDest.y = item->physLocY;
00572         }
00573         // see if rect is further right
00574         if ((delta = rect->x - item->physLocX) > 0) {
00575             // check for no horizontal overlap and set overlap width
00576             if ((delta > item->loc.w) || !(item->physDest.w =
00577             (item->loc.w - delta) > rect->w ? rect->w :
00578             item->loc.w - delta))
00579                 continue;
00580             // set x starting position
00581             item->physDest.x = rect->x;
00582         }
00583         else {
00584             // check for no horizontal overlap and set overlap width
00585             if ((-delta > rect->w) || !(item->physDest.w =
00586             (rect->w + delta) > item->loc.w ? item->loc.w :
00587             rect->w + delta))
00588                 continue;
00589             // set x starting position
00590             item->physDest.x = item->physLocX;
00591         }
00592         // Collision!
00593         // set the rectangle index for future reference
00594         item->rectIndex[0] = loop;
00595         // set the source rect
00596         item->src.x = item->physDest.x - item->physLocX;
00597         item->src.y = item->physDest.y - item->physLocY;
00598         item->src.w = item->physDest.w;
00599         item->src.h = item->physDest.h;
00600         return TRUE;
00601     }
00602     // no collision
00603     return FALSE;
00604 }
00605 
00606 void Render() {
00607     RenderItem * _restrict_ item;  // first test of restrict keyword
00608     Layer * _restrict_ layer;
00609     int loop, state;
00610     SDL_Rect * _restrict_ rect;
00611     if (updateList.renderAll) {
00612         // render everything
00613         // First, loop through the layers.
00614         for (layer = layers, loop = MAX_LAYERS; loop > 0; layer++, loop--) {
00615             // Iterate through all items within the layer.
00616             for (item = layer->worldListFirst; item != NULL; item = item->next) {
00617                 // see if this item should not be drawn
00618                 if (!item->enableDraw) continue;
00619                 // compute the physical position
00620                 item->physDest.x = item->physLocX = item->loc.x + layer->offX;
00621                 item->physDest.y = item->physLocY = item->loc.y + layer->offY;
00622                 item->physDest.w = item->loc.w;
00623                 item->physDest.h = item->loc.h;
00624                 // clip to the display region
00625                 ClipRectToWH(&(item->physDest), dInfo.pw, dInfo.ph);
00626                 // check for an invisible item
00627                 if ((item->physDest.w == 0) || (item->physDest.h == 0)) {
00628                     // shortened state update for invisible items
00629                     for (state = updateList.totalStates - 1; state > 0; state--) {
00630                         // copy one state
00631                         item->prevStates[state] = item->prevStates[state - 1];
00632                     }
00633                     // Next, set a new state indicating the item was not drawn
00634                     // region of the item, not just what was redrawn.
00635                     item->prevStates[0].w = item->prevStates[0].h = 0;
00636                     // reset flags
00637                     item->dirty = item->visible = item->placed = FALSE;
00638                     // done!
00639                     continue;
00640                 }
00641                 // set the new source rect
00642                 item->src.x = item->physDest.x - item->physLocX;
00643                 item->src.y = item->physDest.y - item->physLocY;
00644                 item->src.w = item->physDest.w;
00645                 item->src.h = item->physDest.h;
00646                 // render the item 
00647                 (*(item->renderer))(dInfo.display, item);
00648                 #ifdef RENDER_INDIVIDUAL_UPDATES
00649                 SDL_UpdateRect(dInfo.display, item->physDest.x,
00650                 item->physDest.y, item->physDest.w, item->physDest.h);
00651                 #endif
00652                 // Update the previous states.
00653                 // First, move the old states to make room for the new one
00654                 for (state = updateList.totalStates - 1; state > 0; state--) {
00655                     // copy one state
00656                     item->prevStates[state] = item->prevStates[state - 1];
00657                 }
00658                 // Next, add in the new state. Must include the entire region of
00659                 // the item, not just what was redrawn.
00660                 item->prevStates[0].x = item->physLocX;
00661                 item->prevStates[0].y = item->physLocY;
00662                 item->prevStates[0].w = item->loc.w;
00663                 item->prevStates[0].h = item->loc.h;
00664                 // clip to the display region
00665                 ClipRectToWH(&(item->prevStates[0]), dInfo.pw, dInfo.ph);
00666                 // Reset flags.
00667                 item->dirty = item->visible = item->placed = FALSE;
00668             }
00669             // clear the layer's flags
00670             layer->flags = 0;
00671         }
00672         #ifndef RENDER_INDIVIDUAL_UPDATES
00673         // update the screen
00674         SDL_UpdateRect(dInfo.display, 0, 0, 0, 0);
00675         #endif
00676     }
00677     else if (updateList.dirty) {
00678         // First, loop through the layers.
00679         for (layer = layers, loop = MAX_LAYERS; loop > 0; layer++, loop--) {
00680             // Make the render list.
00681             // Iterate through all items within the layer.
00682             for (item = layer->worldListFirst; item != NULL; item = item->next) {
00683                 // see if this item is already flagged as dirty
00684                 if (item->dirty) {
00685                     // Update the source and dest rects to reflect any
00686                     // enlargement of the update region that may have occured.
00687                     // First, get a reference to the item's update rect.
00688                     rect = &(updateList.rects[updateList.currState][item->rectIndex[0]]);
00689                     // see if the item does not use all the space
00690                     if ((item->physDest.w < rect->w) ||
00691                     (item->physDest.h < rect->h)) {
00692                         // set the dest to be the entire item
00693                         item->physDest.x = item->physLocX;
00694                         item->physDest.y = item->physLocY;
00695                         item->physDest.w = item->loc.w;
00696                         item->physDest.h = item->loc.h;
00697                         // clip the dest to the update rect
00698                         ClipRectToRect(&(item->physDest), rect);
00699                         // set the new source rect
00700                         item->src.x = item->physDest.x - item->physLocX;
00701                         item->src.y = item->physDest.y - item->physLocY;
00702                         item->src.w = item->physDest.w;
00703                         item->src.h = item->physDest.h;
00704                     }
00705                     // render it
00706                     (*(item->renderer))(dInfo.display, item);
00707                     #ifdef RENDER_INDIVIDUAL_UPDATES
00708                     SDL_UpdateRect(dInfo.display, item->physDest.x,
00709                     item->physDest.y, item->physDest.w, item->physDest.h);
00710                     #endif
00711                     // Update the previous states.
00712                     Render_updateStates:
00713                     // First, move the old states to make room for the new one
00714                     for (state = updateList.totalStates - 1; state > 0; state--) {
00715                         // copy one state
00716                         item->prevStates[state] = item->prevStates[state - 1];
00717                     }
00718                     // Next, add in the new state. Must include the entire
00719                     // region of the item, not just what was redrawn.
00720                     item->prevStates[0].x = item->physLocX;
00721                     item->prevStates[0].y = item->physLocY;
00722                     item->prevStates[0].w = item->loc.w;
00723                     item->prevStates[0].h = item->loc.h;
00724                     // clip to the display region
00725                     ClipRectToWH(&(item->prevStates[0]), dInfo.pw, dInfo.ph);
00726                 }
00727                 else if ((layer->dirty || !item->placed) && item->enableDraw) {
00728                     // Items that are not dirty may need to be partially drawn.
00729                     // Set the physical location of the item.
00730                     item->physLocX = item->loc.x + layer->offX;
00731                     item->physLocY = item->loc.y + layer->offY;
00732                     // check for visibility and set the flag accordingly
00733                     if ((item->physLocX <= -item->loc.w)
00734                     || (item->physLocX >= dInfo.pw)
00735                     || (item->physLocY <= -item->loc.h)
00736                     || (item->physLocY >= dInfo.ph)) {
00737                         // the item is not visible
00738                         item->visible = FALSE;
00739                         // update its state
00740                         goto Render_updateStatesInvis;
00741                     }
00742                     else {
00743                         // the item is visible
00744                         item->visible = TRUE;
00745                         // check for a collision with an update rect
00746                         item->rectIndex[0] = -1;
00747                         // loop through all collisions
00748                         while (FindNextCollision(item)) {
00749                             // render it
00750                             (*(item->renderer))(dInfo.display, item);
00751                             #ifdef RENDER_INDIVIDUAL_UPDATES
00752                             SDL_UpdateRect(dInfo.display, item->physDest.x,
00753                             item->physDest.y, item->physDest.w,
00754                             item->physDest.h);
00755                             #endif
00756                         }
00757                     }
00758                     // update the item's states
00759                     goto Render_updateStates;
00760                 }
00761                 else {
00762                     // shortened state update for invisible items
00763                     Render_updateStatesInvis:
00764                     for (state = updateList.totalStates - 1; state > 0; state--) {
00765                         // copy one state
00766                         item->prevStates[state] = item->prevStates[state - 1];
00767                     }
00768                     // Next, set a new state indicating the item was not drawn
00769                     // region of the item, not just what was redrawn.
00770                     item->prevStates[0].w = item->prevStates[0].h = 0;
00771                 }
00772                 // from here to the end of Render() the RenderItem_t::placed
00773                 // flag is irrelavent and should be cleared for all items
00774                 // Reset flags.
00775                 item->dirty = item->visible = item->placed = FALSE;
00776                 // clear region to update
00777                 item->src.x = item->src.y = item->src.w = item->src.h = 0;
00778             }
00779             // clear the layer's flags
00780             layer->flags = 0;
00781         }
00782         // update the screen
00783         #ifndef RENDER_INDIVIDUAL_UPDATES
00784         SDL_UpdateRects(dInfo.display,
00785         updateList.numRects[updateList.currState],
00786         updateList.rects[updateList.currState]);
00787         #endif
00788     }
00789     // decrement the dirty count and check for a clean display
00790     if (--updateList.dirty <= 0) {
00791         // assure the dirty count does not go below zero
00792         updateList.dirty = 0;
00793         // no need to render anything more until change; clear the flag
00794         updateList.renderAll = FALSE;
00795     }
00796     // remove all rects for this state
00797     updateList.numRects[updateList.currState] = 0;
00798     // advance the display state indicators
00799     updateList.nextState = ((updateList.currState = (updateList.currState + 1)
00800     % updateList.totalStates) + 1) % updateList.totalStates;
00801     // show the new frame
00802     if (dInfo.display->flags & SDL_DOUBLEBUF) {
00803         SDL_Flip(dInfo.display);
00804     }
00805 }
00806 
00807 void GenericSurfaceRenderer(SDL_Surface *dest, RenderItem *item) {
00808     // Both src and physLoc in RenderItem must be clipped by the render system.
00809     // Call SDL_LowerBlit() in the generic renderer function to draw
00810     // an image; this will avoid the clipping done by SDL_UpperBlit() /
00811     // SDL_BlitSurface() and the time taken for clipping again.
00812     SDL_LowerBlit(item->data, &(item->src), dest, &(item->physDest));
00813 }
00814 
00815 void SolidFillRenderer(SDL_Surface *dest, RenderItem *item) {
00816     // render a rectangle
00817     SDL_FillRect(dest, &(item->physDest), *(Uint32*)item->data);
00818 }
00819 
00823 Uint32 videoFlags = 0;
00824 
00825 #define rounddivup(n, d)  ((((n) % (d)) > 0) ? ((int)(n) / (d) + 1) : ((int)(n) / (d)))
00826 
00827 Bool ResizeWindow(Uint16 w, Uint16 h) {
00828     if ((dInfo.display = SDL_SetVideoMode(w, h, 0, videoFlags)) == NULL) {
00829         //fprintf(stderr, "Resize failure from SDL\n");
00830         return FALSE;
00831     }
00832     dInfo.pw = w;
00833     dInfo.lw = rounddivup(dInfo.pw, dInfo.luw);
00834     dInfo.ph = h;
00835     dInfo.lh = rounddivup(dInfo.ph, dInfo.luh);
00836     ForceRenderAll();
00837     return TRUE;
00838 }
00839 

Generated on Mon May 28 04:41:39 2007 for Retro Tank Super Attack by  doxygen 1.5.2