ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/EmulatorView.mm
Revision: 1.9
Committed: 2003-03-21T06:41:04Z (21 years, 8 months ago) by nigel
Branch: MAIN
CVS Tags: nigel-build-12
Changes since 1.8: +59 -21 lines
Log Message:
Allow snapshot of window, no matter what the drawing strategy. Mention drawing strategy in benchmark results

File Contents

# User Rev Content
1 nigel 1.1 /*
2 nigel 1.9 * EmulatorView.mm - Custom NSView for Basilisk II windowed graphics output
3 nigel 1.1 *
4 nigel 1.9 * $Id: EmulatorView.mm,v 1.8 2003/03/11 11:27:20 nigel Exp $
5 nigel 1.1 *
6 nigel 1.9 * Basilisk II (C) 1997-2003 Christian Bauer
7 nigel 1.1 *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21     */
22    
23     #import "sysdeps.h" // Types used in Basilisk C++ code,
24    
25     #define DEBUG 0
26     #import <debug.h>
27    
28     #import <Cocoa/Cocoa.h>
29    
30     #import "main_macosx.h" // For WarningAlert() et al prototypes
31     #import "misc_macosx.h" // For InfoSheet() prototype
32     #import "video_macosx.h" // For init_* globals, and bitmap drawing strategy
33    
34     #import "EmulatorView.h"
35    
36     @implementation EmulatorView
37    
38    
39     //
40     // Standard NSView methods that we override
41     //
42    
43     - (id) initWithFrame: (NSRect) frameRect
44     {
45     self = [super initWithFrame: frameRect];
46    
47     output = self; // Set global for access by Basilisk C++ code
48     // bitmap = nil; // Set by readyToDraw:
49     drawView = NO; // Disable drawing until later
50 nigel 1.4 fullScreen = NO;
51 nigel 1.1
52     return self;
53     }
54    
55 nigel 1.8 - (void) awakeFromNib
56     {
57     // Here we store the height of the screen which the app was opened on.
58     // NSApplication's sendEvent: always uses that screen for its mouse co-ords
59     screen_height = (int) [[NSScreen mainScreen] frame].size.height;
60     }
61    
62    
63 nigel 1.5 // Mouse click in this window. If window is not active,
64     // should the click be passed to this view?
65 nigel 1.1 - (BOOL) acceptsFirstMouse: (NSEvent *) event
66     {
67     return [self mouseInView];
68     }
69    
70    
71 nigel 1.8 //
72     // Key event processing.
73     // OS X doesn't send us separate events for the modifier keys
74     // (shift/control/command), so we need to monitor them separately
75     //
76    
77 nigel 1.1 #include <adb.h>
78    
79     static int prevFlags;
80    
81     - (void) flagsChanged: (NSEvent *) event
82     {
83     int flags = [event modifierFlags];
84    
85     if ( (flags & NSAlphaShiftKeyMask) != (prevFlags & NSAlphaShiftKeyMask) )
86     if ( flags & NSAlphaShiftKeyMask )
87     ADBKeyDown(0x39); // CAPS_LOCK
88     else
89     ADBKeyUp(0x39);
90    
91     if ( (flags & NSShiftKeyMask) != (prevFlags & NSShiftKeyMask) )
92     if ( flags & NSShiftKeyMask )
93     ADBKeyDown(0x38); // SHIFT_LEFT
94     else
95     ADBKeyUp(0x38);
96    
97     if ( (flags & NSControlKeyMask) != (prevFlags & NSControlKeyMask) )
98     if ( flags & NSControlKeyMask )
99     ADBKeyDown(0x36); // CTL_LEFT
100     else
101     ADBKeyUp(0x36);
102    
103     if ( (flags & NSAlternateKeyMask) != (prevFlags & NSAlternateKeyMask) )
104     if ( flags & NSAlternateKeyMask )
105     ADBKeyDown(0x3a); // OPTION_LEFT
106     else
107     ADBKeyUp(0x3a);
108    
109     if ( (flags & NSCommandKeyMask) != (prevFlags & NSCommandKeyMask) )
110     if ( flags & NSCommandKeyMask )
111     ADBKeyDown(0x37); // APPLE_LEFT
112     else
113     ADBKeyUp(0x37);
114    
115     prevFlags = flags;
116     }
117    
118 nigel 1.8 //
119     // Windowed mode. We only send mouse/key events
120     // if the OS X mouse is within the little screen
121     //
122 nigel 1.1 - (BOOL) mouseInView: (NSEvent *) event
123     {
124 nigel 1.4 NSRect box;
125 nigel 1.5 NSPoint loc;
126    
127 nigel 1.4 if ( fullScreen )
128 nigel 1.5 {
129     box = displayBox;
130     loc = [NSEvent mouseLocation];
131     }
132 nigel 1.4 else
133 nigel 1.5 {
134 nigel 1.4 box = [self frame];
135 nigel 1.5 loc = [event locationInWindow];
136     }
137    
138     D(NSLog (@"%s - loc.x=%f, loc.y=%f, box.origin.x=%f, box.origin.y=%f, box.size.width=%f, box.size.height=%f", __PRETTY_FUNCTION__, loc.x, loc.y, box.origin.x, box.origin.y, box.size.width, box.size.height));
139 nigel 1.1 return [self mouse: loc inRect: box];
140     }
141    
142     - (BOOL) mouseInView
143     {
144     NSPoint loc = [[self window] mouseLocationOutsideOfEventStream];
145     NSRect box = [self frame];
146     D(NSLog (@"%s - loc.x=%f, loc.y=%f, box.origin.x=%f, box.origin.y=%f",
147     __PRETTY_FUNCTION__, loc.x, loc.y, box.origin.x, box.origin.y));
148     return [self mouse: loc inRect: box];
149     }
150    
151     //
152     // Custom methods
153     //
154    
155     - (void) benchmark
156     {
157     int i;
158     float seconds;
159     NSDate *startDate;
160 nigel 1.9 char *method;
161 nigel 1.1
162     if ( ! drawView )
163 nigel 1.9 {
164     WarningSheet (@"The emulator has not been setup yet.",
165     @"Try to run, then pause the emulator, first.", nil, [self window]);
166 nigel 1.1 return;
167 nigel 1.9 }
168 nigel 1.1
169     drawView = NO;
170     [self lockFocus];
171     startDate = [NSDate date];
172     for (i = 1; i < 300; ++i )
173     #ifdef NSBITMAP
174     [bitmap draw];
175     #endif
176     #ifdef CGIMAGEREF
177 nigel 1.7 cgDrawInto([self bounds], cgImgRep);
178 nigel 1.1 #endif
179     #ifdef CGDRAWBITMAP
180     [self CGDrawBitmap];
181     #endif
182     seconds = -[startDate timeIntervalSinceNow];
183     [self unlockFocus];
184     drawView = YES;
185    
186 nigel 1.9 #ifdef NSBITMAP
187     method = "NSBITMAP";
188     #endif
189     #ifdef CGIMAGEREF
190     method = "CGIMAGEREF";
191     #endif
192     #ifdef CGDRAWBITMAP
193     method = "CGDRAWBITMAP";
194     #endif
195    
196     InfoSheet(@"Ran benchmark (300 screen redraws)",
197 nigel 1.1 [NSString stringWithFormat:
198 nigel 1.9 @"%.2f seconds, %.3f frames per second (using %s implementation)",
199     seconds, i/seconds, method],
200 nigel 1.1 @"Thanks", [self window]);
201     }
202    
203     // Return a TIFF for a snapshot of the screen image
204     - (NSData *) TIFFrep
205     {
206     #ifdef NSBITMAP
207     return [bitmap TIFFRepresentation];
208     #else
209 nigel 1.9 NSBitmapImageRep *b = [NSBitmapImageRep alloc];
210    
211     b = [b initWithBitmapDataPlanes: (unsigned char **) &bitmap
212     pixelsWide: x
213     pixelsHigh: y
214     #ifdef CGIMAGEREF
215     bitsPerSample: CGImageGetBitsPerComponent(cgImgRep)
216     samplesPerPixel: 3
217     hasAlpha: NO
218     isPlanar: NO
219     colorSpaceName: NSCalibratedRGBColorSpace
220     bytesPerRow: CGImageGetBytesPerRow(cgImgRep)
221     bitsPerPixel: CGImageGetBitsPerPixel(cgImgRep)];
222     #endif
223     #ifdef CGDRAWBITMAP
224     bitsPerSample: bps
225     samplesPerPixel: spp
226     hasAlpha: hasAlpha
227     isPlanar: isPlanar
228     colorSpaceName: NSCalibratedRGBColorSpace
229     bytesPerRow: bytesPerRow
230     bitsPerPixel: bpp];
231     #endif
232    
233     if ( ! b )
234     {
235     ErrorAlert("Could not allocate an NSBitmapImageRep for the TIFF");
236     return nil;
237     }
238    
239     return [b TIFFRepresentation];
240 nigel 1.1 #endif
241     }
242    
243     // Enable display of, and drawing into, the view
244     #ifdef NSBITMAP
245     - (void) readyToDraw: (NSBitmapImageRep *) theBitmap
246     imageWidth: (short) width
247     imageHeight: (short) height
248     {
249 nigel 1.7 numBytes = [theBitmap bytesPerRow] * height;
250 nigel 1.1 #endif
251     #ifdef CGIMAGEREF
252     - (void) readyToDraw: (CGImageRef) image
253 nigel 1.9 bitmap: (void *) theBitmap
254 nigel 1.1 imageWidth: (short) width
255     imageHeight: (short) height
256     {
257 nigel 1.7 cgImgRep = image;
258 nigel 1.8 numBytes = CGImageGetBytesPerRow(image) * height;
259 nigel 1.1 #endif
260     #ifdef CGDRAWBITMAP
261     - (void) readyToDraw: (void *) theBitmap
262     width: (short) width
263     height: (short) height
264     bps: (short) bitsPerSample
265     spp: (short) samplesPerPixel
266     bpp: (short) bitsPerPixel
267     bpr: (int) bpr
268     isPlanar: (BOOL) planar
269     hasAlpha: (BOOL) alpha
270     {
271     bps = bitsPerSample;
272     spp = samplesPerPixel;
273     bpp = bitsPerPixel;
274     bytesPerRow = bpr;
275     isPlanar = planar;
276     hasAlpha = alpha;
277 nigel 1.7 numBytes = bpr * height;
278 nigel 1.1 #endif
279 nigel 1.9 D(NSLog(@"readyToDraw: theBitmap=%lx\n", theBitmap));
280    
281     bitmap = theBitmap;
282 nigel 1.1 x = width, y = height;
283     drawView = YES;
284     [[self window] setAcceptsMouseMovedEvents: YES];
285     // [[self window] setInitialFirstResponder: self];
286     [[self window] makeFirstResponder: self];
287     }
288    
289     - (void) disableDrawing
290     {
291     drawView = NO;
292     }
293    
294 nigel 1.5 - (void) startedFullScreen: (CGDirectDisplayID) display
295 nigel 1.4 {
296 nigel 1.5 CGRect displayBounds = CGDisplayBounds(display);
297    
298 nigel 1.4 fullScreen = YES;
299 nigel 1.5 memcpy(&displayBox, &displayBounds, sizeof(displayBox));
300 nigel 1.4 }
301    
302 nigel 1.1 - (short) width
303     {
304     return (short)[self bounds].size.width;
305     }
306    
307     - (short) height
308     {
309     return (short)[self bounds].size.height;
310     }
311    
312 nigel 1.4 - (BOOL) isFullScreen
313     {
314     return fullScreen;
315     }
316    
317 nigel 1.1 - (BOOL) isOpaque
318     {
319     return drawView;
320     }
321    
322     - (BOOL) processKeyEvent: (NSEvent *) event
323     {
324 nigel 1.4 if ( fullScreen || [self acceptsFirstMouse: event] )
325 nigel 1.1 if ( [event isARepeat] )
326     return NO;
327     else
328     return YES;
329    
330     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
331     return NO;
332     }
333    
334     - (void) keyDown: (NSEvent *) event
335     {
336     if ( [self processKeyEvent: event] )
337 nigel 1.2 {
338     int code = [event keyCode];
339    
340     if ( code == 126 ) code = 0x3e; // CURS_UP
341     if ( code == 125 ) code = 0x3d; // CURS_DOWN
342     if ( code == 124 ) code = 0x3c; // CURS_RIGHT
343     if ( code == 123 ) code = 0x3b; // CURS_LEFT
344    
345     ADBKeyDown(code);
346     }
347 nigel 1.1 }
348    
349     - (void) keyUp: (NSEvent *) event
350     {
351     if ( [self processKeyEvent: event] )
352 nigel 1.2 {
353     int code = [event keyCode];
354    
355     if ( code == 126 ) code = 0x3e; // CURS_UP
356     if ( code == 125 ) code = 0x3d; // CURS_DOWN
357     if ( code == 124 ) code = 0x3c; // CURS_RIGHT
358     if ( code == 123 ) code = 0x3b; // CURS_LEFT
359    
360     ADBKeyUp(code);
361     }
362 nigel 1.1 }
363    
364 nigel 1.8
365     - (void) fullscreenMouseMove
366     {
367     NSPoint location = [NSEvent mouseLocation];
368    
369     D(NSLog (@"%s - loc.x=%f, loc.y=%f",
370     __PRETTY_FUNCTION__, location.x, location.y));
371     D(NSLog (@"%s - Sending ADBMouseMoved(%d,%d). (%d-%d)",
372     __PRETTY_FUNCTION__, (int)location.x,
373     screen_height - (int)location.y, screen_height, (int)location.y));
374     ADBMouseMoved((int)location.x, screen_height - (int)location.y);
375     }
376    
377 nigel 1.1 static NSPoint mouse; // Previous/current mouse location
378    
379     - (BOOL) processMouseMove: (NSEvent *) event
380     {
381 nigel 1.5 NSPoint location;
382 nigel 1.1
383 nigel 1.4 if ( fullScreen )
384 nigel 1.8 {
385     [self fullscreenMouseMove];
386     return YES;
387     }
388    
389     location = [self convertPoint: [event locationInWindow] fromView:nil];
390    
391     D(NSLog (@"%s - loc.x=%f, loc.y=%f",
392     __PRETTY_FUNCTION__, location.x, location.y));
393 nigel 1.1
394 nigel 1.5 if ( NSEqualPoints(location, mouse) )
395 nigel 1.1 return NO;
396    
397 nigel 1.5 mouse = location;
398 nigel 1.1
399     #ifdef CAN_RESIZE_VIEW
400     int mouseY = y - y * mouse.y / [self height];
401     int mouseX = x * mouse.x / [self width];
402     #else
403     int mouseY = y - (int) mouse.y;
404     int mouseX = (int) mouse.x;
405     #endif
406    
407     ADBMouseMoved(mouseX, mouseY);
408     return YES;
409     }
410    
411     - (void) mouseDown: (NSEvent *) event
412     {
413     [self processMouseMove: event];
414     ADBMouseDown(0);
415     }
416    
417     - (void) mouseDragged: (NSEvent *) event
418     {
419     [self processMouseMove: event];
420     }
421    
422     - (void) mouseMoved: (NSEvent *) event
423     {
424     #if DEBUG
425     if ( ! [self mouseInView] )
426     {
427     NSLog (@"%s - Received event while outside of view", __PRETTY_FUNCTION__);
428     return;
429     }
430     #endif
431     [self processMouseMove: event];
432     }
433    
434     - (void) mouseUp: (NSEvent *) event
435     {
436     [self processMouseMove: event];
437     ADBMouseUp(0);
438     }
439    
440 nigel 1.9 #if DEBUG
441 nigel 1.1 - (void) randomise // Draw some coloured snow in the bitmap
442     {
443 nigel 1.7 unsigned char *data,
444     *pixel;
445    
446     #ifdef NSBITMAP
447     data = [bitmap bitmapData];
448 nigel 1.9 #else
449     data = bitmap;
450 nigel 1.7 #endif
451 nigel 1.1
452     for ( int i = 0; i < 1000; ++i )
453     {
454 nigel 1.7 pixel = data + (int) (numBytes * rand() / RAND_MAX);
455 nigel 1.1 *pixel = (unsigned char) (256.0 * rand() / RAND_MAX);
456     }
457     }
458     #endif
459    
460     - (void) drawRect: (NSRect) rect
461     {
462     if ( ! drawView ) // If the emulator is still being setup,
463     return; // we do not want to draw
464    
465     #if DEBUG
466     NSLog(@"In drawRect");
467 nigel 1.7 [self randomise];
468 nigel 1.1 #endif
469    
470     #ifdef NSBITMAP
471     NSRectClip(rect);
472     [bitmap draw];
473     #endif
474     #ifdef CGIMAGEREF
475 nigel 1.7 cgDrawInto(rect, cgImgRep);
476 nigel 1.1 #endif
477     #ifdef CGDRAWBITMAP
478     [self CGDrawBitmap];
479     #endif
480     }
481    
482     //
483     // Extra drawing stuff
484     //
485    
486     #ifdef CGDRAWBITMAP
487 nigel 1.6 extern "C" void CGDrawBitmap(...);
488 nigel 1.1
489     - (void) CGDrawBitmap
490     {
491 nigel 1.7 CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext]
492     graphicsPort];
493 nigel 1.1 NSRect rect = [self bounds];
494     CGRect cgRect = {
495     {rect.origin.x, rect.origin.y},
496     {rect.size.width, rect.size.height}
497     };
498    
499     CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
500    
501    
502 nigel 1.7 // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect?
503 nigel 1.1
504     CGDrawBitmap(cgContext, cgRect, x, y, bps, spp, bpp,
505     bytesPerRow, isPlanar, hasAlpha, colourSpace, &bitmap);
506     }
507     #endif
508    
509     #ifdef CGIMAGEREF
510     void
511 nigel 1.7 cgDrawInto(NSRect rect, CGImageRef cgImgRep)
512 nigel 1.1 {
513 nigel 1.7 CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext]
514     graphicsPort];
515 nigel 1.1 CGRect cgRect = {
516     {rect.origin.x, rect.origin.y},
517     {rect.size.width, rect.size.height}
518     };
519    
520 nigel 1.7 // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect?
521 nigel 1.1
522 nigel 1.7 CGContextDrawImage(cgContext, cgRect, cgImgRep);
523 nigel 1.1 }
524     #endif
525    
526 nigel 1.3 @end