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, ©);
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