1 /* Public domain */
2
3 /*
4 * Primitive GUI rendering routines.
5 */
6
7 #ifndef _AGAR_GUI_PRIMITIVE_H_
8 #define _AGAR_GUI_PRIMITIVE_H_
9
10 #include <agar/gui/widget.h>
11
12 #include <agar/gui/begin.h>
13
14 __BEGIN_DECLS
15 /* Increment individual RGB components of a pixel. */
16 /* XXX TODO use SIMD where available */
17 static __inline__ AG_Color
AG_ColorShift(AG_Color C,Sint8 * shift)18 AG_ColorShift(AG_Color C, Sint8 *shift)
19 {
20 int r = C.r + shift[0];
21 int g = C.g + shift[1];
22 int b = C.b + shift[2];
23
24 if (r > 255) { r = 255; } else if (r < 0) { r = 0; }
25 if (g > 255) { g = 255; } else if (g < 0) { g = 0; }
26 if (b > 255) { b = 255; } else if (b < 0) { b = 0; }
27
28 C.r = (Uint8)r;
29 C.g = (Uint8)g;
30 C.b = (Uint8)b;
31 return (C);
32 }
33
34 /*
35 * Calls to rendering routines implemented by the underlying driver.
36 */
37
38 /* Write a pixel (AG_Color argument) */
39 static __inline__ void
AG_PutPixel(void * obj,int x,int y,AG_Color C)40 AG_PutPixel(void *obj, int x, int y, AG_Color C)
41 {
42 AG_Widget *wid = (AG_Widget *)obj;
43
44 wid->drvOps->putPixel(wid->drv,
45 wid->rView.x1 + x,
46 wid->rView.y1 + y,
47 C);
48 }
49
50 /* Write a pixel (32-bit videoFmt argument) */
51 static __inline__ void
AG_PutPixel32(void * obj,int x,int y,Uint32 c)52 AG_PutPixel32(void *obj, int x, int y, Uint32 c)
53 {
54 AG_Widget *wid = (AG_Widget *)obj;
55
56 wid->drvOps->putPixel32(wid->drv,
57 wid->rView.x1 + x,
58 wid->rView.y1 + y,
59 c);
60 }
61
62 /* Write a pixel (RGB arguments) */
63 static __inline__ void
AG_PutPixelRGB(void * obj,int x,int y,Uint8 r,Uint8 g,Uint8 b)64 AG_PutPixelRGB(void *obj, int x, int y, Uint8 r, Uint8 g, Uint8 b)
65 {
66 AG_Widget *wid = (AG_Widget *)obj;
67
68 wid->drvOps->putPixelRGB(wid->drv,
69 wid->rView.x1 + x,
70 wid->rView.y1 + y,
71 r,g,b);
72 }
73
74 /* Blend a pixel (AG_Color argument) */
75 static __inline__ void
AG_BlendPixel(void * obj,int x,int y,AG_Color C,AG_BlendFn fnSrc)76 AG_BlendPixel(void *obj, int x, int y, AG_Color C, AG_BlendFn fnSrc)
77 {
78 AG_Widget *wid = (AG_Widget *)obj;
79
80 wid->drvOps->blendPixel(wid->drv,
81 wid->rView.x1 + x,
82 wid->rView.y1 + y,
83 C, fnSrc, AG_ALPHA_ZERO);
84 }
85
86 /* Blend a pixel (32-bit agSurfaceFmt argument) */
87 static __inline__ void
AG_BlendPixel32(void * obj,int x,int y,Uint32 px,AG_BlendFn fnSrc)88 AG_BlendPixel32(void *obj, int x, int y, Uint32 px, AG_BlendFn fnSrc)
89 {
90 AG_Widget *wid = (AG_Widget *)obj;
91 AG_Color C = AG_GetColorRGBA(px, agSurfaceFmt);
92
93 wid->drvOps->blendPixel(wid->drv,
94 wid->rView.x1 + x,
95 wid->rView.y1 + y,
96 C, fnSrc, AG_ALPHA_ZERO);
97 }
98
99 /* Blend a pixel (RGBA arguments) */
100 static __inline__ void
AG_BlendPixelRGBA(void * obj,int x,int y,Uint8 c[4],AG_BlendFn fnSrc)101 AG_BlendPixelRGBA(void *obj, int x, int y, Uint8 c[4], AG_BlendFn fnSrc)
102 {
103 AG_Widget *wid = (AG_Widget *)obj;
104
105 wid->drvOps->blendPixel(wid->drv,
106 wid->rView.x1 + x,
107 wid->rView.y1 + y,
108 AG_ColorRGBA(c[0],c[1],c[2],c[3]),
109 fnSrc, AG_ALPHA_ZERO);
110 }
111
112 /* Render a line from two endpoints. */
113 static __inline__ void
AG_DrawLine(void * obj,int x1,int y1,int x2,int y2,AG_Color C)114 AG_DrawLine(void *obj, int x1, int y1, int x2, int y2, AG_Color C)
115 {
116 AG_Widget *wid = (AG_Widget *)obj;
117
118 wid->drvOps->drawLine(wid->drv,
119 wid->rView.x1 + x1,
120 wid->rView.y1 + y1,
121 wid->rView.x1 + x2,
122 wid->rView.y1 + y2,
123 C);
124 }
125
126 /* Render a horizontal line. */
127 static __inline__ void
AG_DrawLineH(void * obj,int x1,int x2,int y,AG_Color C)128 AG_DrawLineH(void *obj, int x1, int x2, int y, AG_Color C)
129 {
130 AG_Widget *wid = (AG_Widget *)obj;
131
132 wid->drvOps->drawLineH(wid->drv,
133 wid->rView.x1 + x1,
134 wid->rView.x1 + x2,
135 wid->rView.y1 + y,
136 C);
137 }
138
139 /* Render a vertical line. */
140 static __inline__ void
AG_DrawLineV(void * obj,int x,int y1,int y2,AG_Color C)141 AG_DrawLineV(void *obj, int x, int y1, int y2, AG_Color C)
142 {
143 AG_Widget *wid = (AG_Widget *)obj;
144
145 wid->drvOps->drawLineV(wid->drv,
146 wid->rView.x1 + x,
147 wid->rView.y1 + y1,
148 wid->rView.y1 + y2,
149 C);
150 }
151
152 /* Render a line with blending. */
153 static __inline__ void
AG_DrawLineBlended(void * obj,int x1,int y1,int x2,int y2,AG_Color C,AG_BlendFn fnSrc)154 AG_DrawLineBlended(void *obj, int x1, int y1, int x2, int y2, AG_Color C,
155 AG_BlendFn fnSrc)
156 {
157 AG_Widget *wid = (AG_Widget *)obj;
158
159 wid->drvOps->drawLineBlended(wid->drv,
160 wid->rView.x1 + x1,
161 wid->rView.y1 + y1,
162 wid->rView.x1 + x2,
163 wid->rView.y1 + y2,
164 C, fnSrc, AG_ALPHA_ZERO);
165 }
166
167 /* Render an arrow pointing up. */
168 static __inline__ void
AG_DrawArrowUp(void * obj,int x0,int y0,int h,AG_Color c1,AG_Color c2)169 AG_DrawArrowUp(void *obj, int x0, int y0, int h, AG_Color c1, AG_Color c2)
170 {
171 AG_Widget *wid = (AG_Widget *)obj;
172 AG_Color c[2];
173
174 c[0] = c1;
175 c[1] = c2;
176 wid->drvOps->drawArrowUp(wid->drv,
177 wid->rView.x1 + x0,
178 wid->rView.y1 + y0,
179 h, c);
180 }
181
182 /* Render an arrow pointing down. */
183 static __inline__ void
AG_DrawArrowDown(void * obj,int x0,int y0,int h,AG_Color c1,AG_Color c2)184 AG_DrawArrowDown(void *obj, int x0, int y0, int h, AG_Color c1, AG_Color c2)
185 {
186 AG_Widget *wid = (AG_Widget *)obj;
187 AG_Color c[2];
188
189 c[0] = c1;
190 c[1] = c2;
191 wid->drvOps->drawArrowDown(wid->drv,
192 wid->rView.x1 + x0,
193 wid->rView.y1 + y0,
194 h, c);
195 }
196
197 /* Render an arrow pointing left. */
198 static __inline__ void
AG_DrawArrowLeft(void * obj,int x0,int y0,int h,AG_Color c1,AG_Color c2)199 AG_DrawArrowLeft(void *obj, int x0, int y0, int h, AG_Color c1, AG_Color c2)
200 {
201 AG_Widget *wid = (AG_Widget *)obj;
202 AG_Color c[2];
203
204 c[0] = c1;
205 c[1] = c2;
206 wid->drvOps->drawArrowLeft(wid->drv,
207 wid->rView.x1 + x0,
208 wid->rView.y1 + y0,
209 h, c);
210 }
211
212 /* Render an arrow pointing right. */
213 static __inline__ void
AG_DrawArrowRight(void * obj,int x0,int y0,int h,AG_Color c1,AG_Color c2)214 AG_DrawArrowRight(void *obj, int x0, int y0, int h, AG_Color c1, AG_Color c2)
215 {
216 AG_Widget *wid = (AG_Widget *)obj;
217 AG_Color c[2];
218
219 c[0] = c1;
220 c[1] = c2;
221 wid->drvOps->drawArrowRight(wid->drv,
222 wid->rView.x1 + x0,
223 wid->rView.y1 + y0,
224 h, c);
225 }
226
227 /* Render a 3D-style box with rounded edges. */
228 static __inline__ void
AG_DrawBoxRounded(void * obj,AG_Rect r,int z,int rad,AG_Color cBg)229 AG_DrawBoxRounded(void *obj, AG_Rect r, int z, int rad, AG_Color cBg)
230 {
231 AG_Widget *wid = (AG_Widget *)obj;
232 AG_Color c[3];
233
234 AG_WidgetOffsetRect(wid, &r);
235
236 c[0] = AG_ColorShift(cBg, (z<0) ? agSunkColorShift : agRaisedColorShift);
237 c[1] = AG_ColorShift(c[0], (z<0) ? agLowColorShift : agHighColorShift);
238 c[2] = AG_ColorShift(c[0], (z<0) ? agHighColorShift : agLowColorShift);
239 wid->drvOps->drawBoxRounded(wid->drv, r, z, rad, c);
240 }
241
242 /* Render a 3D-style box with rounded top edges. */
243 static __inline__ void
AG_DrawBoxRoundedTop(void * obj,AG_Rect r,int z,int rad,AG_Color cBg)244 AG_DrawBoxRoundedTop(void *obj, AG_Rect r, int z, int rad, AG_Color cBg)
245 {
246 AG_Widget *wid = (AG_Widget *)obj;
247 AG_Color c[3];
248
249 AG_WidgetOffsetRect(wid, &r);
250 c[0] = cBg;
251 c[1] = AG_ColorShift(c[0], (z<0)?agLowColorShift:agHighColorShift);
252 c[2] = AG_ColorShift(c[0], (z<0)?agHighColorShift:agLowColorShift);
253 wid->drvOps->drawBoxRoundedTop(wid->drv, r, z, rad, c);
254 }
255
256 /* Render a circle of specified radius. */
257 static __inline__ void
AG_DrawCircle(void * obj,int x,int y,int r,AG_Color c)258 AG_DrawCircle(void *obj, int x, int y, int r, AG_Color c)
259 {
260 AG_Widget *wid = (AG_Widget *)obj;
261
262 wid->drvOps->drawCircle(wid->drv,
263 wid->rView.x1 + x,
264 wid->rView.y1 + y,
265 r, c);
266 }
267
268 /* Render a circle of specified radius. */
269 static __inline__ void
AG_DrawCircleFilled(void * obj,int x,int y,int r,AG_Color c)270 AG_DrawCircleFilled(void *obj, int x, int y, int r, AG_Color c)
271 {
272 AG_Widget *wid = (AG_Widget *)obj;
273
274 wid->drvOps->drawCircleFilled(wid->drv,
275 wid->rView.x1 + x,
276 wid->rView.y1 + y,
277 r, c);
278 }
279
280 /* Render a filled rectangle (opaque or transparent). */
281 static __inline__ void
AG_DrawRect(void * obj,AG_Rect r,AG_Color c)282 AG_DrawRect(void *obj, AG_Rect r, AG_Color c)
283 {
284 AG_Widget *wid = (AG_Widget *)obj;
285
286 AG_WidgetOffsetRect(wid, &r);
287 if (c.a < AG_ALPHA_OPAQUE) {
288 wid->drvOps->drawRectBlended(wid->drv, r, c,
289 AG_ALPHA_SRC, AG_ALPHA_ONE_MINUS_SRC);
290 } else {
291 wid->drvOps->drawRectFilled(wid->drv, r, c);
292 }
293 }
294
295 /* Render a filled rectangle (opaque). */
296 static __inline__ void
AG_DrawRectFilled(void * obj,AG_Rect r,AG_Color c)297 AG_DrawRectFilled(void *obj, AG_Rect r, AG_Color c)
298 {
299 AG_Widget *wid = (AG_Widget *)obj;
300
301 AG_WidgetOffsetRect(wid, &r);
302 wid->drvOps->drawRectFilled(wid->drv, r, c);
303 }
304
305 /* Render a filled rectangle (transparent). */
306 static __inline__ void
AG_DrawRectBlended(void * obj,AG_Rect r,AG_Color c,AG_BlendFn fnSrc)307 AG_DrawRectBlended(void *obj, AG_Rect r, AG_Color c, AG_BlendFn fnSrc)
308 {
309 AG_Widget *wid = (AG_Widget *)obj;
310
311 AG_WidgetOffsetRect(wid, &r);
312 wid->drvOps->drawRectBlended(wid->drv, r, c,
313 fnSrc, AG_ALPHA_ONE_MINUS_SRC);
314 }
315
316 /* Render a filled rectangle with dithering. */
317 static __inline__ void
AG_DrawRectDithered(void * obj,AG_Rect r,AG_Color c)318 AG_DrawRectDithered(void *obj, AG_Rect r, AG_Color c)
319 {
320 AG_Widget *wid = (AG_Widget *)obj;
321
322 AG_WidgetOffsetRect(wid, &r);
323 wid->drvOps->drawRectDithered(wid->drv, r, c);
324 }
325
326
327 /* Render a 3D-style frame. */
328 static __inline__ void
AG_DrawFrame(void * obj,AG_Rect r,int z,AG_Color cBase)329 AG_DrawFrame(void *obj, AG_Rect r, int z, AG_Color cBase)
330 {
331 AG_Widget *wid = (AG_Widget *)obj;
332 AG_Driver *drv = wid->drv;
333 AG_DriverClass *drvOps = wid->drvOps;
334 AG_Color c[2];
335 int y2, x2;
336
337 AG_WidgetOffsetRect(wid, &r);
338 c[0] = AG_ColorShift(cBase, (z<0)?agLowColorShift:agHighColorShift);
339 c[1] = AG_ColorShift(cBase, (z<0)?agHighColorShift:agLowColorShift);
340 x2 = r.x+r.w - 1;
341 y2 = r.y+r.h - 1;
342
343 if (c[0].a < AG_ALPHA_OPAQUE) {
344 drvOps->drawLineBlended(drv, r.x, r.y, x2, r.y, c[0], AG_ALPHA_SRC, AG_ALPHA_ZERO);
345 drvOps->drawLineBlended(drv, r.x, r.y, r.x, y2, c[0], AG_ALPHA_SRC, AG_ALPHA_ZERO);
346 } else {
347 drvOps->drawLineH(drv, r.x, x2, r.y, c[0]);
348 drvOps->drawLineV(drv, r.x, r.y, y2, c[0]);
349 }
350 if (c[1].a < AG_ALPHA_OPAQUE) {
351 drvOps->drawLineBlended(drv, r.x, y2, x2, y2, c[1], AG_ALPHA_SRC, AG_ALPHA_ZERO);
352 drvOps->drawLineBlended(drv, x2, r.y, x2, y2, c[1], AG_ALPHA_SRC, AG_ALPHA_ZERO);
353 } else {
354 drvOps->drawLineH(drv, r.x, x2, y2, c[1]);
355 drvOps->drawLineV(drv, x2, r.y, y2, c[1]);
356 }
357 }
358
359 /*
360 * Miscellaneous, utility rendering routines.
361 */
362
363 /* Render a 3D-style box. */
364 static __inline__ void
AG_DrawBox(void * obj,AG_Rect r,int z,AG_Color c)365 AG_DrawBox(void *obj, AG_Rect r, int z, AG_Color c)
366 {
367 AG_Widget *wid = (AG_Widget *)obj;
368 AG_Driver *drv = wid->drv;
369 AG_Rect rOffs;
370
371 c = AG_ColorShift(c, (z < 0) ? agSunkColorShift : agRaisedColorShift);
372 rOffs = r;
373 AG_WidgetOffsetRect(wid, &rOffs);
374 if (c.a < AG_ALPHA_OPAQUE) {
375 wid->drvOps->drawRectBlended(drv, rOffs, c,
376 AG_ALPHA_SRC, AG_ALPHA_ONE_MINUS_SRC);
377 } else {
378 wid->drvOps->drawRectFilled(drv, rOffs, c);
379 }
380 AG_DrawFrame(wid, r, z, c);
381 }
382
383 /* Render a 3D-style box with disabled control-style dithering. */
384 static __inline__ void
AG_DrawBoxDisabled(void * obj,AG_Rect r,int z,AG_Color cBox,AG_Color cDither)385 AG_DrawBoxDisabled(void *obj, AG_Rect r, int z, AG_Color cBox, AG_Color cDither)
386 {
387 AG_Widget *wid = (AG_Widget *)obj;
388 AG_Rect rOffs;
389
390 cDither = AG_ColorShift(cDither, (z < 0) ? agSunkColorShift : agRaisedColorShift);
391 rOffs = r;
392 AG_WidgetOffsetRect(wid, &rOffs);
393 wid->drvOps->drawRectFilled(wid->drv, rOffs, cBox);
394 AG_DrawFrame(wid, r, z, cBox);
395 wid->drvOps->drawRectDithered(wid->drv, rOffs, cDither);
396 }
397
398 /* Render 3D-style frame using a specific blending mode. */
399 static __inline__ void
AG_DrawFrameBlended(void * obj,AG_Rect r,AG_Color C,AG_BlendFn fnSrc)400 AG_DrawFrameBlended(void *obj, AG_Rect r, AG_Color C, AG_BlendFn fnSrc)
401 {
402 AG_Widget *wid = (AG_Widget *)obj;
403 AG_Driver *drv = wid->drv;
404 AG_DriverClass *drvOps = wid->drvOps;
405 int x2, y2;
406
407 AG_WidgetOffsetRect(wid, &r);
408 x2 = r.x+r.w - 1;
409 y2 = r.y+r.h - 1;
410 drvOps->drawLineBlended(drv, r.x, r.y, x2, r.y, C, fnSrc, AG_ALPHA_ZERO);
411 drvOps->drawLineBlended(drv, r.x, r.y, r.x, y2, C, fnSrc, AG_ALPHA_ZERO);
412 drvOps->drawLineBlended(drv, r.x, y2, x2, y2, C, fnSrc, AG_ALPHA_ZERO);
413 drvOps->drawLineBlended(drv, x2, r.y, x2, y2, C, fnSrc, AG_ALPHA_ZERO);
414 }
415
416 /* Render a rectangle outline. */
417 static __inline__ void
AG_DrawRectOutline(void * obj,AG_Rect r,AG_Color c)418 AG_DrawRectOutline(void *obj, AG_Rect r, AG_Color c)
419 {
420 AG_Widget *wid = (AG_Widget *)obj;
421 AG_Driver *drv = wid->drv;
422 AG_DriverClass *drvOps = wid->drvOps;
423 int x2, y2;
424
425 AG_WidgetOffsetRect(wid, &r);
426 x2 = r.x+r.w - 1;
427 y2 = r.y+r.h - 1;
428 if (c.a < AG_ALPHA_OPAQUE) {
429 drvOps->drawLineBlended(drv, r.x, r.y, x2, r.y, c, AG_ALPHA_SRC, AG_ALPHA_ZERO);
430 drvOps->drawLineBlended(drv, r.x, r.y, x2, y2, c, AG_ALPHA_SRC, AG_ALPHA_ZERO);
431 drvOps->drawLineBlended(drv, r.x, r.y, r.x, y2, c, AG_ALPHA_SRC, AG_ALPHA_ZERO);
432 drvOps->drawLineBlended(drv, x2, r.y, r.x, y2, c, AG_ALPHA_SRC, AG_ALPHA_ZERO);
433 } else {
434 drvOps->drawLineH(drv, r.x, x2, r.y, c);
435 drvOps->drawLineH(drv, r.x, x2, y2, c);
436 drvOps->drawLineV(drv, r.x, r.y, y2, c);
437 drvOps->drawLineV(drv, x2, r.y, y2, c);
438 }
439 }
440
441 /* Render a [+] sign. */
442 static __inline__ void
AG_DrawPlus(void * obj,AG_Rect r,AG_Color C,AG_BlendFn fnSrc)443 AG_DrawPlus(void *obj, AG_Rect r, AG_Color C, AG_BlendFn fnSrc)
444 {
445 AG_Widget *wid = (AG_Widget *)obj;
446 AG_Driver *drv = wid->drv;
447 int x1, y1;
448
449 AG_WidgetOffsetRect(wid, &r);
450 x1 = r.x + r.w/2;
451 y1 = r.y + r.h/2;
452 wid->drvOps->drawLineBlended(drv, x1, r.y, x1, r.y+r.h, C, fnSrc, AG_ALPHA_ZERO);
453 wid->drvOps->drawLineBlended(drv, r.x, y1, r.x+r.w, y1, C, fnSrc, AG_ALPHA_ZERO);
454 }
455
456 /* Render a [-] sign. */
457 static __inline__ void
AG_DrawMinus(void * obj,AG_Rect r,AG_Color C,AG_BlendFn fnSrc)458 AG_DrawMinus(void *obj, AG_Rect r, AG_Color C, AG_BlendFn fnSrc)
459 {
460 AG_Widget *wid = (AG_Widget *)obj;
461 int x, y;
462
463 AG_WidgetOffsetRect(wid, &r);
464 x = r.x + r.w/2;
465 y = r.y + r.h/2;
466 wid->drvOps->drawLineBlended(wid->drv, x,y, r.x+r.w, y, C, fnSrc, AG_ALPHA_ZERO);
467 }
468
469 /* Render a 3D-style line. */
470 static __inline__ void
AG_DrawLine2(void * obj,int x1,int y1,int x2,int y2,AG_Color color)471 AG_DrawLine2(void *obj, int x1, int y1, int x2, int y2, AG_Color color)
472 {
473 AG_Widget *wid = (AG_Widget *)obj;
474
475 x1 += wid->rView.x1;
476 y1 += wid->rView.y1;
477 x2 += wid->rView.x1;
478 y2 += wid->rView.y1;
479 wid->drvOps->drawLine(wid->drv, x1, y1, x2, y2,
480 AG_ColorShift(color, agHighColorShift));
481 wid->drvOps->drawLine(wid->drv, x1+1, y1+1, x2+1, y2+1,
482 AG_ColorShift(color, agLowColorShift));
483 }
484
485 /* Render a gimp-style background tiling. */
486 static __inline__ void
AG_DrawTiling(void * obj,AG_Rect r,int tsz,int offs,AG_Color c1,AG_Color c2)487 AG_DrawTiling(void *obj, AG_Rect r, int tsz, int offs, AG_Color c1, AG_Color c2)
488 {
489 AG_Widget *wid = (AG_Widget *)obj;
490 AG_Driver *drv = wid->drv;
491 int alt1 = 0, alt2 = 0;
492 AG_Rect rt;
493
494 AG_WidgetOffsetRect(wid, &r);
495
496 rt.w = tsz;
497 rt.h = tsz;
498
499 /* XXX inelegant */
500 for (rt.y = r.y-tsz+offs;
501 rt.y < r.y+r.h;
502 rt.y += tsz) {
503 for (rt.x = r.x-tsz+offs;
504 rt.x < r.x+r.w;
505 rt.x += tsz) {
506 if (alt1++ == 1) {
507 wid->drvOps->drawRectFilled(drv, rt, c1);
508 alt1 = 0;
509 } else {
510 wid->drvOps->drawRectFilled(drv, rt, c2);
511 }
512 }
513 if (alt2++ == 1) {
514 alt2 = 0;
515 }
516 alt1 = alt2;
517 }
518 }
519 __END_DECLS
520
521 #include <agar/gui/close.h>
522 #endif /* _AGAR_GUI_PRIMITIVE_H_ */
523