mapbox / mapbox-gl-js

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL
https://docs.mapbox.com/mapbox-gl-js/
Other
11.15k stars 2.22k forks source link

Porting mapboxgl-js to Qml/Canvas3D #10796

Open amosawi9999 opened 3 years ago

amosawi9999 commented 3 years ago

Hi As far as i know, the mapboxgl-native isn't actively developed anymore and Qt/Qml users wont get updates and new features like terrain and fog, so as Qml user i started porting js to Qml, the Qml engine support es5 and some features of es6 and also theres QtCanvas3D module which implements WebGL like API's. the Canvas3D module has example projects which some of them are based on three.js, so conceptually and practically softwares developed with WebGL could also work with Canvas3D. There are some differences between Qml JS engine and browser ones, however as far as i know none of them are blocker. for example there isn't DOM API's in Qml.

I started porting the JS version to Qml, there are some DOM dependencies like document global objects, methods like createElement, getElementById and ..., i have developed simple DOM like environment with Qml objects and fixed lots of missing dependencies. The 'this' behavior in arrow functions was different i think due to strict mode, so i have to transpile it using babel to get function(){ } instead () => { } . (i can't figure out how integrate babel presets into build system, sorry i came from c++/native world, anybody can help me!?).

Right now, the codes are based on v2.3.0-master, i separated shared, mapboxgl and worker js files and all the interaction and inclusions are ok, no warnings are generated, style and sprite/tiles get fetched and render function called at 10 times a second (limited by me), I debugged into the render function and draw function of layers get called in all required render passes, but nothing drawn on screen.

One of the main differences of Canvas3D item and html canvas is context initialization, in html canvas when the canvas is created the getContext('webgl') could be called for getting gl context, but in Canvas3D we should wait for initialized signal gets fired and the context will be available, so i created the Canvas3D in advance and then initialized the Map.

Edit I can get background layer rendered while tiles are loading independently but tiles are black (tested with satellite style), where should i check for error or something problematic ?!

can anybody help me through this?!

karimnaaji commented 3 years ago

Hey @amosawi9999 , this is a great initiative. Some of your questions might be difficult to answer as I'm not very knowledgeable about the Canvas3D API, but If you have ways to share your project that would be great to realize the extent of this port and better help with your questions! I vaguely remember that it wasn't necessarily tested cleanly with the WebGL conformance tests so this let me think that there could be surprises compared to angle or native browser rendering. Though, not sure about the status of this as of today.

the mapboxgl-native isn't actively developed anymore

The public mapboxgl-native repository isn't maintained but it is still actively developed in an internal codebase.

so conceptually and practically softwares developed with WebGL could also work with Canvas3D.

The gesture layer might be challenging to replicate, Is there anything from the Canvas3D API that helps with this?

The 'this' behavior in arrow functions was different i think due to strict mode, so i have to transpile it using babel to get function(){ } instead () => { } . (i can't figure out how integrate babel presets into build system, sorry i came from c++/native world, anybody can help me!?).

It would probably be necessary to integrate a step as part of your qmake build. @arindam1993 Do you have any recommendation or build step that would help with that?

Edit I can get background layer rendered while tiles are loading independently but tiles are black (tested with satellite style), where should i check for error or something problematic ?!

This would need a bit of advanced debugging but is there any meaningful log output? There could be issues with the satellite texture data not being uploaded correctly, but it's difficult to diagnose from your description. I would inspect with something like renderdoc to determine whether the webgl qt translation to gl results in meaningful draw calls.

amosawi9999 commented 3 years ago

The code is ugly right now, i am currently playing with final code generated by build system, its huge and editing such huge file is awfull. I started playing without any hope to be working but surprisingly nothing blocked until now and everything works without errors and warnings, i'll try to cleaning it up and share it.

The gesture layer might be challenging to replicate, Is there anything from the Canvas3D API that helps with this?

The Canvas3D API isn't actively developed by Qt anymore, but its nothing more than a translation layer between JS canvas API and OpenGL calls, however within its current state three.js examples working on top of it without any major modifications. see the introduction presentation

The gesture layer might be challenging to replicate, Is there anything from the Canvas3D API that helps with this?

I argue that this may getting difficult, but Qml has its own gesture handling components which there isn't much difference between them, also if the rendering issue will be ok, we can integrate it with qtlocation (like old mapboxgl-native one), and those gestures could be handled by qtlocation.

This would need a bit of advanced debugging but is there any meaningful log output? There could be issues with the satellite texture data not being uploaded correctly, but it's difficult to diagnose from your description. I would inspect with something like renderdoc to determine whether the webgl qt translation to gl results in meaningful draw calls.

I debugged it until Texture class, the problem is with updating texture with img elements fetched by tile requests, in tile requests when the tile data became ready, an img element created and received data will be passed as src to it, gl.texImage2D accepts an img element as texture source, i changed the img element with Qml image and transformed the image data (through drawing it inside 2d canvas) into Uin8Array and feeding those gl.texImage2D with array of pixel values. by ruuning the application with help of renderdoc, i can see the uploaded textures are black and empty, so i have to debug pixel format or something other.

karimnaaji commented 3 years ago

Keep us posted of the updates!

amosawi9999 commented 3 years ago

Keep us posted of the updates!

Sure,

Is there any easy way to completely disabling workers and do all the stuffs in main thread ?!

amosawi9999 commented 3 years ago

Sorry for silly question, i am native guy and dont know much about javascript build systems. How can i tell the yarn build system to transpile the output with just es2015/transform_arrow_functions plugin, i have to transpile the code manually using babel but i know it should be possible by adding browserlist to some where :smile:

arindam1993 commented 3 years ago

Hey @amosawi9999 , thanks a lot for trying this.

I don't think browserslist will help in your case since you need to transpile to ES5. For that the best way forward is to take mapbox-gl-csp.js and mapbox-gl-csp-worker.js, pass both through babel independently ( you can directly use the babel cli for this) and load both files independently into the Qml environment and then intruct mapboxgl to load the worker code via a url.

mapboxgl.workerUrl = <path to transpiled mapbox-gl-csp-worker.js here>

This way you don't have to interface with JS build systems very much.