[core][ios][android][macos] Use premultiplied image directly for RasterTile and ImageSource, un-premultiply in the shader for blending

This commit is contained in:
Asheem Mamoowala
2017-07-11 14:31:05 -07:00
parent 1d15ed64dc
commit 8ae7010546
15 changed files with 53 additions and 34 deletions

View File

@@ -18,7 +18,7 @@ public:
optional<std::string> getURL() const;
void setURL(const std::string& url);
void setImage(UnassociatedImage&&);
void setImage(PremultipliedImage&&);
void setCoordinates(const std::array<LatLng, 4>&);
std::array<LatLng, 4> getCoordinates() const;

View File

@@ -1,10 +1,16 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngQuad;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -106,17 +112,27 @@ public class AnimatedImageSourceActivity extends AppCompatActivity implements On
private MapboxMap mapboxMap;
private Handler handler;
private int[] drawables;
private Bitmap[] drawables;
private int drawableIndex;
Bitmap getBitmap(int resourceId) {
Context context = Mapbox.getApplicationContext();
Drawable drawable = ContextCompat.getDrawable(context, resourceId);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
return bitmapDrawable.getBitmap();
}
return null;
}
RefreshImageRunnable(MapboxMap mapboxMap, Handler handler) {
this.mapboxMap = mapboxMap;
this.handler = handler;
drawables = new int[4];
drawables[0] = R.drawable.southeast_radar_0;
drawables[1] = R.drawable.southeast_radar_1;
drawables[2] = R.drawable.southeast_radar_2;
drawables[3] = R.drawable.southeast_radar_3;
drawables = new Bitmap[4];
drawables[0] = getBitmap(R.drawable.southeast_radar_0);
drawables[1] = getBitmap(R.drawable.southeast_radar_1);
drawables[2] = getBitmap(R.drawable.southeast_radar_2);
drawables[3] = getBitmap(R.drawable.southeast_radar_3);
drawableIndex = 1;
}

View File

@@ -40,8 +40,7 @@ namespace android {
}
void ImageSource::setImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap) {
UnassociatedImage image = util::unpremultiply(Bitmap::GetImage(env, bitmap));
source.as<mbgl::style::ImageSource>()->setImage(std:: move(image));
source.as<mbgl::style::ImageSource>()->setImage(Bitmap::GetImage(env, bitmap));
}
jni::Class<ImageSource> ImageSource::javaClass;

View File

@@ -60,10 +60,9 @@
- (void)setImage:(MGLImage *)image {
if (image != nullptr) {
mbgl::UnassociatedImage unassociatedImage = mbgl::util::unpremultiply(image.mgl_premultipliedImage);
self.rawSource->setImage(std::move(unassociatedImage));
self.rawSource->setImage(image.mgl_premultipliedImage);
} else {
self.rawSource->setImage(mbgl::UnassociatedImage({0,0}));
self.rawSource->setImage(mbgl::PremultipliedImage({0,0}));
}
_image = image;
}

View File

@@ -9,11 +9,11 @@ namespace mbgl {
using namespace style;
RasterBucket::RasterBucket(UnassociatedImage&& image_) {
image = std::make_shared<UnassociatedImage>(std::move(image_));
RasterBucket::RasterBucket(PremultipliedImage&& image_) {
image = std::make_shared<PremultipliedImage>(std::move(image_));
}
RasterBucket::RasterBucket(std::shared_ptr<UnassociatedImage> image_): image(image_) {
RasterBucket::RasterBucket(std::shared_ptr<PremultipliedImage> image_): image(image_) {
}
void RasterBucket::upload(gl::Context& context) {
@@ -40,7 +40,7 @@ void RasterBucket::clear() {
uploaded = false;
}
void RasterBucket::setImage(std::shared_ptr<UnassociatedImage> image_) {
void RasterBucket::setImage(std::shared_ptr<PremultipliedImage> image_) {
image = std::move(image_);
texture = {};
uploaded = false;

View File

@@ -13,8 +13,8 @@ namespace mbgl {
class RasterBucket : public Bucket {
public:
RasterBucket(UnassociatedImage&&);
RasterBucket(std::shared_ptr<UnassociatedImage>);
RasterBucket(PremultipliedImage&&);
RasterBucket(std::shared_ptr<PremultipliedImage>);
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
void render(Painter& painter,
@@ -24,8 +24,8 @@ public:
bool hasData() const override;
void clear();
void setImage(std::shared_ptr<UnassociatedImage>);
std::shared_ptr<UnassociatedImage> image;
void setImage(std::shared_ptr<PremultipliedImage>);
std::shared_ptr<PremultipliedImage> image;
optional<gl::Texture> texture;
// Bucket specific vertices are used for Image Sources only

View File

@@ -82,7 +82,7 @@ void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_,
std::swap(baseImpl, baseImpl_);
auto coords = impl().getCoordinates();
std::shared_ptr<UnassociatedImage> image = impl().getImage();
std::shared_ptr<PremultipliedImage> image = impl().getImage();
if (!image || !image->valid()) {
enabled = false;

View File

@@ -45,6 +45,12 @@ void main() {
// read and cross-fade colors from the main and parent tiles
vec4 color0 = texture2D(u_image0, v_pos0);
vec4 color1 = texture2D(u_image1, v_pos1);
if (color0.a > 0.0) {
color0.rgb = color0.rgb / color0.a;
}
if (color1.a > 0.0) {
color1.rgb = color1.rgb / color1.a;
}
vec4 color = mix(color0, color1, u_fade_t);
color.a *= u_opacity;
vec3 rgb = color.rgb;

View File

@@ -37,7 +37,7 @@ void ImageSource::setURL(const std::string& url_) {
}
}
void ImageSource::setImage(UnassociatedImage&& image_) {
void ImageSource::setImage(PremultipliedImage&& image_) {
url = {};
if (req) {
req.reset();
@@ -70,8 +70,7 @@ void ImageSource::loadDescription(FileSource& fileSource) {
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty image url")));
} else {
try {
UnassociatedImage image = util::unpremultiply(decodeImage(*res.data));
baseImpl = makeMutable<Impl>(impl(), std::move(image));
baseImpl = makeMutable<Impl>(impl(), decodeImage(*res.data));
} catch (...) {
observer->onSourceError(*this, std::current_exception());
}

View File

@@ -15,14 +15,14 @@ ImageSource::Impl::Impl(const Impl& other, std::array<LatLng, 4> coords_)
image(other.image) {
}
ImageSource::Impl::Impl(const Impl& rhs, UnassociatedImage&& image_)
ImageSource::Impl::Impl(const Impl& rhs, PremultipliedImage&& image_)
: Source::Impl(rhs),
coords(rhs.coords),
image(std::make_shared<UnassociatedImage>(std::move(image_))) {
image(std::make_shared<PremultipliedImage>(std::move(image_))) {
}
ImageSource::Impl::~Impl() = default;
std::shared_ptr<UnassociatedImage> ImageSource::Impl::getImage() const {
std::shared_ptr<PremultipliedImage> ImageSource::Impl::getImage() const {
return image;
}

View File

@@ -13,17 +13,17 @@ class ImageSource::Impl : public Source::Impl {
public:
Impl(std::string id, std::array<LatLng, 4> coords);
Impl(const Impl& rhs, std::array<LatLng, 4> coords);
Impl(const Impl& rhs, UnassociatedImage&& image);
Impl(const Impl& rhs, PremultipliedImage&& image);
~Impl() final;
std::shared_ptr<UnassociatedImage> getImage() const;
std::shared_ptr<PremultipliedImage> getImage() const;
std::array<LatLng, 4> getCoordinates() const;
optional<std::string> getAttribution() const final;
private:
std::array<LatLng, 4> coords;
std::shared_ptr<UnassociatedImage> image;
std::shared_ptr<PremultipliedImage> image;
};
} // namespace style

View File

@@ -17,7 +17,7 @@ void RasterTileWorker::parse(std::shared_ptr<const std::string> data) {
}
try {
auto bucket = std::make_unique<RasterBucket>(util::unpremultiply(decodeImage(*data)));
auto bucket = std::make_unique<RasterBucket>(decodeImage(*data));
parent.invoke(&RasterTile::onParsed, std::move(bucket));
} catch (...) {
parent.invoke(&RasterTile::onError, std::current_exception());

View File

@@ -101,7 +101,7 @@ TEST(Buckets, SymbolBucket) {
TEST(Buckets, RasterBucket) {
gl::Context context;
UnassociatedImage rgba({ 1, 1 });
PremultipliedImage rgba({ 1, 1 });
// RasterBucket::hasData() is always true.
RasterBucket bucket = { std::move(rgba) };

View File

@@ -531,7 +531,7 @@ TEST(Source, ImageSourceImageUpdate) {
// Load initial, so the source state will be loaded=true
source.loadDescription(test.fileSource);
UnassociatedImage rgba({ 1, 1 });
PremultipliedImage rgba({ 1, 1 });
rgba.data[0] = 255;
rgba.data[1] = 254;
rgba.data[2] = 253;

View File

@@ -60,7 +60,7 @@ TEST(RasterTile, onError) {
TEST(RasterTile, onParsed) {
RasterTileTest test;
RasterTile tile(OverscaledTileID(0, 0, 0), test.tileParameters, test.tileset);
tile.onParsed(std::make_unique<RasterBucket>(UnassociatedImage{}));
tile.onParsed(std::make_unique<RasterBucket>(PremultipliedImage{}));
EXPECT_TRUE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());