fix remapping behavior. Remapping is only necessary if we are rendering on the workbe...
[AROS-Contrib.git] / Demo / Metaballs / metaballs.c
blob8fae619bc66a7f6ca59730bda01ff2662a0edccf
2 #include <dos/dos.h>
3 #include <intuition/intuition.h>
4 #include <graphics/gfx.h>
5 #include <cybergraphx/cybergraphics.h>
6 #include <proto/exec.h>
7 #include <proto/dos.h>
8 #include <proto/graphics.h>
9 #include <proto/cybergraphics.h>
10 #include <proto/intuition.h>
12 #include <math.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <memory.h>
19 /***********************************************************************************/
21 struct IntuitionBase *IntuitionBase;
22 struct GfxBase *GfxBase;
23 struct Library *CyberGfxBase;
24 struct Screen *scr;
25 struct Window *win;
26 struct RastPort *rp;
27 ULONG cgfx_coltab[256];
28 UBYTE remaptable[256];
29 UBYTE Keys[128];
30 char s[256];
31 WORD winx = -1, winy = -1;
32 BOOL forcescreen, forcewindow;
33 BOOL mustremap, truecolor, remapped, wbscreen = TRUE;
35 static void cleanup(char *msg);
37 /***********************************************************************************/
39 #define balls 20
41 static WORD x, i;
43 static struct
45 APTR p;
46 WORD dia;
47 BYTE rand;
48 } ball[balls];
50 #define W 320 // Full width
51 #define hW 160 // Half width
52 #define qW 80 // Quarter width
53 #define eW 40 // 1/8 width
54 #define H 200 // Full height
55 #define hH 100 // Half height
56 #define qH 50 // Quarter height
57 #define eH 25 // 1/8 height
59 static UBYTE chunkybuffer[W * H];
60 static UBYTE chunkybuffer_remapped[W * H];
62 /***********************************************************************************/
64 static void refresh(void)
66 if (truecolor)
68 WriteLUTPixelArray(chunkybuffer,
72 rp,
73 cgfx_coltab,
74 win->BorderLeft,
75 win->BorderTop,
78 CTABFMT_XRGB8);
80 else if (mustremap)
82 LONG i;
83 UBYTE *src = chunkybuffer;
84 UBYTE *dest = chunkybuffer_remapped;
86 for(i = 0; i < W * H; i++)
88 *dest++ = remaptable[*src++];
90 WriteChunkyPixels(rp,
91 win->BorderLeft,
92 win->BorderTop,
93 win->BorderLeft + W - 1,
94 win->BorderTop + H - 1,
95 chunkybuffer_remapped,
96 W);
99 else
101 WriteChunkyPixels(rp,
102 win->BorderLeft,
103 win->BorderTop,
104 win->BorderLeft + W - 1,
105 win->BorderTop + H - 1,
106 chunkybuffer,
111 /***********************************************************************************/
113 #define SQR(x) ((x) * (x))
114 #define pi 3.14159265
115 #define deg 0.017453
117 static void Calc_Ball(WORD hohe, WORD breite, APTR po)
119 WORD x, y, col;
120 float e;
122 for(y = 0; y < hohe; y++)
124 for(x = 0; x < breite; x++)
126 e = sqrt(SQR(x-(breite+1)/2) + 1.5*SQR(y-(breite+1)/2));
127 col = (WORD)(130.0+130.0*cos(e*pi/(hohe/2)));
128 if (col > 255) col=255;
129 if (e < (hohe / 2))
131 ((UBYTE *)po)[breite * y + x] = col;
133 else
135 ((UBYTE *)po)[breite * y + x] = 0;
142 /***********************************************************************************/
144 static void Do_Ball(WORD x, WORD y, WORD h, WORD b, APTR po)
146 WORD loopy, loopx;
147 UWORD destoffset = (y * W) + x;
148 UWORD col;
149 UBYTE *src = (UBYTE *)po;
151 for(loopy = 0; loopy < h; loopy++)
153 for(loopx = 0; loopx < b; loopx++)
155 col = *src++;
156 col += chunkybuffer[destoffset];
157 if (col > 255) col = 255;
158 chunkybuffer[destoffset++] = col;
160 destoffset += (W - b);
164 /***********************************************************************************/
166 static void initpalette(void)
168 WORD palindex = 0;
170 for(palindex = 0; palindex < 64; palindex++)
172 ULONG red = 0;
173 ULONG green = 0;
174 ULONG blue = palindex * 4;
176 cgfx_coltab[palindex] = (red << 16) + (green << 8) + blue;
178 red = palindex * 4;
179 green = palindex * 4;
180 blue = 0xFF;
182 cgfx_coltab[palindex + 64] = (red << 16) + (green << 8) + blue;
184 red = 0xFF - palindex * 4;
185 green = 0xFF - palindex * 4;
186 blue = 0xFF - palindex * 4;
188 cgfx_coltab[palindex + 128] = (red << 16) + (green << 8) + blue;
190 red = palindex * 4;
191 green = palindex * 4;
192 blue = palindex * 4;
194 cgfx_coltab[palindex + 192] = (red << 16) + (green << 8) + blue;
197 cgfx_coltab[255] = 0xFFFFFF;
199 if (!truecolor)
201 WORD i;
203 for(i = 0; i < 256; i++)
205 ULONG r = (cgfx_coltab[i] >> 16) & 0xFF;
206 ULONG g = (cgfx_coltab[i] >> 8) & 0xFF;
207 ULONG b = cgfx_coltab[i] & 0xFF;
209 if (mustremap)
211 ULONG red = r * 0x01010101;
212 ULONG green = g * 0x01010101;
213 ULONG blue = b * 0x01010101;
215 remaptable[i] = ObtainBestPen(scr->ViewPort.ColorMap,
216 red,
217 green,
218 blue,
219 OBP_Precision, PRECISION_IMAGE,
220 OBP_FailIfBad, FALSE,
221 TAG_DONE);
222 remapped = TRUE;
224 else
227 ULONG red = r * 0x01010101;
228 ULONG green = g * 0x01010101;
229 ULONG blue = b * 0x01010101;
231 SetRGB32(&scr->ViewPort, i, red, green, blue);
237 /***********************************************************************************/
239 static void initstuff(void)
241 int j=1;
243 for(i = 1; i <= balls; i++)
245 if(i&0x1)
246 j=i;
247 else
248 j=balls-i;
250 ball[i - 1].dia = 30 + abs(5 * (j-1));
251 ball[i - 1].rand = (BYTE)(20.0+20.0*sin(i*pi/balls*13));
252 ball[i - 1].p = malloc(SQR(ball[i - 1].dia));
253 if (ball[i].p) cleanup("out of memory!");
254 Calc_Ball(ball[i-1].dia, ball[i-1].dia, ball[i-1].p);
258 /***********************************************************************************/
260 static void ticker(void)
262 // Movement parameters
263 // The chain consists of four sin/cos waves per axis
264 // *dis* represents distance between blobs in the chain
265 // *add* represents the movement speed of the chain/waves
267 // Implemented by using local floats to make it easier
268 // to later implement CLI parameter values.
270 float xdis1 = -45.0;
271 float xdis2 = 65.0;
272 float xdis3 = 12.0;
273 float xdis4 = -25.0;
275 float ydis1 = 35.0;
276 float ydis2 = -55.0;
277 float ydis3 = -15.0;
278 float ydis4 = -05.0;
280 float xadd1 = 2.0;
281 float xadd2 = 1.25;
282 float xadd3 = -0.55;
283 float xadd4 = 0.93;
285 float yadd1 = 1.55;
286 float yadd2 = 0.63;
287 float yadd3 = 0.23;
288 float yadd4 = -0.94;
290 float xpos1, ypos1;
291 float xpos2, ypos2;
292 float xpos3, ypos3;
293 float xpos4, ypos4;
295 float xnew = 0, ynew = 0;
297 memset(chunkybuffer, 0, sizeof(chunkybuffer));
299 // Precalculating position of each wave
300 xpos1 = x * xadd1;
301 xpos2 = x * xadd2;
302 xpos3 = x * xadd3;
303 xpos4 = x * xadd4;
305 ypos1 = x * yadd1;
306 ypos2 = x * yadd2;
307 ypos3 = x * yadd3;
308 ypos4 = x * yadd4;
310 for(i = 0; i < balls; i++)
313 xnew = hW - ball[i].dia/2 +
314 qW * sin ((xdis1 * i + xpos1) * deg)+
315 qW * sin ((xdis2 * i + xpos2) * deg)+
316 qW * sin ((xdis3 * i + xpos3) * deg)+
317 qW * sin ((xdis4 * i + xpos4) * deg);
319 ynew = hW - ball[i].dia/2 +
320 qH * cos ((ydis1 * i + ypos1) * deg)+
321 qH * cos ((ydis2 * i + ypos2) * deg)+
322 qH * cos ((ydis3 * i + ypos3) * deg)+
323 qH * cos ((ydis4 * i + ypos4) * deg);
325 // replace qW/qH with eW/eH if you wish to keep
326 // the blobs from moving entirely over the edges.
328 Do_Ball((WORD)xnew,(WORD)ynew,
329 ball[i].dia, ball[i].dia, ball[i].p);
332 x++;
335 /***********************************************************************************/
337 static void cleanup(char *msg)
340 if (msg)
342 printf("metaballs: %s\n",msg);
345 if (win) CloseWindow(win);
347 if (remapped)
349 WORD i;
351 for(i = 0; i < 256; i++)
353 ReleasePen(scr->ViewPort.ColorMap, remaptable[i]);
357 if (scr)
359 if (wbscreen)
360 UnlockPubScreen(0, scr);
361 else
362 CloseScreen(scr);
365 if (CyberGfxBase) CloseLibrary(CyberGfxBase);
366 if (GfxBase) CloseLibrary((struct Library *)GfxBase);
367 if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
369 exit(0);
372 /***********************************************************************************/
374 #define ARG_TEMPLATE "WINPOSX=X/N/K,WINPOSY=Y/N/K,FORCESCREEN=SCR/S,FORCEWINDOW=WIN/S"
375 #define ARG_X 0
376 #define ARG_Y 1
377 #define ARG_SCR 2
378 #define ARG_WIN 3
379 #define NUM_ARGS 4
381 static IPTR args[NUM_ARGS];
383 static void getarguments(void)
385 struct RDArgs *myargs;
387 if ((myargs = ReadArgs(ARG_TEMPLATE, args, NULL)))
389 if (args[ARG_SCR])
390 forcescreen = TRUE;
391 else if (args[ARG_WIN])
392 forcewindow = TRUE;
394 if (args[ARG_X]) winx = *(IPTR *)args[ARG_X];
395 if (args[ARG_Y]) winy = *(IPTR *)args[ARG_Y];
397 FreeArgs(myargs);
401 /***********************************************************************************/
403 static void openlibs(void)
405 if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39)))
407 cleanup("Can't open intuition.library V39!");
410 if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 39)))
412 cleanup("Can't open graphics.library V39!");
415 if (!(CyberGfxBase = OpenLibrary("cybergraphics.library",0)))
417 cleanup("Can't open cybergraphics.library!");
422 /***********************************************************************************/
424 static void getvisual(void)
426 if (forcescreen)
427 wbscreen = FALSE;
429 if (!wbscreen)
431 scr = OpenScreenTags(NULL, SA_Width , W ,
432 SA_Height , H ,
433 SA_Depth , 8 ,
434 TAG_DONE);
435 if (!scr) cleanup("Failed to open specified screen!");
437 else if (!(scr = LockPubScreen(NULL)))
439 cleanup("Failed to lock pub screen (workbench)!");
442 truecolor = (GetBitMapAttr(scr->RastPort.BitMap, BMA_DEPTH) >= 15) ? TRUE : FALSE;
444 if ((!truecolor) && (wbscreen))
445 mustremap = TRUE;
448 /***********************************************************************************/
450 static void makewin(void)
452 struct TagItem winonwbtags[] =
454 {WA_DragBar , TRUE },
455 {WA_DepthGadget , TRUE },
456 {WA_CloseGadget , TRUE },
457 {WA_Title , (IPTR)"Metaballs" },
458 {TAG_DONE }
461 struct TagItem winonscrtags[] =
463 {WA_Borderless, TRUE },
464 {TAG_DONE }
467 if (winx == -1) winx = (scr->Width - W - scr->WBorLeft - scr->WBorRight) / 2;
468 if (winy == -1) winy = (scr->Height - H - scr->WBorTop - scr->WBorTop - scr->Font->ta_YSize - 1) / 2;
470 win = OpenWindowTags(NULL, WA_CustomScreen , (IPTR)scr,
471 WA_Left , winx,
472 WA_Top , winy,
473 WA_InnerWidth , W,
474 WA_InnerHeight , H,
475 WA_AutoAdjust , TRUE,
476 WA_Activate , TRUE,
477 WA_IDCMP , IDCMP_CLOSEWINDOW |
478 IDCMP_RAWKEY,
479 TAG_MORE , wbscreen ? winonwbtags : winonscrtags);
481 if (!win) cleanup("Can't open window");
483 rp = win->RPort;
486 /***********************************************************************************/
488 #define KC_LEFT 0x4F
489 #define KC_RIGHT 0x4E
490 #define KC_UP 0x4C
491 #define KC_DOWN 0x4D
492 #define KC_ESC 0x45
494 /***********************************************************************************/
496 static void getevents(void)
498 struct IntuiMessage *msg;
500 while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
502 switch(msg->Class)
504 case IDCMP_CLOSEWINDOW:
505 Keys[KC_ESC] = 1;
506 break;
508 case IDCMP_RAWKEY:
510 WORD code = msg->Code & ~IECODE_UP_PREFIX;
512 Keys[code] = (code == msg->Code) ? 1 : 0;
515 break;
518 ReplyMsg((struct Message *)msg);
523 /***********************************************************************************/
525 static void action(void)
527 initpalette();
528 initstuff();
530 while (!Keys[KC_ESC])
532 getevents();
534 ticker();
535 refresh();
536 WaitTOF();
541 /***********************************************************************************/
543 int main(void)
545 getarguments();
546 openlibs();
547 getvisual();
548 makewin();
549 action();
550 cleanup(0);
552 return 0;
555 /***********************************************************************************/