1 /*
2 	NatFeat VDI driver
3 
4 	ARAnyM (C) 2005,2006 Patrice Mandin
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 "cpu_emulation.h"
23 #include "parameters.h"
24 #include "dirty_rects.h"
25 #include "host_surface.h"
26 #include "nfvdi.h"
27 #include "fvdidrv_nfapi.h"	// keep in sync with same file in fVDI CVS
28 #include "hostscreen.h"
29 #include "host.h"
30 
31 #include "cpu_emulation.h"
32 
33 #define DEBUG 0
34 #include "debug.h"
35 
36 #include <new>
37 
38 /*--- Defines ---*/
39 
40 #define EINVFN -32
41 
42 /*--- Types ---*/
43 
44 /*--- Variables ---*/
45 
46 /*--- Public functions ---*/
47 
dispatch(uint32 fncode)48 int32 VdiDriver::dispatch(uint32 fncode)
49 {
50 	int32 ret = EINVFN;
51 
52 	D(bug("nfvdi: dispatch(%u)", fncode));
53 
54 	if (fncode & 0x80000000) {
55 	    if (!events)
56 		return 1;
57 
58 	    fncode &= 0x7fffffff;
59 	    if (fncode & 0x8000) {
60 		mouse_x = fncode >> 16;
61 		mouse_y = fncode & 0x7fff;
62 		new_event |= 1;
63 	    } else {
64 		switch (fncode >> 28) {
65 		case 3:
66 		    buttons = ((fncode & 1) << 1) | ((fncode & 2) >> 1);
67 		    new_event |= 2;
68 		    break;
69 	        case 4:
70 		    wheel += (signed char)(fncode & 0xff);
71 		    new_event |= 4;
72 		    break;
73 	        case 5:
74 		    vblank++;
75 		    new_event |= 8;
76 		    break;
77 		}
78 	    }
79 	    TriggerInt3();
80 
81 	    return 0;
82 	}
83 
84 	if (fncode == FVDI_EVENT) {
85 	    memptr array = getParameter(0);
86 	    switch((int)array) {
87 	    case 0:
88 		return bx_options.nfvdi.use_host_mouse_cursor;
89 	    case 1:
90 		new_event = buttons = wheel = vblank = 0;
91 		events = 1;
92 		break;
93 	    default:
94 		int n = 0;
95 		if (new_event & 1) {
96 		    WriteInt32(array + n++ * 4, 2);
97 		    WriteInt32(array + n++ * 4,
98 		               (mouse_x << 16) | (mouse_y & 0xffff));
99 		}
100 		if (new_event & 2) {
101 		    WriteInt32(array + n++ * 4, 3);
102 		    WriteInt32(array + n++ * 4, buttons);
103 		}
104 		if (new_event & 4) {
105 		    WriteInt32(array + n++ * 4, 4);
106 		    WriteInt32(array + n++ * 4, 0x00000000 | (wheel & 0xffff));
107 		}
108 		if (new_event & 8) {
109 		    WriteInt32(array + n++ * 4, 5);
110 		    WriteInt32(array + n++ * 4, vblank);
111 		}
112 		if (n < 8)
113 		    WriteInt32(array + n * 4, 0);
114 		new_event = wheel = vblank = 0;
115 		break;
116 	    }
117 	    return 1;
118 	}
119 
120 	switch(fncode) {
121 		case FVDI_GET_VERSION:
122     		ret = FVDIDRV_NFAPI_VERSION;
123 			break;
124 		case FVDI_GET_PIXEL:
125 			ret = getPixel((memptr)getParameter(0),(memptr)getParameter(1),getParameter(2),getParameter(3));
126 			break;
127 		case FVDI_PUT_PIXEL:
128 			ret = putPixel((memptr)getParameter(0),(memptr)getParameter(1),getParameter(2),getParameter(3),getParameter(4));
129 			break;
130 		case FVDI_MOUSE:
131 			{
132 				// mode (0/1 - move, 2 - hide, 3 - show)
133 				// These are only valid when not mode
134 				uint32 mask = getParameter(3);
135 				if ( mask > 7 ) {
136 					ret = drawMouse((memptr)getParameter(0),	// wk
137 						getParameter(1), getParameter(2),	// x, y
138 						mask,                                // mask*
139 						getParameter(4),			            // data*
140 						getParameter(5), getParameter(6),	// hot_x, hot_y
141 						getParameter(7),			// fgColor
142 						getParameter(8),			// bgColor
143 						getParameter(9));			        // type
144 				} else {
145 					ret = drawMouse((memptr)getParameter(0),		        // wk
146 						getParameter(1), getParameter(2),	// x, y
147 						mask,
148 						0, 0, 0, 0, 0, 0); // dummy
149 				}
150 			}
151 			break;
152 		case FVDI_EXPAND_AREA:
153 			ret = expandArea((memptr)getParameter(0),		// vwk
154 			                    (memptr)getParameter(1),		// src MFDB*
155 			                    getParameter(2), getParameter(3),	// sx, sy
156 			                    (memptr)getParameter(4),		// dest MFDB*
157 			                    getParameter(5), getParameter(6),	// dx, dy
158 			                    getParameter(7),			// width
159 			                    getParameter(8),			// height
160 			                    getParameter(9),			// logical operation
161 			                  getParameter(10),			// fgColor
162 			                  getParameter(11));			// bgColor
163 			break;
164 		case FVDI_FILL_AREA:
165 			ret = fillArea((memptr)getParameter(0),		// vwk
166 			                  getParameter(1), getParameter(2),	// x, y
167 			                                               		// table*, table length/type (0 - y/x1/x2 spans)
168 			                  getParameter(3), getParameter(4),	// width, height
169 			                  (memptr)getParameter(5),		// pattern*
170 			                  getParameter(6),			// fgColor
171 			                  getParameter(7),			// bgColor
172 			                  getParameter(8),			// mode
173 			                  getParameter(9));			// interior style
174 			break;
175 		case FVDI_BLIT_AREA:
176 			ret = blitArea((memptr)getParameter(0),		// vwk
177 			                  (memptr)getParameter(1),		// src MFDB*
178 			                  getParameter(2), getParameter(3),	// sx, sy
179 			                  (memptr)getParameter(4),		// dest MFDB*
180 			                  getParameter(5), getParameter(6),	// dx, dy
181 			                  getParameter(7),			// width
182 			                  getParameter(8),			// height
183 			                  getParameter(9));			// logical operation
184 			break;
185 		case FVDI_LINE:
186 			ret = drawLine((memptr)getParameter(0),		// vwk
187 			                  getParameter(1), getParameter(2),	// x1, y1
188 			                                                	// table*, table length/type (0 - coordinate pairs, 1 - pairs + moves)
189 			                  getParameter(3), getParameter(4),	// x2, y2
190 			                                                	// move point count, move index*
191 			                  getParameter(5) & 0xffff,		// pattern
192 			                  getParameter(6),			// fgColor
193 			                  getParameter(7),			// bgColor
194 			                  getParameter(8) & 0xffff,		// logical operation
195 			                  (memptr)getParameter(9));		// clip rectangle* (0 or long[4])
196 			break;
197 		case FVDI_FILL_POLYGON:
198 			ret = fillPoly((memptr)getParameter(0),		// vwk
199 			                  (memptr)getParameter(1),		// points*
200 			                  getParameter(2),			// point count
201 			                  (memptr)getParameter(3),		// index*
202 			                  getParameter(4),			// index count
203 			                  (memptr)getParameter(5),		// pattern*
204 			                  getParameter(6),			// fgColor
205 			                  getParameter(7),			// bgColor
206 			                  getParameter(8),			// logic operation
207 			                  getParameter(9),			// interior style
208 			                  (memptr)getParameter(10));		// clip rectangle
209 			break;
210 		case FVDI_TEXT_AREA:
211 			ret = drawText((memptr)getParameter(0),		// vwk
212 			                  (memptr)getParameter(1),		// text*
213 			                  getParameter(2),			// length
214 			                  getParameter(3),			// dst_x
215 			                  getParameter(4),			// dst_y
216 			                  (memptr)getParameter(5),		// font*
217 			                  getParameter(6),			// width
218 			                  getParameter(7),			// height
219 			                  getParameter(8),			// fgColor
220 			                  getParameter(9),			// bgColor
221 			                  getParameter(10),			// logic operation
222 			                  (memptr)getParameter(11));		// clip rectangle
223 			break;
224 		case FVDI_GET_HWCOLOR:
225 			getHwColor(getParameter(0), getParameter(1), getParameter(2), getParameter(3), getParameter(4));
226 			break;
227 		case FVDI_SET_COLOR:
228 			setColor(getParameter(4), getParameter(0), getParameter(1), getParameter(2), getParameter(3));
229 			break;
230 		case FVDI_GET_FBADDR:
231 			ret = getFbAddr();
232 			break;
233 		case FVDI_SET_RESOLUTION:
234 			setResolution(getParameter(0),getParameter(1),getParameter(2));
235 			ret = 0;
236 			break;
237 		case FVDI_GET_WIDTH:
238 			ret = getWidth();
239 			break;
240 		case FVDI_GET_HEIGHT:
241 			ret = getHeight();
242 			break;
243 		case FVDI_OPENWK:
244 			ret = openWorkstation();
245 			break;
246 		case FVDI_CLOSEWK:
247 			ret = closeWorkstation();
248 			break;
249 		case FVDI_GETBPP:
250 			ret = getBpp();
251 			break;
252 		default:
253 			D(bug("nfvdi: unimplemented function #%d", fncode));
254 			break;
255 	}
256 
257 	D(bug("nfvdi: function returning with 0x%08x", ret));
258 	return ret;
259 }
260 
VdiDriver()261 VdiDriver::VdiDriver()
262 	: surface(NULL)
263 {
264 	index_count = crossing_count = point_count = 0;
265 	alloc_index = alloc_crossing = alloc_point = NULL;
266 	cursor = NULL;
267 	Mouse.storage.x = Mouse.storage.y = Mouse.storage.width = Mouse.storage.height = 0;
268 	events = 0;
269 }
270 
~VdiDriver()271 VdiDriver::~VdiDriver()
272 {
273 	delete[] alloc_index;
274 	delete[] alloc_crossing;
275 	delete[] alloc_point;
276 
277 	if (cursor) {
278 		SDL_FreeCursor(cursor);
279 		cursor = NULL;
280 	}
281 
282 	if (surface) {
283 		host->video->destroySurface(surface);
284 	}
285 }
286 
reset()287 void VdiDriver::reset()
288 {
289 	host->video->setVidelRendering(true);
290 }
291 
292 /*--- Protected functions ---*/
293 
chunkyToBitplane(uint8 * sdlPixelData,uint16 bpp,uint16 bitplaneWords[8])294 void VdiDriver::chunkyToBitplane(uint8 *sdlPixelData, uint16 bpp,
295 	uint16 bitplaneWords[8])
296 {
297 	DUNUSED(bpp);
298 	for (int l=0; l<16; l++) {
299 		uint8 data = sdlPixelData[l]; // note: this is about 2000 dryhstones speedup (the local variable)
300 
301 		bitplaneWords[0] <<= 1; bitplaneWords[0] |= (data >> 0) & 1;
302 		bitplaneWords[1] <<= 1; bitplaneWords[1] |= (data >> 1) & 1;
303 		bitplaneWords[2] <<= 1; bitplaneWords[2] |= (data >> 2) & 1;
304 		bitplaneWords[3] <<= 1; bitplaneWords[3] |= (data >> 3) & 1;
305 		bitplaneWords[4] <<= 1; bitplaneWords[4] |= (data >> 4) & 1;
306 		bitplaneWords[5] <<= 1; bitplaneWords[5] |= (data >> 5) & 1;
307 		bitplaneWords[6] <<= 1; bitplaneWords[6] |= (data >> 6) & 1;
308 		bitplaneWords[7] <<= 1; bitplaneWords[7] |= (data >> 7) & 1;
309 	}
310 }
311 
applyBlitLogOperation(int logicalOperation,uint32 destinationData,uint32 sourceData)312 uint32 VdiDriver::applyBlitLogOperation(int logicalOperation,
313 	uint32 destinationData, uint32 sourceData)
314 {
315 	switch(logicalOperation) {
316 		case ALL_WHITE:
317 			destinationData = 0;
318 			break;
319 		case S_AND_D:
320 			destinationData = sourceData & destinationData;
321 			break;
322 		case S_AND_NOTD:
323 			destinationData = sourceData & ~destinationData;
324 			break;
325 		case S_ONLY:
326 			destinationData = sourceData;
327 			break;
328 		case NOTS_AND_D:
329 			destinationData = ~sourceData & destinationData;
330 			break;
331 /*
332 		case D_ONLY:
333 			destinationData = destinationData;
334 			break;
335 */
336 		case S_XOR_D:
337 			destinationData = sourceData ^ destinationData;
338 			break;
339 		case S_OR_D:
340 			destinationData = sourceData | destinationData;
341 			break;
342 		case NOT_SORD:
343 			destinationData = ~(sourceData | destinationData);
344 			break;
345 		case NOT_SXORD:
346 			destinationData = ~(sourceData ^ destinationData);
347 			break;
348 		case D_INVERT:
349 			destinationData = ~destinationData;
350 			break;
351 		case S_OR_NOTD:
352 			destinationData = sourceData | ~destinationData;
353 			break;
354 		case NOT_S:
355 			destinationData = ~sourceData;
356 			break;
357 		case NOTS_OR_D:
358 			destinationData = ~sourceData | destinationData;
359 			break;
360 		case NOT_SANDD:
361 			destinationData = ~(sourceData & destinationData);
362 			break;
363 		case ALL_BLACK:
364 			destinationData = 0xffffffffUL;
365 			break;
366 	}
367 
368 	return destinationData;
369 }
370 
getSurface(void)371 HostSurface *VdiDriver::getSurface(void)
372 {
373 	return surface;
374 }
375 
setResolution(int32 width,int32 height,int32 depth)376 void VdiDriver::setResolution(int32 width, int32 height, int32 depth)
377 {
378 	if (bx_options.autozoom.fixedsize) {
379 		width = bx_options.autozoom.width;
380 		height = bx_options.autozoom.height;
381 		if ((bx_options.autozoom.width == 0)
382 		  && (bx_options.autozoom.height == 0))
383 		{
384 			width = host->video->getWidth();
385 			height = host->video->getHeight();
386 		}
387 	}
388 
389 	if (width<64) {
390 		width = 64;
391 	}
392 	if (height<64) {
393 		height = 64;
394 	}
395 	if (depth<8) {
396 		depth = 8;
397 	}
398 
399 	/* Recreate surface if needed */
400 	if (surface) {
401 		if (surface->getBpp() == depth) {
402 			if ((surface->getWidth() != width) || (surface->getHeight() != height)) {
403 				surface->resize(width, height);
404 			}
405 		} else {
406 			delete surface;
407 			surface = NULL;
408 		}
409 	}
410 	if (surface==NULL) {
411 		surface = host->video->createSurface(width,height,depth);
412 	}
413 
414 	/* TODO: restore palette ? */
415 }
416 
getWidth(void)417 int32 VdiDriver::getWidth(void)
418 {
419 	return (surface ? surface->getWidth() : 0);
420 }
421 
getHeight(void)422 int32 VdiDriver::getHeight(void)
423 {
424 	return (surface ? surface->getHeight() : 0);
425 }
426 
openWorkstation(void)427 int32 VdiDriver::openWorkstation(void)
428 {
429 	host->video->setVidelRendering(false);
430 	return 1;
431 }
432 
closeWorkstation(void)433 int32 VdiDriver::closeWorkstation(void)
434 {
435 	host->video->setVidelRendering(true);
436 	return 1;
437 }
438 
getBpp(void)439 int32 VdiDriver::getBpp(void)
440 {
441 	if (!surface) {
442 		return 0;
443 	}
444 	SDL_Surface *sdl_surf = surface->getSdlSurface();
445 	return (sdl_surf ? sdl_surf->format->BitsPerPixel : 0);
446 }
447 
448 // The polygon code needs some arrays of unknown size
449 // These routines and members are used so that no unnecessary allocations are done
AllocIndices(int n)450 bool VdiDriver::AllocIndices(int n)
451 {
452 	if (n > index_count) {
453 		D2(bug("More indices %d->%d\n", index_count, n));
454 		int count = n * 2;		// Take a few extra right away
455 		int16* tmp = new(std::nothrow) int16[count];
456 		if (!tmp) {
457 			count = n;
458 			tmp = new(std::nothrow) int16[count];
459 		}
460 		if (tmp) {
461 			delete[] alloc_index;
462 			alloc_index = tmp;
463 			index_count = count;
464 		}
465 	}
466 
467 	return index_count >= n;
468 }
469 
AllocCrossings(int n)470 bool VdiDriver::AllocCrossings(int n)
471 {
472 	if (n > crossing_count) {
473 		D2(bug("More crossings %d->%d\n", crossing_count, n));
474 		int count = n * 2;		// Take a few extra right away
475 		int16* tmp = new(std::nothrow) int16[count];
476 		if (!tmp) {
477 			count = (n * 3) / 2;	// Try not so many extra
478 			tmp = new(std::nothrow) int16[count];
479 		}
480 		if (!tmp) {
481 			count = n;		// This is going to be slow if it goes on...
482 			tmp = new(std::nothrow) int16[count];
483 		}
484 		if (tmp) {
485 			memcpy(tmp, alloc_crossing, crossing_count * sizeof(*alloc_crossing));
486 			delete[] alloc_crossing;
487 			alloc_crossing = tmp;
488 			crossing_count = count;
489 		}
490 	}
491 
492 	return crossing_count >= n;
493 }
494 
AllocPoints(int n)495 bool VdiDriver::AllocPoints(int n)
496 {
497 	if (n > point_count) {
498 		D2(bug("More points %d->%d", point_count, n));
499 		int count = n * 2;		// Take a few extra right away
500 		int16* tmp = new(std::nothrow) int16[count * 2];
501 		if (!tmp) {
502 			count = n;
503 			tmp = new(std::nothrow) int16[count * 2];
504 		}
505 		if (tmp) {
506 			delete[] alloc_point;
507 			alloc_point = tmp;
508 			point_count = count;
509 		}
510 	}
511 
512 	return point_count >= n;
513 }
514 
515 
516 /*--- Virtual functions ---*/
517 
518 /**
519  * Get a coloured pixel.
520  *
521  * c_read_pixel(Virtual *vwk, MFDB *mfdb, long x, long y)
522  * read_pixel
523  * In:  a1  VDI struct, source MFDB
524  *  d1  x
525  *  d2  y
526  *
527  * Only one mode here.
528  *
529  * Note that a1 does not point to the VDI struct, but to a place in memory
530  * where the VDI struct pointer can be found. Four bytes beyond that address
531  * is a pointer to the destination MFDB.
532  *
533  * Since an MFDB is passed, the source is not necessarily the screen.
534  **/
535 
getPixel(memptr vwk,memptr src,int32 x,int32 y)536 int32 VdiDriver::getPixel(memptr vwk, memptr src, int32 x, int32 y)
537 {
538 	DUNUSED(vwk);
539 	uint32 row_address, color = 0;
540 	uint16 planes;
541 
542 	if (!src) {
543 		D(bug("VdiDriver::getPixel(): source is NULL"));
544 		return color;
545 	}
546 
547 	planes = ReadInt16(src + MFDB_NPLANES);
548 	row_address = ReadInt32(src + MFDB_ADDRESS) +
549 		ReadInt16(src + MFDB_WDWIDTH) * 2 * planes * y;
550 
551 	switch (planes) {
552 		case 8:
553 			color = ReadInt8(row_address + x);
554 			break;
555 		case 16:
556 			color = ReadInt16(row_address + x * 2);
557 			break;
558 		case 24:
559 			color = ((uint32)ReadInt8(row_address + x * 3) << 16) +
560 				((uint32)ReadInt8(row_address + x * 3 + 1) << 8) +
561 				(uint32)ReadInt8(row_address + x * 3 + 2);
562 			break;
563 		case 32:
564 			color = ReadInt32(row_address + x * 4);
565 			break;
566 	}
567 
568 	return color;
569 }
570 
571 /**
572  * Set a coloured pixel.
573  *
574  * c_write_pixel(Virtual *vwk, MFDB *mfdb, long x, long y, long colour)
575  * write_pixel
576  * In:   a1  VDI struct, destination MFDB
577  *   d0  colour
578  *   d1  x or table address
579  *   d2  y or table length (high) and type (low)
580  * XXX: ?
581  *
582  * This function has two modes:
583  *   - single pixel
584  *   - table based multi pixel (special mode 0 (low word of 'y'))
585  *
586  * Note that a1 does not point to the VDI struct, but to a place in memory
587  * where the VDI struct pointer can be found. Four bytes beyond that address
588  * is a pointer to the destination MFDB.
589  *
590  * As usual, only the first one is necessary, and a return with d0 = -1
591  * signifies that a special mode should be broken down to the basic one.
592  *
593  * Since an MFDB is passed, the destination is not necessarily the screen.
594  **/
595 
putPixel(memptr vwk,memptr dst,int32 x,int32 y,uint32 color)596 int32 VdiDriver::putPixel(memptr vwk, memptr dst, int32 x, int32 y,
597 	uint32 color)
598 {
599 	if (vwk & 1)
600 		return 0;
601 
602 	if (!dst) {
603 		D(bug("VdiDriver::putPixel(): destination is NULL"));
604 		return color;
605 	}
606 
607 	uint16 planes = ReadInt16(dst + MFDB_NPLANES);
608 	uint32 row_address = ReadInt32(dst + MFDB_ADDRESS) +
609 		ReadInt16(dst + MFDB_WDWIDTH) * 2 * planes * y;
610 
611 	switch (planes) {
612 		case 8:
613 			WriteInt8(row_address + x, color);
614 			break;
615 		case 16:
616 			WriteInt16(row_address + x * 2, color);
617 			break;
618 		case 24:
619 			WriteInt8(row_address + x * 3, (color >> 16) & 0xff);
620 			WriteInt8(row_address + x * 3 + 1, (color >> 8) & 0xff);
621 			WriteInt8(row_address + x * 3 + 2, color & 0xff);
622 			break;
623 		case 32:
624 			WriteInt32(row_address + x * 4, color);
625 			break;
626 		}
627 
628 	return 1;
629 }
630 
631 /**
632  * Draw the mouse
633  *
634  * Draw a coloured line between two points.
635  *
636  * c_mouse_draw(Workstation *wk, long x, long y, Mouse *mouse)
637  * mouse_draw
638  * In:  a1  Pointer to Workstation struct
639  *  d0/d1   x,y
640  *  d2  0 - move shown  1 - move hidden  2 - hide  3 - show  >3 - change shape (pointer to mouse struct)
641  *
642  * Unlike all the other functions, this does not receive a pointer to a VDI
643  * struct, but rather one to the screen's workstation struct. This is
644  * because the mouse handling concerns the screen as a whole (and the
645  * routine is also called from inside interrupt routines).
646  *
647  * The Mouse structure pointer doubles as a mode variable. If it is a small
648  * number, the mouse's state is supposed to change somehow, while a large
649  * number is a pointer to a new mouse shape.
650  *
651  * This is currently not a required function, but it probably should be.
652  * The fallback handling is not done in the usual way, and to make it
653  * at least somewhat usable, the mouse pointer is reduced to 4x4 pixels.
654  *
655  * typedef struct Fgbg_ {
656  *   short background;
657  *   short foreground;
658  * } Fgbg;
659  *
660  * typedef struct Mouse_ {
661  * 0  short type;
662  * 2   short hide;
663  *   struct position_ {
664  * 4   short x;
665  * 6   short y;
666  *   } position;
667  *   struct hotspot_ {
668  * 8   short x;
669  * 10   short y;
670  *   } hotspot;
671  * 12  Fgbg colour;
672  * 16  short mask[16];
673  * 48  short data[16];
674  * 80  void *extra_info;
675  * } Mouse;
676  **/
677 
restoreMouseBackground(void)678 void VdiDriver::restoreMouseBackground(void)
679 {
680 }
681 
saveMouseBackground(int16,int16,int16,int16)682 void VdiDriver::saveMouseBackground(int16 /*x*/, int16 /*y*/, int16 /*width*/,
683 	int16 /*height*/)
684 {
685 }
686 
drawMouse(memptr wk,int32 x,int32 y,uint32 mode,uint32 data,uint32 hot_x,uint32 hot_y,uint32 fgColor,uint32 bgColor,uint32 mouse_type)687 int32 VdiDriver::drawMouse(memptr wk, int32 x, int32 y, uint32 mode,
688 	uint32 data, uint32 hot_x, uint32 hot_y, uint32 fgColor, uint32 bgColor,
689 	uint32 mouse_type)
690 {
691 	DUNUSED(wk);
692 	DUNUSED(fgColor);
693 	DUNUSED(bgColor);
694 	DUNUSED(mouse_type);
695 
696 	D(bug("VdiDriver::drawMouse(): x,y = [%ld,%ld] mode=%ld", x, y, mode));
697 
698 	switch (mode) {
699 		case 0:
700 		case 1:
701 			break;
702 		case 2:
703 #if 0
704 			SDL_ShowCursor(SDL_DISABLE);
705 #endif
706 			break;
707 		case 3:
708 			SDL_ShowCursor(SDL_ENABLE);
709 			break;
710 		case 4:
711 		case 5:
712 			host->video->WarpMouse(x, y);
713 			break;
714 		case 6:
715 		case 7:
716 			break;
717 		default:
718 			{
719 				if (cursor)
720 					SDL_FreeCursor(cursor);
721 
722 				cursor = SDL_CreateCursor(
723 					(Uint8 *)Atari2HostAddr(data),
724 					(Uint8 *)Atari2HostAddr(mode),
725 					16, 16, hot_x, hot_y
726 				);
727 
728 				SDL_SetCursor(cursor);
729 			}
730 			break;
731 	}
732 
733 	return 1;
734 }
735 
736 /**
737  * Expand a monochrome area to a coloured one.
738  *
739  * c_expand_area(Virtual *vwk, MFDB *src, long src_x, long src_y,
740  *                             MFDB *dst, long dst_x, long dst_y,
741  *                             long w, long h, long operation, long colour)
742  * expand_area
743  * In:  a1  VDI struct, destination MFDB, VDI struct, source MFDB
744  *  d0  height and width to move (high and low word)
745  *  d1-d2   source coordinates
746  *  d3-d4   destination coordinates
747  *  d6  background and foreground colour
748  *  d7  logic operation
749  *
750  * Only one mode here.
751  *
752  * Note that a1 does not point to the VDI struct, but to a place in memory
753  * where the VDI struct pointer can be found. Four bytes beyond that address
754  * is a pointer to the destination MFDB, and then comes a VDI struct
755  * pointer again (the same) and a pointer to the source MFDB.
756  *
757  * Since MFDBs are passed, the screen is not necessarily involved.
758  *
759  * A return with 0 gives a fallback (normally pixel by pixel drawing by
760  * the fVDI engine).
761  *
762  * typedef struct MFDB_ {
763  *   short *address;
764  *   short width;
765  *   short height;
766  *   short wdwidth;
767  *   short standard;
768  *   short bitplanes;
769  *   short reserved[3];
770  * } MFDB;
771  **/
772 
expandArea(memptr vwk,memptr src,int32 sx,int32 sy,memptr dest,int32 dx,int32 dy,int32 w,int32 h,uint32 logOp,uint32 fgColor,uint32 bgColor)773 int32 VdiDriver::expandArea(memptr vwk, memptr src, int32 sx, int32 sy,
774 	memptr dest, int32 dx, int32 dy, int32 w, int32 h, uint32 logOp,
775 	uint32 fgColor, uint32 bgColor)
776 {
777 	DUNUSED(vwk);
778 
779 	if (!dest) {
780 		D(bug("VdiDriver::expandArea(): destination is NULL"));
781 		return 1;
782 	}
783 
784 	if (getBpp() == 8) {
785 		fgColor &= 0xff;
786 		bgColor &= 0xff;
787 	}
788 
789 	uint16 pitch = ReadInt16(src + MFDB_WDWIDTH) * 2; // the byte width (always monochrom);
790 	memptr data  = ReadInt32(src + MFDB_ADDRESS) + sy * pitch; // MFDB *src->address;
791 
792 	D(bug("fVDI: %s %x %d,%d:%d,%d:%d,%d (%lx, %lx)", "expandArea", logOp, sx, sy, dx, dy, w, h, fgColor, bgColor ));
793 	D2(bug("fVDI: %s %x,%x : %x,%x", "expandArea - MFDB addresses", src, dest, ReadInt32( src ),ReadInt32( dest )));
794 	D2(bug("fVDI: %s %x, %d, %d", "expandArea - src: data address, MFDB wdwidth << 1, bitplanes", data, pitch, ReadInt16( src + MFDB_NPLANES )));
795 	D2(bug("fVDI: %s %x, %d, %d", "expandArea - dst: data address, MFDB wdwidth << 1, bitplanes", ReadInt32(dest), ReadInt16(dest + MFDB_WDWIDTH) * (ReadInt16(dest + MFDB_NPLANES) >> 2), ReadInt16(dest + MFDB_NPLANES)));
796 
797 	uint32 destPlanes  = (uint32)ReadInt16( dest + MFDB_NPLANES );
798 	uint32 destPitch   = ReadInt16(dest + MFDB_WDWIDTH) * destPlanes << 1; // MFDB *dest->pitch
799 	uint32 destAddress = ReadInt32(dest);
800 
801 	switch(destPlanes) {
802 		case 16:
803 			for(uint16 j = 0; j < h; j++) {
804 				D2(fprintf(stderr, "fVDI: bmp:"));
805 
806 				uint16 theWord = ReadInt16(data + j * pitch + ((sx >> 3) & 0xfffe));
807 				for(uint16 i = sx; i < sx + w; i++) {
808 					uint32 offset = (dx + i - sx) * 2 + (dy + j) * destPitch;
809 					if (i % 16 == 0)
810 						theWord = ReadInt16(data + j * pitch + ((i >> 3) & 0xfffe));
811 
812 					D2(fprintf(stderr, "%s", ((theWord >> (15 - (i & 0xf))) & 1) ? "1" : " "));
813 					switch(logOp) {
814 					case 1:
815 						WriteInt16(destAddress + offset, ((theWord >> (15 - (i & 0xf))) & 1) ? fgColor : bgColor);
816 						break;
817 					case 2:
818 						if ((theWord >> (15 - (i & 0xf))) & 1)
819 							WriteInt16(destAddress + offset, fgColor);
820 						break;
821 					case 3:
822 						if ((theWord >> (15 - (i & 0xf))) & 1)
823 							WriteInt16(destAddress + offset, ~ReadInt16(destAddress + offset));
824 						break;
825 					case 4:
826 						if (!((theWord >> (15 - (i & 0xf))) & 1))
827 							WriteInt16(destAddress + offset, bgColor);
828 						break;
829 					}
830 				}
831 				D2(bug("")); //newline
832 			}
833 			break;
834 		case 24:
835 			for(uint16 j = 0; j < h; j++) {
836 				D2(fprintf(stderr, "fVDI: bmp:"));
837 
838 				uint16 theWord = ReadInt16(data + j * pitch + ((sx >> 3) & 0xfffe));
839 				for(uint16 i = sx; i < sx + w; i++) {
840 					uint32 offset = (dx + i - sx) * 3 + (dy + j) * destPitch;
841 					if (i % 16 == 0)
842 						theWord = ReadInt16(data + j * pitch + ((i >> 3) & 0xfffe));
843 
844 					D2(fprintf(stderr, "%s", ((theWord >> (15 - (i & 0xf))) & 1) ? "1" : " "));
845 					switch(logOp) {
846 					case 1:
847 						put_dtriplet(destAddress + offset, ((theWord >> (15 - (i & 0xf))) & 1) ? fgColor : bgColor);
848 						break;
849 					case 2:
850 						if ((theWord >> (15 - (i & 0xf))) & 1)
851 							put_dtriplet(destAddress + offset, fgColor);
852 						break;
853 					case 3:
854 						if ((theWord >> (15-(i&0xf))) & 1)
855 							put_dtriplet(destAddress + offset, ~get_dtriplet(destAddress + offset));
856 						break;
857 					case 4:
858 						if (!((theWord >> (15 - (i & 0xf))) & 1))
859 							put_dtriplet(destAddress + offset, bgColor);
860 						break;
861 					}
862 				}
863 				D2(bug("")); //newline
864 			}
865 			break;
866 		case 32:
867 			for(uint16 j = 0; j < h; j++) {
868 				D2(fprintf(stderr, "fVDI: bmp:"));
869 
870 				uint16 theWord = ReadInt16(data + j * pitch + ((sx >> 3) & 0xfffe));
871 				for(uint16 i = sx; i < sx + w; i++) {
872 					uint32 offset = (dx + i - sx) * 4 + (dy + j) * destPitch;
873 					if (i % 16 == 0)
874 						theWord = ReadInt16(data + j * pitch + ((i >> 3) & 0xfffe));
875 
876 					D2(fprintf(stderr, "%s", ((theWord >> (15 - (i & 0xf))) & 1) ? "1" : " "));
877 					switch(logOp) {
878 					case 1:
879 						WriteInt32(destAddress + offset, ((theWord >> (15 - (i & 0xf))) & 1) ? fgColor : bgColor);
880 						break;
881 					case 2:
882 						if ((theWord >> (15-(i&0xf))) & 1)
883 							WriteInt32(destAddress + offset, fgColor);
884 						break;
885 					case 3:
886 						if ((theWord >> (15 - (i & 0xf))) & 1)
887 							WriteInt32(destAddress + offset, ~ReadInt32(destAddress + offset));
888 						break;
889 					case 4:
890 						if (!((theWord >> (15 - (i & 0xf))) & 1))
891 							WriteInt32(destAddress + offset, bgColor);
892 						break;
893 					}
894 				}
895 				D2(bug("")); //newline
896 			}
897 			break;
898 		default:
899 			{ // do the mangling for bitplanes. TOS<->VDI color conversions implemented.
900 				uint8 color[16];
901 				uint16 bitplanePixels[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // initialized just to quiet GCC warning
902 
903 				for(uint16 j = 0; j < h; j++) {
904 					D2(fprintf(stderr, "fVDI: bmp:"));
905 
906 					uint32 address = destAddress + ((((dx >> 4) * destPlanes) << 1) + (dy + j) * destPitch);
907 					HostScreen::bitplaneToChunky((uint16*)Atari2HostAddr(address), destPlanes, color);
908 
909 					uint16 theWord = ReadInt16(data + j * pitch + ((sx >> 3) & 0xfffe));
910 					for(uint16 i = sx; i < sx + w; i++) {
911 						if (i % 16 == 0) {
912 							uint32 wordIndex = ((dx + i - sx) >> 4) * destPlanes;
913 
914 							// convert the 16pixels (VDI->TOS colors - within the chunkyToBitplane
915 							// function) into the bitplane and write it to the destination
916 							//
917 							// note: we can't do the conversion directly
918 							//       because it needs the little->bigendian conversion
919 							chunkyToBitplane(color, destPlanes, bitplanePixels);
920 							for(uint32 d = 0; d < destPlanes; d++)
921 								WriteInt16(address + (d<<1), bitplanePixels[d]);
922 
923 							// convert next 16pixels to chunky
924 							address = destAddress + ((wordIndex << 1) + (dy + j) * destPitch);
925 							HostScreen::bitplaneToChunky((uint16*)Atari2HostAddr(address), destPlanes, color);
926 							theWord = ReadInt16(data + j * pitch + ((i >> 3) & 0xfffe));
927 						}
928 
929 						D2(fprintf(stderr, "%s", ((theWord >> (15 - (i & 0xf))) & 1) ? "1" : " "));
930 						switch(logOp) {
931 							case 1:
932 								color[i&0xf] = ((theWord >> (15 - (i & 0xf))) & 1) ? fgColor : bgColor;
933 								break;
934 							case 2:
935 								if ((theWord >> (15-(i&0xf))) & 1)
936 									color[i&0xf] = fgColor;
937 								break;
938 							case 3:
939 								if ((theWord >> (15 - (i & 0xf))) & 1)
940 									color[i&0xf] = ~color[i&0xf];
941 								break;
942 							case 4:
943 								if (!((theWord >> (15 - (i & 0xf))) & 1))
944 									color[i&0xf] = bgColor;
945 								break;
946 						}
947 					}
948 					chunkyToBitplane(color, destPlanes, bitplanePixels);
949 					for(uint32 d = 0; d < destPlanes; d++)
950 						WriteInt16(address + (d<<1), bitplanePixels[d]);
951 
952 					D2(bug("")); //newline
953 				}
954 			}
955 			break;
956 	}
957 
958 	return 1;
959 }
960 
961 /**
962  * Fill a coloured area using a monochrome pattern.
963  *
964  * c_fill_area(Virtual *vwk, long x, long y, long w, long h,
965  *                           short *pattern, long colour, long mode, long interior_style)
966  * fill_area
967  * In:  a1  VDI struct
968  *  d0  height and width to fill (high and low word)
969  *  d1  x or table address
970  *  d2  y or table length (high) and type (low)
971  *  d3  pattern address
972  *  d4  colour
973  *
974  * This function has two modes:
975  * - single block to fill
976  * - table based y/x1/x2 spans to fill (special mode 0 (low word of 'y'))
977  *
978  * As usual, only the first one is necessary, and a return with d0 = -1
979  * signifies that a special mode should be broken down to the basic one.
980  *
981  * An immediate return with 0 gives a fallback (normally line based drawing
982  * by the fVDI engine for solid fills, otherwise pixel by pixel).
983  * A negative return will break down the special mode into separate calls,
984  * with no more fallback possible.
985  **/
986 
fillArea(memptr vwk,uint32 x_,uint32 y_,int32 w,int32 h,memptr pattern_addr,uint32 fgColor,uint32 bgColor,uint32 logOp,uint32 interior_style)987 int32 VdiDriver::fillArea(memptr vwk, uint32 x_, uint32 y_, int32 w,
988 	int32 h, memptr pattern_addr, uint32 fgColor, uint32 bgColor,
989 	uint32 logOp, uint32 interior_style)
990 {
991 	DUNUSED(vwk);
992 	DUNUSED(x_);
993 	DUNUSED(y_);
994 	DUNUSED(w);
995 	DUNUSED(h);
996 	DUNUSED(pattern_addr);
997 	DUNUSED(fgColor);
998 	DUNUSED(bgColor);
999 	DUNUSED(logOp);
1000 	DUNUSED(interior_style);
1001 
1002 	return -1;
1003 }
1004 
1005 /**
1006  * Blit an area
1007  *
1008  * c_blit_area(Virtual *vwk, MFDB *src, long src_x, long src_y,
1009  *                        MFDB *dst, long dst_x, long dst_y,
1010  *                        long w, long h, long operation)
1011  * blit_area
1012  * In:  a1  VDI struct, destination MFDB, VDI struct, source MFDB
1013  *  d0  height and width to move (high and low word)
1014  *  d1-d2   source coordinates
1015  *  d3-d4   destination coordinates
1016  *  d7  logic operation
1017  *
1018  * Only one mode here.
1019  *
1020  * Note that a1 does not point to the VDI struct, but to a place in memory
1021  * where the VDI struct pointer can be found. Four bytes beyond that address
1022  * is a pointer to the destination MFDB, and then comes a VDI struct
1023  * pointer again (the same) and a pointer to the source MFDB.
1024  *
1025  * Since MFDBs are passed, the screen is not necessarily involved.
1026  *
1027  * A return with 0 gives a fallback (normally pixel by pixel drawing by the
1028  * fVDI engine).
1029  **/
1030 
blitArea(memptr vwk,memptr src,int32 sx,int32 sy,memptr dest,int32 dx,int32 dy,int32 w,int32 h,uint32 logOp)1031 int32 VdiDriver::blitArea(memptr vwk, memptr src, int32 sx, int32 sy,
1032 	memptr dest, int32 dx, int32 dy, int32 w, int32 h, uint32 logOp)
1033 {
1034 	int32 ret;
1035 
1036 	if (src) {
1037 		if (dest) {
1038 			ret=blitArea_M2M(vwk, src, sx, sy, dest, dx, dy, w, h, logOp);
1039 		} else {
1040 			ret=blitArea_M2S(vwk, src, sx, sy, dest, dx, dy, w, h, logOp);
1041 		}
1042 	} else {
1043 		if (dest) {
1044 			ret=blitArea_S2M(vwk, src, sx, sy, dest, dx, dy, w, h, logOp);
1045 		} else {
1046 			ret=blitArea_S2S(vwk, src, sx, sy, dest, dx, dy, w, h, logOp);
1047 		}
1048 	}
1049 
1050 	return ret;
1051 }
1052 
blitArea_M2M(memptr vwk,memptr src,int32 sx,int32 sy,memptr dest,int32 dx,int32 dy,int32 w,int32 h,uint32 logOp)1053 int32 VdiDriver::blitArea_M2M(memptr vwk, memptr src, int32 sx, int32 sy,
1054 	memptr dest, int32 dx, int32 dy, int32 w, int32 h, uint32 logOp)
1055 {
1056 	DUNUSED(vwk);
1057 
1058 	uint32 planes = ReadInt16(src + MFDB_NPLANES);			// MFDB *src->bitplanes
1059 	uint32 pitch  = ReadInt16(src + MFDB_WDWIDTH) * planes * 2;	// MFDB *src->pitch
1060 	memptr data   = ReadInt32(src) + sy * pitch;			// MFDB *src->address host OS address
1061 
1062 	// the destPlanes is always the same?
1063 	planes = ReadInt16(dest + MFDB_NPLANES);		// MFDB *dest->bitplanes
1064 	uint32 destPitch = ReadInt16(dest + MFDB_WDWIDTH) * planes * 2;	// MFDB *dest->pitch
1065 	memptr destAddress = (memptr)ReadInt32(dest);
1066 
1067 	D(bug("fVDI: blitArea M->M"));
1068 
1069 	uint32 srcData;
1070 	uint32 destData;
1071 
1072 	switch(planes) {
1073 		case 16:
1074 			for(int32 j = 0; j < h; j++)
1075 				for(int32 i = sx; i < sx + w; i++) {
1076 					uint32 offset = (dx + i - sx) * 2 + (dy + j) * destPitch;
1077 					srcData = ReadInt16(data + j * pitch + i * 2);
1078 					destData = ReadInt16(destAddress + offset);
1079 					destData = applyBlitLogOperation(logOp, destData, srcData);
1080 					WriteInt16(destAddress + offset, destData);
1081 				}
1082 			break;
1083 		case 24:
1084 			for(int32 j = 0; j < h; j++)
1085 				for(int32 i = sx; i < sx + w; i++) {
1086 					uint32 offset = (dx + i - sx) * 3 + (dy + j) * destPitch;
1087 					srcData = get_dtriplet(data + j * pitch + i * 3);
1088 					destData = get_dtriplet(destAddress + offset);
1089 					destData = applyBlitLogOperation(logOp, destData, srcData);
1090 					put_dtriplet(destAddress + offset, destData);
1091 				}
1092 			break;
1093 		case 32:
1094 			for(int32 j = 0; j < h; j++)
1095 				for(int32 i = sx; i < sx + w; i++) {
1096 					uint32 offset = (dx + i - sx) * 4 + (dy + j) * destPitch;
1097 					srcData = ReadInt32(data + j * pitch + i * 4);
1098 					destData = ReadInt32(destAddress + offset);
1099 					destData = applyBlitLogOperation(logOp, destData, srcData);
1100 					WriteInt32(destAddress + offset, destData);
1101 				}
1102 			break;
1103 		default:
1104 			if (planes < 16) {
1105 				D(bug("fVDI: blitArea M->M: NOT TESTED bitplaneToCunky conversion"));
1106 			}
1107 	}
1108 
1109 	return 1;
1110 }
1111 
blitArea_M2S(memptr vwk,memptr src,int32 sx,int32 sy,memptr dest,int32 dx,int32 dy,int32 w,int32 h,uint32 logOp)1112 int32 VdiDriver::blitArea_M2S(memptr vwk, memptr src, int32 sx, int32 sy,
1113 	memptr dest, int32 dx, int32 dy, int32 w, int32 h, uint32 logOp)
1114 {
1115 	DUNUSED(vwk);
1116 	DUNUSED(src);
1117 	DUNUSED(sx);
1118 	DUNUSED(sy);
1119 	DUNUSED(dest);
1120 	DUNUSED(dx);
1121 	DUNUSED(dy);
1122 	DUNUSED(w);
1123 	DUNUSED(h);
1124 	DUNUSED(logOp);
1125 	return -1;
1126 }
1127 
blitArea_S2M(memptr vwk,memptr src,int32 sx,int32 sy,memptr dest,int32 dx,int32 dy,int32 w,int32 h,uint32 logOp)1128 int32 VdiDriver::blitArea_S2M(memptr vwk, memptr src, int32 sx, int32 sy,
1129 	memptr dest, int32 dx, int32 dy, int32 w, int32 h, uint32 logOp)
1130 {
1131 	DUNUSED(vwk);
1132 	DUNUSED(src);
1133 	DUNUSED(sx);
1134 	DUNUSED(sy);
1135 	DUNUSED(dest);
1136 	DUNUSED(dx);
1137 	DUNUSED(dy);
1138 	DUNUSED(w);
1139 	DUNUSED(h);
1140 	DUNUSED(logOp);
1141 	return -1;
1142 }
1143 
blitArea_S2S(memptr vwk,memptr src,int32 sx,int32 sy,memptr dest,int32 dx,int32 dy,int32 w,int32 h,uint32 logOp)1144 int32 VdiDriver::blitArea_S2S(memptr vwk, memptr src, int32 sx, int32 sy,
1145 	memptr dest, int32 dx, int32 dy, int32 w, int32 h, uint32 logOp)
1146 {
1147 	DUNUSED(vwk);
1148 	DUNUSED(src);
1149 	DUNUSED(sx);
1150 	DUNUSED(sy);
1151 	DUNUSED(dest);
1152 	DUNUSED(dx);
1153 	DUNUSED(dy);
1154 	DUNUSED(w);
1155 	DUNUSED(h);
1156 	DUNUSED(logOp);
1157 	return -1;
1158 }
1159 
1160 /**
1161  * Draw a coloured line between two points
1162  *
1163  * c_draw_line(Virtual *vwk, long x1, long y1, long x2, long y2,
1164  *                          long pattern, long colour)
1165  * draw_line
1166  * In:  a1  VDI struct
1167  *  d0  logic operation
1168  *  d1  x1 or table address
1169  *  d2  y1 or table length (high) and type (low)
1170  *  d3  x2 or move point count
1171  *  d4  y2 or move index address
1172  *  d5  pattern
1173  *  d6  colour
1174  *
1175  * This function has three modes:
1176  * - single line
1177  * - table based coordinate pairs (special mode 0 (low word of 'y1'))
1178  * - table based coordinate pairs+moves (special mode 1)
1179  *
1180  * As usual, only the first one is necessary, and a return with d0 = -1
1181  * signifies that a special mode should be broken down to the basic one.
1182  *
1183  * An immediate return with 0 gives a fallback (normally pixel by pixel
1184  * drawing by the fVDI engine).
1185  * A negative return will break down the special modes into separate calls,
1186  * with no more fallback possible.
1187  **/
1188 
drawLine(memptr vwk,uint32 x1_,uint32 y1_,uint32 x2_,uint32 y2_,uint32 pattern,uint32 fgColor,uint32 bgColor,uint32 logOp,memptr clip)1189 int32 VdiDriver::drawLine(memptr vwk, uint32 x1_, uint32 y1_, uint32 x2_,
1190 	uint32 y2_, uint32 pattern, uint32 fgColor, uint32 bgColor,
1191 	uint32 logOp, memptr clip)
1192 {
1193 	DUNUSED(vwk);
1194 	DUNUSED(x1_);
1195 	DUNUSED(y1_);
1196 	DUNUSED(x2_);
1197 	DUNUSED(y2_);
1198 	DUNUSED(pattern);
1199 	DUNUSED(fgColor);
1200 	DUNUSED(bgColor);
1201 	DUNUSED(logOp);
1202 	DUNUSED(clip);
1203 
1204 	return -1;
1205 }
1206 
fillPoly(memptr vwk,memptr points_addr,int n,memptr index_addr,int moves,memptr pattern_addr,uint32 fgColor,uint32 bgColor,uint32 logOp,uint32 interior_style,memptr clip)1207 int32 VdiDriver::fillPoly(memptr vwk, memptr points_addr, int n,
1208 	memptr index_addr, int moves, memptr pattern_addr, uint32 fgColor,
1209 	uint32 bgColor, uint32 logOp, uint32 interior_style, memptr clip)
1210 {
1211 	DUNUSED(interior_style);
1212 	if (vwk & 1)
1213 		return -1;      // Don't know about any special fills
1214 
1215 	// Allocate arrays for data
1216 	if (!AllocPoints(n) || !AllocIndices(moves) || !AllocCrossings(200))
1217 		return -1;
1218 
1219 	uint16 pattern[16];
1220 	for(int i = 0; i < 16; ++i)
1221 		pattern[i] = ReadInt16(pattern_addr + i * 2);
1222 
1223 	int cliparray[4];
1224 	int* cliprect = 0;
1225 	if (clip) {	// Clipping is not off
1226 		cliprect = cliparray;
1227 		cliprect[0] = (int16)ReadInt32(clip);
1228 		cliprect[1] = (int16)ReadInt32(clip + 4);
1229 		cliprect[2] = (int16)ReadInt32(clip + 8);
1230 		cliprect[3] = (int16)ReadInt32(clip + 12);
1231 		D2(bug("fVDI: %s %d,%d:%d,%d", "clipLineTO", cliprect[0], cliprect[1],
1232 		       cliprect[2], cliprect[3]));
1233 	}
1234 
1235 	Points p(alloc_point);
1236 	int16* index = alloc_index;
1237 	int16* crossing = alloc_crossing;
1238 
1239 	for(int i = 0; i < n; ++i) {
1240 		p[i][0] = (int16)ReadInt16(points_addr + i * 4);
1241 		p[i][1] = (int16)ReadInt16(points_addr + i * 4 + 2);
1242 	}
1243 	bool indices = moves;
1244 	for(int i = 0; i < moves; ++i)
1245 		index[i] = (int16)ReadInt16(index_addr + i * 2);
1246 
1247 
1248 	if (!n)
1249 		return 1;
1250 
1251 	if (!indices) {
1252 		if ((p[0][0] == p[n - 1][0]) && (p[0][1] == p[n - 1][1]))
1253 			n--;
1254 	} else {
1255 		moves--;
1256 		if (index[moves] == -4)
1257 			moves--;
1258 		if (index[moves] == -2)
1259 			moves--;
1260 	}
1261 
1262 	int miny = p[0][1];
1263 	int maxy = miny;
1264 	for(int i = 1; i < n; ++i) {
1265 		int16 y = p[i][1];
1266 		if (y < miny) {
1267 			miny = y;
1268 		}
1269 		if (y > maxy) {
1270 			maxy = y;
1271 		}
1272 	}
1273 	if (cliprect) {
1274 		if (miny < cliprect[1])
1275 			miny = cliprect[1];
1276 		if (maxy > cliprect[3])
1277 			maxy = cliprect[3];
1278 	}
1279 
1280 	int minx = 1000000;
1281 	int maxx = -1000000;
1282 
1283 	for(int16 y = miny; y <= maxy; ++y) {
1284 		int ints = 0;
1285 		int16 x1 = 0;	// Make the compiler happy with some initializations
1286 		int16 y1 = 0;
1287 		int16 x2 = 0;
1288 		int16 y2 = 0;
1289 		int move_n = 0;
1290 		int movepnt = 0;
1291 		if (indices) {
1292 			move_n = moves;
1293 			movepnt = (index[move_n] + 4) / 2;
1294 			x2 = p[0][0];
1295 			y2 = p[0][1];
1296 		} else {
1297 			x1 = p[n - 1][0];
1298 			y1 = p[n - 1][1];
1299 		}
1300 
1301 		for(int i = indices; i < n; ++i) {
1302 			if (EnoughCrossings(ints + 1) || AllocCrossings(ints + 1))
1303 				crossing = alloc_crossing;
1304 			else
1305 				break;		// At least something will get drawn
1306 
1307 			if (indices) {
1308 				x1 = x2;
1309 				y1 = y2;
1310 			}
1311 			x2 = p[i][0];
1312 			y2 = p[i][1];
1313 			if (indices) {
1314 				if (i == movepnt) {
1315 					if (--move_n >= 0)
1316 						movepnt = (index[move_n] + 4) / 2;
1317 					else
1318 						movepnt = -1;		// Never again equal to n
1319 					continue;
1320 				}
1321 			}
1322 
1323 			if (y1 < y2) {
1324 				if ((y >= y1) && (y < y2)) {
1325 					crossing[ints++] = SMUL_DIV((y - y1), (x2 - x1), (y2 - y1)) + x1;
1326 				}
1327 			} else if (y1 > y2) {
1328 				if ((y >= y2) && (y < y1)) {
1329 					crossing[ints++] = SMUL_DIV((y - y2), (x1 - x2), (y1 - y2)) + x2;
1330 				}
1331 			}
1332 			if (!indices) {
1333 				x1 = x2;
1334 				y1 = y2;
1335 			}
1336 		}
1337 
1338 		for(int i = 0; i < ints - 1; ++i) {
1339 			for(int j = i + 1; j < ints; ++j) {
1340 				if (crossing[i] > crossing[j]) {
1341 					int16 tmp = crossing[i];
1342 					crossing[i] = crossing[j];
1343 					crossing[j] = tmp;
1344 				}
1345 			}
1346 		}
1347 
1348 		x1 = cliprect[0];
1349 		x2 = cliprect[2];
1350 		for(int i = 0; i < ints - 1; i += 2) {
1351 			y1 = crossing[i];	// Really x-values, but...
1352 			y2 = crossing[i + 1];
1353 			if (y1 < x1)
1354 				y1 = x1;
1355 			if (y2 > x2)
1356 				y2 = x2;
1357 			if (y1 <= y2) {
1358 				fillArea(y1, y, y2 - y1 + 1, 1, pattern,
1359 				         fgColor, bgColor, logOp);
1360 				if (y1 < minx)
1361 					minx = y1;
1362 				if (y2 > maxx)
1363 					maxx = y2;
1364 			}
1365 		}
1366 	}
1367 
1368 	return 1;
1369 }
1370 
drawText(memptr vwk,memptr text,uint32 length,int32 dst_x,int32 dst_y,memptr font,uint32 w,uint32 h,uint32 fgColor,uint32 bgColor,uint32 logOp,memptr clip)1371 int32 VdiDriver::drawText(memptr vwk, memptr text, uint32 length, int32 dst_x, int32 dst_y,
1372 			  memptr font, uint32 w, uint32 h, uint32 fgColor, uint32 bgColor,
1373 			  uint32 logOp, memptr clip)
1374 {
1375 	DUNUSED(vwk);
1376 	DUNUSED(text);
1377 	DUNUSED(length);
1378 	DUNUSED(dst_x);
1379 	DUNUSED(dst_y);
1380 	DUNUSED(font);
1381 	DUNUSED(w);
1382 	DUNUSED(h);
1383 	DUNUSED(fgColor);
1384 	DUNUSED(bgColor);
1385 	DUNUSED(logOp);
1386 	DUNUSED(clip);
1387 
1388 	return -1;
1389 }
1390 
getHwColor(uint16 index,uint32 red,uint32 green,uint32 blue,memptr hw_value)1391 void VdiDriver::getHwColor(uint16 index, uint32 red, uint32 green,
1392 	uint32 blue, memptr hw_value)
1393 {
1394 	DUNUSED(index);
1395 	DUNUSED(red);
1396 	DUNUSED(green);
1397 	DUNUSED(blue);
1398 	DUNUSED(hw_value);
1399 }
1400 
setColor(memptr vwk,uint32 paletteIndex,uint32 red,uint32 green,uint32 blue)1401 void VdiDriver::setColor(memptr vwk, uint32 paletteIndex, uint32 red,
1402 	uint32 green, uint32 blue)
1403 {
1404 	DUNUSED(vwk);
1405 	DUNUSED(paletteIndex);
1406 	DUNUSED(red);
1407 	DUNUSED(green);
1408 	DUNUSED(blue);
1409 }
1410 
getFbAddr(void)1411 int32 VdiDriver::getFbAddr(void)
1412 {
1413 	return 0;
1414 }
1415 
1416