JNI rendering impl

This commit is contained in:
Victor Shcherb 2012-05-10 00:32:17 +02:00
parent d44b535574
commit a6da67223e
7 changed files with 318 additions and 38 deletions

View file

@ -1,5 +1,10 @@
package net.osmand;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class RenderingContext {
static enum ShadowRenderingMode {
// int shadowRenderingMode = 0; // no shadow (minumum CPU)
@ -13,6 +18,7 @@ public class RenderingContext {
this.value = v;
}
}
private File iconsBaseDir;
// FIELDS OF THAT CLASS ARE USED IN C++
public boolean interrupted = false;
@ -23,6 +29,11 @@ public class RenderingContext {
public RenderingContext() {
}
public RenderingContext(File iconsBaseDir){
this.iconsBaseDir = iconsBaseDir;
}
public float leftX;
public float topY;
public int width;
@ -61,6 +72,27 @@ public class RenderingContext {
}
protected byte[] getIconRawData(String data) {
if(iconsBaseDir != null) {
File fs = new File(iconsBaseDir+"/h_"+data+".png");
if(!fs.exists()) {
fs = new File(iconsBaseDir+"/g_"+data+".png");
}
if (fs.exists()) {
try {
byte[] dta = new byte[(int) fs.length()];
FileInputStream fis = new FileInputStream(fs);
int l = fis.read(dta);
fis.close();
if (l == dta.length) {
return dta;
} else {
System.err.println("Read data " + l + " however was expected " + dta.length + " for " + data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}

View file

@ -64,6 +64,9 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
private static final long serialVersionUID = 1L;
private static final int EXPAND_X = 100;
private static final int EXPAND_Y = 100;
protected static final Log log = LogUtil.getLog(MapPanel.class);
public static final int divNonLoadedImage = 16;
@ -202,14 +205,11 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
public static void main(String[] args) throws IOException {
LatLon def = DataExtractionSettings.getSettings().getDefaultLocation();
showMainWindow(512, 512, def.getLatitude(), def.getLongitude(),
DataExtractionSettings.getSettings().getDefaultZoom(), null);
showMainWindow(512, 512, null);
}
public static void showMainWindow(int wx, int hy,
double latitude, double longitude, int zoom, NativeSwingRendering nativeLib) {
public static MapPanel showMainWindow(int wx, int hy, NativeSwingRendering nativeLib) {
JFrame frame = new JFrame(Messages.getString("MapPanel.MAP.VIEW")); //$NON-NLS-1$
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
@ -219,9 +219,9 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
final MapPanel panel = new MapPanel(DataExtractionSettings.getSettings().getTilesDirectory());
panel.nativeLibRendering = nativeLib;
panel.longitude = longitude;
panel.latitude = latitude;
panel.zoom = zoom;
// panel.longitude = longitude;
// panel.latitude = latitude;
// panel.zoom = zoom;
frame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
@ -238,9 +238,8 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
bar.add(getMenuToChooseSource(panel));
frame.setJMenuBar(bar);
frame.setSize(wx, hy);
NativeRendererRunnable runable = panel.new NativeRendererRunnable(512, 512);
runable.run();
// frame.setVisible(true);
frame.setVisible(true);
return panel;
}
private File tilesLocation = null;
@ -251,6 +250,8 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
private NativeSwingRendering nativeLibRendering;
private NativeRendererRunnable lastAddedRunnable;
private Image nativeRenderingImg;
private LatLon nativeLatLon;
private int nativeZoom;
private ThreadPoolExecutor nativeRenderer = new ThreadPoolExecutor(1, 1, 30, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(1));
@ -367,7 +368,14 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
@Override
protected void paintComponent(Graphics g) {
if(nativeLibRendering != null) {
g.drawImage(nativeRenderingImg, 0, 0, this);
// TODO : 1. zoom scale 2. extend margin (these are center positions)
if (zoom == nativeZoom) {
int shx = (int) ((-MapUtils.getTileNumberX(zoom, longitude) + MapUtils.getTileNumberX(zoom, nativeLatLon.getLongitude())) * getTileSize());
int shy = (int) ((-MapUtils.getTileNumberY(zoom, latitude) + MapUtils.getTileNumberY(zoom, nativeLatLon.getLatitude())) * getTileSize());
shx -= EXPAND_X;
shy -= EXPAND_Y;
g.drawImage(nativeRenderingImg, shx, shy, this);
}
} else if (images != null) {
for (int i = 0; i < images.length; i++) {
for (int j = 0; j < images[i].length; j++) {
@ -490,18 +498,23 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
public void prepareImage(){
if(nativeLibRendering != null) {
prepareNativeImage();
} else {
prepareRasterImage(DataExtractionSettings.getSettings().useInternetToLoadImages());
}
}
private synchronized void prepareNativeImage() {
nativeRenderer.getQueue().clear();
NativeRendererRunnable runnable = new NativeRendererRunnable(getWidth(), getHeight());
if(lastAddedRunnable == null || !lastAddedRunnable.contains(runnable)) {
lastAddedRunnable = runnable;
nativeRenderer.getQueue().clear();
nativeRenderer.execute(runnable);
}
for(MapPanelLayer l : layers){
l.prepareToDraw();
}
repaint();
}
@ -860,19 +873,20 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
private int stop;
private int sbottom;
private int z;
private int EXPAND_X = 100;
private int EXPAND_Y = 100;
private LatLon latLon;
private final int cf;
public NativeRendererRunnable(int w, int h) {
int tileSize = getTileSize();
latLon = new LatLon(latitude, longitude);
this.z = zoom;
cf = (1 << (31 - zoom)) / tileSize;
sleft = MapUtils.get31TileNumberX(longitude) - (w / 2) * cf;
sright = MapUtils.get31TileNumberX(longitude) + (w / 2) * cf;
stop = MapUtils.get31TileNumberY(latitude) - (h / 2) * cf;
sbottom = MapUtils.get31TileNumberY(latitude) + (h / 2) * cf;
cf = (1 << (31 - z)) / tileSize;
sleft = MapUtils.get31TileNumberX(latLon.getLongitude()) - (w / 2) * cf;
sright = MapUtils.get31TileNumberX(latLon.getLongitude()) + (w / 2) * cf;
stop = MapUtils.get31TileNumberY(latLon.getLatitude()) - (h / 2) * cf;
sbottom = MapUtils.get31TileNumberY(latLon.getLatitude()) + (h / 2) * cf;
}
public boolean contains(NativeRendererRunnable r) {
if(r.sright > sright + EXPAND_X * cf ||
r.sleft < sleft - EXPAND_X * cf ||
@ -880,6 +894,9 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
r.sbottom > sbottom + EXPAND_Y * cf) {
return false;
}
if(r.z != z){
return false;
}
return true;
}
@ -889,7 +906,10 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
public void run() {
if (nativeRenderer.getQueue().isEmpty()) {
try {
nativeRenderingImg = nativeLibRendering.renderImage(sleft, sright, stop, sbottom, z);
nativeRenderingImg = nativeLibRendering.renderImage(sleft - EXPAND_X * cf,
sright + EXPAND_X * cf, stop - EXPAND_Y * cf, sbottom + EXPAND_Y * cf, z);
nativeLatLon = latLon;
nativeZoom = z;
} catch (IOException e) {
e.printStackTrace();
}

View file

@ -0,0 +1,190 @@
package net.osmand.swing;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.osmand.data.preparation.MapZooms;
public class NativePreferencesDialog extends JDialog {
private static final long serialVersionUID = -4862884032977071296L;
private JButton okButton;
private JButton cancelButton;
private JTextField nativeFilesDirectory;
private JTextField renderingStyleFile;
private JTextField nativeLibFile;
public NativePreferencesDialog(Component parent){
super(JOptionPane.getFrameForComponent(parent), true);
setTitle(Messages.getString("OsmExtractionPreferencesDialog.PREFERENCES")); //$NON-NLS-1$
initDialog();
}
public void showDialog(){
setSize(700, 380);
double x = getParent().getBounds().getCenterX();
double y = getParent().getBounds().getCenterY();
setLocation((int) x - getWidth() / 2, (int) y - getHeight() / 2);
setVisible(true);
}
private void initDialog() {
JPanel pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10));
add(pane);
createGeneralSection(pane);
pane.add(Box.createVerticalGlue());
FlowLayout l = new FlowLayout(FlowLayout.RIGHT);
JPanel buttonsPane = new JPanel(l);
okButton = new JButton(Messages.getString("OsmExtractionPreferencesDialog.OK")); //$NON-NLS-1$
buttonsPane.add(okButton);
cancelButton = new JButton(Messages.getString("OsmExtractionPreferencesDialog.CANCEL")); //$NON-NLS-1$
buttonsPane.add(cancelButton);
buttonsPane.setMaximumSize(new Dimension(Short.MAX_VALUE, (int) l.preferredLayoutSize(buttonsPane).getHeight()));
pane.add(buttonsPane);
addListeners();
}
private void createGeneralSection(JPanel root) {
JPanel panel = new JPanel();
// panel.setLayout(new GridLayout(3, 1, 5, 5));
GridBagLayout l = new GridBagLayout();
panel.setLayout(l);
panel.setBorder(BorderFactory.createTitledBorder(Messages.getString("OsmExtractionPreferencesDialog.GENERAL"))); //$NON-NLS-1$
root.add(panel);
JLabel label = new JLabel("Directory with binary files : ");
panel.add(label);
GridBagConstraints constr = new GridBagConstraints();
constr.ipadx = 5;
constr.gridx = 0;
constr.gridy = 1;
constr.anchor = GridBagConstraints.WEST;
l.setConstraints(label, constr);
nativeFilesDirectory = new JTextField();
nativeFilesDirectory.setText(DataExtractionSettings.getSettings().getDefaultWorkingDir().getAbsolutePath());
panel.add(nativeFilesDirectory);
constr = new GridBagConstraints();
constr.weightx = 1;
constr.fill = GridBagConstraints.HORIZONTAL;
constr.ipadx = 5;
constr.gridx = 1;
constr.gridy = 1;
l.setConstraints(nativeFilesDirectory, constr);
label = new JLabel("City admin level : ");
panel.add(label);
constr = new GridBagConstraints();
constr.ipadx = 5;
constr.gridx = 0;
constr.gridy = 2;
constr.anchor = GridBagConstraints.WEST;
l.setConstraints(label, constr);
nativeLibFile = new JTextField();
nativeLibFile.setText(DataExtractionSettings.getSettings().getCityAdminLevel());
panel.add(nativeLibFile);
constr = new GridBagConstraints();
constr.weightx = 1;
constr.fill = GridBagConstraints.HORIZONTAL;
constr.ipadx = 5;
constr.gridx = 1;
constr.gridy = 2;
l.setConstraints(nativeLibFile, constr);
label = new JLabel("Rendering style file : ");
panel.add(label);
constr = new GridBagConstraints();
constr.ipadx = 5;
constr.gridx = 0;
constr.gridy = 3;
constr.anchor = GridBagConstraints.WEST;
l.setConstraints(label, constr);
renderingStyleFile = new JTextField();
renderingStyleFile.setText(DataExtractionSettings.getSettings().getOsrmServerAddress());
panel.add(renderingStyleFile);
constr = new GridBagConstraints();
constr.weightx = 1;
constr.fill = GridBagConstraints.HORIZONTAL;
constr.ipadx = 5;
constr.gridx = 1;
constr.gridy = 3;
l.setConstraints(renderingStyleFile, constr);
panel.setMaximumSize(new Dimension(Short.MAX_VALUE, panel.getPreferredSize().height));
}
private void addListeners(){
okButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
saveProperties();
setVisible(false);
}
});
cancelButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
}
public void saveProperties(){
// TODO
// DataExtractionSettings settings = DataExtractionSettings.getSettings();
// if(!settings.getSuffixesToNormalizeStreetsString().equals(streetSuffixes.getText())){
// settings.setSuffixesToNormalizeStreets(streetSuffixes.getText());
// }
// if(!settings.getDefaultSuffixesToNormalizeStreetsString().equals(streetDefaultSuffixes.getText())){
// settings.setDefaultSuffixesToNormalizeStreets(streetDefaultSuffixes.getText());
// }
// if(settings.useInternetToLoadImages() != useInternet.isSelected()){
// settings.setUseInterentToLoadImages(useInternet.isSelected());
// }
//
// if(!settings.getLineSmoothness().equals(lineSmoothness.getText())){
// settings.setLineSmoothness(lineSmoothness.getText());
// }
}
}

View file

@ -1,6 +1,7 @@
package net.osmand.swing;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
@ -21,10 +22,11 @@ import net.osmand.render.RenderingRulesStorage.RenderingRulesStorageResolver;
public class NativeSwingRendering extends NativeLibrary {
static {
System.load("/home/victor/projects/OsmAnd/git/Osmand-kernel/jni-prebuilt/linux-x86/osmand.lib");
// System.load("/home/victor/projects/OsmAnd/git/Osmand-kernel/jni-prebuilt/linux-x86/osmand.lib");
}
RenderingRulesStorage storage;
private final File baseDirRC;
private RenderingRulesStorage getDefault() throws SAXException, IOException{
RenderingRulesStorage storage = new RenderingRulesStorage();
@ -45,7 +47,8 @@ public class NativeSwingRendering extends NativeLibrary {
return storage;
}
public NativeSwingRendering(){
public NativeSwingRendering(File baseDirRC){
this.baseDirRC = baseDirRC;
try {
storage = getDefault();
} catch (SAXException e) {
@ -58,7 +61,9 @@ public class NativeSwingRendering extends NativeLibrary {
public BufferedImage renderImage(int sleft, int sright, int stop, int sbottom, int zoom) throws IOException {
RenderingContext rctx = new RenderingContext();
long time = -System.currentTimeMillis();
RenderingContext rctx = new RenderingContext(baseDirRC);
RenderingRuleSearchRequest request = new RenderingRuleSearchRequest(storage);
NativeSearchResult res = searchObjectsForRendering(sleft, sright, stop, sbottom, zoom, request, true,
rctx, "Nothing found");
@ -69,10 +74,10 @@ public class NativeSwingRendering extends NativeLibrary {
rctx.height = (int) ((sbottom - stop) / MapUtils.getPowZoom(31 - zoom - 8));
rctx.shadowRenderingMode = 2;
rctx.zoom = zoom;
long search = time + System.currentTimeMillis();
final RenderingGenerationResult rres = NativeSwingRendering.generateRenderingIndirect(rctx, res.nativeHandler,
false, request, true);
System.out.println(rres.bitmapBuffer.capacity());
long rendering = time + System.currentTimeMillis() - search;
InputStream inputStream = new InputStream() {
int nextInd = 0;
@Override
@ -92,18 +97,40 @@ public class NativeSwingRendering extends NativeLibrary {
ImageReader reader = readers.next();
reader.setInput(new MemoryCacheImageInputStream(inputStream), true);
BufferedImage img = reader.read(0);
long last = time + System.currentTimeMillis() - rendering;
System.out.println(" TIMES search - " + search + " rendering - " + rendering + " unpack - " + last);
return img;
}
public void initFilesInDir(File filesDir){
File[] lf = filesDir.listFiles();
for(File f : lf){
if(f.getName().endsWith(".obf")) {
initMapFile(f.getAbsolutePath());
}
}
}
public static void main(String[] args) throws SAXException, IOException {
NativeSwingRendering lib = new NativeSwingRendering();
lib.initMapFile("/home/victor/projects/OsmAnd/data/osm-gen/Cuba2.obf");
lib.initMapFile("/home/victor/projects/OsmAnd/data/osm-gen/basemap_2.obf");
System.load("/home/victor/projects/OsmAnd/git/Osmand-kernel/jni-prebuilt/linux-x86/osmand.lib");
NativeSwingRendering lib = new NativeSwingRendering(
new File("/home/victor/projects/OsmAnd/git/OsmAnd/res/drawable-mdpi/"));
lib.initFilesInDir(new File("/home/victor/projects/OsmAnd/data/version2"));
double latTop = 22.5;
double lonLeft = -80;
int zoom = 11;
MapPanel.showMainWindow(512, 512, latTop, lonLeft, zoom, lib);
float tileX = 2;
float tileY = 2;
double latBottom = MapUtils.getLatitudeFromTile(zoom, MapUtils.getTileNumberY(zoom, latTop) + tileY);
double lonRight = MapUtils.getLongitudeFromTile(zoom, MapUtils.getTileNumberX(zoom, lonLeft) + tileX);
int sleft = MapUtils.get31TileNumberX(lonLeft);
int sright = MapUtils.get31TileNumberX(lonRight);
int stop = MapUtils.get31TileNumberY(latTop);
int sbottom = MapUtils.get31TileNumberY(latBottom);
lib.renderImage(sleft, sright, stop, sbottom, zoom);
MapPanel.showMainWindow(512, 512, lib);
}
}

View file

@ -130,11 +130,10 @@ public class OsmExtractionUI implements IMapLocationListener {
private JCheckBox buildMapIndex;
private JCheckBox buildTransportIndex;
private JCheckBox normalizingStreets;
private JCheckBox showOfflineIndex;
private String regionName;
public OsmExtractionUI(){
createUI();
}
@ -212,7 +211,17 @@ public class OsmExtractionUI implements IMapLocationListener {
panel.add(buildTransportIndex);
buildTransportIndex.setSelected(true);
showOfflineIndex = new JCheckBox();
showOfflineIndex.setText("Use Offline");
panel.add(showOfflineIndex);
showOfflineIndex.setSelected(false);
showOfflineIndex.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
NativePreferencesDialog dlg = new NativePreferencesDialog(frame);
dlg.showDialog();
}
});
}

View file

@ -207,7 +207,7 @@ public:
pointInsideCount(0), visible(0), allObjects(0){
setRotate(0);
setZoom(15);
setDefaultColor(0xf1eee8);
setDefaultColor(0xfff1eee8);
}
virtual ~RenderingContext();

View file

@ -196,7 +196,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLib
// Main part do rendering
rc.nativeOperations.start();
SkCanvas* canvas = new SkCanvas(*bitmap);
canvas->drawColor(defaultColor);
canvas->drawColor(rc.getDefaultColor() | 0xFFCCCCCC);
if(result != NULL) {
doRendering(result->result, canvas, req, &rc);
}
@ -276,7 +276,7 @@ extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_NativeLibrary_generateRende
// Main part do rendering
SkCanvas* canvas = new SkCanvas(*bitmap);
canvas->drawColor(rc.getDefaultColor());
canvas->drawColor(rc.getDefaultColor() | 0xFFCCCCCC);
if (result != NULL) {
doRendering(result->result, canvas, req, &rc);
}
@ -312,6 +312,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_NativeLibrary_generateRende
delete req;
delete bitmap;
fflush(stdout);
/* Construct a result object */
jobject resultObject = ienv->NewObject(resultClass, resultClassCtorId, bitmapBuffer);