summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile9
-rw-r--r--include/llmr/map/map.hpp23
-rw-r--r--include/llmr/platform/platform.hpp4
-rw-r--r--ios/Info.plist47
-rw-r--r--ios/MBXAppDelegate.h15
-rw-r--r--ios/MBXAppDelegate.m24
-rw-r--r--ios/MBXSettings.h21
-rw-r--r--ios/MBXSettings.mm68
-rw-r--r--ios/MBXViewController.h14
-rw-r--r--ios/MBXViewController.mm256
-rw-r--r--ios/README.md8
-rw-r--r--ios/img/Icon-60.pngbin0 -> 9366 bytes
-rw-r--r--ios/img/Icon-60@2x.pngbin0 -> 28880 bytes
-rw-r--r--ios/img/Icon-72.pngbin0 -> 12517 bytes
-rw-r--r--ios/img/Icon-72@2x.pngbin0 -> 38964 bytes
-rw-r--r--ios/img/Icon-76.pngbin0 -> 13775 bytes
-rw-r--r--ios/img/Icon-76@2x.pngbin0 -> 42213 bytes
-rw-r--r--ios/img/Icon-Small-50.pngbin0 -> 6960 bytes
-rw-r--r--ios/img/Icon-Small-50@2x.pngbin0 -> 21430 bytes
-rw-r--r--ios/img/Icon-Small.pngbin0 -> 3270 bytes
-rw-r--r--ios/img/Icon-Small@2x.pngbin0 -> 8688 bytes
-rw-r--r--ios/img/Icon-Spotlight-40.pngbin0 -> 5052 bytes
-rw-r--r--ios/img/Icon-Spotlight-40@2x.pngbin0 -> 14870 bytes
-rw-r--r--ios/img/Icon.pngbin0 -> 8532 bytes
-rw-r--r--ios/img/Icon@2x.pngbin0 -> 26725 bytes
-rw-r--r--ios/img/iTunesArtworkbin0 -> 264721 bytes
-rw-r--r--ios/img/iTunesArtwork@2xbin0 -> 661346 bytes
-rw-r--r--ios/llmr-app.gyp51
-rw-r--r--ios/main.m18
-rwxr-xr-xios/setup_libpng.sh18
-rw-r--r--src/map/map.cpp26
-rw-r--r--src/renderer/shader.cpp4
33 files changed, 599 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index bee8a64754..bbd74195c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,6 @@
config.gypi
config.mk
.DS_Store
+out
+mapnik-packaging
+*.xcodeproj
diff --git a/Makefile b/Makefile
index 7bf075bb6d..d2cffacb8e 100644
--- a/Makefile
+++ b/Makefile
@@ -24,15 +24,24 @@ xapp: xcode config.gypi src macosx/llmr-app.gyp
xcodebuild -project ./macosx/llmr-app.xcodeproj
open macosx/build/Release/llmr.app
+# build iOS app with xcodebuild
+iapp: xcode config.gypi src ios/llmr-app.gyp
+ deps/run_gyp ios/llmr-app.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode
+ xcodebuild -project ./ios/llmr-app.xcodeproj
+ # launch app with ios-sim?
+
clean:
-rm -rf out
-rm -rf build
-rm -rf macosx/build
+ -rm -rf ios/build
distclean:
-rm -f config.gypi
-rm -f config.mk
-rm -rf llmr.xcodeproj
+ -rm -rf macosx/llmr-app.xcodeproj
+ -rm -rf ios/llmr-app.xcodeproj
test: all
echo test
diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp
index 7950158e35..5c18c87918 100644
--- a/include/llmr/map/map.hpp
+++ b/include/llmr/map/map.hpp
@@ -25,6 +25,7 @@ public:
Map &operator=(const Map&) = delete;
Map &operator=(const Map&&) = delete;
+ /* setup */
void setup();
void loadStyle(const uint8_t *const data, uint32_t bytes);
void loadSprite(const std::string& url);
@@ -33,19 +34,29 @@ public:
/* callback */
bool render();
- void moveBy(double dx, double dy);
- void scaleBy(double ds, double cx, double cy);
- void rotateBy(double cx, double cy, double sx, double sy, double ex, double ey);
void tileLoaded(std::shared_ptr<Tile> tile);
void tileFailed(std::shared_ptr<Tile> tile);
/* position */
- void resetNorth();
- void resetPosition();
- // void setAngle(double angle);
+ void moveBy(double dx, double dy);
// void setLonLat(double lon, double lat);
+ void resetPosition();
+
+ /* scale */
+ void scaleBy(double ds, double cx, double cy);
+ void setScale(double scale);
+ double getScale() const;
// void setZoom(double zoom);
// void setLonLatZoom(double lon, double lat, double zoom);
+ // double getZoom() const;
+ // void getLonLatZoom(double &lon, double &lat, double &zoom) const;
+ // void resetZoom();
+
+ /* rotation */
+ void rotateBy(double cx, double cy, double sx, double sy, double ex, double ey);
+ void setAngle(double angle);
+ double getAngle() const;
+ void resetNorth();
void toggleDebug();
diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp
index f729c4e21a..b31a112b87 100644
--- a/include/llmr/platform/platform.hpp
+++ b/include/llmr/platform/platform.hpp
@@ -5,8 +5,8 @@
#include <functional>
#include <string>
-#define kTileURL "http://localhost:3333/gl/tiles/plain/%d-%d-%d.vector.pbf"
-#define kSpriteURL "http://localhost:3333/gl/debug/img/sprite"
+#define kTileURL "http://mapbox:magic@kkaefer.net/gl/tiles/plain/%d-%d-%d.vector.pbf"
+#define kSpriteURL "http://mapbox:magic@kkaefer.net/gl/debug/img/sprite"
namespace llmr {
diff --git a/ios/Info.plist b/ios/Info.plist
new file mode 100644
index 0000000000..d78b5428e1
--- /dev/null
+++ b/ios/Info.plist
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.mapbox.llmr.native</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>0.0.1</string>
+ <key>CFBundleSignature</key>
+ <string>LLMR</string>
+ <key>CFBundleVersion</key>
+ <string>0.0.1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>NSHumanReadableCopyright</key>
+ <string>(c) 2014 Mapbox</string>
+</dict>
+</plist>
diff --git a/ios/MBXAppDelegate.h b/ios/MBXAppDelegate.h
new file mode 100644
index 0000000000..1023433320
--- /dev/null
+++ b/ios/MBXAppDelegate.h
@@ -0,0 +1,15 @@
+//
+// MBXAppDelegate.h
+// ios
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+@interface MBXAppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end \ No newline at end of file
diff --git a/ios/MBXAppDelegate.m b/ios/MBXAppDelegate.m
new file mode 100644
index 0000000000..4b860a361b
--- /dev/null
+++ b/ios/MBXAppDelegate.m
@@ -0,0 +1,24 @@
+//
+// MBXAppDelegate.m
+// ios
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import "MBXAppDelegate.h"
+
+#import "MBXViewController.h"
+
+@implementation MBXAppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ self.window.rootViewController = [MBXViewController new];
+ [self.window makeKeyAndVisible];
+
+ return YES;
+}
+
+@end \ No newline at end of file
diff --git a/ios/MBXSettings.h b/ios/MBXSettings.h
new file mode 100644
index 0000000000..fa0e55c724
--- /dev/null
+++ b/ios/MBXSettings.h
@@ -0,0 +1,21 @@
+//
+// MBXSettings.hpp
+// llmr
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import <llmr/map/settings.hpp>
+
+namespace llmr
+{
+ class Settings_iOS : public Settings
+ {
+ public:
+ Settings_iOS();
+ virtual void save();
+ virtual void load();
+ virtual void clear();
+ };
+} \ No newline at end of file
diff --git a/ios/MBXSettings.mm b/ios/MBXSettings.mm
new file mode 100644
index 0000000000..a19db0dab3
--- /dev/null
+++ b/ios/MBXSettings.mm
@@ -0,0 +1,68 @@
+//
+// MBXSettings.cpp
+// llmr
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import "MBXSettings.h"
+
+#import <Foundation/Foundation.h>
+
+using namespace llmr;
+
+Settings_iOS::Settings_iOS() {
+ NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+
+ // position
+ [NSNumber numberWithDouble:longitude], @"longitude",
+ [NSNumber numberWithDouble:latitude], @"latitude",
+ [NSNumber numberWithDouble:scale], @"scale",
+ [NSNumber numberWithDouble:angle], @"angle",
+
+ // debug
+ [NSNumber numberWithBool:debug], @"debug",
+
+ nil
+ ];
+
+ [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
+}
+
+void Settings_iOS::load() {
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+
+ // position
+ longitude = [defaults doubleForKey:@"longitude"];
+ latitude = [defaults doubleForKey:@"latitude"];
+ scale = [defaults doubleForKey:@"scale"];
+ angle = [defaults doubleForKey:@"angle"];
+
+ // debug
+ debug = [defaults boolForKey:@"debug"];
+}
+
+void Settings_iOS::save() {
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+
+ NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+
+ // position
+ [NSNumber numberWithDouble:longitude], @"longitude",
+ [NSNumber numberWithDouble:latitude], @"latitude",
+ [NSNumber numberWithDouble:scale], @"scale",
+ [NSNumber numberWithDouble:angle], @"angle",
+
+ // debug
+ [NSNumber numberWithBool:debug], @"debug",
+
+ nil
+ ];
+// [defaults setPersistentDomain:appDefaults forName:[[NSBundle mainBundle] bundleIdentifier]];
+
+// [defaults synchronize];
+}
+
+void Settings_iOS::clear() {
+} \ No newline at end of file
diff --git a/ios/MBXViewController.h b/ios/MBXViewController.h
new file mode 100644
index 0000000000..a554a72617
--- /dev/null
+++ b/ios/MBXViewController.h
@@ -0,0 +1,14 @@
+//
+// MBXViewController.h
+// ios
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import <GLKit/GLKit.h>
+#import <UIKit/UIKit.h>
+
+@interface MBXViewController : GLKViewController
+
+@end \ No newline at end of file
diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm
new file mode 100644
index 0000000000..62cd8ce013
--- /dev/null
+++ b/ios/MBXViewController.mm
@@ -0,0 +1,256 @@
+//
+// MBXViewController.m
+// ios
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import "MBXViewController.h"
+
+#import "MBXSettings.h"
+
+#import <OpenGLES/EAGL.h>
+#import <QuartzCore/QuartzCore.h>
+
+#include <llmr/llmr.hpp>
+#include <llmr/platform/platform.hpp>
+
+@interface MBXViewController ()
+
+@property (nonatomic) EAGLContext *context;
+@property (nonatomic) CGPoint center;
+@property (nonatomic) CGFloat zoom;
+@property (nonatomic) CGFloat angle;
+
+@end
+
+@implementation MBXViewController
+
+class MBXMapView
+{
+ public:
+ MBXMapView() : settings(), map(settings)
+ {
+ }
+
+ ~MBXMapView()
+ {
+ }
+
+ void init()
+ {
+ settings.load();
+
+ map.setup();
+
+ CGRect frame = [[UIScreen mainScreen] bounds];
+ map.resize(frame.size.width, frame.size.height, frame.size.width, frame.size.height);
+
+ map.loadSettings();
+ }
+
+ public:
+ llmr::Settings_iOS settings;
+ llmr::Map map;
+};
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+
+ if ( ! self.context)
+ {
+ NSLog(@"Failed to initialize OpenGL ES context");
+ return;
+ }
+
+ mapView = new MBXMapView();
+
+ GLKView *view = (GLKView *)self.view;
+ view.context = self.context;
+ view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
+ [view bindDrawable];
+
+ [EAGLContext setCurrentContext:self.context];
+
+ displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render:)];
+ [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+
+ mapView->init();
+
+ UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
+ [self.view addGestureRecognizer:pan];
+
+ UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapGesture:)];
+ doubleTap.numberOfTapsRequired = 2;
+ [self.view addGestureRecognizer:doubleTap];
+
+ UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)];
+ twoFingerTap.numberOfTouchesRequired = 2;
+ [self.view addGestureRecognizer:twoFingerTap];
+
+ UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
+ [self.view addGestureRecognizer:longPress];
+
+ UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
+ [self.view addGestureRecognizer:pinch];
+
+ UIRotationGestureRecognizer *rotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotateGesture:)];
+ [self.view addGestureRecognizer:rotate];
+}
+
+- (void)render:(id)sender
+{
+ mapView->map.render();
+
+ static double frames = 0;
+ static double elapsed = 0;
+
+ frames++;
+
+ double current = [[NSDate date] timeIntervalSince1970];
+
+ if (current - elapsed >= 1)
+ {
+ NSLog(@"FPS: %f", frames / (current - elapsed));
+ elapsed = current;
+ frames = 0;
+ }
+}
+
+- (void)handlePanGesture:(UIPanGestureRecognizer *)pan
+{
+ if (pan.state == UIGestureRecognizerStateBegan)
+ self.center = CGPointMake(0, 0);
+
+ CGPoint delta = CGPointMake([pan translationInView:pan.view].x - self.center.x,
+ [pan translationInView:pan.view].y - self.center.y);
+
+ mapView->map.moveBy(delta.x, delta.y);
+
+ self.center = CGPointMake(self.center.x + delta.x, self.center.y + delta.y);
+}
+
+- (void)handleDoubleTapGesture:(UIPanGestureRecognizer *)doubleTap
+{
+ CGPoint gesturePoint = [doubleTap locationInView:doubleTap.view];
+
+ mapView->map.scaleBy(2, gesturePoint.x, gesturePoint.y);
+}
+
+- (void)handleTwoFingerTapGesture:(UIPanGestureRecognizer *)twoFingerTap
+{
+ CGPoint gesturePoint = [twoFingerTap locationInView:twoFingerTap.view];
+
+ mapView->map.scaleBy(0.5, gesturePoint.x, gesturePoint.y);
+}
+
+- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)longPress
+{
+ mapView->map.resetNorth();
+}
+
+- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch
+{
+ CGFloat scale = mapView->map.getScale();
+
+ if (pinch.state == UIGestureRecognizerStateBegan)
+ self.zoom = log2f(scale);
+
+ CGFloat newZoom = self.zoom + (pinch.scale > 1 ? ((pinch.scale / 10) * 1) : (((1 - pinch.scale) / 0.9) * -1));
+
+ mapView->map.setScale(powf(2, newZoom));
+}
+
+- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate
+{
+ if (rotate.state == UIGestureRecognizerStateBegan)
+ self.angle = mapView->map.getAngle();
+
+ mapView->map.setAngle(self.angle + rotate.rotation);
+}
+
+CADisplayLink *displayLink;
+MBXMapView *mapView;
+NSOperationQueue *queue;
+
+namespace llmr
+{
+ namespace platform
+ {
+ void restart(void *)
+ {
+ }
+
+ void async(std::function<void()> fn, std::function<void()> cb)
+ {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
+ {
+ fn();
+
+ dispatch_async(dispatch_get_main_queue(), ^(void)
+ {
+ cb();
+ });
+ });
+ }
+
+ void request_http(std::string url, std::function<void(Response&)> func)
+ {
+ NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithUTF8String:url.c_str()]]];
+
+ [NSURLConnection sendAsynchronousRequest:urlRequest
+ queue:[NSOperationQueue mainQueue]
+ completionHandler: ^(NSURLResponse *response, NSData *data, NSError *error)
+ {
+ if ( ! error)
+ {
+ Response res;
+
+ res.code = [(NSHTTPURLResponse *)response statusCode];
+ res.body = { (const char *)[data bytes], [data length] };
+
+ func(res);
+ }
+ else
+ {
+ Response res;
+
+ func(res);
+ }
+ }];
+ }
+
+ void request_http(std::string url, std::function<void(Response&)> func, std::function<void()> cb)
+ {
+ NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithUTF8String:url.c_str()]]];
+
+ [NSURLConnection sendAsynchronousRequest:urlRequest
+ queue:[NSOperationQueue mainQueue]
+ completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
+ {
+ Response res;
+
+ if (error == nil)
+ {
+ res.code = [(NSHTTPURLResponse *)response statusCode];
+ res.body = { (const char *)[data bytes], [data length] };
+ }
+
+ func(res);
+
+ cb();
+ }];
+ }
+
+ double time()
+ {
+ return [displayLink timestamp];
+ }
+ }
+}
+
+@end \ No newline at end of file
diff --git a/ios/README.md b/ios/README.md
new file mode 100644
index 0000000000..b0dad9e14a
--- /dev/null
+++ b/ios/README.md
@@ -0,0 +1,8 @@
+llmr-ios
+========
+
+1. Because `libpng` isn't included in the iOS SDK, you will need to build a cross-architecture version yourself. Run `./setup_libpng.sh`, which is derived from Mapnik's cross-architecture build scripts.
+
+1. `make iapp` to create and build the iOS test app Xcode project.
+
+1. Consider `sudo npm install -g ios-sim` for auto-launching the simulator, but it can be tricky and it's better to run on an ARM-based device anyway. Open `./llmr-app.xcodeproj`, then build and run on the simulator or a device yourself. \ No newline at end of file
diff --git a/ios/img/Icon-60.png b/ios/img/Icon-60.png
new file mode 100644
index 0000000000..d062c32754
--- /dev/null
+++ b/ios/img/Icon-60.png
Binary files differ
diff --git a/ios/img/Icon-60@2x.png b/ios/img/Icon-60@2x.png
new file mode 100644
index 0000000000..84550f36e4
--- /dev/null
+++ b/ios/img/Icon-60@2x.png
Binary files differ
diff --git a/ios/img/Icon-72.png b/ios/img/Icon-72.png
new file mode 100644
index 0000000000..9218aca973
--- /dev/null
+++ b/ios/img/Icon-72.png
Binary files differ
diff --git a/ios/img/Icon-72@2x.png b/ios/img/Icon-72@2x.png
new file mode 100644
index 0000000000..b4fb12ba7b
--- /dev/null
+++ b/ios/img/Icon-72@2x.png
Binary files differ
diff --git a/ios/img/Icon-76.png b/ios/img/Icon-76.png
new file mode 100644
index 0000000000..debb8c453e
--- /dev/null
+++ b/ios/img/Icon-76.png
Binary files differ
diff --git a/ios/img/Icon-76@2x.png b/ios/img/Icon-76@2x.png
new file mode 100644
index 0000000000..1dce0cbd50
--- /dev/null
+++ b/ios/img/Icon-76@2x.png
Binary files differ
diff --git a/ios/img/Icon-Small-50.png b/ios/img/Icon-Small-50.png
new file mode 100644
index 0000000000..a72e343a32
--- /dev/null
+++ b/ios/img/Icon-Small-50.png
Binary files differ
diff --git a/ios/img/Icon-Small-50@2x.png b/ios/img/Icon-Small-50@2x.png
new file mode 100644
index 0000000000..0535d00f0a
--- /dev/null
+++ b/ios/img/Icon-Small-50@2x.png
Binary files differ
diff --git a/ios/img/Icon-Small.png b/ios/img/Icon-Small.png
new file mode 100644
index 0000000000..46d4a5de64
--- /dev/null
+++ b/ios/img/Icon-Small.png
Binary files differ
diff --git a/ios/img/Icon-Small@2x.png b/ios/img/Icon-Small@2x.png
new file mode 100644
index 0000000000..99058cebdb
--- /dev/null
+++ b/ios/img/Icon-Small@2x.png
Binary files differ
diff --git a/ios/img/Icon-Spotlight-40.png b/ios/img/Icon-Spotlight-40.png
new file mode 100644
index 0000000000..14b1ae1125
--- /dev/null
+++ b/ios/img/Icon-Spotlight-40.png
Binary files differ
diff --git a/ios/img/Icon-Spotlight-40@2x.png b/ios/img/Icon-Spotlight-40@2x.png
new file mode 100644
index 0000000000..4a45d8eff9
--- /dev/null
+++ b/ios/img/Icon-Spotlight-40@2x.png
Binary files differ
diff --git a/ios/img/Icon.png b/ios/img/Icon.png
new file mode 100644
index 0000000000..bb426e6681
--- /dev/null
+++ b/ios/img/Icon.png
Binary files differ
diff --git a/ios/img/Icon@2x.png b/ios/img/Icon@2x.png
new file mode 100644
index 0000000000..3069b485fa
--- /dev/null
+++ b/ios/img/Icon@2x.png
Binary files differ
diff --git a/ios/img/iTunesArtwork b/ios/img/iTunesArtwork
new file mode 100644
index 0000000000..ac6a0c58e8
--- /dev/null
+++ b/ios/img/iTunesArtwork
Binary files differ
diff --git a/ios/img/iTunesArtwork@2x b/ios/img/iTunesArtwork@2x
new file mode 100644
index 0000000000..fae1dad8bf
--- /dev/null
+++ b/ios/img/iTunesArtwork@2x
Binary files differ
diff --git a/ios/llmr-app.gyp b/ios/llmr-app.gyp
new file mode 100644
index 0000000000..f812eb1d7e
--- /dev/null
+++ b/ios/llmr-app.gyp
@@ -0,0 +1,51 @@
+{
+ 'includes': [
+ '../common.gypi',
+ '../config.gypi'
+ ],
+ 'targets': [
+ {
+ "target_name": "iosapp",
+ "product_name": "llmr",
+ "type": "executable",
+ "sources": [
+ "./main.m",
+ "./MBXAppDelegate.m",
+ "./MBXSettings.mm",
+ "./MBXViewController.mm"
+ ],
+ 'product_extension': 'app',
+ 'mac_bundle': 1,
+ 'mac_bundle_resources': [
+ '<!@(find img -type f)'
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/OpenGLES.framework',
+ '$(SDKROOT)/System/Library/Frameworks/GLKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework'
+ ],
+ },
+ 'xcode_settings': {
+ 'ARCHS': [ "armv7", "armv7s", "arm64" ],
+ 'SUPPORTED_PLATFORMS': [ 'iphoneos', 'iphonesimulator' ],
+ 'OTHER_LDFLAGS': [
+ '-stdlib=libc++'
+ ],
+ 'SDKROOT': 'iphoneos',
+ 'INFOPLIST_FILE': 'Info.plist',
+ 'CLANG_CXX_LIBRARY': 'libc++',
+ 'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
+ 'IPHONEOS_DEPLOYMENT_TARGET':'5.0',
+ 'TARGETED_DEVICE_FAMILY': '1,2',
+ 'CODE_SIGN_IDENTITY': 'iPhone Developer',
+ 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+ 'CLANG_ENABLE_OBJC_ARC': 'YES'
+ },
+ "dependencies": [
+ "../llmr.gyp:llmr-ios"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/ios/main.m b/ios/main.m
new file mode 100644
index 0000000000..92613c6ab2
--- /dev/null
+++ b/ios/main.m
@@ -0,0 +1,18 @@
+//
+// main.m
+// ios
+//
+// Created by Justin R. Miller on 1/27/14.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+#import "MBXAppDelegate.h"
+
+int main(int argc, char * argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([MBXAppDelegate class]));
+ }
+}
diff --git a/ios/setup_libpng.sh b/ios/setup_libpng.sh
new file mode 100755
index 0000000000..a66e06d5c1
--- /dev/null
+++ b/ios/setup_libpng.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+cd ../
+if [ ! -d 'mapnik-packaging' ]; then
+ git clone --depth=0 https://github.com/mapnik/mapnik-packaging.git
+fi
+cd mapnik-packaging/osx/
+export CXX11=true
+(source iPhoneSimulator.sh; ./scripts/build_png.sh; \
+ source MacOSX.sh; ./scripts/build_png.sh; \
+ source iPhoneOS.sh; ./scripts/build_png.sh; \
+ source iPhoneOSs.sh; ./scripts/build_png.sh; \
+ source iPhoneOS64.sh; ./scripts/build_png.sh; \
+ ./scripts/make_universal.sh)
+export UNIVERSAL_LIBS=`pwd`/out/build-cpp11-libcpp-universal/
+export PNG_INCLUDES=`pwd`/out/build-cpp11-libcpp-i386/
+cd ../../
+./configure --png-libpath=${UNIVERSAL_LIBS} --png-includes=${PNG_INCLUDES} \ No newline at end of file
diff --git a/src/map/map.cpp b/src/map/map.cpp
index fabf26c08f..6ed3c0284c 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -83,6 +83,32 @@ void Map::rotateBy(double cx, double cy, double sx, double sy, double ex, double
settings.save();
}
+void Map::setScale(double scale) {
+ transform.setScale(scale);
+ style.cascade(transform.getZoom());
+ update();
+
+ transform.getLonLat(settings.longitude, settings.latitude);
+ settings.scale = transform.getScale();
+ settings.save();
+}
+
+void Map::setAngle(double angle) {
+ transform.setAngle(angle);
+ update();
+
+ settings.angle = transform.getAngle();
+ settings.save();
+}
+
+double Map::getScale() const {
+ return transform.getScale();
+}
+
+double Map::getAngle() const {
+ return transform.getAngle();
+}
+
void Map::resetNorth() {
transform.setAngle(0, 0.5); // 500 ms
update();
diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp
index 311e46e4b2..f2326efd73 100644
--- a/src/renderer/shader.cpp
+++ b/src/renderer/shader.cpp
@@ -105,8 +105,8 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
*shader = glCreateShader(type);
-#ifdef EMSCRIPTEN
- // Add WebGL GLSL precision premable
+#if defined(EMSCRIPTEN) || defined(GL_ES_VERSION_2_0)
+ // Add WebGL GLSL / OpenGL ES precision premable
const GLchar *preamble = "precision mediump float;\n\n";
#else
// Desktop GLSL