1 /*
2  * OpenTyrian: A modern cross-platform port of Tyrian
3  * Copyright (C) 2007-2009  The OpenTyrian Development Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 #include "keyboard.h"
20 #include "opentyr.h"
21 #include "palette.h"
22 #include "video.h"
23 #include "video_scale.h"
24 
25 #include <assert.h>
26 #include <stdbool.h>
27 
28 bool fullscreen_enabled = false;
29 
30 SDL_Surface *VGAScreen, *VGAScreenSeg;
31 SDL_Surface *VGAScreen2;
32 SDL_Surface *game_screen;
33 
34 static ScalerFunction scaler_function;
35 
init_video(void)36 void init_video( void )
37 {
38 	if (SDL_WasInit(SDL_INIT_VIDEO))
39 		return;
40 
41 	if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1)
42 	{
43 		fprintf(stderr, "error: failed to initialize SDL video: %s\n", SDL_GetError());
44 		exit(1);
45 	}
46 
47 	SDL_WM_SetCaption("OpenTyrian", NULL);
48 
49 	VGAScreen = VGAScreenSeg = SDL_CreateRGBSurface(SDL_SWSURFACE, vga_width, vga_height, 8, 0, 0, 0, 0);
50 	VGAScreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, vga_width, vga_height, 8, 0, 0, 0, 0);
51 	game_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, vga_width, vga_height, 8, 0, 0, 0, 0);
52 
53 	SDL_FillRect(VGAScreen, NULL, 0);
54 
55 	if (!init_scaler(scaler, fullscreen_enabled) &&  // try desired scaler and desired fullscreen state
56 	    !init_any_scaler(fullscreen_enabled) &&      // try any scaler in desired fullscreen state
57 	    !init_any_scaler(!fullscreen_enabled))       // try any scaler in other fullscreen state
58 	{
59 		fprintf(stderr, "error: failed to initialize any supported video mode\n");
60 		exit(EXIT_FAILURE);
61 	}
62 }
63 
can_init_scaler(unsigned int new_scaler,bool fullscreen)64 int can_init_scaler( unsigned int new_scaler, bool fullscreen )
65 {
66 	if (new_scaler >= scalers_count)
67 		return false;
68 
69 	int w = scalers[new_scaler].width,
70 	    h = scalers[new_scaler].height;
71 	int flags = SDL_SWSURFACE | SDL_HWPALETTE | (fullscreen ? SDL_FULLSCREEN : 0);
72 
73 	// test each bitdepth
74 	for (uint bpp = 32; bpp > 0; bpp -= 8)
75 	{
76 		uint temp_bpp = SDL_VideoModeOK(w, h, bpp, flags);
77 
78 		if ((temp_bpp == 32 && scalers[new_scaler].scaler32) ||
79 		    (temp_bpp == 16 && scalers[new_scaler].scaler16) ||
80 		    (temp_bpp == 8  && scalers[new_scaler].scaler8 ))
81 		{
82 			return temp_bpp;
83 		}
84 		else if (temp_bpp == 24 && scalers[new_scaler].scaler32)
85 		{
86 			// scalers don't support 24 bpp because it's a pain
87 			// so let SDL handle the conversion
88 			return 32;
89 		}
90 	}
91 
92 	return 0;
93 }
94 
init_scaler(unsigned int new_scaler,bool fullscreen)95 bool init_scaler( unsigned int new_scaler, bool fullscreen )
96 {
97 	int w = scalers[new_scaler].width,
98 	    h = scalers[new_scaler].height;
99 	int bpp = can_init_scaler(new_scaler, fullscreen);
100 	int flags = SDL_SWSURFACE | SDL_HWPALETTE | (fullscreen ? SDL_FULLSCREEN : 0);
101 
102 	if (bpp == 0)
103 		return false;
104 
105 	SDL_Surface *const surface = SDL_SetVideoMode(w, h, bpp, flags);
106 
107 	if (surface == NULL)
108 	{
109 		fprintf(stderr, "error: failed to initialize %s video mode %dx%dx%d: %s\n", fullscreen ? "fullscreen" : "windowed", w, h, bpp, SDL_GetError());
110 		return false;
111 	}
112 
113 	w = surface->w;
114 	h = surface->h;
115 	bpp = surface->format->BitsPerPixel;
116 
117 	printf("initialized video: %dx%dx%d %s\n", w, h, bpp, fullscreen ? "fullscreen" : "windowed");
118 
119 	scaler = new_scaler;
120 	fullscreen_enabled = fullscreen;
121 
122 	switch (bpp)
123 	{
124 	case 32:
125 		scaler_function = scalers[scaler].scaler32;
126 		break;
127 	case 16:
128 		scaler_function = scalers[scaler].scaler16;
129 		break;
130 	case 8:
131 		scaler_function = scalers[scaler].scaler8;
132 		break;
133 	default:
134 		scaler_function = NULL;
135 		break;
136 	}
137 
138 	if (scaler_function == NULL)
139 	{
140 		assert(false);
141 		return false;
142 	}
143 
144 	input_grab(input_grab_enabled);
145 
146 	JE_showVGA();
147 
148 	return true;
149 }
150 
can_init_any_scaler(bool fullscreen)151 bool can_init_any_scaler( bool fullscreen )
152 {
153 	for (int i = scalers_count - 1; i >= 0; --i)
154 		if (can_init_scaler(i, fullscreen) != 0)
155 			return true;
156 
157 	return false;
158 }
159 
init_any_scaler(bool fullscreen)160 bool init_any_scaler( bool fullscreen )
161 {
162 	// attempts all scalers from last to first
163 	for (int i = scalers_count - 1; i >= 0; --i)
164 		if (init_scaler(i, fullscreen))
165 			return true;
166 
167 	return false;
168 }
169 
deinit_video(void)170 void deinit_video( void )
171 {
172 	SDL_FreeSurface(VGAScreenSeg);
173 	SDL_FreeSurface(VGAScreen2);
174 	SDL_FreeSurface(game_screen);
175 
176 	SDL_QuitSubSystem(SDL_INIT_VIDEO);
177 }
178 
JE_clr256(SDL_Surface * screen)179 void JE_clr256( SDL_Surface * screen)
180 {
181 	memset(screen->pixels, 0, screen->pitch * screen->h);
182 }
JE_showVGA(void)183 void JE_showVGA( void ) { scale_and_flip(VGAScreen); }
184 
scale_and_flip(SDL_Surface * src_surface)185 void scale_and_flip( SDL_Surface *src_surface )
186 {
187 	assert(src_surface->format->BitsPerPixel == 8);
188 
189 	SDL_Surface *dst_surface = SDL_GetVideoSurface();
190 
191 	assert(scaler_function != NULL);
192 	scaler_function(src_surface, dst_surface);
193 
194 	SDL_Flip(dst_surface);
195 }
196 
197