1 // Emacs style mode select -*- C++ -*-
2 //--------------------------------------------------------------------------
3 //
4 // $Id: video.c,v 1.3 2003/03/26 13:53:29 fraggle Exp $
5 //
6 // Copyright(C) 2001-2003 Simon Howard
7 //
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2 of the License, or (at your
11 // option) any later version. This program is distributed in the hope that
12 // it will be useful, but WITHOUT ANY WARRANTY; without even the implied
13 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14 // the GNU General Public License for more details. You should have
15 // received a copy of the GNU General Public License along with this
16 // program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 // Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 //--------------------------------------------------------------------------
20 //
21 // SDL Video Code
22 //
23 // By Simon Howard
24 //
25 //-----------------------------------------------------------------------
26
27 #include <SDL.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34
35 #include "video.h"
36 #include "sw.h"
37
38 #include "vid_vga.c"
39
40 // lcd mode to emulate my old laptop i used to play sopwith on :)
41
42 //#define LCD
43
44 static SDL_Color cga_pal[] = {
45 #ifdef LCD
46 {213, 226, 138}, {150, 160, 150},
47 {120, 120, 160}, {0, 20, 200},
48 #else
49 {0, 0, 0}, {0, 255, 255},
50 {255, 0, 255}, {255, 255, 255},
51 #endif
52 };
53
54 BOOL vid_fullscreen = FALSE;
55 BOOL vid_double_size = TRUE;
56
57 BOOL use_custom_keys = FALSE;
58 char custom_keys[NUM_KEYS];
59
60
61 static int ctrlbreak = 0;
62 static BOOL initted = 0;
63 static SDL_Surface *screen;
64 static SDL_Surface *screenbuf = NULL; // draw into buffer in 2x mode
65 static int colors[16];
66
getcolor(int r,int g,int b)67 static int getcolor(int r, int g, int b)
68 {
69 SDL_Palette *pal = screen->format->palette;
70 int i;
71 int nearest = 0xffff, n = 0;
72
73 for (i = 0; i < pal->ncolors; ++i) {
74 int diff =
75 (r - pal->colors[i].r) * (r - pal->colors[i].r) +
76 (g - pal->colors[i].g) * (g - pal->colors[i].g) +
77 (b - pal->colors[i].b) * (b - pal->colors[i].b);
78
79 // printf("%i, %i, %i\n",
80 // pal->colors[i].r, pal->colors[i].g,
81 // pal->colors[i].b);
82
83 if (!diff)
84 return i;
85
86 if (diff < nearest) {
87 nearest = diff;
88 n = i;
89 }
90 }
91
92 return n;
93 }
94
95 // convert a sopsym_t into a surface
96
surface_from_sopsym(sopsym_t * sym)97 SDL_Surface *surface_from_sopsym(sopsym_t *sym)
98 {
99 SDL_Surface *surface = SDL_CreateRGBSurface(0, sym->w, sym->h, 8,
100 0, 0, 0, 0);
101 unsigned char *p1, *p2;
102 int y;
103
104 if (!surface)
105 return NULL;
106
107 // set palette
108
109 SDL_SetColors(surface, cga_pal, 0, sizeof(cga_pal)/sizeof(*cga_pal));
110
111 SDL_LockSurface(surface);
112
113 p1 = sym->data;
114 p2 = (unsigned char *) surface->pixels;
115
116 // copy data from symbol into surface
117
118 for (y=0; y<sym->h; ++y, p1 += sym->w, p2 += surface->pitch)
119 memcpy(p2, p1, sym->w);
120
121 SDL_UnlockSurface(surface);
122
123 return surface;
124 }
125
126 // 2x scale
127
Vid_UpdateScaled()128 static void Vid_UpdateScaled()
129 {
130 register char *pixels = (char *) screen->pixels;
131 register char *pixels2 = (char *) screenbuf->pixels;
132 register int pitch = screen->pitch;
133 register int pitch2 = screenbuf->pitch;
134 register int x, y;
135
136 SDL_LockSurface(screen);
137 SDL_LockSurface(screenbuf);
138
139 for (y = 0; y < SCR_HGHT; ++y) {
140 register char *p = pixels;
141 register char *p2 = pixels2;
142
143 for (x=0; x<SCR_WDTH; ++x) {
144 p[0] = p[1] = p[pitch] = p[pitch + 1] = *p2++;
145 p += 2;
146 }
147
148 pixels += pitch * 2;
149 pixels2 += pitch2;
150 }
151
152 SDL_UnlockSurface(screenbuf);
153 SDL_UnlockSurface(screen);
154 }
155
Vid_Update()156 void Vid_Update()
157 {
158 if (!initted)
159 Vid_Init();
160
161 SDL_UnlockSurface(screenbuf);
162
163 if (vid_double_size)
164 Vid_UpdateScaled();
165 else
166 SDL_BlitSurface(screenbuf, NULL, screen, NULL);
167
168 SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
169
170 SDL_LockSurface(screenbuf);
171 }
172
set_icon(sopsym_t * sym)173 static void set_icon(sopsym_t *sym)
174 {
175 unsigned char *pixels;
176 unsigned char *mask;
177 SDL_Surface *icon = surface_from_sopsym(sym);
178 int mask_size;
179 int i;
180 int x, y;
181
182 if (!icon)
183 return;
184
185 // generate mask from icon
186
187 mask_size = (icon->w * icon->h) / 8 + 1;
188
189 mask = (unsigned char *)malloc(mask_size);
190
191 SDL_LockSurface(icon);
192
193 pixels = (unsigned char *)icon->pixels;
194
195 i = 0;
196
197 for (y=0; y<icon->h; y++) {
198 for (x=0; x<icon->w; x++) {
199 if (i % 8) {
200 mask[i / 8] <<= 1;
201 } else {
202 mask[i / 8] = 0;
203 }
204
205 if (pixels[i])
206 mask[i / 8] |= 0x01;
207
208 ++i;
209 }
210 }
211
212 SDL_UnlockSurface(icon);
213
214 // set icon
215
216 SDL_WM_SetIcon(icon, mask);
217
218 SDL_FreeSurface(icon);
219 free(mask);
220 }
221
222
Vid_UnsetMode()223 static void Vid_UnsetMode()
224 {
225 SDL_QuitSubSystem(SDL_INIT_VIDEO);
226 }
227
228
229
230 /* This function attempts to load custom
231 key definitions from a text file, located at
232 ~/.sopwith/keys
233 The function returns TRUE if keys are found and
234 loaded. It returns FALSE if keys are not loaded.
235 Keys are saved in the custom_keys array.
236 */
Load_Custom_Keys()237 BOOL Load_Custom_Keys()
238 {
239 FILE *key_file;
240 char *file_path;
241 int index;
242 char *home_dir;
243 char line[256], *status;
244
245 // get file path
246 #ifndef WIN32
247 home_dir = getenv("HOME");
248 #else
249 home_dir = getenv("AppData");
250 #endif
251 file_path = (char *) calloc( strlen(home_dir) + 64, sizeof(char));
252 if (! file_path)
253 return FALSE;
254 sprintf(file_path, "%s/.sopwith/keys", home_dir);
255
256 // try to open key file
257 key_file = fopen(file_path, "r");
258 if (key_file)
259 {
260 // set all keys to be their defaults in case
261 // something goes wrong
262 for (index = 0; index < NUM_KEYS; index++)
263 custom_keys[index] = index;
264
265 // load keys from the file
266 status = fgets(line, 256, key_file);
267 while (status)
268 {
269 if (! strncmp(line, "pullup", 6) )
270 sscanf(& (line[7]), "%c", &custom_keys[KEY_PULLUP]);
271 else if (! strncmp(line, "pulldown", 8) )
272 sscanf(& (line[9]), "%c", &custom_keys[KEY_PULLDOWN]);
273 else if (! strncmp(line, "pulldown", 8) )
274 sscanf(& (line[9]), "%c", &custom_keys[KEY_PULLDOWN]);
275 else if (! strncmp(line, "flip", 4) )
276 sscanf(& (line[5]), "%c", &custom_keys[KEY_FLIP]);
277 else if (! strncmp(line, "bomb", 4) )
278 sscanf(& (line[5]), "%c", &custom_keys[KEY_BOMB]);
279 else if (! strncmp(line, "fire", 4) )
280 sscanf(& (line[5]), "%c", &custom_keys[KEY_FIRE]);
281 else if (! strncmp(line, "home", 4) )
282 sscanf(& (line[5]), "%c", &custom_keys[KEY_HOME]);
283 else if (! strncmp(line, "missile", 7) )
284 sscanf(& (line[8]), "%c", &custom_keys[KEY_MISSILE]);
285 else if (! strncmp(line, "starburst", 9) )
286 sscanf(& (line[10]), "%c", &custom_keys[KEY_STARBURST]);
287 else if (! strncmp(line, "accel", 5) )
288 sscanf(& (line[6]), "%c", &custom_keys[KEY_ACCEL]);
289 else if (! strncmp(line, "decel", 5) )
290 sscanf(& (line[6]), "%c", &custom_keys[KEY_DECEL]);
291 else if (! strncmp(line, "sound", 5) )
292 sscanf(& (line[6]), "%c", &custom_keys[KEY_SOUND]);
293 status = fgets(line, 256, key_file);
294 }
295 // close file
296 fclose(key_file);
297 } // end of we opened thefile
298 free(file_path);
299
300 /* debug stuff
301 for (index = 0; index < NUM_KEYS; index++)
302 printf("%d %c\n", index, custom_keys[index]);
303 */
304 return TRUE;
305 }
306
307
308 /*
309 This function creates a custom key file in our
310 home directory.
311 */
Create_Custom_File()312 void Create_Custom_File()
313 {
314 char *path_to_file;
315 FILE *key_file;
316 char *home_dir;
317
318 #ifndef WIN32
319 home_dir = getenv("HOME");
320 #else
321 home_dir = getenv("AppData");
322 #endif
323 path_to_file = (char *) calloc( strlen(home_dir) + 64, sizeof(char));
324 if (! path_to_file)
325 return;
326 // check to see if file already exists
327 sprintf(path_to_file, "%s/.sopwith/keys", home_dir);
328 key_file = fopen(path_to_file, "r");
329 if (key_file)
330 {
331 fclose(key_file);
332 free(path_to_file);
333 return;
334 }
335 sprintf(path_to_file, "%s/.sopwith", home_dir);
336 #ifndef WIN32
337 mkdir(path_to_file, 0700);
338 #else
339 mkdir(path_to_file);
340 #endif
341 // create file
342 sprintf(path_to_file, "%s/.sopwith/keys", home_dir);
343 key_file = fopen(path_to_file, "w");
344 if (key_file)
345 {
346 fprintf(key_file, "pullup ,\n");
347 fprintf(key_file, "pulldown /\n");
348 fprintf(key_file, "flip . \n");
349 fprintf(key_file, "bomb b\n");
350 fprintf(key_file, "fire \n");
351 fprintf(key_file, "home h\n");
352 fprintf(key_file, "missile m\n");
353 fprintf(key_file, "starburst v\n");
354 fprintf(key_file, "accel x\n");
355 fprintf(key_file, "decel z\n");
356 fprintf(key_file, "sound s\n");
357 fclose(key_file);
358 }
359 }
360
361
Vid_SetMode()362 static void Vid_SetMode()
363 {
364 int n;
365 int w, h;
366 int flags = 0;
367 int status;
368
369 printf("CGA Screen Emulation\n");
370 printf("init screen: ");
371
372 status = SDL_Init(SDL_INIT_VIDEO);
373 if (status == -1)
374 {
375 fprintf(stderr, "Unable to locate video device. Exiting.\n");
376 exit(1);
377 }
378 srand(time(NULL));
379 set_icon(symbol_plane[rand() % 2][rand() % 16]);
380
381 w = SCR_WDTH;
382 h = SCR_HGHT;
383
384 if (vid_double_size) {
385 w *= 2;
386 h *= 2;
387 }
388
389 flags = SDL_HWPALETTE;
390 if (vid_fullscreen)
391 flags |= SDL_FULLSCREEN;
392
393 screen = SDL_SetVideoMode(w, h, 8, flags);
394
395 if (screen) {
396 printf("initialised\n");
397 } else {
398 printf("failed\n");
399 fprintf(stderr, "cant init SDL\n");
400 exit(-1);
401 }
402
403 SDL_EnableUNICODE(1);
404
405 for (n = 0; n < NUM_KEYS; ++n)
406 keysdown[n] = 0;
407
408 SDL_WM_SetCaption("SDL Sopwith", NULL);
409
410 SDL_SetColors(screen, cga_pal, 0, sizeof(cga_pal)/sizeof(*cga_pal));
411 SDL_SetColors(screenbuf, cga_pal, 0, sizeof(cga_pal)/sizeof(*cga_pal));
412
413 // create custom key file
414 Create_Custom_File();
415 // load custom keys
416 use_custom_keys = Load_Custom_Keys();
417 }
418
Vid_Shutdown()419 void Vid_Shutdown()
420 {
421 if (!initted)
422 return;
423
424 Vid_UnsetMode();
425
426 SDL_FreeSurface(screenbuf);
427
428 initted = 0;
429 }
430
Vid_Init()431 void Vid_Init()
432 {
433 if (initted)
434 return;
435
436 fflush(stdout);
437
438 screenbuf = SDL_CreateRGBSurface(0, SCR_WDTH, SCR_HGHT, 8,
439 0, 0, 0, 0);
440 vid_vram = screenbuf->pixels;
441 vid_pitch = screenbuf->pitch;
442
443 Vid_SetMode();
444
445 initted = 1;
446
447 atexit(Vid_Shutdown);
448
449 SDL_LockSurface(screenbuf);
450 }
451
Vid_Reset()452 void Vid_Reset()
453 {
454 if (!initted)
455 return;
456
457 Vid_UnsetMode();
458 Vid_SetMode();
459
460 // need to redraw buffer to screen
461
462 Vid_Update();
463 }
464
465 static int input_buffer[128];
466 static int input_buffer_head=0, input_buffer_tail=0;
467
input_buffer_push(int c)468 static void input_buffer_push(int c)
469 {
470 input_buffer[input_buffer_tail++] = c;
471 input_buffer_tail %= sizeof(input_buffer) / sizeof(*input_buffer);
472 }
473
input_buffer_pop()474 static int input_buffer_pop()
475 {
476 int c;
477
478 if (input_buffer_head == input_buffer_tail)
479 return 0;
480
481 c = input_buffer[input_buffer_head++];
482
483 input_buffer_head %= sizeof(input_buffer) / sizeof(*input_buffer);
484
485 return c;
486 }
487
488
489 /*
490 This function is called when we have loaded custom key mapping.
491 It passes back our key to translate_key.
492 */
translate_custom_key(int the_key)493 sopkey_t translate_custom_key(int the_key)
494 {
495 char my_key;
496 int index, found;
497 index = found = 0;
498 my_key = (char) the_key;
499
500 while ( (index < NUM_KEYS) && (! found) )
501 {
502 if (my_key == custom_keys[index])
503 found = 1;
504 else
505 index++;
506 }
507 if (found)
508 return index;
509 else
510 return KEY_UNKNOWN;
511 }
512
513
translate_key(int sdl_key)514 static sopkey_t translate_key(int sdl_key)
515 {
516 if (use_custom_keys)
517 return translate_custom_key(sdl_key);
518 switch (sdl_key) {
519 case SDLK_LEFT:
520 case SDLK_COMMA:
521 return KEY_PULLUP;
522 case SDLK_RIGHT:
523 case SDLK_SLASH:
524 return KEY_PULLDOWN;
525 case SDLK_DOWN:
526 case SDLK_PERIOD:
527 return KEY_FLIP;
528 case SDLK_x:
529 return KEY_ACCEL;
530 case SDLK_z:
531 return KEY_DECEL;
532 case SDLK_b:
533 return KEY_BOMB;
534 case SDLK_SPACE:
535 return KEY_FIRE;
536 case SDLK_h:
537 return KEY_HOME;
538 case SDLK_v:
539 return KEY_MISSILE;
540 case SDLK_c:
541 return KEY_STARBURST;
542 case SDLK_s:
543 return KEY_SOUND;
544 default:
545 return KEY_UNKNOWN;
546 }
547 }
548
getevents()549 static void getevents()
550 {
551 SDL_Event event;
552 static BOOL ctrldown = 0, altdown = 0;
553 sopkey_t translated;
554
555 while (SDL_PollEvent(&event)) {
556 switch (event.type) {
557 case SDL_KEYDOWN:
558 if (event.key.keysym.sym == SDLK_LALT)
559 altdown = 1;
560 else if (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL)
561 ctrldown = 1;
562 else if (ctrldown &&
563 (event.key.keysym.sym == SDLK_c ||
564 event.key.keysym.sym == SDLK_BREAK)) {
565 ++ctrlbreak;
566 if (ctrlbreak >= 3) {
567 fprintf(stderr,
568 "user aborted with 3 ^C's\n");
569 exit(-1);
570 }
571 } else if (event.key.keysym.sym == SDLK_ESCAPE) {
572 input_buffer_push(27);
573 } else if (event.key.keysym.sym == SDLK_RETURN) {
574 if(altdown) {
575 vid_fullscreen = !vid_fullscreen;
576 Vid_Reset();
577 } else {
578 input_buffer_push('\n');
579 }
580 } else {
581 input_buffer_push(event.key.keysym.unicode & 0x7f);
582 }
583 translated = translate_key(event.key.keysym.sym);
584 if (translated)
585 keysdown[translated] |= 3;
586 break;
587 case SDL_KEYUP:
588 if (event.key.keysym.sym == SDLK_LALT)
589 altdown = 0;
590 else if (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL)
591 ctrldown = 0;
592 else {
593 translated = translate_key(event.key.keysym.sym);
594 if (translated)
595 keysdown[translated] &= ~1;
596 }
597 break;
598 }
599 }
600 }
601
Vid_GetKey()602 int Vid_GetKey()
603 {
604 int l;
605
606 getevents();
607
608 return input_buffer_pop();
609 }
610
Vid_GetCtrlBreak()611 BOOL Vid_GetCtrlBreak()
612 {
613 getevents();
614 return ctrlbreak;
615 }
616
617 //-----------------------------------------------------------------------
618 //
619 // $Log: video.c,v $
620 // Revision 1.3 2003/03/26 13:53:29 fraggle
621 // Allow control via arrow keys
622 // Some code restructuring, system-independent video.c added
623 //
624 // Revision 1.2 2003/03/26 12:02:38 fraggle
625 // Apply patch from David B. Harris (ElectricElf) for right ctrl key and
626 // documentation
627 //
628 // Revision 1.1.1.1 2003/02/14 19:03:37 fraggle
629 // Initial Sourceforge CVS import
630 //
631 //
632 // sdh 14/2/2003: change license header to GPL
633 // sdh 25/04/2002: rename vga_{pitch,vram} to vid_{pitch,vram}
634 // sdh 26/03/2002: now using platform specific vga code for drawing stuff
635 // (#include "vid_vga.c")
636 // rename CGA_ to Vid_
637 // sdh 17/11/2001: buffered input for keypresses,
638 // CGA_GetLastKey->CGA_GetKey
639 // sdh 07/11/2001: add CGA_Reset
640 // sdh 21/10/2001: added cvs tags
641 //
642 //-----------------------------------------------------------------------
643