52 |
|
bool luminance_mapping; // Luminance mapping on/off |
53 |
|
bool interrupts_enabled; // VBL interrupts on/off |
54 |
|
uint32 gamma_table; // Mac address of gamma table |
55 |
+ |
int alloc_gamma_table_size; // Allocated size of gamma table |
56 |
|
uint16 current_mode; // Currently selected depth/resolution |
57 |
|
uint32 current_id; |
58 |
|
uint16 preferred_mode; // Preferred depth/resolution |
134 |
|
|
135 |
|
static void set_gray_palette(void) |
136 |
|
{ |
137 |
< |
if (!IsDirectMode(VidLocal.current_mode)) { |
138 |
< |
for (int i=0; i<256; i++) { |
139 |
< |
VidLocal.palette[i * 3 + 0] = 127; |
140 |
< |
VidLocal.palette[i * 3 + 1] = 127; |
141 |
< |
VidLocal.palette[i * 3 + 2] = 127; |
137 |
> |
for (int i=0; i<256; i++) { |
138 |
> |
VidLocal.palette[i * 3 + 0] = 127; |
139 |
> |
VidLocal.palette[i * 3 + 1] = 127; |
140 |
> |
VidLocal.palette[i * 3 + 2] = 127; |
141 |
> |
} |
142 |
> |
video_set_palette(VidLocal.palette); |
143 |
> |
} |
144 |
> |
|
145 |
> |
|
146 |
> |
/* |
147 |
> |
* Load gamma-corrected black-to-white ramp to palette for direct-color mode |
148 |
> |
*/ |
149 |
> |
|
150 |
> |
static void load_ramp_palette(void) |
151 |
> |
{ |
152 |
> |
// Find tables for gamma correction |
153 |
> |
uint8 *red_gamma, *green_gamma, *blue_gamma; |
154 |
> |
bool have_gamma = false; |
155 |
> |
int data_width = 0; |
156 |
> |
if (VidLocal.gamma_table) { |
157 |
> |
uint32 table = VidLocal.gamma_table; |
158 |
> |
red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize)); |
159 |
> |
int chan_cnt = ReadMacInt16(table + gChanCnt); |
160 |
> |
if (chan_cnt == 1) |
161 |
> |
green_gamma = blue_gamma = red_gamma; |
162 |
> |
else { |
163 |
> |
int ofs = ReadMacInt16(table + gDataCnt); |
164 |
> |
green_gamma = red_gamma + ofs; |
165 |
> |
blue_gamma = green_gamma + ofs; |
166 |
> |
} |
167 |
> |
data_width = ReadMacInt16(table + gDataWidth); |
168 |
> |
have_gamma = true; |
169 |
> |
} |
170 |
> |
|
171 |
> |
int num = (VidLocal.desc->mode.depth == VDEPTH_16BIT ? 32 : 256); |
172 |
> |
int inc = 256 / num, value = 0; |
173 |
> |
uint8 *p = VidLocal.palette; |
174 |
> |
for (int i=0; i<num; i++) { |
175 |
> |
uint8 red = value, green = value, blue = value; |
176 |
> |
if (have_gamma) { |
177 |
> |
red = red_gamma[red >> (8 - data_width)]; |
178 |
> |
green = green_gamma[green >> (8 - data_width)]; |
179 |
> |
blue = blue_gamma[blue >> (8 - data_width)]; |
180 |
> |
} |
181 |
> |
*p++ = red; |
182 |
> |
*p++ = green; |
183 |
> |
*p++ = blue; |
184 |
> |
value += inc; |
185 |
> |
} |
186 |
> |
|
187 |
> |
video_set_palette(VidLocal.palette); |
188 |
> |
} |
189 |
> |
|
190 |
> |
|
191 |
> |
/* |
192 |
> |
* Allocate gamma table of specified size |
193 |
> |
*/ |
194 |
> |
|
195 |
> |
static bool allocate_gamma_table(int size) |
196 |
> |
{ |
197 |
> |
M68kRegisters r; |
198 |
> |
|
199 |
> |
if (size > VidLocal.alloc_gamma_table_size) { |
200 |
> |
if (VidLocal.gamma_table) { |
201 |
> |
r.a[0] = VidLocal.gamma_table; |
202 |
> |
Execute68kTrap(0xa01f, &r); // DisposePtr() |
203 |
> |
VidLocal.gamma_table = 0; |
204 |
> |
VidLocal.alloc_gamma_table_size = 0; |
205 |
|
} |
206 |
< |
video_set_palette(VidLocal.palette); |
206 |
> |
r.d[0] = size; |
207 |
> |
Execute68kTrap(0xa71e, &r); // NewPtrSysClear() |
208 |
> |
if (r.a[0] == 0) |
209 |
> |
return false; |
210 |
> |
VidLocal.gamma_table = r.a[0]; |
211 |
> |
VidLocal.alloc_gamma_table_size = size; |
212 |
|
} |
213 |
+ |
return true; |
214 |
+ |
} |
215 |
+ |
|
216 |
+ |
|
217 |
+ |
/* |
218 |
+ |
* Set gamma table (0 = build linear ramp) |
219 |
+ |
*/ |
220 |
+ |
|
221 |
+ |
static bool set_gamma_table(uint32 user_table) |
222 |
+ |
{ |
223 |
+ |
if (user_table == 0) { // Build linear ramp, 256 entries |
224 |
+ |
|
225 |
+ |
// Allocate new table, if necessary |
226 |
+ |
if (!allocate_gamma_table(SIZEOF_GammaTbl + 256)) |
227 |
+ |
return memFullErr; |
228 |
+ |
uint32 table = VidLocal.gamma_table; |
229 |
+ |
|
230 |
+ |
// Initialize header |
231 |
+ |
WriteMacInt16(table + gVersion, 0); |
232 |
+ |
WriteMacInt16(table + gType, 0); |
233 |
+ |
WriteMacInt16(table + gFormulaSize, 0); |
234 |
+ |
WriteMacInt16(table + gChanCnt, 1); |
235 |
+ |
WriteMacInt16(table + gDataCnt, 256); |
236 |
+ |
WriteMacInt16(table + gDataWidth, 8); |
237 |
+ |
|
238 |
+ |
// Build ramp |
239 |
+ |
uint32 p = table + gFormulaData; |
240 |
+ |
for (int i=0; i<256; i++) |
241 |
+ |
WriteMacInt8(p + i, i); |
242 |
+ |
|
243 |
+ |
} else { // User-supplied gamma table |
244 |
+ |
|
245 |
+ |
// Validate header |
246 |
+ |
if (ReadMacInt16(user_table + gVersion)) |
247 |
+ |
return paramErr; |
248 |
+ |
if (ReadMacInt16(user_table + gType)) |
249 |
+ |
return paramErr; |
250 |
+ |
int chan_cnt = ReadMacInt16(user_table + gChanCnt); |
251 |
+ |
if (chan_cnt != 1 && chan_cnt != 3) |
252 |
+ |
return paramErr; |
253 |
+ |
int data_width = ReadMacInt16(user_table + gDataWidth); |
254 |
+ |
if (data_width > 8) |
255 |
+ |
return paramErr; |
256 |
+ |
int data_cnt = ReadMacInt16(user_table + gDataCnt); |
257 |
+ |
if (data_cnt != (1 << data_width)) |
258 |
+ |
return paramErr; |
259 |
+ |
|
260 |
+ |
// Allocate new table, if necessary |
261 |
+ |
int size = SIZEOF_GammaTbl + ReadMacInt16(user_table + gFormulaSize) + chan_cnt * data_cnt; |
262 |
+ |
if (!allocate_gamma_table(size)) |
263 |
+ |
return memFullErr; |
264 |
+ |
uint32 table = VidLocal.gamma_table; |
265 |
+ |
|
266 |
+ |
// Copy table |
267 |
+ |
Mac2Mac_memcpy(table, user_table, size); |
268 |
+ |
} |
269 |
+ |
|
270 |
+ |
if (IsDirectMode(VidLocal.current_mode)) |
271 |
+ |
load_ramp_palette(); |
272 |
+ |
|
273 |
+ |
return true; |
274 |
|
} |
275 |
|
|
276 |
|
|
305 |
|
D(bug("SPBlock at %08x\n", VidLocal.sp)); |
306 |
|
|
307 |
|
// Find and set default gamma table |
308 |
< |
VidLocal.gamma_table = 0; //!! |
308 |
> |
VidLocal.gamma_table = 0; |
309 |
> |
VidLocal.alloc_gamma_table_size = 0; |
310 |
> |
set_gamma_table(0); |
311 |
|
|
312 |
|
// Init color palette (solid gray) |
313 |
|
set_gray_palette(); |
350 |
|
return noErr; |
351 |
|
} |
352 |
|
|
353 |
< |
case cscSetEntries: { // Set palette |
354 |
< |
D(bug(" SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); |
355 |
< |
if (IsDirectMode(VidLocal.current_mode)) |
353 |
> |
case cscSetEntries: // Set palette |
354 |
> |
case cscDirectSetEntries: { |
355 |
> |
D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); |
356 |
> |
bool is_direct = IsDirectMode(VidLocal.current_mode); |
357 |
> |
if (code == cscSetEntries && is_direct) |
358 |
> |
return controlErr; |
359 |
> |
if (code == cscDirectSetEntries && !is_direct) |
360 |
|
return controlErr; |
361 |
|
|
362 |
|
uint32 s_pal = ReadMacInt32(param + csTable); // Source palette |
366 |
|
if (s_pal == 0 || count > 255) |
367 |
|
return paramErr; |
368 |
|
|
369 |
+ |
// Find tables for gamma correction |
370 |
+ |
uint8 *red_gamma, *green_gamma, *blue_gamma; |
371 |
+ |
bool have_gamma = false; |
372 |
+ |
int data_width = 0; |
373 |
+ |
if (VidLocal.gamma_table) { |
374 |
+ |
uint32 table = VidLocal.gamma_table; |
375 |
+ |
red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize)); |
376 |
+ |
int chan_cnt = ReadMacInt16(table + gChanCnt); |
377 |
+ |
if (chan_cnt == 1) |
378 |
+ |
green_gamma = blue_gamma = red_gamma; |
379 |
+ |
else { |
380 |
+ |
int ofs = ReadMacInt16(table + gDataCnt); |
381 |
+ |
green_gamma = red_gamma + ofs; |
382 |
+ |
blue_gamma = green_gamma + ofs; |
383 |
+ |
} |
384 |
+ |
data_width = ReadMacInt16(table + gDataWidth); |
385 |
+ |
have_gamma = true; |
386 |
+ |
} |
387 |
+ |
|
388 |
+ |
// Convert palette |
389 |
|
if (start == 0xffff) { // Indexed |
390 |
|
for (uint32 i=0; i<=count; i++) { |
391 |
|
d_pal = VidLocal.palette + (ReadMacInt16(s_pal) & 0xff) * 3; |
392 |
|
uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8; |
393 |
|
uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8; |
394 |
|
uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8; |
395 |
< |
if (VidLocal.luminance_mapping) |
395 |
> |
if (VidLocal.luminance_mapping && !is_direct) |
396 |
|
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; |
397 |
< |
//!! gamma correction |
397 |
> |
if (have_gamma) { |
398 |
> |
red = red_gamma[red >> (8 - data_width)]; |
399 |
> |
green = green_gamma[green >> (8 - data_width)]; |
400 |
> |
blue = blue_gamma[blue >> (8 - data_width)]; |
401 |
> |
} |
402 |
|
*d_pal++ = red; |
403 |
|
*d_pal++ = green; |
404 |
|
*d_pal++ = blue; |
412 |
|
uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8; |
413 |
|
uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8; |
414 |
|
uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8; |
415 |
< |
if (VidLocal.luminance_mapping) |
415 |
> |
if (VidLocal.luminance_mapping && !is_direct) |
416 |
|
red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; |
417 |
< |
//!! gamma correction |
417 |
> |
if (have_gamma) { |
418 |
> |
red = red_gamma[red >> (8 - data_width)]; |
419 |
> |
green = green_gamma[green >> (8 - data_width)]; |
420 |
> |
blue = blue_gamma[blue >> (8 - data_width)]; |
421 |
> |
} |
422 |
|
*d_pal++ = red; |
423 |
|
*d_pal++ = green; |
424 |
|
*d_pal++ = blue; |
429 |
|
return noErr; |
430 |
|
} |
431 |
|
|
432 |
< |
case cscSetGamma: // Set gamma table |
433 |
< |
D(bug(" SetGamma\n")); |
434 |
< |
//!! |
435 |
< |
return controlErr; |
432 |
> |
case cscSetGamma: { // Set gamma table |
433 |
> |
uint32 user_table = ReadMacInt32(param + csGTable); |
434 |
> |
D(bug(" SetGamma %08x\n", user_table)); |
435 |
> |
return set_gamma_table(user_table) ? noErr : memFullErr; |
436 |
> |
} |
437 |
|
|
438 |
|
case cscGrayPage: { // Fill page with dithered gray pattern |
439 |
|
D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage))); |
460 |
|
p += VidLocal.desc->mode.bytes_per_row; |
461 |
|
pat = ~pat; |
462 |
|
} |
463 |
< |
//!! if direct mode, load gamma table to CLUT |
463 |
> |
|
464 |
> |
if (IsDirectMode(VidLocal.current_mode)) |
465 |
> |
load_ramp_palette(); |
466 |
> |
|
467 |
|
return noErr; |
468 |
|
} |
469 |
|
|
655 |
|
return noErr; |
656 |
|
|
657 |
|
case cscGetGamma: |
658 |
< |
D(bug(" GetGamma -> \n")); |
659 |
< |
//!! |
660 |
< |
return statusErr; |
658 |
> |
D(bug(" GetGamma -> %08x\n", VidLocal.gamma_table)); |
659 |
> |
WriteMacInt32(param + csGTable, VidLocal.gamma_table); |
660 |
> |
return noErr; |
661 |
|
|
662 |
|
case cscGetDefaultMode: // Get default color depth |
663 |
|
D(bug(" GetDefaultMode -> %04x\n", VidLocal.preferred_mode)); |