ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/EmulatorView.mm
Revision: 1.12
Committed: 2004-01-12T15:29:24Z (20 years, 8 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-15
Changes since 1.11: +2 -2 lines
Log Message:
Happy New Year! :)

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 cebix 1.12 * $Id: EmulatorView.mm,v 1.11 2003/04/02 00:37:34 nigel Exp $
5 nigel 1.1 *
6 cebix 1.12 * Basilisk II (C) 1997-2004 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 nigel 1.11 int mouseY = y - (int) (y * mouse.y / [self height]);
400     int mouseX = (int) (x * mouse.x / [self width]);
401 nigel 1.10 // If the view was not resizable, then this would be simpler:
402     // int mouseY = y - (int) mouse.y;
403     // int mouseX = (int) mouse.x;
404 nigel 1.1
405     ADBMouseMoved(mouseX, mouseY);
406     return YES;
407     }
408    
409     - (void) mouseDown: (NSEvent *) event
410     {
411     [self processMouseMove: event];
412     ADBMouseDown(0);
413     }
414    
415     - (void) mouseDragged: (NSEvent *) event
416     {
417     [self processMouseMove: event];
418     }
419    
420     - (void) mouseMoved: (NSEvent *) event
421     {
422     #if DEBUG
423     if ( ! [self mouseInView] )
424     {
425     NSLog (@"%s - Received event while outside of view", __PRETTY_FUNCTION__);
426     return;
427     }
428     #endif
429     [self processMouseMove: event];
430     }
431    
432     - (void) mouseUp: (NSEvent *) event
433     {
434     [self processMouseMove: event];
435     ADBMouseUp(0);
436     }
437    
438 nigel 1.9 #if DEBUG
439 nigel 1.1 - (void) randomise // Draw some coloured snow in the bitmap
440     {
441 nigel 1.7 unsigned char *data,
442     *pixel;
443    
444     #ifdef NSBITMAP
445     data = [bitmap bitmapData];
446 nigel 1.9 #else
447     data = bitmap;
448 nigel 1.7 #endif
449 nigel 1.1
450     for ( int i = 0; i < 1000; ++i )
451     {
452 nigel 1.7 pixel = data + (int) (numBytes * rand() / RAND_MAX);
453 nigel 1.1 *pixel = (unsigned char) (256.0 * rand() / RAND_MAX);
454     }
455     }
456     #endif
457    
458     - (void) drawRect: (NSRect) rect
459     {
460     if ( ! drawView ) // If the emulator is still being setup,
461     return; // we do not want to draw
462    
463     #if DEBUG
464     NSLog(@"In drawRect");
465 nigel 1.7 [self randomise];
466 nigel 1.1 #endif
467    
468     #ifdef NSBITMAP
469     NSRectClip(rect);
470     [bitmap draw];
471     #endif
472     #ifdef CGIMAGEREF
473 nigel 1.7 cgDrawInto(rect, cgImgRep);
474 nigel 1.1 #endif
475     #ifdef CGDRAWBITMAP
476     [self CGDrawBitmap];
477     #endif
478 nigel 1.10 }
479    
480     - (void) setTo: (int) val // Set all of bitmap to val
481     {
482     unsigned char *data
483     #ifdef NSBITMAP
484     = [bitmap bitmapData];
485     #else
486 nigel 1.11 = (unsigned char *) bitmap;
487 nigel 1.10 #endif
488    
489 nigel 1.11 memset(data, val, (long unsigned)numBytes);
490 nigel 1.10 }
491    
492     - (void) blacken // Set bitmap black
493     {
494     [self setTo: 0];
495     }
496    
497     - (void) clear // Set bitmap white
498     {
499     [self setTo: 0xFF];
500 nigel 1.1 }
501    
502     //
503     // Extra drawing stuff
504     //
505    
506     #ifdef CGDRAWBITMAP
507 nigel 1.6 extern "C" void CGDrawBitmap(...);
508 nigel 1.1
509     - (void) CGDrawBitmap
510     {
511 nigel 1.7 CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext]
512     graphicsPort];
513 nigel 1.1 NSRect rect = [self bounds];
514     CGRect cgRect = {
515     {rect.origin.x, rect.origin.y},
516     {rect.size.width, rect.size.height}
517     };
518    
519     CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
520    
521    
522 nigel 1.7 // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect?
523 nigel 1.1
524     CGDrawBitmap(cgContext, cgRect, x, y, bps, spp, bpp,
525     bytesPerRow, isPlanar, hasAlpha, colourSpace, &bitmap);
526     }
527     #endif
528    
529     #ifdef CGIMAGEREF
530     void
531 nigel 1.7 cgDrawInto(NSRect rect, CGImageRef cgImgRep)
532 nigel 1.1 {
533 nigel 1.7 CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext]
534     graphicsPort];
535 nigel 1.1 CGRect cgRect = {
536     {rect.origin.x, rect.origin.y},
537     {rect.size.width, rect.size.height}
538     };
539    
540 nigel 1.7 // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect?
541 nigel 1.1
542 nigel 1.7 CGContextDrawImage(cgContext, cgRect, cgImgRep);
543 nigel 1.1 }
544     #endif
545    
546 nigel 1.3 @end