diff --git a/BasiliskII/src/MacOSX/clip_macosx64.mm b/BasiliskII/src/MacOSX/clip_macosx64.mm index 6ea5511f..2fd64938 100644 --- a/BasiliskII/src/MacOSX/clip_macosx64.mm +++ b/BasiliskII/src/MacOSX/clip_macosx64.mm @@ -30,6 +30,7 @@ #include "cpu_emulation.h" #include "emul_op.h" #include "autorelease.h" +#include "pict.h" #define DEBUG 0 #include "debug.h" @@ -43,13 +44,14 @@ #define TYPE_STYL FOURCC('s','t','y','l') static NSPasteboard *g_pboard; +static NSUInteger g_pb_change_count = 0; // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the MacOS X side static bool we_put_this_data = false; static bool should_clear = false; -static NSMutableDictionary *macScrap; +static NSMutableDictionary *g_macScrap; // flavor UTIs @@ -150,7 +152,7 @@ static ScriptCode ScriptNumberForFontID(int16_t fontID) } /* - * Get Mac's default text encoding + * Get Mac's default text encoding */ static TextEncoding MacDefaultTextEncoding() @@ -269,7 +271,7 @@ static NSData *ConvertToMacTextEncoding(NSAttributedString *aStr, NSArray **styl } /* - * Count all Mac font IDs on the system + * Count all Mac font IDs on the system */ static NSUInteger CountMacFonts() @@ -305,7 +307,7 @@ static NSUInteger CountMacFonts() } /* - * Get Mac font ID at index + * Get Mac font ID at index */ static int16_t MacFontIDAtIndex(NSUInteger index) @@ -377,7 +379,7 @@ static int16_t MacFontIDAtIndex(NSUInteger index) } /* - * List all font IDs on the system + * List all font IDs on the system */ static NSArray *ListMacFonts() @@ -395,7 +397,7 @@ static NSArray *ListMacFonts() } /* - * List all font IDs having a certain script + * List all font IDs having a certain script */ static NSArray *ListMacFontsForScript(ScriptCode script) @@ -411,7 +413,7 @@ static NSArray *ListMacFontsForScript(ScriptCode script) } /* - * Convert Mac font ID to font name + * Convert Mac font ID to font name */ static NSString *FontNameFromFontID(int16_t fontID) @@ -456,7 +458,7 @@ static NSString *FontNameFromFontID(int16_t fontID) } /* - * Convert font name to Mac font ID + * Convert font name to Mac font ID */ static int16_t FontIDFromFontName(NSString *fontName) @@ -506,7 +508,7 @@ static int16_t FontIDFromFontName(NSString *fontName) } /* - * Get font ID in desired script if possible; otherwise, try to get some font in the desired script. + * Get font ID in desired script if possible; otherwise, try to get some font in the desired script. */ static int16_t FontIDFromFontNameAndScript(NSString *fontName, ScriptCode script) @@ -536,7 +538,7 @@ static int16_t FontIDFromFontNameAndScript(NSString *fontName, ScriptCode script } /* - * Convert Mac TEXT/styl to attributed string + * Convert Mac TEXT/styl to attributed string */ static NSAttributedString *AttributedStringFromMacTEXTAndStyl(NSData *textData, NSData *stylData) @@ -667,7 +669,7 @@ static NSAttributedString *AttributedStringFromMacTEXTAndStyl(NSData *textData, } /* - * Append styl data for one text run + * Append styl data for one text run */ static void AppendStylRunData(NSMutableData *stylData, NSDictionary *attrs, ScriptCode script) @@ -739,7 +741,7 @@ static void AppendStylRunData(NSMutableData *stylData, NSDictionary *attrs, Scri } /* - * Convert attributed string to TEXT/styl + * Convert attributed string to TEXT/styl */ static NSData *ConvertToMacTEXTAndStyl(NSAttributedString *aStr, NSData **outStylData) @@ -789,10 +791,28 @@ static NSData *ConvertToMacTEXTAndStyl(NSAttributedString *aStr, NSData **outSty } /* - * Convert Mac TEXT/styl to RTF + * Get data of a particular flavor from the pasteboard */ -static void WriteMacTEXTAndStylToPasteboard(NSData *textData, NSData *stylData) +static NSData *DataFromPasteboard(NSPasteboard *pboard, NSString *flavor) +{ + NSArray *objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSPasteboardItem class]] options:nil]; + + for (NSPasteboardItem *eachItem in objs) { + NSData *data = [eachItem dataForType:flavor]; + + if ([data length]) + return data; + } + + return nil; +} + +/* + * Convert Mac TEXT/styl to RTF + */ + +static void WriteMacTEXTAndStylToPasteboard(NSPasteboard *pboard, NSData *textData, NSData *stylData) { NSMutableAttributedString *aStr = [AttributedStringFromMacTEXTAndStyl(textData, stylData) mutableCopy]; @@ -810,23 +830,23 @@ static void WriteMacTEXTAndStylToPasteboard(NSData *textData, NSData *stylData) // fix line endings [[aStr mutableString] replaceOccurrencesOfString:@"\r" withString:@"\n" options:NSLiteralSearch range:NSMakeRange(0, [aStr length])]; - [g_pboard writeObjects:[NSArray arrayWithObject:aStr]]; + [pboard writeObjects:[NSArray arrayWithObject:aStr]]; } /* - * Convert RTF to Mac TEXT/styl + * Convert RTF to Mac TEXT/styl */ -static NSData *GetMacTEXTAndStylDataFromPasteboard(NSData **outStylData) +static NSData *MacTEXTAndStylDataFromPasteboard(NSPasteboard *pboard, NSData **outStylData) { NSMutableAttributedString *aStr; - NSArray *objs = [g_pboard readObjectsForClasses:[NSArray arrayWithObject:[NSAttributedString class]] options:nil]; + NSArray *objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSAttributedString class]] options:nil]; if ([objs count]) { aStr = [[objs objectAtIndex:0] mutableCopy]; } else { - objs = [g_pboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil]; + objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil]; if (![objs count]) return nil; @@ -859,7 +879,7 @@ void ClipInit(void) D(bug("could not create Pasteboard\n")); } - macScrap = [[NSMutableDictionary alloc] init]; + g_macScrap = [[NSMutableDictionary alloc] init]; } @@ -872,12 +892,105 @@ void ClipExit(void) [g_pboard release]; g_pboard = nil; - [macScrap release]; - macScrap = nil; + [g_macScrap release]; + g_macScrap = nil; } /* - * Zero Mac clipboard + * Convert an NSImage to PICT format. + */ + +static NSData *ConvertImageToPICT(NSImage *image) { + if ([[image representations] count] == 0) { + return nil; + } + + NSImageRep *rep = [[image representations] objectAtIndex:0]; + NSUInteger width; + NSUInteger height; + + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + width = [rep pixelsWide]; + height = [rep pixelsHigh]; + } else { + width = lrint([image size].width); + height = lrint([image size].height); + } + + // create a new bitmap image rep in our desired format, following the advice here: + // https://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html#X10_6Notes + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:width * 4 + bitsPerPixel:32]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]]; + [rep draw]; + [NSGraphicsContext restoreGraphicsState]; + + unsigned char *rgba = [bitmap bitmapData]; + + long bufSize = ConvertRGBAToPICT(NULL, 0, rgba, width, height); + + NSData *pictData = nil; + + if (bufSize > 0) { + uint8_t *buf = (uint8_t *)malloc(bufSize); + + long pictSize = ConvertRGBAToPICT(buf, bufSize, rgba, width, height); + + if (pictSize > 0) + pictData = [NSData dataWithBytes:buf length:pictSize]; + + free(buf); + } + + [bitmap release]; + + return pictData; +} + +/* + * Convert any images that may be on the clipboard to PICT format if possible. + */ + +static NSData *MacPICTDataFromPasteboard(NSPasteboard *pboard) +{ + // check if there's any PICT data on the pasteboard + NSData *pictData = DataFromPasteboard(pboard, (NSString *)kUTTypePICT); + + if (pictData) + return pictData; + + // now check to see if any images on the pasteboard have PICT representations + NSArray *objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSImage class]] options:nil]; + + for (NSImage *eachImage in objs) { + for (NSImageRep *eachRep in [eachImage representations]) { + + if ([eachRep isKindOfClass:[NSPICTImageRep class]]) + return [(NSPICTImageRep *)eachRep PICTRepresentation]; + } + } + + // Give up and perform the conversion ourselves + if ([objs count]) + return ConvertImageToPICT([objs objectAtIndex:0]); + + // If none of that worked, sorry, we're out of options + return nil; +} + +/* + * Zero Mac clipboard */ static void ZeroMacClipboard() @@ -904,7 +1017,7 @@ static void ZeroMacClipboard() } /* - * Write data to Mac clipboard + * Write data to Mac clipboard */ static void WriteDataToMacClipboard(NSData *pbData, uint32_t type) @@ -948,6 +1061,8 @@ static void WriteDataToMacClipboard(NSData *pbData, uint32_t type) r.a[0] = proc_area; Execute68kTrap(0xa01f, &r); // DisposePtr + + [g_macScrap setObject:pbData forKey:[NSNumber numberWithInteger:type]]; } r.a[0] = scrap_area; @@ -955,6 +1070,80 @@ static void WriteDataToMacClipboard(NSData *pbData, uint32_t type) } } +/* + * Take all the data on host pasteboard and convert it to something the Mac understands if possible + */ + +static void ConvertHostPasteboardToMacScrap() +{ + ZeroMacClipboard(); + + NSData *stylData = nil; + NSData *textData = MacTEXTAndStylDataFromPasteboard(g_pboard, &stylData); + + if (textData) { + if (stylData) + WriteDataToMacClipboard(stylData, TYPE_STYL); + + WriteDataToMacClipboard(textData, TYPE_TEXT); + } + + NSData *pictData = MacPICTDataFromPasteboard(g_pboard); + + if (pictData) + WriteDataToMacClipboard(pictData, TYPE_PICT); +} + +/* + * Take all the data on the Mac clipbord and convert it to something the host pasteboard understands if possible + */ + +static void ConvertMacScrapToHostPasteboard() +{ + BOOL wroteText = NO; + + [g_pboard clearContents]; + + for (NSNumber *eachTypeNum in g_macScrap) AUTORELEASE_POOL { + uint32_t eachType = [eachTypeNum integerValue]; + + if (eachType == TYPE_TEXT || eachType == TYPE_STYL) { + if(wroteText) + continue; + + NSData *textData; + NSData *stylData; + + textData = [g_macScrap objectForKey:[NSNumber numberWithInteger:TYPE_TEXT]]; + stylData = [g_macScrap objectForKey:[NSNumber numberWithInteger:TYPE_STYL]]; + + if (textData) { + WriteMacTEXTAndStylToPasteboard(g_pboard, textData, stylData); + wroteText = YES; + } + + continue; + } + + NSData *pbData = [g_macScrap objectForKey:eachTypeNum]; + + if (pbData) { + NSString *typeStr = GetUTIFromFlavor(eachType); + + if(!typeStr) + continue; + + NSPasteboardItem *pbItem = [[NSPasteboardItem alloc] init]; + + [pbItem setData:pbData forType:typeStr]; + + [g_pboard writeObjects:[NSArray arrayWithObject:pbItem]]; + + [pbItem release]; + } + } +} + /* * Mac application reads clipboard */ @@ -964,52 +1153,18 @@ void GetScrap(void **handle, uint32_t type, int32_t offset) D(bug("GetScrap handle %p, type %4.4s, offset %d\n", handle, (char *)&type, offset)); AUTORELEASE_POOL { - NSString *typeStr; - if (!g_pboard) return; - if (!(typeStr = GetUTIFromFlavor(type))) - return; - - if (type == TYPE_TEXT || type == TYPE_STYL) { - NSData *stylData = nil; - NSData *textData = GetMacTEXTAndStylDataFromPasteboard(&stylData); - - if (textData) { - ZeroMacClipboard(); - - if (stylData) - WriteDataToMacClipboard(stylData, TYPE_STYL); - - WriteDataToMacClipboard(textData, TYPE_TEXT); - - return; - } - } - - NSData *pbData = nil; - - NSArray *objs = [g_pboard readObjectsForClasses:[NSArray arrayWithObject:[NSPasteboardItem class]] options:nil]; - - for (NSPasteboardItem *eachItem in objs) { - NSData *data = [eachItem dataForType:typeStr]; - - if ([data length]) { - pbData = data; - break; - } - } - - if (pbData) { - ZeroMacClipboard(); - WriteDataToMacClipboard(pbData, type); + if ([g_pboard changeCount] > g_pb_change_count) { + ConvertHostPasteboardToMacScrap(); + g_pb_change_count = [g_pboard changeCount]; } } } /* - * ZeroScrap() is called before a Mac application writes to the clipboard; clears out the previous contents + * ZeroScrap() is called before a Mac application writes to the clipboard; clears out the previous contents */ void ZeroScrap() @@ -1032,25 +1187,19 @@ void PutScrap(uint32_t type, void *scrap, int32_t length) D(bug("PutScrap type %4.4s, data %p, length %ld\n", (char *)&type, scrap, (long)length)); AUTORELEASE_POOL { - NSString *typeStr; - if (!g_pboard) return; - if (!(typeStr = GetUTIFromFlavor(type))) - return; - if (we_put_this_data) { we_put_this_data = false; return; } + if (length <= 0) return; if (should_clear) { - [g_pboard clearContents]; - - [macScrap removeAllObjects]; + [g_macScrap removeAllObjects]; should_clear = false; } @@ -1058,24 +1207,11 @@ void PutScrap(uint32_t type, void *scrap, int32_t length) if (!pbData) return; - [macScrap setObject:pbData forKey:[NSNumber numberWithInteger:type]]; + [g_macScrap setObject:pbData forKey:[NSNumber numberWithInteger:type]]; - if (type == TYPE_TEXT || type == TYPE_STYL) { - NSData *textData; - NSData *stylData; + ConvertMacScrapToHostPasteboard(); - textData = [macScrap objectForKey:[NSNumber numberWithInteger:TYPE_TEXT]]; - stylData = [macScrap objectForKey:[NSNumber numberWithInteger:TYPE_STYL]]; - - if (textData) { - WriteMacTEXTAndStylToPasteboard(textData, stylData); - } - } else if (pbData) { - NSPasteboardItem *pbItem = [[[NSPasteboardItem alloc] init] autorelease]; - - [pbItem setData:pbData forType:typeStr]; - - [g_pboard writeObjects:[NSArray arrayWithObject:pbItem]]; - } + // So that our PutScrap() patch won't bounce the data we just wrote back to the Mac clipboard + g_pb_change_count = [g_pboard changeCount]; } } diff --git a/BasiliskII/src/Unix/configure.ac b/BasiliskII/src/Unix/configure.ac index 71a18d02..56044d3f 100644 --- a/BasiliskII/src/Unix/configure.ac +++ b/BasiliskII/src/Unix/configure.ac @@ -744,7 +744,7 @@ if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then [AC_MSG_RESULT(yes); LP64_DEFINED=yes], [AC_MSG_RESULT(no)]) if [[ "x$LP64_DEFINED" = "xyes" ]]; then - EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm" + EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm ../pict.c" else EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp" fi diff --git a/BasiliskII/src/include/pict.h b/BasiliskII/src/include/pict.h new file mode 100644 index 00000000..598516d9 --- /dev/null +++ b/BasiliskII/src/include/pict.h @@ -0,0 +1,29 @@ +/* + * pict.h - convert an image to PICT. + * + * Currently creates a bitmap PICT resource; vector graphics are not preserved. + * + * By Charles Srstka. + * + * Public Domain. Do with it as you wish. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ConvertRGBAToPICT + * + * Converts image data, in 32-bit RGBA format, to PICT. + * Calling it first with NULL for the buffer will cause it to return a suggested buffer size. + * Returns the number of bytes actually written, or negative if something went wrong. + * However, this usually just means the buffer wasn't large enough. + */ + +ssize_t ConvertRGBAToPICT(uint8_t *buf, unsigned long bufSize, uint8_t *rgbaPixels, uint16_t width, uint16_t height); + +#ifdef __cplusplus +} +#endif diff --git a/BasiliskII/src/pict.c b/BasiliskII/src/pict.c new file mode 100644 index 00000000..715c8feb --- /dev/null +++ b/BasiliskII/src/pict.c @@ -0,0 +1,267 @@ +/* + * pict.c - convert an image to PICT. + * + * Currently creates a bitmap PICT resource; vector graphics are not preserved. + * + * By Charles Srstka. + * + * Public Domain. Do with it as you wish. + * + */ + +/* + * PICT format: + * + * Size: 2 bytes + * Bounding Rect: 8 bytes + * + * This is followed by a series of opcodes. + * Each opcode is 1 byte long for a Version 1 PICT, or 2 bytes long for a Version 2 PICT. + * The ones we currently care about are: + * + * 0x0011 VersionOp: begins PICT version 2 + * 0x02ff Version: identifies PICT version 2 + * 0x0c00 HeaderOp: followed by 24 header bytes + * 4 bytes: 0xFFFFFFFF for regular v2 PICT or 0xFFFE0000 for extended v2 PICT + * 16 bytes: fixed-point bounding rectangle (or resolution, if an extended v2 PICT) + * 4 bytes: reserved + * + * 0x0001 Clip: set clipping region: followed by variable-sized region + * 0x001e DefHilite: set default highlight color + * 0x009b DirectBitsRgn: bitmap data + * pixMap: 50 bytes (PixMap) + * srcRect: 8 bytes (Rect) + * dstRect: 8 bytes (Rect) + * mode: 2 bytes (Mode) + * maskRgn: variable (Region) + * pixData: variable + * 0x00ff End of File + */ + +/* + * PixMap format: + * + * baseAddr: Ptr (4 bytes) + * rowBytes: Integer (2 bytes) + * bounds: Rect (8 bytes) + * pmVersion: Integer (2 bytes) + * packType: Integer (2 bytes) + * packSize: LongInt (4 bytes) + * hRes: Fixed (4 bytes) + * vRes: Fixed (4 bytes) + * pixelType: Integer (2 bytes) + * pixelSize: Integer (2 bytes) + * cmpCount: Integer (2 bytes) + * cmpSize: Integer (2 bytes) + * planeBytes: LongInt (4 bytes) + * pmTable: CTabHandle (4 bytes) + * pmReserved: LongInt (4 bytes) + */ + +#include +#include +#include +#include + +static ssize_t CompressUsingRLE(uint8_t *row, uint16_t uncmpLength, uint8_t *outBuf, size_t bufSize) +{ + int byteCountLength = 1 + (uncmpLength > 250); + + uint16_t cmpCursor = byteCountLength; + uint16_t cursor = 0; + + // enough to output the data uncompressed if we have to, plus the length bytes + size_t maxSize = byteCountLength + uncmpLength + (uncmpLength + 126) / 127; + + int outOfRoom = 0; + uint16_t cmpLength; + + if (row == NULL || outBuf == NULL || bufSize == 0) + return maxSize; + + while (cursor < uncmpLength) { + uint8_t byte = row[cursor++]; + uint8_t nextByte; + + if (cursor < uncmpLength && (nextByte = row[cursor]) == byte) { + int8_t matches = 1; + + while (++cursor < uncmpLength && matches < 127 && row[cursor] == byte) { + matches++; + } + + if(cmpCursor + 2 > bufSize) { + outOfRoom = 1; + break; + } + + outBuf[cmpCursor++] = -matches; + outBuf[cmpCursor++] = byte; + } else { + uint8_t literals = 0; + uint8_t i; + + while (cursor + literals + 1 < uncmpLength && literals < 127 && nextByte != (nextByte = row[cursor + literals + 1])) { + literals++; + } + + if(cmpCursor + 2 + literals > bufSize) { + outOfRoom = 1; + break; + } + + outBuf[cmpCursor++] = literals; + outBuf[cmpCursor++] = byte; + + for (i = 0; i < literals; i++) { + outBuf[cmpCursor++] = row[cursor++]; + } + } + } + + if(outOfRoom) { + // Trying to compress this just made it larger; just output the data uncompressed instead + + if(bufSize < maxSize) { + // sorry folks, don't have enough buffer + return -1; + } + + cursor = 0; + cmpCursor = byteCountLength; + + while (cursor < uncmpLength) { + uint8_t bytesToCopy = uncmpLength - cursor > 128 ? 128 : uncmpLength - cursor; + + outBuf[cmpCursor++] = bytesToCopy - 1; + memcpy(outBuf + cmpCursor, row + cursor, bytesToCopy); cmpCursor += bytesToCopy; cursor += bytesToCopy; + } + + cmpLength = cmpCursor - 1; + } + + cmpLength = cmpCursor - byteCountLength; + + if (byteCountLength == 2) { + outBuf[0] = cmpLength >> 8; + outBuf[1] = cmpLength & 0xff; + } else { + outBuf[0] = cmpLength; + } + + return cmpCursor; +} + +ssize_t ConvertRGBAToPICT(uint8_t *buf, unsigned long bufSize, uint8_t *rgbaPixels, uint16_t width, uint16_t height) +{ + unsigned long initialSize = (10 /* size + rect */ + + 6 /* initial opcodes */ + + 24 /* header */ + + 12 /* clip region */ + + 2 /* DefHilite */ + + 70 /* DirectBitsRgn - pixData - maskRgn */ + + 10 /* maskRgn */); + +#define RECT_SIZE 8 +#define REGION_SIZE 10 +#define FIXED_RECT_SIZE 16 + + char rect[RECT_SIZE] = {0, 0, 0, 0, height >> 8, height & 0xff, width >> 8, width & 0xff }; + char region[REGION_SIZE] = { 0x00, 0x0a, rect[0], rect[1], rect[2], rect[3], rect[4], rect[5], rect[6], rect[7] }; + char fixedRect[FIXED_RECT_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, width >> 8, width & 0xff, 0, 0, height >> 8, height & 0xff, 0, 0 }; + + uint32_t hDPI = htonl(0x00480000); // 72 dpi + uint32_t vDPI = hDPI; + + uint16_t bytesPerPixel = 4; // RGBA + uint16_t bytesPerRow = width * bytesPerPixel; + + unsigned long cursor = 2; // size bytes filled in at the end + + ssize_t cmpBufSize = CompressUsingRLE(NULL, bytesPerRow, NULL, 0); + uint8_t cmpBuf[cmpBufSize]; + + uint16_t i; + + if (buf == NULL || bufSize == 0) { + // Give an upper bound for the buffer size. + + return initialSize + height * cmpBufSize + 2; + } + + if (bufSize < initialSize) { + return -1; + } + + memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE; + + buf[cursor++] = 0x00; buf[cursor++] = 0x11; buf[cursor++] = 0x02; buf[cursor++] = 0xff; + + buf[cursor++] = 0x0c; buf[cursor++] = 0x00; + buf[cursor++] = 0xff; buf[cursor++] = 0xff; buf[cursor++] = 0xff; buf[cursor++] = 0xff; + memcpy(buf + cursor, fixedRect, FIXED_RECT_SIZE); cursor += FIXED_RECT_SIZE; + memset(buf + cursor, '\0', 4); cursor += 4; + + buf[cursor++] = 0x00; buf[cursor++] = 0x1e; + + buf[cursor++] = 0x00; buf[cursor++] = 0x01; + memcpy(buf + cursor, region, REGION_SIZE); cursor += REGION_SIZE; + + buf[cursor++] = 0x00; buf[cursor++] = 0x9b; + memset(buf + cursor, '\0', 4); cursor += 4; // I think this pointer isn't used + buf[cursor++] = (bytesPerRow >> 8) | 0x80; buf[cursor++] = bytesPerRow & 0xff; // rowBytes + memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE; //bounds + buf[cursor++] = 0x00; buf[cursor++] = 0x00; // pmVersion + buf[cursor++] = 0x00; buf[cursor++] = 0x04; // packType + buf[cursor++] = 0x00; buf[cursor++] = 0x00; buf[cursor++] = 0x00; buf[cursor++] = 0x00; // packSize is always 0 + memcpy(buf + cursor, &hDPI, 4); cursor += 4; // hRes + memcpy(buf + cursor, &vDPI, 4); cursor += 4; // vRes + buf[cursor++] = 0x00; buf[cursor++] = 0x10; // pixelType; direct device + buf[cursor++] = 0x00; buf[cursor++] = 0x20; // pixelSize; 32 bits per pixel + buf[cursor++] = bytesPerPixel >> 8; buf[cursor++] = bytesPerPixel & 0xff; // components per pixel + buf[cursor++] = 0x00; buf[cursor++] = 0x08; // 8 bits per component + memset(buf + cursor, '\0', 4); cursor += 4; // planeBytes isn't used + memset(buf + cursor, '\0', 4); cursor += 4; // don't think we need pmTable + memset(buf + cursor, '\0', 4); cursor += 4; // reserved + + memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE; + memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE; + buf[cursor++] = 0x00; buf[cursor++] = 0x00; // no transfer mode + memcpy(buf + cursor, region, REGION_SIZE); cursor += REGION_SIZE; + + for (i = 0; i < height; i++) { + uint8_t row[bytesPerRow]; + ssize_t cmpLength; + uint16_t j; + + for (j = 0; j < width; j++) { + row[j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel + 3]; + row[width + j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel]; + row[width * 2 + j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel + 1]; + row[width * 3 + j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel + 2]; + } + + cmpLength = CompressUsingRLE(row, bytesPerRow, cmpBuf, cmpBufSize); + + if (cmpLength < 0 || cursor + cmpLength > bufSize) + return -1; + + memcpy(buf + cursor, cmpBuf, cmpLength); cursor += cmpLength; + } + + // Fun fact: forgetting to put 0x00ff at the end of a PICT picture causes the entire + // Classic Mac OS to crash when it tries to read it! Don't ask me how I learned this. + if (cursor + 2 > bufSize) + return -1; + + buf[cursor++] = 0x00; buf[cursor++] = 0xff; + + if(cursor > UINT16_MAX) { + buf[0] = buf[1] = 0xff; + } else { + buf[0] = cursor >> 8; + buf[1] = cursor & 0xff; + } + + return cursor; +} diff --git a/SheepShaver/src/Unix/configure.ac b/SheepShaver/src/Unix/configure.ac index 58d91c7c..ce26ae7d 100644 --- a/SheepShaver/src/Unix/configure.ac +++ b/SheepShaver/src/Unix/configure.ac @@ -716,7 +716,7 @@ if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then [AC_MSG_RESULT(yes); LP64_DEFINED=yes], [AC_MSG_RESULT(no)]) if [[ "x$LP64_DEFINED" = "xyes" ]]; then - EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm" + EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm ../pict.c" else EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp" fi diff --git a/SheepShaver/src/include/pict.h b/SheepShaver/src/include/pict.h new file mode 120000 index 00000000..6e5a0b71 --- /dev/null +++ b/SheepShaver/src/include/pict.h @@ -0,0 +1 @@ +../../../BasiliskII/src/include/pict.h \ No newline at end of file diff --git a/SheepShaver/src/pict.c b/SheepShaver/src/pict.c new file mode 120000 index 00000000..bcbd7ff4 --- /dev/null +++ b/SheepShaver/src/pict.c @@ -0,0 +1 @@ +../../BasiliskII/src/pict.c \ No newline at end of file