OsmAnd/Osmand-kernel/osmand/rendering.cpp
2012-04-30 13:33:05 +02:00

817 lines
27 KiB
C++

#include <jni.h>
#include "osmand_log.h"
#include <dlfcn.h>
#include <math.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <set>
#ifdef LINUX_BUILD
#include <ext/hash_map>
using namespace __gnu_cxx;
#else
#include <hash_map>
#endif
#include <time.h>
#include <SkTypes.h>
#include <SkBitmap.h>
#include <SkColorFilter.h>
#include <SkShader.h>
#include <SkBitmapProcShader.h>
#include <SkPathEffect.h>
#include <SkBlurDrawLooper.h>
#include <SkDashPathEffect.h>
#include <SkCanvas.h>
#include <SkPaint.h>
#include <SkPath.h>
#include "common.h"
#include "renderRules.h"
#include "textdraw.cpp"
#include "mapObjects.h"
jclass jclass_JUnidecode;
jmethodID jmethod_JUnidecode_unidecode;
void calcPoint(std::pair<int, int> c, RenderingContext* rc)
{
rc->pointCount++;
float tx = c.first/ (rc->tileDivisor);
float ty = c.second / (rc->tileDivisor);
float dTileX = tx - rc->leftX;
float dTileY = ty - rc->topY;
rc->calcX = rc->cosRotateTileSize * dTileX - rc->sinRotateTileSize * dTileY;
rc->calcY = rc->sinRotateTileSize * dTileX + rc->cosRotateTileSize * dTileY;
if (rc->calcX >= 0 && rc->calcX < rc->width && rc->calcY >= 0 && rc->calcY < rc->height)
rc->pointInsideCount++;
}
std::hash_map<std::string, SkPathEffect*> pathEffects;
SkPathEffect* getDashEffect(std::string input)
{
if(pathEffects.find(input) != pathEffects.end())
return pathEffects[input];
const char* chars = input.c_str();
int i = 0;
char fval[10];
int flength = 0;
float primFloats[20];
int floatLen = 0;
for(;;i++)
{
if(chars[i] == 0)
{
if(flength > 0) { fval[flength] = 0;
primFloats[floatLen++] = atof(fval); flength = 0;}
break;
}
else
{
if(chars[i] != '_')
{
// suppose it is a character
fval[flength++] = chars[i];
}
else
{
if(flength > 0)
{
fval[flength] = 0;
primFloats[floatLen++] = atof(fval); flength = 0;
}
}
}
}
SkPathEffect* r = new SkDashPathEffect(primFloats, floatLen, 0);
pathEffects[input] = r;
return r;
}
int updatePaint(RenderingRuleSearchRequest* req, SkPaint* paint, int ind, int area, RenderingContext* rc)
{
RenderingRuleProperty* rColor;
RenderingRuleProperty* rStrokeW;
RenderingRuleProperty* rCap;
RenderingRuleProperty* rPathEff;
if (ind == 0)
{
rColor = req->props()->R_COLOR;
rStrokeW = req->props()->R_STROKE_WIDTH;
rCap = req->props()->R_CAP;
rPathEff = req->props()->R_PATH_EFFECT;
}
else if (ind == 1)
{
rColor = req->props()->R_COLOR_2;
rStrokeW = req->props()->R_STROKE_WIDTH_2;
rCap = req->props()->R_CAP_2;
rPathEff = req->props()->R_PATH_EFFECT_2;
}
else
{
rColor = req->props()->R_COLOR_3;
rStrokeW = req->props()->R_STROKE_WIDTH_3;
rCap = req->props()->R_CAP_3;
rPathEff = req->props()->R_PATH_EFFECT_3;
}
paint->setColorFilter(NULL);
paint->setShader(NULL);
paint->setLooper(NULL);
if (area)
{
paint->setStyle(SkPaint::kStrokeAndFill_Style);
paint->setStrokeWidth(0);
}
else
{
float stroke = req->getFloatPropertyValue(rStrokeW);
if (!(stroke > 0))
return 0;
paint->setStyle(SkPaint::kStroke_Style);
paint->setStrokeWidth(stroke);
std::string cap = req->getStringPropertyValue(rCap);
std::string pathEff = req->getStringPropertyValue(rPathEff);
if (cap == "BUTT" || cap == "")
paint->setStrokeCap(SkPaint::kButt_Cap);
else if (cap == "ROUND")
paint->setStrokeCap(SkPaint::kRound_Cap);
else if (cap == "SQUARE")
paint->setStrokeCap(SkPaint::kSquare_Cap);
else
paint->setStrokeCap(SkPaint::kButt_Cap);
if (pathEff.size() > 0)
{
SkPathEffect* p = getDashEffect(pathEff);
paint->setPathEffect(p);
}
else
{
paint->setPathEffect(NULL);
}
}
int color = req->getIntPropertyValue(rColor);
paint->setColor(color);
if (ind == 0)
{
std::string shader = req->getStringPropertyValue(req->props()->R_SHADER);
if (shader.size() > 0)
{
SkBitmap* bmp = getCachedBitmap(rc, shader);
if (bmp != NULL)
paint->setShader(new SkBitmapProcShader(*bmp, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode))->unref();
}
}
// do not check shadow color here
if (rc->shadowRenderingMode == 1 && ind == 0)
{
int shadowColor = req->getIntPropertyValue(req->props()->R_SHADOW_COLOR);
int shadowLayer = req->getIntPropertyValue(req->props()->R_SHADOW_RADIUS);
if (shadowColor == 0)
shadowLayer = 0;
if (shadowLayer > 0)
paint->setLooper(new SkBlurDrawLooper(shadowLayer, 0, 0, shadowColor))->unref();
}
return 1;
}
void renderText(MapDataObject* obj, RenderingRuleSearchRequest* req, RenderingContext* rc, std::string tag,
std::string value, float xText, float yText, SkPath* path) {
hash_map<std::string, std::string>::iterator it = obj->objectNames.begin();
while (it != obj->objectNames.end()) {
if (it->second.length() > 0) {
std::string name = it->second;
if (rc->useEnglishNames) {
jstring n = rc->env->NewStringUTF(name.c_str());
name = getString(rc->env,
(jstring) rc->env->CallStaticObjectMethod(jclass_JUnidecode,
jmethod_JUnidecode_unidecode, n));
rc->env->DeleteLocalRef(n);
}
req->setInitialTagValueZoom(tag, value, rc->zoom, obj);
req->setIntFilter(req->props()->R_TEXT_LENGTH, name.length());
std::string tagName = it->first == "name" ? "" : it->first;
req->setStringFilter(req->props()->R_NAME_TAG, tagName);
if (req->searchRule(RenderingRulesStorage::TEXT_RULES)
&& req->getIntPropertyValue(req->props()->R_TEXT_SIZE) > 0) {
TextDrawInfo* info = new TextDrawInfo(name);
info->drawOnPath = (path != NULL) && (req->getIntPropertyValue(req->props()->R_TEXT_ON_PATH, 0) > 0);
if (path != NULL)
info->path = new SkPath(*path);
fillTextProperties(info, req, xText, yText);
rc->textToDraw.push_back(info);
}
}
it++;
}
}
void drawPolylineShadow(SkCanvas* cv, SkPaint* paint, RenderingContext* rc, SkPath* path, int shadowColor, int shadowRadius)
{
// blurred shadows
if (rc->shadowRenderingMode == 2 && shadowRadius > 0) {
// simply draw shadow? difference from option 3 ?
// paint->setColor(0xffffffff);
paint->setLooper(new SkBlurDrawLooper(shadowRadius, 0, 0, shadowColor))->unref();
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*path, *paint));
}
// option shadow = 3 with solid border
if (rc->shadowRenderingMode == 3 && shadowRadius > 0) {
paint->setLooper(NULL);
paint->setStrokeWidth(paint->getStrokeWidth() + shadowRadius * 2);
// paint->setColor(0xffbababa);
paint->setColorFilter(SkColorFilter::CreateModeFilter(shadowColor, SkXfermode::kSrcIn_Mode))->unref();
// paint->setColor(shadowColor);
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*path, *paint));
}
}
std::vector<SkPaint> oneWayPaints;
SkPaint* oneWayPaint(){
SkPaint* oneWay = new SkPaint;
oneWay->setStyle(SkPaint::kStroke_Style);
oneWay->setColor(0xff6c70d5);
oneWay->setAntiAlias(true);
return oneWay;
}
void drawOneWayPaints(RenderingContext* rc, SkCanvas* cv, SkPath* p) {
if (oneWayPaints.size() == 0) {
SkPathEffect* arrowDashEffect1 = new SkDashPathEffect((float []){ 0, 12, 10, 152 }, 4, 0);
SkPathEffect* arrowDashEffect2 = new SkDashPathEffect((float[]){ 0, 12, 9, 153 }, 4, 1);
SkPathEffect* arrowDashEffect3 = new SkDashPathEffect((float[]){ 0, 18, 2, 154 }, 4, 1);
SkPathEffect* arrowDashEffect4 = new SkDashPathEffect((float[]){ 0, 18, 1, 155 }, 4, 1);
SkPaint* p = oneWayPaint();
p->setStrokeWidth(1);
p->setPathEffect(arrowDashEffect1)->unref();
oneWayPaints.push_back(*p);
p = oneWayPaint();
p->setStrokeWidth(2);
p->setPathEffect(arrowDashEffect2)->unref();
oneWayPaints.push_back(*p);
p = oneWayPaint();
p->setStrokeWidth(3);
p->setPathEffect(arrowDashEffect3)->unref();
oneWayPaints.push_back(*p);
p = oneWayPaint();
p->setStrokeWidth(4);
p->setPathEffect(arrowDashEffect4)->unref();
oneWayPaints.push_back(*p);
}
for (size_t i = 0; i < oneWayPaints.size(); i++) {
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*p, oneWayPaints.at(i)));
}
}
void drawPolyline(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* cv, SkPaint* paint,
RenderingContext* rc, tag_value pair, int layer, int drawOnlyShadow) {
jint length = mObj->points.size();
if (length < 2) {
return;
}
std::string tag = pair.first;
std::string value = pair.second;
req->setInitialTagValueZoom(tag, value, rc->zoom, mObj);
req->setIntFilter(req->props()->R_LAYER, layer);
bool rendered = req->searchRule(2);
if (!rendered || !updatePaint(req, paint, 0, 0, rc)) {
return;
}
int oneway = 0;
if (rc->zoom >= 16 && pair.first == "highway") {
if (mObj->containsAdditional("oneway", "yes")) {
oneway = 1;
} else if (mObj->containsAdditional("oneway", "-1")) {
oneway = -1;
}
}
rc->visible++;
SkPath path;
int i = 0;
SkPoint middlePoint;
int middle = length / 2;
for (; i < length; i++) {
calcPoint(mObj->points.at(i), rc);
if (i == 0) {
path.moveTo(rc->calcX, rc->calcY);
} else {
if (i == middle) {
middlePoint.set(rc->calcX, rc->calcY);
}
path.lineTo(rc->calcX, rc->calcY);
}
}
if (i > 0) {
if (drawOnlyShadow) {
int shadowColor = req->getIntPropertyValue(req->props()->R_SHADOW_COLOR);
int shadowRadius = req->getIntPropertyValue(req->props()->R_SHADOW_RADIUS);
drawPolylineShadow(cv, paint, rc, &path, shadowColor, shadowRadius);
} else {
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
if (updatePaint(req, paint, 1, 0, rc)) {
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
if (updatePaint(req, paint, 2, 0, rc)) {
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
}
}
if (oneway && !drawOnlyShadow) {
drawOneWayPaints(rc, cv, &path);
}
if (!drawOnlyShadow) {
renderText(mObj, req, rc, pair.first, pair.second, middlePoint.fX, middlePoint.fY, &path);
}
}
}
}
void drawPolygon(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* cv, SkPaint* paint,
RenderingContext* rc, tag_value pair) {
jint length = mObj->points.size();
if (length <= 2) {
return;
}
std::string tag = pair.first;
std::string value = pair.second;
req->setInitialTagValueZoom(tag, value, rc->zoom, mObj);
bool rendered = req->searchRule(3);
float xText = 0;
float yText = 0;
if (!rendered || !updatePaint(req, paint, 0, 1, rc)) {
return;
}
rc->visible++;
SkPath path;
int i = 0;
for (; i < length; i++) {
calcPoint(mObj->points.at(i), rc);
if (i == 0) {
path.moveTo(rc->calcX, rc->calcY);
} else {
path.lineTo(rc->calcX, rc->calcY);
}
xText += rc->calcX;
yText += rc->calcY;
}
std::vector<coordinates> polygonInnerCoordinates = mObj->polygonInnerCoordinates;
if (polygonInnerCoordinates.size() > 0) {
path.setFillType(SkPath::kEvenOdd_FillType);
for (int j = 0; j < polygonInnerCoordinates.size(); j++) {
coordinates cs = polygonInnerCoordinates.at(j);
for (int i = 0; i < cs.size(); i++) {
calcPoint(cs[i], rc);
if (i == 0) {
path.moveTo(rc->calcX, rc->calcY);
} else {
path.lineTo(rc->calcX, rc->calcY);
}
}
}
}
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
if (updatePaint(req, paint, 1, 0, rc)) {
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
}
renderText(mObj, req, rc, pair.first, pair.second, xText / length, yText / length, NULL);
}
void drawPoint(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* cv, SkPaint* paint,
RenderingContext* rc, std::pair<std::string, std::string> pair, int renderTxt)
{
std::string tag = pair.first;
std::string value = pair.second;
req->setInitialTagValueZoom(tag, value, rc->zoom, mObj);
req->searchRule(1);
std::string resId = req->getStringPropertyValue(req-> props()-> R_ICON);
SkBitmap* bmp = getCachedBitmap(rc, resId);
if (!bmp && !renderText)
return;
jint length = mObj->points.size();
rc->visible++;
float px = 0;
float py = 0;
int i = 0;
for (; i < length; i++) {
calcPoint(mObj->points.at(i), rc);
px += rc->calcX;
py += rc->calcY;
}
if (length > 1) {
px /= length;
py /= length;
}
if (bmp != NULL) {
IconDrawInfo ico;
ico.x = px;
ico.y = py;
ico.bmp = bmp;
rc->iconsToDraw.push_back(ico);
}
if (renderTxt) {
renderText(mObj, req, rc, pair.first, pair.second, px, py, NULL);
}
}
void drawObject(RenderingContext* rc, MapDataObject* mObj, SkCanvas* cv, RenderingRuleSearchRequest* req,
SkPaint* paint, int l, int renderText, int drawOnlyShadow) {
rc->allObjects++;
int t = mObj->objectType;
tag_value pair = mObj->types.at(l);
if (t == 1 && !drawOnlyShadow) {
// point
drawPoint(mObj, req, cv, paint, rc, pair, renderText);
} else if (t == 2) {
drawPolyline(mObj, req, cv, paint, rc, pair, mObj->getSimpleLayer(), drawOnlyShadow);
} else if (t == 3 && !drawOnlyShadow) {
// polygon
drawPolygon(mObj, req, cv, paint, rc, pair);
}
}
void drawIconsOverCanvas(RenderingContext* rc, SkCanvas* canvas)
{
int skewConstant = (int) getDensityValue(rc, 16);
int iconsW = rc -> width / skewConstant;
int iconsH = rc -> height / skewConstant;
int len = (iconsW * iconsH) / 32;
int alreadyDrawnIcons[len];
memset(alreadyDrawnIcons, 0, sizeof(int)*len);
size_t ji = 0;
SkPaint p;
p.setStyle(SkPaint::kStroke_Style);
for(;ji< rc->iconsToDraw.size(); ji++)
{
IconDrawInfo icon = rc->iconsToDraw.at(ji);
if (icon.y >= 0 && icon.y < rc -> height && icon.x >= 0 && icon.x < rc -> width &&
icon.bmp != NULL) {
int z = (((int) icon.x / skewConstant) + ((int) icon.y / skewConstant) * iconsW);
int i = z / 32;
if (i >= len) {
continue;
}
int ind = alreadyDrawnIcons[i];
int b = z % 32;
// check bit b if it is set
if (((ind >> b) & 1) == 0) {
alreadyDrawnIcons[i] = ind | (1 << b);
SkBitmap* ico = icon.bmp;
if(rc->highResMode) {
float left = icon.x - getDensityValue(rc, ico->width() / 2);
float top = icon.y - getDensityValue(rc, ico->height() / 2);
SkRect r = SkRect::MakeXYWH(left, top, getDensityValue(rc, ico->width()), getDensityValue(rc, ico->height()));
PROFILE_NATIVE_OPERATION(rc, canvas->drawBitmapRect(*ico, (SkIRect*) NULL, r, &p));
} else {
PROFILE_NATIVE_OPERATION(rc, canvas->drawBitmap(*ico, icon.x - ico->width() / 2, icon.y - ico->height() / 2, &p));
}
}
}
if(rc->interrupted()){
return;
}
}
}
std::hash_map<int, std::vector<int> > sortObjectsByProperOrder(std::vector <MapDataObject* > mapDataObjects,
RenderingRuleSearchRequest* req, RenderingContext* rc) {
std::hash_map<int, std::vector<int> > orderMap;
if (req != NULL) {
req->clearState();
const int size = mapDataObjects.size();
int i = 0;
for (; i < size; i++) {
uint sh = i << 8;
MapDataObject* mobj = mapDataObjects[i];
size_t sizeTypes = mobj->types.size();
size_t j = 0;
for (; j < sizeTypes; j++) {
int layer = mobj->getSimpleLayer();
tag_value pair = mobj->types[j];
req->setTagValueZoomLayer(pair.first, pair.second, rc->zoom, layer, mobj);
req->setIntFilter(req->props()->R_AREA, mobj->area);
req->setIntFilter(req->props()->R_POINT, mobj->points.size() == 1);
req->setIntFilter(req->props()->R_CYCLE, mobj->cycle());
if (req->searchRule(RenderingRulesStorage::ORDER_RULES)) {
mobj->objectType = req->getIntPropertyValue(req->props()->R_OBJECT_TYPE);
int order = req->getIntPropertyValue(req->props()->R_ORDER);
orderMap[order].push_back(sh + j);
if (req->getIntPropertyValue(req->props()->R_SHADOW_LEVEL) > 0) {
rc->shadowLevelMin = std::min(rc->shadowLevelMin, order);
rc->shadowLevelMax = std::max(rc->shadowLevelMax, order);
req->clearIntvalue(req->props()->R_SHADOW_LEVEL);
}
}
}
}
}
return orderMap;
}
void doRendering(std::vector <MapDataObject* > mapDataObjects, SkCanvas* canvas, SkPaint* paint,
RenderingRuleSearchRequest* req, RenderingContext* rc) {
// put in order map
hash_map<int, std::vector<int> > orderMap = sortObjectsByProperOrder(mapDataObjects, req, rc);
std::set<int> keys;
hash_map<int, std::vector<int> >::iterator it = orderMap.begin();
while(it != orderMap.end())
{
keys.insert(it->first);
it++;
}
bool shadowDrawn = false;
for (std::set<int>::iterator ks = keys.begin(); ks != keys.end() ; ks++) {
if (!shadowDrawn && *ks >= rc->shadowLevelMin && *ks <= rc->shadowLevelMax &&
rc->shadowRenderingMode > 1) {
for (std::set<int>::iterator ki = ks; ki != keys.end() ; ki++) {
if (*ki > rc->shadowLevelMax || rc->interrupted()) {
break;
}
std::vector<int> list = orderMap[*ki];
for (std::vector<int>::iterator ls = list.begin(); ls != list.end(); ls++) {
int i = *ls;
int ind = i >> 8;
int l = i & 0xff;
MapDataObject* mapObject = mapDataObjects.at(ind);
// show text only for main type
drawObject(rc, mapObject, canvas, req, paint, l, l == 0, true);
}
}
shadowDrawn = true;
}
std::vector<int> list = orderMap[*ks];
for (std::vector<int>::iterator ls = list.begin(); ls != list.end(); ls++) {
int i = *ls;
int ind = i >> 8;
int l = i & 0xff;
MapDataObject* mapObject = mapDataObjects.at(ind);
// show text only for main type
drawObject(rc, mapObject, canvas, req, paint, l, l == 0, false);
}
rc->lastRenderedKey = *ks;
if (rc->interrupted()) {
return;
}
}
drawIconsOverCanvas(rc, canvas);
rc->textRendering.start();
drawTextOverCanvas(rc, canvas);
rc->textRendering.pause();
}
void loadJniRendering(JNIEnv* env)
{
jclass_JUnidecode = findClass(env, "net/sf/junidecode/Junidecode");
jmethod_JUnidecode_unidecode = env->GetStaticMethodID(jclass_JUnidecode, "unidecode", "(Ljava/lang/String;)Ljava/lang/String;");
}
#ifdef ANDROID_BUILD
#include <android/bitmap.h>
extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering_1Direct( JNIEnv* ienv, jobject obj,
jobject renderingContext, jint searchResult,
jobject targetBitmap,
jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) {
// libJniGraphics interface
typedef int (*PTR_AndroidBitmap_getInfo)(JNIEnv*, jobject, AndroidBitmapInfo*);
typedef int (*PTR_AndroidBitmap_lockPixels)(JNIEnv*, jobject, void**);
typedef int (*PTR_AndroidBitmap_unlockPixels)(JNIEnv*, jobject);
static PTR_AndroidBitmap_getInfo dl_AndroidBitmap_getInfo = 0;
static PTR_AndroidBitmap_lockPixels dl_AndroidBitmap_lockPixels = 0;
static PTR_AndroidBitmap_unlockPixels dl_AndroidBitmap_unlockPixels = 0;
static void* module_libjnigraphics = 0;
if(!module_libjnigraphics)
{
module_libjnigraphics = dlopen("jnigraphics", /*RTLD_NOLOAD*/0x0004);
if(!module_libjnigraphics) {
osmand_log_print(LOG_WARN, "jnigraphics was not found in loaded libraries");
module_libjnigraphics = dlopen("jnigraphics", RTLD_NOW);
}
if(!module_libjnigraphics) {
osmand_log_print(LOG_WARN, "jnigraphics was not loaded in default location");
module_libjnigraphics = dlopen("/system/lib/libjnigraphics.so", RTLD_NOW);
}
if(!module_libjnigraphics)
{
osmand_log_print(LOG_ERROR, "Failed to load jnigraphics via dlopen, will going to crash");
return NULL;
}
dl_AndroidBitmap_getInfo = (PTR_AndroidBitmap_getInfo)dlsym(module_libjnigraphics, "AndroidBitmap_getInfo");
dl_AndroidBitmap_lockPixels = (PTR_AndroidBitmap_lockPixels)dlsym(module_libjnigraphics, "AndroidBitmap_lockPixels");
dl_AndroidBitmap_unlockPixels = (PTR_AndroidBitmap_unlockPixels)dlsym(module_libjnigraphics, "AndroidBitmap_unlockPixels");
}
// Gain information about bitmap
AndroidBitmapInfo bitmapInfo;
if(dl_AndroidBitmap_getInfo(ienv, targetBitmap, &bitmapInfo) != ANDROID_BITMAP_RESUT_SUCCESS)
osmand_log_print(LOG_ERROR, "Failed to execute AndroidBitmap_getInfo");
osmand_log_print(LOG_INFO, "Creating SkBitmap in native w:%d h:%d s:%d f:%d!", bitmapInfo.width, bitmapInfo.height, bitmapInfo.stride, bitmapInfo.format);
SkBitmap* bitmap = new SkBitmap();
if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
int rowBytes = bitmapInfo.stride;
osmand_log_print(LOG_INFO, "Row bytes for RGBA_8888 is %d", rowBytes);
bitmap->setConfig(SkBitmap::kARGB_8888_Config, bitmapInfo.width, bitmapInfo.height, rowBytes);
} else if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565) {
int rowBytes = bitmapInfo.stride;
osmand_log_print(LOG_INFO, "Row bytes for RGB_565 is %d", rowBytes);
bitmap->setConfig(SkBitmap::kRGB_565_Config, bitmapInfo.width, bitmapInfo.height, rowBytes);
} else {
osmand_log_print(LOG_ERROR, "Unknown target bitmap format");
}
void* lockedBitmapData = NULL;
if(dl_AndroidBitmap_lockPixels(ienv, targetBitmap, &lockedBitmapData) != ANDROID_BITMAP_RESUT_SUCCESS || !lockedBitmapData) {
osmand_log_print(LOG_ERROR, "Failed to execute AndroidBitmap_lockPixels");
}
osmand_log_print(LOG_INFO, "Locked %d bytes at %p", bitmap->getSize(), lockedBitmapData);
bitmap->setPixels(lockedBitmapData);
SkCanvas* canvas = new SkCanvas(*bitmap);
canvas->drawColor(defaultColor);
SkPaint* paint = new SkPaint;
paint->setAntiAlias(true);
osmand_log_print(LOG_INFO, "Initializing rendering");
ElapsedTimer initObjects;
initObjects.start();
RenderingRuleSearchRequest* req = initSearchRequest(ienv, renderingRuleSearchRequest);
RenderingContext rc;
pullFromJavaRenderingContext(ienv, renderingContext, &rc);
rc.useEnglishNames = useEnglishNames;
SearchResult* result = ((SearchResult*) searchResult);
// std::vector <BaseMapDataObject* > mapDataObjects = marshalObjects(binaryMapDataObjects);
osmand_log_print(LOG_INFO, "Rendering image");
initObjects.pause();
// Main part do rendering
rc.nativeOperations.start();
if(result != NULL) {
doRendering(result->result, canvas, paint, req, &rc);
}
rc.nativeOperations.pause();
pushToJavaRenderingContext(ienv, renderingContext, &rc);
osmand_log_print(LOG_INFO, "End Rendering image");
if(dl_AndroidBitmap_unlockPixels(ienv, targetBitmap) != ANDROID_BITMAP_RESUT_SUCCESS) {
osmand_log_print(LOG_ERROR, "Failed to execute AndroidBitmap_unlockPixels");
}
// delete variables
delete paint;
delete canvas;
delete req;
delete bitmap;
// deleteObjects(mapDataObjects);
jclass resultClass = findClass(ienv, "net/osmand/plus/render/NativeOsmandLibrary$RenderingGenerationResult");
jmethodID resultClassCtorId = ienv->GetMethodID(resultClass, "<init>", "(Ljava/nio/ByteBuffer;)V");
#ifdef DEBUG_NAT_OPERATIONS
osmand_log_print(LOG_INFO, LOG_TAG,"Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
#else
osmand_log_print(LOG_INFO, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
#endif
/* Construct a result object */
jobject resultObject = ienv->NewObject(resultClass, resultClassCtorId, NULL);
return resultObject;
}
#endif
void* bitmapData = NULL;
size_t bitmapDataSize = 0;
extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering_1Indirect( JNIEnv* ienv, jobject obj,
jobject renderingContext, jint searchResult,
jint requestedBitmapWidth, jint requestedBitmapHeight, jint rowBytes, jboolean isTransparent,
jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) {
osmand_log_print(LOG_INFO, "Creating SkBitmap in native w:%d h:%d!", requestedBitmapWidth, requestedBitmapHeight);
SkBitmap* bitmap = new SkBitmap();
if(isTransparent == JNI_TRUE)
bitmap->setConfig(SkBitmap::kARGB_8888_Config, requestedBitmapWidth, requestedBitmapHeight, rowBytes);
else
bitmap->setConfig(SkBitmap::kRGB_565_Config, requestedBitmapWidth, requestedBitmapHeight, rowBytes);
if(bitmapData != NULL && bitmapDataSize != bitmap->getSize()) {
free(bitmapData);
bitmapData = NULL;
bitmapDataSize = 0;
}
if(bitmapData == NULL && bitmapDataSize == 0) {
bitmapDataSize = bitmap->getSize();
bitmapData = malloc(bitmapDataSize);
osmand_log_print(LOG_INFO, "Allocated %d bytes at %p", bitmapDataSize, bitmapData);
}
bitmap->setPixels(bitmapData);
SkCanvas* canvas = new SkCanvas(*bitmap);
canvas->drawColor(defaultColor);
SkPaint* paint = new SkPaint;
paint->setAntiAlias(true);
osmand_log_print(LOG_INFO, "Initializing rendering");
ElapsedTimer initObjects;
initObjects.start();
RenderingRuleSearchRequest* req = initSearchRequest(ienv, renderingRuleSearchRequest);
RenderingContext rc;
pullFromJavaRenderingContext(ienv, renderingContext, &rc);
rc.useEnglishNames = useEnglishNames;
SearchResult* result = ((SearchResult*) searchResult);
// std::vector <BaseMapDataObject* > mapDataObjects = marshalObjects(binaryMapDataObjects);
osmand_log_print(LOG_INFO, "Rendering image");
initObjects.pause();
// Main part do rendering
rc.nativeOperations.start();
if(result != NULL) {
doRendering(result->result, canvas, paint, req, &rc);
}
rc.nativeOperations.pause();
pushToJavaRenderingContext(ienv, renderingContext, &rc);
osmand_log_print(LOG_INFO, "End Rendering image");
// delete variables
delete paint;
delete canvas;
delete req;
delete bitmap;
// deleteObjects(mapDataObjects);
jclass resultClass = findClass(ienv, "net/osmand/plus/render/NativeOsmandLibrary$RenderingGenerationResult");
jmethodID resultClassCtorId = ienv->GetMethodID(resultClass, "<init>", "(Ljava/nio/ByteBuffer;)V");
#ifdef DEBUG_NAT_OPERATIONS
osmand_log_print(LOG_INFO, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
#else
osmand_log_print(LOG_INFO, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
#endif
// Allocate ctor paramters
jobject bitmapBuffer = ienv->NewDirectByteBuffer(bitmapData, bitmap->getSize());
/* Construct a result object */
jobject resultObject = ienv->NewObject(resultClass, resultClassCtorId, bitmapBuffer);
return resultObject;
}