|
85
|
1 /*
|
|
|
2 pygame - Python Game Library
|
|
107
|
3 Copyright (C) 2000-2001 Pete Shinners
|
|
85
|
4
|
|
|
5 This library is free software; you can redistribute it and/or
|
|
|
6 modify it under the terms of the GNU Library General Public
|
|
|
7 License as published by the Free Software Foundation; either
|
|
|
8 version 2 of the License, or (at your option) any later version.
|
|
|
9
|
|
|
10 This library is distributed in the hope that it will be useful,
|
|
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
13 Library General Public License for more details.
|
|
|
14
|
|
|
15 You should have received a copy of the GNU Library General Public
|
|
|
16 License along with this library; if not, write to the Free
|
|
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
18
|
|
|
19 Pete Shinners
|
|
|
20 pete@shinners.org
|
|
|
21 */
|
|
|
22
|
|
|
23 /*
|
|
|
24 * drawing module for pygame
|
|
|
25 */
|
|
|
26 #include "pygame.h"
|
|
442
|
27 #include <math.h>
|
|
|
28
|
|
457
|
29 #ifdef _MSC_VER
|
|
|
30 #pragma warning (disable:4244)
|
|
|
31
|
|
|
32 float trunc(float d)
|
|
|
33 {
|
|
|
34 if (d >= 0)
|
|
|
35 return floor(d);
|
|
|
36 return ceil(d);
|
|
|
37 }
|
|
|
38
|
|
|
39 #endif
|
|
|
40
|
|
442
|
41 #define FRAC(z) (z-trunc(z))
|
|
|
42 #define INVFRAC(z) (1-(z-trunc(z)))
|
|
85
|
43
|
|
93
|
44 static int clip_and_draw_line(SDL_Surface* surf, SDL_Rect* rect, Uint32 color, int* pts);
|
|
442
|
45 static int clip_and_draw_aaline(SDL_Surface* surf, SDL_Rect* rect, Uint32 color, float* pts, int blend);
|
|
176
|
46 static int clip_and_draw_line_width(SDL_Surface* surf, SDL_Rect* rect, Uint32 color, int width, int* pts);
|
|
85
|
47 static int clipline(int* pts, int left, int top, int right, int bottom);
|
|
442
|
48 static int clipaaline(float* pts, int left, int top, int right, int bottom);
|
|
85
|
49 static void drawline(SDL_Surface* surf, Uint32 color, int startx, int starty, int endx, int endy);
|
|
442
|
50 static void drawaaline(SDL_Surface* surf, Uint32 color, float startx, float starty, float endx, float endy,
|
|
|
51 int blend);
|
|
93
|
52 static void drawhorzline(SDL_Surface* surf, Uint32 color, int startx, int starty, int endx);
|
|
257
|
53 static void drawvertline(SDL_Surface* surf, Uint32 color, int x1, int y1, int y2);
|
|
256
|
54 static void draw_ellipse(SDL_Surface *dst, int x, int y, int rx, int ry, Uint32 color);
|
|
|
55 static void draw_fillellipse(SDL_Surface *dst, int x, int y, int rx, int ry, Uint32 color);
|
|
|
56 static void draw_fillpoly(SDL_Surface *dst, int *vx, int *vy, int n, Uint32 color);
|
|
85
|
57
|
|
|
58
|
|
442
|
59 /*DOC*/ static char doc_aaline[] =
|
|
|
60 /*DOC*/ "pygame.draw.aaline(Surface, color, startpos, endpos, blend=1) -> Rect\n"
|
|
|
61 /*DOC*/ "draw a line on a surface\n"
|
|
|
62 /*DOC*/ "\n"
|
|
|
63 /*DOC*/ "Draws an anti-aliased line on a surface. This will respect the\n"
|
|
|
64 /*DOC*/ "clipping rectangle. A bounding box of the effected area is returned\n"
|
|
|
65 /*DOC*/ "returned as a rectangle. The if blend is true, the shades will be\n"
|
|
|
66 /*DOC*/ "be blended with existing pixel shades instead of overwriting them.\n"
|
|
|
67 /*DOC*/ "This function accepts floating point values for the end points.\n"
|
|
|
68 /*DOC*/ "\n"
|
|
|
69 /*DOC*/ "The color argument must be a RGB sequence.\n"
|
|
|
70 /*DOC*/ "\n"
|
|
|
71 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
72 /*DOC*/ ;
|
|
|
73
|
|
|
74 static PyObject* aaline(PyObject* self, PyObject* arg)
|
|
|
75 {
|
|
|
76 PyObject *surfobj, *colorobj, *start, *end;
|
|
|
77 SDL_Surface* surf;
|
|
|
78 float startx, starty, endx, endy;
|
|
|
79 int top, left, bottom, right;
|
|
|
80 int blend=1;
|
|
|
81 float pts[4];
|
|
|
82 Uint8 rgba[4];
|
|
|
83 Uint32 color;
|
|
|
84 int anydraw;
|
|
|
85
|
|
|
86 /*get all the arguments*/
|
|
|
87 if(!PyArg_ParseTuple(arg, "O!OOO|i", &PySurface_Type, &surfobj, &colorobj, &start, &end, &blend))
|
|
|
88 return NULL;
|
|
|
89 surf = PySurface_AsSurface(surfobj);
|
|
|
90
|
|
|
91 if(surf->format->BytesPerPixel !=3 && surf->format->BytesPerPixel != 4)
|
|
|
92 return RAISE(PyExc_ValueError, "unsupported bit depth for aaline draw (supports 32 & 24 bit)");
|
|
|
93
|
|
|
94 if(RGBAFromObj(colorobj, rgba))
|
|
|
95 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
96 else
|
|
|
97 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
|
98
|
|
|
99 if(!TwoFloatsFromObj(start, &startx, &starty))
|
|
|
100 return RAISE(PyExc_TypeError, "Invalid start position argument");
|
|
|
101 if(!TwoFloatsFromObj(end, &endx, &endy))
|
|
|
102 return RAISE(PyExc_TypeError, "Invalid end position argument");
|
|
|
103
|
|
|
104 if(!PySurface_Lock(surfobj)) return NULL;
|
|
|
105
|
|
|
106 pts[0] = startx; pts[1] = starty;
|
|
|
107 pts[2] = endx; pts[3] = endy;
|
|
|
108 anydraw = clip_and_draw_aaline(surf, &surf->clip_rect, color, pts, blend);
|
|
|
109
|
|
|
110 if(!PySurface_Unlock(surfobj)) return NULL;
|
|
|
111
|
|
|
112 /*compute return rect*/
|
|
|
113 if(!anydraw)
|
|
|
114 return PyRect_New4((short)(startx), (short)(starty), 0, 0);
|
|
|
115 if(pts[0] < pts[2])
|
|
|
116 {
|
|
|
117 left = (int)(pts[0]);
|
|
|
118 right = (int)(pts[2]);
|
|
|
119 }
|
|
|
120 else
|
|
|
121 {
|
|
|
122 left = (int)(pts[2]);
|
|
|
123 right = (int)(pts[0]);
|
|
|
124 }
|
|
|
125 if(pts[1] < pts[3])
|
|
|
126 {
|
|
|
127 top = (int)(pts[1]);
|
|
|
128 bottom = (int)(pts[3]);
|
|
|
129 }
|
|
|
130 else
|
|
|
131 {
|
|
|
132 top = (int)(pts[3]);
|
|
|
133 bottom = (int)(pts[1]);
|
|
|
134 }
|
|
|
135 return PyRect_New4((short)left, (short)top, (short)(right-left+2), (short)(bottom-top+2));
|
|
|
136 }
|
|
|
137
|
|
85
|
138 /*DOC*/ static char doc_line[] =
|
|
177
|
139 /*DOC*/ "pygame.draw.line(Surface, color, startpos, endpos, width=1) -> Rect\n"
|
|
85
|
140 /*DOC*/ "draw a line on a surface\n"
|
|
|
141 /*DOC*/ "\n"
|
|
|
142 /*DOC*/ "Draws a line on a surface. This will respect the clipping\n"
|
|
|
143 /*DOC*/ "rectangle. A bounding box of the effected area is returned\n"
|
|
|
144 /*DOC*/ "as a rectangle.\n"
|
|
|
145 /*DOC*/ "\n"
|
|
96
|
146 /*DOC*/ "The color argument can be either a RGB sequence or mapped color integer.\n"
|
|
|
147 /*DOC*/ "\n"
|
|
92
|
148 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
85
|
149 /*DOC*/ ;
|
|
|
150
|
|
|
151 static PyObject* line(PyObject* self, PyObject* arg)
|
|
|
152 {
|
|
|
153 PyObject *surfobj, *colorobj, *start, *end;
|
|
|
154 SDL_Surface* surf;
|
|
|
155 short startx, starty, endx, endy;
|
|
|
156 int top, left, bottom, right;
|
|
176
|
157 int width = 1;
|
|
85
|
158 int pts[4];
|
|
|
159 Uint8 rgba[4];
|
|
|
160 Uint32 color;
|
|
93
|
161 int anydraw;
|
|
85
|
162
|
|
|
163 /*get all the arguments*/
|
|
176
|
164 if(!PyArg_ParseTuple(arg, "O!OOO|i", &PySurface_Type, &surfobj, &colorobj, &start, &end, &width))
|
|
85
|
165 return NULL;
|
|
|
166 surf = PySurface_AsSurface(surfobj);
|
|
|
167
|
|
|
168 if(surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
|
|
|
169 return RAISE(PyExc_ValueError, "unsupport bit depth for line draw");
|
|
|
170
|
|
96
|
171 if(PyInt_Check(colorobj))
|
|
|
172 color = (Uint32)PyInt_AsLong(colorobj);
|
|
|
173 else if(RGBAFromObj(colorobj, rgba))
|
|
|
174 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
175 else
|
|
|
176 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
85
|
177
|
|
|
178 if(!TwoShortsFromObj(start, &startx, &starty))
|
|
|
179 return RAISE(PyExc_TypeError, "Invalid start position argument");
|
|
|
180 if(!TwoShortsFromObj(end, &endx, &endy))
|
|
|
181 return RAISE(PyExc_TypeError, "Invalid end position argument");
|
|
176
|
182
|
|
|
183 if(width < 1)
|
|
|
184 return PyRect_New4(startx, starty, 0, 0);
|
|
|
185
|
|
85
|
186
|
|
90
|
187 if(!PySurface_Lock(surfobj)) return NULL;
|
|
85
|
188
|
|
93
|
189 pts[0] = startx; pts[1] = starty;
|
|
|
190 pts[2] = endx; pts[3] = endy;
|
|
176
|
191 anydraw = clip_and_draw_line_width(surf, &surf->clip_rect, color, width, pts);
|
|
85
|
192
|
|
90
|
193 if(!PySurface_Unlock(surfobj)) return NULL;
|
|
85
|
194
|
|
93
|
195
|
|
85
|
196 /*compute return rect*/
|
|
93
|
197 if(!anydraw)
|
|
|
198 return PyRect_New4(startx, starty, 0, 0);
|
|
|
199 if(pts[0] < pts[2])
|
|
85
|
200 {
|
|
93
|
201 left = pts[0];
|
|
|
202 right = pts[2];
|
|
85
|
203 }
|
|
|
204 else
|
|
|
205 {
|
|
93
|
206 left = pts[2];
|
|
|
207 right = pts[0];
|
|
85
|
208 }
|
|
93
|
209 if(pts[1] < pts[3])
|
|
85
|
210 {
|
|
93
|
211 top = pts[1];
|
|
|
212 bottom = pts[3];
|
|
85
|
213 }
|
|
|
214 else
|
|
|
215 {
|
|
93
|
216 top = pts[3];
|
|
|
217 bottom = pts[1];
|
|
85
|
218 }
|
|
110
|
219 return PyRect_New4((short)left, (short)top, (short)(right-left+1), (short)(bottom-top+1));
|
|
85
|
220 }
|
|
|
221
|
|
|
222
|
|
442
|
223 /*DOC*/ static char doc_aalines[] =
|
|
|
224 /*DOC*/ "pygame.draw.aalines(Surface, color, closed, point_array, blend=1) -> Rect\n"
|
|
|
225 /*DOC*/ "draw multiple connected anti-aliased lines on a surface\n"
|
|
|
226 /*DOC*/ "\n"
|
|
|
227 /*DOC*/ "Draws a sequence on a surface. You must pass at least two points\n"
|
|
|
228 /*DOC*/ "in the sequence of points. The closed argument is a simple boolean\n"
|
|
|
229 /*DOC*/ "and if true, a line will be draw between the first and last points.\n"
|
|
|
230 /*DOC*/ "The boolean blend argument set to true will blend the shades with\n"
|
|
|
231 /*DOC*/ "existing shades instead of overwriting them.\n"
|
|
|
232 /*DOC*/ "This function accepts floating point values for the end points.\n"
|
|
|
233 /*DOC*/ "\n"
|
|
|
234 /*DOC*/ "This will respect the clipping rectangle. A bounding box of the\n"
|
|
|
235 /*DOC*/ "effected area is returned as a rectangle.\n"
|
|
|
236 /*DOC*/ "\n"
|
|
|
237 /*DOC*/ "The color argument must be an RGB sequence.\n"
|
|
|
238 /*DOC*/ "\n"
|
|
|
239 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
240 /*DOC*/ ;
|
|
|
241
|
|
|
242 static PyObject* aalines(PyObject* self, PyObject* arg)
|
|
|
243 {
|
|
|
244 PyObject *surfobj, *colorobj, *closedobj, *points, *item;
|
|
|
245 SDL_Surface* surf;
|
|
|
246 float x, y;
|
|
|
247 int top, left, bottom, right;
|
|
|
248 float pts[4];
|
|
|
249 Uint8 rgba[4];
|
|
|
250 Uint32 color;
|
|
|
251 int closed, blend;
|
|
|
252 int result, loop, length, drawn;
|
|
|
253 float startx, starty;
|
|
|
254
|
|
|
255 /*get all the arguments*/
|
|
|
256 if(!PyArg_ParseTuple(arg, "O!OOO|i", &PySurface_Type, &surfobj, &colorobj, &closedobj,
|
|
|
257 &points, &blend))
|
|
|
258 return NULL;
|
|
|
259 surf = PySurface_AsSurface(surfobj);
|
|
|
260
|
|
|
261 if(surf->format->BytesPerPixel !=3 && surf->format->BytesPerPixel != 4)
|
|
|
262 return RAISE(PyExc_ValueError, "unsupported bit depth for aaline draw (supports 32 & 24 bit)");
|
|
|
263
|
|
|
264 if(RGBAFromObj(colorobj, rgba))
|
|
|
265 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
266 else
|
|
|
267 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
|
268
|
|
|
269 closed = PyObject_IsTrue(closedobj);
|
|
|
270
|
|
|
271 if(!PySequence_Check(points))
|
|
|
272 return RAISE(PyExc_TypeError, "points argument must be a sequence of number pairs");
|
|
|
273 length = PySequence_Length(points);
|
|
|
274 if(length < 2)
|
|
|
275 return RAISE(PyExc_ValueError, "points argument must contain more than 1 points");
|
|
|
276
|
|
|
277 item = PySequence_GetItem(points, 0);
|
|
|
278 result = TwoFloatsFromObj(item, &x, &y);
|
|
|
279 Py_DECREF(item);
|
|
|
280 if(!result) return RAISE(PyExc_TypeError, "points must be number pairs");
|
|
|
281
|
|
|
282 startx = pts[0] = x;
|
|
|
283 starty = pts[1] = y;
|
|
|
284 left = right = (int)x;
|
|
|
285 top = bottom = (int)y;
|
|
|
286
|
|
|
287 if(!PySurface_Lock(surfobj)) return NULL;
|
|
|
288
|
|
|
289 drawn = 1;
|
|
|
290 for(loop = 1; loop < length; ++loop)
|
|
|
291 {
|
|
|
292 item = PySequence_GetItem(points, loop);
|
|
|
293 result = TwoFloatsFromObj(item, &x, &y);
|
|
|
294 Py_DECREF(item);
|
|
|
295 if(!result) continue; /*note, we silently skip over bad points :[ */
|
|
|
296 ++drawn;
|
|
|
297 pts[0] = startx;
|
|
|
298 pts[1] = starty;
|
|
|
299 startx = pts[2] = x;
|
|
|
300 starty = pts[3] = y;
|
|
|
301 if(clip_and_draw_aaline(surf, &surf->clip_rect, color, pts, blend))
|
|
|
302 {
|
|
|
303 left = min((int)min(pts[0], pts[2]), left);
|
|
|
304 top = min((int)min(pts[1], pts[3]), top);
|
|
|
305 right = max((int)max(pts[0], pts[2]), right);
|
|
|
306 bottom = max((int)max(pts[1], pts[3]), bottom);
|
|
|
307 }
|
|
|
308 }
|
|
|
309 if(closed && drawn > 2)
|
|
|
310 {
|
|
|
311 item = PySequence_GetItem(points, 0);
|
|
|
312 result = TwoFloatsFromObj(item, &x, &y);
|
|
|
313 Py_DECREF(item);
|
|
|
314 if(result)
|
|
|
315 {
|
|
|
316 pts[0] = startx;
|
|
|
317 pts[1] = starty;
|
|
|
318 pts[2] = x;
|
|
|
319 pts[3] = y;
|
|
|
320 clip_and_draw_aaline(surf, &surf->clip_rect, color, pts, blend);
|
|
|
321 }
|
|
|
322 }
|
|
|
323
|
|
|
324 if(!PySurface_Unlock(surfobj)) return NULL;
|
|
|
325
|
|
|
326 /*compute return rect*/
|
|
|
327 return PyRect_New4((short)left, (short)top, (short)(right-left+2), (short)(bottom-top+2));
|
|
|
328 }
|
|
|
329
|
|
93
|
330 /*DOC*/ static char doc_lines[] =
|
|
176
|
331 /*DOC*/ "pygame.draw.lines(Surface, color, closed, point_array, width=1) -> Rect\n"
|
|
93
|
332 /*DOC*/ "draw multiple connected lines on a surface\n"
|
|
|
333 /*DOC*/ "\n"
|
|
|
334 /*DOC*/ "Draws a sequence on a surface. You must pass at least two points\n"
|
|
|
335 /*DOC*/ "in the sequence of points. The closed argument is a simple boolean\n"
|
|
|
336 /*DOC*/ "and if true, a line will be draw between the first and last points.\n"
|
|
176
|
337 /*DOC*/ "Note that specifying a linewidth wider than 1 does not fill in the\n"
|
|
|
338 /*DOC*/ "gaps between the lines. Therefore wide lines and sharp corners won't\n"
|
|
|
339 /*DOC*/ "be joined seamlessly.\n"
|
|
93
|
340 /*DOC*/ "\n"
|
|
244
|
341 /*DOC*/ "This will respect the clipping rectangle. A bounding box of the\n"
|
|
|
342 /*DOC*/ "effected area is returned as a rectangle.\n"
|
|
93
|
343 /*DOC*/ "\n"
|
|
96
|
344 /*DOC*/ "The color argument can be either a RGB sequence or mapped color integer.\n"
|
|
|
345 /*DOC*/ "\n"
|
|
93
|
346 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
347 /*DOC*/ ;
|
|
|
348
|
|
|
349 static PyObject* lines(PyObject* self, PyObject* arg)
|
|
|
350 {
|
|
|
351 PyObject *surfobj, *colorobj, *closedobj, *points, *item;
|
|
|
352 SDL_Surface* surf;
|
|
|
353 short x, y;
|
|
|
354 int top, left, bottom, right;
|
|
176
|
355 int pts[4], width=1;
|
|
93
|
356 Uint8 rgba[4];
|
|
|
357 Uint32 color;
|
|
|
358 int closed;
|
|
|
359 int result, loop, length, drawn;
|
|
186
|
360 int startx, starty;
|
|
93
|
361
|
|
|
362 /*get all the arguments*/
|
|
176
|
363 if(!PyArg_ParseTuple(arg, "O!OOO|i", &PySurface_Type, &surfobj, &colorobj, &closedobj, &points, &width))
|
|
93
|
364 return NULL;
|
|
|
365 surf = PySurface_AsSurface(surfobj);
|
|
|
366
|
|
|
367 if(surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
|
|
|
368 return RAISE(PyExc_ValueError, "unsupport bit depth for line draw");
|
|
|
369
|
|
96
|
370 if(PyInt_Check(colorobj))
|
|
|
371 color = (Uint32)PyInt_AsLong(colorobj);
|
|
|
372 else if(RGBAFromObj(colorobj, rgba))
|
|
|
373 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
374 else
|
|
|
375 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
93
|
376
|
|
|
377 closed = PyObject_IsTrue(closedobj);
|
|
|
378
|
|
|
379 if(!PySequence_Check(points))
|
|
|
380 return RAISE(PyExc_TypeError, "points argument must be a sequence of number pairs");
|
|
|
381 length = PySequence_Length(points);
|
|
|
382 if(length < 2)
|
|
|
383 return RAISE(PyExc_ValueError, "points argument must contain more than 1 points");
|
|
244
|
384
|
|
93
|
385 item = PySequence_GetItem(points, 0);
|
|
|
386 result = TwoShortsFromObj(item, &x, &y);
|
|
|
387 Py_DECREF(item);
|
|
|
388 if(!result) return RAISE(PyExc_TypeError, "points must be number pairs");
|
|
|
389
|
|
186
|
390 startx = pts[0] = left = right = x;
|
|
|
391 starty = pts[1] = top = bottom = y;
|
|
93
|
392
|
|
176
|
393 if(width < 1)
|
|
|
394 return PyRect_New4((short)left, (short)top, 0, 0);
|
|
|
395
|
|
93
|
396 if(!PySurface_Lock(surfobj)) return NULL;
|
|
|
397
|
|
|
398 drawn = 1;
|
|
|
399 for(loop = 1; loop < length; ++loop)
|
|
|
400 {
|
|
|
401 item = PySequence_GetItem(points, loop);
|
|
|
402 result = TwoShortsFromObj(item, &x, &y);
|
|
|
403 Py_DECREF(item);
|
|
|
404 if(!result) continue; /*note, we silently skip over bad points :[ */
|
|
|
405 ++drawn;
|
|
186
|
406 pts[0] = startx;
|
|
|
407 pts[1] = starty;
|
|
|
408 startx = pts[2] = x;
|
|
|
409 starty = pts[3] = y;
|
|
176
|
410 if(clip_and_draw_line_width(surf, &surf->clip_rect, color, width, pts))
|
|
93
|
411 {
|
|
|
412 left = min(min(pts[0], pts[2]), left);
|
|
|
413 top = min(min(pts[1], pts[3]), top);
|
|
|
414 right = max(max(pts[0], pts[2]), right);
|
|
|
415 bottom = max(max(pts[1], pts[3]), bottom);
|
|
|
416 }
|
|
|
417 }
|
|
|
418 if(closed && drawn > 2)
|
|
|
419 {
|
|
|
420 item = PySequence_GetItem(points, 0);
|
|
|
421 result = TwoShortsFromObj(item, &x, &y);
|
|
|
422 Py_DECREF(item);
|
|
|
423 if(result)
|
|
|
424 {
|
|
186
|
425 pts[0] = startx;
|
|
|
426 pts[1] = starty;
|
|
93
|
427 pts[2] = x;
|
|
|
428 pts[3] = y;
|
|
176
|
429 clip_and_draw_line_width(surf, &surf->clip_rect, color, width, pts);
|
|
93
|
430 }
|
|
|
431 }
|
|
|
432
|
|
|
433
|
|
|
434 if(!PySurface_Unlock(surfobj)) return NULL;
|
|
|
435
|
|
|
436 /*compute return rect*/
|
|
110
|
437 return PyRect_New4((short)left, (short)top, (short)(right-left+1), (short)(bottom-top+1));
|
|
93
|
438 }
|
|
|
439
|
|
|
440
|
|
225
|
441 /*DOC*/ static char doc_ellipse[] =
|
|
349
|
442 /*DOC*/ "pygame.draw.ellipse(Surface, color, Rect, width=0) -> Rect\n"
|
|
225
|
443 /*DOC*/ "draw an ellipse on a surface\n"
|
|
|
444 /*DOC*/ "\n"
|
|
257
|
445 /*DOC*/ "Draws an elliptical shape on the Surface. The given rectangle\n"
|
|
225
|
446 /*DOC*/ "is the area that the circle will fill. The width argument is\n"
|
|
|
447 /*DOC*/ "the thickness to draw the outer edge. If width is zero then\n"
|
|
|
448 /*DOC*/ "the ellipse will be filled.\n"
|
|
|
449 /*DOC*/ "\n"
|
|
|
450 /*DOC*/ "The color argument can be either a RGB sequence or mapped color integer.\n"
|
|
|
451 /*DOC*/ "\n"
|
|
|
452 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
453 /*DOC*/ ;
|
|
|
454
|
|
|
455 static PyObject* ellipse(PyObject* self, PyObject* arg)
|
|
|
456 {
|
|
|
457 PyObject *surfobj, *colorobj, *rectobj;
|
|
|
458 GAME_Rect *rect, temp;
|
|
|
459 SDL_Surface* surf;
|
|
|
460 Uint8 rgba[4];
|
|
|
461 Uint32 color;
|
|
349
|
462 int width=0, loop, t, l, b, r;
|
|
225
|
463
|
|
|
464 /*get all the arguments*/
|
|
349
|
465 if(!PyArg_ParseTuple(arg, "O!OO|i", &PySurface_Type, &surfobj, &colorobj, &rectobj, &width))
|
|
225
|
466 return NULL;
|
|
|
467 rect = GameRect_FromObject(rectobj, &temp);
|
|
|
468 if(!rect)
|
|
|
469 return RAISE(PyExc_TypeError, "Invalid recstyle argument");
|
|
|
470
|
|
|
471 surf = PySurface_AsSurface(surfobj);
|
|
|
472 if(surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
|
|
|
473 return RAISE(PyExc_ValueError, "unsupport bit depth for drawing");
|
|
|
474
|
|
|
475 if(PyInt_Check(colorobj))
|
|
|
476 color = (Uint32)PyInt_AsLong(colorobj);
|
|
|
477 else if(RGBAFromObj(colorobj, rgba))
|
|
|
478 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
479 else
|
|
|
480 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
|
481
|
|
257
|
482 if ( width < 0 )
|
|
|
483 return RAISE(PyExc_ValueError, "negative width");
|
|
|
484 if ( width > rect->w / 2 || width > rect->h / 2 )
|
|
|
485 return RAISE(PyExc_ValueError, "width greater than ellipse radius");
|
|
225
|
486
|
|
|
487 if(!PySurface_Lock(surfobj)) return NULL;
|
|
|
488
|
|
|
489 if(!width)
|
|
256
|
490 draw_fillellipse(surf, (Sint16)(rect->x+rect->w/2), (Sint16)(rect->y+rect->h/2),
|
|
225
|
491 (Sint16)(rect->w/2), (Sint16)(rect->h/2), color);
|
|
|
492 else
|
|
|
493 {
|
|
|
494 width = min(width, min(rect->w, rect->h) / 2);
|
|
|
495 for(loop=0; loop<width; ++loop)
|
|
|
496 {
|
|
256
|
497 draw_ellipse(surf, rect->x+rect->w/2, rect->y+rect->h/2,
|
|
225
|
498 rect->w/2-loop, rect->h/2-loop, color);
|
|
|
499 }
|
|
|
500 }
|
|
|
501
|
|
|
502 if(!PySurface_Unlock(surfobj)) return NULL;
|
|
|
503
|
|
256
|
504 l = max(rect->x, surf->clip_rect.x);
|
|
|
505 t = max(rect->y, surf->clip_rect.y);
|
|
|
506 r = min(rect->x + rect->w, surf->clip_rect.x + surf->clip_rect.w);
|
|
|
507 b = min(rect->y + rect->h, surf->clip_rect.y + surf->clip_rect.h);
|
|
|
508 return PyRect_New4((short)l, (short)t, (short)max(r-l, 0), (short)max(b-t, 0));
|
|
225
|
509 }
|
|
|
510
|
|
|
511
|
|
|
512
|
|
244
|
513 /*DOC*/ static char doc_circle[] =
|
|
349
|
514 /*DOC*/ "pygame.draw.circle(Surface, color, pos, radius, width=0) -> Rect\n"
|
|
244
|
515 /*DOC*/ "draw a circle on a surface\n"
|
|
|
516 /*DOC*/ "\n"
|
|
|
517 /*DOC*/ "Draws a circular shape on the Surface. The given position\n"
|
|
|
518 /*DOC*/ "is the center of the circle, and radius is the size. The width\n"
|
|
|
519 /*DOC*/ "argument is the thickness to draw the outer edge. If width is\n"
|
|
257
|
520 /*DOC*/ "zero then the circle will be filled.\n"
|
|
244
|
521 /*DOC*/ "\n"
|
|
|
522 /*DOC*/ "The color argument can be either a RGB sequence or mapped color integer.\n"
|
|
|
523 /*DOC*/ "\n"
|
|
|
524 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
525 /*DOC*/ ;
|
|
|
526
|
|
|
527 static PyObject* circle(PyObject* self, PyObject* arg)
|
|
|
528 {
|
|
|
529 PyObject *surfobj, *colorobj;
|
|
|
530 SDL_Surface* surf;
|
|
|
531 Uint8 rgba[4];
|
|
|
532 Uint32 color;
|
|
256
|
533 int posx, posy, radius, t, l, b, r;
|
|
349
|
534 int width=0, loop;
|
|
244
|
535
|
|
|
536 /*get all the arguments*/
|
|
349
|
537 if(!PyArg_ParseTuple(arg, "O!O(ii)i|i", &PySurface_Type, &surfobj, &colorobj, &posx, &posy, &radius, &width))
|
|
244
|
538 return NULL;
|
|
|
539
|
|
|
540 surf = PySurface_AsSurface(surfobj);
|
|
|
541 if(surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
|
|
|
542 return RAISE(PyExc_ValueError, "unsupport bit depth for drawing");
|
|
|
543
|
|
|
544 if(PyInt_Check(colorobj))
|
|
|
545 color = (Uint32)PyInt_AsLong(colorobj);
|
|
|
546 else if(RGBAFromObj(colorobj, rgba))
|
|
|
547 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
548 else
|
|
|
549 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
|
550
|
|
257
|
551 if ( radius < 0 )
|
|
|
552 return RAISE(PyExc_ValueError, "negative radius");
|
|
|
553 if ( width < 0 )
|
|
|
554 return RAISE(PyExc_ValueError, "negative width");
|
|
|
555 if ( width > radius )
|
|
|
556 return RAISE(PyExc_ValueError, "width greater than radius");
|
|
|
557
|
|
244
|
558
|
|
|
559 if(!PySurface_Lock(surfobj)) return NULL;
|
|
|
560
|
|
|
561 if(!width)
|
|
256
|
562 draw_fillellipse(surf, (Sint16)posx, (Sint16)posy, (Sint16)radius, (Sint16)radius, color);
|
|
244
|
563 else
|
|
|
564 for(loop=0; loop<width; ++loop)
|
|
256
|
565 draw_ellipse(surf, posx, posy, radius-loop, radius-loop, color);
|
|
244
|
566
|
|
|
567 if(!PySurface_Unlock(surfobj)) return NULL;
|
|
|
568
|
|
256
|
569 l = max(posx - radius, surf->clip_rect.x);
|
|
|
570 t = max(posy - radius, surf->clip_rect.y);
|
|
|
571 r = min(posx + radius, surf->clip_rect.x + surf->clip_rect.w);
|
|
|
572 b = min(posy + radius, surf->clip_rect.y + surf->clip_rect.h);
|
|
|
573 return PyRect_New4((short)l, (short)t, (short)max(r-l, 0), (short)max(b-t, 0));
|
|
244
|
574 }
|
|
|
575
|
|
|
576
|
|
|
577
|
|
|
578
|
|
225
|
579 /*DOC*/ static char doc_polygon[] =
|
|
349
|
580 /*DOC*/ "pygame.draw.polygon(Surface, color, pointslist, width=0) -> Rect\n"
|
|
226
|
581 /*DOC*/ "draws a polygon on a surface\n"
|
|
225
|
582 /*DOC*/ "\n"
|
|
226
|
583 /*DOC*/ "Draws a polygonal shape on the Surface. The given pointlist\n"
|
|
|
584 /*DOC*/ "is the vertices of the polygon. The width argument is\n"
|
|
|
585 /*DOC*/ "the thickness to draw the outer edge. If width is zero then\n"
|
|
257
|
586 /*DOC*/ "the polygon will be filled.\n"
|
|
225
|
587 /*DOC*/ "\n"
|
|
|
588 /*DOC*/ "The color argument can be either a RGB sequence or mapped color integer.\n"
|
|
|
589 /*DOC*/ "\n"
|
|
|
590 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
591 /*DOC*/ ;
|
|
|
592
|
|
|
593 static PyObject* polygon(PyObject* self, PyObject* arg)
|
|
|
594 {
|
|
|
595 PyObject *surfobj, *colorobj, *points, *item;
|
|
|
596 SDL_Surface* surf;
|
|
|
597 Uint8 rgba[4];
|
|
|
598 Uint32 color;
|
|
349
|
599 int width=0, length, loop, numpoints;
|
|
225
|
600 int *xlist, *ylist;
|
|
|
601 short x, y, top, left, bottom, right, result;
|
|
|
602
|
|
|
603 /*get all the arguments*/
|
|
349
|
604 if(!PyArg_ParseTuple(arg, "O!OO|i", &PySurface_Type, &surfobj, &colorobj, &points, &width))
|
|
225
|
605 return NULL;
|
|
|
606
|
|
|
607
|
|
|
608 if(width)
|
|
|
609 {
|
|
|
610 PyObject *args, *ret;
|
|
|
611 args = Py_BuildValue("(OOiOi)", surfobj, colorobj, 1, points, width);
|
|
|
612 if(!args) return NULL;
|
|
|
613 ret = lines(NULL, args);
|
|
|
614 Py_DECREF(args);
|
|
|
615 return ret;
|
|
|
616 }
|
|
244
|
617
|
|
257
|
618
|
|
225
|
619 surf = PySurface_AsSurface(surfobj);
|
|
|
620
|
|
|
621 if(surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
|
|
|
622 return RAISE(PyExc_ValueError, "unsupport bit depth for line draw");
|
|
|
623
|
|
|
624 if(PyInt_Check(colorobj))
|
|
|
625 color = (Uint32)PyInt_AsLong(colorobj);
|
|
|
626 else if(RGBAFromObj(colorobj, rgba))
|
|
|
627 color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
|
628 else
|
|
|
629 return RAISE(PyExc_TypeError, "invalid color argument");
|
|
|
630
|
|
|
631 if(!PySequence_Check(points))
|
|
|
632 return RAISE(PyExc_TypeError, "points argument must be a sequence of number pairs");
|
|
|
633 length = PySequence_Length(points);
|
|
|
634 if(length < 3)
|
|
|
635 return RAISE(PyExc_ValueError, "points argument must contain more than 2 points");
|
|
|
636
|
|
|
637
|
|
|
638 item = PySequence_GetItem(points, 0);
|
|
|
639 result = TwoShortsFromObj(item, &x, &y);
|
|
|
640 Py_DECREF(item);
|
|
|
641 if(!result) return RAISE(PyExc_TypeError, "points must be number pairs");
|
|
|
642 left = right = x;
|
|
|
643 top = bottom = y;
|
|
|
644
|
|
|
645 xlist = PyMem_New(int, length);
|
|
|
646 ylist = PyMem_New(int, length);
|
|
|
647
|
|
|
648 numpoints = 0;
|
|
|
649 for(loop = 0; loop < length; ++loop)
|
|
|
650 {
|
|
|
651 item = PySequence_GetItem(points, loop);
|
|
|
652 result = TwoShortsFromObj(item, &x, &y);
|
|
|
653 Py_DECREF(item);
|
|
|
654 if(!result) continue; /*note, we silently skip over bad points :[ */
|
|
|
655 xlist[numpoints] = x;
|
|
|
656 ylist[numpoints] = y;
|
|
|
657 ++numpoints;
|
|
|
658 left = min(x, left);
|
|
|
659 top = min(y, top);
|
|
|
660 right = max(x, right);
|
|
|
661 bottom = max(y, bottom);
|
|
|
662 }
|
|
|
663
|
|
|
664 if(!PySurface_Lock(surfobj))
|
|
|
665 {
|
|
|
666 PyMem_Del(xlist); PyMem_Del(ylist);
|
|
|
667 return NULL;
|
|
|
668 }
|
|
|
669
|
|
256
|
670 draw_fillpoly(surf, xlist, ylist, numpoints, color);
|
|
225
|
671
|
|
|
672 PyMem_Del(xlist); PyMem_Del(ylist);
|
|
|
673 if(!PySurface_Unlock(surfobj))
|
|
|
674 return NULL;
|
|
|
675
|
|
|
676 left = max(left, surf->clip_rect.x);
|
|
|
677 top = max(top, surf->clip_rect.y);
|
|
|
678 right = min(right, surf->clip_rect.x + surf->clip_rect.w);
|
|
|
679 bottom = min(bottom, surf->clip_rect.y + surf->clip_rect.h);
|
|
|
680 return PyRect_New4(left, top, (short)(right-left+1), (short)(bottom-top+1));
|
|
|
681 }
|
|
|
682
|
|
|
683
|
|
244
|
684 /*DOC*/ static char doc_rect[] =
|
|
349
|
685 /*DOC*/ "pygame.draw.rect(Surface, color, Rect, width=0) -> Rect\n"
|
|
317
|
686 /*DOC*/ "draws a rectangle on a surface\n"
|
|
244
|
687 /*DOC*/ "\n"
|
|
257
|
688 /*DOC*/ "Draws a rectangular shape on the Surface. The given Rect\n"
|
|
244
|
689 /*DOC*/ "is the area of the rectangle. The width argument is\n"
|
|
|
690 /*DOC*/ "the thickness to draw the outer edge. If width is zero then\n"
|
|
257
|
691 /*DOC*/ "the rectangle will be filled.\n"
|
|
244
|
692 /*DOC*/ "\n"
|
|
|
693 /*DOC*/ "The color argument can be either a RGB sequence or mapped color integer.\n"
|
|
|
694 /*DOC*/ "\n"
|
|
|
695 /*DOC*/ "This function will temporarily lock the surface.\n"
|
|
|
696 /*DOC*/ "\n"
|
|
|
697 /*DOC*/ "Keep in mind the Surface.fill() method works just as well\n"
|
|
|
698 /*DOC*/ "for drawing filled rectangles. In fact the Surface.fill()\n"
|
|
|
699 /*DOC*/ "can be hardware accelerated when the moons are in alignement.\n"
|
|
|
700 /*DOC*/ ;
|
|
|
701
|
|
|
702 static PyObject* rect(PyObject* self, PyObject* arg)
|
|
|
703 {
|
|
|
704 PyObject *surfobj, *colorobj, *rectobj, *points, *args, *ret=NULL;
|
|
|
705 GAME_Rect* rect, temp;
|
|
349
|
706 int t, l, b, r, width=0;
|
|
244
|
707
|
|
|
708 /*get all the arguments*/
|
|
349
|
709 if(!PyArg_ParseTuple(arg, "O!OO|i", &PySurface_Type, &surfobj, &colorobj, &rectobj, &width))
|
|
244
|
710 return NULL;
|
|
|
711
|
|
|
712 if(!(rect = GameRect_FromObject(rectobj, &temp)))
|
|
|
713 return RAISE(PyExc_TypeError, "Rect argument is invalid");
|
|
|
714
|
|
339
|
715 l = rect->x; r = rect->x + rect->w - 1;
|
|
|
716 t = rect->y; b = rect->y + rect->h - 1;
|
|
244
|
717
|
|
|
718 /*build the pointlist*/
|
|
|
719 points = Py_BuildValue("((ii)(ii)(ii)(ii))", l, t, r, t, r, b, l, b);
|
|
|
720
|
|
|
721 args = Py_BuildValue("(OOOi)", surfobj, colorobj, points, width);
|
|
|
722 if(args) ret = polygon(NULL, args);
|
|
|
723
|
|
|
724 Py_XDECREF(args);
|
|
|
725 Py_XDECREF(points);
|
|
|
726 return ret;
|
|
|
727 }
|
|
225
|
728
|
|
|
729
|
|
93
|
730
|
|
|
731
|
|
|
732 /*internal drawing tools*/
|
|
|
733
|
|
442
|
734 static int clip_and_draw_aaline(SDL_Surface* surf, SDL_Rect* rect, Uint32 color, float* pts, int blend)
|
|
|
735 {
|
|
|
736 if(!clipaaline(pts, rect->x+1, rect->y+1, rect->x+rect->w-2, rect->y+rect->h-2))
|
|
|
737 return 0;
|
|
|
738 drawaaline(surf, color, pts[0], pts[1], pts[2], pts[3], blend);
|
|
|
739 return 1;
|
|
|
740 }
|
|
|
741
|
|
93
|
742 static int clip_and_draw_line(SDL_Surface* surf, SDL_Rect* rect, Uint32 color, int* pts)
|
|
|
743 {
|
|
|
744 if(!clipline(pts, rect->x, rect->y, rect->x+rect->w-1, rect->y+rect->h-1))
|
|
|
745 return 0;
|
|
|
746 if(pts[1] == pts[3])
|
|
|
747 drawhorzline(surf, color, pts[0], pts[1], pts[2]);
|
|
257
|
748 else if(pts[0] == pts[2])
|
|
|
749 drawvertline(surf, color, pts[0], pts[1], pts[3]);
|
|
93
|
750 else
|
|
|
751 drawline(surf, color, pts[0], pts[1], pts[2], pts[3]);
|
|
|
752 return 1;
|
|
|
753 }
|
|
85
|
754
|
|
176
|
755 static int clip_and_draw_line_width(SDL_Surface* surf, SDL_Rect* rect, Uint32 color, int width, int* pts)
|
|
|
756 {
|
|
|
757 int loop;
|
|
|
758 int xinc=0, yinc=0;
|
|
|
759 int newpts[4];
|
|
|
760 int range[4];
|
|
|
761 int anydrawn = 0;
|
|
|
762
|
|
|
763 if(abs(pts[0]-pts[2]) > abs(pts[1]-pts[3]))
|
|
|
764 yinc = 1;
|
|
|
765 else
|
|
|
766 xinc = 1;
|
|
|
767
|
|
|
768 memcpy(newpts, pts, sizeof(int)*4);
|
|
|
769 if(clip_and_draw_line(surf, rect, color, newpts))
|
|
|
770 {
|
|
|
771 anydrawn = 1;
|
|
|
772 memcpy(range, newpts, sizeof(int)*4);
|
|
|
773 }
|
|
|
774 else
|
|
|
775 {
|
|
|
776 range[0] = range[1] = 10000;
|
|
|
777 range[2] = range[3] = -10000;
|
|
|
778 }
|
|
|
779
|
|
186
|
780 for(loop = 1; loop < width; loop += 2)
|
|
176
|
781 {
|
|
|
782 newpts[0] = pts[0] + xinc*(loop/2+1);
|
|
|
783 newpts[1] = pts[1] + yinc*(loop/2+1);
|
|
|
784 newpts[2] = pts[2] + xinc*(loop/2+1);
|
|
|
785 newpts[3] = pts[3] + yinc*(loop/2+1);
|
|
|
786 if(clip_and_draw_line(surf, rect, color, newpts))
|
|
|
787 {
|
|
|
788 anydrawn = 1;
|
|
|
789 range[0] = min(newpts[0], range[0]);
|
|
|
790 range[1] = min(newpts[1], range[1]);
|
|
|
791 range[2] = max(newpts[2], range[2]);
|
|
|
792 range[3] = max(newpts[3], range[3]);
|
|
|
793 }
|
|
|
794 if(loop+1<width)
|
|
|
795 {
|
|
225
|
796 newpts[0] = pts[0] - xinc*(loop/2+1);
|
|
|
797 newpts[1] = pts[1] - yinc*(loop/2+1);
|
|
|
798 newpts[2] = pts[2] - xinc*(loop/2+1);
|
|
|
799 newpts[3] = pts[3] - yinc*(loop/2+1);
|
|
176
|
800 if(clip_and_draw_line(surf, rect, color, newpts))
|
|
|
801 {
|
|
|
802 anydrawn = 1;
|
|
|
803 range[0] = min(newpts[0], range[0]);
|
|
|
804 range[1] = min(newpts[1], range[1]);
|
|
|
805 range[2] = max(newpts[2], range[2]);
|
|
|
806 range[3] = max(newpts[3], range[3]);
|
|
|
807 }
|
|
|
808 }
|
|
|
809 }
|
|
|
810 if(anydrawn)
|
|
|
811 memcpy(pts, range, sizeof(int)*4);
|
|
|
812 return anydrawn;
|
|
|
813 }
|
|
|
814
|
|
85
|
815
|
|
|
816 /*this line clipping based heavily off of code from
|
|
|
817 http://www.ncsa.uiuc.edu/Vis/Graphics/src/clipCohSuth.c */
|
|
|
818 #define LEFT_EDGE 0x1
|
|
|
819 #define RIGHT_EDGE 0x2
|
|
|
820 #define BOTTOM_EDGE 0x4
|
|
|
821 #define TOP_EDGE 0x8
|
|
|
822 #define INSIDE(a) (!a)
|
|
|
823 #define REJECT(a,b) (a&b)
|
|
|
824 #define ACCEPT(a,b) (!(a|b))
|
|
|
825
|
|
|
826 static int encode(int x, int y, int left, int top, int right, int bottom)
|
|
|
827 {
|
|
|
828 int code = 0;
|
|
|
829 if(x < left) code |= LEFT_EDGE;
|
|
|
830 if(x > right) code |= RIGHT_EDGE;
|
|
|
831 if(y < top) code |= TOP_EDGE;
|
|
|
832 if(y > bottom)code |= BOTTOM_EDGE;
|
|
|
833 return code;
|
|
|
834 }
|
|
|
835
|
|
442
|
836 static int encodeFloat(float x, float y, int left, int top, int right, int bottom)
|
|
|
837 {
|
|
|
838 int code = 0;
|
|
|
839 if(x < left) code |= LEFT_EDGE;
|
|
|
840 if(x > right) code |= RIGHT_EDGE;
|
|
|
841 if(y < top) code |= TOP_EDGE;
|
|
|
842 if(y > bottom)code |= BOTTOM_EDGE;
|
|
|
843 return code;
|
|
|
844 }
|
|
|
845
|
|
|
846 static int clipaaline(float* pts, int left, int top, int right, int bottom)
|
|
|
847 {
|
|
|
848 float x1 = pts[0];
|
|
|
849 float y1 = pts[1];
|
|
|
850 float x2 = pts[2];
|
|
|
851 float y2 = pts[3];
|
|
|
852 int code1, code2;
|
|
|
853 int draw = 0;
|
|
|
854 float swaptmp;
|
|
|
855 int intswaptmp;
|
|
|
856 float m; /*slope*/
|
|
|
857
|
|
|
858 while(1) {
|
|
|
859 code1 = encodeFloat(x1, y1, left, top, right, bottom);
|
|
|
860 code2 = encodeFloat(x2, y2, left, top, right, bottom);
|
|
|
861 if(ACCEPT(code1, code2)) {
|
|
|
862 draw = 1;
|
|
|
863 break;
|
|
|
864 }
|
|
|
865 else if(REJECT(code1, code2)) {
|
|
|
866 break;
|
|
|
867 }
|
|
|
868 else {
|
|
|
869 if(INSIDE(code1)) {
|
|
|
870 swaptmp = x2; x2 = x1; x1 = swaptmp;
|
|
|
871 swaptmp = y2; y2 = y1; y1 = swaptmp;
|
|
|
872 intswaptmp = code2; code2 = code1; code1 = intswaptmp;
|
|
|
873 }
|
|
|
874 if(x2 != x1)
|
|
|
875 m = (y2 - y1) / (x2 - x1);
|
|
|
876 else
|
|
|
877 m = 1.0f;
|
|
|
878 if(code1 & LEFT_EDGE) {
|
|
|
879 y1 += ((float)left - x1) * m;
|
|
|
880 x1 = (float)left;
|
|
|
881 }
|
|
|
882 else if(code1 & RIGHT_EDGE) {
|
|
|
883 y1 += ((float)right - x1) * m;
|
|
|
884 x1 = (float)right;
|
|
|
885 }
|
|
|
886 else if(code1 & BOTTOM_EDGE) {
|
|
|
887 if(x2 != x1)
|
|
|
888 x1 += ((float)bottom - y1) / m;
|
|
|
889 y1 = (float)bottom;
|
|
|
890 }
|
|
|
891 else if(code1 & TOP_EDGE) {
|
|
|
892 if(x2 != x1)
|
|
|
893 x1 += ((float)top - y1) / m;
|
|
|
894 y1 = (float)top;
|
|
|
895 }
|
|
|
896 }
|
|
|
897 }
|
|
|
898 if(draw) {
|
|
|
899 pts[0] = x1; pts[1] = y1;
|
|
|
900 pts[2] = x2; pts[3] = y2;
|
|
|
901 }
|
|
|
902 return draw;
|
|
|
903 }
|
|
|
904
|
|
85
|
905 static int clipline(int* pts, int left, int top, int right, int bottom)
|
|
|
906 {
|
|
|
907 int x1 = pts[0];
|
|
|
908 int y1 = pts[1];
|
|
|
909 int x2 = pts[2];
|
|
|
910 int y2 = pts[3];
|
|
|
911 int code1, code2;
|
|
|
912 int draw = 0;
|
|
|
913 int swaptmp;
|
|
|
914 float m; /*slope*/
|
|
|
915
|
|
|
916 while(1)
|
|
|
917 {
|
|
|
918 code1 = encode(x1, y1, left, top, right, bottom);
|
|
|
919 code2 = encode(x2, y2, left, top, right, bottom);
|
|
|
920 if(ACCEPT(code1, code2)) {
|
|
|
921 draw = 1;
|
|
|
922 break;
|
|
|
923 }
|
|
|
924 else if(REJECT(code1, code2))
|
|
|
925 break;
|
|
|
926 else {
|
|
|
927 if(INSIDE(code1)) {
|
|
|
928 swaptmp = x2; x2 = x1; x1 = swaptmp;
|
|
|
929 swaptmp = y2; y2 = y1; y1 = swaptmp;
|
|
|
930 swaptmp = code2; code2 = code1; code1 = swaptmp;
|
|
|
931 }
|
|
238
|
932 if(x2 != x1)
|
|
85
|
933 m = (y2 - y1) / (float)(x2 - x1);
|
|
99
|
934 else
|
|
|
935 m = 1.0f;
|
|
85
|
936 if(code1 & LEFT_EDGE) {
|
|
|
937 y1 += (int)((left - x1) * m);
|
|
|
938 x1 = left;
|
|
|
939 }
|
|
|
940 else if(code1 & RIGHT_EDGE) {
|
|
|
941 y1 += (int)((right - x1) * m);
|
|
|
942 x1 = right;
|
|
|
943 }
|
|
|
944 else if(code1 & BOTTOM_EDGE) {
|
|
|
945 if(x2 != x1)
|
|
|
946 x1 += (int)((bottom - y1) / m);
|
|
|
947 y1 = bottom;
|
|
|
948 }
|
|
|
949 else if(code1 & TOP_EDGE) {
|
|
|
950 if(x2 != x1)
|
|
|
951 x1 += (int)((top - y1) / m);
|
|
|
952 y1 = top;
|
|
|
953 }
|
|
|
954 }
|
|
|
955 }
|
|
|
956 if(draw) {
|
|
|
957 pts[0] = x1; pts[1] = y1;
|
|
|
958 pts[2] = x2; pts[3] = y2;
|
|
|
959 }
|
|
|
960 return draw;
|
|
|
961 }
|
|
|
962
|
|
|
963
|
|
|
964
|
|
257
|
965 static int set_at(SDL_Surface* surf, int x, int y, Uint32 color)
|
|
|
966 {
|
|
|
967 SDL_PixelFormat* format = surf->format;
|
|
|
968 Uint8* pixels = (Uint8*)surf->pixels;
|
|
|
969 Uint8* byte_buf, rgb[4];
|
|
|
970
|
|
|
971 if(x < surf->clip_rect.x || x >= surf->clip_rect.x + surf->clip_rect.w ||
|
|
|
972 y < surf->clip_rect.y || y >= surf->clip_rect.y + surf->clip_rect.h)
|
|
|
973 return 0;
|
|
|
974
|
|
|
975 switch(format->BytesPerPixel)
|
|
|
976 {
|
|
|
977 case 1:
|
|
|
978 *((Uint8*)pixels + y * surf->pitch + x) = (Uint8)color;
|
|
|
979 break;
|
|
|
980 case 2:
|
|
|
981 *((Uint16*)(pixels + y * surf->pitch) + x) = (Uint16)color;
|
|
|
982 break;
|
|
|
983 case 4:
|
|
|
984 *((Uint32*)(pixels + y * surf->pitch) + x) = color;
|
|
|
985 /* *((Uint32*)(pixels + y * surf->pitch) + x) =
|
|
|
986 ~(*((Uint32*)(pixels + y * surf->pitch) + x)) * 31;
|
|
|
987 */ break;
|
|
|
988 default:/*case 3:*/
|
|
|
989 SDL_GetRGB(color, format, rgb, rgb+1, rgb+2);
|
|
|
990 byte_buf = (Uint8*)(pixels + y * surf->pitch) + x * 3;
|
|
|
991 *(byte_buf + (format->Rshift >> 3)) = rgb[0];
|
|
|
992 *(byte_buf + (format->Gshift >> 3)) = rgb[1];
|
|
|
993 *(byte_buf + (format->Bshift >> 3)) = rgb[2];
|
|
|
994 break;
|
|
|
995 }
|
|
|
996 return 1;
|
|
|
997 }
|
|
|
998
|
|
85
|
999
|
|
442
|
1000 #define DRAWPIX32(pixel,colorptr,br,blend) \
|
|
|
1001 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) color <<= 8; \
|
|
|
1002 if(blend) { \
|
|
|
1003 short x; \
|
|
|
1004 x = colorptr[0]*br+pixel[0]; \
|
|
|
1005 pixel[0]= (x>254) ? 255: x; \
|
|
|
1006 x = colorptr[1]*br+pixel[1]; \
|
|
|
1007 pixel[1]= (x>254) ? 255: x; \
|
|
|
1008 x = colorptr[2]*br+pixel[2]; \
|
|
|
1009 pixel[2]= (x>254) ? 255: x; \
|
|
|
1010 } else { \
|
|
|
1011 pixel[0]=(Uint8)(colorptr[0]*br); \
|
|
|
1012 pixel[1]=(Uint8)(colorptr[1]*br); \
|
|
|
1013 pixel[2]=(Uint8)(colorptr[2]*br); \
|
|
|
1014 }
|
|
|
1015
|
|
|
1016 /* Adapted from http://freespace.virgin.net/hugo.elias/graphics/x_wuline.htm */
|
|
|
1017 static void drawaaline(SDL_Surface* surf, Uint32 color, float x1, float y1, float x2, float y2, int blend) {
|
|
|
1018 float grad, xd, yd;
|
|
|
1019 float xgap, ygap, xend, yend, xf, yf;
|
|
|
1020 float brightness1, brightness2;
|
|
|
1021 float swaptmp;
|
|
|
1022 int x, y, ix1, ix2, iy1, iy2;
|
|
|
1023 int pixx, pixy;
|
|
|
1024 Uint8* pixel;
|
|
|
1025 Uint8* pm = (Uint8*)surf->pixels;
|
|
|
1026 Uint8* colorptr = (Uint8*)&color;
|
|
|
1027
|
|
|
1028 pixx = surf->format->BytesPerPixel;
|
|
|
1029 pixy = surf->pitch;
|
|
|
1030
|
|
|
1031 xd = x2-x1;
|
|
|
1032 yd = y2-y1;
|
|
|
1033 if(fabs(xd)>fabs(yd)) {
|
|
|
1034 if(x1>x2) {
|
|
|
1035 swaptmp=x1; x1=x2; x2=swaptmp;
|
|
|
1036 swaptmp=y1; y1=y2; y2=swaptmp;
|
|
|
1037 xd = (x2-x1);
|
|
|
1038 yd = (y2-y1);
|
|
|
1039 }
|
|
|
1040 grad = yd/xd;
|
|
|
1041 xend = trunc(x1)+0.5; /* This makes more sense than trunc(x1+0.5) */
|
|
|
1042 yend = y1+grad*(xend-x1);
|
|
|
1043 xgap = INVFRAC(x1);
|
|
|
1044 ix1 = (int)xend;
|
|
|
1045 iy1 = (int)yend;
|
|
|
1046 yf = yend+grad;
|
|
|
1047 brightness1 = INVFRAC(yend) * xgap;
|
|
|
1048 brightness2 = FRAC(yend) * xgap;
|
|
|
1049 pixel = pm + pixx * ix1 + pixy * iy1;
|
|
|
1050 DRAWPIX32(pixel, colorptr, brightness1, blend)
|
|
|
1051 pixel += pixy;
|
|
|
1052 DRAWPIX32(pixel, colorptr, brightness2, blend)
|
|
|
1053 xend = trunc(x2)+0.5;
|
|
|
1054 yend = y2+grad*(xend-x2);
|
|
|
1055 xgap = FRAC(x2); /* this also differs from Hugo's description. */
|
|
|
1056 ix2 = (int)xend;
|
|
|
1057 iy2 = (int)yend;
|
|
|
1058 brightness1 = INVFRAC(yend) * xgap;
|
|
|
1059 brightness2 = FRAC(yend) * xgap;
|
|
|
1060 pixel = pm + pixx * ix2 + pixy * iy2;
|
|
|
1061 DRAWPIX32(pixel, colorptr, brightness1, blend)
|
|
|
1062 pixel += pixy;
|
|
|
1063 DRAWPIX32(pixel, colorptr, brightness2, blend)
|
|
|
1064 for(x=ix1+1; x<ix2; ++x) {
|
|
|
1065 brightness1=INVFRAC(yf);
|
|
|
1066 brightness2= FRAC(yf);
|
|
|
1067 pixel = pm + pixx * x + pixy * (int)yf;
|
|
|
1068 DRAWPIX32(pixel, colorptr, brightness1, blend)
|
|
|
1069 pixel += pixy;
|
|
|
1070 DRAWPIX32(pixel, colorptr, brightness2, blend)
|
|
|
1071 yf += grad;
|
|
|
1072 }
|
|
|
1073 }
|
|
|
1074 else {
|
|
|
1075 if(y1>y2) {
|
|
|
1076 swaptmp=y1; y1=y2; y2=swaptmp;
|
|
|
1077 swaptmp=x1; x1=x2; x2=swaptmp;
|
|
|
1078 yd = (y2-y1);
|
|
|
1079 xd = (x2-x1);
|
|
|
1080 }
|
|
|
1081 grad = xd/yd;
|
|
|
1082 yend = trunc(y1)+0.5; /* This makes more sense than trunc(x1+0.5) */
|
|
|
1083 xend = x1+grad*(yend-y1);
|
|
|
1084 ygap = INVFRAC(y1);
|
|
|
1085 iy1 = (int)yend;
|
|
|
1086 ix1 = (int)xend;
|
|
|
1087 xf = xend+grad;
|
|
|
1088 brightness1 = INVFRAC(xend) * ygap;
|
|
|
1089 brightness2 = FRAC(xend) * ygap;
|
|
|
1090 pixel = pm + pixx * ix1 + pixy * iy1;
|
|
|
1091 DRAWPIX32(pixel, colorptr, brightness1, blend)
|
|
|
1092 pixel += pixx;
|
|
|
1093 DRAWPIX32(pixel, colorptr, brightness2, blend)
|
|
|
1094 yend = trunc(y2)+0.5;
|
|
|
1095 xend = x2+grad*(yend-y2);
|
|
|
1096 ygap = FRAC(y2);
|
|
|
1097 iy2 = (int)yend;
|
|
|
1098 ix2 = (int)xend;
|
|
|
1099 brightness1 = INVFRAC(xend) * ygap;
|
|
|
1100 brightness2 = FRAC(xend) * ygap;
|
|
|
1101 pixel = pm + pixx * ix2 + pixy * iy2;
|
|
|
1102 DRAWPIX32(pixel, colorptr, brightness1, blend)
|
|
|
1103 pixel += pixx;
|
|
|
1104 DRAWPIX32(pixel, colorptr, brightness2, blend)
|
|
|
1105 for(y=iy1+1; y<iy2; ++y) {
|
|
|
1106 brightness1=INVFRAC(xf);
|
|
|
1107 brightness2= FRAC(xf);
|
|
|
1108 pixel = pm + pixx * (int)xf + pixy * y;
|
|
|
1109 DRAWPIX32(pixel, colorptr, brightness1, blend)
|
|
|
1110 pixel += pixx;
|
|
|
1111 DRAWPIX32(pixel, colorptr, brightness2, blend)
|
|
|
1112 xf += grad;
|
|
|
1113 }
|
|
|
1114 }
|
|
|
1115 }
|
|
|
1116
|
|
|
1117
|
|
93
|
1118 /*here's my sdl'ized version of bresenham*/
|
|
85
|
1119 static void drawline(SDL_Surface* surf, Uint32 color, int x1, int y1, int x2, int y2)
|
|
|
1120 {
|
|
|
1121 int deltax, deltay, signx, signy;
|
|
|
1122 int pixx, pixy;
|
|
|
1123 int x = 0, y = 0;
|
|
|
1124 int swaptmp;
|
|
|
1125 Uint8 *pixel;
|
|
87
|
1126 Uint8 *colorptr;
|
|
85
|
1127
|
|
238
|
1128 deltax = x2 - x1;
|
|
|
1129 deltay = y2 - y1;
|
|
|
1130 signx = (deltax < 0) ? -1 : 1;
|
|
|
1131 signy = (deltay < 0) ? -1 : 1;
|
|
|
1132 deltax = signx * deltax + 1;
|
|
|
1133 deltay = signy * deltay + 1;
|
|
85
|
1134
|
|
|
1135 pixx = surf->format->BytesPerPixel;
|
|
|
1136 pixy = surf->pitch;
|
|
|
1137 pixel = ((Uint8*)surf->pixels) + pixx * x1 + pixy * y1;
|
|
|
1138
|
|
|
1139 pixx *= signx;
|
|
|
1140 pixy *= signy;
|
|
|
1141 if(deltax < deltay) /*swap axis if rise > run*/
|
|
|
1142 {
|
|
|
1143 swaptmp = deltax; deltax = deltay; deltay = swaptmp;
|
|
|
1144 swaptmp = pixx; pixx = pixy; pixy = swaptmp;
|
|
|
1145 }
|
|
|
1146
|
|
|
1147 switch(surf->format->BytesPerPixel)
|
|
|
1148 {
|
|
|
1149 case 1:
|
|
|
1150 for(; x < deltax; x++, pixel += pixx) {
|
|
|
1151 *pixel = (Uint8)color;
|
|
|
1152 y += deltay; if(y >= deltax) {y -= deltax; pixel += pixy;}
|
|
|
1153 }break;
|
|
|
1154 case 2:
|
|
|
1155 for(; x < deltax; x++, pixel += pixx) {
|
|
|
1156 *(Uint16*)pixel = (Uint16)color;
|
|
|
1157 y += deltay; if(y >= deltax) {y -= deltax; pixel += pixy;}
|
|
|
1158 }break;
|
|
|
1159 case 3:
|
|
87
|
1160 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) color <<= 8;
|
|
|
1161 colorptr = (Uint8*)&color;
|
|
85
|
1162 for(; x < deltax; x++, pixel += pixx) {
|
|
87
|
1163 pixel[0] = colorptr[0];
|
|
|
1164 pixel[1] = colorptr[1];
|
|
|
1165 pixel[2] = colorptr[2];
|
|
85
|
1166 y += deltay; if(y >= deltax) {y -= deltax; pixel += pixy;}
|
|
|
1167 }break;
|
|
|
1168 default: /*case 4*/
|
|
|
1169 for(; x < deltax; x++, pixel += pixx) {
|
|
442
|
1170 *(Uint32*)pixel = (Uint32)color;
|
|
85
|
1171 y += deltay; if(y >= deltax) {y -= deltax; pixel += pixy;}
|
|
|
1172 }break;
|
|
|
1173 }
|
|
|
1174 }
|
|
|
1175
|
|
|
1176
|
|
|
1177
|
|
93
|
1178 static void drawhorzline(SDL_Surface* surf, Uint32 color, int x1, int y1, int x2)
|
|
85
|
1179 {
|
|
|
1180 Uint8 *pixel, *end;
|
|
87
|
1181 Uint8 *colorptr;
|
|
85
|
1182
|
|
|
1183 if(x1 == x2) return;
|
|
|
1184
|
|
|
1185 pixel = ((Uint8*)surf->pixels) + surf->pitch * y1;
|
|
|
1186 if(x1 < x2)
|
|
|
1187 {
|
|
|
1188 end = pixel + x2 * surf->format->BytesPerPixel;
|
|
|
1189 pixel += x1 * surf->format->BytesPerPixel;
|
|
|
1190 }
|
|
|
1191 else
|
|
|
1192 {
|
|
|
1193 end = pixel + x1 * surf->format->BytesPerPixel;
|
|
|
1194 pixel += x2 * surf->format->BytesPerPixel;
|
|
|
1195 }
|
|
|
1196 switch(surf->format->BytesPerPixel)
|
|
|
1197 {
|
|
|
1198 case 1:
|
|
|
1199 for(; pixel <= end; ++pixel) {
|
|
|
1200 *pixel = (Uint8)color;
|
|
|
1201 }break;
|
|
|
1202 case 2:
|
|
110
|
1203 for(; pixel <= end; pixel+=2) {
|
|
85
|
1204 *(Uint16*)pixel = (Uint16)color;
|
|
|
1205 }break;
|
|
|
1206 case 3:
|
|
87
|
1207 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) color <<= 8;
|
|
|
1208 colorptr = (Uint8*)&color;
|
|
110
|
1209 for(; pixel <= end; pixel+=3) {
|
|
87
|
1210 pixel[0] = colorptr[0];
|
|
|
1211 pixel[1] = colorptr[1];
|
|
|
1212 pixel[2] = colorptr[2];
|
|
85
|
1213 }break;
|
|
|
1214 default: /*case 4*/
|
|
110
|
1215 for(; pixel <= end; pixel+=4) {
|
|
225
|
1216 *(Uint32*)pixel = color;
|
|
260
|
1217 }break;
|
|
85
|
1218 }
|
|
|
1219 }
|
|
|
1220
|
|
225
|
1221 static void drawhorzlineclip(SDL_Surface* surf, Uint32 color, int x1, int y1, int x2)
|
|
|
1222 {
|
|
257
|
1223 if(y1 < surf->clip_rect.y || y1 >= surf->clip_rect.y + surf->clip_rect.h)
|
|
|
1224 return;
|
|
|
1225
|
|
260
|
1226 if( x2 < x1 )
|
|
257
|
1227 {
|
|
260
|
1228 int temp = x1;
|
|
|
1229 x1 = x2; x2 = temp;
|
|
257
|
1230 }
|
|
|
1231
|
|
225
|
1232 x1 = max(x1, surf->clip_rect.x);
|
|
257
|
1233 x2 = min(x2, surf->clip_rect.x + surf->clip_rect.w-1);
|
|
260
|
1234
|
|
|
1235 if(x2 < surf->clip_rect.x || x1 >= surf->clip_rect.x + surf->clip_rect.w)
|
|
|
1236 return;
|
|
|
1237
|
|
257
|
1238 if(x1 == x2)
|
|
260
|
1239 set_at(surf, x1, y1, color);
|
|
257
|
1240 else
|
|
|
1241 drawhorzline(surf, color, x1, y1, x2);
|
|
|
1242 }
|
|
|
1243
|
|
|
1244 static void drawvertline(SDL_Surface* surf, Uint32 color, int x1, int y1, int y2)
|
|
|
1245 {
|
|
|
1246 Uint8 *pixel, *end;
|
|
|
1247 Uint8 *colorptr;
|
|
|
1248 Uint32 pitch = surf->pitch;
|
|
|
1249
|
|
|
1250 if(y1 == y2) return;
|
|
|
1251
|
|
|
1252 pixel = ((Uint8*)surf->pixels) + x1 * surf->format->BytesPerPixel;
|
|
|
1253 if(y1 < y2)
|
|
|
1254 {
|
|
|
1255 end = pixel + surf->pitch * y2;
|
|
|
1256 pixel += surf->pitch * y1;
|
|
|
1257 }
|
|
|
1258 else
|
|
|
1259 {
|
|
|
1260 end = pixel + surf->pitch * y1;
|
|
|
1261 pixel += surf->pitch * y2;
|
|
|
1262 }
|
|
|
1263
|
|
|
1264 switch(surf->format->BytesPerPixel)
|
|
|
1265 {
|
|
|
1266 case 1:
|
|
|
1267 for(; pixel <= end; pixel+=pitch) {
|
|
|
1268 *pixel = (Uint8)color;
|
|
|
1269 }break;
|
|
|
1270 case 2:
|
|
|
1271 for(; pixel <= end; pixel+=pitch) {
|
|
|
1272 *(Uint16*)pixel = (Uint16)color;
|
|
|
1273 }break;
|
|
|
1274 case 3:
|
|
|
1275 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) color <<= 8;
|
|
|
1276 colorptr = (Uint8*)&color;
|
|
|
1277 for(; pixel <= end; pixel+=pitch) {
|
|
|
1278 pixel[0] = colorptr[0];
|
|
|
1279 pixel[1] = colorptr[1];
|
|
|
1280 pixel[2] = colorptr[2];
|
|
|
1281 }break;
|
|
|
1282 default: /*case 4*/
|
|
|
1283 for(; pixel <= end; pixel+=pitch) {
|
|
|
1284 *(Uint32*)pixel = color;
|
|
|
1285 }break;
|
|
|
1286 }
|
|
225
|
1287 }
|
|
|
1288
|
|
|
1289
|
|
257
|
1290 static void drawvertlineclip(SDL_Surface* surf, Uint32 color, int x1, int y1, int y2)
|
|
225
|
1291 {
|
|
257
|
1292 if(x1 < surf->clip_rect.x || x1 >= surf->clip_rect.x + surf->clip_rect.w)
|
|
|
1293 return;
|
|
|
1294 if ( y2 < y1 )
|
|
225
|
1295 {
|
|
257
|
1296 int temp = y1;
|
|
|
1297 y1 = y2; y2 = temp;
|
|
225
|
1298 }
|
|
257
|
1299 y1 = max(y1, surf->clip_rect.y);
|
|
|
1300 y2 = min(y2, surf->clip_rect.y + surf->clip_rect.h-1);
|
|
|
1301 if(y2 - y1 < 1)
|
|
|
1302 set_at( surf, x1, y1, color);
|
|
|
1303 else
|
|
|
1304 drawvertline(surf, color, x1, y1, y2);
|
|
225
|
1305 }
|
|
|
1306
|
|
256
|
1307 static void draw_ellipse(SDL_Surface *dst, int x, int y, int rx, int ry, Uint32 color)
|
|
225
|
1308 {
|
|
|
1309 int ix, iy;
|
|
|
1310 int h, i, j, k;
|
|
|
1311 int oh, oi, oj, ok;
|
|
|
1312 int xmh, xph, ypk, ymk;
|
|
|
1313 int xmi, xpi, ymj, ypj;
|
|
|
1314 int xmj, xpj, ymi, ypi;
|
|
|
1315 int xmk, xpk, ymh, yph;
|
|
|
1316
|
|
257
|
1317 if (rx==0 && ry==0) { /* Special case - draw a single pixel */
|
|
|
1318 set_at( dst, x, y, color);
|
|
|
1319 return;
|
|
225
|
1320 }
|
|
257
|
1321 if (rx==0) { /* Special case for rx=0 - draw a vline */
|
|
|
1322 drawvertlineclip( dst, color, x, (Sint16)(y-ry), (Sint16)(y+ry) );
|
|
|
1323 return;
|
|
|
1324 }
|
|
|
1325 if (ry==0) { /* Special case for ry=0 - draw a hline */
|
|
|
1326 drawhorzlineclip( dst, color, (Sint16)(x-rx), y, (Sint16)(x+rx) );
|
|
|
1327 return;
|
|
|
1328 }
|
|
|
1329
|
|
|
1330
|
|
225
|
1331 /* Init vars */
|
|
|
1332 oh = oi = oj = ok = 0xFFFF;
|
|
|
1333 if (rx > ry) {
|
|
|
1334 ix = 0;
|
|
|
1335 iy = rx * 64;
|
|
|
1336 do {
|
|
257
|
1337 h = (ix + 16) >> 6;
|
|
|
1338 i = (iy + 16) >> 6;
|
|
225
|
1339 j = (h * ry) / rx;
|
|
|
1340 k = (i * ry) / rx;
|
|
257
|
1341
|
|
225
|
1342 if (((ok!=k) && (oj!=k)) || ((oj!=j) && (ok!=j)) || (k!=j)) {
|
|
256
|
1343 xph=x+h-1;
|
|
225
|
1344 xmh=x-h;
|
|
|
1345 if (k>0) {
|
|
256
|
1346 ypk=y+k-1;
|
|
225
|
1347 ymk=y-k;
|
|
257
|
1348 if(h > 0) {
|
|
|
1349 set_at(dst, xmh, ypk, color);
|
|
|
1350 set_at(dst, xmh, ymk, color);
|
|
|
1351 }
|
|
225
|
1352 set_at(dst, xph, ypk, color);
|
|
|
1353 set_at(dst, xph, ymk, color);
|
|
257
|
1354 }
|
|
225
|
1355 ok=k;
|
|
256
|
1356 xpi=x+i-1;
|
|
225
|
1357 xmi=x-i;
|
|
|
1358 if (j>0) {
|
|
256
|
1359 ypj=y+j-1;
|
|
225
|
1360 ymj=y-j;
|
|
|
1361 set_at(dst, xmi, ypj, color);
|
|
|
1362 set_at(dst, xpi, ypj, color);
|
|
|
1363 set_at(dst, xmi, ymj, color);
|
|
|
1364 set_at(dst, xpi, ymj, color);
|
|
257
|
1365 }
|
|
225
|
1366 oj=j;
|
|
|
1367 }
|
|
|
1368 ix = ix + iy / rx;
|
|
|
1369 iy = iy - ix / rx;
|
|
257
|
1370
|
|
225
|
1371 } while (i > h);
|
|
|
1372 } else {
|
|
|
1373 ix = 0;
|
|
|
1374 iy = ry * 64;
|
|
|
1375 do {
|
|
|
1376 h = (ix + 32) >> 6;
|
|
|
1377 i = (iy + 32) >> 6;
|
|
|
1378 j = (h * rx) / ry;
|
|
|
1379 k = (i * rx) / ry;
|
|
257
|
1380
|
|
225
|
1381 if (((oi!=i) && (oh!=i)) || ((oh!=h) && (oi!=h) && (i!=h))) {
|
|
|
1382 xmj=x-j;
|
|
256
|
1383 xpj=x+j-1;
|
|
225
|
1384 if (i>0) {
|
|
256
|
1385 ypi=y+i-1;
|
|
225
|
1386 ymi=y-i;
|
|
257
|
1387 if(j > 0) {
|
|
|
1388 set_at(dst, xmj, ypi, color);
|
|
|
1389 set_at(dst, xmj, ymi, color);
|
|
|
1390 }
|
|
|
1391 set_at(dst, xpj, ypi, color);
|
|
|
1392 set_at(dst, xpj, ymi, color);
|
|
|
1393 }
|
|
225
|
1394 oi=i;
|
|
|
1395 xmk=x-k;
|
|
256
|
1396 xpk=x+k-1;
|
|
225
|
1397 if (h>0) {
|
|
256
|
1398 yph=y+h-1;
|
|
225
|
1399 ymh=y-h;
|
|
|
1400 set_at(dst, xmk, yph, color);
|
|
|
1401 set_at(dst, xpk, yph, color);
|
|
|
1402 set_at(dst, xmk, ymh, color);
|
|
|
1403 set_at(dst, xpk, ymh, color);
|
|
257
|
1404 }
|
|
225
|
1405 oh=h;
|
|
|
1406 }
|
|
|
1407 ix = ix + iy / ry;
|
|
|
1408 iy = iy - ix / ry;
|
|
|
1409 } while(i > h);
|
|
|
1410 }
|
|
|
1411 }
|
|
|
1412
|
|
|
1413
|
|
|
1414
|
|
|
1415
|
|
|
1416
|
|
|
1417
|
|
|
1418
|
|
256
|
1419 static void draw_fillellipse(SDL_Surface *dst, int x, int y, int rx, int ry, Uint32 color)
|
|
225
|
1420 {
|
|
|
1421 int ix, iy;
|
|
|
1422 int h, i, j, k;
|
|
|
1423 int oh, oi, oj, ok;
|
|
257
|
1424
|
|
|
1425 if (rx==0 && ry==0) { /* Special case - draw a single pixel */
|
|
|
1426 set_at( dst, x, y, color);
|
|
|
1427 return;
|
|
225
|
1428 }
|
|
257
|
1429 if (rx==0) { /* Special case for rx=0 - draw a vline */
|
|
|
1430 drawvertlineclip( dst, color, x, (Sint16)(y-ry), (Sint16)(y+ry) );
|
|
|
1431 return;
|
|
225
|
1432 }
|
|
257
|
1433 if (ry==0) { /* Special case for ry=0 - draw a hline */
|
|
|
1434 drawhorzlineclip( dst, color, (Sint16)(x-rx), y, (Sint16)(x+rx) );
|
|
|
1435 return;
|
|
225
|
1436 }
|
|
257
|
1437
|
|
225
|
1438 /* Init vars */
|
|
|
1439 oh = oi = oj = ok = 0xFFFF;
|
|
|
1440
|
|
|
1441 /* Draw */
|
|
257
|
1442 if (rx >= ry) {
|
|
225
|
1443 ix = 0;
|
|
|
1444 iy = rx * 64;
|
|
|
1445
|
|
|
1446 do {
|
|
258
|
1447 h = (ix + 4/*32*/) >> 6;
|
|
|
1448 i = (iy + 4/*32*/) >> 6;
|
|
225
|
1449 j = (h * ry) / rx;
|
|
|
1450 k = (i * ry) / rx;
|
|
|
1451 if ((ok!=k) && (oj!=k)) {
|
|
257
|
1452 drawhorzlineclip(dst, color, x-h, y+k, x+h-1);
|
|
|
1453 drawhorzlineclip(dst, color, x-h, y-k-1, x+h-1);
|
|
225
|
1454 ok=k;
|
|
|
1455 }
|
|
|
1456 if ((oj!=j) && (ok!=j) && (k!=j)) {
|
|
257
|
1457 drawhorzlineclip(dst, color, x-i, y+j, x+i-1);
|
|
|
1458 drawhorzlineclip(dst, color, x-i, y-j-1, x+i-1);
|
|
225
|
1459 oj=j;
|
|
|
1460 }
|
|
|
1461 ix = ix + iy / rx;
|
|
|
1462 iy = iy - ix / rx;
|
|
|
1463
|
|
|
1464 } while (i > h);
|
|
|
1465 } else {
|
|
|
1466 ix = 0;
|
|
|
1467 iy = ry * 64;
|
|
|
1468
|
|
|
1469 do {
|
|
|
1470 h = (ix + 32) >> 6;
|
|
|
1471 i = (iy + 32) >> 6;
|
|
|
1472 j = (h * rx) / ry;
|
|
|
1473 k = (i * rx) / ry;
|
|
|
1474
|
|
|
1475 if ((oi!=i) && (oh!=i)) {
|
|
257
|
1476 drawhorzlineclip(dst, color, x-j, y+i, x+j-1);
|
|
|
1477 drawhorzlineclip(dst, color, x-j, y-i-1, x+j-1);
|
|
225
|
1478 oi=i;
|
|
|
1479 }
|
|
|
1480 if ((oh!=h) && (oi!=h) && (i!=h)) {
|
|
258
|
1481 drawhorzlineclip(dst, color, x-k, y+h, x+k-1);
|
|
|
1482 drawhorzlineclip(dst, color, x-k, y-h-1, x+k-1);
|
|
225
|
1483 oh=h;
|
|
|
1484 }
|
|
|
1485
|
|
|
1486 ix = ix + iy / ry;
|
|
|
1487 iy = iy - ix / ry;
|
|
|
1488
|
|
|
1489 } while(i > h);
|
|
|
1490 }
|
|
|
1491 }
|
|
|
1492
|
|
|
1493
|
|
|
1494 static int compare_int(const void *a, const void *b)
|
|
|
1495 {
|
|
|
1496 return (*(const int *)a) - (*(const int *)b);
|
|
|
1497 }
|
|
|
1498
|
|
256
|
1499 static void draw_fillpoly(SDL_Surface *dst, int *vx, int *vy, int n, Uint32 color)
|
|
225
|
1500 {
|
|
|
1501 int i;
|
|
|
1502 int y;
|
|
|
1503 int miny, maxy;
|
|
|
1504 int x1, y1;
|
|
|
1505 int x2, y2;
|
|
|
1506 int ind1, ind2;
|
|
|
1507 int ints;
|
|
|
1508 int *polyints = PyMem_New(int, n);
|
|
|
1509
|
|
|
1510
|
|
|
1511 /* Determine Y maxima */
|
|
|
1512 miny = vy[0];
|
|
|
1513 maxy = vy[0];
|
|
|
1514 for (i=1; (i < n); i++)
|
|
|
1515 {
|
|
|
1516 miny = min(miny, vy[i]);
|
|
|
1517 maxy = max(maxy, vy[i]);
|
|
|
1518 }
|
|
|
1519
|
|
|
1520 /* Draw, scanning y */
|
|
|
1521 for(y=miny; (y <= maxy); y++) {
|
|
|
1522 ints = 0;
|
|
|
1523 for (i=0; (i < n); i++) {
|
|
|
1524 if (!i) {
|
|
|
1525 ind1 = n-1;
|
|
|
1526 ind2 = 0;
|
|
|
1527 } else {
|
|
|
1528 ind1 = i-1;
|
|
|
1529 ind2 = i;
|
|
|
1530 }
|
|
|
1531 y1 = vy[ind1];
|
|
|
1532 y2 = vy[ind2];
|
|
|
1533 if (y1 < y2) {
|
|
|
1534 x1 = vx[ind1];
|
|
|
1535 x2 = vx[ind2];
|
|
|
1536 } else if (y1 > y2) {
|
|
|
1537 y2 = vy[ind1];
|
|
|
1538 y1 = vy[ind2];
|
|
|
1539 x2 = vx[ind1];
|
|
|
1540 x1 = vx[ind2];
|
|
|
1541 } else {
|
|
|
1542 continue;
|
|
|
1543 }
|
|
|
1544 if ((y >= y1) && (y < y2)) {
|
|
|
1545 polyints[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
|
|
|
1546 } else if ((y == maxy) && (y > y1) && (y <= y2)) {
|
|
|
1547 polyints[ints++] = (y-y1) * (x2-x1) / (y2-y1) + x1;
|
|
|
1548 }
|
|
|
1549 }
|
|
|
1550 qsort(polyints, ints, sizeof(int), compare_int);
|
|
|
1551
|
|
|
1552 for (i=0; (i<ints); i+=2) {
|
|
|
1553 drawhorzlineclip(dst, color, polyints[i], y, polyints[i+1]);
|
|
|
1554 }
|
|
|
1555 }
|
|
|
1556 }
|
|
|
1557
|
|
|
1558
|
|
|
1559
|
|
|
1560
|
|
|
1561
|
|
85
|
1562
|
|
|
1563
|
|
|
1564 static PyMethodDef draw_builtins[] =
|
|
|
1565 {
|
|
442
|
1566 { "aaline", aaline, 1, doc_aaline },
|
|
85
|
1567 { "line", line, 1, doc_line },
|
|
442
|
1568 { "aalines", aalines, 1, doc_aalines },
|
|
93
|
1569 { "lines", lines, 1, doc_lines },
|
|
225
|
1570 { "ellipse", ellipse, 1, doc_ellipse },
|
|
244
|
1571 { "circle", circle, 1, doc_circle },
|
|
225
|
1572 { "polygon", polygon, 1, doc_polygon },
|
|
244
|
1573 { "rect", rect, 1, doc_rect },
|
|
225
|
1574
|
|
85
|
1575 { NULL, NULL }
|
|
|
1576 };
|
|
|
1577
|
|
|
1578
|
|
|
1579
|
|
|
1580 /*DOC*/ static char doc_pygame_draw_MODULE[] =
|
|
|
1581 /*DOC*/ "Contains routines to draw onto a surface.\n"
|
|
|
1582 /*DOC*/ "\n"
|
|
|
1583 /*DOC*/ "Note that all\n"
|
|
|
1584 /*DOC*/ "drawing routines use direct pixel access, so the surfaces\n"
|
|
|
1585 /*DOC*/ "must be locked for use. The draw functions will temporarily\n"
|
|
|
1586 /*DOC*/ "lock the surface if needed, but if performing many drawing\n"
|
|
|
1587 /*DOC*/ "routines together, it would be best to surround the drawing\n"
|
|
|
1588 /*DOC*/ "code with a lock/unlock pair.\n"
|
|
|
1589 /*DOC*/ ;
|
|
|
1590
|
|
120
|
1591 PYGAME_EXPORT
|
|
85
|
1592 void initdraw(void)
|
|
|
1593 {
|
|
|
1594 PyObject *module, *dict;
|
|
|
1595
|
|
|
1596 /* create the module */
|
|
|
1597 module = Py_InitModule3("draw", draw_builtins, doc_pygame_draw_MODULE);
|
|
|
1598 dict = PyModule_GetDict(module);
|
|
|
1599
|
|
|
1600 /*imported needed apis*/
|
|
|
1601 import_pygame_base();
|
|
|
1602 import_pygame_rect();
|
|
|
1603 import_pygame_surface();
|
|
|
1604 }
|
|
|
1605
|
|
93
|
1606
|