|
1 /* |
|
2 * Hedgewars-iOS, a Hedgewars port for iOS devices |
|
3 * Copyright (c) 2009-2010 Vittorio Giovara <vittorio.giovara@gmail.com> |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation; version 2 of the License |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
17 * |
|
18 * File created on 26/09/2010. |
|
19 */ |
|
20 |
|
21 |
|
22 #import "MapPreviewButtonView.h" |
|
23 #import "MapConfigViewController.h" |
|
24 #import "UIImageExtra.h" |
|
25 #import <pthread.h> |
|
26 |
|
27 #define INDICATOR_TAG 7654 |
|
28 |
|
29 @implementation MapPreviewButtonView |
|
30 @synthesize delegate; |
|
31 |
|
32 -(id) initWithFrame:(CGRect)frame { |
|
33 if ((self = [super initWithFrame:frame])) { |
|
34 delegate = nil; |
|
35 [self setBackgroundImageRounded:[UIImage whiteImage:frame.size] forState:UIControlStateNormal]; |
|
36 } |
|
37 return self; |
|
38 } |
|
39 |
|
40 -(id) initWithCoder:(NSCoder *)aDecoder { |
|
41 if ((self = [super initWithCoder:aDecoder])) { |
|
42 delegate = nil; |
|
43 [self setBackgroundImageRounded:[UIImage whiteImage:self.frame.size] forState:UIControlStateNormal]; |
|
44 } |
|
45 return self; |
|
46 } |
|
47 |
|
48 -(void) dealloc { |
|
49 self.delegate = nil; |
|
50 [super dealloc]; |
|
51 } |
|
52 |
|
53 #pragma mark - |
|
54 #pragma mark image wrappers |
|
55 -(void) setBackgroundImageRounded:(UIImage *)image forState:(UIControlState)state { |
|
56 [self setBackgroundImage:[image makeRoundCornersOfSize:CGSizeMake(12, 12)] forState:UIControlStateNormal]; |
|
57 } |
|
58 |
|
59 -(void) setImageRounded:(UIImage *)image forState:(UIControlState)state { |
|
60 [self setImage:[image makeRoundCornersOfSize:CGSizeMake(12, 12)] forState:UIControlStateNormal]; |
|
61 } |
|
62 |
|
63 -(void) setImageRoundedForNormalState:(UIImage *)image { |
|
64 [self setImageRounded:image forState:UIControlStateNormal]; |
|
65 } |
|
66 |
|
67 #pragma mark - |
|
68 #pragma mark preview |
|
69 -(int) sendToEngine:(NSString *)string { |
|
70 unsigned char length = [string length]; |
|
71 |
|
72 SDLNet_TCP_Send(csd, &length, 1); |
|
73 return SDLNet_TCP_Send(csd, [string UTF8String], length); |
|
74 } |
|
75 |
|
76 -(const uint8_t *)engineProtocol { |
|
77 IPaddress ip; |
|
78 BOOL serverQuit = NO; |
|
79 static uint8_t map[128*32]; |
|
80 int port = randomPort(); |
|
81 |
|
82 if (SDLNet_Init() < 0) { |
|
83 DLog(@"SDLNet_Init: %s", SDLNet_GetError()); |
|
84 serverQuit = YES; |
|
85 } |
|
86 |
|
87 // Resolving the host using NULL make network interface to listen |
|
88 if (SDLNet_ResolveHost(&ip, NULL, port) < 0) { |
|
89 DLog(@"SDLNet_ResolveHost: %s\n", SDLNet_GetError()); |
|
90 serverQuit = YES; |
|
91 } |
|
92 |
|
93 // Open a connection with the IP provided (listen on the host's port) |
|
94 if (!(sd = SDLNet_TCP_Open(&ip))) { |
|
95 DLog(@"SDLNet_TCP_Open: %s %\n", SDLNet_GetError(), port); |
|
96 serverQuit = YES; |
|
97 } |
|
98 |
|
99 // launch the preview here so that we're sure the tcp channel is open |
|
100 pthread_t thread_id; |
|
101 pthread_create(&thread_id, NULL, (void *)GenLandPreview, (void *)port); |
|
102 pthread_detach(thread_id); |
|
103 |
|
104 DLog(@"Waiting for a client on port %d", port); |
|
105 while (!serverQuit) { |
|
106 /* This check the sd if there is a pending connection. |
|
107 * If there is one, accept that, and open a new socket for communicating */ |
|
108 csd = SDLNet_TCP_Accept(sd); |
|
109 if (NULL != csd) { |
|
110 DLog(@"Client found"); |
|
111 |
|
112 NSDictionary *dictForEngine = [self getDataForEngine]; |
|
113 [self sendToEngine:[dictForEngine objectForKey:@"seedCommand"]]; |
|
114 [self sendToEngine:[dictForEngine objectForKey:@"templateFilterCommand"]]; |
|
115 [self sendToEngine:[dictForEngine objectForKey:@"mapGenCommand"]]; |
|
116 [self sendToEngine:[dictForEngine objectForKey:@"mazeSizeCommand"]]; |
|
117 [self sendToEngine:@"!"]; |
|
118 |
|
119 memset(map, 0, 128*32); |
|
120 SDLNet_TCP_Recv(csd, map, 128*32); |
|
121 SDLNet_TCP_Recv(csd, &maxHogs, sizeof(uint8_t)); |
|
122 |
|
123 SDLNet_TCP_Close(csd); |
|
124 serverQuit = YES; |
|
125 } |
|
126 } |
|
127 |
|
128 SDLNet_TCP_Close(sd); |
|
129 SDLNet_Quit(); |
|
130 return map; |
|
131 } |
|
132 |
|
133 -(void) drawingThread { |
|
134 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
135 const uint8_t *map = [self engineProtocol]; |
|
136 uint8_t mapExp[128*32*8]; |
|
137 |
|
138 // draw the buffer (1 pixel per component, 0= transparent 1= color) |
|
139 int k = 0; |
|
140 for (int i = 0; i < 32*128; i++) { |
|
141 unsigned char byte = map[i]; |
|
142 for (int j = 0; j < 8; j++) { |
|
143 // select the color based on the leftmost bit |
|
144 if ((byte & 0x80) != 0) |
|
145 mapExp[k] = 100; |
|
146 else |
|
147 mapExp[k] = 255; |
|
148 // shift to next bit |
|
149 byte <<= 1; |
|
150 k++; |
|
151 } |
|
152 } |
|
153 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray(); |
|
154 CGContextRef bitmapImage = CGBitmapContextCreate(mapExp, 256, 128, 8, 256, colorspace, kCGImageAlphaNone); |
|
155 CGColorSpaceRelease(colorspace); |
|
156 |
|
157 CGImageRef previewCGImage = CGBitmapContextCreateImage(bitmapImage); |
|
158 CGContextRelease(bitmapImage); |
|
159 UIImage *previewImage = [[UIImage alloc] initWithCGImage:previewCGImage]; |
|
160 CGImageRelease(previewCGImage); |
|
161 previewCGImage = nil; |
|
162 |
|
163 // all these are performed on the main thread to prevent a leak |
|
164 [self performSelectorOnMainThread:@selector(setImageRoundedForNormalState:) |
|
165 withObject:previewImage |
|
166 waitUntilDone:NO]; |
|
167 [previewImage release]; |
|
168 [self performSelectorOnMainThread:@selector(setLabelText:) |
|
169 withObject:[NSString stringWithFormat:@"%d", maxHogs] |
|
170 waitUntilDone:NO]; |
|
171 [self performSelectorOnMainThread:@selector(turnOnWidgets) |
|
172 withObject:nil |
|
173 waitUntilDone:NO]; |
|
174 [self performSelectorOnMainThread:@selector(removeIndicator) |
|
175 withObject:nil |
|
176 waitUntilDone:NO]; |
|
177 |
|
178 [pool release]; |
|
179 |
|
180 /* |
|
181 // http://developer.apple.com/mac/library/qa/qa2001/qa1037.html |
|
182 UIGraphicsBeginImageContext(CGSizeMake(256,128)); |
|
183 CGContextRef context = UIGraphicsGetCurrentContext(); |
|
184 UIGraphicsPushContext(context); |
|
185 CGContextSetRGBFillColor(context, 0.5, 0.5, 0.7, 1.0); |
|
186 CGContextFillRect(context,CGRectMake(xc,yc,1,1)); |
|
187 UIGraphicsPopContext(); |
|
188 UIImage *previewImage = UIGraphicsGetImageFromCurrentImageContext(); |
|
189 UIGraphicsEndImageContext(); |
|
190 */ |
|
191 } |
|
192 |
|
193 -(void) updatePreviewWithSeed:(NSString *)seed { |
|
194 // remove the current preview and title |
|
195 [self setImage:nil forState:UIControlStateNormal]; |
|
196 [self setTitle:nil forState:UIControlStateNormal]; |
|
197 |
|
198 // don't display preview on slower device, too slow and memory hog |
|
199 NSString *modelId = modelType(); |
|
200 if ([modelId hasPrefix:@"iPhone1"] || [modelId hasPrefix:@"iPod1,1"] || [modelId hasPrefix:@"iPod2,1"]) { |
|
201 //self.delegate.busy = NO; |
|
202 [self setTitle:NSLocalizedString(@"Preview not available",@"") forState:UIControlStateNormal]; |
|
203 } else { |
|
204 // add a very nice spinning wheel |
|
205 UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] |
|
206 initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; |
|
207 indicator.center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); |
|
208 indicator.tag = INDICATOR_TAG; |
|
209 [indicator startAnimating]; |
|
210 [self addSubview:indicator]; |
|
211 [indicator release]; |
|
212 |
|
213 // let's draw in a separate thread so the gui can work; at the end it restore other widgets |
|
214 [NSThread detachNewThreadSelector:@selector(drawingThread) toTarget:self withObject:nil]; |
|
215 } |
|
216 } |
|
217 |
|
218 -(void) updatePreviewWithFile:(NSString *)filePath { |
|
219 UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath]; |
|
220 [self setImageRounded:image forState:UIControlStateNormal]; |
|
221 [image release]; |
|
222 } |
|
223 |
|
224 -(void) removeIndicator { |
|
225 UIActivityIndicatorView *indicator = (UIActivityIndicatorView *)[self viewWithTag:INDICATOR_TAG]; |
|
226 if (indicator) { |
|
227 [indicator stopAnimating]; |
|
228 [indicator removeFromSuperview]; |
|
229 } |
|
230 } |
|
231 |
|
232 #pragma mark - |
|
233 #pragma mark delegate |
|
234 -(void) turnOnWidgets { |
|
235 [self.delegate turnOnWidgets]; |
|
236 } |
|
237 |
|
238 -(void) setLabelText:(NSString *)string { |
|
239 [self.delegate setLabelText:string]; |
|
240 } |
|
241 |
|
242 -(NSDictionary *)getDataForEngine { |
|
243 return [self.delegate getDataForEngine]; |
|
244 } |
|
245 |
|
246 @end |