1 #include "SDL_Painter.h"
2 #include <stdlib.h>
3 
4 // #define DEBUG
5 
6 extern SDL_Surface *display;
7 
SDL_Painter(IIM_Surface * gameScreen,IIM_Surface * bg)8 SDL_Painter::SDL_Painter(IIM_Surface *gameScreen, IIM_Surface *bg)
9   : gameScreen(gameScreen), backGround(bg), nbElts(0), nbPrev(0) {}
10 
requestDraw(IIM_Surface * surf,SDL_Rect * where)11 void SDL_Painter::requestDraw(IIM_Surface *surf, SDL_Rect *where)
12 {
13 #ifdef DEBUG
14   if (nbElts >= MAX_PAINT_ELTS) {
15     fprintf(stderr, "To much elements given to SDL_Painter...\n");
16     exit(1);
17   }
18 #endif
19   DrawElt elt;
20   elt.surf =  surf;
21   elt.rect = *where;
22   onScreenElts[nbElts++] = elt;
23 }
24 
isEqual(DrawElt & d1,DrawElt & d2)25 static inline bool isEqual(DrawElt &d1, DrawElt &d2)
26 {
27   return (d1.surf == d2.surf)
28     && (d1.rect.x == d2.rect.x)
29     && (d1.rect.y == d2.rect.y)
30     && (d1.rect.w == d2.rect.w)
31     && (d1.rect.h == d2.rect.h);
32 }
33 
isEqual(const SDL_Rect & r1,const SDL_Rect & r2)34 static inline bool isEqual(const SDL_Rect &r1, const SDL_Rect &r2)
35 {
36   return (r1.x == r2.x)
37     && (r1.y == r2.y)
38     && (r1.w == r2.w)
39     && (r1.h == r2.h);
40 }
41 
isInside(const SDL_Rect & r1,const SDL_Rect & r2)42 static inline bool isInside(const SDL_Rect &r1, const SDL_Rect &r2)
43 {
44   return (r1.x >= r2.x) && (r1.x + r1.w <= r2.x + r2.w)
45       && (r1.y >= r2.y) && (r1.y + r1.h <= r2.y + r2.h);
46 }
47 
addRectToList(SDL_Rect rectList[MAX_PAINT_ELTS],int nbRect,const SDL_Rect & rect)48 static inline int addRectToList(SDL_Rect rectList[MAX_PAINT_ELTS], int nbRect, const SDL_Rect &rect)
49 {
50   if ((rect.w <= 0) || (rect.h <= 0)) return nbRect;
51   for (int r=0; r<nbRect; ++r)
52   {
53     // rectangle deja contenu dans un autre...
54     if (isInside(rect, rectList[r]) || isEqual(rect, rectList[r]))
55       return nbRect;
56     // rectangle en contenant d'autre
57     if (isInside(rectList[r], rect)) {
58       rectList[r] = rectList[nbRect-1];
59       return addRectToList(rectList, nbRect-1, rect);
60     }
61     // rectangle colle a un autre: on etend l'autre.
62     // voisin horizontal
63     if ((rect.y == rectList[r].y) && (rect.h == rectList[r].h)) {
64       if ((rect.x >= rectList[r].x) && (rect.x <= rectList[r].x + rectList[r].w)) {
65         SDL_Rect newRect = rectList[r];
66         newRect.w = rect.w + rect.x - rectList[r].x;
67         rectList[r] = rectList[nbRect-1];
68         return addRectToList(rectList, nbRect-1, newRect);
69       }
70       if ((rectList[r].x >= rect.x) && (rectList[r].x <= rect.x + rect.w)) {
71         SDL_Rect newRect = rect;
72         newRect.w = rectList[r].w + rectList[r].x - rect.x;
73         rectList[r] = rectList[nbRect-1];
74         return addRectToList(rectList, nbRect-1, newRect);
75       }
76     }
77     // voisin vertical
78     if ((rect.x == rectList[r].x) && (rect.w == rectList[r].w)) {
79       if ((rect.y >= rectList[r].y) && (rect.y <= rectList[r].y + rectList[r].h)) {
80         SDL_Rect newRect = rectList[r];
81         newRect.h = rect.h + rect.y - rectList[r].y;
82         rectList[r] = rectList[nbRect-1];
83         return addRectToList(rectList, nbRect-1, newRect);
84       }
85       if ((rectList[r].y >= rect.y) && (rectList[r].y <= rect.y + rect.h)) {
86         SDL_Rect newRect = rect;
87         newRect.h = rectList[r].h + rectList[r].y - rect.y;
88         rectList[r] = rectList[nbRect-1];
89         return addRectToList(rectList, nbRect-1, newRect);
90       }
91     }
92   }
93   rectList[nbRect] = rect;
94   return nbRect + 1;
95 }
96 
draw(SDL_Surface * surf)97 void SDL_Painter::draw(SDL_Surface *surf)
98 {
99   SDL_Rect rectToUpdate[MAX_PAINT_ELTS]; // liste des zones a reafficher.
100   int nbRects = 0;
101 
102   bool findMatchPrev[MAX_PAINT_ELTS];
103 
104   for (int j=0; j<nbPrev; ++j)
105     findMatchPrev[j] = false;
106 
107   // Chercher les differences entre la liste actuelle et l'ancienne,
108   // les stocker dans une liste.
109   for (int i=0; i<nbElts; ++i) {
110     bool findMatchElts = false;
111     for (int j=0; j<nbPrev; ++j) {
112       if (isEqual(onScreenElts[i], onScreenPrev[j])) {
113         findMatchElts = true;
114         findMatchPrev[j] = true;
115       }
116     }
117     // Nouvel elements: ajouter une zone a reafficher.
118     if (!findMatchElts)
119       nbRects = addRectToList(rectToUpdate, nbRects, onScreenElts[i].rect);
120   }
121 
122   // Reafficher aussi les zones des elements ayant disparus.
123   for (int j=0; j<nbPrev; ++j) {
124     if (!findMatchPrev[j])
125       nbRects = addRectToList(rectToUpdate, nbRects, onScreenPrev[j].rect);
126   }
127 
128   // Pour chaque rectangle
129   // Chercher les elements de la liste actuelle qui intersectent
130   //  (note: j'assume que SDL fait ca aussi bien que nous)
131 #ifdef DEBUG
132 
133   SDL_SetClipRect(surf, NULL);
134   SDL_BlitSurface(backGround, NULL, surf, NULL);
135 
136   // Draw everything.
137   for (int i=0; i<nbElts; ++i) {
138     SDL_Rect copy = onScreenElts[i].rect;
139     SDL_BlitSurface(onScreenElts[i].surf, NULL,
140         surf, &copy);
141   }
142 
143   for (int r=0; r<nbRects; ++r) {
144     SDL_Rect over1 = rectToUpdate[r];
145     SDL_Rect over2 = over1;
146     SDL_Rect over3 = over2;
147     SDL_Rect over4 = over3;
148     over1.h = 1;
149     over2.w = 1;
150     over3.y += over3.h;
151     over3.h = 1;
152     over4.x += over4.w;
153     over4.w = 1;
154     SDL_FillRect(surf,&over1,0xffffffff);
155     SDL_FillRect(surf,&over2,0xffffffff);
156     SDL_FillRect(surf,&over3,0xffffffff);
157     SDL_FillRect(surf,&over4,0xffffffff);
158   }
159 
160 #else
161 
162   for (int r=0; r<nbRects; ++r) {
163     SDL_SetClipRect(surf, &rectToUpdate[r]);
164     SDL_BlitSurface(backGround->surf, &rectToUpdate[r], surf, &rectToUpdate[r]);
165     for (int i=0; i<nbElts; ++i) {
166       // Afficher ces elements.
167       SDL_Rect rect = onScreenElts[i].rect;
168       SDL_BlitSurface(onScreenElts[i].surf->surf, NULL,
169                       surf, &rect);
170     }
171   }
172 #endif
173 
174   // Draw what is necessary...
175   storeScreenContent(surf);
176 }
177 
storeScreenContent(SDL_Surface * surf)178 void SDL_Painter::storeScreenContent(SDL_Surface *surf)
179 {
180   if (surf != display) {
181     SDL_SetClipRect(display,NULL);
182     SDL_BlitSurface(surf,NULL,display,NULL);
183   }
184   nbPrev = nbElts;
185   while(nbElts > 0) {
186     nbElts --;
187     onScreenPrev[nbElts] = onScreenElts[nbElts];
188   }
189   nbElts = 0;
190 }
191 
redrawAll(SDL_Surface * surf)192 void SDL_Painter::redrawAll(SDL_Surface *surf)
193 {
194   SDL_SetClipRect(surf, NULL);
195 
196   // Draw everything.
197   SDL_BlitSurface(backGround->surf, NULL, surf, NULL);
198   for (int i=0; i<nbElts; ++i) {
199     SDL_BlitSurface(onScreenElts[i].surf->surf, NULL,
200         surf, &onScreenElts[i].rect);
201   }
202 
203   // Remember what is on screen...
204   storeScreenContent(surf);
205 }
206