fixed text drawing
[awish.git] / src / gameglobals.c
blob90dfb1660d0538b31eecc32aac33b9dd5c0ad865
1 /*
2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #ifndef AWISH_NO_SOUND
16 # include "SDL_mixer.h"
17 #endif
19 #include "video.h"
20 #include "polymod.h"
22 #include "gameglobals.h"
25 ////////////////////////////////////////////////////////////////////////////////
26 ResFile resfile;
27 ResFile sndfile;
29 SDL_Surface *backs[9];
30 SpriteBank banks[257];
32 int disableSound = 0;
34 extern int goobers;
37 int mouseX = 0;
38 int mouseY = 0;
39 int mouseButtons = 0;
40 int mouseVisible = 1;
44 ////////////////////////////////////////////////////////////////////////////////
45 __attribute__((__noreturn__)) __attribute__((format(printf, 1, 2))) void fatal (const char *fmt, ...) {
46 va_list ap;
48 fprintf(stderr, "AWISH FATAL: ");
49 va_start(ap, fmt);
50 vfprintf(stderr, fmt, ap);
51 va_end(ap);
52 fprintf(stderr, "\n");
53 exit(1);
57 ////////////////////////////////////////////////////////////////////////////////
58 // These values are not magical, just the default values Marsaglia used.
59 // Any pair of unsigned integers should be fine.
60 #define DEFAULT_M_W (521288629LL)
61 #define DEFAULT_M_Z (362436069LL)
63 static Uint32 m_w = DEFAULT_M_W;
64 static Uint32 m_z = DEFAULT_M_Z;
67 Uint32 getSeedH (void) {
68 return m_z;
72 Uint32 getSeedL (void) {
73 return m_w;
77 Uint32 getSeed (void) {
78 return m_w;
82 /* from system time: long x = dt.ToFileTime(); SetSeed((uint)(x >> 16), (uint)(x % 4294967296)); */
83 void setSeedH (Uint32 u) {
84 m_z = u ? u : DEFAULT_M_Z;
88 void setSeedL (Uint32 u) {
89 m_w = u ? u : DEFAULT_M_W;
93 void setSeedHL (Uint32 h, Uint32 l) {
94 setSeedH(h);
95 setSeedL(l);
99 void setSeed (Uint32 u) {
100 setSeedHL(0, u);
104 Uint32 randUInt32 (void) {
105 Uint32 res;
107 m_z = 36969*(m_z&65535)+(m_z>>16);
108 m_w = 18000*(m_w&65535)+(m_w>>16);
109 res = (m_z<<16)+m_w;
110 if (m_w == 0) m_w = DEFAULT_M_Z;
111 if (m_z == 0) m_z = DEFAULT_M_Z;
112 return res;
116 // the magic number below is 1/(2^32 + 2)
117 // uniform: (randUInt32()+1.0)*2.328306435454494e-10;
118 // the result is strictly between 0 and 1.
121 ////////////////////////////////////////////////////////////////////////////////
122 // return vm code size
123 int loadCodeFile (ResFile *resfile, int pc, int idx, int asmodule) {
124 int rsz = 0, res = 0;
125 uint8_t *buf = loadResFile(resfile, idx, &rsz);
127 if (buf == NULL) return -1;
129 res = vmLoadCodeFileFromDump(buf, rsz, pc, vmMaxGVar, vmMaxTVar, asmodule?NULL:&vmMaxGVar, asmodule?NULL:&vmMaxTVar);
130 free(buf);
131 return res;
135 ////////////////////////////////////////////////////////////////////////////////
136 #include "vm_gamelabelsdef.c"
137 void initLabels (void) {
138 #include "vm_gamelabelsinit.c"
142 ////////////////////////////////////////////////////////////////////////////////
143 #ifndef AWISH_NO_SOUND
144 typedef struct SoundInfo {
145 struct SoundInfo *next;
146 int idx;
147 Mix_Chunk *data;
148 } SoundInfo;
150 static SoundInfo *sndlist = NULL;
153 static SoundInfo *findSound (int idx) {
154 for (SoundInfo *snd = sndlist; snd != NULL; snd = snd->next) if (snd->idx == idx) return snd;
155 return NULL;
159 int loadSound (int idx) {
160 SoundInfo *snd = findSound(idx);
162 if (snd == NULL) {
163 Mix_Chunk *data = loadSoundFile(&sndfile, idx);
165 if (data != NULL) {
166 snd = malloc(sizeof(SoundInfo));
167 if (snd != NULL) {
168 snd->next = sndlist;
169 snd->idx = idx;
170 snd->data = data;
171 sndlist = snd;
172 } else {
173 Mix_FreeChunk(data);
177 return (snd != NULL) ? 0 : -1;
181 int unloadSound (int idx) {
182 SoundInfo *snd, *p;
184 for (p = NULL, snd = sndlist; snd != NULL; p = snd, snd = snd->next) {
185 if (snd->idx == idx) {
186 Mix_FreeChunk(snd->data);
187 if (p != NULL) p->next = snd->next; else sndlist = snd->next;
188 free(snd);
189 return 0;
193 return -1;
197 int isSoundLoaded (int idx) {
198 return findSound(idx) ? 1 : 0;
202 int playSound (int idx, int chan) {
203 if (!disableSound) {
204 SoundInfo *snd = findSound(idx);
206 if (snd == 0) {
207 if (loadSound(idx) != 0) return -1;
208 snd = findSound(idx);
209 if (snd == NULL) return -1;
212 return Mix_PlayChannel(chan, snd->data, 0);
214 return -1;
218 int stopChannel (int chan) {
219 if (!disableSound) Mix_HaltChannel(chan);
220 return 0;
224 int isChannelPlaying (int chan) {
225 return Mix_Playing(chan);
229 void unloadAllSounds (void) {
230 Mix_HaltChannel(-1); // stop all sounds
231 while (sndlist != NULL) {
232 SoundInfo *c = sndlist;
234 sndlist = c->next;
235 Mix_FreeChunk(c->data);
236 free(c);
240 #else
242 int loadSound (int idx) {
243 return -1;
247 int unloadSound (int idx) {
248 return -1;
252 int isSoundLoaded (int idx) {
253 return 0;
257 int playSound (int idx, int chan) {
258 return -1;
262 int stopChannel (int chan) {
263 return 0;
267 int isChannelPlaying (int chan) {
268 return 0;
272 void unloadAllSounds (void) {
274 #endif
277 ////////////////////////////////////////////////////////////////////////////////
278 // return # of sprites loaded or <0 on error
279 int loadSpriteBankFromFile (SpriteBank *bank, const char *fname) {
280 Uint8 *buf;
281 int sz, pos;
283 if ((buf = loadDiskFileEx(fname, &sz)) == NULL) return -1;
284 if (sz < 3) { free(buf); return -1; }
285 pos = 0;
286 for (int f = bank->count-1; f >= 0; --f) {
287 SDL_FreeSurface(bank->spr[f][1]);
288 SDL_FreeSurface(bank->spr[f][0]);
290 bank->count = 0;
291 while (pos+4 <= sz) {
292 int h = ((Uint32)buf[pos+0])+256*((Uint32)buf[pos+1]);
293 int w = ((Uint32)buf[pos+2])+256*((Uint32)buf[pos+3]);
295 pos += 4;
296 if (h > 0 && w > 0) {
297 SDL_Surface *s0 = createSurface(w*2, h*2);
298 SDL_Surface *s1 = createSurface(w*2, h*2);
300 if (!s0 || !s1) { free(buf); return -1; }
302 for (int y = 0; y < h; ++y) {
303 for (int x = 0; x < w; ++x) {
304 if (pos < sz) {
305 putPixel2x(s0, x, y, buf[pos]);
306 putPixel2x(s1, w-x-1, y, buf[pos]);
307 ++pos;
311 bank->spr[bank->count][0] = s0;
312 bank->spr[bank->count][1] = s1;
313 ++(bank->count);
316 free(buf);
317 return bank->count;
321 ////////////////////////////////////////////////////////////////////////////////
322 typedef struct {
323 int x, y;
324 int bank;
325 int num;
326 int dir;
327 int inlevel;
328 } SpriteInfo;
331 typedef struct {
332 int count;
333 int size; // # of slots
334 SpriteInfo *list;
335 } SpriteLayer;
338 #define MAX_LAYER (63)
339 static SpriteLayer spLayers[MAX_LAYER+1];
340 static int spLayersInitialized = 0;
343 void clearSpriteLayers (void) {
344 if (!spLayersInitialized) {
345 for (int f = 0; f <= MAX_LAYER; ++f) {
346 spLayers[f].size = 0;
347 spLayers[f].list = NULL;
349 spLayersInitialized = 1;
351 for (int f = 0; f <= MAX_LAYER; ++f) spLayers[f].count = 0;
355 void addSpriteToLayer (int x, int y, int layer, int bank, int num, int dir, int inlevel) {
356 //fprintf(stderr, "*x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", x, y, layer, bank, num, dir, inlevel);
357 if (layer >= 0 && layer <= MAX_LAYER &&
358 bank >= 0 && bank <= 256 &&
359 num >= 0 && num < 256) {
361 if (spLayers[layer].count+1 >= spLayers[layer].size) {
362 int newsz = spLayers[layer].size+64;
363 SpriteInfo *n = realloc(spLayers[layer].list, newsz);
365 if (n == NULL) fatal("out of memory");
366 spLayers[layer].list = n;
367 spLayers[layer].size = newsz;
370 SpriteInfo *si = spLayers[layer].list+(spLayers[layer].count++);
372 si->x = x;
373 si->y = y;
374 si->bank = bank;
375 si->num = num;
376 si->dir = dir;
377 si->inlevel = inlevel;
382 void levelDrawSpriteLayers (SDL_Surface *frame, int visx, int visy, int visw, int vish) {
383 SDL_Rect rc;
385 rc.x = visx*2;
386 rc.y = visy*2;
387 rc.w = visw*2;
388 rc.h = vish*2;
389 SDL_SetClipRect(frame, &rc);
390 for (int f = MAX_LAYER; f >= 0; --f) {
391 SpriteInfo *list = spLayers[f].list;
393 if (list == NULL && spLayers[f].count != 0) {
394 fatal("WTF? f=%d; count=%d", f, spLayers[f].count);
396 for (int c = spLayers[f].count; c > 0; --c, ++list) {
397 if (list->inlevel &&
398 list->dir >= 0 && list->dir <= 1 &&
399 list->bank >= 0 && list->bank <= 256 &&
400 list->num >= 0 && list->num < banks[list->bank].count &&
401 banks[list->bank].spr[list->num][list->dir]) {
402 blitSurface2x(frame, visx+list->x, visy+list->y, banks[list->bank].spr[list->num][list->dir]);
407 SDL_SetClipRect(frame, NULL);
408 for (int f = MAX_LAYER; f >= 0; --f) {
409 SpriteInfo *list = spLayers[f].list;
411 if (list == NULL) continue;
412 for (int c = spLayers[f].count; c > 0; --c, ++list) {
413 //fprintf(stderr, ":x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", list->x, list->y, f, list->bank, list->num, list->dir, list->inlevel);
414 if (!list->inlevel &&
415 list->dir >= 0 && list->dir <= 1 &&
416 list->bank >= 0 && list->bank <= 256 &&
417 list->num >= 0 && list->num < banks[list->bank].count &&
418 banks[list->bank].spr[list->num][list->dir]) {
419 blitSurface2x(frame, list->x, list->y, banks[list->bank].spr[list->num][list->dir]);
426 ////////////////////////////////////////////////////////////////////////////////
427 typedef struct Poly {
428 struct Poly *next;
429 int ofsx;
430 int ofsy;
431 int scale;
432 int angle;
433 int color;
434 int alpha;
435 int size;
436 int used;
437 int *points;
438 } Poly;
441 static Poly *plist = NULL, *ptail = NULL;
444 void pmClear (void) {
445 while (plist != NULL) {
446 Poly *c = plist;
448 plist = c->next;
449 if (c->points != NULL) free(c->points);
450 free(c);
452 ptail = plist = NULL;
456 void pmStart (int ofsx, int ofsy, int scale, int angle) {
457 Poly *p = calloc(1, sizeof(Poly));
459 if (p == NULL) fatal("out of memory");
460 p->ofsx = ofsx;
461 p->ofsy = ofsy;
462 p->scale = scale;
463 p->angle = angle;
464 p->points = NULL;
465 p->used = p->size = 0;
466 p->alpha = 0;
467 p->next = NULL;
468 if (ptail != NULL) ptail->next = p; else plist = p;
469 ptail = p;
473 void pmAddPoint (int x, int y) {
474 if (ptail != NULL) {
475 if (ptail->used+2 > ptail->size) {
476 int newsz = ptail->size+128;
477 int *np = realloc(ptail->points, newsz*sizeof(int));
479 if (np == NULL) fatal("out of memory");
480 ptail->points = np;
481 ptail->size = newsz;
483 ptail->points[ptail->used++] = x;
484 ptail->points[ptail->used++] = y;
489 void pmDone (int color, int alpha) {
490 if (ptail != NULL && ptail->used > 0) {
491 if (color < 0) color = 0; else if (color > 255) color = 255;
492 if (alpha < 0) alpha = 0; else if (alpha > 255) alpha = 255;
493 ptail->color = color;
494 ptail->alpha = alpha;
499 void pmDraw (SDL_Surface *frame) {
500 for (Poly *p = plist; p != NULL; p = p->next) {
501 if (p->used > 0 && p->alpha > 0) {
502 polymodStart(p->ofsx, p->ofsy, p->scale, p->angle);
503 for (int f = 0; f < p->used; f += 2) polymodAddPoint(p->points[f], p->points[f+1]);
504 polymodEnd();
505 polymodFill(frame, p->color, p->alpha);
511 ////////////////////////////////////////////////////////////////////////////////
512 typedef struct Text {
513 struct Text *next;
514 char *str;
515 int len;
516 int x;
517 int y;
518 int scale;
519 int angle;
520 int color;
521 int alpha;
522 } Text;
525 static Text *tlist = NULL, *ttail = NULL;
528 void textClear (void) {
529 while (tlist != NULL) {
530 Text *c = tlist;
532 tlist = c->next;
533 if (c->str) free(c->str);
534 free(c);
536 ttail = NULL;
540 void textAdd (const char *str, int len, int x, int y, int scale, int angle, int color, int alpha) {
541 Text *p;
543 if (str == NULL) return;
544 if (len < 0) len = strlen(str);
545 if ((p = calloc(1, sizeof(Text))) == NULL) fatal("out of memory");
546 if ((p->str = calloc(len+1, 1)) == NULL) { free(p); fatal("out of memory"); }
547 if (color < 0) color = 0; else if (color > 255) color = 255;
548 if (alpha < 0) alpha = 0; else if (alpha > 255) alpha = 255;
549 p->x = x;
550 p->y = y;
551 p->scale = scale;
552 p->angle = angle;
553 p->color = color;
554 p->alpha = alpha;
555 if (len > 0) memcpy(p->str, str, len);
556 p->next = NULL;
557 if (ttail != NULL) ttail->next = p; else tlist = p;
558 ttail = p;
562 void textDraw (SDL_Surface *frame) {
563 for (Text *t = tlist; t != NULL; t = t->next) {
564 polymodStr(frame, t->str, t->x, t->y, t->scale, t->angle, t->color, t->alpha);