1 /*
2 	Falcon VIDEL emulation, with zoom
3 
4 	(C) 2006-2007 ARAnyM developer team
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 2 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with this program; if not, write to the Free Software
18 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include "sysdeps.h"
22 #include "parameters.h"
23 #include "hostscreen.h"
24 #include "host.h"
25 #include "icio.h"
26 #include "host_surface.h"
27 #include "videl.h"
28 #include "videl_zoom.h"
29 
30 #define DEBUG 0
31 #include "debug.h"
32 
33 #define HW	getHWoffset()
34 
VidelZoom(memptr addr,uint32 size)35 VidelZoom::VidelZoom(memptr addr, uint32 size) :
36 	VIDEL(addr, size), surface(NULL),
37 	zoomWidth(0), zoomHeight(0),
38 	prevWidth(0), prevHeight(0), prevBpp(0),
39 	xtable(NULL), ytable(NULL)
40 {
41 	reset();
42 }
43 
~VidelZoom(void)44 VidelZoom::~VidelZoom(void)
45 {
46 	if (surface) {
47 		host->video->destroySurface(surface);
48 	}
49 	if (xtable) {
50 		delete [] xtable;
51 	}
52 	if (ytable) {
53 		delete [] ytable;
54 	}
55 }
56 
reset(void)57 void VidelZoom::reset(void)
58 {
59 	VIDEL::reset();
60 }
61 
getSurface(void)62 HostSurface *VidelZoom::getSurface(void)
63 {
64 	HostSurface *videl_hsurf = VIDEL::getSurface();
65 	if (!videl_hsurf) {
66 		return NULL;
67 	}
68 
69 	int videlWidth = videl_hsurf->getWidth();
70 	int videlHeight = videl_hsurf->getHeight();
71 	int videlBpp = videl_hsurf->getBpp();
72 
73 	int hostWidth = host->video->getWidth();
74 	int hostHeight = host->video->getHeight();
75 	int autozoom_enabled = bx_options.autozoom.enabled;
76 
77 	zoomWidth = hostWidth;
78 	zoomHeight = hostHeight;
79 	if ((hostWidth>=videlWidth) && (hostHeight>=videlHeight)) {
80 		if (autozoom_enabled) {
81 			float coefx, coefy;
82 			coefx = (float) hostWidth / (videlWidth * aspect_x);
83 			coefy = (float) hostHeight / (videlHeight * aspect_y);
84 			if (bx_options.autozoom.integercoefs) {
85 				/* Integer coefs */
86 				coefx = (float) ((int) coefx);
87 				coefy = (float) ((int) coefy);
88 			}
89 			/* Keep aspect ratio by using smallest coef */
90 			if (coefx < coefy) {
91 				coefy = coefx;
92 			} else {
93 				coefx = coefy;
94 			}
95 			zoomWidth = videlWidth * aspect_x * coefx;
96 			zoomHeight = videlHeight * aspect_y * coefy;
97 		} else if ((aspect_x>1) || (aspect_y>1)) {
98 			zoomWidth = videlWidth * aspect_x;
99 			zoomHeight = videlHeight * aspect_y;
100 			autozoom_enabled = 1;
101 		}
102 	}
103 
104 	/* Return non zoomed surface if correct size, or zoom not suitable */
105 	if (bx_options.opengl.enabled || !autozoom_enabled ||
106 		((zoomWidth==videlWidth) && (zoomHeight==videlHeight))) {
107 		return videl_hsurf;
108 	}
109 
110 	/* Recalc zoom table if videl or host screen size changes */
111 	bool updateZoomTable = (!xtable || !ytable);
112 	if (prevVidelBpp!=videlBpp) {
113 		updateZoomTable=true;
114 		prevVidelBpp=videlBpp;
115 	}
116 	if (prevVidelWidth!=videlWidth) {
117 		updateZoomTable=true;
118 		prevVidelWidth=videlWidth;
119 	}
120 	if (prevVidelHeight!=videlHeight) {
121 		updateZoomTable=true;
122 		prevVidelHeight=videlHeight;
123 	}
124 
125 	/* Recreate surface if needed */
126 	if (surface) {
127 		if (prevBpp == videlBpp) {
128 			if ((prevWidth!=zoomWidth) || (prevHeight!=zoomHeight)) {
129 				surface->resize(zoomWidth, zoomHeight);
130 				updateZoomTable = true;
131 			}
132 		} else {
133 			delete surface;
134 			surface = NULL;
135 		}
136 	}
137 	if (surface==NULL) {
138 		surface = host->video->createSurface(zoomWidth,zoomHeight,videlBpp);
139 		updateZoomTable = true;
140 	}
141 
142 	prevWidth = zoomWidth;
143 	prevHeight = zoomHeight;
144 	prevBpp = videlBpp;
145 
146 	/* Update zoom tables if needed */
147 	if (updateZoomTable) {
148 		int i;
149 
150 		if (xtable) {
151 			delete [] xtable;
152 		}
153 		xtable = new int[zoomWidth];
154 		for (i=0; i<zoomWidth; i++) {
155 			xtable[i] = (i*videlWidth)/zoomWidth;
156 		}
157 
158 		if (ytable) {
159 			delete [] ytable;
160 		}
161 		ytable = new int[zoomHeight];
162 		for (i=0; i<zoomHeight; i++) {
163 			ytable[i] = (i*videlHeight)/zoomHeight;
164 		}
165 	}
166 
167 	/* Refresh dirty parts of non zoomed surface to zoomed surface */
168 	refreshScreen();
169 
170 	return surface;
171 }
172 
forceRefresh(void)173 void VidelZoom::forceRefresh(void)
174 {
175 	VIDEL::forceRefresh();
176 
177 	if (!surface) {
178 		return;
179 	}
180 
181 	surface->setDirtyRect(0,0,
182 		surface->getWidth(), surface->getHeight());
183 }
184 
refreshScreen(void)185 void VidelZoom::refreshScreen(void)
186 {
187 	HostSurface *videl_hsurf = VIDEL::getSurface();
188 	if (!videl_hsurf) {
189 		return;
190 	}
191 	SDL_Surface *videl_surf = videl_hsurf->getSdlSurface();
192 	if (!videl_surf) {
193 		return;
194 	}
195 
196 	if (!surface) {
197 		return;
198 	}
199 	SDL_Surface *sdl_surf = surface->getSdlSurface();
200 	if (!sdl_surf) {
201 		return;
202 	}
203 
204 	/* Update palette from non zoomed surface */
205 	if ((videl_hsurf->getBpp()==8) && (surface->getBpp()==8)) {
206 		int i;
207 		SDL_Color palette[256];
208 		for (i=0;i<256;i++) {
209 			palette[i].r = videl_surf->format->palette->colors[i].r;
210 			palette[i].g = videl_surf->format->palette->colors[i].g;
211 			palette[i].b = videl_surf->format->palette->colors[i].b;
212 #if SDL_VERSION_ATLEAST(2, 0, 0)
213 			palette[i].a = videl_surf->format->palette->colors[i].a;
214 #endif
215 		}
216 		surface->setPalette(palette, 0, 256);
217 	}
218 
219 	int videlWidth = videl_hsurf->getWidth();
220 	int videlHeight = videl_hsurf->getHeight();
221 	int videlBpp = videl_hsurf->getBpp();
222 
223 	Uint8 *dirtyRects = videl_hsurf->getDirtyRects();
224 	if (!dirtyRects) {
225 		return;
226 	}
227 
228 	int dirty_w = videl_hsurf->getDirtyWidth();
229 	int dirty_h = videl_hsurf->getDirtyHeight();
230 
231 	int x,y;
232 	for (y=0;y<dirty_h;y++) {
233 		/* Atari screen may not have a multiple of 16 lines */
234 		int num_lines = videl_hsurf->getHeight() - (y<<4);
235 		if (num_lines>16) {
236 			num_lines=16;
237 		}
238 		for (x=0;x<dirty_w;x++) {
239 			if (!dirtyRects[y * dirty_w + x]) {
240 				continue;
241 			}
242 
243 			/* Zoom 16x16 block */
244 			int dst_x1 = ((x<<4) * zoomWidth) / videlWidth;
245 			int dst_x2 = (((x+1)<<4) * zoomWidth) / videlWidth;
246 			int dst_y1 = ((y<<4) * zoomHeight) / videlHeight;
247 			int dst_y2 = (((y<<4)+num_lines) * zoomHeight) / videlHeight;
248 
249 			int i,j;
250 
251 			Uint8 *dst = (Uint8 *) sdl_surf->pixels;
252 			dst += dst_y1 * sdl_surf->pitch;
253 			dst += dst_x1 * (videlBpp>>3);
254 
255 			if (videlBpp==16) {
256 				/* True color, 16 bits surface */
257 				Uint16 *dst_line = (Uint16 *) dst;
258 				for(j=dst_y1;j<dst_y2;j++) {
259 					Uint16 *src_col = (Uint16 *) videl_surf->pixels;
260 					src_col += ytable[j] * (videl_surf->pitch>>1);
261 					Uint16 *dst_col = dst_line;
262 					for(i=dst_x1;i<dst_x2;i++) {
263 						*dst_col++ = src_col[xtable[i]];
264 					}
265 					dst_line += sdl_surf->pitch >> 1;
266 				}
267 			} else {
268 				/* Bitplanes, 8 bits surface */
269 				Uint8 *dst_line = (Uint8 *) dst;
270 				for(j=dst_y1;j<dst_y2;j++) {
271 					Uint8 *src_col = (Uint8 *) videl_surf->pixels;
272 					src_col += ytable[j] * videl_surf->pitch;
273 					Uint8 *dst_col = dst_line;
274 					for(i=dst_x1;i<dst_x2;i++) {
275 						*dst_col++ = src_col[xtable[i]];
276 					}
277 					dst_line += sdl_surf->pitch;
278 				}
279 			}
280 
281 			surface->setDirtyRect(dst_x1,dst_y1,
282 				dst_x2-dst_x1,dst_y2-dst_y1);
283 		}
284 	}
285 
286 	/* Mark original surface as updated */
287 	videl_hsurf->clearDirtyRects();
288 }
289