SHOW:
|
|
- or go back to the newest paste.
1 | // | |
2 | // InterfaceController.m | |
3 | // cemu_core WatchKit Extension | |
4 | // | |
5 | // Created by Adrien Bertrand on 2016-01-07. | |
6 | // Copyright © 2016 adriweb. All rights reserved. | |
7 | // | |
8 | ||
9 | #import "InterfaceController.h" | |
10 | #import <WatchConnectivity/WatchConnectivity.h> | |
11 | #import <UIKit/UIGraphics.h> | |
12 | #import "emu.h" | |
13 | #import "lcd.h" | |
14 | ||
15 | @interface InterfaceController() <WCSessionDelegate> | |
16 | ||
17 | @property (strong, nonatomic) WCSession *session; | |
18 | ||
19 | @end | |
20 | ||
21 | @implementation InterfaceController | |
22 | ||
23 | uint16_t framebuffer[320 * 240]; | |
24 | uint32_t outPixel8888[320 * 240]; | |
25 | uint32_t bitfields[] = { 0x01F, 0x000, 0x000 }; | |
26 | CGSize scaleSize; | |
27 | bool portraitOrientation = true; | |
28 | bool lcdOff = true; | |
29 | ||
30 | extern bool doGuiStuff; | |
31 | ||
32 | -(instancetype)init { | |
33 | self = [super init]; | |
34 | ||
35 | if (self) { | |
36 | if ([WCSession isSupported]) { | |
37 | self.session = [WCSession defaultSession]; | |
38 | self.session.delegate = self; | |
39 | [self.session activateSession]; | |
40 | } | |
41 | } | |
42 | ||
43 | return self; | |
44 | } | |
45 | ||
46 | - (void)awakeWithContext:(id)context { | |
47 | [super awakeWithContext:context]; | |
48 | // Configure interface objects here. | |
49 | ||
50 | [self.screenButton setBackgroundImage:[UIImage imageNamed:@"icon"]]; | |
51 | ||
52 | CGFloat viewHeight = self.contentFrame.size.height; | |
53 | scaleSize = CGSizeMake(viewHeight * 240.0 / 320.0, viewHeight); | |
54 | ||
55 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
56 | NSString *romPath = [[[NSBundle mainBundle] URLForResource:@"84pce_51" withExtension:@"rom"] path]; | |
57 | NSLog(@"romPath = %@", romPath); | |
58 | rom_image = strdup([romPath UTF8String]); | |
59 | ||
60 | bool reset_true = true; | |
61 | bool success = emu_start(); | |
62 | ||
63 | NSLog(@"started"); | |
64 | ||
65 | if (success) { | |
66 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ | |
67 | while (!exiting) { | |
68 | [self updateLCD]; | |
69 | usleep(25000); | |
70 | } | |
71 | }); | |
72 | emu_loop(reset_true); | |
73 | } | |
74 | }); | |
75 | ||
76 | NSLog(@"finished"); | |
77 | } | |
78 | ||
79 | - (IBAction)toggleOrientation:(id)sender | |
80 | { | |
81 | portraitOrientation = !portraitOrientation; | |
82 | } | |
83 | ||
84 | ||
85 | - (UIImage *) convertBitmapRGB16ToUIImage:(const uint16_t*) buffer | |
86 | withWidth:(int) width | |
87 | withHeight:(int) height | |
88 | { | |
89 | size_t outBufferLength = width * height * sizeof(uint32_t); | |
90 | ||
91 | uint16_t *inPixel565 = (uint16_t*)buffer; | |
92 | ||
93 | for (unsigned int cnt=0; cnt < width * height; inPixel565++, cnt++) | |
94 | { | |
95 | outPixel8888[cnt] = ( ((((*inPixel565 >> 11) & 0x1F) * 527) + 23) >> 6 ) | |
96 | | ( ((((*inPixel565 >> 5) & 0x3F) * 259) + 33) >> 6 ) << 8 | |
97 | | ( ((( *inPixel565 & 0x1F) * 527) + 23) >> 6 ) << 16; | |
98 | } | |
99 | ||
100 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, outPixel8888, outBufferLength, NULL); | |
101 | size_t bitsPerComponent = 8; | |
102 | size_t bitsPerPixel = 32; | |
103 | size_t bytesPerRow = sizeof(uint32_t) * width; | |
104 | ||
105 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); | |
106 | if(colorSpaceRef == NULL) { | |
107 | NSLog(@"Error allocating color space"); | |
108 | CGDataProviderRelease(provider); | |
109 | return nil; | |
110 | } | |
111 | CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast; | |
112 | CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; | |
113 | ||
114 | CGImageRef iref = CGImageCreate(width, | |
115 | height, | |
116 | bitsPerComponent, | |
117 | bitsPerPixel, | |
118 | bytesPerRow, | |
119 | colorSpaceRef, | |
120 | bitmapInfo, | |
121 | provider, // data provider | |
122 | NULL, // decode | |
123 | YES, // should interpolate | |
124 | renderingIntent); | |
125 | ||
126 | uint32_t* pixels = (uint32_t*)malloc(outBufferLength); | |
127 | ||
128 | if(pixels == NULL) { | |
129 | NSLog(@"Error: Memory not allocated for bitmap"); | |
130 | CGDataProviderRelease(provider); | |
131 | CGColorSpaceRelease(colorSpaceRef); | |
132 | CGImageRelease(iref); | |
133 | return nil; | |
134 | } | |
135 | ||
136 | CGContextRef context = CGBitmapContextCreate(pixels, | |
137 | width, | |
138 | height, | |
139 | bitsPerComponent, | |
140 | bytesPerRow, | |
141 | colorSpaceRef, | |
142 | bitmapInfo); | |
143 | ||
144 | if(context == NULL) { | |
145 | NSLog(@"Error context not created"); | |
146 | free(pixels); | |
147 | } | |
148 | ||
149 | UIImage *image = nil; | |
150 | if(context) { | |
151 | ||
152 | CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref); | |
153 | ||
154 | CGImageRef imageRef = CGBitmapContextCreateImage(context); | |
155 | ||
156 | image = [UIImage imageWithCGImage:imageRef]; | |
157 | ||
158 | CGImageRelease(imageRef); | |
159 | CGContextRelease(context); | |
160 | } | |
161 | ||
162 | CGColorSpaceRelease(colorSpaceRef); | |
163 | CGImageRelease(iref); | |
164 | CGDataProviderRelease(provider); | |
165 | ||
166 | if (pixels) { | |
167 | free(pixels); | |
168 | } | |
169 | ||
170 | return image; | |
171 | } | |
172 | ||
173 | ||
174 | - (void)updateLCD | |
175 | { | |
176 | if (!doGuiStuff) | |
177 | { | |
178 | return; | |
179 | } else { | |
180 | doGuiStuff = false; | |
181 | } | |
182 | ||
183 | if (!(lcd.control & 0x800)) | |
184 | { | |
185 | if (!lcdOff) | |
186 | { | |
187 | lcdOff = true; | |
188 | [self.screenButton setBackgroundImage:nil]; | |
189 | [self.screenButton setTitle:@"LCD Off"]; | |
190 | } | |
191 | return; | |
192 | } else { | |
193 | lcdOff = false; | |
194 | [self.screenButton setTitle:@""]; | |
195 | } | |
196 | ||
197 | lcd_drawframe(framebuffer, bitfields); | |
198 | ||
199 | UIImage *tmpImage = [self convertBitmapRGB16ToUIImage:(const uint16_t*)framebuffer withWidth:320 withHeight:240]; | |
200 | ||
201 | if (!portraitOrientation) | |
202 | { | |
203 | UIImage *screenRotated = [[UIImage alloc] initWithCGImage: tmpImage.CGImage | |
204 | scale: 1 | |
205 | orientation: UIImageOrientationRight]; | |
206 | ||
207 | @autoreleasepool { | |
208 | UIGraphicsBeginImageContextWithOptions(scaleSize, NO, 0.0); | |
209 | [screenRotated drawInRect:CGRectMake(0, 0, scaleSize.width, scaleSize.height)]; | |
210 | UIImage * resizedImage = UIGraphicsGetImageFromCurrentImageContext(); | |
211 | UIGraphicsEndImageContext(); | |
212 | [self.screenButton setBackgroundImage:resizedImage]; | |
213 | } | |
214 | ||
215 | [screenRotated release]; | |
216 | } else { | |
217 | [self.screenButton setBackgroundImage:tmpImage]; | |
218 | } | |
219 | ||
220 | [tmpImage release]; | |
221 | } | |
222 | ||
223 | - (void)willActivate { | |
224 | // This method is called when watch view controller is about to be visible to user | |
225 | [super willActivate]; | |
226 | } | |
227 | ||
228 | - (void)didDeactivate { | |
229 | // This method is called when watch view controller is no longer visible | |
230 | [super didDeactivate]; | |
231 | } | |
232 | ||
233 | @end |