Make pixelRatio constant across a Map object lifetime
also moves framebuffer size out of TransformState into its own object
This commit is contained in:
@@ -180,12 +180,12 @@ namespace {
|
||||
using namespace mbgl::android;
|
||||
|
||||
jlong JNICALL
|
||||
nativeCreate(JNIEnv *env, jobject obj, jstring cachePath_, jstring dataPath_, jstring apkPath_) {
|
||||
nativeCreate(JNIEnv *env, jobject obj, jstring cachePath_, jstring dataPath_, jstring apkPath_, jfloat pixelRatio) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreate");
|
||||
cachePath = std_string_from_jstring(env, cachePath_);
|
||||
dataPath = std_string_from_jstring(env, dataPath_);
|
||||
apkPath = std_string_from_jstring(env, apkPath_);
|
||||
NativeMapView *nativeMapView = new NativeMapView(env, obj);
|
||||
NativeMapView *nativeMapView = new NativeMapView(env, obj, pixelRatio);
|
||||
jlong mapViewPtr = reinterpret_cast<jlong>(nativeMapView);
|
||||
return mapViewPtr;
|
||||
}
|
||||
@@ -285,20 +285,26 @@ void JNICALL nativeOnInvalidate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr
|
||||
nativeMapView->onInvalidate();
|
||||
}
|
||||
|
||||
void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height,
|
||||
jfloat ratio, jint fbWidth, jint fbHeight) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeResize");
|
||||
void JNICALL nativeViewResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeViewResize");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
assert(width >= 0);
|
||||
assert(height >= 0);
|
||||
assert(width <= UINT16_MAX);
|
||||
assert(height <= UINT16_MAX);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->resizeView(width, height);
|
||||
}
|
||||
|
||||
void JNICALL nativeFramebufferResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint fbWidth, jint fbHeight) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeFramebufferResize");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
assert(fbWidth >= 0);
|
||||
assert(fbHeight >= 0);
|
||||
assert(fbWidth <= UINT16_MAX);
|
||||
assert(fbHeight <= UINT16_MAX);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().resize(width, height, ratio);
|
||||
nativeMapView->resizeFramebuffer(fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
void JNICALL nativeRemoveClass(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring clazz) {
|
||||
@@ -922,7 +928,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
}
|
||||
|
||||
const std::vector<JNINativeMethod> methods = {
|
||||
{"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
|
||||
{"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;F)J",
|
||||
reinterpret_cast<void *>(&nativeCreate)},
|
||||
{"nativeDestroy", "(J)V", reinterpret_cast<void *>(&nativeDestroy)},
|
||||
{"nativeInitializeDisplay", "(J)V", reinterpret_cast<void *>(&nativeInitializeDisplay)},
|
||||
@@ -936,9 +942,12 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
{"nativeResume", "(J)V", reinterpret_cast<void *>(&nativeResume)},
|
||||
{"nativeUpdate", "(J)V", reinterpret_cast<void *>(&nativeUpdate)},
|
||||
{"nativeOnInvalidate", "(J)V", reinterpret_cast<void *>(&nativeOnInvalidate)},
|
||||
{"nativeResize", "(JIIFII)V",
|
||||
{"nativeViewResize", "(JII)V",
|
||||
reinterpret_cast<void *>(static_cast<void JNICALL (
|
||||
*)(JNIEnv *, jobject, jlong, jint, jint, jfloat, jint, jint)>(&nativeResize))},
|
||||
*)(JNIEnv *, jobject, jlong, jint, jint)>(&nativeViewResize))},
|
||||
{"nativeFramebufferResize", "(JII)V",
|
||||
reinterpret_cast<void *>(static_cast<void JNICALL (
|
||||
*)(JNIEnv *, jobject, jlong, jint, jint)>(&nativeFramebufferResize))},
|
||||
{"nativeAddClass", "(JLjava/lang/String;)V",
|
||||
reinterpret_cast<void *>(&nativeAddClass)},
|
||||
{"nativeRemoveClass", "(JLjava/lang/String;)V",
|
||||
|
||||
@@ -52,8 +52,9 @@ void log_gl_string(GLenum name, const char *label) {
|
||||
}
|
||||
}
|
||||
|
||||
NativeMapView::NativeMapView(JNIEnv *env, jobject obj_)
|
||||
NativeMapView::NativeMapView(JNIEnv *env, jobject obj_, float pixelRatio_)
|
||||
: mbgl::View(*this),
|
||||
pixelRatio(pixelRatio_),
|
||||
fileCache(mbgl::android::cachePath + "/mbgl-cache.db"),
|
||||
fileSource(&fileCache),
|
||||
map(*this, fileSource, MapMode::Continuous) {
|
||||
@@ -98,6 +99,18 @@ NativeMapView::~NativeMapView() {
|
||||
vm = nullptr;
|
||||
}
|
||||
|
||||
float NativeMapView::getPixelRatio() const {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> NativeMapView::getSize() const {
|
||||
return {{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> NativeMapView::getFramebufferSize() const {
|
||||
return {{ static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }};
|
||||
}
|
||||
|
||||
void NativeMapView::activate() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::activate");
|
||||
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE) && (context != EGL_NO_CONTEXT)) {
|
||||
@@ -754,5 +767,16 @@ void NativeMapView::onInvalidate() {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::resizeView(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
map.update(mbgl::Update::Dimensions);
|
||||
}
|
||||
|
||||
void NativeMapView::resizeFramebuffer(int w, int h) {
|
||||
fbWidth = w;
|
||||
fbHeight = h;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ public class MapView extends SurfaceView {
|
||||
String apkPath = context.getPackageCodePath();
|
||||
|
||||
// Create the NativeMapView
|
||||
mNativeMapView = new NativeMapView(this, cachePath, dataPath, apkPath);
|
||||
mNativeMapView = new NativeMapView(this, cachePath, dataPath, apkPath, mScreenDensity);
|
||||
|
||||
// Load the attributes
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapView, 0, 0);
|
||||
@@ -477,6 +477,10 @@ public class MapView extends SurfaceView {
|
||||
mNativeMapView.resume();
|
||||
}
|
||||
|
||||
public void onSizeChanged(int width, int height, int oldw, int oldh) {
|
||||
mNativeMapView.resizeView((int)(width / mScreenDensity), (int)(height / mScreenDensity));
|
||||
}
|
||||
|
||||
// This class handles SurfaceHolder callbacks
|
||||
private class Callbacks implements SurfaceHolder.Callback {
|
||||
|
||||
@@ -498,9 +502,8 @@ public class MapView extends SurfaceView {
|
||||
// changed
|
||||
// Must handle window resizing here.
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
||||
int height) {
|
||||
mNativeMapView.resize((int) (width / mScreenDensity), (int) (height / mScreenDensity), mScreenDensity, width, height);
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
mNativeMapView.resizeFramebuffer(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,11 @@ class NativeMapView {
|
||||
// Constructors
|
||||
//
|
||||
|
||||
public NativeMapView(MapView mapView, String cachePath, String dataPath, String apkPath) {
|
||||
public NativeMapView(MapView mapView, String cachePath, String dataPath, String apkPath, float pixelRatio) {
|
||||
mMapView = mapView;
|
||||
|
||||
// Create the NativeMapView
|
||||
mNativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath);
|
||||
mNativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -90,8 +90,7 @@ class NativeMapView {
|
||||
nativeOnInvalidate(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resize(int width, int height, float ratio, int fbWidth,
|
||||
int fbHeight) {
|
||||
public void resizeView(int width, int height) {
|
||||
if (width < 0) {
|
||||
throw new IllegalArgumentException("width cannot be negative.");
|
||||
}
|
||||
@@ -100,6 +99,19 @@ class NativeMapView {
|
||||
throw new IllegalArgumentException("height cannot be negative.");
|
||||
}
|
||||
|
||||
if (width > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"width cannot be greater than 65535.");
|
||||
}
|
||||
|
||||
if (height > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"height cannot be greater than 65535.");
|
||||
}
|
||||
nativeViewResize(mNativeMapViewPtr, width, height);
|
||||
}
|
||||
|
||||
public void resizeFramebuffer(int fbWidth, int fbHeight) {
|
||||
if (fbWidth < 0) {
|
||||
throw new IllegalArgumentException("fbWidth cannot be negative.");
|
||||
}
|
||||
@@ -117,7 +129,7 @@ class NativeMapView {
|
||||
throw new IllegalArgumentException(
|
||||
"fbHeight cannot be greater than 65535.");
|
||||
}
|
||||
nativeResize(mNativeMapViewPtr, width, height, ratio, fbWidth, fbHeight);
|
||||
nativeFramebufferResize(mNativeMapViewPtr, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
public void addClass(String clazz) {
|
||||
@@ -370,7 +382,7 @@ class NativeMapView {
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private native long nativeCreate(String cachePath, String dataPath, String apkPath);
|
||||
private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio);
|
||||
|
||||
private native void nativeDestroy(long nativeMapViewPtr);
|
||||
|
||||
@@ -395,8 +407,9 @@ class NativeMapView {
|
||||
|
||||
private native void nativeOnInvalidate(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResize(long nativeMapViewPtr, int width,
|
||||
int height, float ratio, int fbWidth, int fbHeight);
|
||||
private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
|
||||
|
||||
private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight);
|
||||
|
||||
private native void nativeAddClass(long nativeMapViewPtr, String clazz);
|
||||
|
||||
|
||||
@@ -85,13 +85,12 @@ int main(int argc, char *argv[]) {
|
||||
fileSource.setAccessToken(std::string(token));
|
||||
}
|
||||
|
||||
HeadlessView view;
|
||||
HeadlessView view(pixelRatio, width, height);
|
||||
Map map(view, fileSource, MapMode::Still);
|
||||
|
||||
map.setStyleJSON(style, ".");
|
||||
map.setClasses(classes);
|
||||
|
||||
map.resize(width, height, pixelRatio);
|
||||
map.setLatLngZoom({ lat, lon }, zoom);
|
||||
map.setBearing(bearing);
|
||||
|
||||
|
||||
@@ -17,9 +17,12 @@ namespace android {
|
||||
|
||||
class NativeMapView : public mbgl::View, private mbgl::util::noncopyable {
|
||||
public:
|
||||
NativeMapView(JNIEnv *env, jobject obj);
|
||||
NativeMapView(JNIEnv *env, jobject obj, float pixelRatio);
|
||||
virtual ~NativeMapView();
|
||||
|
||||
float getPixelRatio() const override;
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void notify() override;
|
||||
@@ -48,6 +51,9 @@ public:
|
||||
|
||||
void onInvalidate();
|
||||
|
||||
void resizeView(int width, int height);
|
||||
void resizeFramebuffer(int width, int height);
|
||||
|
||||
private:
|
||||
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
|
||||
|
||||
@@ -73,6 +79,12 @@ private:
|
||||
bool fpsEnabled = false;
|
||||
double fps = 0.0;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int fbWidth = 0;
|
||||
int fbHeight = 0;
|
||||
const float pixelRatio;
|
||||
|
||||
// Ensure these are initialised last
|
||||
mbgl::SQLiteCache fileCache;
|
||||
mbgl::DefaultFileSource fileSource;
|
||||
|
||||
@@ -113,7 +113,6 @@ public:
|
||||
void resetNorth();
|
||||
|
||||
// Size
|
||||
void resize(uint16_t width, uint16_t height, float ratio = 1);
|
||||
uint16_t getWidth() const;
|
||||
uint16_t getHeight() const;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using UpdateType = uint32_t;
|
||||
|
||||
enum class Update : UpdateType {
|
||||
Nothing = 0,
|
||||
Dimensions = 1 << 1,
|
||||
DefaultTransitionDuration = 1 << 2,
|
||||
Classes = 1 << 3,
|
||||
Zoom = 1 << 4,
|
||||
|
||||
@@ -30,6 +30,21 @@ enum MapChange : uint8_t {
|
||||
|
||||
class View {
|
||||
public:
|
||||
// Called from the main thread directly after initialization. Must always return the same value,
|
||||
// i.e. it may not change over time.
|
||||
virtual float getPixelRatio() const = 0;
|
||||
|
||||
// Called from the main thread when the View signaled a dimension change. Must return the
|
||||
// logical dimension of this map in pixels.
|
||||
virtual std::array<uint16_t, 2> getSize() const = 0;
|
||||
|
||||
// Called from the main thread for every frame that is being rendered. Must return the absolute
|
||||
// dimensions of the current framebuffer. Typically, this is the logical width scaled by the
|
||||
// pixel ratio, but in case the view was moved to display with a different pixel ratio, it can
|
||||
// also be different from that rule.
|
||||
virtual std::array<uint16_t, 2> getFramebufferSize() const = 0;
|
||||
|
||||
// Called from the main thread when this View is associated with a Map object.
|
||||
virtual void initialize(Map *map_);
|
||||
|
||||
// Called from the render thread. Makes the GL context active in the current
|
||||
@@ -43,9 +58,6 @@ public:
|
||||
|
||||
virtual void notify() = 0;
|
||||
|
||||
// Called from the render thread. The implementation should resize the framebuffer.
|
||||
virtual void resize(uint16_t width, uint16_t height, float pixelRatio);
|
||||
|
||||
// Called from the render thread. The implementation must trigger a rerender.
|
||||
// (map->renderSync() from the main thread must be called as a result of this)
|
||||
virtual void invalidate() = 0;
|
||||
|
||||
@@ -15,6 +15,10 @@ public:
|
||||
GLFWView(bool fullscreen = false);
|
||||
~GLFWView();
|
||||
|
||||
float getPixelRatio() const override;
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
|
||||
void initialize(mbgl::Map *map) override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
@@ -24,7 +28,8 @@ public:
|
||||
|
||||
static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods);
|
||||
static void onScroll(GLFWwindow *window, double xoffset, double yoffset);
|
||||
static void onResize(GLFWwindow *window, int width, int height);
|
||||
static void onWindowResize(GLFWwindow *window, int width, int height);
|
||||
static void onFramebufferResize(GLFWwindow *window, int width, int height);
|
||||
static void onMouseClick(GLFWwindow *window, int button, int action, int modifiers);
|
||||
static void onMouseMove(GLFWwindow *window, double x, double y);
|
||||
|
||||
@@ -57,6 +62,9 @@ private:
|
||||
|
||||
int width = 1024;
|
||||
int height = 768;
|
||||
int fbWidth;
|
||||
int fbHeight;
|
||||
float pixelRatio;
|
||||
|
||||
double lastX = 0, lastY = 0;
|
||||
|
||||
|
||||
@@ -25,18 +25,23 @@ class HeadlessDisplay;
|
||||
|
||||
class HeadlessView : public View {
|
||||
public:
|
||||
HeadlessView(uint16_t width = 256, uint16_t height = 256, float pixelRatio = 1);
|
||||
HeadlessView(std::shared_ptr<HeadlessDisplay> display, uint16_t width = 256, uint16_t height = 256, float pixelRatio = 1);
|
||||
HeadlessView(float pixelRatio, uint16_t width = 256, uint16_t height = 256);
|
||||
HeadlessView(std::shared_ptr<HeadlessDisplay> display, float pixelRatio, uint16_t width = 256, uint16_t height = 256);
|
||||
~HeadlessView();
|
||||
|
||||
float getPixelRatio() const override;
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void notify() override;
|
||||
void resize(uint16_t width, uint16_t height, float pixelRatio) override;
|
||||
void invalidate() override;
|
||||
void swap() override;
|
||||
std::unique_ptr<StillImage> readStillImage() override;
|
||||
|
||||
void resize(uint16_t width, uint16_t height);
|
||||
|
||||
private:
|
||||
void createContext();
|
||||
void loadExtensions();
|
||||
@@ -45,18 +50,8 @@ private:
|
||||
|
||||
private:
|
||||
std::shared_ptr<HeadlessDisplay> display;
|
||||
|
||||
struct Dimensions {
|
||||
inline Dimensions(uint16_t width = 0, uint16_t height = 0, float pixelRatio = 0);
|
||||
inline uint16_t pixelWidth() const { return width * pixelRatio; }
|
||||
inline uint16_t pixelHeight() const { return height * pixelRatio; }
|
||||
|
||||
uint16_t width = 0;
|
||||
uint16_t height = 0;
|
||||
float pixelRatio = 0;
|
||||
};
|
||||
|
||||
Dimensions dimensions;
|
||||
const float pixelRatio;
|
||||
std::array<uint16_t, 2> dimensions;
|
||||
|
||||
#if MBGL_USE_CGL
|
||||
CGLContextObj glContext = nullptr;
|
||||
|
||||
@@ -58,13 +58,17 @@ GLFWView::GLFWView(bool fullscreen_) : fullscreen(fullscreen_) {
|
||||
|
||||
glfwSetCursorPosCallback(window, onMouseMove);
|
||||
glfwSetMouseButtonCallback(window, onMouseClick);
|
||||
glfwSetWindowSizeCallback(window, onResize);
|
||||
glfwSetFramebufferSizeCallback(window, onResize);
|
||||
glfwSetWindowSizeCallback(window, onWindowResize);
|
||||
glfwSetFramebufferSizeCallback(window, onFramebufferResize);
|
||||
glfwSetScrollCallback(window, onScroll);
|
||||
glfwSetKeyCallback(window, onKey);
|
||||
|
||||
mbgl::gl::InitializeExtensions(glfwGetProcAddress);
|
||||
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
|
||||
pixelRatio = static_cast<float>(fbWidth) / width;
|
||||
|
||||
glfwMakeContextCurrent(nullptr);
|
||||
}
|
||||
|
||||
@@ -75,9 +79,6 @@ GLFWView::~GLFWView() {
|
||||
|
||||
void GLFWView::initialize(mbgl::Map *map_) {
|
||||
View::initialize(map_);
|
||||
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
onResize(window, width, height);
|
||||
}
|
||||
|
||||
void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) {
|
||||
@@ -226,15 +227,20 @@ void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset)
|
||||
view->map->scaleBy(scale, view->lastX, view->lastY);
|
||||
}
|
||||
|
||||
void GLFWView::onResize(GLFWwindow *window, int width, int height ) {
|
||||
void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) {
|
||||
GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
|
||||
view->width = width;
|
||||
view->height = height;
|
||||
|
||||
int fbWidth, fbHeight;
|
||||
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
|
||||
view->map->update(mbgl::Update::Dimensions);
|
||||
}
|
||||
|
||||
view->map->resize(width, height, static_cast<float>(fbWidth) / static_cast<float>(width));
|
||||
void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) {
|
||||
GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
|
||||
view->fbWidth = width;
|
||||
view->fbHeight = height;
|
||||
|
||||
view->map->update();
|
||||
}
|
||||
|
||||
void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) {
|
||||
@@ -287,6 +293,18 @@ void GLFWView::run() {
|
||||
}
|
||||
}
|
||||
|
||||
float GLFWView::getPixelRatio() const {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> GLFWView::getSize() const {
|
||||
return {{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> GLFWView::getFramebufferSize() const {
|
||||
return {{ static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }};
|
||||
}
|
||||
|
||||
void GLFWView::activate() {
|
||||
glfwMakeContextCurrent(window);
|
||||
}
|
||||
|
||||
@@ -20,21 +20,17 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
HeadlessView::HeadlessView(uint16_t width, uint16_t height, float pixelRatio)
|
||||
: display(std::make_shared<HeadlessDisplay>()) {
|
||||
activate();
|
||||
resize(width, height, pixelRatio);
|
||||
deactivate();
|
||||
HeadlessView::HeadlessView(float pixelRatio_, uint16_t width, uint16_t height)
|
||||
: display(std::make_shared<HeadlessDisplay>()), pixelRatio(pixelRatio_) {
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display_,
|
||||
float pixelRatio_,
|
||||
uint16_t width,
|
||||
uint16_t height,
|
||||
float pixelRatio)
|
||||
: display(display_) {
|
||||
activate();
|
||||
resize(width, height, pixelRatio);
|
||||
deactivate();
|
||||
uint16_t height)
|
||||
: display(display_), pixelRatio(pixelRatio_) {
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
void HeadlessView::loadExtensions() {
|
||||
@@ -118,17 +114,15 @@ bool HeadlessView::isActive() {
|
||||
return std::this_thread::get_id() == thread;
|
||||
}
|
||||
|
||||
HeadlessView::Dimensions::Dimensions(uint16_t width_, uint16_t height_, float pixelRatio_)
|
||||
: width(width_), height(height_), pixelRatio(pixelRatio_) {
|
||||
}
|
||||
void HeadlessView::resize(const uint16_t width, const uint16_t height) {
|
||||
activate();
|
||||
|
||||
void HeadlessView::resize(const uint16_t width, const uint16_t height, const float pixelRatio) {
|
||||
dimensions = { width, height, pixelRatio };
|
||||
dimensions = {{ width, height }};
|
||||
|
||||
clearBuffers();
|
||||
|
||||
const unsigned int w = dimensions.width * dimensions.pixelRatio;
|
||||
const unsigned int h = dimensions.height * dimensions.pixelRatio;
|
||||
const unsigned int w = dimensions[0] * pixelRatio;
|
||||
const unsigned int h = dimensions[1] * pixelRatio;
|
||||
|
||||
// Create depth/stencil buffer
|
||||
MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil));
|
||||
@@ -150,26 +144,28 @@ void HeadlessView::resize(const uint16_t width, const uint16_t height, const flo
|
||||
GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
std::stringstream error("Couldn't create framebuffer: ");
|
||||
std::string error("Couldn't create framebuffer: ");
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error << "incomplete attachment.\n"); break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error << "incomplete missing attachment.\n"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error << "incomplete dimensions.\n"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error << "incomplete formats.\n"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error << "incomplete draw buffer.\n"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error << "incomplete read buffer.\n"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error << "unsupported.\n"; break;
|
||||
default: error << "other\n"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error += "incomplete attachment"); break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error += "incomplete missing attachment"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error += "incomplete dimensions"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error += "incomplete formats"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error += "incomplete draw buffer"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error += "incomplete read buffer"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error += "unsupported"; break;
|
||||
default: error += "other"; break;
|
||||
}
|
||||
throw std::runtime_error(error.str());
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
deactivate();
|
||||
}
|
||||
|
||||
std::unique_ptr<StillImage> HeadlessView::readStillImage() {
|
||||
assert(isActive());
|
||||
|
||||
const unsigned int w = dimensions.pixelWidth();
|
||||
const unsigned int h = dimensions.pixelHeight();
|
||||
const unsigned int w = dimensions[0] * pixelRatio;
|
||||
const unsigned int h = dimensions[1] * pixelRatio;
|
||||
|
||||
auto image = std::make_unique<StillImage>();
|
||||
image->width = w;
|
||||
@@ -234,6 +230,19 @@ void HeadlessView::notify() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
float HeadlessView::getPixelRatio() const {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> HeadlessView::getSize() const {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> HeadlessView::getFramebufferSize() const {
|
||||
return {{ static_cast<uint16_t>(dimensions[0] * pixelRatio),
|
||||
static_cast<uint16_t>(dimensions[1] * pixelRatio) }};
|
||||
}
|
||||
|
||||
void HeadlessView::activate() {
|
||||
if (thread != std::thread::id()) {
|
||||
throw std::runtime_error("OpenGL context was already current");
|
||||
|
||||
@@ -218,9 +218,9 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
|
||||
_glView.enableSetNeedsDisplay = YES;
|
||||
_glView.drawableStencilFormat = GLKViewDrawableStencilFormat8;
|
||||
_glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
|
||||
if ([UIScreen instancesRespondToSelector:@selector(nativeScale)]) {
|
||||
_glView.contentScaleFactor = [[UIScreen mainScreen] nativeScale];
|
||||
}
|
||||
|
||||
const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
|
||||
_glView.contentScaleFactor = scaleFactor;
|
||||
_glView.delegate = self;
|
||||
[_glView bindDrawable];
|
||||
[self insertSubview:_glView atIndex:0];
|
||||
@@ -247,7 +247,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
|
||||
|
||||
// setup mbgl map
|
||||
//
|
||||
_mbglView = new MBGLView(self);
|
||||
_mbglView = new MBGLView(self, scaleFactor);
|
||||
_mbglFileSource = new mbgl::DefaultFileSource([MGLFileCache obtainSharedCacheWithObject:self]);
|
||||
|
||||
// Start paused on the IB canvas
|
||||
@@ -255,7 +255,6 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
|
||||
if (_isTargetingInterfaceBuilder) {
|
||||
_mbglMap->pause();
|
||||
}
|
||||
_mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor);
|
||||
|
||||
// Observe for changes to the global access token (and find out the current one).
|
||||
[[MGLAccountManager sharedManager] addObserver:self
|
||||
@@ -666,12 +665,10 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
|
||||
}
|
||||
|
||||
// This is the delegate of the GLKView object's display call.
|
||||
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
|
||||
- (void)glkView:(__unused GLKView *)view drawInRect:(__unused CGRect)rect
|
||||
{
|
||||
if ( ! self.isDormant)
|
||||
{
|
||||
_mbglMap->resize(rect.size.width, rect.size.height, view.contentScaleFactor);
|
||||
|
||||
CGFloat zoomFactor = _mbglMap->getMaxZoom() - _mbglMap->getMinZoom() + 1;
|
||||
CGFloat cpuFactor = (CGFloat)[[NSProcessInfo processInfo] processorCount];
|
||||
CGFloat memoryFactor = (CGFloat)[[NSProcessInfo processInfo] physicalMemory] / 1000 / 1000 / 1000;
|
||||
@@ -693,7 +690,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
|
||||
|
||||
if ( ! _isTargetingInterfaceBuilder)
|
||||
{
|
||||
_mbglMap->update();
|
||||
_mbglMap->update(mbgl::Update::Dimensions);
|
||||
}
|
||||
|
||||
if (self.attributionSheet.visible)
|
||||
@@ -2449,6 +2446,11 @@ CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng)
|
||||
|
||||
- (void)notifyMapChange:(mbgl::MapChange)change
|
||||
{
|
||||
// Ignore map updates when the Map object isn't set.
|
||||
if (!_mbglMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (change)
|
||||
{
|
||||
case mbgl::MapChangeRegionWillChange:
|
||||
@@ -2778,10 +2780,26 @@ CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng)
|
||||
class MBGLView : public mbgl::View
|
||||
{
|
||||
public:
|
||||
MBGLView(MGLMapView *nativeView_) : nativeView(nativeView_) {}
|
||||
MBGLView(MGLMapView* nativeView_, const float scaleFactor_)
|
||||
: nativeView(nativeView_), scaleFactor(scaleFactor_) {
|
||||
}
|
||||
virtual ~MBGLView() {}
|
||||
|
||||
|
||||
float getPixelRatio() const override {
|
||||
return scaleFactor;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> getSize() const override {
|
||||
return {{ static_cast<uint16_t>([nativeView bounds].size.width),
|
||||
static_cast<uint16_t>([nativeView bounds].size.height) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override {
|
||||
return {{ static_cast<uint16_t>([[nativeView glView] drawableWidth]),
|
||||
static_cast<uint16_t>([[nativeView glView] drawableHeight]) }};
|
||||
}
|
||||
|
||||
void notify() override
|
||||
{
|
||||
// no-op
|
||||
@@ -2817,6 +2835,7 @@ class MBGLView : public mbgl::View
|
||||
|
||||
private:
|
||||
__weak MGLMapView *nativeView = nullptr;
|
||||
const float scaleFactor;
|
||||
};
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,10 +15,11 @@ namespace mbgl {
|
||||
Map::Map(View& view_, FileSource& fileSource, MapMode mode)
|
||||
: view(view_),
|
||||
transform(std::make_unique<Transform>(view)),
|
||||
data(std::make_unique<MapData>(mode)),
|
||||
data(std::make_unique<MapData>(mode, view.getPixelRatio())),
|
||||
context(std::make_unique<util::Thread<MapContext>>(util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, *data))
|
||||
{
|
||||
view.initialize(this);
|
||||
update(Update::Dimensions);
|
||||
}
|
||||
|
||||
Map::~Map() {
|
||||
@@ -43,7 +44,8 @@ void Map::resume() {
|
||||
}
|
||||
|
||||
void Map::renderStill(StillImageCallback callback) {
|
||||
context->invoke(&MapContext::renderStill, transform->getState(), callback);
|
||||
context->invoke(&MapContext::renderStill, transform->getState(),
|
||||
FrameData{ view.getFramebufferSize() }, callback);
|
||||
}
|
||||
|
||||
void Map::renderSync() {
|
||||
@@ -53,8 +55,8 @@ void Map::renderSync() {
|
||||
|
||||
view.notifyMapChange(MapChangeWillStartRenderingFrame);
|
||||
|
||||
MapContext::RenderResult result =
|
||||
context->invokeSync<MapContext::RenderResult>(&MapContext::renderSync, transform->getState());
|
||||
MapContext::RenderResult result = context->invokeSync<MapContext::RenderResult>(
|
||||
&MapContext::renderSync, transform->getState(), FrameData{ view.getFramebufferSize() });
|
||||
|
||||
view.notifyMapChange(result.fullyLoaded ?
|
||||
MapChangeDidFinishRenderingFrameFullyRendered :
|
||||
@@ -75,6 +77,10 @@ void Map::renderSync() {
|
||||
}
|
||||
|
||||
void Map::update(Update update_) {
|
||||
if (update_ == Update::Dimensions) {
|
||||
transform->resize(view.getSize());
|
||||
}
|
||||
|
||||
context->invoke(&MapContext::triggerUpdate, transform->getState(), update_);
|
||||
}
|
||||
|
||||
@@ -96,15 +102,6 @@ std::string Map::getStyleJSON() const {
|
||||
return context->invokeSync<std::string>(&MapContext::getStyleJSON);
|
||||
}
|
||||
|
||||
#pragma mark - Size
|
||||
|
||||
void Map::resize(uint16_t width, uint16_t height, float ratio) {
|
||||
if (transform->resize(width, height, ratio, width * ratio, height * ratio)) {
|
||||
context->invoke(&MapContext::resize, width, height, ratio);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Transitions
|
||||
|
||||
void Map::cancelTransitions() {
|
||||
@@ -185,7 +182,7 @@ void Map::fitBounds(AnnotationSegment segment, EdgeInsets padding, Duration dura
|
||||
if (segment.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Calculate the bounds of the possibly rotated shape with respect to the viewport.
|
||||
vec2<> nePixel = {-INFINITY, -INFINITY};
|
||||
vec2<> swPixel = {INFINITY, INFINITY};
|
||||
|
||||
@@ -79,10 +79,6 @@ void MapContext::pause() {
|
||||
view.activate();
|
||||
}
|
||||
|
||||
void MapContext::resize(uint16_t width, uint16_t height, float ratio) {
|
||||
view.resize(width, height, ratio);
|
||||
}
|
||||
|
||||
void MapContext::triggerUpdate(const TransformState& state, const Update u) {
|
||||
transformState = state;
|
||||
updated |= static_cast<UpdateType>(u);
|
||||
@@ -266,14 +262,14 @@ void MapContext::update() {
|
||||
if (data.mode == MapMode::Continuous) {
|
||||
view.invalidate();
|
||||
} else if (callback && style->isLoaded()) {
|
||||
renderSync(transformState);
|
||||
renderSync(transformState, frameData);
|
||||
}
|
||||
}
|
||||
|
||||
updated = static_cast<UpdateType>(Update::Nothing);
|
||||
}
|
||||
|
||||
void MapContext::renderStill(const TransformState& state, StillImageCallback fn) {
|
||||
void MapContext::renderStill(const TransformState& state, const FrameData& frame, StillImageCallback fn) {
|
||||
if (!fn) {
|
||||
Log::Error(Event::General, "StillImageCallback not set");
|
||||
return;
|
||||
@@ -301,12 +297,13 @@ void MapContext::renderStill(const TransformState& state, StillImageCallback fn)
|
||||
|
||||
callback = fn;
|
||||
transformState = state;
|
||||
frameData = frame;
|
||||
|
||||
updated |= static_cast<UpdateType>(Update::RenderStill);
|
||||
asyncUpdate->send();
|
||||
}
|
||||
|
||||
MapContext::RenderResult MapContext::renderSync(const TransformState& state) {
|
||||
MapContext::RenderResult MapContext::renderSync(const TransformState& state, const FrameData& frame) {
|
||||
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
|
||||
|
||||
// Style was not loaded yet.
|
||||
@@ -320,12 +317,12 @@ MapContext::RenderResult MapContext::renderSync(const TransformState& state) {
|
||||
glObjectStore.performCleanup();
|
||||
|
||||
if (!painter) {
|
||||
painter = std::make_unique<Painter>();
|
||||
painter = std::make_unique<Painter>(data.pixelRatio);
|
||||
painter->setup();
|
||||
}
|
||||
|
||||
painter->setDebug(data.getDebug());
|
||||
painter->render(*style, transformState, data.getAnimationTime());
|
||||
painter->render(*style, transformState, frame, data.getAnimationTime());
|
||||
|
||||
if (data.mode == MapMode::Still) {
|
||||
callback(nullptr, view.readStillImage());
|
||||
|
||||
@@ -26,6 +26,11 @@ class StillImage;
|
||||
struct LatLng;
|
||||
struct LatLngBounds;
|
||||
|
||||
|
||||
struct FrameData {
|
||||
std::array<uint16_t, 2> framebufferSize;
|
||||
};
|
||||
|
||||
class MapContext : public Style::Observer {
|
||||
public:
|
||||
MapContext(View&, FileSource&, MapData&);
|
||||
@@ -38,13 +43,11 @@ public:
|
||||
|
||||
void pause();
|
||||
|
||||
void resize(uint16_t width, uint16_t height, float ratio);
|
||||
|
||||
using StillImageCallback = std::function<void(std::exception_ptr, std::unique_ptr<const StillImage>)>;
|
||||
|
||||
void triggerUpdate(const TransformState&, Update = Update::Nothing);
|
||||
void renderStill(const TransformState&, StillImageCallback callback);
|
||||
RenderResult renderSync(const TransformState&);
|
||||
void renderStill(const TransformState&, const FrameData&, StillImageCallback callback);
|
||||
RenderResult renderSync(const TransformState&, const FrameData&);
|
||||
|
||||
void setStyleURL(const std::string&);
|
||||
void setStyleJSON(const std::string& json, const std::string& base);
|
||||
@@ -95,6 +98,7 @@ private:
|
||||
StillImageCallback callback;
|
||||
size_t sourceCacheSize;
|
||||
TransformState transformState;
|
||||
FrameData frameData;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ class MapData {
|
||||
using Lock = std::lock_guard<std::mutex>;
|
||||
|
||||
public:
|
||||
inline MapData(MapMode mode_) : mode(mode_) {
|
||||
inline MapData(MapMode mode_, const float pixelRatio_) : mode(mode_), pixelRatio(pixelRatio_) {
|
||||
assert(pixelRatio > 0);
|
||||
setAnimationTime(TimePoint::min());
|
||||
setDefaultTransitionDuration(Duration::zero());
|
||||
}
|
||||
@@ -77,7 +78,7 @@ public:
|
||||
}
|
||||
inline void setDefaultTransitionDuration(Duration duration) {
|
||||
defaultTransitionDuration = duration;
|
||||
};
|
||||
}
|
||||
|
||||
util::exclusive<AnnotationManager> getAnnotationManager() {
|
||||
return util::exclusive<AnnotationManager>(
|
||||
@@ -87,6 +88,7 @@ public:
|
||||
|
||||
public:
|
||||
const MapMode mode;
|
||||
const float pixelRatio;
|
||||
|
||||
private:
|
||||
mutable std::mutex annotationManagerMutex;
|
||||
|
||||
@@ -292,11 +292,11 @@ TileData::State Source::addTile(MapData& data,
|
||||
if (info.type == SourceType::Vector) {
|
||||
auto tileData = std::make_shared<VectorTileData>(normalized_id, style, info,
|
||||
transformState.getAngle(), data.getCollisionDebug());
|
||||
tileData->request(transformState.getPixelRatio(), callback);
|
||||
tileData->request(data.pixelRatio, callback);
|
||||
new_tile.data = tileData;
|
||||
} else if (info.type == SourceType::Raster) {
|
||||
auto tileData = std::make_shared<RasterTileData>(normalized_id, texturePool, info, style.workers);
|
||||
tileData->request(transformState.getPixelRatio(), callback);
|
||||
tileData->request(data.pixelRatio, callback);
|
||||
new_tile.data = tileData;
|
||||
} else if (info.type == SourceType::Annotations) {
|
||||
new_tile.data = std::make_shared<LiveTileData>(normalized_id,
|
||||
|
||||
@@ -34,18 +34,13 @@ Transform::Transform(View &view_)
|
||||
|
||||
#pragma mark - Map View
|
||||
|
||||
bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio,
|
||||
const uint16_t fb_w, const uint16_t fb_h) {
|
||||
if (state.width != w || state.height != h || state.pixelRatio != ratio ||
|
||||
state.framebuffer[0] != fb_w || state.framebuffer[1] != fb_h) {
|
||||
bool Transform::resize(const std::array<uint16_t, 2> size) {
|
||||
if (state.width != size[0] || state.height != size[1]) {
|
||||
|
||||
view.notifyMapChange(MapChangeRegionWillChange);
|
||||
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
state.pixelRatio = ratio;
|
||||
state.framebuffer[0] = fb_w;
|
||||
state.framebuffer[1] = fb_h;
|
||||
state.width = size[0];
|
||||
state.height = size[1];
|
||||
state.constrain(state.scale, state.y);
|
||||
|
||||
view.notifyMapChange(MapChangeRegionDidChange);
|
||||
|
||||
@@ -20,9 +20,7 @@ public:
|
||||
Transform(View&);
|
||||
|
||||
// Map view
|
||||
// Note: width * ratio does not necessarily equal fb_width
|
||||
bool resize(uint16_t width, uint16_t height, float ratio,
|
||||
uint16_t fb_width, uint16_t fb_height);
|
||||
bool resize(std::array<uint16_t, 2> size);
|
||||
|
||||
// Position
|
||||
void moveBy(double dx, double dy, Duration = Duration::zero());
|
||||
|
||||
@@ -74,23 +74,6 @@ uint16_t TransformState::getHeight() const {
|
||||
return height;
|
||||
}
|
||||
|
||||
uint16_t TransformState::getFramebufferWidth() const {
|
||||
return framebuffer[0];
|
||||
}
|
||||
|
||||
uint16_t TransformState::getFramebufferHeight() const {
|
||||
return framebuffer[1];
|
||||
}
|
||||
|
||||
const std::array<uint16_t, 2> TransformState::getFramebufferDimensions() const {
|
||||
return framebuffer;
|
||||
}
|
||||
|
||||
float TransformState::getPixelRatio() const {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Position
|
||||
|
||||
const LatLng TransformState::getLatLng() const {
|
||||
|
||||
@@ -27,10 +27,6 @@ public:
|
||||
bool hasSize() const;
|
||||
uint16_t getWidth() const;
|
||||
uint16_t getHeight() const;
|
||||
uint16_t getFramebufferWidth() const;
|
||||
uint16_t getFramebufferHeight() const;
|
||||
const std::array<uint16_t, 2> getFramebufferDimensions() const;
|
||||
float getPixelRatio() const;
|
||||
|
||||
float worldSize() const;
|
||||
float lngX(float lon) const;
|
||||
@@ -73,12 +69,7 @@ private:
|
||||
// logical dimensions
|
||||
uint16_t width = 0, height = 0;
|
||||
|
||||
// physical (framebuffer) dimensions
|
||||
std::array<uint16_t, 2> framebuffer = {{ 0, 0 }};
|
||||
|
||||
// map scale factor
|
||||
float pixelRatio = 0;
|
||||
|
||||
private:
|
||||
// animation state
|
||||
bool rotating = false;
|
||||
bool scaling = false;
|
||||
|
||||
@@ -11,10 +11,6 @@ void View::initialize(Map *map_) {
|
||||
map = map_;
|
||||
}
|
||||
|
||||
void View::resize(uint16_t, uint16_t, float) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
std::unique_ptr<StillImage> View::readStillImage() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/gl/debugging.hpp>
|
||||
@@ -40,7 +41,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
Painter::Painter() {
|
||||
Painter::Painter(const float pixelRatio_) : pixelRatio(pixelRatio_) {
|
||||
}
|
||||
|
||||
Painter::~Painter() {
|
||||
@@ -104,8 +105,8 @@ void Painter::setupShaders() {
|
||||
}
|
||||
|
||||
void Painter::resize() {
|
||||
if (gl_viewport != state.getFramebufferDimensions()) {
|
||||
gl_viewport = state.getFramebufferDimensions();
|
||||
if (gl_viewport != frame.framebufferSize) {
|
||||
gl_viewport = frame.framebufferSize;
|
||||
assert(gl_viewport[0] > 0 && gl_viewport[1] > 0);
|
||||
MBGL_CHECK_ERROR(glViewport(0, 0, gl_viewport[0], gl_viewport[1]));
|
||||
}
|
||||
@@ -164,8 +165,9 @@ void Painter::prepareTile(const Tile& tile) {
|
||||
config.stencilFunc = { GL_EQUAL, ref, mask };
|
||||
}
|
||||
|
||||
void Painter::render(const Style& style, TransformState state_, TimePoint time) {
|
||||
void Painter::render(const Style& style, TransformState state_, const FrameData& frame_, TimePoint time) {
|
||||
state = state_;
|
||||
frame = frame_;
|
||||
|
||||
glyphAtlas = style.glyphAtlas.get();
|
||||
spriteAtlas = style.spriteAtlas.get();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MBGL_RENDERER_PAINTER
|
||||
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/map/map_context.hpp>
|
||||
|
||||
#include <mbgl/renderer/frame_history.hpp>
|
||||
#include <mbgl/renderer/bucket.hpp>
|
||||
@@ -31,6 +32,7 @@ class SpriteAtlas;
|
||||
class GlyphAtlas;
|
||||
class LineAtlas;
|
||||
class Source;
|
||||
struct FrameData;
|
||||
|
||||
|
||||
class DebugBucket;
|
||||
@@ -79,7 +81,7 @@ struct RenderItem {
|
||||
|
||||
class Painter : private util::noncopyable {
|
||||
public:
|
||||
Painter();
|
||||
Painter(float pixelRatio);
|
||||
~Painter();
|
||||
|
||||
void setup();
|
||||
@@ -93,6 +95,7 @@ public:
|
||||
|
||||
void render(const Style& style,
|
||||
TransformState state,
|
||||
const FrameData& frame,
|
||||
TimePoint time);
|
||||
|
||||
// Renders debug information for a tile.
|
||||
@@ -118,6 +121,7 @@ public:
|
||||
|
||||
void createPrerendered(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID& id);
|
||||
|
||||
// Adjusts the dimensions of the OpenGL viewport
|
||||
void resize();
|
||||
|
||||
// Changes whether debug information is drawn onto the map
|
||||
@@ -187,7 +191,10 @@ public:
|
||||
}();
|
||||
|
||||
private:
|
||||
const float pixelRatio;
|
||||
|
||||
TransformState state;
|
||||
FrameData frame;
|
||||
|
||||
bool debug = false;
|
||||
int indent = 0;
|
||||
|
||||
@@ -28,7 +28,7 @@ void Painter::renderDebugText(DebugBucket& bucket, const mat4 &matrix) {
|
||||
|
||||
// Draw white outline
|
||||
plainShader->u_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
|
||||
lineWidth(4.0f * state.getPixelRatio());
|
||||
lineWidth(4.0f * pixelRatio);
|
||||
bucket.drawLines(*plainShader);
|
||||
|
||||
#ifndef GL_ES_VERSION_2_0
|
||||
@@ -39,7 +39,7 @@ void Painter::renderDebugText(DebugBucket& bucket, const mat4 &matrix) {
|
||||
|
||||
// Draw black text.
|
||||
plainShader->u_color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
|
||||
lineWidth(2.0f * state.getPixelRatio());
|
||||
lineWidth(2.0f * pixelRatio);
|
||||
bucket.drawLines(*plainShader);
|
||||
|
||||
config.depthTest = true;
|
||||
@@ -60,6 +60,6 @@ void Painter::renderDebugFrame(const mat4 &matrix) {
|
||||
// draw tile outline
|
||||
tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET(0));
|
||||
plainShader->u_color = {{ 1.0f, 0.0f, 0.0f, 1.0f }};
|
||||
lineWidth(4.0f * state.getPixelRatio());
|
||||
lineWidth(4.0f * pixelRatio);
|
||||
MBGL_CHECK_ERROR(glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)tileBorderBuffer.index()));
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const
|
||||
|
||||
// Draw the entire line
|
||||
outlineShader->u_world = {{
|
||||
static_cast<float>(state.getFramebufferWidth()),
|
||||
static_cast<float>(state.getFramebufferHeight())
|
||||
static_cast<float>(frame.framebufferSize[0]),
|
||||
static_cast<float>(frame.framebufferSize[1])
|
||||
}};
|
||||
config.depthRange = { strata, 1.0f };
|
||||
bucket.drawVertices(*outlineShader);
|
||||
@@ -128,8 +128,8 @@ void Painter::renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const
|
||||
|
||||
// Draw the entire line
|
||||
outlineShader->u_world = {{
|
||||
static_cast<float>(state.getFramebufferWidth()),
|
||||
static_cast<float>(state.getFramebufferHeight())
|
||||
static_cast<float>(frame.framebufferSize[0]),
|
||||
static_cast<float>(frame.framebufferSize[1])
|
||||
}};
|
||||
|
||||
config.depthRange = { strata + strata_epsilon + strata_epsilon, 1.0f };
|
||||
|
||||
@@ -26,7 +26,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
|
||||
// the distance over which the line edge fades out.
|
||||
// Retina devices need a smaller distance to avoid aliasing.
|
||||
float antialiasing = 1 / state.getPixelRatio();
|
||||
float antialiasing = 1.0 / pixelRatio;
|
||||
|
||||
float blur = properties.blur + antialiasing;
|
||||
float edgeWidth = properties.width / 2.0;
|
||||
@@ -50,7 +50,6 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
color[2] *= properties.opacity;
|
||||
color[3] *= properties.opacity;
|
||||
|
||||
float ratio = state.getPixelRatio();
|
||||
mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);
|
||||
|
||||
config.depthRange = { strata, 1.0f };
|
||||
@@ -62,7 +61,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
linesdfShader->u_matrix = vtxMatrix;
|
||||
linesdfShader->u_exmatrix = extrudeMatrix;
|
||||
linesdfShader->u_linewidth = {{ outset, inset }};
|
||||
linesdfShader->u_ratio = ratio;
|
||||
linesdfShader->u_ratio = pixelRatio;
|
||||
linesdfShader->u_blur = blur;
|
||||
linesdfShader->u_color = color;
|
||||
|
||||
@@ -81,7 +80,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }};
|
||||
linesdfShader->u_tex_y_b = posB.y;
|
||||
linesdfShader->u_image = 0;
|
||||
linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * state.getPixelRatio()) / 2;
|
||||
linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * pixelRatio) / 2;
|
||||
linesdfShader->u_mix = properties.dash_array.t;
|
||||
|
||||
bucket.drawLineSDF(*linesdfShader);
|
||||
@@ -97,7 +96,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
linepatternShader->u_matrix = vtxMatrix;
|
||||
linepatternShader->u_exmatrix = extrudeMatrix;
|
||||
linepatternShader->u_linewidth = {{ outset, inset }};
|
||||
linepatternShader->u_ratio = ratio;
|
||||
linepatternShader->u_ratio = pixelRatio;
|
||||
linepatternShader->u_blur = blur;
|
||||
|
||||
linepatternShader->u_pattern_size_a = {{imagePosA.size[0] * factor * properties.image.fromScale, imagePosA.size[1]}};
|
||||
@@ -121,7 +120,7 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const
|
||||
lineShader->u_matrix = vtxMatrix;
|
||||
lineShader->u_exmatrix = extrudeMatrix;
|
||||
lineShader->u_linewidth = {{ outset, inset }};
|
||||
lineShader->u_ratio = ratio;
|
||||
lineShader->u_ratio = pixelRatio;
|
||||
lineShader->u_blur = blur;
|
||||
|
||||
lineShader->u_color = color;
|
||||
|
||||
@@ -60,7 +60,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
|
||||
|
||||
// The default gamma value has to be adjust for the current pixelratio so that we're not
|
||||
// drawing blurry font on retina screens.
|
||||
const float gamma = 0.105 * sdfFontSize / fontSize / state.getPixelRatio();
|
||||
const float gamma = 0.105 * sdfFontSize / fontSize / pixelRatio;
|
||||
|
||||
const float sdfPx = 8.0f;
|
||||
const float blurOffset = 1.19f;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/map/sprite.hpp>
|
||||
#include <mbgl/map/map_data.hpp>
|
||||
#include <mbgl/map/source.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/style/style_layer.hpp>
|
||||
@@ -67,12 +68,11 @@ Style::~Style() {
|
||||
void Style::update(MapData& data,
|
||||
const TransformState& transform,
|
||||
TexturePool& texturePool) {
|
||||
const float pixelRatio = transform.getPixelRatio();
|
||||
if (!sprite || !sprite->hasPixelRatio(pixelRatio)) {
|
||||
sprite = std::make_unique<Sprite>(spriteURL, pixelRatio);
|
||||
if (!sprite || !sprite->hasPixelRatio(data.pixelRatio)) {
|
||||
sprite = std::make_unique<Sprite>(spriteURL, data.pixelRatio);
|
||||
sprite->setObserver(this);
|
||||
|
||||
spriteAtlas->resize(pixelRatio);
|
||||
spriteAtlas->resize(data.pixelRatio);
|
||||
spriteAtlas->setSprite(sprite);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ TEST(API, RenderWithoutCallback) {
|
||||
Log::setObserver(std::unique_ptr<Log::Observer>(log));
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
view.resize(128, 512);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
std::unique_ptr<Map> map = std::make_unique<Map>(view, fileSource, MapMode::Still);
|
||||
map->resize(128, 512, 1);
|
||||
map->renderStill(nullptr);
|
||||
|
||||
// Force Map thread to join.
|
||||
@@ -39,11 +39,11 @@ TEST(API, RenderWithoutCallback) {
|
||||
|
||||
TEST(API, RenderWithoutStyle) {
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
view.resize(128, 512);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Map map(view, fileSource, MapMode::Still);
|
||||
map.resize(128, 512, 1);
|
||||
|
||||
std::promise<std::exception_ptr> promise;
|
||||
map.renderStill([&promise](std::exception_ptr error, std::unique_ptr<const StillImage>) {
|
||||
|
||||
@@ -17,7 +17,7 @@ TEST(API, RepeatedRender) {
|
||||
const auto style = util::read_file("test/fixtures/api/water.json");
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1, 256, 512);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Log::setObserver(std::make_unique<FixtureLogObserver>());
|
||||
@@ -25,29 +25,27 @@ TEST(API, RepeatedRender) {
|
||||
Map map(view, fileSource, MapMode::Still);
|
||||
|
||||
{
|
||||
map.resize(128, 512, 1);
|
||||
map.setStyleJSON(style, "test/suite");
|
||||
std::promise<std::unique_ptr<const StillImage>> promise;
|
||||
map.renderStill([&promise](std::exception_ptr, std::unique_ptr<const StillImage> image) {
|
||||
promise.set_value(std::move(image));
|
||||
});
|
||||
auto result = promise.get_future().get();
|
||||
ASSERT_EQ(128, result->width);
|
||||
ASSERT_EQ(256, result->width);
|
||||
ASSERT_EQ(512, result->height);
|
||||
const std::string png = util::compress_png(result->width, result->height, result->pixels.get());
|
||||
util::write_file("test/fixtures/api/1.png", png);
|
||||
}
|
||||
|
||||
{
|
||||
map.resize(512, 512, 2);
|
||||
map.setStyleJSON(style, "TEST_DATA/suite");
|
||||
std::promise<std::unique_ptr<const StillImage>> promise;
|
||||
map.renderStill([&promise](std::exception_ptr, std::unique_ptr<const StillImage> image) {
|
||||
promise.set_value(std::move(image));
|
||||
});
|
||||
auto result = promise.get_future().get();
|
||||
ASSERT_EQ(1024, result->width);
|
||||
ASSERT_EQ(1024, result->height);
|
||||
ASSERT_EQ(256, result->width);
|
||||
ASSERT_EQ(512, result->height);
|
||||
const std::string png = util::compress_png(result->width, result->height, result->pixels.get());
|
||||
util::write_file("test/fixtures/api/2.png", png);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ TEST(API, SetStyle) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Log::setObserver(std::make_unique<FixtureLogObserver>());
|
||||
|
||||
6
test/fixtures/mock_view.hpp
vendored
6
test/fixtures/mock_view.hpp
vendored
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <mbgl/map/view.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class MockView : public View {
|
||||
@@ -10,6 +12,10 @@ public:
|
||||
MockView() = default;
|
||||
|
||||
// View implementation.
|
||||
float getPixelRatio() const { return 1; }
|
||||
std::array<uint16_t, 2> getSize() const { return {{ 0, 0 }}; }
|
||||
std::array<uint16_t, 2> getFramebufferSize() const { return {{ 0, 0 }}; }
|
||||
|
||||
void activate() override {};
|
||||
void deactivate() override {};
|
||||
void notify() override {};
|
||||
|
||||
@@ -141,11 +141,10 @@ TEST_P(HeadlessTest, render) {
|
||||
|
||||
std::promise<void> promise;
|
||||
|
||||
HeadlessView view(display, width, height, pixelRatio);
|
||||
HeadlessView view(display, pixelRatio, width, height);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
Map map(view, fileSource, MapMode::Still);
|
||||
|
||||
map.resize(width, height, pixelRatio);
|
||||
map.setClasses(classes);
|
||||
map.setStyleJSON(style, "test/suite");
|
||||
map.setLatLngZoom(mbgl::LatLng(latitude, longitude), zoom);
|
||||
|
||||
@@ -11,7 +11,7 @@ TEST(Map, PauseResume) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
@@ -24,7 +24,7 @@ TEST(Map, DoublePause) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
@@ -38,7 +38,7 @@ TEST(Map, ResumeWithoutPause) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
@@ -50,7 +50,7 @@ TEST(Map, DestroyPaused) {
|
||||
using namespace mbgl;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
|
||||
@@ -11,9 +11,9 @@ using namespace mbgl;
|
||||
|
||||
TEST(MapContext, DoubleStyleLoad) {
|
||||
std::shared_ptr<HeadlessDisplay> display = std::make_shared<HeadlessDisplay>();
|
||||
HeadlessView view(display, 512, 512, 1);
|
||||
HeadlessView view(display, 1, 512, 512);
|
||||
DefaultFileSource fileSource(nullptr);
|
||||
MapData data(MapMode::Continuous);
|
||||
MapData data(MapMode::Continuous, view.getPixelRatio());
|
||||
|
||||
util::Thread<MapContext> context({"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, data);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ TEST_P(PendingResources, DeleteMapObjectWithPendingRequest) {
|
||||
util::RunLoop loop(uv_default_loop());
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display);
|
||||
HeadlessView view(display, 1, 1000, 1000);
|
||||
MockFileSource fileSource(MockFileSource::SuccessWithDelay, GetParam());
|
||||
|
||||
std::unique_ptr<Map> map = std::make_unique<Map>(view, fileSource, MapMode::Still);
|
||||
@@ -43,7 +43,6 @@ TEST_P(PendingResources, DeleteMapObjectWithPendingRequest) {
|
||||
fileSource.setOnRequestDelayedCallback([&endTest] { endTest.send(); });
|
||||
|
||||
const std::string style = util::read_file("test/fixtures/resources/style.json");
|
||||
map->resize(1000, 1000, 1.0);
|
||||
map->setStyleJSON(style, ".");
|
||||
|
||||
map->renderStill([&endTest](std::exception_ptr, std::unique_ptr<const StillImage>) {
|
||||
|
||||
@@ -23,12 +23,12 @@ public:
|
||||
MockMapContext(View& view,
|
||||
FileSource& fileSource,
|
||||
const std::function<void(std::exception_ptr error)>& callback)
|
||||
: data_(MapMode::Still),
|
||||
: data_(MapMode::Still, view.getPixelRatio()),
|
||||
transform_(view),
|
||||
callback_(callback) {
|
||||
util::ThreadContext::setFileSource(&fileSource);
|
||||
|
||||
transform_.resize(1000, 1000, 1.0, 1000, 1000);
|
||||
transform_.resize({{ 1000, 1000 }});
|
||||
transform_.setLatLngZoom({0, 0}, 16);
|
||||
|
||||
const std::string style = util::read_file("test/fixtures/resources/style.json");
|
||||
|
||||
Reference in New Issue
Block a user