From a6ee7b701e06128b63c54d77d5965385faa9fbdd Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 11:42:05 -0700 Subject: [PATCH 01/24] get rid of unused framework --- ios/llmr-app.gyp | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/llmr-app.gyp b/ios/llmr-app.gyp index 82b9b8963..c0b40c1cc 100644 --- a/ios/llmr-app.gyp +++ b/ios/llmr-app.gyp @@ -29,7 +29,6 @@ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework', '$(SDKROOT)/System/Library/Frameworks/OpenGLES.framework', '$(SDKROOT)/System/Library/Frameworks/GLKit.framework', - '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework', '$(SDKROOT)/System/Library/Frameworks/CoreLocation.framework' ], }, From 9a79f348fa4262c557a3b2dac5e54c37efde9fbc Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 11:42:52 -0700 Subject: [PATCH 02/24] move debug app over to use of Cocoa API --- .gitmodules | 3 + ios/MBXViewController.mm | 360 ++++----------------------------------- ios/MVKMapKit | 1 + ios/llmr-app.gyp | 2 + 4 files changed, 41 insertions(+), 325 deletions(-) create mode 100644 .gitmodules create mode 160000 ios/MVKMapKit diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..37a988d2b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ios/MVKMapKit"] + path = ios/MVKMapKit + url = git@github.com:mapbox/MVKMapKit.git diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 9c4b5d2fe..6cad26762 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -1,24 +1,14 @@ #import "MBXViewController.h" -#import "../common/settings_nsuserdefaults.hpp" -#import "../common/foundation_request.h" +#import "MVKMapView.h" + +#import "../common/settings_nsuserdefaults.hpp" -#import -#import -#import #import -#include -#include -#include +@interface MBXViewController () -@interface MBXViewController () - -@property (nonatomic) EAGLContext *context; -@property (nonatomic) CGPoint center; -@property (nonatomic) CGFloat scale; -@property (nonatomic) CGFloat angle; -@property (nonatomic) CGFloat quickZoomStart; +@property (nonatomic) MVKMapView *mapView; @property (nonatomic) BOOL debug; @property (nonatomic) UIView *palette; @property (nonatomic) CLLocationManager *locationManager; @@ -27,12 +17,7 @@ @implementation MBXViewController -class View; - -llmr::Map *map = nullptr; -View *viewObj = nullptr; llmr::Settings_NSUserDefaults *settings = nullptr; -MBXViewController *viewController = nullptr; #pragma mark - Setup @@ -49,110 +34,52 @@ MBXViewController *viewController = nullptr; return self; } -- (void)loadView -{ - [super loadView]; - - self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - - if (!self.context) - { - NSLog(@"Failed to create OpenGL ES context"); - } - - GLKView *view = [[GLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds] context:self.context]; - view.enableSetNeedsDisplay = NO; - view.drawableStencilFormat = GLKViewDrawableStencilFormat8; - view.drawableDepthFormat = GLKViewDrawableDepthFormat16; - [view bindDrawable]; - - self.view = view; -} - - (void)viewDidLoad { [super viewDidLoad]; - [self setupMap]; - [self setupInteraction]; + self.mapView = [[MVKMapView alloc] initWithFrame:self.view.bounds]; + self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.view addSubview:self.mapView]; + + settings = new llmr::Settings_NSUserDefaults(); + [self restoreState]; + [self setupDebugUI]; self.locationManager = [CLLocationManager new]; self.locationManager.delegate = self; - - map->start(); -} - -- (void)setupMap -{ - viewObj = new View(self); - map = new llmr::Map(*viewObj); - - // Load settings - settings = new llmr::Settings_NSUserDefaults(); - [self restoreState]; } - (void)saveState { - if (map && settings) + if (self.mapView && settings) { - map->getLonLatZoom(settings->longitude, settings->latitude, settings->zoom); - settings->angle = map->getAngle(); - settings->debug = map->getDebug(); + settings->longitude = self.mapView.centerCoordinate.longitude; + settings->latitude = self.mapView.centerCoordinate.latitude; + settings->zoom = self.mapView.zoomLevel; + settings->angle = self.mapView.direction; + settings->debug = self.mapView.isDebugActive; settings->save(); } } - (void)restoreState { - if (map && settings) { + if (self.mapView && settings) { settings->load(); - map->setLonLatZoom(settings->longitude, settings->latitude, settings->zoom); - map->setAngle(settings->angle); - map->setDebug(settings->debug); - } -} - -- (void)setupInteraction -{ - UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; - pan.delegate = self; - [self.view addGestureRecognizer:pan]; - - UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; - pinch.delegate = self; - [self.view addGestureRecognizer:pinch]; - - UIRotationGestureRecognizer *rotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotateGesture:)]; - rotate.delegate = self; - [self.view addGestureRecognizer:rotate]; - - UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)]; - singleTap.numberOfTapsRequired = 1; - [self.view addGestureRecognizer:singleTap]; - - UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapGesture:)]; - doubleTap.numberOfTapsRequired = 2; - [self.view addGestureRecognizer:doubleTap]; - - [singleTap requireGestureRecognizerToFail:doubleTap]; - - UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)]; - twoFingerTap.numberOfTouchesRequired = 2; - [self.view addGestureRecognizer:twoFingerTap]; - - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) - { - UILongPressGestureRecognizer *quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)]; - quickZoom.numberOfTapsRequired = 1; - quickZoom.minimumPressDuration = 0.25; - [self.view addGestureRecognizer:quickZoom]; + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(settings->latitude, settings->longitude) zoomLevel:settings->zoom animated:NO]; + self.mapView.direction = settings->angle; + [self.mapView setDebugActive:settings->debug]; } } - (void)setupDebugUI { + UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)]; + singleTap.numberOfTapsRequired = 1; + [self.mapView addGestureRecognizer:singleTap]; + NSArray *selectorNames = @[ @"unrotate", @"resetPosition", @"toggleDebug", @"toggleRaster", @"locateUser" ]; CGFloat buttonSize = 40; CGFloat bufferSize = 20; @@ -182,32 +109,19 @@ MBXViewController *viewController = nullptr; - (NSUInteger)supportedInterfaceOrientations { - // We support everything; it's up to the embedding application to limit the orientations. return UIInterfaceOrientationMaskAll; } -#pragma mark - Rendering delegates +#pragma mark - Debugging UI -- (void)swap +- (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap { - if (map->needsSwap()) + if (singleTap.state == UIGestureRecognizerStateEnded) { - [(GLKView *)self.view display]; - map->swapped(); + [self togglePalette]; } } -- (void)viewWillLayoutSubviews -{ - [super viewWillLayoutSubviews]; - - GLKView *view = (GLKView *)self.view; - CGRect rect = [view bounds]; - map->resize(rect.size.width, rect.size.height, view.contentScaleFactor, view.drawableWidth, view.drawableHeight); -} - -#pragma mark - Debugging UI - - (void)togglePalette { if (self.palette.alpha < 1) @@ -232,24 +146,24 @@ MBXViewController *viewController = nullptr; - (void)unrotate { - map->resetNorth(); + [self.mapView resetNorth]; } - (void)resetPosition { - map->resetPosition(); + [self.mapView resetPosition]; } - (void)toggleDebug { - map->toggleDebug(); + [self.mapView toggleDebug]; self.debug = ! self.debug; } - (void)toggleRaster { - map->toggleRaster(); + [self.mapView toggleRaster]; } - (void)locateUser @@ -269,197 +183,10 @@ MBXViewController *viewController = nullptr; if (settings) { - // Save settings [self saveState]; delete settings; settings = nullptr; } - - if (map) - { - delete map; - map = nullptr; - } - - if (viewObj) - { - delete viewObj; - viewObj = nullptr; - } - - if ([[EAGLContext currentContext] isEqual:self.context]) - { - [EAGLContext setCurrentContext:nil]; - } -} - -#pragma mark - UI gestures - -- (void)cancelPreviousActions -{ - map->cancelTransitions(); - - [self.locationManager stopUpdatingLocation]; -} - -- (void)handlePanGesture:(UIPanGestureRecognizer *)pan -{ - [self cancelPreviousActions]; - - if (pan.state == UIGestureRecognizerStateBegan) - { - self.center = CGPointMake(0, 0); - } - else if (pan.state == UIGestureRecognizerStateChanged) - { - CGPoint delta = CGPointMake([pan translationInView:pan.view].x - self.center.x, - [pan translationInView:pan.view].y - self.center.y); - - map->moveBy(delta.x, delta.y); - - self.center = CGPointMake(self.center.x + delta.x, self.center.y + delta.y); - } - else if (pan.state == UIGestureRecognizerStateEnded) - { - if ([pan velocityInView:pan.view].x < 50 && [pan velocityInView:pan.view].y < 50) - { - return; - } - - CGPoint finalCenter = CGPointMake(self.center.x + (0.1 * [pan velocityInView:pan.view].x), - self.center.y + (0.1 * [pan velocityInView:pan.view].y)); - - CGFloat duration = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad ? 0.3 : 0.5); - - map->moveBy(finalCenter.x - self.center.x, finalCenter.y - self.center.y, duration); - } -} - -- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch -{ - [self cancelPreviousActions]; - - if (pinch.state == UIGestureRecognizerStateBegan) - { - map->startScaling(); - - self.scale = map->getScale(); - } - else if (pinch.state == UIGestureRecognizerStateChanged) - { - CGFloat tolerance = 2.5; - CGFloat adjustment = 0; - - if (pinch.scale > 1) - { - adjustment = (pinch.scale / tolerance) - (1 / tolerance); - } - else - { - adjustment = (-1 / pinch.scale) / tolerance + (1 / tolerance); - } - - CGFloat newZoom = log2f(self.scale) + adjustment; - - map->scaleBy(powf(2, newZoom) / map->getScale(), [pinch locationInView:pinch.view].x, [pinch locationInView:pinch.view].y); - } - else if (pinch.state == UIGestureRecognizerStateEnded) - { - map->stopScaling(); - - if (fabsf(pinch.velocity) < 20) - { - return; - } - - CGFloat finalZoom = log2f(map->getScale()) + (0.01 * pinch.velocity); - - double scale = map->getScale(); - double new_scale = powf(2, finalZoom); - - CGFloat duration = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad ? 0.3 : 0.5); - - map->scaleBy(new_scale / scale, [pinch locationInView:pinch.view].x, [pinch locationInView:pinch.view].y, duration); - } - else if (pinch.state == UIGestureRecognizerStateCancelled) - { - map->stopScaling(); - } -} - -- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate -{ - [self cancelPreviousActions]; - - if (rotate.state == UIGestureRecognizerStateBegan) - { - map->startRotating(); - - self.angle = map->getAngle(); - } - else if (rotate.state == UIGestureRecognizerStateChanged) - { - map->setAngle(self.angle + rotate.rotation, [rotate locationInView:rotate.view].x, [rotate locationInView:rotate.view].y); - } - else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled) - { - map->stopRotating(); - } -} - -- (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap -{ - if (singleTap.state == UIGestureRecognizerStateEnded) - { - [self togglePalette]; - } -} - -- (void)handleDoubleTapGesture:(UITapGestureRecognizer *)doubleTap -{ - [self cancelPreviousActions]; - - if (doubleTap.state == UIGestureRecognizerStateEnded) - { - map->scaleBy(2, [doubleTap locationInView:doubleTap.view].x, [doubleTap locationInView:doubleTap.view].y, 0.3); - } -} - -- (void)handleTwoFingerTapGesture:(UITapGestureRecognizer *)twoFingerTap -{ - [self cancelPreviousActions]; - - if (twoFingerTap.state == UIGestureRecognizerStateEnded) - { - map->scaleBy(0.5, [twoFingerTap locationInView:twoFingerTap.view].x, [twoFingerTap locationInView:twoFingerTap.view].y, 0.3); - } -} - -- (void)handleQuickZoomGesture:(UILongPressGestureRecognizer *)quickZoom -{ - [self cancelPreviousActions]; - - if (quickZoom.state == UIGestureRecognizerStateBegan) - { - self.scale = map->getScale(); - - self.quickZoomStart = [quickZoom locationInView:quickZoom.view].y; - } - else if (quickZoom.state == UIGestureRecognizerStateChanged) - { - CGFloat distance = self.quickZoomStart - [quickZoom locationInView:quickZoom.view].y; - - CGFloat newZoom = log2f(self.scale) + (distance / 100); - - map->scaleBy(powf(2, newZoom) / map->getScale(), self.view.bounds.size.width / 2, self.view.bounds.size.height / 2); - } -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ - NSArray *validSimultaneousGestures = @[ [UIPanGestureRecognizer class], [UIPinchGestureRecognizer class], [UIRotationGestureRecognizer class] ]; - - return ([validSimultaneousGestures containsObject:[gestureRecognizer class]] && [validSimultaneousGestures containsObject:[otherGestureRecognizer class]]); } #pragma mark - User location @@ -468,24 +195,7 @@ MBXViewController *viewController = nullptr; { CLLocation *latestLocation = locations.lastObject; - map->setLonLatZoom(latestLocation.coordinate.longitude, latestLocation.coordinate.latitude, 17, 0.3); + [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(latestLocation.coordinate.latitude, latestLocation.coordinate.longitude) zoomLevel:17 animated:YES]; } -class View : public llmr::View { -public: - View(MBXViewController *controller) : controller(controller) {} - virtual ~View() {} - - void make_active() { - [EAGLContext setCurrentContext:controller.context]; - } - - void swap() { - [controller performSelectorOnMainThread:@selector(swap) withObject:nil waitUntilDone:NO]; - } - -private: - MBXViewController *controller = nullptr; -}; - @end diff --git a/ios/MVKMapKit b/ios/MVKMapKit new file mode 160000 index 000000000..9c536c3b1 --- /dev/null +++ b/ios/MVKMapKit @@ -0,0 +1 @@ +Subproject commit 9c536c3b12636292ef70bbbc9800858a9d19a1ef diff --git a/ios/llmr-app.gyp b/ios/llmr-app.gyp index c0b40c1cc..6bd463ab7 100644 --- a/ios/llmr-app.gyp +++ b/ios/llmr-app.gyp @@ -14,6 +14,8 @@ "./MBXAppDelegate.m", "./MBXViewController.h", "./MBXViewController.mm", + "./MVKMapKit/MVKMapKit/MVKMapView.h", + "./MVKMapKit/MVKMapKit/MVKMapView.mm", "../common/settings_nsuserdefaults.hpp", "../common/settings_nsuserdefaults.mm", "../common/foundation_request.h", From 7b2a977f21f6a2d48b7d77cccbe50614ec4ffa4a Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 14:12:53 -0700 Subject: [PATCH 03/24] technically these take an argument --- ios/MBXViewController.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 6cad26762..eb63da317 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -27,8 +27,8 @@ llmr::Settings_NSUserDefaults *settings = nullptr; if (self) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveState) name:UIApplicationDidEnterBackgroundNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restoreState) name:UIApplicationWillEnterForegroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveState:) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restoreState:) name:UIApplicationWillEnterForegroundNotification object:nil]; } return self; @@ -43,7 +43,7 @@ llmr::Settings_NSUserDefaults *settings = nullptr; [self.view addSubview:self.mapView]; settings = new llmr::Settings_NSUserDefaults(); - [self restoreState]; + [self restoreState:nil]; [self setupDebugUI]; @@ -51,7 +51,7 @@ llmr::Settings_NSUserDefaults *settings = nullptr; self.locationManager.delegate = self; } -- (void)saveState +- (void)saveState:(NSNotification *)notification { if (self.mapView && settings) { @@ -64,7 +64,7 @@ llmr::Settings_NSUserDefaults *settings = nullptr; } } -- (void)restoreState +- (void)restoreState:(NSNotification *)notification { if (self.mapView && settings) { settings->load(); @@ -183,7 +183,7 @@ llmr::Settings_NSUserDefaults *settings = nullptr; if (settings) { - [self saveState]; + [self saveState:nil]; delete settings; settings = nullptr; } From 9a16483b8d9b77a1f3a85a87d7089855747f5dfe Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 14:33:26 -0700 Subject: [PATCH 04/24] ignore unused parameters --- ios/MBXViewController.mm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index eb63da317..25fca0599 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -51,6 +51,9 @@ llmr::Settings_NSUserDefaults *settings = nullptr; self.locationManager.delegate = self; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + - (void)saveState:(NSNotification *)notification { if (self.mapView && settings) @@ -74,6 +77,8 @@ llmr::Settings_NSUserDefaults *settings = nullptr; } } +#pragma clang diagnostic pop + - (void)setupDebugUI { UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)]; @@ -191,6 +196,9 @@ llmr::Settings_NSUserDefaults *settings = nullptr; #pragma mark - User location +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { CLLocation *latestLocation = locations.lastObject; @@ -198,4 +206,6 @@ llmr::Settings_NSUserDefaults *settings = nullptr; [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(latestLocation.coordinate.latitude, latestLocation.coordinate.longitude) zoomLevel:17 animated:YES]; } +#pragma clang diagnostic pop + @end From ec408f85921e812d09dafbd2ef90a56fa8cfae24 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 14:45:37 -0700 Subject: [PATCH 05/24] bump MVKMapKit --- ios/MVKMapKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/MVKMapKit b/ios/MVKMapKit index 9c536c3b1..053dd5186 160000 --- a/ios/MVKMapKit +++ b/ios/MVKMapKit @@ -1 +1 @@ -Subproject commit 9c536c3b12636292ef70bbbc9800858a9d19a1ef +Subproject commit 053dd518621ee94cd32c891c00453195c18366d3 From f640ee08cdf63537110be1dade7f4c6dc63ff3da Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 15:52:10 -0700 Subject: [PATCH 06/24] fixes #205: fix Travis builds --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 796d2f2c5..9dde1b9bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,3 +29,6 @@ script: notifications: - hipchat: WB52YkcbCGMbNcStsGeaoRO7cyBSK4wX2ZHo2Y4b@GL + +git: + submodules: false From 609144d87ead332fc88fca2f0e38ec2abc73aaf6 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 17:32:32 -0700 Subject: [PATCH 07/24] bump bindings --- ios/MVKMapKit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/MVKMapKit b/ios/MVKMapKit index 053dd5186..172218fa9 160000 --- a/ios/MVKMapKit +++ b/ios/MVKMapKit @@ -1 +1 @@ -Subproject commit 053dd518621ee94cd32c891c00453195c18366d3 +Subproject commit 172218fa978dc061c31ce3a814294fd7cd5559b9 From 18b930362dd4ed6233000660c529fef25dc1951e Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 17:46:26 -0700 Subject: [PATCH 08/24] formatting --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c2af76b08..3b607414f 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ implemented in C++11, targeting iOS & OS X. # Depends - Modern C++ compiler that supports `-std=c++11` - - libpng - - libuv - - libcurl (depends on OpenSSL) - - glfw3 + - `libpng` + - `libuv` + - `libcurl` (depends on OpenSSL) + - `glfw3` - Boost (for Rtree support) - Python (for build only) - Node.js (for build only) @@ -28,10 +28,10 @@ used on both OS X and iOS. To create projects, you can run: - `make xproj`: Creates an Xcode project with OS X-specific handlers for HTTP downloads and - settings storage. It uses GLFW for window handling + settings storage. It uses GLFW for window handling. - `make lproj`: Creates an Xcode project with platform-independent handlers for downloads - and settings storage. This is what is also being built on Linux -- `make linux`: Builds the Linux GLFW application with make + and settings storage. This is what is also being built on Linux. +- `make linux`: Builds the Linux GLFW application with `make`. ## iOS @@ -66,7 +66,7 @@ Build static dependencies: This will automatically run configure for you and set the correct paths. -You can then proceed to build the library, tests or a GLFW app itself. +You can then proceed to build the library, tests, or a GLFW app itself. # Style From f329685544ef77d8c59f2b1faf612f64029234fc Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 14 May 2014 17:49:10 -0700 Subject: [PATCH 09/24] update iOS details --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3b607414f..43a174221 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,19 @@ To create projects, you can run: ## iOS -Because `libpng` isn't included in the iOS SDK, you will need to build a cross-architecture version +iOS makes use of a Cocoa-specific API currently housed in [MVKMapKit](https://github.com/mapbox/MVKMapKit), +which is included as a submodule and provides a `UIView` interface to the map view. + +First, pull down the submodule(s): + + git submodule init + git submodule update + +Then, because `libpng` isn't included in the iOS SDK, you will need to build a cross-architecture version yourself. Run `./setup-libraries.sh`, which is derived from Mapnik's cross-architecture build scripts. This will also run `./configure`. -Then, `make iproj` to create and open an Xcode project with an iOS-specific view controller housing and basic gesture support. +Lastly, `make iproj` to create and open an Xcode project with an iOS-specific view controller housing. Target devices: iPhone 4 and above (4S, 5, 5c, 5s) and iPad 2 and above (3, 4, mini and/or retina). From 949c10782db9db1a4c4ebe7f3aeaef6568248a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 14:27:04 +0200 Subject: [PATCH 10/24] remove poi translation --- bin/style.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/bin/style.js b/bin/style.js index fa0e915f7..4bd98db8d 100644 --- a/bin/style.js +++ b/bin/style.js @@ -586,10 +586,7 @@ module.exports = { "rail": "#bbb", "text": "#334", "marine_text": "#8dbeed", - "maki": "#666", - "point_translate": [ - 0, -30 - ] + "maki": "#666" }, "structure": [{ "name": "background", @@ -2016,52 +2013,42 @@ module.exports = { "poi_airport": { "color": "maki", "image": "airport-12", - "translate": "point_translate", }, "poi_restaurant": { "color": "maki", "image": "restaurant-12", - "translate": "point_translate", }, "poi_bus": { "color": "maki", "image": "bus-12", - "translate": "point_translate", }, "poi_rail": { "color": "maki", "image": "rail-12", - "translate": "point_translate", }, "poi_fire_station": { "color": "maki", "image": "fire-station-12", - "translate": "point_translate", }, "poi_park": { "color": "maki", "image": "park-12", - "translate": "point_translate", }, "poi_hospital": { "color": "maki", "image": "hospital-12", - "translate": "point_translate", }, "poi_playground": { "color": "maki", "image": "playground-12", - "translate": "point_translate", }, "poi_cafe": { "color": "maki", "image": "cafe-12", - "translate": "point_translate", }, "poi_beer": { "color": "maki", "image": "beer-12", - "translate": "point_translate", }, "satellite": { "type": "raster", From aeae6248ad182c3752d69ced094435cb2f33ba46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 14:27:49 +0200 Subject: [PATCH 11/24] simplify point shader in preparation for #196 --- include/llmr/shader/point_shader.hpp | 12 ++++++------ src/renderer/painter_point.cpp | 29 ++++++++++++++++------------ src/shader/point.fragment.glsl | 21 +++++--------------- src/shader/point_shader.cpp | 24 +++++++++++------------ src/shader/shaders_gl.cpp | 2 +- src/shader/shaders_gles2.cpp | 2 +- 6 files changed, 42 insertions(+), 48 deletions(-) diff --git a/include/llmr/shader/point_shader.hpp b/include/llmr/shader/point_shader.hpp index f0935f478..921e950a5 100644 --- a/include/llmr/shader/point_shader.hpp +++ b/include/llmr/shader/point_shader.hpp @@ -13,8 +13,8 @@ public: void setImage(int32_t image); void setColor(const std::array& color); - void setPointTopLeft(const std::array& point_tl); - void setPointBottomRight(const std::array& point_br); + void setPosition(const std::array& pos); + void setDimension(const std::array& dimension); void setSize(float size); private: @@ -26,11 +26,11 @@ private: std::array color = {{}}; int32_t u_color = -1; - std::array point_tl = {{}}; - int32_t u_point_tl = -1; + std::array pos = {{}}; + int32_t u_pos = -1; - std::array point_br = {{}}; - int32_t u_point_br = -1; + std::array dimension = {{}}; + int32_t u_dimension = -1; float size = 0; int32_t u_size = -1; diff --git a/src/renderer/painter_point.cpp b/src/renderer/painter_point.cpp index 84861367d..85a7444cf 100644 --- a/src/renderer/painter_point.cpp +++ b/src/renderer/painter_point.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using namespace llmr; @@ -43,9 +44,8 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co dotShader->setColor(color); const float pointSize = (properties.radius ? properties.radius * 2 : 8) * map.getState().getPixelRatio(); -#if defined(GL_ES_VERSION_2_0) - dotShader->setSize(pointSize); -#else + dotShader->setSize(pointSize); +#ifndef GL_ES_VERSION_2_0 glPointSize(pointSize); glEnable(GL_POINT_SPRITE); #endif @@ -57,19 +57,24 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co useProgram(pointShader->program); pointShader->setMatrix(vtxMatrix); pointShader->setColor(color); - pointShader->setImage(0); - pointShader->setPointTopLeft({{ imagePos.tl.x, imagePos.tl.y }}); - pointShader->setPointBottomRight({{ imagePos.br.x, imagePos.br.y }}); + pointShader->setPosition({{ + 0.5f * (imagePos.tl.x + imagePos.br.x), + 0.5f * (imagePos.tl.y + imagePos.br.y), + }}); + + pointShader->setDimension({{ + static_cast(sprite->raster.width), + static_cast(sprite->raster.height) + }}); sprite->raster.bind(map.getState().isChanging()); - const float pointSize = (properties.size ? properties.size : (imagePos.size.x / map.getState().getPixelRatio())) * 1.4142135623730951 * map.getState().getPixelRatio(); -#if defined(GL_ES_VERSION_2_0) - pointShader->setSize(pointSize); -#else - glPointSize(pointSize); - glEnable(GL_POINT_SPRITE); + const float pointSize = util::max(imagePos.size.x, imagePos.size.y) + 2; + pointShader->setSize(pointSize); +#ifndef GL_ES_VERSION_2_0 + glPointSize(pointSize); + glEnable(GL_POINT_SPRITE); #endif glDepthRange(strata, 1.0f); diff --git a/src/shader/point.fragment.glsl b/src/shader/point.fragment.glsl index 2f099feb7..d82bfaa88 100644 --- a/src/shader/point.fragment.glsl +++ b/src/shader/point.fragment.glsl @@ -1,21 +1,10 @@ -#define root2 1.4142135623730951 - uniform sampler2D u_image; -uniform vec2 u_tl; -uniform vec2 u_br; +uniform vec2 u_pos; +uniform vec2 u_dimension; uniform vec4 u_color; - -uniform vec2 pos; -uniform float inbounds; -uniform vec4 color; +uniform float u_size; void main() { - vec2 pos = (gl_PointCoord * 2.0 - 1.0) * root2 / 2.0 + 0.5; - - float inbounds = step(0.0, pos.x) * step(0.0, pos.y) * - (1.0 - step(1.0, pos.x)) * (1.0 - step(1.0, pos.y)); - - vec4 color = texture2D(u_image, mix(u_tl, u_br, pos)) * inbounds; - - gl_FragColor = color * u_color; + vec2 pos = u_pos + (gl_PointCoord - 0.5) * u_size / u_dimension; + gl_FragColor = texture2D(u_image, pos) * u_color; } diff --git a/src/shader/point_shader.cpp b/src/shader/point_shader.cpp index 61e3f3abf..757c8b217 100644 --- a/src/shader/point_shader.cpp +++ b/src/shader/point_shader.cpp @@ -21,15 +21,15 @@ PointShader::PointShader() u_matrix = glGetUniformLocation(program, "u_matrix"); u_color = glGetUniformLocation(program, "u_color"); u_size = glGetUniformLocation(program, "u_size"); - u_point_tl = glGetUniformLocation(program, "u_tl"); - u_point_br = glGetUniformLocation(program, "u_br"); + u_pos = glGetUniformLocation(program, "u_pos"); + u_dimension = glGetUniformLocation(program, "u_dimension"); // fprintf(stderr, "PointShader:\n"); // fprintf(stderr, " - u_matrix: %d\n", u_matrix); // fprintf(stderr, " - u_color: %d\n", u_color); // fprintf(stderr, " - u_size: %d\n", u_size); - // fprintf(stderr, " - u_point_tl: %d\n", u_point_tl); - // fprintf(stderr, " - u_point_br: %d\n", u_point_br); + // fprintf(stderr, " - u_pos: %d\n", u_pos); + // fprintf(stderr, " - u_dimension: %d\n", u_dimension); // fprintf(stderr, " - u_image: %d\n", u_image); } @@ -59,16 +59,16 @@ void PointShader::setSize(float new_size) { } } -void PointShader::setPointTopLeft(const std::array& new_point_tl) { - if (point_tl != new_point_tl) { - glUniform2fv(u_point_tl, 1, new_point_tl.data()); - point_tl = new_point_tl; +void PointShader::setPosition(const std::array& new_pos) { + if (pos != new_pos) { + glUniform2fv(u_pos, 1, new_pos.data()); + pos = new_pos; } } -void PointShader::setPointBottomRight(const std::array& new_point_br) { - if (point_br != new_point_br) { - glUniform2fv(u_point_br, 1, new_point_br.data()); - point_br = new_point_br; +void PointShader::setDimension(const std::array& new_dimension) { + if (dimension != new_dimension) { + glUniform2fv(u_dimension, 1, new_dimension.data()); + dimension = new_dimension; } } diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index 32f8af081..22bc15ea6 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -32,7 +32,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { }, { "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_tl;\nuniform vec2 u_br;\nuniform vec4 u_color;\nvoid main ()\n{\n vec2 tmpvar_1;\n tmpvar_1 = (((\n ((gl_PointCoord * 2.0) - 1.0)\n * 1.41421) / 2.0) + 0.5);\n gl_FragColor = ((texture2D (u_image, mix (u_tl, u_br, tmpvar_1)) * (\n ((float((tmpvar_1.x >= 0.0)) * float((tmpvar_1.y >= 0.0))) * (1.0 - float((tmpvar_1.x >= 1.0))))\n * \n (1.0 - float((tmpvar_1.y >= 1.0)))\n )) * u_color);\n}\n\n", + "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, (u_pos + (\n ((gl_PointCoord - 0.5) * u_size)\n / u_dimension))) * u_color);\n}\n\n", }, { "#version 120\nuniform mat4 u_matrix;\nattribute vec2 a_pos;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n v_pos = (a_pos / 4096.0);\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index cd247a9e5..ce24d4081 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -32,7 +32,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { }, { "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_tl;\nuniform vec2 u_br;\nuniform vec4 u_color;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = (((\n ((gl_PointCoord * 2.0) - 1.0)\n * 1.41421) / 2.0) + 0.5);\n mediump vec2 tmpvar_2;\n tmpvar_2 = mix (u_tl, u_br, tmpvar_1);\n lowp vec4 tmpvar_3;\n tmpvar_3 = texture2D (u_image, tmpvar_2);\n gl_FragColor = ((tmpvar_3 * (\n ((float((tmpvar_1.x >= 0.0)) * float((tmpvar_1.y >= 0.0))) * (1.0 - float((tmpvar_1.x >= 1.0))))\n * \n (1.0 - float((tmpvar_1.y >= 1.0)))\n )) * u_color);\n}\n\n", + "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = (u_pos + ((\n (gl_PointCoord - 0.5)\n * u_size) / u_dimension));\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", }, { "precision highp float;\nuniform mat4 u_matrix;\nattribute vec2 a_pos;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n v_pos = (a_pos / 4096.0);\n}\n\n", From fda64b67af9eb25918dcceb2e7f57e6c2bce351c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 14:51:02 +0200 Subject: [PATCH 12/24] rename point => icon --- .../{point_buffer.hpp => icon_buffer.hpp} | 6 +-- include/llmr/map/tile_parser.hpp | 2 +- include/llmr/map/vector_tile_data.hpp | 4 +- .../{point_bucket.hpp => icon_bucket.hpp} | 20 ++++----- include/llmr/renderer/painter.hpp | 8 ++-- .../{point_shader.hpp => icon_shader.hpp} | 8 ++-- include/llmr/style/bucket_description.hpp | 4 +- include/llmr/style/class_description.hpp | 2 +- include/llmr/style/properties.hpp | 4 +- include/llmr/style/style.hpp | 2 +- include/llmr/style/style_parser.hpp | 2 +- .../{point_buffer.cpp => icon_buffer.cpp} | 4 +- src/map/map.cpp | 4 +- src/map/tile_parser.cpp | 12 +++--- src/map/vector_tile.cpp | 2 +- .../{point_bucket.cpp => icon_bucket.cpp} | 20 ++++----- src/renderer/painter.cpp | 2 +- .../{painter_point.cpp => painter_icon.cpp} | 42 +++++++++---------- ...point.fragment.glsl => icon.fragment.glsl} | 0 .../{point.vertex.glsl => icon.vertex.glsl} | 0 .../{point_shader.cpp => icon_shader.cpp} | 24 +++++------ src/shader/shaders_gl.cpp | 8 ++-- src/shader/shaders_gles2.cpp | 8 ++-- src/style/style.cpp | 32 +++++++------- src/style/style_parser.cpp | 8 ++-- 25 files changed, 114 insertions(+), 114 deletions(-) rename include/llmr/geometry/{point_buffer.hpp => icon_buffer.hpp} (64%) rename include/llmr/renderer/{point_bucket.hpp => icon_bucket.hpp} (66%) rename include/llmr/shader/{point_shader.hpp => icon_shader.hpp} (84%) rename src/geometry/{point_buffer.cpp => icon_buffer.cpp} (64%) rename src/renderer/{point_bucket.cpp => icon_bucket.cpp} (69%) rename src/renderer/{painter_point.cpp => painter_icon.cpp} (61%) rename src/shader/{point.fragment.glsl => icon.fragment.glsl} (100%) rename src/shader/{point.vertex.glsl => icon.vertex.glsl} (100%) rename src/shader/{point_shader.cpp => icon_shader.cpp} (72%) diff --git a/include/llmr/geometry/point_buffer.hpp b/include/llmr/geometry/icon_buffer.hpp similarity index 64% rename from include/llmr/geometry/point_buffer.hpp rename to include/llmr/geometry/icon_buffer.hpp index 8c01a20ee..fc918c545 100644 --- a/include/llmr/geometry/point_buffer.hpp +++ b/include/llmr/geometry/icon_buffer.hpp @@ -1,11 +1,11 @@ -#ifndef LLMR_GEOMETRY_POINT_BUFFER -#define LLMR_GEOMETRY_POINT_BUFFER +#ifndef LLMR_GEOMETRY_ICON_BUFFER +#define LLMR_GEOMETRY_ICON_BUFFER #include "buffer.hpp" namespace llmr { - class PointVertexBuffer : public Buffer< + class IconVertexBuffer : public Buffer< 4 // 2 coordinates per vertex (== 4 bytes) > { public: diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 269ab3ba9..91566d40a 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -24,7 +24,7 @@ private: std::unique_ptr createBucket(const BucketDescription& bucket_desc); std::unique_ptr createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::unique_ptr createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); - std::unique_ptr createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); + std::unique_ptr createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::unique_ptr createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc); diff --git a/include/llmr/map/vector_tile_data.hpp b/include/llmr/map/vector_tile_data.hpp index b9a428dde..24d2c7cc2 100644 --- a/include/llmr/map/vector_tile_data.hpp +++ b/include/llmr/map/vector_tile_data.hpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -33,7 +33,7 @@ protected: // Holds the actual geometries in this tile. FillVertexBuffer fillVertexBuffer; LineVertexBuffer lineVertexBuffer; - PointVertexBuffer pointVertexBuffer; + IconVertexBuffer iconVertexBuffer; TextVertexBuffer textVertexBuffer; TriangleElementsBuffer triangleElementsBuffer; diff --git a/include/llmr/renderer/point_bucket.hpp b/include/llmr/renderer/icon_bucket.hpp similarity index 66% rename from include/llmr/renderer/point_bucket.hpp rename to include/llmr/renderer/icon_bucket.hpp index 2aacbe865..a3338767e 100644 --- a/include/llmr/renderer/point_bucket.hpp +++ b/include/llmr/renderer/icon_bucket.hpp @@ -1,10 +1,10 @@ -#ifndef LLMR_RENDERER_POINTBUCKET -#define LLMR_RENDERER_POINTBUCKET +#ifndef LLMR_RENDERER_ICONBUCKET +#define LLMR_RENDERER_ICONBUCKET #include #include #include -#include +#include #include #include @@ -16,15 +16,15 @@ namespace llmr { class Style; -class PointVertexBuffer; +class IconVertexBuffer; class BucketDescription; -class PointShader; +class IconShader; class DotShader; struct pbf; -class PointBucket : public Bucket { +class IconBucket : public Bucket { public: - PointBucket(PointVertexBuffer& vertexBuffer, + IconBucket(IconVertexBuffer& vertexBuffer, const BucketDescription& bucket_desc); virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); @@ -32,15 +32,15 @@ public: void addGeometry(pbf& data); - void drawPoints(PointShader& shader); - void drawPoints(DotShader& shader); + void drawIcons(IconShader& shader); + void drawIcons(DotShader& shader); public: const BucketGeometryDescription geometry; private: - PointVertexBuffer& vertexBuffer; + IconVertexBuffer& vertexBuffer; VertexArrayObject array; const size_t vertex_start; diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 73281a906..09ee8e42f 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -30,7 +30,7 @@ class GlyphAtlas; class FillBucket; class LineBucket; -class PointBucket; +class IconBucket; class TextBucket; class RasterBucket; @@ -65,7 +65,7 @@ public: void renderDebugText(const std::vector &strings); void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id); void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id); - void renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& id); + void renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id); void renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id); void renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& id); @@ -123,7 +123,7 @@ private: std::unique_ptr lineShader; std::unique_ptr linejoinShader; std::unique_ptr patternShader; - std::unique_ptr pointShader; + std::unique_ptr iconShader; std::unique_ptr rasterShader; std::unique_ptr textShader; std::unique_ptr dotShader; diff --git a/include/llmr/shader/point_shader.hpp b/include/llmr/shader/icon_shader.hpp similarity index 84% rename from include/llmr/shader/point_shader.hpp rename to include/llmr/shader/icon_shader.hpp index 921e950a5..db3bfe686 100644 --- a/include/llmr/shader/point_shader.hpp +++ b/include/llmr/shader/icon_shader.hpp @@ -1,13 +1,13 @@ -#ifndef LLMR_SHADER_SHADER_POINT -#define LLMR_SHADER_SHADER_POINT +#ifndef LLMR_SHADER_SHADER_ICON +#define LLMR_SHADER_SHADER_ICON #include namespace llmr { -class PointShader : public Shader { +class IconShader : public Shader { public: - PointShader(); + IconShader(); void bind(char *offset); diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index e7cde3db8..615b5af65 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -13,7 +13,7 @@ enum class BucketType { None = 0, Fill = 1, Line = 2, - Point = 3, + Icon = 3, Text = 4, Raster = 5 }; @@ -41,7 +41,7 @@ enum class TextPathType { inline BucketType bucketType(const std::string& type) { if (type == "fill") return BucketType::Fill; else if (type == "line") return BucketType::Line; - else if (type == "point") return BucketType::Point; + else if (type == "point") return BucketType::Icon; else if (type == "text") return BucketType::Text; else if (type == "raster") return BucketType::Raster; else return BucketType::None; diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp index dc8c5faa2..782f5da4f 100644 --- a/include/llmr/style/class_description.hpp +++ b/include/llmr/style/class_description.hpp @@ -13,7 +13,7 @@ public: BackgroundClass background; std::map fill; std::map line; - std::map point; + std::map icon; std::map text; std::map raster; }; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 2fd43f8f5..a9bd89909 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -60,7 +60,7 @@ struct FunctionProperty { template inline T evaluate(float z) const { return function(z, values); } }; -struct PointClass { +struct IconClass { FunctionProperty enabled = true; std::array translate = {{ 0, 0 }}; TranslateAnchor translateAnchor = TranslateAnchor::Map; @@ -72,7 +72,7 @@ struct PointClass { FunctionProperty blur = 0; }; -struct PointProperties { +struct IconProperties { bool enabled = true; std::array translate = {{ 0, 0 }}; TranslateAnchor translateAnchor = TranslateAnchor::Map; diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 213a0b94c..8fcb99732 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -46,7 +46,7 @@ public: BackgroundProperties background; std::map fills; std::map lines; - std::map points; + std::map icons; std::map texts; std::map rasters; } computed; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 25a7fd3b0..4d6af15d9 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -22,7 +22,7 @@ private: void parseClass(const std::string& name, JSVal value, ClassDescription& class_desc, std::map& buckets, std::vector& layers); FillClass parseFillClass(JSVal value); LineClass parseLineClass(JSVal value); - PointClass parsePointClass(JSVal value); + IconClass parseIconClass(JSVal value); TextClass parseTextClass(JSVal value); BackgroundClass parseBackgroundClass(JSVal value); RasterClass parseRasterClass(JSVal value); diff --git a/src/geometry/point_buffer.cpp b/src/geometry/icon_buffer.cpp similarity index 64% rename from src/geometry/point_buffer.cpp rename to src/geometry/icon_buffer.cpp index 00137eae3..df5b7434d 100644 --- a/src/geometry/point_buffer.cpp +++ b/src/geometry/icon_buffer.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include using namespace llmr; -void PointVertexBuffer::add(vertex_type x, vertex_type y) { +void IconVertexBuffer::add(vertex_type x, vertex_type y) { vertex_type *vertices = static_cast(addElement()); vertices[0] = x; vertices[1] = y; diff --git a/src/map/map.cpp b/src/map/map.cpp index 9d1537538..de5c178a3 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -518,9 +518,9 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) { if (pass == Opaque) return; if (is_invisible(style.computed.lines, layer_desc)) return; break; - case BucketType::Point: + case BucketType::Icon: if (pass == Opaque) return; - if (is_invisible(style.computed.points, layer_desc)) return; + if (is_invisible(style.computed.icons, layer_desc)) return; break; case BucketType::Text: if (pass == Opaque) return; diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 793ef353b..ebbba78d3 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -91,8 +91,8 @@ std::unique_ptr TileParser::createBucket(const BucketDescription& bucket return createFillBucket(layer, bucket_desc); } else if (bucket_desc.type == BucketType::Line) { return createLineBucket(layer, bucket_desc); - } else if (bucket_desc.type == BucketType::Point) { - return createPointBucket(layer, bucket_desc); + } else if (bucket_desc.type == BucketType::Icon) { + return createIconBucket(layer, bucket_desc); } else if (bucket_desc.type == BucketType::Text) { return createTextBucket(layer, bucket_desc); } else { @@ -134,9 +134,9 @@ std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& laye return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr TileParser::createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { - std::unique_ptr bucket = std::make_unique( - tile.pointVertexBuffer, bucket_desc); +std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { + std::unique_ptr bucket = std::make_unique( + tile.iconVertexBuffer, bucket_desc); addBucketFeatures(bucket, layer, bucket_desc); return obsolete() ? nullptr : std::move(bucket); } diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 634b296f2..248e94712 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -302,7 +302,7 @@ void FilteredVectorTileLayer::iterator::operator++() { } } else if (feature_pbf.tag == 3) { // geometry type switch (feature_pbf.varint()) { - case 1 /* Point */: type = BucketType::Point; break; + case 1 /* Point */: type = BucketType::Icon; break; case 2 /* LineString */: type = BucketType::Line; break; case 3 /* Polygon */: type = BucketType::Fill; break; default: type = BucketType::None; break; diff --git a/src/renderer/point_bucket.cpp b/src/renderer/icon_bucket.cpp similarity index 69% rename from src/renderer/point_bucket.cpp rename to src/renderer/icon_bucket.cpp index fa8482944..6e3c65276 100644 --- a/src/renderer/point_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include @@ -15,14 +15,14 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; -PointBucket::PointBucket(PointVertexBuffer& vertexBuffer, +IconBucket::IconBucket(IconVertexBuffer& vertexBuffer, const BucketDescription& bucket_desc) : geometry(bucket_desc.geometry), vertexBuffer(vertexBuffer), vertex_start(vertexBuffer.index()) { } -void PointBucket::addGeometry(pbf& geom) { +void IconBucket::addGeometry(pbf& geom) { Geometry::command cmd; Geometry geometry(geom); int32_t x, y; @@ -30,28 +30,28 @@ void PointBucket::addGeometry(pbf& geom) { if (cmd == Geometry::move_to) { vertexBuffer.add(x, y); } else { - fprintf(stderr, "other command than move_to in point geometry\n"); + fprintf(stderr, "other command than move_to in icon geometry\n"); } } vertex_end = vertexBuffer.index(); } -void PointBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { - painter.renderPoint(*this, layer_name, id); +void IconBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { + painter.renderIcon(*this, layer_name, id); } -bool PointBucket::hasData() const { +bool IconBucket::hasData() const { return vertex_end > 0; } -void PointBucket::drawPoints(PointShader& shader) { +void IconBucket::drawIcons(IconShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); array.bind(shader, vertexBuffer, vertex_index); glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start)); } -void PointBucket::drawPoints(DotShader& shader) { +void IconBucket::drawIcons(DotShader& shader) { char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); array.bind(shader, vertexBuffer, vertex_index); glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start)); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 833f7b6a4..4ddd21a77 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -63,7 +63,7 @@ void Painter::setupShaders() { lineShader = std::make_unique(); linejoinShader = std::make_unique(); patternShader = std::make_unique(); - pointShader = std::make_unique(); + iconShader = std::make_unique(); rasterShader = std::make_unique(); textShader = std::make_unique(); dotShader = std::make_unique(); diff --git a/src/renderer/painter_point.cpp b/src/renderer/painter_icon.cpp similarity index 61% rename from src/renderer/painter_point.cpp rename to src/renderer/painter_icon.cpp index 85a7444cf..37a7b61e5 100644 --- a/src/renderer/painter_point.cpp +++ b/src/renderer/painter_icon.cpp @@ -1,21 +1,21 @@ #include -#include +#include #include #include #include using namespace llmr; -void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& id) { +void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id) { // Abort early. if (!bucket.hasData()) return; if (pass == Opaque) return; - auto point_properties = map.getStyle().computed.points; - auto point_properties_it = point_properties.find(layer_name); - if (point_properties_it == point_properties.end()) return; + auto icon_properties = map.getStyle().computed.icons; + auto icon_properties_it = icon_properties.find(layer_name); + if (icon_properties_it == icon_properties.end()) return; - const PointProperties& properties = point_properties_it->second; + const IconProperties& properties = icon_properties_it->second; if (!properties.enabled) return; Color color = properties.color; @@ -43,41 +43,41 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co dotShader->setMatrix(vtxMatrix); dotShader->setColor(color); - const float pointSize = (properties.radius ? properties.radius * 2 : 8) * map.getState().getPixelRatio(); - dotShader->setSize(pointSize); + const float iconSize = (properties.radius ? properties.radius * 2 : 8) * map.getState().getPixelRatio(); + dotShader->setSize(iconSize); #ifndef GL_ES_VERSION_2_0 - glPointSize(pointSize); + glPointSize(iconSize); glEnable(GL_POINT_SPRITE); #endif - dotShader->setBlur((properties.blur ? properties.blur : 1.5) / pointSize); + dotShader->setBlur((properties.blur ? properties.blur : 1.5) / iconSize); glDepthRange(strata, 1.0f); - bucket.drawPoints(*dotShader); + bucket.drawIcons(*dotShader); } else { - useProgram(pointShader->program); - pointShader->setMatrix(vtxMatrix); - pointShader->setColor(color); - pointShader->setImage(0); - pointShader->setPosition({{ + useProgram(iconShader->program); + iconShader->setMatrix(vtxMatrix); + iconShader->setColor(color); + iconShader->setImage(0); + iconShader->setPosition({{ 0.5f * (imagePos.tl.x + imagePos.br.x), 0.5f * (imagePos.tl.y + imagePos.br.y), }}); - pointShader->setDimension({{ + iconShader->setDimension({{ static_cast(sprite->raster.width), static_cast(sprite->raster.height) }}); sprite->raster.bind(map.getState().isChanging()); - const float pointSize = util::max(imagePos.size.x, imagePos.size.y) + 2; - pointShader->setSize(pointSize); + const float iconSize = util::max(imagePos.size.x, imagePos.size.y) + 2; + iconShader->setSize(iconSize); #ifndef GL_ES_VERSION_2_0 - glPointSize(pointSize); + glPointSize(iconSize); glEnable(GL_POINT_SPRITE); #endif glDepthRange(strata, 1.0f); - bucket.drawPoints(*pointShader); + bucket.drawIcons(*iconShader); } } diff --git a/src/shader/point.fragment.glsl b/src/shader/icon.fragment.glsl similarity index 100% rename from src/shader/point.fragment.glsl rename to src/shader/icon.fragment.glsl diff --git a/src/shader/point.vertex.glsl b/src/shader/icon.vertex.glsl similarity index 100% rename from src/shader/point.vertex.glsl rename to src/shader/icon.vertex.glsl diff --git a/src/shader/point_shader.cpp b/src/shader/icon_shader.cpp similarity index 72% rename from src/shader/point_shader.cpp rename to src/shader/icon_shader.cpp index 757c8b217..820a5118b 100644 --- a/src/shader/point_shader.cpp +++ b/src/shader/icon_shader.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -6,13 +6,13 @@ using namespace llmr; -PointShader::PointShader() +IconShader::IconShader() : Shader( - shaders[POINT_SHADER].vertex, - shaders[POINT_SHADER].fragment + shaders[ICON_SHADER].vertex, + shaders[ICON_SHADER].fragment ) { if (!valid) { - fprintf(stderr, "invalid point shader\n"); + fprintf(stderr, "invalid icon shader\n"); return; } @@ -24,7 +24,7 @@ PointShader::PointShader() u_pos = glGetUniformLocation(program, "u_pos"); u_dimension = glGetUniformLocation(program, "u_dimension"); - // fprintf(stderr, "PointShader:\n"); + // fprintf(stderr, "IconShader:\n"); // fprintf(stderr, " - u_matrix: %d\n", u_matrix); // fprintf(stderr, " - u_color: %d\n", u_color); // fprintf(stderr, " - u_size: %d\n", u_size); @@ -33,40 +33,40 @@ PointShader::PointShader() // fprintf(stderr, " - u_image: %d\n", u_image); } -void PointShader::bind(char *offset) { +void IconShader::bind(char *offset) { glEnableVertexAttribArray(a_pos); glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); } -void PointShader::setImage(int32_t new_image) { +void IconShader::setImage(int32_t new_image) { if (image != new_image) { glUniform1i(u_image, new_image); image = new_image; } } -void PointShader::setColor(const std::array& new_color) { +void IconShader::setColor(const std::array& new_color) { if (color != new_color) { glUniform4fv(u_color, 1, new_color.data()); color = new_color; } } -void PointShader::setSize(float new_size) { +void IconShader::setSize(float new_size) { if (size != new_size) { glUniform1f(u_size, new_size); size = new_size; } } -void PointShader::setPosition(const std::array& new_pos) { +void IconShader::setPosition(const std::array& new_pos) { if (pos != new_pos) { glUniform2fv(u_pos, 1, new_pos.data()); pos = new_pos; } } -void PointShader::setDimension(const std::array& new_dimension) { +void IconShader::setDimension(const std::array& new_dimension) { if (dimension != new_dimension) { glUniform2fv(u_dimension, 1, new_dimension.data()); dimension = new_dimension; diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index 22bc15ea6..b78dc0436 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -10,6 +10,10 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", "#version 120\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", }, + { + "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", + "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, (u_pos + (\n ((gl_PointCoord - 0.5) * u_size)\n / u_dimension))) * u_color);\n}\n\n", + }, { "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", "#version 120\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform vec2 u_dasharray;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n float tmpvar_1;\n tmpvar_1 = (sqrt(dot (v_normal, v_normal)) * u_linewidth.x);\n float tmpvar_2;\n tmpvar_2 = (float(mod (v_linesofar, (u_dasharray.x + u_dasharray.y))));\n gl_FragColor = (u_color * (clamp (\n min ((tmpvar_1 - (u_linewidth.y - 1.0)), (u_linewidth.x - tmpvar_1))\n , 0.0, 1.0) * max (\n float((-(u_dasharray.y) >= 0.0))\n , \n clamp (min (tmpvar_2, (u_dasharray.x - tmpvar_2)), 0.0, 1.0)\n )));\n}\n\n", @@ -30,10 +34,6 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n}\n\n", "#version 120\nuniform vec4 u_color;\nvoid main ()\n{\n gl_FragColor = u_color;\n}\n\n", }, - { - "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, (u_pos + (\n ((gl_PointCoord - 0.5) * u_size)\n / u_dimension))) * u_color);\n}\n\n", - }, { "#version 120\nuniform mat4 u_matrix;\nattribute vec2 a_pos;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n v_pos = (a_pos / 4096.0);\n}\n\n", "#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, v_pos) * u_opacity);\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index ce24d4081..b6d6832a1 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -10,6 +10,10 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", "precision highp float;\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n mediump vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n mediump float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", }, + { + "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", + "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = (u_pos + ((\n (gl_PointCoord - 0.5)\n * u_size) / u_dimension));\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", + }, { "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", "precision highp float;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform vec2 u_dasharray;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n float tmpvar_1;\n tmpvar_1 = (sqrt(dot (v_normal, v_normal)) * u_linewidth.x);\n float tmpvar_2;\n tmpvar_2 = (float(mod (v_linesofar, (u_dasharray.x + u_dasharray.y))));\n gl_FragColor = (u_color * (clamp (\n min ((tmpvar_1 - (u_linewidth.y - 1.0)), (u_linewidth.x - tmpvar_1))\n , 0.0, 1.0) * max (\n float((-(u_dasharray.y) >= 0.0))\n , \n clamp (min (tmpvar_2, (u_dasharray.x - tmpvar_2)), 0.0, 1.0)\n )));\n}\n\n", @@ -30,10 +34,6 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n}\n\n", "precision highp float;\nuniform vec4 u_color;\nvoid main ()\n{\n gl_FragColor = u_color;\n}\n\n", }, - { - "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = (u_pos + ((\n (gl_PointCoord - 0.5)\n * u_size) / u_dimension));\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", - }, { "precision highp float;\nuniform mat4 u_matrix;\nattribute vec2 a_pos;\nvarying vec2 v_pos;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n v_pos = (a_pos / 4096.0);\n}\n\n", "precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\nvarying vec2 v_pos;\nvoid main ()\n{\n lowp vec4 tmpvar_1;\n tmpvar_1 = (texture2D (u_image, v_pos) * u_opacity);\n gl_FragColor = tmpvar_1;\n}\n\n", diff --git a/src/style/style.cpp b/src/style/style.cpp index 54ebe0936..56426d2a3 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -14,7 +14,7 @@ Style::Style() { void Style::reset() { computed.fills.clear(); computed.lines.clear(); - computed.points.clear(); + computed.icons.clear(); } void Style::cascade(float z) { @@ -69,24 +69,24 @@ void Style::cascade(float z) { stroke.opacity = layer.opacity.evaluate(z); } - // Cascade point classes - for (const auto& point_pair : sheetClass.point) { - const std::string& layer_name = point_pair.first; - const llmr::PointClass& layer = point_pair.second; + // Cascade icon classes + for (const auto& icon_pair : sheetClass.icon) { + const std::string& layer_name = icon_pair.first; + const llmr::IconClass& layer = icon_pair.second; - // TODO: This should be restricted to point styles that have actual + // TODO: This should be restricted to icon styles that have actual // values so as to not override with default values. - llmr::PointProperties& point = computed.points[layer_name]; - point.enabled = layer.enabled.evaluate(z); - point.translate = {{ layer.translate[0].evaluate(z), + llmr::IconProperties& icon = computed.icons[layer_name]; + icon.enabled = layer.enabled.evaluate(z); + icon.translate = {{ layer.translate[0].evaluate(z), layer.translate[1].evaluate(z) }}; - point.translateAnchor = layer.translateAnchor; - point.color = layer.color; - point.size = layer.size.evaluate(z); - point.opacity = layer.opacity.evaluate(z); - point.image = layer.image; - point.radius = layer.radius.evaluate(z); - point.blur = layer.blur.evaluate(z); + icon.translateAnchor = layer.translateAnchor; + icon.color = layer.color; + icon.size = layer.size.evaluate(z); + icon.opacity = layer.opacity.evaluate(z); + icon.image = layer.image; + icon.radius = layer.radius.evaluate(z); + icon.blur = layer.blur.evaluate(z); } // Cascade text classes diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index e41ceba4d..057b75d09 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -269,8 +269,8 @@ void StyleParser::parseClass(const std::string& name, JSVal value, ClassDescript class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); } else if (type == BucketType::Line) { class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); - } else if (type == BucketType::Point) { - class_desc.point.insert({ name, std::forward(parsePointClass(value)) }); + } else if (type == BucketType::Icon) { + class_desc.icon.insert({ name, std::forward(parseIconClass(value)) }); } else if (type == BucketType::Text) { class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); } else if (type == BucketType::Raster) { @@ -512,8 +512,8 @@ LineClass StyleParser::parseLineClass(JSVal value) { return klass; } -PointClass StyleParser::parsePointClass(JSVal value) { - PointClass klass; +IconClass StyleParser::parseIconClass(JSVal value) { + IconClass klass; if (value.HasMember("enabled")) { klass.enabled = parseFunction(value["enabled"]); From 44f8c80d21897edc985b9d72c65aad8e7b311637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 14:51:11 +0200 Subject: [PATCH 13/24] also clear text and raster styles --- src/style/style.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/style/style.cpp b/src/style/style.cpp index 56426d2a3..b95cb5f20 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -15,6 +15,8 @@ void Style::reset() { computed.fills.clear(); computed.lines.clear(); computed.icons.clear(); + computed.texts.clear(); + computed.rasters.clear(); } void Style::cascade(float z) { From 27b695b0687d5f2966a6938ab80ed4aa91d52d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 14:56:06 +0200 Subject: [PATCH 14/24] use explicit constructors --- include/llmr/style/sprite.hpp | 6 +++--- src/style/sprite.cpp | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/llmr/style/sprite.hpp b/include/llmr/style/sprite.hpp index 6dd4828e3..a4752f9eb 100644 --- a/include/llmr/style/sprite.hpp +++ b/include/llmr/style/sprite.hpp @@ -16,7 +16,7 @@ class Map; class SpritePosition { public: - SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t pixelRatio = 1); + explicit SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t pixelRatio = 1); uint16_t x = 0, y = 0; uint16_t width = 0, height = 0; @@ -25,8 +25,8 @@ public: class ImagePosition { public: - ImagePosition() {} - ImagePosition(const vec2& size, vec2 tl, vec2 br); + explicit ImagePosition() {} + explicit ImagePosition(const vec2& size, vec2 tl, vec2 br); vec2 size = { 0, 0 }; vec2 tl = { 0, 0 }; diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index e91a24c49..016149385 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -101,15 +101,14 @@ void Sprite::parseJSON(std::shared_ptr &sprite) { if (value.HasMember("width")) width = value["width"].GetInt(); if (value.HasMember("height")) height = value["height"].GetInt(); if (value.HasMember("pixelRatio")) pixelRatio = value["pixelRatio"].GetInt(); - - sprite->pos.insert({ name, { x, y, width, height, pixelRatio } }); + sprite->pos.emplace(name, SpritePosition { x, y, width, height, pixelRatio }); } } } } ImagePosition Sprite::getPosition(const std::string& name, bool repeating) { - if (!isLoaded()) return {}; + if (!isLoaded()) return ImagePosition {}; // `repeating` indicates that the image will be used in a repeating pattern // repeating pattern images are assumed to have a 1px padding that mirrors the opposite edge @@ -117,10 +116,10 @@ ImagePosition Sprite::getPosition(const std::string& name, bool repeating) { int8_t offset = repeating ? 1 : 0; auto it = pos.find(name); - if (it == pos.end()) return {}; + if (it == pos.end()) return ImagePosition {}; SpritePosition& pos = it->second; - return { + return ImagePosition { { pos.width, pos.height From 4c99014a1371c4acb352c0fa48d6008c8492d440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 15:16:34 +0200 Subject: [PATCH 15/24] don't use fractional texture coordiantes in the shader --- include/llmr/style/sprite.hpp | 5 ++++- src/renderer/painter_icon.cpp | 12 ++++++------ src/shader/icon.fragment.glsl | 2 +- src/shader/shaders_gl.cpp | 2 +- src/shader/shaders_gles2.cpp | 2 +- src/style/sprite.cpp | 10 ++++++++-- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/include/llmr/style/sprite.hpp b/include/llmr/style/sprite.hpp index a4752f9eb..58fd2b1ef 100644 --- a/include/llmr/style/sprite.hpp +++ b/include/llmr/style/sprite.hpp @@ -16,6 +16,7 @@ class Map; class SpritePosition { public: + explicit SpritePosition() {} explicit SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t pixelRatio = 1); uint16_t x = 0, y = 0; @@ -40,7 +41,8 @@ public: void load(const std::string& base_url); - ImagePosition getPosition(const std::string& name, bool repeating = false); + ImagePosition getPosition(const std::string& name, bool repeating = false) const; + const SpritePosition &getSpritePosition(const std::string& name) const; bool isLoaded() const; @@ -62,6 +64,7 @@ private: std::string image; std::atomic loaded; std::map pos; + const SpritePosition empty; }; } diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 37a7b61e5..28e9c6f66 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -25,7 +25,7 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons color[3] *= properties.opacity; auto &sprite = map.getStyle().sprite; - ImagePosition imagePos; + SpritePosition spritePos; if (properties.image.length() && sprite && sprite->isLoaded()) { std::string sized_image = properties.image; @@ -33,12 +33,12 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons sized_image.append("-"); sized_image.append(std::to_string(static_cast(std::round(properties.size)))); } - imagePos = sprite->getPosition(sized_image, false); + spritePos = sprite->getSpritePosition(sized_image); } const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); - if (!imagePos.size) { + if (!spritePos.width || !spritePos.height) { useProgram(dotShader->program); dotShader->setMatrix(vtxMatrix); dotShader->setColor(color); @@ -59,8 +59,8 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons iconShader->setColor(color); iconShader->setImage(0); iconShader->setPosition({{ - 0.5f * (imagePos.tl.x + imagePos.br.x), - 0.5f * (imagePos.tl.y + imagePos.br.y), + spritePos.x + (float)spritePos.width / 2.0f, + spritePos.y + (float)spritePos.height / 2.0f, }}); iconShader->setDimension({{ @@ -70,7 +70,7 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons sprite->raster.bind(map.getState().isChanging()); - const float iconSize = util::max(imagePos.size.x, imagePos.size.y) + 2; + const float iconSize = util::max(spritePos.width, spritePos.height) + 2; iconShader->setSize(iconSize); #ifndef GL_ES_VERSION_2_0 glPointSize(iconSize); diff --git a/src/shader/icon.fragment.glsl b/src/shader/icon.fragment.glsl index d82bfaa88..f5a424ae9 100644 --- a/src/shader/icon.fragment.glsl +++ b/src/shader/icon.fragment.glsl @@ -5,6 +5,6 @@ uniform vec4 u_color; uniform float u_size; void main() { - vec2 pos = u_pos + (gl_PointCoord - 0.5) * u_size / u_dimension; + vec2 pos = (u_pos + (gl_PointCoord - 0.5) * u_size) / u_dimension; gl_FragColor = texture2D(u_image, pos) * u_color; } diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index b78dc0436..45f1651dc 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -12,7 +12,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { }, { "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, (u_pos + (\n ((gl_PointCoord - 0.5) * u_size)\n / u_dimension))) * u_color);\n}\n\n", + "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, ((u_pos + \n ((gl_PointCoord - 0.5) * u_size)\n ) / u_dimension)) * u_color);\n}\n\n", }, { "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index b6d6832a1..d94e04f29 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -12,7 +12,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { }, { "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = (u_pos + ((\n (gl_PointCoord - 0.5)\n * u_size) / u_dimension));\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", + "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = ((u_pos + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension);\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", }, { "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index 016149385..93dd6bd24 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -107,7 +107,7 @@ void Sprite::parseJSON(std::shared_ptr &sprite) { } } -ImagePosition Sprite::getPosition(const std::string& name, bool repeating) { +ImagePosition Sprite::getPosition(const std::string& name, bool repeating) const { if (!isLoaded()) return ImagePosition {}; // `repeating` indicates that the image will be used in a repeating pattern @@ -118,7 +118,7 @@ ImagePosition Sprite::getPosition(const std::string& name, bool repeating) { auto it = pos.find(name); if (it == pos.end()) return ImagePosition {}; - SpritePosition& pos = it->second; + const SpritePosition& pos = it->second; return ImagePosition { { pos.width, @@ -134,3 +134,9 @@ ImagePosition Sprite::getPosition(const std::string& name, bool repeating) { } }; } + +const SpritePosition &Sprite::getSpritePosition(const std::string& name) const { + if (!isLoaded()) return empty; + auto it = pos.find(name); + return it == pos.end() ? empty : it->second; +} From 01183a0a1937267d3466509ac1f5b98bff9172a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 18:09:00 +0200 Subject: [PATCH 16/24] fix remaining cases of point => icon --- src/renderer/painter.cpp | 2 +- src/shader/dot_shader.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 4ddd21a77..f18e1a680 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -29,7 +29,7 @@ void Painter::setup() { setupShaders(); - assert(pointShader); + assert(iconShader); assert(plainShader); assert(outlineShader); assert(lineShader); diff --git a/src/shader/dot_shader.cpp b/src/shader/dot_shader.cpp index df2a6924f..2f0325427 100644 --- a/src/shader/dot_shader.cpp +++ b/src/shader/dot_shader.cpp @@ -23,7 +23,7 @@ DotShader::DotShader() u_size = glGetUniformLocation(program, "u_size"); u_blur = glGetUniformLocation(program, "u_blur"); - // fprintf(stderr, "PointShader:\n"); + // fprintf(stderr, "DotShader:\n"); // fprintf(stderr, " - u_matrix: %d\n", u_matrix); // fprintf(stderr, " - u_color: %d\n", u_color); // fprintf(stderr, " - u_size: %d\n", u_size); From 264bcd34d9f3661755e8030e889de2000d662ea1 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 16 May 2014 14:04:12 -0400 Subject: [PATCH 17/24] flush command buffers when done --- src/map/map.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/map/map.cpp b/src/map/map.cpp index de5c178a3..79a26305e 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -464,6 +464,8 @@ void Map::render() { if (transform.needsTransition()) { update(); } + + glFlush(); } void Map::renderLayers(const std::vector& layers, RenderPass pass) { From 27f8ed29e4b79a917b4aa715469bc22018a06037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 17:19:14 +0200 Subject: [PATCH 18/24] encode icon texture coordinate in buffer so we can render all pois with 1 draw call --- bin/style.js | 182 +--------------------- include/llmr/geometry/buffer.hpp | 40 +++-- include/llmr/geometry/icon_buffer.hpp | 5 +- include/llmr/map/tile_parser.hpp | 1 + include/llmr/renderer/icon_bucket.hpp | 5 +- include/llmr/shader/icon_shader.hpp | 5 +- include/llmr/style/bucket_description.hpp | 5 +- src/geometry/icon_buffer.cpp | 10 +- src/map/tile_parser.cpp | 19 ++- src/renderer/icon_bucket.cpp | 27 +++- src/renderer/painter_icon.cpp | 22 +-- src/renderer/painter_text.cpp | 4 +- src/renderer/text_bucket.cpp | 2 +- src/shader/dot_shader.cpp | 2 +- src/shader/icon.fragment.glsl | 5 +- src/shader/icon.vertex.glsl | 4 + src/shader/icon_shader.cpp | 15 +- src/shader/shaders_gl.cpp | 4 +- src/shader/shaders_gles2.cpp | 4 +- src/style/bucket_description.cpp | 2 +- src/style/style_parser.cpp | 8 +- src/text/placement.cpp | 2 +- 22 files changed, 120 insertions(+), 253 deletions(-) diff --git a/bin/style.js b/bin/style.js index 4bd98db8d..558c64242 100644 --- a/bin/style.js +++ b/bin/style.js @@ -452,116 +452,13 @@ module.exports = { "feature_type": "point", "type": "text" }, - "poi_airport": { + "poi": { "source": "mapbox streets", "layer": "poi_label", - "field": "maki", - "value": "airport", - "size": { - "x": 12, - "y": 12 - }, + "icon": "maki", + "size": 12, "type": "point" }, - "poi_rail": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "rail", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_fire_station": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "fire-station", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_bus": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "bus", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_restaurant": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "restaurant", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_park": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "park", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_playground": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "playground", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_hospital": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "hospital", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_cafe": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "cafe", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - }, - "poi_beer": { - "source": "mapbox streets", - "layer": "poi_label", - "field": "maki", - "value": "beer", - "size": { - "x": 12, - "y": 12 - }, - "type": "point" - } }, "constants": { "land": "#f8f4f0", @@ -801,42 +698,12 @@ module.exports = { }, { "name": "road_label", "bucket": "road_label" - }, { - "name": "poi_label", - "bucket": "poi_label" }, { "name": "water_label", "bucket": "water_label" }, { - "name": "poi_airport", - "bucket": "poi_airport" - }, { - "name": "poi_rail", - "bucket": "poi_rail" - }, { - "name": "poi_bus", - "bucket": "poi_bus" - }, { - "name": "poi_fire_station", - "bucket": "poi_fire_station" - }, { - "name": "poi_restaurant", - "bucket": "poi_restaurant" - }, { - "name": "poi_park", - "bucket": "poi_park" - }, { - "name": "poi_hospital", - "bucket": "poi_hospital" - }, { - "name": "poi_playground", - "bucket": "poi_playground" - }, { - "name": "poi_cafe", - "bucket": "poi_cafe" - }, { - "name": "poi_beer", - "bucket": "poi_beer" + "name": "poi", + "bucket": "poi" }], "classes": [{ "name": "default", @@ -2010,45 +1877,8 @@ module.exports = { 0.75 ], }, - "poi_airport": { + "poi": { "color": "maki", - "image": "airport-12", - }, - "poi_restaurant": { - "color": "maki", - "image": "restaurant-12", - }, - "poi_bus": { - "color": "maki", - "image": "bus-12", - }, - "poi_rail": { - "color": "maki", - "image": "rail-12", - }, - "poi_fire_station": { - "color": "maki", - "image": "fire-station-12", - }, - "poi_park": { - "color": "maki", - "image": "park-12", - }, - "poi_hospital": { - "color": "maki", - "image": "hospital-12", - }, - "poi_playground": { - "color": "maki", - "image": "playground-12", - }, - "poi_cafe": { - "color": "maki", - "image": "cafe-12", - }, - "poi_beer": { - "color": "maki", - "image": "beer-12", }, "satellite": { "type": "raster", diff --git a/include/llmr/geometry/buffer.hpp b/include/llmr/geometry/buffer.hpp index 89adfb37f..0e31cf438 100644 --- a/include/llmr/geometry/buffer.hpp +++ b/include/llmr/geometry/buffer.hpp @@ -11,15 +11,13 @@ namespace llmr { template < size_t item_size, int bufferType = GL_ARRAY_BUFFER, - size_t defaultLength = 8192 + size_t defaultLength = 8192, + bool retainAfterUpload = false > class Buffer : private util::noncopyable { public: ~Buffer() { - if (array) { - free(array); - array = nullptr; - } + cleanup(); if (buffer != 0) { glDeleteBuffers(1, &buffer); buffer = 0; @@ -33,18 +31,27 @@ public: } // Transfers this buffer to the GPU and binds the buffer to the GL context. - void bind() { + void bind(bool force = false) { if (buffer == 0) { glGenBuffers(1, &buffer); - glBindBuffer(bufferType, buffer); + force = true; + } + glBindBuffer(bufferType, buffer); + if (force) { + assert("Buffer was already deleted" && array != nullptr); glBufferData(bufferType, pos, array, GL_STATIC_DRAW); - free(array); - array = nullptr; - } else { - glBindBuffer(bufferType, buffer); + if (!retainAfterUpload) { + cleanup(); + } } } + void cleanup() { + if (array) { + free(array); + array = nullptr; + } + } protected: // increase the buffer size by at least /required/ bytes. @@ -59,6 +66,17 @@ protected: return static_cast(array) + (pos - itemSize); } + // Get a pointer to the item at a given index. + inline void *getElement(size_t index) { + assert("Buffer was deleted" && array != nullptr); + + if (index * itemSize >= pos) { + throw new std::runtime_error("Can't get element after array bounds"); + } else { + return static_cast(array) + (index * itemSize); + } + } + public: static const size_t itemSize = item_size; diff --git a/include/llmr/geometry/icon_buffer.hpp b/include/llmr/geometry/icon_buffer.hpp index fc918c545..6bb0ec30c 100644 --- a/include/llmr/geometry/icon_buffer.hpp +++ b/include/llmr/geometry/icon_buffer.hpp @@ -6,12 +6,13 @@ namespace llmr { class IconVertexBuffer : public Buffer< - 4 // 2 coordinates per vertex (== 4 bytes) + 4 + // int16 x/y coordinates per vertex (== 4 bytes) + 4 // uint16 x/y coordinates of icon in sprite (== 4 bytes) > { public: typedef int16_t vertex_type; - void add(vertex_type x, vertex_type y); + void add(vertex_type x, vertex_type y, uint16_t tx, uint16_t ty); }; } diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 91566d40a..12f3da8ff 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -27,6 +27,7 @@ private: std::unique_ptr createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::unique_ptr createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args... args); private: const VectorTile vector_data; diff --git a/include/llmr/renderer/icon_bucket.hpp b/include/llmr/renderer/icon_bucket.hpp index a3338767e..ce90edce3 100644 --- a/include/llmr/renderer/icon_bucket.hpp +++ b/include/llmr/renderer/icon_bucket.hpp @@ -20,7 +20,8 @@ class IconVertexBuffer; class BucketDescription; class IconShader; class DotShader; -struct pbf; +class Sprite; +class VectorTileFeature; class IconBucket : public Bucket { public: @@ -30,7 +31,7 @@ public: virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); virtual bool hasData() const; - void addGeometry(pbf& data); + void addFeature(const VectorTileFeature &feature, const std::shared_ptr &sprite); void drawIcons(IconShader& shader); void drawIcons(DotShader& shader); diff --git a/include/llmr/shader/icon_shader.hpp b/include/llmr/shader/icon_shader.hpp index db3bfe686..6b3644f28 100644 --- a/include/llmr/shader/icon_shader.hpp +++ b/include/llmr/shader/icon_shader.hpp @@ -13,12 +13,12 @@ public: void setImage(int32_t image); void setColor(const std::array& color); - void setPosition(const std::array& pos); void setDimension(const std::array& dimension); void setSize(float size); private: int32_t a_pos = -1; + int32_t a_tex = -1; int32_t image = -1; int32_t u_image = -1; @@ -26,9 +26,6 @@ private: std::array color = {{}}; int32_t u_color = -1; - std::array pos = {{}}; - int32_t u_pos = -1; - std::array dimension = {{}}; int32_t u_dimension = -1; diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 615b5af65..54593eec7 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -73,8 +73,9 @@ public: CapType cap = CapType::None; JoinType join = JoinType::None; std::string font; - std::string text_field; - float font_size = 0.0f; + std::string field; + std::string icon; + float size = 0.0f; float miter_limit = 2.0f; float round_limit = 1.0f; TextPathType path = TextPathType::Horizontal; diff --git a/src/geometry/icon_buffer.cpp b/src/geometry/icon_buffer.cpp index df5b7434d..22a47ff09 100644 --- a/src/geometry/icon_buffer.cpp +++ b/src/geometry/icon_buffer.cpp @@ -5,8 +5,14 @@ using namespace llmr; -void IconVertexBuffer::add(vertex_type x, vertex_type y) { - vertex_type *vertices = static_cast(addElement()); +void IconVertexBuffer::add(vertex_type x, vertex_type y, uint16_t tx, uint16_t ty) { + void *data = addElement(); + + vertex_type *vertices = static_cast(data); vertices[0] = x; vertices[1] = y; + + uint16_t *texture = static_cast(data); + texture[2] = tx; + texture[3] = ty; } diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index ebbba78d3..61957e607 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -120,6 +120,15 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } } +template +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args... args) { + FilteredVectorTileLayer filtered_layer(layer, bucket_desc); + for (const pbf& feature_pbf : filtered_layer) { + if (obsolete()) return; + bucket->addFeature({ feature_pbf, layer }, args...); + } +} + std::unique_ptr TileParser::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { std::unique_ptr bucket = std::make_unique( tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, bucket_desc); @@ -137,7 +146,7 @@ std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& laye std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { std::unique_ptr bucket = std::make_unique( tile.iconVertexBuffer, bucket_desc); - addBucketFeatures(bucket, layer, bucket_desc); + addBucketFeatures(bucket, layer, bucket_desc, style.sprite); return obsolete() ? nullptr : std::move(bucket); } @@ -166,12 +175,6 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye std::unique_ptr bucket = std::make_unique( tile.textVertexBuffer, tile.triangleElementsBuffer, bucket_desc, placement); - - FilteredVectorTileLayer filtered_layer(layer, bucket_desc); - for (const pbf& feature_pbf : filtered_layer) { - if (obsolete()) return nullptr; - bucket->addFeature({ feature_pbf, layer }, faces, shaping); - } - + addBucketFeatures(bucket, layer, bucket_desc, faces, shaping); return std::move(bucket); } diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp index 6e3c65276..060e1e016 100644 --- a/src/renderer/icon_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -22,13 +23,35 @@ IconBucket::IconBucket(IconVertexBuffer& vertexBuffer, vertex_start(vertexBuffer.index()) { } -void IconBucket::addGeometry(pbf& geom) { +void IconBucket::addFeature(const VectorTileFeature &feature, const std::shared_ptr &sprite) { + // TODO: We somehow need to reparse the stylesheet, or maintain a mapping of id => sprite name + // For now, we're just not showing points if the sprite was not yet loaded at *parse time* of + // the tile. + if (!sprite || !sprite->isLoaded()) return; + + auto field_it = feature.properties.find(geometry.field); + if (field_it == feature.properties.end()) { + fprintf(stderr, "feature doesn't contain field '%s'\n", geometry.field.c_str()); + return; + } + + std::string field = toString(field_it->second); + if (geometry.size) { + field.append("-"); + field.append(std::to_string(static_cast(std::round(geometry.size)))); + } + + const SpritePosition &pos = sprite->getSpritePosition(field); + const uint16_t tx = pos.x + pos.width / 2; + const uint16_t ty = pos.y + pos.height / 2; + Geometry::command cmd; + pbf geom = feature.geometry; Geometry geometry(geom); int32_t x, y; while ((cmd = geometry.next(x, y)) != Geometry::end) { if (cmd == Geometry::move_to) { - vertexBuffer.add(x, y); + vertexBuffer.add(x, y, tx, ty); } else { fprintf(stderr, "other command than move_to in icon geometry\n"); } diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 28e9c6f66..0590aeb1d 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -24,21 +24,11 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons color[2] *= properties.opacity; color[3] *= properties.opacity; - auto &sprite = map.getStyle().sprite; - SpritePosition spritePos; - - if (properties.image.length() && sprite && sprite->isLoaded()) { - std::string sized_image = properties.image; - if (properties.size) { - sized_image.append("-"); - sized_image.append(std::to_string(static_cast(std::round(properties.size)))); - } - spritePos = sprite->getSpritePosition(sized_image); - } - const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); - if (!spritePos.width || !spritePos.height) { + const std::shared_ptr &sprite = map.getStyle().sprite; + + if (!sprite || !sprite->isLoaded()) { useProgram(dotShader->program); dotShader->setMatrix(vtxMatrix); dotShader->setColor(color); @@ -58,10 +48,6 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons iconShader->setMatrix(vtxMatrix); iconShader->setColor(color); iconShader->setImage(0); - iconShader->setPosition({{ - spritePos.x + (float)spritePos.width / 2.0f, - spritePos.y + (float)spritePos.height / 2.0f, - }}); iconShader->setDimension({{ static_cast(sprite->raster.width), @@ -70,7 +56,7 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons sprite->raster.bind(map.getState().isChanging()); - const float iconSize = util::max(spritePos.width, spritePos.height) + 2; + const float iconSize = bucket.geometry.size * map.getState().getPixelRatio(); iconShader->setSize(iconSize); #ifndef GL_ES_VERSION_2_0 glPointSize(iconSize); diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index c083da964..a94df4613 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -28,7 +28,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons } // If layerStyle.size > bucket.info.fontSize then labels may collide - float fontSize = std::fmin(properties.size, bucket.geom_desc.font_size); + float fontSize = std::fmin(properties.size, bucket.geom_desc.size); matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f); const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); @@ -47,7 +47,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons float angle = std::round((map.getState().getAngle() + rotate) / M_PI * 128); // adjust min/max zooms for variable font sies - float zoomAdjust = log(fontSize / bucket.geom_desc.font_size) / log(2); + float zoomAdjust = log(fontSize / bucket.geom_desc.size) / log(2); textShader->setAngle((int32_t)(angle + 256) % 256); textShader->setFlip(bucket.geom_desc.path == TextPathType::Curve ? 1 : 0); diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp index 052fd5a08..d9aa76d89 100644 --- a/src/renderer/text_bucket.cpp +++ b/src/renderer/text_bucket.cpp @@ -102,7 +102,7 @@ void TextBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, void TextBucket::addFeature(const VectorTileFeature &feature, const IndexedFaces &faces, const std::map &shapings) { - auto it_prop = feature.properties.find(geom_desc.text_field); + auto it_prop = feature.properties.find(geom_desc.field); if (it_prop == feature.properties.end()) { // feature does not have the correct property return; diff --git a/src/shader/dot_shader.cpp b/src/shader/dot_shader.cpp index 2f0325427..e159f0f11 100644 --- a/src/shader/dot_shader.cpp +++ b/src/shader/dot_shader.cpp @@ -32,7 +32,7 @@ DotShader::DotShader() void DotShader::bind(char *offset) { glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset); } void DotShader::setColor(const std::array& new_color) { diff --git a/src/shader/icon.fragment.glsl b/src/shader/icon.fragment.glsl index f5a424ae9..aacbb6a54 100644 --- a/src/shader/icon.fragment.glsl +++ b/src/shader/icon.fragment.glsl @@ -1,10 +1,11 @@ uniform sampler2D u_image; -uniform vec2 u_pos; uniform vec2 u_dimension; uniform vec4 u_color; uniform float u_size; +varying vec2 v_tex; + void main() { - vec2 pos = (u_pos + (gl_PointCoord - 0.5) * u_size) / u_dimension; + vec2 pos = (v_tex + (gl_PointCoord - 0.5) * u_size) / u_dimension; gl_FragColor = texture2D(u_image, pos) * u_color; } diff --git a/src/shader/icon.vertex.glsl b/src/shader/icon.vertex.glsl index 4ccc52663..51b378f3f 100644 --- a/src/shader/icon.vertex.glsl +++ b/src/shader/icon.vertex.glsl @@ -1,9 +1,13 @@ attribute vec2 a_pos; +attribute vec2 a_tex; uniform mat4 u_matrix; uniform float u_size; +varying vec2 v_tex; + void main() { gl_Position = u_matrix * vec4(a_pos, 0, 1); gl_PointSize = u_size; + v_tex = a_tex; } diff --git a/src/shader/icon_shader.cpp b/src/shader/icon_shader.cpp index 820a5118b..f991d1f39 100644 --- a/src/shader/icon_shader.cpp +++ b/src/shader/icon_shader.cpp @@ -17,25 +17,27 @@ IconShader::IconShader() } a_pos = glGetAttribLocation(program, "a_pos"); + a_tex = glGetAttribLocation(program, "a_tex"); u_matrix = glGetUniformLocation(program, "u_matrix"); u_color = glGetUniformLocation(program, "u_color"); u_size = glGetUniformLocation(program, "u_size"); - u_pos = glGetUniformLocation(program, "u_pos"); u_dimension = glGetUniformLocation(program, "u_dimension"); // fprintf(stderr, "IconShader:\n"); // fprintf(stderr, " - u_matrix: %d\n", u_matrix); // fprintf(stderr, " - u_color: %d\n", u_color); // fprintf(stderr, " - u_size: %d\n", u_size); - // fprintf(stderr, " - u_pos: %d\n", u_pos); // fprintf(stderr, " - u_dimension: %d\n", u_dimension); // fprintf(stderr, " - u_image: %d\n", u_image); } void IconShader::bind(char *offset) { glEnableVertexAttribArray(a_pos); - glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset); + + glEnableVertexAttribArray(a_tex); + glVertexAttribPointer(a_tex, 2, GL_UNSIGNED_SHORT, false, 8, offset + 4); } void IconShader::setImage(int32_t new_image) { @@ -59,13 +61,6 @@ void IconShader::setSize(float new_size) { } } -void IconShader::setPosition(const std::array& new_pos) { - if (pos != new_pos) { - glUniform2fv(u_pos, 1, new_pos.data()); - pos = new_pos; - } -} - void IconShader::setDimension(const std::array& new_dimension) { if (dimension != new_dimension) { glUniform2fv(u_dimension, 1, new_dimension.data()); diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index 45f1651dc..aebd5bfac 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -11,8 +11,8 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "#version 120\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", }, { - "#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, ((u_pos + \n ((gl_PointCoord - 0.5) * u_size)\n ) / u_dimension)) * u_color);\n}\n\n", + "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = a_tex;\n}\n\n", + "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, ((v_tex + \n ((gl_PointCoord - 0.5) * u_size)\n ) / u_dimension)) * u_color);\n}\n\n", }, { "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index d94e04f29..185e4c0a8 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -11,8 +11,8 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "precision highp float;\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n mediump vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n mediump float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", }, { - "precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform float u_size;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n}\n\n", - "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_pos;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = ((u_pos + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension);\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", + "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = a_tex;\n}\n\n", + "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = ((v_tex + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension);\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", }, { "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp index eb3b550be..0dc1a111d 100644 --- a/src/style/bucket_description.cpp +++ b/src/style/bucket_description.cpp @@ -14,6 +14,6 @@ std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket os << " - cap: " << (uint32_t)bucket.geometry.cap << std::endl; os << " - join: " << (uint32_t)bucket.geometry.join << std::endl; os << " - font: " << bucket.geometry.font << std::endl; - os << " - font_size: " << bucket.geometry.font_size << std::endl; + os << " - size: " << bucket.geometry.size << std::endl; return os; } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 057b75d09..f2c1f3093 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -83,15 +83,15 @@ BucketDescription StyleParser::parseBucket(JSVal value) { } else { throw Style::exception("font stack must be a string"); } - } else if (name == "fontSize") { + } else if (name == "fontSize" || name == "size") { if (value.IsNumber()) { - bucket.geometry.font_size = value.GetDouble(); + bucket.geometry.size = value.GetDouble(); } else { throw Style::exception("font size must be a number"); } - } else if (name == "text_field") { + } else if (name == "text_field" || name == "icon") { if (value.IsString()) { - bucket.geometry.text_field = { value.GetString(), value.GetStringLength() }; + bucket.geometry.field = { value.GetString(), value.GetStringLength() }; } else { throw Style::exception("text field must be a string"); } diff --git a/src/text/placement.cpp b/src/text/placement.cpp index 5c8b15474..e48eff5c4 100644 --- a/src/text/placement.cpp +++ b/src/text/placement.cpp @@ -278,7 +278,7 @@ void Placement::addFeature(TextBucket& bucket, const float textMinDistance = info.textMinDistance; const float rotate = info.rotate; const float fontScale = - (tileExtent / util::tileSize) / (glyphSize / info.font_size); + (tileExtent / util::tileSize) / (glyphSize / info.size); const float advance = measureText(faces, shaping); Anchors anchors; From 24bd0bb667e6c2570838cd64992ffa388e8fb941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 15 May 2014 17:46:36 +0200 Subject: [PATCH 19/24] include header --- include/llmr/geometry/buffer.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/llmr/geometry/buffer.hpp b/include/llmr/geometry/buffer.hpp index 0e31cf438..6f43774e5 100644 --- a/include/llmr/geometry/buffer.hpp +++ b/include/llmr/geometry/buffer.hpp @@ -1,11 +1,13 @@ #ifndef LLMR_GEOMETRY_BUFFER #define LLMR_GEOMETRY_BUFFER -#include -#include #include #include +#include +#include +#include + namespace llmr { template < From 13575330f7d32630f6dbf4244405c46b453152fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 19 May 2014 10:48:11 +0200 Subject: [PATCH 20/24] use sprite atlas --- common/glfw_view.cpp | 29 +++ include/llmr/geometry/sprite_atlas.hpp | 68 +++++++ include/llmr/map/map.hpp | 2 + include/llmr/map/tile_parser.hpp | 6 +- include/llmr/platform/platform.hpp | 5 +- include/llmr/renderer/icon_bucket.hpp | 4 +- include/llmr/style/style.hpp | 1 + include/llmr/util/math.hpp | 16 ++ include/llmr/util/raster.hpp | 2 + include/llmr/util/rect.hpp | 5 + src/geometry/sprite_atlas.cpp | 235 +++++++++++++++++++++++++ src/map/map.cpp | 15 ++ src/map/tile_parser.cpp | 11 +- src/map/vector_tile_data.cpp | 2 +- src/renderer/icon_bucket.cpp | 19 +- src/renderer/painter_icon.cpp | 53 ++---- src/shader/icon.fragment.glsl | 2 +- src/shader/shaders_gl.cpp | 2 +- src/shader/shaders_gles2.cpp | 2 +- src/style/sprite.cpp | 46 ++--- 20 files changed, 439 insertions(+), 86 deletions(-) create mode 100644 include/llmr/geometry/sprite_atlas.hpp create mode 100644 src/geometry/sprite_atlas.cpp diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index 7ec5d3b08..2542e6cf9 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -231,5 +231,34 @@ void show_debug_image(std::string name, const char *data, size_t width, size_t h glfwMakeContextCurrent(current_window); } + +void show_color_debug_image(std::string name, const char *data, size_t width, size_t height) { + static GLFWwindow *debug_window = nullptr; + if (!debug_window) { + debug_window = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); + if (!debug_window) { + glfwTerminate(); + fprintf(stderr, "Failed to initialize window\n"); + exit(1); + } + } + + GLFWwindow *current_window = glfwGetCurrentContext(); + + glfwSetWindowSize(debug_window, width, height); + glfwMakeContextCurrent(debug_window); + + int fb_width, fb_height; + glfwGetFramebufferSize(debug_window, &fb_width, &fb_height); + float scale = (float)fb_width / (float)width; + + glPixelZoom(scale, -scale); + glRasterPos2f(-1.0f, 1.0f); + glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data); + glfwSwapBuffers(debug_window); + + glfwMakeContextCurrent(current_window); +} + } } diff --git a/include/llmr/geometry/sprite_atlas.hpp b/include/llmr/geometry/sprite_atlas.hpp new file mode 100644 index 000000000..e6557846a --- /dev/null +++ b/include/llmr/geometry/sprite_atlas.hpp @@ -0,0 +1,68 @@ +#ifndef LLMR_GEOMETRY_SPRITE_ATLAS +#define LLMR_GEOMETRY_SPRITE_ATLAS + +#include + +#include +#include +#include +#include +#include + +namespace llmr { + +class Sprite; + +class SpriteAtlas { +public: + typedef uint16_t dimension; + +public: + // Add way to construct this from another SpriteAtlas (e.g. with another pixelRatio) + SpriteAtlas(dimension width, dimension height); + ~SpriteAtlas(); + + // Changes the pixel ratio. + bool resize(float newRatio); + + // Update uninitialized sprites in this atlas from the given sprite. + void update(const Sprite &sprite); + + // Returns the coordinates of the icon. The getter also *creates* new icons in the atlas + // if they don't exist, but they'll be default-initialized with a a black circle. + Rect getIcon(int size, const std::string &name); + + // Updates or creates an icon with a given size and name. The data must be a + // a (pixelRatio * size)^2 * 4 byte long RGBA image buffer. + Rect setIcon(int size, const std::string &name, const std::string &icon); + + // Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out + // of date. + void bind(bool linear = false); + + inline float getTextureWidth() const { return width * pixelRatio; } + inline float getTextureHeight() const { return height * pixelRatio; } + +private: + void allocate(); + +public: + const dimension width = 0; + const dimension height = 0; + +private: + std::mutex mtx; + float pixelRatio = 1.0f; + BinPack bin; + std::map>> index; + std::set> uninitialized; + char *data = nullptr; + std::atomic dirty; + uint32_t texture = 0; + uint32_t filter = 0; + static const int buffer = 1; +}; + +}; + +#endif diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 4600e1a96..87d64b073 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -92,6 +92,7 @@ public: inline const TransformState &getState() const { return state; } inline const Style &getStyle() const { return style; } inline GlyphAtlas &getGlyphAtlas() { return glyphAtlas; } + inline SpriteAtlas &getSpriteAtlas() { return spriteAtlas; } inline uv_loop_t *getLoop() { return loop; } inline time getAnimationTime() const { return animationTime; } inline Texturepool &getTexturepool() { return texturepool; } @@ -143,6 +144,7 @@ private: Texturepool texturepool; Style style; GlyphAtlas glyphAtlas; + SpriteAtlas spriteAtlas; Painter painter; std::map> sources; diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 12f3da8ff..86545e4f7 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -9,13 +9,14 @@ namespace llmr { class Style; class GlyphAtlas; +class SpriteAtlas; class LayerDescription; class Bucket; class TileParser { public: - TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas); + TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, SpriteAtlas &spriteAtlas); private: bool obsolete() const; @@ -27,13 +28,14 @@ private: std::unique_ptr createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::unique_ptr createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc); - template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args... args); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args&& ...args); private: const VectorTile vector_data; VectorTileData& tile; const Style& style; GlyphAtlas& glyphAtlas; + SpriteAtlas &spriteAtlas; Faces faces; Placement placement; }; diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index 4f7b4ed69..dc8f7b5fa 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -32,8 +32,11 @@ std::shared_ptr request_http(const std::string &url, // Cancels an HTTP request. void cancel_request_http(const std::shared_ptr &req); -// Shows an RGBA image with the specified dimensions in a named window. +// Shows an alpha image with the specified dimensions in a named window. void show_debug_image(std::string name, const char *data, size_t width, size_t height); + +// Shows an alpha image with the specified dimensions in a named window. +void show_color_debug_image(std::string name, const char *data, size_t width, size_t height); } } diff --git a/include/llmr/renderer/icon_bucket.hpp b/include/llmr/renderer/icon_bucket.hpp index ce90edce3..0878622ec 100644 --- a/include/llmr/renderer/icon_bucket.hpp +++ b/include/llmr/renderer/icon_bucket.hpp @@ -20,7 +20,7 @@ class IconVertexBuffer; class BucketDescription; class IconShader; class DotShader; -class Sprite; +class SpriteAtlas; class VectorTileFeature; class IconBucket : public Bucket { @@ -31,7 +31,7 @@ public: virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); virtual bool hasData() const; - void addFeature(const VectorTileFeature &feature, const std::shared_ptr &sprite); + void addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas); void drawIcons(IconShader& shader); void drawIcons(DotShader& shader); diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 8fcb99732..d9c8c22bd 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/include/llmr/util/math.hpp b/include/llmr/util/math.hpp index 531a13a1a..ab8e392c4 100644 --- a/include/llmr/util/math.hpp +++ b/include/llmr/util/math.hpp @@ -87,12 +87,28 @@ inline T dist(const S1& a, const S2& b) { return c; } +template +inline T length(T a, T b) { + return std::sqrt(a * a + b * b); +} + // Take the magnitude of vector a. template inline T mag(const S& a) { return std::sqrt(a.x * a.x + a.y * a.y); } +template +T clamp(T value, T min, T max) { + return value < min ? min : (value > max ? max : value); +} + +template +T smoothstep(T edge0, T edge1, T x) { + T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1)); + return t * t * (T(3) - T(2) * t); +} + } } diff --git a/include/llmr/util/raster.hpp b/include/llmr/util/raster.hpp index ccdffeef3..0ad29dc7a 100644 --- a/include/llmr/util/raster.hpp +++ b/include/llmr/util/raster.hpp @@ -32,6 +32,8 @@ public: bool needsTransition() const; void updateTransitions(time now); + inline const char *getData() const { return img; } + public: // loaded image dimensions uint32_t width = 0, height = 0; diff --git a/include/llmr/util/rect.hpp b/include/llmr/util/rect.hpp index 56bab2c9c..2e142c301 100644 --- a/include/llmr/util/rect.hpp +++ b/include/llmr/util/rect.hpp @@ -9,6 +9,11 @@ struct Rect { T x = 0, y = 0; T w = 0, h = 0; + template + Rect operator *(Number value) const { + return Rect(x * value, y * value, w * value, h * value); + } + operator bool() const { return w == 0 || h == 0; } }; } diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp new file mode 100644 index 000000000..80212c1df --- /dev/null +++ b/src/geometry/sprite_atlas.cpp @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +using namespace llmr; + +SpriteAtlas::SpriteAtlas(dimension width, dimension height) + : width(width), + height(height), + bin(width, height), + dirty(true) { +} + +bool SpriteAtlas::resize(const float newRatio) { + if (pixelRatio == newRatio) return false; + + std::lock_guard lock(mtx); + + const float oldRatio = pixelRatio; + pixelRatio = newRatio; + + if (data) { + char *old_data = data; + + data = nullptr; + allocate(); + + dimension w = static_cast(width * newRatio); + dimension h = static_cast(height * newRatio); + float s = std::pow(oldRatio / newRatio, 2); + + // Basic image scaling. TODO: Replace this with better image scaling. + uint32_t *img_new = reinterpret_cast(data); + uint32_t *img_old = reinterpret_cast(old_data); + for (size_t i = 0, length = w * h; i < length; i++) { + img_new[i] = img_old[static_cast(s * i)]; + } + + free(old_data); + dirty = true; + } + + return dirty; +} + +Rect SpriteAtlas::getIcon(const int size, const std::string &name) { + std::lock_guard lock(mtx); + + std::map> &size_index = index[size]; + + auto rect_it = size_index.find(name); + if (rect_it != size_index.end()) { + return rect_it->second; + } + + // We have to allocate a new area in the bin, and store an empty image in it. + // Add a 1px border around every image. + const dimension pack_size = size + 2 * buffer; + + Rect rect = bin.allocate(pack_size, pack_size); + if (rect.w == 0) { + fprintf(stderr, "sprite atlas bitmap overflow"); + return rect; + } + + size_index.emplace(name, rect); + + allocate(); + + + // Draw an antialiased circle. + const int img_size = size * pixelRatio; + const int img_offset_x = (rect.x + buffer) * pixelRatio; + const int img_offset_y = (rect.y + buffer) * pixelRatio; + + uint32_t *sprite_img = reinterpret_cast(data); + const float blur = 1.5f / size; + + const uint8_t r = 0x7F; + const uint8_t g = 0x7F; + const uint8_t b = 0x7F; + + const int sprite_stride = width * pixelRatio; + for (int y = 0; y < img_size; y++) { + const int img_y = (img_offset_y + y) * sprite_stride + img_offset_x; + for (int x = 0; x < img_size; x++) { + + const float dist = util::length(float(x) / img_size - 0.5f, float(y) / img_size - 0.5f); + const float t = util::smoothstep(0.5f, 0.5f - blur, dist); + const uint8_t alpha = t * 255; + + uint32_t color = (uint32_t(r * t) << 0) | + (uint32_t(g * t) << 8) | + (uint32_t(b * t) << 16) | + (uint32_t(alpha) << 24); + sprite_img[img_y + x] = color; + } + } + + uninitialized.emplace(size, name); + + dirty = true; + + return rect; +} + +void SpriteAtlas::allocate() { + if (!data) { + dimension w = static_cast(width * pixelRatio); + dimension h = static_cast(height * pixelRatio); + data = (char *)calloc(w * h, sizeof(uint32_t)); + } +} + +Rect SpriteAtlas::setIcon(const int size, const std::string &name, const std::string &icon) { + Rect rect = getIcon(size, name); + + // Copy the bitmap + const int img_size = size * pixelRatio; + const int img_offset_x = (rect.x + buffer) * pixelRatio; + const int img_offset_y = (rect.y + buffer) * pixelRatio; + + if (std::pow(size * pixelRatio, 2) * 4 /* rgba */ != icon.size()) { fprintf(stderr, "mismatched icon buffer size!"); } + + const uint32_t *icon_img = reinterpret_cast(icon.data()); + uint32_t *sprite_img = reinterpret_cast(data); + + const int sprite_stride = width * pixelRatio; + const int icon_stride = size * pixelRatio; + for (size_t y = 0; y < img_size; y++) { + const int img_y = (img_offset_y + y) * sprite_stride + img_offset_x; + const int icon_y = y * icon_stride; + for (size_t x = 0; x < img_size; x++) { + sprite_img[img_y + x] = icon_img[icon_y + x]; + } + } + + dirty = true; + + return rect; +} + +void SpriteAtlas::update(const Sprite &sprite) { + if (!sprite.isLoaded()) return; + + SpriteAtlas &atlas = *this; + std::erase_if(uninitialized, [&sprite, &atlas](const std::pair &pair) { + const int &size = pair.first; + const std::string &name = pair.second; + const SpritePosition &src = sprite.getSpritePosition(name + "-" + std::to_string(size)); + if (src.width == size && src.height == size && src.pixelRatio == atlas.pixelRatio) { + const uint32_t *src_img = reinterpret_cast(sprite.raster.getData()); + + uint32_t *dst_img = reinterpret_cast(atlas.data); + Rect dst = atlas.getIcon(size, name); + dst.x = (dst.x + buffer) * atlas.pixelRatio; + dst.y = (dst.y + buffer) * atlas.pixelRatio; + dst.w = (dst.w - 2 * buffer) * atlas.pixelRatio; + dst.h = (dst.h - 2 * buffer) * atlas.pixelRatio; + + + const int src_image_stride = sprite.raster.width; + const int dst_image_stride = atlas.width * atlas.pixelRatio; + const int src_stride = src.width * src.pixelRatio; + + for (int y = 0; y < dst.h; y++) { + const int src_pos = (src.y * src.pixelRatio + y) * src_image_stride + src.x * src.pixelRatio; + const int dst_pos = (dst.y + y) * dst_image_stride + dst.x; + + // TODO: this is crashing + // memcpy(dst_img + dst_pos, src_img + src_pos, src_stride * sizeof(uint32_t)); + } + + + return true; + } else { + return false; + } + }); +} + +void SpriteAtlas::bind(bool linear) { + if (!texture) { + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glBindTexture(GL_TEXTURE_2D, texture); + } + + GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST; + if (filter_val != filter) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val); + filter = filter_val; + } + + if (dirty) { + std::lock_guard lock(mtx); + allocate(); + glTexImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + GL_RGBA, // GLint internalformat + width * pixelRatio, // GLsizei width + height * pixelRatio, // GLsizei height + 0, // GLint border + GL_RGBA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + data // const GLvoid * data + ); + + platform::show_color_debug_image("Sprite Atlas", data, width * pixelRatio, height * pixelRatio); + + dirty = false; + } +}; + +SpriteAtlas::~SpriteAtlas() { + std::lock_guard lock(mtx); + if (data) { + free(data); + data = nullptr; + } +} diff --git a/src/map/map.cpp b/src/map/map.cpp index 79a26305e..4a16ac417 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -20,6 +20,7 @@ Map::Map(View& view) texturepool(), style(), glyphAtlas(1024, 1024), + spriteAtlas(512, 512), painter(*this), loop(uv_loop_new()) { @@ -175,7 +176,16 @@ void Map::resize(uint16_t width, uint16_t height, float ratio) { } void Map::resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width, uint16_t fb_height) { + bool changed = false; + if (transform.resize(width, height, ratio, fb_width, fb_height)) { + changed = true; + } + if (spriteAtlas.resize(ratio)) { + changed = true; + } + + if (changed) { update(); } } @@ -393,6 +403,11 @@ void Map::prepare() { style.sprite->load(kSpriteURL); } + // Allow the sprite atlas to potentially pull new sprite images if needed. + if (style.sprite && style.sprite->isLoaded()) { + spriteAtlas.update(*style.sprite); + } + updateTiles(); updateClippingIDs(); diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index 61957e607..67a32d4cb 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -14,11 +14,12 @@ using namespace llmr; -TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas) +TileParser::TileParser(const std::string& data, VectorTileData& tile, const Style& style, GlyphAtlas& glyphAtlas, SpriteAtlas &spriteAtlas) : vector_data(pbf((const uint8_t *)data.data(), data.size())), tile(tile), style(style), glyphAtlas(glyphAtlas), + spriteAtlas(spriteAtlas), placement(tile.id.z) { parseGlyphs(); parseStyleLayers(style.layers); @@ -120,12 +121,12 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } } -template -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args... args) { +template +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args&& ...args) { FilteredVectorTileLayer filtered_layer(layer, bucket_desc); for (const pbf& feature_pbf : filtered_layer) { if (obsolete()) return; - bucket->addFeature({ feature_pbf, layer }, args...); + bucket->addFeature({ feature_pbf, layer }, std::forward(args)...); } } @@ -146,7 +147,7 @@ std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& laye std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { std::unique_ptr bucket = std::make_unique( tile.iconVertexBuffer, bucket_desc); - addBucketFeatures(bucket, layer, bucket_desc, style.sprite); + addBucketFeatures(bucket, layer, bucket_desc, spriteAtlas); return obsolete() ? nullptr : std::move(bucket); } diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp index 84fc4ffc4..337e2fcc3 100644 --- a/src/map/vector_tile_data.cpp +++ b/src/map/vector_tile_data.cpp @@ -22,7 +22,7 @@ void VectorTileData::parse() { // Parsing creates state that is encapsulated in TileParser. While parsing, // the TileParser object writes results into this objects. All other state // is going to be discarded afterwards. - TileParser parser(data, *this, map.getStyle(), map.getGlyphAtlas()); + TileParser parser(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getSpriteAtlas()); } catch (const std::exception& ex) { fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); cancel(); diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp index 060e1e016..9d1505c03 100644 --- a/src/renderer/icon_bucket.cpp +++ b/src/renderer/icon_bucket.cpp @@ -23,27 +23,18 @@ IconBucket::IconBucket(IconVertexBuffer& vertexBuffer, vertex_start(vertexBuffer.index()) { } -void IconBucket::addFeature(const VectorTileFeature &feature, const std::shared_ptr &sprite) { - // TODO: We somehow need to reparse the stylesheet, or maintain a mapping of id => sprite name - // For now, we're just not showing points if the sprite was not yet loaded at *parse time* of - // the tile. - if (!sprite || !sprite->isLoaded()) return; - +void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas) { auto field_it = feature.properties.find(geometry.field); if (field_it == feature.properties.end()) { - fprintf(stderr, "feature doesn't contain field '%s'\n", geometry.field.c_str()); + // fprintf(stderr, "feature doesn't contain field '%s'\n", geometry.field.c_str()); return; } std::string field = toString(field_it->second); - if (geometry.size) { - field.append("-"); - field.append(std::to_string(static_cast(std::round(geometry.size)))); - } - const SpritePosition &pos = sprite->getSpritePosition(field); - const uint16_t tx = pos.x + pos.width / 2; - const uint16_t ty = pos.y + pos.height / 2; + const Rect rect = sprite_atlas.getIcon(geometry.size, field); + const uint16_t tx = rect.x + rect.w / 2; + const uint16_t ty = rect.y + rect.h / 2; Geometry::command cmd; pbf geom = feature.geometry; diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 0590aeb1d..53d775a17 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -26,44 +26,27 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor); - const std::shared_ptr &sprite = map.getStyle().sprite; + SpriteAtlas &spriteAtlas = map.getSpriteAtlas(); - if (!sprite || !sprite->isLoaded()) { - useProgram(dotShader->program); - dotShader->setMatrix(vtxMatrix); - dotShader->setColor(color); + useProgram(iconShader->program); + iconShader->setMatrix(vtxMatrix); + iconShader->setColor(color); + iconShader->setImage(0); - const float iconSize = (properties.radius ? properties.radius * 2 : 8) * map.getState().getPixelRatio(); - dotShader->setSize(iconSize); + iconShader->setDimension({{ + spriteAtlas.getTextureWidth(), + spriteAtlas.getTextureHeight(), + }}); + + spriteAtlas.bind(map.getState().isChanging()); + + const float iconSize = bucket.geometry.size * map.getState().getPixelRatio(); + iconShader->setSize(iconSize); #ifndef GL_ES_VERSION_2_0 - glPointSize(iconSize); - glEnable(GL_POINT_SPRITE); -#endif - dotShader->setBlur((properties.blur ? properties.blur : 1.5) / iconSize); - - glDepthRange(strata, 1.0f); - bucket.drawIcons(*dotShader); - } else { - useProgram(iconShader->program); - iconShader->setMatrix(vtxMatrix); - iconShader->setColor(color); - iconShader->setImage(0); - - iconShader->setDimension({{ - static_cast(sprite->raster.width), - static_cast(sprite->raster.height) - }}); - - sprite->raster.bind(map.getState().isChanging()); - - const float iconSize = bucket.geometry.size * map.getState().getPixelRatio(); - iconShader->setSize(iconSize); -#ifndef GL_ES_VERSION_2_0 - glPointSize(iconSize); - glEnable(GL_POINT_SPRITE); + glPointSize(iconSize); + glEnable(GL_POINT_SPRITE); #endif - glDepthRange(strata, 1.0f); - bucket.drawIcons(*iconShader); - } + glDepthRange(strata, 1.0f); + bucket.drawIcons(*iconShader); } diff --git a/src/shader/icon.fragment.glsl b/src/shader/icon.fragment.glsl index aacbb6a54..a3191b3a8 100644 --- a/src/shader/icon.fragment.glsl +++ b/src/shader/icon.fragment.glsl @@ -7,5 +7,5 @@ varying vec2 v_tex; void main() { vec2 pos = (v_tex + (gl_PointCoord - 0.5) * u_size) / u_dimension; - gl_FragColor = texture2D(u_image, pos) * u_color; + gl_FragColor = texture2D(u_image, pos); } diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index aebd5bfac..8473296f2 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -12,7 +12,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { }, { "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = a_tex;\n}\n\n", - "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n gl_FragColor = (texture2D (u_image, ((v_tex + \n ((gl_PointCoord - 0.5) * u_size)\n ) / u_dimension)) * u_color);\n}\n\n", + "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n gl_FragColor = texture2D (u_image, ((v_tex + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension));\n}\n\n", }, { "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index 185e4c0a8..db78f4657 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -12,7 +12,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { }, { "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = a_tex;\n}\n\n", - "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = ((v_tex + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension);\n lowp vec4 tmpvar_2;\n tmpvar_2 = (texture2D (u_image, tmpvar_1) * u_color);\n gl_FragColor = tmpvar_2;\n}\n\n", + "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = ((v_tex + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension);\n lowp vec4 tmpvar_2;\n tmpvar_2 = texture2D (u_image, tmpvar_1);\n gl_FragColor = tmpvar_2;\n}\n\n", }, { "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nvarying vec2 v_normal;\nvarying float v_linesofar;\nvoid main ()\n{\n vec2 normal_1;\n vec2 tmpvar_2;\n tmpvar_2 = (vec2(mod (a_pos, 2.0)));\n normal_1.x = tmpvar_2.x;\n normal_1.y = sign((tmpvar_2.y - 0.5));\n v_normal = normal_1;\n vec4 tmpvar_3;\n tmpvar_3.zw = vec2(0.0, 0.0);\n tmpvar_3.xy = ((u_linewidth.x * a_extrude) * 0.015873);\n vec4 tmpvar_4;\n tmpvar_4.zw = vec2(0.0, 1.0);\n tmpvar_4.xy = floor((a_pos * 0.5));\n gl_Position = ((u_matrix * tmpvar_4) + (u_exmatrix * tmpvar_3));\n v_linesofar = (a_linesofar * u_ratio);\n}\n\n", diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index 93dd6bd24..fb3a959f9 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -31,35 +31,35 @@ Sprite::Sprite(Map &map, float pixelRatio) } void Sprite::load(const std::string& base_url) { - std::shared_ptr sprite = shared_from_this(); + std::shared_ptr sprite = shared_from_this(); - std::string suffix = (pixelRatio > 1 ? "@2x" : ""); + std::string suffix = (pixelRatio > 1 ? "@2x" : ""); - platform::request_http(base_url + suffix + ".json", [sprite](platform::Response *res) { - if (res->code == 200) { - sprite->body.swap(res->body); - sprite->asyncParseJSON(); - } else { - fprintf(stderr, "failed to load sprite\n"); - } - }, map.getLoop()); + platform::request_http(base_url + suffix + ".json", [sprite](platform::Response *res) { + if (res->code == 200) { + sprite->body.swap(res->body); + sprite->asyncParseJSON(); + } else { + fprintf(stderr, "failed to load sprite\n"); + } + }, map.getLoop()); - platform::request_http(base_url + suffix + ".png", [sprite](platform::Response *res) { - if (res->code == 200) { - sprite->image.swap(res->body); - sprite->asyncParseImage(); - } else { - fprintf(stderr, "failed to load sprite image\n"); - } - }, map.getLoop()); + platform::request_http(base_url + suffix + ".png", [sprite](platform::Response *res) { + if (res->code == 200) { + sprite->image.swap(res->body); + sprite->asyncParseImage(); + } else { + fprintf(stderr, "failed to load sprite image\n"); + } + }, map.getLoop()); } void Sprite::complete(std::shared_ptr &sprite) { - if (sprite->raster.isLoaded() && sprite->pos.size()) { - sprite->loaded = true; - sprite->map.update(); - fprintf(stderr, "sprite loaded\n"); - } + if (sprite->raster.isLoaded() && sprite->pos.size()) { + sprite->loaded = true; + sprite->map.update(); + fprintf(stderr, "sprite loaded\n"); + } } bool Sprite::isLoaded() const { From 898c6d6714bcbd1a8600deca1437a59f3c33f10e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 19 May 2014 11:13:22 +0200 Subject: [PATCH 21/24] fix for retina screens --- common/glfw_view.cpp | 11 ++++++----- include/llmr/platform/platform.hpp | 2 +- include/llmr/shader/icon_shader.hpp | 4 ++++ src/geometry/sprite_atlas.cpp | 4 ++-- src/renderer/painter_icon.cpp | 2 +- src/shader/icon.vertex.glsl | 3 ++- src/shader/icon_shader.cpp | 9 +++++++++ src/shader/shaders_gl.cpp | 2 +- src/shader/shaders_gles2.cpp | 2 +- 9 files changed, 27 insertions(+), 12 deletions(-) diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index 2542e6cf9..3ef7bc36a 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -232,10 +232,10 @@ void show_debug_image(std::string name, const char *data, size_t width, size_t h } -void show_color_debug_image(std::string name, const char *data, size_t width, size_t height) { +void show_color_debug_image(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height) { static GLFWwindow *debug_window = nullptr; if (!debug_window) { - debug_window = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); + debug_window = glfwCreateWindow(logical_width, logical_height, name.c_str(), nullptr, nullptr); if (!debug_window) { glfwTerminate(); fprintf(stderr, "Failed to initialize window\n"); @@ -245,14 +245,15 @@ void show_color_debug_image(std::string name, const char *data, size_t width, si GLFWwindow *current_window = glfwGetCurrentContext(); - glfwSetWindowSize(debug_window, width, height); + glfwSetWindowSize(debug_window, logical_width, logical_height); glfwMakeContextCurrent(debug_window); int fb_width, fb_height; glfwGetFramebufferSize(debug_window, &fb_width, &fb_height); - float scale = (float)fb_width / (float)width; + float x_scale = (float)fb_width / (float)width; + float y_scale = (float)fb_height / (float)height; - glPixelZoom(scale, -scale); + glPixelZoom(x_scale, -y_scale); glRasterPos2f(-1.0f, 1.0f); glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data); glfwSwapBuffers(debug_window); diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index dc8f7b5fa..62fa1badc 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -36,7 +36,7 @@ void cancel_request_http(const std::shared_ptr &req); void show_debug_image(std::string name, const char *data, size_t width, size_t height); // Shows an alpha image with the specified dimensions in a named window. -void show_color_debug_image(std::string name, const char *data, size_t width, size_t height); +void show_color_debug_image(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height); } } diff --git a/include/llmr/shader/icon_shader.hpp b/include/llmr/shader/icon_shader.hpp index 6b3644f28..daf37b374 100644 --- a/include/llmr/shader/icon_shader.hpp +++ b/include/llmr/shader/icon_shader.hpp @@ -15,6 +15,7 @@ public: void setColor(const std::array& color); void setDimension(const std::array& dimension); void setSize(float size); + void setRatio(float ratio); private: int32_t a_pos = -1; @@ -31,6 +32,9 @@ private: float size = 0; int32_t u_size = -1; + + float ratio = 0; + int32_t u_ratio = -1; }; } diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 80212c1df..4c6f51878 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -83,7 +83,7 @@ Rect SpriteAtlas::getIcon(const int size, const std::str const int img_offset_y = (rect.y + buffer) * pixelRatio; uint32_t *sprite_img = reinterpret_cast(data); - const float blur = 1.5f / size; + const float blur = 1.0f / size / pixelRatio; const uint8_t r = 0x7F; const uint8_t g = 0x7F; @@ -220,7 +220,7 @@ void SpriteAtlas::bind(bool linear) { data // const GLvoid * data ); - platform::show_color_debug_image("Sprite Atlas", data, width * pixelRatio, height * pixelRatio); + platform::show_color_debug_image("Sprite Atlas", data, width, height, width * pixelRatio, height * pixelRatio); dirty = false; } diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp index 53d775a17..b5f4964e6 100644 --- a/src/renderer/painter_icon.cpp +++ b/src/renderer/painter_icon.cpp @@ -32,7 +32,7 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons iconShader->setMatrix(vtxMatrix); iconShader->setColor(color); iconShader->setImage(0); - + iconShader->setRatio(map.getState().getPixelRatio()); iconShader->setDimension({{ spriteAtlas.getTextureWidth(), spriteAtlas.getTextureHeight(), diff --git a/src/shader/icon.vertex.glsl b/src/shader/icon.vertex.glsl index 51b378f3f..d0ffe4b33 100644 --- a/src/shader/icon.vertex.glsl +++ b/src/shader/icon.vertex.glsl @@ -3,11 +3,12 @@ attribute vec2 a_tex; uniform mat4 u_matrix; uniform float u_size; +uniform float u_ratio; varying vec2 v_tex; void main() { gl_Position = u_matrix * vec4(a_pos, 0, 1); gl_PointSize = u_size; - v_tex = a_tex; + v_tex = a_tex * u_ratio; } diff --git a/src/shader/icon_shader.cpp b/src/shader/icon_shader.cpp index f991d1f39..c656eb333 100644 --- a/src/shader/icon_shader.cpp +++ b/src/shader/icon_shader.cpp @@ -22,12 +22,14 @@ IconShader::IconShader() u_matrix = glGetUniformLocation(program, "u_matrix"); u_color = glGetUniformLocation(program, "u_color"); u_size = glGetUniformLocation(program, "u_size"); + u_ratio = glGetUniformLocation(program, "u_ratio"); u_dimension = glGetUniformLocation(program, "u_dimension"); // fprintf(stderr, "IconShader:\n"); // fprintf(stderr, " - u_matrix: %d\n", u_matrix); // fprintf(stderr, " - u_color: %d\n", u_color); // fprintf(stderr, " - u_size: %d\n", u_size); + // fprintf(stderr, " - u_ratio: %d\n", u_ratio); // fprintf(stderr, " - u_dimension: %d\n", u_dimension); // fprintf(stderr, " - u_image: %d\n", u_image); } @@ -61,6 +63,13 @@ void IconShader::setSize(float new_size) { } } +void IconShader::setRatio(float new_ratio) { + if (ratio != new_ratio) { + glUniform1f(u_ratio, new_ratio); + ratio = new_ratio; + } +} + void IconShader::setDimension(const std::array& new_dimension) { if (dimension != new_dimension) { glUniform2fv(u_dimension, 1, new_dimension.data()); diff --git a/src/shader/shaders_gl.cpp b/src/shader/shaders_gl.cpp index 8473296f2..29cbc0ead 100644 --- a/src/shader/shaders_gl.cpp +++ b/src/shader/shaders_gl.cpp @@ -11,7 +11,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "#version 120\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", }, { - "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = a_tex;\n}\n\n", + "#version 120\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nuniform float u_ratio;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = (a_tex * u_ratio);\n}\n\n", "#version 120\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n gl_FragColor = texture2D (u_image, ((v_tex + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension));\n}\n\n", }, { diff --git a/src/shader/shaders_gles2.cpp b/src/shader/shaders_gles2.cpp index db78f4657..f19edf540 100644 --- a/src/shader/shaders_gles2.cpp +++ b/src/shader/shaders_gles2.cpp @@ -11,7 +11,7 @@ const shader_source llmr::shaders[SHADER_COUNT] = { "precision highp float;\nuniform vec4 u_color;\nuniform float u_blur;\nvoid main ()\n{\n mediump vec2 x_1;\n x_1 = (gl_PointCoord - 0.5);\n mediump float tmpvar_2;\n tmpvar_2 = clamp (((\n sqrt(dot (x_1, x_1))\n - 0.5) / (\n (0.5 - u_blur)\n - 0.5)), 0.0, 1.0);\n gl_FragColor = (u_color * (tmpvar_2 * (tmpvar_2 * \n (3.0 - (2.0 * tmpvar_2))\n )));\n}\n\n", }, { - "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = a_tex;\n}\n\n", + "precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_tex;\nuniform mat4 u_matrix;\nuniform float u_size;\nuniform float u_ratio;\nvarying vec2 v_tex;\nvoid main ()\n{\n vec4 tmpvar_1;\n tmpvar_1.zw = vec2(0.0, 1.0);\n tmpvar_1.xy = a_pos;\n gl_Position = (u_matrix * tmpvar_1);\n gl_PointSize = u_size;\n v_tex = (a_tex * u_ratio);\n}\n\n", "precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform float u_size;\nvarying vec2 v_tex;\nvoid main ()\n{\n mediump vec2 tmpvar_1;\n tmpvar_1 = ((v_tex + (\n (gl_PointCoord - 0.5)\n * u_size)) / u_dimension);\n lowp vec4 tmpvar_2;\n tmpvar_2 = texture2D (u_image, tmpvar_1);\n gl_FragColor = tmpvar_2;\n}\n\n", }, { From f848868c16ff4b55e0f983e25853589a50d94824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 19 May 2014 14:18:29 +0200 Subject: [PATCH 22/24] fix texture binding --- include/llmr/geometry/sprite_atlas.hpp | 20 ++- include/llmr/style/sprite.hpp | 14 +- include/llmr/util/image.hpp | 20 +++ include/llmr/util/raster.hpp | 9 +- src/geometry/sprite_atlas.cpp | 216 ++++++++++++++----------- src/renderer/painter_fill.cpp | 24 ++- src/style/sprite.cpp | 40 +---- src/util/image.cpp | 126 +++++++++++++++ src/util/raster.cpp | 131 +-------------- 9 files changed, 310 insertions(+), 290 deletions(-) diff --git a/include/llmr/geometry/sprite_atlas.hpp b/include/llmr/geometry/sprite_atlas.hpp index e6557846a..220edc701 100644 --- a/include/llmr/geometry/sprite_atlas.hpp +++ b/include/llmr/geometry/sprite_atlas.hpp @@ -12,6 +12,7 @@ namespace llmr { class Sprite; +class SpritePosition; class SpriteAtlas { public: @@ -28,23 +29,28 @@ public: // Update uninitialized sprites in this atlas from the given sprite. void update(const Sprite &sprite); - // Returns the coordinates of the icon. The getter also *creates* new icons in the atlas - // if they don't exist, but they'll be default-initialized with a a black circle. + // Returns the coordinates of a square icon. The getter also *creates* new square icons in the + // atlas if they don't exist, but they'll be default-initialized with a a black circle. Rect getIcon(int size, const std::string &name); - // Updates or creates an icon with a given size and name. The data must be a - // a (pixelRatio * size)^2 * 4 byte long RGBA image buffer. - Rect setIcon(int size, const std::string &name, const std::string &icon); + // Returns the coordinates of an image that is sourced from the sprite image. + // This getter does not create images, as the dimension of the texture us unknown if the + // sprite is not yet loaded. Instead, it returns a 0/0/0/0 rect. + Rect getImage(const std::string &name, const Sprite &sprite); // Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out // of date. void bind(bool linear = false); + inline float getWidth() const { return width; } + inline float getHeight() const { return height; } inline float getTextureWidth() const { return width * pixelRatio; } inline float getTextureHeight() const { return height * pixelRatio; } private: void allocate(); + Rect allocateImage(size_t width, size_t height); + void copy(const Rect &dst, const SpritePosition &src, const Sprite &sprite); public: const dimension width = 0; @@ -54,8 +60,8 @@ private: std::mutex mtx; float pixelRatio = 1.0f; BinPack bin; - std::map>> index; - std::set> uninitialized; + std::map> images; + std::set uninitialized; char *data = nullptr; std::atomic dirty; uint32_t texture = 0; diff --git a/include/llmr/style/sprite.hpp b/include/llmr/style/sprite.hpp index 58fd2b1ef..60a61c033 100644 --- a/include/llmr/style/sprite.hpp +++ b/include/llmr/style/sprite.hpp @@ -24,31 +24,19 @@ public: uint8_t pixelRatio = 1; }; -class ImagePosition { -public: - explicit ImagePosition() {} - explicit ImagePosition(const vec2& size, vec2 tl, vec2 br); - - vec2 size = { 0, 0 }; - vec2 tl = { 0, 0 }; - vec2 br = { 0, 0 }; -}; - - class Sprite : public std::enable_shared_from_this { public: Sprite(Map &map, float pixelRatio = 1); void load(const std::string& base_url); - ImagePosition getPosition(const std::string& name, bool repeating = false) const; const SpritePosition &getSpritePosition(const std::string& name) const; bool isLoaded() const; public: const float pixelRatio; - Raster raster; + std::unique_ptr raster; private: void asyncParseJSON(); diff --git a/include/llmr/util/image.hpp b/include/llmr/util/image.hpp index abc021e03..d38567041 100644 --- a/include/llmr/util/image.hpp +++ b/include/llmr/util/image.hpp @@ -8,6 +8,26 @@ namespace util { std::string compress_png(int width, int height, void *rgba, bool flip = false); + +class Image { +public: + Image(const std::string &img); + ~Image(); + + inline const char *getData() const { return img; } + inline uint32_t getWidth() const { return width; } + inline uint32_t getHeight() const { return height; } + +private: + // loaded image dimensions + uint32_t width = 0, height = 0; + + // the raw image data + char *img = nullptr; + +}; + + } } diff --git a/include/llmr/util/raster.hpp b/include/llmr/util/raster.hpp index 0ad29dc7a..b6d32eac8 100644 --- a/include/llmr/util/raster.hpp +++ b/include/llmr/util/raster.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -32,8 +33,6 @@ public: bool needsTransition() const; void updateTransitions(time now); - inline const char *getData() const { return img; } - public: // loaded image dimensions uint32_t width = 0, height = 0; @@ -47,10 +46,6 @@ public: // texture opacity double opacity = 0; -private: - // load raw pixels - void loadImage(const std::string& data); - private: mutable std::mutex mtx; @@ -64,7 +59,7 @@ private: uint32_t filter = 0; // the raw pixels - char *img = nullptr; + std::unique_ptr img; // fade in transition std::shared_ptr fade_transition = nullptr; diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 4c6f51878..4f05df620 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -52,49 +52,26 @@ bool SpriteAtlas::resize(const float newRatio) { return dirty; } -Rect SpriteAtlas::getIcon(const int size, const std::string &name) { - std::lock_guard lock(mtx); - - std::map> &size_index = index[size]; - - auto rect_it = size_index.find(name); - if (rect_it != size_index.end()) { - return rect_it->second; +void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, const int src_y, + uint32_t *dst, const int dst_stride, const int dst_x, const int dst_y, + const int width, const int height) { + const int stride = width * sizeof(uint32_t); + src += src_y * src_stride + src_x; + dst += dst_y * dst_stride + dst_x; + for (int y = 0; y < height; y++, src += src_stride, dst += dst_stride) { + memcpy(dst, src, stride); } +} - // We have to allocate a new area in the bin, and store an empty image in it. - // Add a 1px border around every image. - const dimension pack_size = size + 2 * buffer; - - Rect rect = bin.allocate(pack_size, pack_size); - if (rect.w == 0) { - fprintf(stderr, "sprite atlas bitmap overflow"); - return rect; - } - - size_index.emplace(name, rect); - - allocate(); - - - // Draw an antialiased circle. - const int img_size = size * pixelRatio; - const int img_offset_x = (rect.x + buffer) * pixelRatio; - const int img_offset_y = (rect.y + buffer) * pixelRatio; - - uint32_t *sprite_img = reinterpret_cast(data); - const float blur = 1.0f / size / pixelRatio; - - const uint8_t r = 0x7F; - const uint8_t g = 0x7F; - const uint8_t b = 0x7F; - - const int sprite_stride = width * pixelRatio; - for (int y = 0; y < img_size; y++) { - const int img_y = (img_offset_y + y) * sprite_stride + img_offset_x; - for (int x = 0; x < img_size; x++) { - - const float dist = util::length(float(x) / img_size - 0.5f, float(y) / img_size - 0.5f); +void draw_circle(uint32_t *dst, const int dst_stride, const int dst_x, const int dst_y, + const int width, const int height, const float blur, + const uint8_t r = 0xFF, const uint8_t g = 0xFF, const uint8_t b = 0xFF) { + const int sprite_stride = dst_stride; + const int radius = util::min(width, height); + for (int y = 0; y < height; y++) { + const int img_y = (dst_y + y) * sprite_stride + dst_x; + for (int x = 0; x < height; x++) { + const float dist = util::length(float(x) / radius - 0.5f, float(y) / radius - 0.5f); const float t = util::smoothstep(0.5f, 0.5f - blur, dist); const uint8_t alpha = t * 255; @@ -102,11 +79,87 @@ Rect SpriteAtlas::getIcon(const int size, const std::str (uint32_t(g * t) << 8) | (uint32_t(b * t) << 16) | (uint32_t(alpha) << 24); - sprite_img[img_y + x] = color; + dst[img_y + x] = color; } } +} - uninitialized.emplace(size, name); +Rect SpriteAtlas::allocateImage(size_t width, size_t height) { + // We have to allocate a new area in the bin, and store an empty image in it. + // Add a 1px border around every image. + Rect rect = bin.allocate(width + 2 * buffer, height + 2 * buffer); + if (rect.w == 0) { + return rect; + } + + rect.x += buffer; + rect.y += buffer; + rect.w -= 2 * buffer; + rect.h -= 2 * buffer; + + return rect; +} + +Rect SpriteAtlas::getIcon(const int size, const std::string &name) { + std::lock_guard lock(mtx); + + const std::string id = name + "-" + std::to_string(size); + + auto rect_it = images.find(id); + if (rect_it != images.end()) { + return rect_it->second; + } + + Rect rect = allocateImage(size, size); + if (rect.w == 0) { + fprintf(stderr, "sprite atlas bitmap overflow\n"); + return rect; + } + + images.emplace(id, rect); + + allocate(); + + // Draw an antialiased circle. + draw_circle( + reinterpret_cast(data), + width * pixelRatio, + rect.x * pixelRatio, + rect.y * pixelRatio, + size * pixelRatio, + size * pixelRatio, + 1.0f / size / pixelRatio + ); + + uninitialized.emplace(id); + + dirty = true; + + return rect; +} + +Rect SpriteAtlas::getImage(const std::string &name, const Sprite &sprite) { + std::lock_guard lock(mtx); + + auto rect_it = images.find(name); + if (rect_it != images.end()) { + return rect_it->second; + } + + const SpritePosition &pos = sprite.getSpritePosition(name); + if (!pos.width || !pos.height) { + return Rect { 0, 0, 0, 0 }; + } + + Rect rect = allocateImage(pos.width / pos.pixelRatio, pos.height / pos.pixelRatio); + if (rect.w == 0) { + fprintf(stderr, "sprite atlas bitmap overflow\n"); + return rect; + } + + images.emplace(name, rect); + + copy(rect, pos, sprite); dirty = true; @@ -121,68 +174,39 @@ void SpriteAtlas::allocate() { } } -Rect SpriteAtlas::setIcon(const int size, const std::string &name, const std::string &icon) { - Rect rect = getIcon(size, name); +void SpriteAtlas::copy(const Rect &dst, const SpritePosition &src, const Sprite &sprite) { + if (!sprite.raster) return; + const uint32_t *src_img = reinterpret_cast(sprite.raster->getData()); + allocate(); + uint32_t *dst_img = reinterpret_cast(data); - // Copy the bitmap - const int img_size = size * pixelRatio; - const int img_offset_x = (rect.x + buffer) * pixelRatio; - const int img_offset_y = (rect.y + buffer) * pixelRatio; - - if (std::pow(size * pixelRatio, 2) * 4 /* rgba */ != icon.size()) { fprintf(stderr, "mismatched icon buffer size!"); } - - const uint32_t *icon_img = reinterpret_cast(icon.data()); - uint32_t *sprite_img = reinterpret_cast(data); - - const int sprite_stride = width * pixelRatio; - const int icon_stride = size * pixelRatio; - for (size_t y = 0; y < img_size; y++) { - const int img_y = (img_offset_y + y) * sprite_stride + img_offset_x; - const int icon_y = y * icon_stride; - for (size_t x = 0; x < img_size; x++) { - sprite_img[img_y + x] = icon_img[icon_y + x]; - } - } - - dirty = true; - - return rect; + copy_bitmap( + /* source buffer */ src_img, + /* source stride */ sprite.raster->getWidth(), + /* source x */ src.x, + /* source y */ src.y, + /* dest buffer */ dst_img, + /* dest stride */ width * pixelRatio, + /* dest x */ dst.x * pixelRatio, + /* dest y */ dst.y * pixelRatio, + /* icon dimension */ src.width, + /* icon dimension */ src.height + ); } + void SpriteAtlas::update(const Sprite &sprite) { if (!sprite.isLoaded()) return; SpriteAtlas &atlas = *this; - std::erase_if(uninitialized, [&sprite, &atlas](const std::pair &pair) { - const int &size = pair.first; - const std::string &name = pair.second; - const SpritePosition &src = sprite.getSpritePosition(name + "-" + std::to_string(size)); - if (src.width == size && src.height == size && src.pixelRatio == atlas.pixelRatio) { - const uint32_t *src_img = reinterpret_cast(sprite.raster.getData()); - - uint32_t *dst_img = reinterpret_cast(atlas.data); - Rect dst = atlas.getIcon(size, name); - dst.x = (dst.x + buffer) * atlas.pixelRatio; - dst.y = (dst.y + buffer) * atlas.pixelRatio; - dst.w = (dst.w - 2 * buffer) * atlas.pixelRatio; - dst.h = (dst.h - 2 * buffer) * atlas.pixelRatio; - - - const int src_image_stride = sprite.raster.width; - const int dst_image_stride = atlas.width * atlas.pixelRatio; - const int src_stride = src.width * src.pixelRatio; - - for (int y = 0; y < dst.h; y++) { - const int src_pos = (src.y * src.pixelRatio + y) * src_image_stride + src.x * src.pixelRatio; - const int dst_pos = (dst.y + y) * dst_image_stride + dst.x; - - // TODO: this is crashing - // memcpy(dst_img + dst_pos, src_img + src_pos, src_stride * sizeof(uint32_t)); - } - - + std::erase_if(uninitialized, [&sprite, &atlas](const std::string &name) { + Rect dst = atlas.getImage(name, sprite); + const SpritePosition &src = sprite.getSpritePosition(name); + if (src.width == dst.w * atlas.pixelRatio && src.height == dst.h * atlas.pixelRatio && src.pixelRatio == atlas.pixelRatio) { + // atlas.copy(dst, src, sprite); return true; } else { + fprintf(stderr, "sprite icon dimension mismatch\n"); return false; } }); diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index 6193e3068..289e85dfb 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -2,6 +2,7 @@ #include #include #include +#include using namespace llmr; @@ -73,16 +74,17 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons if ((fill_color[3] >= 1.0f) == (pass == Opaque)) { auto &sprite = map.getStyle().sprite; - if (properties.image.size() && sprite && sprite->isLoaded()) { - // Draw texture fill - ImagePosition imagePos = sprite->getPosition(properties.image, true); + if (properties.image.size() && sprite) { + auto &spriteAtlas = map.getSpriteAtlas(); + Rect imagePos = spriteAtlas.getImage(properties.image, *sprite); + float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z); float mix = std::fmod(map.getState().getZoom(), 1.0); std::array imageSize = {{ - imagePos.size.x * factor, - imagePos.size.y *factor + imagePos.w * factor, + imagePos.h * factor } }; @@ -96,11 +98,17 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons patternShader->setMatrix(vtxMatrix); patternShader->setOffset(offset); patternShader->setPatternSize(imageSize); - patternShader->setPatternTopLeft({{ imagePos.tl.x, imagePos.tl.y }}); - patternShader->setPatternBottomRight({{ imagePos.br.x, imagePos.br.y }}); + patternShader->setPatternTopLeft({{ + float(imagePos.x) / spriteAtlas.getWidth(), + float(imagePos.y) / spriteAtlas.getHeight(), + }}); + patternShader->setPatternBottomRight({{ + float(imagePos.x + imagePos.w) / spriteAtlas.getWidth(), + float(imagePos.y + imagePos.h) / spriteAtlas.getHeight(), + }}); patternShader->setColor(fill_color); patternShader->setMix(mix); - sprite->raster.bind(true); + spriteAtlas.bind(true); // Draw the actual triangles into the color & stencil buffer. glDepthRange(strata + strata_epsilon, 1.0f); diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index fb3a959f9..bb24c5fec 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -18,14 +19,9 @@ SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t pixelRatio(pixelRatio) { } -ImagePosition::ImagePosition(const vec2& size, vec2 tl, vec2 br) - : size(size), - tl(tl), - br(br) {} - Sprite::Sprite(Map &map, float pixelRatio) : pixelRatio(pixelRatio), - raster(map.getTexturepool()), + raster(), map(map), loaded(false) { } @@ -55,7 +51,7 @@ void Sprite::load(const std::string& base_url) { } void Sprite::complete(std::shared_ptr &sprite) { - if (sprite->raster.isLoaded() && sprite->pos.size()) { + if (sprite->raster && sprite->pos.size()) { sprite->loaded = true; sprite->map.update(); fprintf(stderr, "sprite loaded\n"); @@ -75,7 +71,7 @@ void Sprite::asyncParseJSON() { } void Sprite::parseImage(std::shared_ptr &sprite) { - sprite->raster.load(sprite->image); + sprite->raster = std::make_unique(sprite->image); sprite->image.clear(); } @@ -107,34 +103,6 @@ void Sprite::parseJSON(std::shared_ptr &sprite) { } } -ImagePosition Sprite::getPosition(const std::string& name, bool repeating) const { - if (!isLoaded()) return ImagePosition {}; - - // `repeating` indicates that the image will be used in a repeating pattern - // repeating pattern images are assumed to have a 1px padding that mirrors the opposite edge - // positions for repeating images are adjusted to exclude the edge - int8_t offset = repeating ? 1 : 0; - - auto it = pos.find(name); - if (it == pos.end()) return ImagePosition {}; - - const SpritePosition& pos = it->second; - return ImagePosition { - { - pos.width, - pos.height - }, - { - (float)(pos.x + offset) / raster.width, - (float)(pos.y + offset) / raster.height - }, - { - (float)(pos.x + pos.width - 2 * offset) / raster.width, - (float)(pos.y + pos.height - 2 * offset) / raster.height - } - }; -} - const SpritePosition &Sprite::getSpritePosition(const std::string& name) const { if (!isLoaded()) return empty; auto it = pos.find(name); diff --git a/src/util/image.cpp b/src/util/image.cpp index 3a29a95a2..156828183 100644 --- a/src/util/image.cpp +++ b/src/util/image.cpp @@ -1,6 +1,8 @@ #include #include +#include + std::string llmr::util::compress_png(int width, int height, void *rgba, bool flip) { png_voidp error_ptr = 0; @@ -48,3 +50,127 @@ std::string llmr::util::compress_png(int width, int height, void *rgba, bool fli return result; } + + +using namespace llmr::util; + + +struct Buffer { + Buffer(const std::string& data) + : data(data.data()), length(data.size()) {} + const char *const data = 0; + const size_t length = 0; + size_t pos = 0; +}; + +void readCallback(png_structp png, png_bytep data, png_size_t length) { + Buffer *reader = static_cast(png_get_io_ptr(png)); + + // Read `length` bytes into `data`. + if (reader->pos + length > reader->length) { + png_error(png, "Read Error"); + } else { + memcpy(data, reader->data + reader->pos, length); + reader->pos += length; + } +} + +void errorHandler(png_structp, png_const_charp error_msg) { + throw std::runtime_error(error_msg); +} + +void warningHandler(png_structp, png_const_charp error_msg) { + fprintf(stderr, "PNG: %s\n", error_msg); +} + +Image::Image(const std::string &data) { + Buffer buffer(data); + + if (buffer.length < 8 || !png_check_sig((const png_bytep)buffer.data, 8)) { + fprintf(stderr, "image is not a valid PNG image\n"); + return; + } + + png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, errorHandler, warningHandler); + assert(png); + + png_infop info = png_create_info_struct(png); + assert(info); + + int depth, color, interlace; + + try { + png_set_read_fn(png, (png_voidp)&buffer, readCallback); + png_read_info(png, info); + png_get_IHDR(png, info, (png_uint_32*)&width, (png_uint_32*)&height, &depth, &color, &interlace, nullptr, nullptr); + bool alpha = (color & PNG_COLOR_MASK_ALPHA) || png_get_valid(png, info, PNG_INFO_tRNS); + + // From http://trac.mapnik.org/browser/trunk/src/png_reader.cpp + if (color == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png); + if (color == PNG_COLOR_TYPE_GRAY) + png_set_expand(png); + if (png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_expand(png); + if (depth == 16) + png_set_strip_16(png); + if (depth < 8) + png_set_packing(png); + if (color == PNG_COLOR_TYPE_GRAY || + color == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + + if (interlace == PNG_INTERLACE_ADAM7) + png_set_interlace_handling(png); + + // Always add an alpha channel. + if (!alpha) { + png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER); + } + + double gamma; + if (png_get_gAMA(png, info, &gamma)) + png_set_gamma(png, 2.2, gamma); + + png_read_update_info(png, info); + + png_size_t rowbytes = png_get_rowbytes(png, info); + assert(width * 4 == rowbytes); + + img = (char *)malloc(width * height * 4); + char *surface = img; + assert(surface); + + struct ptrs { + ptrs(size_t count) : rows(new png_bytep[count]) {} + ~ptrs() { delete[] rows; } + png_bytep *rows = nullptr; + } pointers(height); + for (unsigned i = 0; i < height; ++i) { + pointers.rows[i] = (png_bytep)(surface + (i * rowbytes)); + } + + // Read image data + png_read_image(png, pointers.rows); + + png_read_end(png, nullptr); + + png_destroy_read_struct(&png, &info, nullptr); + } catch (std::exception& e) { + fprintf(stderr, "loading PNG failed: %s\n", e.what()); + png_destroy_read_struct(&png, &info, nullptr); + if (img) { + free(img); + img = nullptr; + } + width = 0; + height = 0; + } +} + +Image::~Image() { + if (img) { + free(img); + img = nullptr; + } +} diff --git a/src/util/raster.cpp b/src/util/raster.cpp index 90268c09b..4f26f8b55 100644 --- a/src/util/raster.cpp +++ b/src/util/raster.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -18,9 +19,7 @@ Raster::Raster(Texturepool &texturepool) {} Raster::~Raster() { - if (img && !textured) { - free(img); - } else if (textured) { + if (textured) { texturepool.removeTextureID(texture); } } @@ -31,130 +30,17 @@ bool Raster::isLoaded() const { } bool Raster::load(const std::string &data) { - loadImage(data); + img = std::make_unique(data); + width = img->getWidth(); + height = img->getHeight(); std::lock_guard lock(mtx); - if (img) { + if (img->getData()) { loaded = true; } return loaded; } -struct Buffer { - Buffer(const std::string& data) - : data(data.data()), length(data.size()) {} - const char *const data = 0; - const size_t length = 0; - size_t pos = 0; -}; - -void readCallback(png_structp png, png_bytep data, png_size_t length) { - Buffer *reader = static_cast(png_get_io_ptr(png)); - - // Read `length` bytes into `data`. - if (reader->pos + length > reader->length) { - png_error(png, "Read Error"); - } else { - memcpy(data, reader->data + reader->pos, length); - reader->pos += length; - } -} - -void errorHandler(png_structp, png_const_charp error_msg) { - throw std::runtime_error(error_msg); -} - -void warningHandler(png_structp, png_const_charp error_msg) { - fprintf(stderr, "PNG: %s\n", error_msg); -} - -void Raster::loadImage(const std::string& data) { - std::lock_guard lock(mtx); - - Buffer buffer(data); - - if (buffer.length < 8 || !png_check_sig((const png_bytep)buffer.data, 8)) { - fprintf(stderr, "image is not a valid PNG image\n"); - return; - } - - png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, errorHandler, warningHandler); - assert(png); - - png_infop info = png_create_info_struct(png); - assert(info); - - int depth, color, interlace; - - try { - png_set_read_fn(png, (png_voidp)&buffer, readCallback); - png_read_info(png, info); - png_get_IHDR(png, info, (png_uint_32*)&width, (png_uint_32*)&height, &depth, &color, &interlace, nullptr, nullptr); - bool alpha = (color & PNG_COLOR_MASK_ALPHA) || png_get_valid(png, info, PNG_INFO_tRNS); - - // From http://trac.mapnik.org/browser/trunk/src/png_reader.cpp - if (color == PNG_COLOR_TYPE_PALETTE) - png_set_expand(png); - if (color == PNG_COLOR_TYPE_GRAY) - png_set_expand(png); - if (png_get_valid(png, info, PNG_INFO_tRNS)) - png_set_expand(png); - if (depth == 16) - png_set_strip_16(png); - if (depth < 8) - png_set_packing(png); - if (color == PNG_COLOR_TYPE_GRAY || - color == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - - if (interlace == PNG_INTERLACE_ADAM7) - png_set_interlace_handling(png); - - // Always add an alpha channel. - if (!alpha) { - png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER); - } - - double gamma; - if (png_get_gAMA(png, info, &gamma)) - png_set_gamma(png, 2.2, gamma); - - png_read_update_info(png, info); - - png_size_t rowbytes = png_get_rowbytes(png, info); - assert(width * 4 == rowbytes); - - img = (char *)malloc(width * height * 4); - char *surface = img; - assert(surface); - - struct ptrs { - ptrs(size_t count) : rows(new png_bytep[count]) {} - ~ptrs() { delete[] rows; } - png_bytep *rows = nullptr; - } pointers(height); - for (unsigned i = 0; i < height; ++i) { - pointers.rows[i] = (png_bytep)(surface + (i * rowbytes)); - } - - // Read image data - png_read_image(png, pointers.rows); - - png_read_end(png, nullptr); - - png_destroy_read_struct(&png, &info, nullptr); - } catch (std::exception& e) { - fprintf(stderr, "loading PNG failed: %s\n", e.what()); - png_destroy_read_struct(&png, &info, nullptr); - if (img) { - free(img); - img = nullptr; - } - width = 0; - height = 0; - } -} - void Raster::bind(bool linear) { if (!width || !height) { @@ -167,9 +53,8 @@ void Raster::bind(bool linear) { glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img); - free(img); - img = nullptr; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img->getData()); + img.reset(); textured = true; } else if (textured) { glBindTexture(GL_TEXTURE_2D, texture); From 92706445d9054fbe7ad66581c8bd56f4e0de4a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 19 May 2014 14:21:15 +0200 Subject: [PATCH 23/24] init glfw for debug images + actually copy images over --- common/glfw_view.cpp | 4 ++++ src/geometry/sprite_atlas.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp index 3ef7bc36a..e03b5ed2f 100644 --- a/common/glfw_view.cpp +++ b/common/glfw_view.cpp @@ -204,6 +204,8 @@ namespace platform { double elapsed() { return glfwGetTime(); } void show_debug_image(std::string name, const char *data, size_t width, size_t height) { + glfwInit(); + static GLFWwindow *debug_window = nullptr; if (!debug_window) { debug_window = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); @@ -233,6 +235,8 @@ void show_debug_image(std::string name, const char *data, size_t width, size_t h void show_color_debug_image(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height) { + glfwInit(); + static GLFWwindow *debug_window = nullptr; if (!debug_window) { debug_window = glfwCreateWindow(logical_width, logical_height, name.c_str(), nullptr, nullptr); diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 4f05df620..1c6afcd30 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -203,7 +203,7 @@ void SpriteAtlas::update(const Sprite &sprite) { Rect dst = atlas.getImage(name, sprite); const SpritePosition &src = sprite.getSpritePosition(name); if (src.width == dst.w * atlas.pixelRatio && src.height == dst.h * atlas.pixelRatio && src.pixelRatio == atlas.pixelRatio) { - // atlas.copy(dst, src, sprite); + atlas.copy(dst, src, sprite); return true; } else { fprintf(stderr, "sprite icon dimension mismatch\n"); From ee82986717ed6684a382d0e262523479f794d769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 19 May 2014 14:21:57 +0200 Subject: [PATCH 24/24] disable debug image --- src/geometry/sprite_atlas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index 1c6afcd30..fbdf5b348 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -244,7 +244,7 @@ void SpriteAtlas::bind(bool linear) { data // const GLvoid * data ); - platform::show_color_debug_image("Sprite Atlas", data, width, height, width * pixelRatio, height * pixelRatio); + // platform::show_color_debug_image("Sprite Atlas", data, width, height, width * pixelRatio, height * pixelRatio); dirty = false; }