I'm using ionic 3 framework to build an Android and Electron Application.
Now I've to add Three.js (the version in use is the r110) in the app and I have no experience in WebGL nor three.js.
When I run the application with Electron all seems fine, but when I run the app in an android emulator with Android API 28 this error happens "Failed to execute 'texImage2D' on 'WebGLRenderingContext': No function was found that matched the signature provided."
I think the problem is that the version of chrome used by Android is "Chrome/69.0.3497.100", while in Electron is "Chrome/76.0.3809.146".
This is the part of code that use the texImage2D function
private loadCollada() {
const loader = new ColladaLoader();
loader.load('assets/edo/model/model.dae', (collada) => {
this.dae = collada.scene;
this.dae.scale.x = this.dae.scale.y = this.dae.scale.z = 1;
this.dae.updateMatrix();
this.scene.add(this.dae);
});
}
I found in three.js library that the error is logged in three.module.js
function texImage2D() {
try {
gl.texImage2D.apply( gl, arguments );
} catch ( error ) {
console.error( 'THREE.WebGLState:', error );
}
}
I don't know if it might be useful but I have also this message in my console printed so many times.
[.WebGL-0xcba04400]RENDER WARNING: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering. [file:///android_asset/www/index.html]
There is a workaround or a way to fix this problem?
Development Environment OS: Windows 7 Enterprise LTS
Browser compatibility minimum requirements: Should support all Edge, Firefox, Chrome browsers, as of 2018.
Current ongoing issue: Unable to run VM on dev workstation; Cannot run Windows 10 VMs to debug Microsoft Edge extensions.
To explain:
An "all-in-one browser extension" refers to a browser extension code that uses the same code with minor differences to work on various WebExtensions / Chrome Extensions supported browsers. At bare minimum, the same codebase should work and run on Edge, Firefox, and Chrome with very minor changes.
Callbacks on the content scripts for Edge/Firefox/Chrome extensions are handled differently.
For unknown reasons, I cannot run VM on my workstation machine. When VM is running, VM client is black. This is a localized issue on my end that I cannot resolve, so I'm forced to find a different solution/alternative.
How are they handled differently on the content scripts:
Edge: browser.runtime.sendMessage uses callbacks, and returns undefined.
Firefox: browser.runtime.sendMessage uses Promises, and returns a Promise.
Chrome: chrome.runtime.sendMessage uses callbacks, and returns undefined.
According to various references:
Firefox / Chrome / MS Edge extensions using chrome.* or browser.*
https://www.smashingmagazine.com/2017/04/browser-extension-edge-chrome-firefox-opera-brave-vivaldi/
On the content scripts, you can declare the following JavaScript snippet at the top in order to create a global variable that can be referenced everywhere else:
//Global "browser" namespace definition.
window.browser = (function() {
return window.msBrowser || window.browser || window.chrome;
})();
Unfortunately, because of the issue I'm experiencing (VM not running), I cannot tell if window.msBrowser is still being used. And this solution is not helpful for me when handling message callbacks when using namespace.runtime.sendMessage.
With all that said, my main question is: How to write a message passing function that can handle callbacks properly?
Currently, I'm using the following code:
function sendGlobalMessage(messageRequest, callback) {
if (chrome && window.openDatabase) {
//This is Chrome browser
chrome.runtime.sendMessage(messageRequest, callback);
}
else if (browser) {
try {
//Edge will error out because of a quirk in Edge IndexedDB implementation.
//See https://gist.github.com/nolanlawson/a841ee23436410f37168
let db = window.indexedDB.open("edge", (Math.pow(2, 30) + 1));
db.onerror = function(e) {
throw new Error("edge is found");
};
db.onsuccess = function(e) {
//This is Firefox browser.
browser.runtime.sendMessage(messageRequest).then(callback);
};
}
catch (e) {
//This is Edge browser
browser.runtime.sendMessage(messageRequest, callback);
}
}
}
I truly felt this is a hacky solution, because the code is based off of browser platform exclusive quirks in order to separate chrome.runtime.sendMessage and browser.runtime.sendMessage API calls, so as to handle callbacks in their respective platforms. I really wanted to change this.
So I'm asking what better ways are there, out there, that is useful to detect the different platforms, and handle message passing callbacks properly at the same time?
Thanks in advance.
I believed I solved it.
EDIT: The FINAL final version (updated and more stable, less message passing):
//Global "browser" namespace definition, defined as "namespace". Can be renamed to anything else.
window.namespace = (function() {
return window.browser || window.chrome;
})();
function sendGlobalResponse(message, callback){
if (window.namespace === window.chrome) {
//Chrome
window.namespace.runtime.sendMessage(message, callback);
}
else if (window.namespace === window.browser) {
//Using instanceof to check for object type, and use the returned evaluation as a truthy value.
let supportPromises = false;
try {
supportPromises = window.namespace.runtime.getPlatformInfo() instanceof Promise;
}
catch(e) { }
if (supportPromises){
//Firefox
window.namespace.runtime.sendMessage(message).then(callback);
}
else {
//Edge
window.namespace.runtime.sendMessage(message, callback);
}
}
}
(Original Post):
The final version (Now obsoleted):
//Global "browser" namespace definition.
window.namespace = (function() {
return window.browser || window.chrome;
})();
function sendGlobalResponse(message, callback){
if (window.namespace === window.chrome) {
//Chrome
window.namespace.runtime.sendMessage(message, callback);
}
else if (window.namespace === window.browser) {
let returnValue = window.namespace.runtime.sendMessage({});
if (typeof returnValue === "undefined"){
//Edge
window.namespace.runtime.sendMessage(message, callback);
}
else {
//Firefox
window.namespace.runtime.sendMessage(message).then(callback);
}
}
}
In the second if statement, by checking to see if the return value of a window.browser.runtime.sendMessage is a Promise or undefined, we can detect if the platform is Firefox or Edge.
I think this is the only solution to handle message passing callbacks/message responses on the content scripts.
I really couldn't think of a better solution than this. So I'll be using this from now on.
But if anyone else knows a better way, a way where you don't need to send out 1 extra dummy message for Firefox and Edge per function call, that would be great!
It sucks that anything inside the content script is not persistent, and even if you store information about what platform the code is being run on, you still have to fetch the information from the background script before filtering out which runtime.sendMessage function to call on, so it doesn't really save much time.
In the last project I use BLE plugin.
adapter.DeviceDiscovered += (s, a) =>
{
myDeviceList.Add(a.Device);
}
await adapter.StartScanningForDevicesAsync();
But right now I'm just looking for devices and adding what you find directly to this list.
I want this scan to work continuously and if any device gets lost, it can automatically delete it here.
BLE has StartScanningForDevicesAsync class but I don't know if this is useful for me.
event EventHandler<DeviceErrorEventArgs> DeviceConnectionLost;
//
// Summary:
// Occurs when a device has been disconnected. This occurs on intendet disconnects
// after Plugin.BLE.Abstractions.Contracts.IAdapter.DisconnectDeviceAsync(Plugin.BLE.Abstractions.Contracts.IDevice).
Is this possible?
I think, you can use something like this (pseudocode + C#):
StartTimer(TimeSpan.FromSeconds(30),
() =>
{
if (!isScanning)
{
new Handler().PostDelayed(StopScan, 10000); // stop
scanning after 10 sec
isScanning = true;
StartScan();
}
return true; // this result will tell to fire onTimer event again
});
Here StartScan and StopScan - functions you use for communicating with BLE
Hope to find some guidance on this one soon, I've added reference for Windows IoT UWT in my project but still getting the following error ?
An exception of type 'System.TypeLoadException' occurred in test_led_alljoyn.exe but was not handled in user code
Additional information: Could not find Windows Runtime type 'Windows.Devices.Gpio.GpioController'.
Has anyone come across this issue while compiling applications for Raspberry Pi on Windows IoT core, on it's own one of my sample push button app works fine. Here's my code
public IAsyncOperation<testlightbulbSwitchResult> SwitchAsync(AllJoynMessageInfo info, bool interfaceMemberOn)
{
return (Task.Run(() =>
{
SwitchLED(interfaceMemberOn);
return testlightbulbSwitchResult.CreateSuccessResult();
}).AsAsyncOperation());
}
private void SwitchLED (bool state)
{
_ledState = state;
if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Devices.Gpio.GpioController"))
{
this.tController = GpioController.GetDefault();
if (this.tController == null)
{
//GpioStatus.Text = "There is no GPIO controller on this device.";
//return;
this.tPin = this.tController.OpenPin(5);
this.tPin.Write(GpioPinValue.High);
this.tPin.SetDriveMode(GpioPinDriveMode.Output);
}
this.tPin.Write(_ledState ? GpioPinValue.Low : GpioPinValue.High);
}
}
Solved. I had to set build platform target compile with .net native tool chain.
In OS X my gamepads are recognised correctly in SDL_PollEvent() at application startup. However, when I try hot plugging new gamepads or removing old gamepads, the SDL_PollEvent() does not trigger either SDL_CONTROLLERDEVICEADDED or SDL_CONTROLLERDEVICEREMOVED. The same code works correctly in Windows when I hot plug game controllers.
A more interesting note is that if I resize the window of my application, the hot plugging works. After resize event all the hot plugging events are triggered. It almost seems that the gamepad events are put in a some kind of waiting queue which is purged when the resize event happens. My SDL_PollEvent() code is quite standard as seen below.
case SDL_CONTROLLERDEVICEADDED:
if (SDL_IsGameController(e.cdevice.which))
{
SDL_GameController *pad = SDL_GameControllerOpen(e.cdevice.which);
if (pad)
{
SDL_Joystick *joy = SDL_GameControllerGetJoystick(pad);
int instanceID = SDL_JoystickInstanceID(joy);
if(m_gameControllers.count(instanceID) == 0)
{
m_gameControllers.insert(std::make_pair(instanceID, pad));
}
}
}
break;
case SDL_CONTROLLERDEVICEREMOVED:
{
auto it = m_gameControllers.find(e.cdevice.which);
if (it != m_gameControllers.end())
{
SDL_GameController* pad = m_gameControllers[e.cdevice.which];
SDL_GameControllerClose(pad);
m_gameControllers.erase(it);
}
}
break;
Has anyone else experienced this?
After some struggling I found the solution: Call SDL_PollEvent() from the main thread. Initially I called the gamepad handling method from the CVDisplayLink thread which resulted the described behaviour.
In my case the solution was simply to add dispatch_async call to my gamepad handling function.
dispatch_async(dispatch_get_main_queue(),^ { handleGamePad();});