1 |
|
/* |
2 |
|
* video.cpp - Video/graphics emulation |
3 |
|
* |
4 |
< |
* SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer |
4 |
> |
* SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer |
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 |
21 |
|
/* |
22 |
|
* TODO |
23 |
|
* - check for supported modes ??? |
24 |
– |
* - window mode "hardware" cursor hotspot |
24 |
|
*/ |
25 |
|
|
26 |
|
#include <stdio.h> |
34 |
|
#include "macos_util.h" |
35 |
|
#include "user_strings.h" |
36 |
|
#include "version.h" |
37 |
+ |
#include "thunks.h" |
38 |
|
|
39 |
|
#define DEBUG 0 |
40 |
|
#include "debug.h" |
73 |
|
// Function pointers of imported functions |
74 |
|
typedef int16 (*iocic_ptr)(void *, int16); |
75 |
|
static uint32 iocic_tvect = 0; |
76 |
< |
static inline int16 IOCommandIsComplete(void *arg1, int16 arg2) |
76 |
> |
static inline int16 IOCommandIsComplete(uintptr arg1, int16 arg2) |
77 |
|
{ |
78 |
< |
return (int16)CallMacOS2(iocic_ptr, iocic_tvect, arg1, arg2); |
78 |
> |
return (int16)CallMacOS2(iocic_ptr, iocic_tvect, (void *)arg1, arg2); |
79 |
|
} |
80 |
|
typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *); |
81 |
|
static uint32 vslnewis_tvect = 0; |
82 |
< |
static inline int16 VSLNewInterruptService(void *arg1, uint32 arg2, uint32 *arg3) |
82 |
> |
static inline int16 VSLNewInterruptService(uintptr arg1, uint32 arg2, uintptr arg3) |
83 |
|
{ |
84 |
< |
return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, arg1, arg2, arg3); |
84 |
> |
return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, (void *)arg1, arg2, (uint32 *)arg3); |
85 |
|
} |
86 |
|
typedef int16 (*vsldisposeis_ptr)(uint32); |
87 |
|
static uint32 vsldisposeis_tvect = 0; |
97 |
|
} |
98 |
|
typedef void (*nqdmisc_ptr)(uint32, void *); |
99 |
|
static uint32 nqdmisc_tvect = 0; |
100 |
< |
void NQDMisc(uint32 arg1, void *arg2) |
100 |
> |
void NQDMisc(uint32 arg1, uintptr arg2) |
101 |
|
{ |
102 |
< |
CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, arg2); |
102 |
> |
CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, (void *)arg2); |
103 |
|
} |
104 |
|
|
105 |
|
|
142 |
|
|
143 |
|
|
144 |
|
/* |
145 |
+ |
* Determine whether we should use the hardware or software cursor, and return true for the former, false for the latter. |
146 |
+ |
* Currently we use the hardware cursor if we can, but perhaps this can be made a preference someday. |
147 |
+ |
*/ |
148 |
+ |
|
149 |
+ |
static bool UseHardwareCursor(void) |
150 |
+ |
{ |
151 |
+ |
return video_can_change_cursor(); |
152 |
+ |
} |
153 |
+ |
|
154 |
+ |
|
155 |
+ |
/* |
156 |
|
* Video driver open routine |
157 |
|
*/ |
158 |
|
|
166 |
|
csSave->saveMode = VModes[cur_mode].viAppleMode; |
167 |
|
csSave->savePage = 0; |
168 |
|
csSave->saveVidParms = 0; // Add the right table |
158 |
– |
csSave->gammaTable = NULL; // No gamma table yet |
159 |
– |
csSave->maxGammaTableSize = 0; |
169 |
|
csSave->luminanceMapping = false; |
170 |
+ |
csSave->cursorHardware = UseHardwareCursor(); |
171 |
|
csSave->cursorX = 0; |
172 |
|
csSave->cursorY = 0; |
173 |
|
csSave->cursorVisible = 0; |
174 |
|
csSave->cursorSet = 0; |
175 |
+ |
csSave->cursorHotFlag = false; |
176 |
+ |
csSave->cursorHotX = 0; |
177 |
+ |
csSave->cursorHotY = 0; |
178 |
|
|
179 |
< |
// Activate default gamma table |
179 |
> |
// Find and set default gamma table |
180 |
> |
csSave->gammaTable = 0; |
181 |
> |
csSave->maxGammaTableSize = 0; |
182 |
|
set_gamma(csSave, 0); |
183 |
|
|
184 |
|
// Install and activate interrupt service |
185 |
< |
uint32 theServiceID = 0; |
186 |
< |
VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), &theServiceID); |
187 |
< |
csSave->vslServiceID = theServiceID; |
185 |
> |
SheepVar32 theServiceID = 0; |
186 |
> |
VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), theServiceID.addr()); |
187 |
> |
csSave->vslServiceID = theServiceID.value(); |
188 |
|
D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID)); |
189 |
|
csSave->interruptsEnabled = true; |
190 |
|
|
196 |
|
* Video driver control routine |
197 |
|
*/ |
198 |
|
|
199 |
< |
static int16 set_gamma(VidLocals *csSave, uint32 gamma) |
199 |
> |
static bool allocate_gamma_table(VidLocals *csSave, uint32 size) |
200 |
|
{ |
201 |
< |
GammaTbl *clientGamma = (GammaTbl *)gamma; |
202 |
< |
GammaTbl *gammaTable = csSave->gammaTable; |
201 |
> |
if (size > csSave->maxGammaTableSize) { |
202 |
> |
if (csSave->gammaTable) { |
203 |
> |
Mac_sysfree(csSave->gammaTable); |
204 |
> |
csSave->gammaTable = 0; |
205 |
> |
csSave->maxGammaTableSize = 0; |
206 |
> |
} |
207 |
> |
if ((csSave->gammaTable = Mac_sysalloc(size)) == 0) |
208 |
> |
return false; |
209 |
> |
csSave->maxGammaTableSize = size; |
210 |
> |
} |
211 |
> |
return true; |
212 |
> |
} |
213 |
|
|
214 |
< |
if (clientGamma == NULL) { |
214 |
> |
static int16 set_gamma(VidLocals *csSave, uint32 gamma) |
215 |
> |
{ |
216 |
> |
if (gamma == 0) { // Build linear ramp, 256 entries |
217 |
|
|
218 |
< |
// No gamma table supplied, build linear ramp |
219 |
< |
uint32 linearRampSize = sizeof(GammaTbl) + 256 - 2; |
220 |
< |
uint8 *correctionData; |
221 |
< |
|
222 |
< |
// Allocate new gamma table if existing gamma table is smaller than required. |
223 |
< |
if (linearRampSize > csSave->maxGammaTableSize) { |
224 |
< |
delete[] csSave->gammaTable; |
225 |
< |
csSave->gammaTable = (GammaTbl *)new uint8[linearRampSize]; |
226 |
< |
csSave->maxGammaTableSize = linearRampSize; |
227 |
< |
gammaTable = csSave->gammaTable; |
228 |
< |
} |
202 |
< |
|
203 |
< |
gammaTable->gVersion = 0; // A version 0 style of the GammaTbl structure |
204 |
< |
gammaTable->gType = 0; // Frame buffer hardware invariant |
205 |
< |
gammaTable->gFormulaSize = 0; // No formula data, just correction data |
206 |
< |
gammaTable->gChanCnt = 1; // Apply same correction to Red, Green, & Blue |
207 |
< |
gammaTable->gDataCnt = 256; // gDataCnt == 2^^gDataWidth |
208 |
< |
gammaTable->gDataWidth = 8; // 8 bits of significant data per entry |
209 |
< |
|
210 |
< |
// Find the starting address of the correction data. This can be computed by starting at |
211 |
< |
// the address of gFormula[0] and adding the gFormulaSize. |
212 |
< |
correctionData = (uint8 *)((uint32)&gammaTable->gFormulaData[0] + gammaTable->gFormulaSize); |
218 |
> |
// Allocate new table, if necessary |
219 |
> |
if (!allocate_gamma_table(csSave, SIZEOF_GammaTbl + 256)) |
220 |
> |
return memFullErr; |
221 |
> |
|
222 |
> |
// Initialize header |
223 |
> |
WriteMacInt16(csSave->gammaTable + gVersion, 0); // A version 0 style of the GammaTbl structure |
224 |
> |
WriteMacInt16(csSave->gammaTable + gType, 0); // Frame buffer hardware invariant |
225 |
> |
WriteMacInt16(csSave->gammaTable + gFormulaSize, 0); // No formula data, just correction data |
226 |
> |
WriteMacInt16(csSave->gammaTable + gChanCnt, 1); // Apply same correction to Red, Green, & Blue |
227 |
> |
WriteMacInt16(csSave->gammaTable + gDataCnt, 256); // gDataCnt == 2^^gDataWidth |
228 |
> |
WriteMacInt16(csSave->gammaTable + gDataWidth, 8); // 8 bits of significant data per entry |
229 |
|
|
230 |
|
// Build the linear ramp |
231 |
< |
for (int i=0; i<gammaTable->gDataCnt; i++) |
232 |
< |
*correctionData++ = i; |
231 |
> |
uint32 p = csSave->gammaTable + gFormulaData; |
232 |
> |
for (int i=0; i<256; i++) |
233 |
> |
WriteMacInt8(p + i, i); |
234 |
|
|
235 |
< |
} else { |
235 |
> |
} else { // User-supplied gamma table |
236 |
|
|
237 |
< |
// User supplied a gamma table, so make sure it is a valid one |
238 |
< |
if (clientGamma->gVersion != 0) |
237 |
> |
// Validate header |
238 |
> |
if (ReadMacInt16(gamma + gVersion) != 0) |
239 |
|
return paramErr; |
240 |
< |
if (clientGamma->gType != 0) |
240 |
> |
if (ReadMacInt16(gamma + gType) != 0) |
241 |
|
return paramErr; |
242 |
< |
if ((clientGamma->gChanCnt != 1) && (clientGamma->gChanCnt != 3)) |
242 |
> |
int chan_cnt = ReadMacInt16(gamma + gChanCnt); |
243 |
> |
if (chan_cnt != 1 && chan_cnt != 3) |
244 |
|
return paramErr; |
245 |
< |
if (clientGamma->gDataWidth > 8) |
245 |
> |
int data_width = ReadMacInt16(gamma + gDataWidth); |
246 |
> |
if (data_width > 8) |
247 |
|
return paramErr; |
248 |
< |
if (clientGamma->gDataCnt != (1 << clientGamma->gDataWidth)) |
248 |
> |
int data_cnt = ReadMacInt16(gamma + gDataWidth); |
249 |
> |
if (data_cnt != (1 << data_width)) |
250 |
|
return paramErr; |
251 |
|
|
252 |
< |
uint32 tableSize = sizeof(GammaTbl) // fixed size header |
253 |
< |
+ clientGamma->gFormulaSize // add formula size |
254 |
< |
+ clientGamma->gChanCnt * clientGamma->gDataCnt // assume 1 byte/entry |
255 |
< |
- 2; // correct gFormulaData[0] counted twice |
256 |
< |
|
257 |
< |
// Allocate new gamma table if existing gamma table is smaller than required. |
258 |
< |
if (tableSize > csSave->maxGammaTableSize) { |
239 |
< |
delete[] csSave->gammaTable; |
240 |
< |
csSave->gammaTable = (GammaTbl *)new uint8[tableSize]; |
241 |
< |
csSave->maxGammaTableSize = tableSize; |
242 |
< |
gammaTable = csSave->gammaTable; |
243 |
< |
} |
244 |
< |
|
245 |
< |
// Copy gamma table header |
246 |
< |
*gammaTable = *clientGamma; |
247 |
< |
|
248 |
< |
// Copy the formula data (if any) |
249 |
< |
uint8 *newData = (uint8 *)&gammaTable->gFormulaData[0]; // Point to newGamma's formula data |
250 |
< |
uint8 *clientData = (uint8 *)&clientGamma->gFormulaData[0]; // Point to clientGamma's formula data |
251 |
< |
for (int i=0; i<gammaTable->gFormulaSize; i++) |
252 |
< |
*newData++ = *clientData++; |
253 |
< |
|
254 |
< |
// Copy the correction data. Convientiently, after copying the formula data, the 'newData' |
255 |
< |
// pointer and the 'clientData' pointer are pointing to the their respective starting points |
256 |
< |
// of their correction data. |
257 |
< |
for (int i=0; i<gammaTable->gChanCnt; i++) |
258 |
< |
for (int j=0; j<gammaTable->gDataCnt; j++) |
259 |
< |
*newData++ = *clientData++; |
252 |
> |
// Allocate new table, if necessary |
253 |
> |
int size = SIZEOF_GammaTbl + ReadMacInt16(gamma + gFormulaSize) + chan_cnt * data_cnt; |
254 |
> |
if (!allocate_gamma_table(csSave, size)) |
255 |
> |
return memFullErr; |
256 |
> |
|
257 |
> |
// Copy table |
258 |
> |
Mac2Mac_memcpy(csSave->gammaTable, gamma, size); |
259 |
|
} |
260 |
|
return noErr; |
261 |
|
} |
285 |
|
case cscSetEntries: { // SetEntries |
286 |
|
D(bug("SetEntries\n")); |
287 |
|
if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr; |
288 |
< |
ColorSpec *s_pal = (ColorSpec *)Mac2HostAddr(ReadMacInt32(param + csTable)); |
289 |
< |
int16 start = ReadMacInt16(param + csStart); |
290 |
< |
int16 count = ReadMacInt16(param + csCount); |
291 |
< |
if (s_pal == NULL || count > 256) return controlErr; |
288 |
> |
uint32 s_pal = ReadMacInt32(param + csTable); |
289 |
> |
uint16 start = ReadMacInt16(param + csStart); |
290 |
> |
uint16 count = ReadMacInt16(param + csCount); |
291 |
> |
if (s_pal == 0 || count > 256) return controlErr; |
292 |
|
|
293 |
|
// Preparations for gamma correction |
294 |
|
bool do_gamma = false; |
296 |
|
uint8 *green_gamma = NULL; |
297 |
|
uint8 *blue_gamma = NULL; |
298 |
|
int gamma_data_width = 0; |
299 |
< |
if (display_type == DIS_SCREEN && csSave->gammaTable != NULL) { // Windows are gamma-corrected by BeOS |
300 |
< |
do_gamma = true; |
301 |
< |
GammaTbl *gamma = csSave->gammaTable; |
302 |
< |
gamma_data_width = gamma->gDataWidth; |
303 |
< |
red_gamma = (uint8 *)&gamma->gFormulaData + gamma->gFormulaSize; |
304 |
< |
if (gamma->gChanCnt == 1) { |
305 |
< |
green_gamma = blue_gamma = red_gamma; |
306 |
< |
} else { |
307 |
< |
green_gamma = red_gamma + gamma->gDataCnt; |
308 |
< |
blue_gamma = red_gamma + 2 * gamma->gDataCnt; |
299 |
> |
if (csSave->gammaTable) { |
300 |
> |
#ifdef __BEOS__ |
301 |
> |
// Windows are gamma-corrected by BeOS |
302 |
> |
const bool can_do_gamma = (display_type == DIS_SCREEN); |
303 |
> |
#else |
304 |
> |
const bool can_do_gamma = true; |
305 |
> |
#endif |
306 |
> |
if (can_do_gamma) { |
307 |
> |
uint32 gamma_table = csSave->gammaTable; |
308 |
> |
red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize)); |
309 |
> |
int chan_cnt = ReadMacInt16(gamma_table + gChanCnt); |
310 |
> |
if (chan_cnt == 1) |
311 |
> |
green_gamma = blue_gamma = red_gamma; |
312 |
> |
else { |
313 |
> |
int ofs = ReadMacInt16(gamma_table + gDataCnt); |
314 |
> |
green_gamma = red_gamma + ofs; |
315 |
> |
blue_gamma = green_gamma + ofs; |
316 |
> |
} |
317 |
> |
gamma_data_width = ReadMacInt16(gamma_table + gDataWidth); |
318 |
> |
do_gamma = true; |
319 |
|
} |
320 |
|
} |
321 |
|
|
322 |
|
// Set palette |
323 |
|
rgb_color *d_pal; |
324 |
< |
if (start == -1) { // Indexed |
324 |
> |
if (start == 0xffff) { // Indexed |
325 |
|
for (int i=0; i<=count; i++) { |
326 |
< |
d_pal = &(mac_pal[(*s_pal).value]); |
327 |
< |
uint8 red = (*s_pal).red >> 8; |
328 |
< |
uint8 green = (*s_pal).green >> 8; |
329 |
< |
uint8 blue = (*s_pal).blue >> 8; |
326 |
> |
d_pal = mac_pal + (ReadMacInt16(s_pal + csValue) & 0xff); |
327 |
> |
uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8; |
328 |
> |
uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8; |
329 |
> |
uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8; |
330 |
|
if (csSave->luminanceMapping) |
331 |
|
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; |
332 |
|
if (do_gamma) { |
337 |
|
(*d_pal).red = red; |
338 |
|
(*d_pal).green = green; |
339 |
|
(*d_pal).blue = blue; |
340 |
< |
s_pal++; |
340 |
> |
s_pal += 8; |
341 |
|
} |
342 |
< |
} else { // Sequential |
343 |
< |
d_pal = &(mac_pal[start]); |
342 |
> |
} else { // Sequential |
343 |
> |
d_pal = mac_pal + start; |
344 |
|
for (int i=0; i<=count; i++) { |
345 |
< |
uint8 red = (*s_pal).red >> 8; |
346 |
< |
uint8 green = (*s_pal).green >> 8; |
347 |
< |
uint8 blue = (*s_pal).blue >> 8; |
345 |
> |
uint8 red = (uint16)ReadMacInt16(s_pal + csRed) >> 8; |
346 |
> |
uint8 green = (uint16)ReadMacInt16(s_pal + csGreen) >> 8; |
347 |
> |
uint8 blue = (uint16)ReadMacInt16(s_pal + csBlue) >> 8; |
348 |
|
if (csSave->luminanceMapping) |
349 |
|
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; |
350 |
|
if (do_gamma) { |
355 |
|
(*d_pal).red = red; |
356 |
|
(*d_pal).green = green; |
357 |
|
(*d_pal).blue = blue; |
358 |
< |
d_pal++; s_pal++; |
358 |
> |
d_pal++; |
359 |
> |
s_pal += 8; |
360 |
|
} |
361 |
|
} |
362 |
|
video_set_palette(); |
363 |
|
return noErr; |
364 |
|
} |
365 |
|
|
366 |
< |
case cscSetGamma: // SetGamma |
367 |
< |
D(bug("SetGamma\n")); |
368 |
< |
return set_gamma(csSave, ReadMacInt32(param)); |
366 |
> |
case cscSetGamma: { // SetGamma |
367 |
> |
uint32 user_table = ReadMacInt32(param + csGTable); |
368 |
> |
D(bug("SetGamma %08x\n", user_table)); |
369 |
> |
return set_gamma(csSave, ReadMacInt32(user_table)); |
370 |
> |
} |
371 |
|
|
372 |
|
case cscGrayPage: { // GrayPage |
373 |
< |
D(bug("GrayPage\n")); |
374 |
< |
uint32 *screen = (uint32 *)csSave->saveBaseAddr; |
375 |
< |
uint32 pattern; |
376 |
< |
uint32 row_bytes = VModes[cur_mode].viRowBytes; |
377 |
< |
switch (VModes[cur_mode].viAppleMode) { |
378 |
< |
case APPLE_8_BIT: |
379 |
< |
pattern=0xff00ff00; |
380 |
< |
for (int i=0;i<VModes[cur_mode].viYsize;i++) { |
381 |
< |
for (int j=0;j<(VModes[cur_mode].viXsize>>2);j++) |
382 |
< |
screen[j] = pattern; |
383 |
< |
pattern = ~pattern; |
384 |
< |
screen = (uint32 *)((uint32)screen + row_bytes); |
385 |
< |
} |
386 |
< |
break; |
387 |
< |
case APPLE_16_BIT: |
388 |
< |
pattern=0xffff0000; |
389 |
< |
for (int i=0;i<VModes[cur_mode].viYsize;i++) { |
390 |
< |
for (int j=0;j<(VModes[cur_mode].viXsize>>1);j++) |
391 |
< |
screen[j]=pattern; |
392 |
< |
pattern = ~pattern; |
393 |
< |
screen = (uint32 *)((uint32)screen + row_bytes); |
394 |
< |
} |
395 |
< |
break; |
384 |
< |
case APPLE_32_BIT: |
385 |
< |
pattern=0xffffffff; |
386 |
< |
for (int i=0;i<VModes[cur_mode].viYsize;i++) { |
387 |
< |
for (int j=0;j<VModes[cur_mode].viXsize;j++) { |
388 |
< |
screen[j]=pattern; |
389 |
< |
pattern = ~pattern; |
390 |
< |
} |
391 |
< |
screen = (uint32 *)((uint32)screen + row_bytes); |
392 |
< |
} |
393 |
< |
break; |
373 |
> |
D(bug("GrayPage %d\n", ReadMacInt16(param + csPage))); |
374 |
> |
if (ReadMacInt16(param + csPage)) |
375 |
> |
return paramErr; |
376 |
> |
|
377 |
> |
uint32 pattern[6] = { |
378 |
> |
0xaaaaaaaa, // 1 bpp |
379 |
> |
0xcccccccc, // 2 bpp |
380 |
> |
0xf0f0f0f0, // 4 bpp |
381 |
> |
0xff00ff00, // 8 bpp |
382 |
> |
0xffff0000, // 16 bpp |
383 |
> |
0xffffffff // 32 bpp |
384 |
> |
}; |
385 |
> |
uint32 p = csSave->saveBaseAddr; |
386 |
> |
uint32 pat = pattern[VModes[cur_mode].viAppleMode - APPLE_1_BIT]; |
387 |
> |
bool invert = (VModes[cur_mode].viAppleMode == APPLE_32_BIT); |
388 |
> |
for (uint32 y=0; y<VModes[cur_mode].viYsize; y++) { |
389 |
> |
for (uint32 x=0; x<VModes[cur_mode].viRowBytes; x+=4) { |
390 |
> |
WriteMacInt32(p + x, pat); |
391 |
> |
if (invert) |
392 |
> |
pat = ~pat; |
393 |
> |
} |
394 |
> |
p += VModes[cur_mode].viRowBytes; |
395 |
> |
pat = ~pat; |
396 |
|
} |
397 |
|
return noErr; |
398 |
|
} |
428 |
|
|
429 |
|
case cscSetHardwareCursor: { |
430 |
|
// D(bug("SetHardwareCursor\n")); |
431 |
+ |
|
432 |
+ |
if (!csSave->cursorHardware) |
433 |
+ |
return controlErr; |
434 |
+ |
|
435 |
|
csSave->cursorSet = false; |
436 |
|
bool changed = false; |
437 |
|
|
432 |
– |
// Get cursor data even on a screen, to set the right cursor image when switching back to a window |
438 |
|
// Image |
439 |
|
uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage |
440 |
|
uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap); |
441 |
|
if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0) |
442 |
|
return controlErr; |
443 |
|
uint32 pixmap = ReadMacInt32(pmhandle); |
444 |
< |
if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) { |
445 |
< |
memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32); |
446 |
< |
changed = true; |
447 |
< |
} |
444 |
> |
|
445 |
> |
// XXX: only certain image formats are handled properly at the moment |
446 |
> |
uint16 rowBytes = ReadMacInt16(pixmap + 4) & 0x7FFF; |
447 |
> |
if (rowBytes != 2) |
448 |
> |
return controlErr; |
449 |
|
|
450 |
|
// Mask |
451 |
|
uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask); |
452 |
|
if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0) |
453 |
|
return controlErr; |
454 |
|
uint32 bitmap = ReadMacInt32(bmhandle); |
455 |
+ |
|
456 |
+ |
// Get cursor data even on a screen, to set the right cursor image when switching back to a window. |
457 |
+ |
// Hotspot is stale, but will be fixed by the next call to DrawHardwareCursor, which is likely to |
458 |
+ |
// occur immediately hereafter. |
459 |
+ |
|
460 |
+ |
if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) { |
461 |
+ |
memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32); |
462 |
+ |
changed = true; |
463 |
+ |
} |
464 |
|
if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) { |
465 |
|
memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32); |
466 |
|
changed = true; |
467 |
|
} |
468 |
|
|
454 |
– |
// Hotspot (!! this doesn't work) |
455 |
– |
MacCursor[2] = ReadMacInt8(0x885); |
456 |
– |
MacCursor[3] = ReadMacInt8(0x887); |
457 |
– |
|
469 |
|
// Set new cursor image |
470 |
< |
if (display_type == DIS_SCREEN) |
470 |
> |
if (!video_can_change_cursor()) |
471 |
|
return controlErr; |
472 |
|
if (changed) |
473 |
|
video_set_cursor(); |
474 |
|
|
475 |
|
csSave->cursorSet = true; |
476 |
+ |
csSave->cursorHotFlag = true; |
477 |
|
return noErr; |
478 |
|
} |
479 |
|
|
480 |
< |
case cscDrawHardwareCursor: |
480 |
> |
case cscDrawHardwareCursor: { |
481 |
|
// D(bug("DrawHardwareCursor\n")); |
482 |
+ |
|
483 |
+ |
if (!csSave->cursorHardware) |
484 |
+ |
return controlErr; |
485 |
+ |
|
486 |
+ |
int32 oldX = csSave->cursorX; |
487 |
+ |
int32 oldY = csSave->cursorY; |
488 |
+ |
uint32 oldVisible = csSave->cursorVisible; |
489 |
+ |
|
490 |
|
csSave->cursorX = ReadMacInt32(param + csCursorX); |
491 |
|
csSave->cursorY = ReadMacInt32(param + csCursorY); |
492 |
|
csSave->cursorVisible = ReadMacInt32(param + csCursorVisible); |
493 |
+ |
bool changed = (csSave->cursorVisible != oldVisible); |
494 |
+ |
|
495 |
+ |
// If this is the first DrawHardwareCursor call since the cursor was last set (via SetHardwareCursor), |
496 |
+ |
// attempt to set an appropriate cursor hotspot. SetHardwareCursor itself does not know what the |
497 |
+ |
// hotspot should be; it knows only the cursor image and mask. The hotspot is known only to the caller, |
498 |
+ |
// and we have to try to infer it here. The usual sequence of calls when changing the cursor is: |
499 |
+ |
// |
500 |
+ |
// DrawHardwareCursor with (oldX, oldY, invisible) |
501 |
+ |
// SetHardwareCursor with (cursor) |
502 |
+ |
// DrawHardwareCursor with (newX, newY, visible) |
503 |
+ |
// |
504 |
+ |
// The key thing to note is that the sequence is intended not to change the current screen pixel location |
505 |
+ |
// indicated by the hotspot. Thus, the difference between (newX, newY) and (oldX, oldY) reflects precisely |
506 |
+ |
// the difference between the old cursor hotspot and the new one. For example, if you change from a |
507 |
+ |
// cursor whose hotspot is (1, 1) to one whose hotspot is (7, 4), then you must adjust the cursor position |
508 |
+ |
// by (-6, -3) in order for the same screen pixel to remain under the new hotspot. |
509 |
+ |
// |
510 |
+ |
// Alas, on rare occasions this heuristic can fail, and if you did nothing else you could even get stuck |
511 |
+ |
// with the wrong hotspot from then on. To address that possibility, we force the hotspot to (1, 1) |
512 |
+ |
// whenever the cursor being drawn is the standard arrow. Thus, while it is very unlikely that you will |
513 |
+ |
// ever have the wrong hotspot, if you do, it is easy to recover. |
514 |
+ |
|
515 |
+ |
if (csSave->cursorHotFlag) { |
516 |
+ |
csSave->cursorHotFlag = false; |
517 |
+ |
D(bug("old hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY)); |
518 |
+ |
|
519 |
+ |
static uint8 arrow[] = { |
520 |
+ |
0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00, |
521 |
+ |
0x7F, 0x80, 0x7C, 0x00, 0x6C, 0x00, 0x46, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, |
522 |
+ |
}; |
523 |
+ |
if (memcmp(MacCursor + 4, arrow, 32) == 0) { |
524 |
+ |
csSave->cursorHotX = 1; |
525 |
+ |
csSave->cursorHotY = 1; |
526 |
+ |
} else if (csSave->cursorX != oldX || csSave->cursorY != oldY) { |
527 |
+ |
int32 hotX = csSave->cursorHotX + (oldX - csSave->cursorX); |
528 |
+ |
int32 hotY = csSave->cursorHotY + (oldY - csSave->cursorY); |
529 |
+ |
|
530 |
+ |
if (0 <= hotX && hotX <= 15 && 0 <= hotY && hotY <= 15) { |
531 |
+ |
csSave->cursorHotX = hotX; |
532 |
+ |
csSave->cursorHotY = hotY; |
533 |
+ |
} |
534 |
+ |
} |
535 |
+ |
if (MacCursor[2] != csSave->cursorHotX || MacCursor[3] != csSave->cursorHotY) { |
536 |
+ |
MacCursor[2] = csSave->cursorHotX; |
537 |
+ |
MacCursor[3] = csSave->cursorHotY; |
538 |
+ |
changed = true; |
539 |
+ |
} |
540 |
+ |
D(bug("new hotspot (%d, %d)\n", csSave->cursorHotX, csSave->cursorHotY)); |
541 |
+ |
} |
542 |
+ |
|
543 |
+ |
if (changed && video_can_change_cursor()) |
544 |
+ |
video_set_cursor(); |
545 |
+ |
|
546 |
|
return noErr; |
547 |
+ |
} |
548 |
|
|
549 |
|
case 43: { // Driver Gestalt |
550 |
|
uint32 sel = ReadMacInt32(pb + csParam); |
601 |
|
return max; |
602 |
|
} |
603 |
|
|
604 |
+ |
// Get X/Y size of specified resolution |
605 |
+ |
static void get_size_of_resolution(int id, uint32 &x, uint32 &y) |
606 |
+ |
{ |
607 |
+ |
VideoInfo *p = VModes; |
608 |
+ |
while (p->viType != DIS_INVALID) { |
609 |
+ |
if (p->viAppleID == id) { |
610 |
+ |
x = p->viXsize; |
611 |
+ |
y = p->viYsize; |
612 |
+ |
return; |
613 |
+ |
} |
614 |
+ |
p++; |
615 |
+ |
} |
616 |
+ |
x = y = 0; |
617 |
+ |
} |
618 |
+ |
|
619 |
|
static int16 VideoStatus(uint32 pb, VidLocals *csSave) |
620 |
|
{ |
621 |
|
int16 code = ReadMacInt16(pb + csCode); |
635 |
|
|
636 |
|
case cscGetEntries: { // GetEntries |
637 |
|
D(bug("GetEntries\n")); |
638 |
< |
ColorSpec *d_pal = (ColorSpec *)Mac2HostAddr(ReadMacInt32(param + csTable)); |
639 |
< |
int16 start = ReadMacInt16(param + csStart); |
640 |
< |
int16 count = ReadMacInt16(param + csCount); |
638 |
> |
uint32 d_pal = ReadMacInt32(param + csTable); |
639 |
> |
uint16 start = ReadMacInt16(param + csStart); |
640 |
> |
uint16 count = ReadMacInt16(param + csCount); |
641 |
|
rgb_color *s_pal; |
642 |
|
if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)|| |
643 |
|
(VModes[cur_mode].viAppleMode == APPLE_16_BIT)) { |
644 |
|
D(bug("ERROR: GetEntries in direct mode \n")); |
645 |
|
return statusErr; |
646 |
|
} |
647 |
< |
if (start >= 0) { // indexed get |
648 |
< |
s_pal = &(mac_pal[start]); |
647 |
> |
|
648 |
> |
if (start == 0xffff) { // Indexed |
649 |
|
for (uint16 i=0;i<count;i++) { |
650 |
< |
(*d_pal).red=(uint16)((*s_pal).red)*0x101; |
651 |
< |
(*d_pal).green=(uint16)((*s_pal).green)*0x101; |
652 |
< |
(*d_pal).blue=(uint16)((*s_pal).blue)*0x101; |
653 |
< |
d_pal++; s_pal++; |
650 |
> |
s_pal = mac_pal + (ReadMacInt16(d_pal + csValue) & 0xff); |
651 |
> |
uint8 red = (*s_pal).red; |
652 |
> |
uint8 green = (*s_pal).green; |
653 |
> |
uint8 blue = (*s_pal).blue; |
654 |
> |
WriteMacInt16(d_pal + csRed, red * 0x0101); |
655 |
> |
WriteMacInt16(d_pal + csGreen, green * 0x0101); |
656 |
> |
WriteMacInt16(d_pal + csBlue, blue * 0x0101); |
657 |
> |
d_pal += 8; |
658 |
|
} |
659 |
< |
} else { // selected set |
659 |
> |
} else { // Sequential |
660 |
> |
if (start + count > 255) |
661 |
> |
return paramErr; |
662 |
> |
s_pal = mac_pal + start; |
663 |
|
for (uint16 i=0;i<count;i++) { |
664 |
< |
s_pal = &(mac_pal[(*d_pal).value]); |
665 |
< |
(*d_pal).red=(uint16)((*s_pal).red)*0x101; |
666 |
< |
(*d_pal).green=(uint16)((*s_pal).green)*0x101; |
667 |
< |
(*d_pal).blue=(uint16)((*s_pal).blue)*0x101; |
668 |
< |
d_pal++; |
664 |
> |
uint8 red = (*s_pal).red; |
665 |
> |
uint8 green = (*s_pal).green; |
666 |
> |
uint8 blue = (*s_pal).blue; |
667 |
> |
s_pal++; |
668 |
> |
WriteMacInt16(d_pal + csRed, red * 0x0101); |
669 |
> |
WriteMacInt16(d_pal + csGreen, green * 0x0101); |
670 |
> |
WriteMacInt16(d_pal + csBlue, blue * 0x0101); |
671 |
> |
d_pal += 8; |
672 |
|
} |
673 |
|
}; |
674 |
|
return noErr; |
697 |
|
case cscGetGamma: // GetGamma |
698 |
|
D(bug("GetGamma\n")); |
699 |
|
WriteMacInt32(param, (uint32)csSave->gammaTable); |
700 |
< |
return statusErr; |
700 |
> |
return noErr; |
701 |
|
|
702 |
|
case cscGetDefaultMode: // GetDefaultMode |
703 |
|
D(bug("GetDefaultMode\n")); |
787 |
|
WriteMacInt32(param + csVerticalLines, 768); |
788 |
|
WriteMacInt32(param + csRefreshRate, 75<<16); |
789 |
|
break; |
790 |
+ |
case APPLE_1152x768: |
791 |
+ |
WriteMacInt32(param + csHorizontalPixels, 1152); |
792 |
+ |
WriteMacInt32(param + csVerticalLines, 768); |
793 |
+ |
WriteMacInt32(param + csRefreshRate, 75<<16); |
794 |
+ |
break; |
795 |
|
case APPLE_1152x900: |
796 |
|
WriteMacInt32(param + csHorizontalPixels, 1152); |
797 |
|
WriteMacInt32(param + csVerticalLines, 900); |
807 |
|
WriteMacInt32(param + csVerticalLines, 1200); |
808 |
|
WriteMacInt32(param + csRefreshRate, 75<<16); |
809 |
|
break; |
810 |
+ |
case APPLE_CUSTOM: { |
811 |
+ |
uint32 x, y; |
812 |
+ |
get_size_of_resolution(work_id, x, y); |
813 |
+ |
WriteMacInt32(param + csHorizontalPixels, x); |
814 |
+ |
WriteMacInt32(param + csVerticalLines, y); |
815 |
+ |
WriteMacInt32(param + csRefreshRate, 75<<16); |
816 |
+ |
break; |
817 |
+ |
} |
818 |
|
} |
819 |
|
return noErr; |
820 |
|
} |
918 |
|
case APPLE_1024x768: |
919 |
|
timing = timingVESA_1024x768_75hz; |
920 |
|
break; |
921 |
+ |
case APPLE_1152x768: |
922 |
+ |
timing = timingApple_1152x870_75hz; // FIXME |
923 |
+ |
break; |
924 |
|
case APPLE_1152x900: |
925 |
|
timing = timingApple_1152x870_75hz; |
926 |
|
break; |
943 |
|
|
944 |
|
case cscSupportsHardwareCursor: |
945 |
|
D(bug("SupportsHardwareCursor\n")); |
946 |
< |
WriteMacInt32(param, 1); |
946 |
> |
WriteMacInt32(param, csSave->cursorHardware); |
947 |
|
return noErr; |
948 |
|
|
949 |
|
case cscGetHardwareCursorDrawState: |
950 |
|
D(bug("GetHardwareCursorDrawState\n")); |
951 |
+ |
|
952 |
+ |
if (!csSave->cursorHardware) |
953 |
+ |
return statusErr; |
954 |
+ |
|
955 |
|
WriteMacInt32(param + csCursorX, csSave->cursorX); |
956 |
|
WriteMacInt32(param + csCursorY, csSave->cursorY); |
957 |
|
WriteMacInt32(param + csCursorVisible, csSave->cursorVisible); |
985 |
|
* Native (PCI) driver entry |
986 |
|
*/ |
987 |
|
|
988 |
< |
int16 VideoDoDriverIO(void *spaceID, void *commandID, void *commandContents, uint32 commandCode, uint32 commandKind) |
988 |
> |
int16 VideoDoDriverIO(uint32 spaceID, uint32 commandID, uint32 commandContents, uint32 commandCode, uint32 commandKind) |
989 |
|
{ |
990 |
< |
// D(bug("VideoDoDriverIO space %p, command %p, contents %p, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind)); |
990 |
> |
// D(bug("VideoDoDriverIO space %08x, command %08x, contents %08x, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind)); |
991 |
|
int16 err = noErr; |
992 |
|
|
993 |
|
switch (commandCode) { |
994 |
|
case kInitializeCommand: |
995 |
|
case kReplaceCommand: |
996 |
< |
if (private_data != NULL) // Might be left over from a reboot |
997 |
< |
delete private_data->gammaTable; |
996 |
> |
if (private_data != NULL) { // Might be left over from a reboot |
997 |
> |
if (private_data->gammaTable) |
998 |
> |
Mac_sysfree(private_data->gammaTable); |
999 |
> |
if (private_data->regEntryID) |
1000 |
> |
Mac_sysfree(private_data->regEntryID); |
1001 |
> |
} |
1002 |
|
delete private_data; |
1003 |
|
|
1004 |
< |
iocic_tvect = (uint32)FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); |
1004 |
> |
iocic_tvect = FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); |
1005 |
|
D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect)); |
1006 |
|
if (iocic_tvect == 0) { |
1007 |
|
printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n"); |
1008 |
|
err = -1; |
1009 |
|
break; |
1010 |
|
} |
1011 |
< |
vslnewis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService"); |
1011 |
> |
vslnewis_tvect = FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService"); |
1012 |
|
D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect)); |
1013 |
|
if (vslnewis_tvect == 0) { |
1014 |
|
printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n"); |
1015 |
|
err = -1; |
1016 |
|
break; |
1017 |
|
} |
1018 |
< |
vsldisposeis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService"); |
1018 |
> |
vsldisposeis_tvect = FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService"); |
1019 |
|
D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect)); |
1020 |
|
if (vsldisposeis_tvect == 0) { |
1021 |
|
printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n"); |
1022 |
|
err = -1; |
1023 |
|
break; |
1024 |
|
} |
1025 |
< |
vsldois_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService"); |
1025 |
> |
vsldois_tvect = FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService"); |
1026 |
|
D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect)); |
1027 |
|
if (vsldois_tvect == 0) { |
1028 |
|
printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n"); |
1029 |
|
err = -1; |
1030 |
|
break; |
1031 |
|
} |
1032 |
< |
nqdmisc_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\007NQDMisc"); |
1032 |
> |
nqdmisc_tvect = FindLibSymbol("\014InterfaceLib", "\007NQDMisc"); |
1033 |
|
D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect)); |
1034 |
|
if (nqdmisc_tvect == 0) { |
1035 |
|
printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n"); |
1038 |
|
} |
1039 |
|
|
1040 |
|
private_data = new VidLocals; |
1041 |
< |
private_data->gammaTable = NULL; |
1042 |
< |
memcpy(private_data->regEntryID, (uint8 *)commandContents + 2, 16); // DriverInitInfo.deviceEntry |
1041 |
> |
private_data->gammaTable = 0; |
1042 |
> |
private_data->regEntryID = Mac_sysalloc(sizeof(RegEntryID)); |
1043 |
> |
if (private_data->regEntryID == 0) { |
1044 |
> |
printf("FATAL: VideoDoDriverIO(): Can't allocate service owner\n"); |
1045 |
> |
err = -1; |
1046 |
> |
break; |
1047 |
> |
} |
1048 |
> |
Mac2Mac_memcpy(private_data->regEntryID, commandContents + 2, 16); // DriverInitInfo.deviceEntry |
1049 |
|
private_data->interruptsEnabled = false; // Disable interrupts |
1050 |
|
break; |
1051 |
|
|
1052 |
|
case kFinalizeCommand: |
1053 |
|
case kSupersededCommand: |
1054 |
< |
if (private_data != NULL) |
1055 |
< |
delete private_data->gammaTable; |
1054 |
> |
if (private_data != NULL) { |
1055 |
> |
if (private_data->gammaTable) |
1056 |
> |
Mac_sysfree(private_data->gammaTable); |
1057 |
> |
if (private_data->regEntryID) |
1058 |
> |
Mac_sysfree(private_data->regEntryID); |
1059 |
> |
} |
1060 |
|
delete private_data; |
1061 |
|
private_data = NULL; |
1062 |
|
break; |
1063 |
|
|
1064 |
|
case kOpenCommand: |
1065 |
< |
err = VideoOpen((uint32)commandContents, private_data); |
1065 |
> |
err = VideoOpen(commandContents, private_data); |
1066 |
|
break; |
1067 |
|
|
1068 |
|
case kCloseCommand: |
1069 |
< |
err = VideoClose((uint32)commandContents, private_data); |
1069 |
> |
err = VideoClose(commandContents, private_data); |
1070 |
|
break; |
1071 |
|
|
1072 |
|
case kControlCommand: |
1073 |
< |
err = VideoControl((uint32)commandContents, private_data); |
1073 |
> |
err = VideoControl(commandContents, private_data); |
1074 |
|
break; |
1075 |
|
|
1076 |
|
case kStatusCommand: |
1077 |
< |
err = VideoStatus((uint32)commandContents, private_data); |
1077 |
> |
err = VideoStatus(commandContents, private_data); |
1078 |
|
break; |
1079 |
|
|
1080 |
|
case kReadCommand: |