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