It is currently November 30th, 2022, 6:25 pm

[CRASH to SUGGESTION] Draw to memory Shape or Image

Report bugs with the Rainmeter application and suggest features.
User avatar
death.crafter
Rainmeter Sage
Posts: 1398
Joined: April 24th, 2021, 8:13 pm

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by death.crafter »

Yincognito wrote: April 4th, 2022, 9:46 am By the way, why did you say it's incomplete?
Last time I checked khan was trying to convert it to a native meter, which could enable using web technology in Rainmeter, as requested by Brian.

The first experimental release, which only lets you set the x, y, h and w. The right click menu is edge context menu instead of Rainmeter, which has been fixed on the meter version (which you can use by compiling Rainmeter from khan's repo).

There are other cons as in it always stays on top without respecting the normal flow of meters, which ofc is Microsoft's fault.

Other than that, yes, it can do everything you can do on the web on your computer. It's literally a browser. You can look for Webview2 to learn more.

The repo: https://github.com/khanhas/PluginWebView
Experimental release: https://github.com/khanhas/PluginWebView/releases/download/v0.1.0/PluginWebView_0.1.0.rmskin

P.S. The current version is capable of doing what you want. In fact, there is a 3D model skin and a 3D visualizer, which ofc burns through my i3 :lol:
from the Realm of Death
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by Yincognito »

death.crafter wrote: April 4th, 2022, 4:54 amIt's possible with Plugin WebView by khanhas, which uses Edge Webview to render web pages in Rainmeter. But that is too incomplete for general use. You can use that to render 3D objects.
And that I did! 8-)

[SkinFolder]\@Resources\index.css:

Code: Select all

body
  {
  width: 414px;
  height: 414px;
  margin: 0px;
  }
[SkinFolder]\@Resources\index.html:

Code: Select all

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="index.css"/>
  </head>
  <body>
    <script src="https://threejs.org/build/three.js"></script>
    <script type="module">
      var camera, scene, renderer;
      var mesh;
      function init()
      {
        renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 100);
        camera.position.z = 13.085;
        scene = new THREE.Scene();
        var geometry = new THREE.SphereGeometry(7.425, 360, 180);
        var material = new THREE.MeshPhongMaterial();
        material.map = new THREE.TextureLoader().load('http://s3-us-west-2.amazonaws.com/s.cdpn.io/1206469/earthmap1k.jpg')
        mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
        var light = new THREE.AmbientLight('rgb(255, 255, 255)');
        light.position.set(100, 50, 100);
        scene.add(light);
        document.body.appendChild(renderer.domElement);
      }
      function resize()
      {
        renderer.setSize(window.innerWidth, window.innerHeight, false);
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix(); 
      }
      function animate()
      {
        resize();
        mesh.rotation.x += (Math.PI * 2 / 360);
        mesh.rotation.y += (Math.PI * 2 / 360);
        mesh.rotation.z += (Math.PI * 2 / 360);
        renderer.render(scene, camera);
        requestAnimationFrame(animate);
      }
      init();
      animate();
    </script>
  </body>
</html>
Alternative, non image, cube script:

Code: Select all

    <script type="module">
      const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
      camera.position.z = 1;
      const scene = new THREE.Scene();
      const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
      const material = new THREE.MeshNormalMaterial();
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
      const renderer = new THREE.WebGLRenderer({antialias: true, alpha: true });
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setAnimationLoop(animation);
      document.body.appendChild(renderer.domElement);
      function animation(time)
      {
        mesh.rotation.x = time / 2000;
        mesh.rotation.y = time / 1000;
        renderer.render(scene, camera);
      }
    </script>
[SkinFolder]\Skin.ini:

Code: Select all

[Variables]
Border=8
Size=414

[Rainmeter]
Update=100000000000000000000
DynamicWindowSize=1
AccurateText=1

---Measures---

[Earth]
Measure=Plugin
Plugin=WebView
X=#Border#
Y=#Border#
W=#Size#
H=#Size#
URL=file:///#@#index.html

---Styles---

---Meters---

[Background]
Meter=Shape
Shape=Rectangle (#Border#/2),(#Border#/2),(#Size#+#Border#),(#Size#+#Border#) | Fill Color 0,0,0,1 | StrokeWidth 8 | Stroke Color 255,0,0,255
UpdateDivider=-1
The performance is very good on my laptop, around 4.25% CPU and 17% GPU usage (including my skin suite), almost similar to my existing native Rainmeter implementation. However, I see now why you mentioned the fact that it's incomplete, since the Edge context menu can't be - at least optionally or temporarily - disabled, not sure how it can be made to react to mouse and do Rainmeter specific tasks (some Javascript listeners could probably help here), CORS is a bitch when you want to use local images like I do (unless I upload them somewhere or make my own server) ... but other than that, it's amazing. :great:

It would be great if the few drawbacks above could be reasonably dealt with and such a plugin would be part of the standard Rainmeter package. I'm all for it, since it would open up a whole new set of possibilities for Rainmeter.
User avatar
death.crafter
Rainmeter Sage
Posts: 1398
Joined: April 24th, 2021, 8:13 pm

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by death.crafter »

Actually there is an interface for interacting with Rainmeter. But since it's incomplete and can change khan hasn't documented it yet. All you can do for now is look at the code that covers the javascript interface. Also, you can just run a local server using Node and disable CORS for local host. But yeah, it's a pain for only running a skin.

Anyways, glad you got it working.
from the Realm of Death
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by Yincognito »

death.crafter wrote: April 4th, 2022, 10:30 pm Actually there is an interface for interacting with Rainmeter. But since it's incomplete and can change khan hasn't documented it yet. All you can do for now is look at the code that covers the javascript interface. Also, you can just run a local server using Node and disable CORS for local host. But yeah, it's a pain for only running a skin.

Anyways, glad you got it working.
Yep, I'll play with the things I can play for the moment and wait for the plugin to evolve and mature in terms of abilities - hopefully it will turn up well, because what it can do so far with minimal performance impact is impressive - and you don't even need a low update to do it. It's you I have to thank for letting me know of the alternative I had, this one is much more compact and performance friendly than what I had in mind, but you know, one only works with the tools at his disposal or that he knows of.

Nice to know that both interaction with Rainmeter and other minor drawbacks are worked on, but IMHO the CORS thingy is a problem, especially for regular users who might either not know or not want to use such workarounds, not to mention depending on being online if one wants to use a non-local URL. Personally, I tried to use a image data URL to bypass CORS and it worked, but dealing with such long strings reminds me of my previous idea, plus, the image itself is not the same as the original after encoding.

I'll continue to experiment with it, but I can already say that it looks to be the winner choice in my case, bar the inconveniences. Thanks again for the idea, you just "crafted" saving GBs of drive space for me on this one, LOL. Let's hope Brian and khansas can eventually add this to Rainmeter the proper way, so more users will benefit from it. :thumbup: :rosegift:

P.S. Also, it would be nice to make triggering the Edge context menu optional, because it's a good way to verify if the HTML / Javascript works via Inspect.
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by Yincognito »

death.crafter wrote: April 4th, 2022, 10:30 pmAlso, you can just run a local server using Node and disable CORS for local host. But yeah, it's a pain for only running a skin.
For the record, it appears disabling CORS for specific local folders is possible (or was possible, as of Feb 2020) via running WebView2 with two flags, according to here. This can only be implemented by the plugin developer however, as it's not under my control. Needless to say, I'd disable such attempts to prevent accessing MY OWN local files with ten hands if I could, since although there is the data URL workaround for images, I'm not even able to run local JS script modules unless I load them as non-modules, preventing importing stuff into another module...
User avatar
death.crafter
Rainmeter Sage
Posts: 1398
Joined: April 24th, 2021, 8:13 pm

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by death.crafter »

Yincognito wrote: April 5th, 2022, 12:30 pm P.S. Also, it would be nice to make triggering the Edge context menu optional, because it's a good way to verify if the HTML / Javascript works via Inspect.
Edge context menu on ctrl+rc

Code: Select all

<body id="body">
...
	<script>
		let body = document.getElementById("body");
		body.addEventListener('contextmenu', (e) => {
    			if (e.ctrlKey) return;
    			e.preventDefault();
    			RainmeterAPI.Bang("[!SkinMenu]")
		})
	</script>
</body>
from the Realm of Death
User avatar
Yincognito
Rainmeter Sage
Posts: 4817
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [CRASH to SUGGESTION] Draw to memory Shape or Image

Post by Yincognito »

death.crafter wrote: April 6th, 2022, 1:18 pm Edge context menu on ctrl+rc

Code: Select all

<body id="body">
...
	<script>
		let body = document.getElementById("body");
		body.addEventListener('contextmenu', (e) => {
    			if (e.ctrlKey) return;
    			e.preventDefault();
    			RainmeterAPI.Bang("[!SkinMenu]")
		})
	</script>
</body>
Thanks, that's nice! :rosegift: I modified the listener to a one liner (I like that more in certain cases) and triggered the Rainmeter context menu when CTRL is pressed instead, since it's more consistent with how it works for other skins, and I also use orbit / trackball controls to freely rotate, move and zoom the Earth (I can't believe how few lines are required for such abilities in Three.js, LOL):

Code: Select all

	  <script>
      body = document.getElementById("body");
      body.addEventListener('contextmenu', (e) => {if (e.ctrlKey) {e.preventDefault(); RainmeterAPI.Bang("[!SkinMenu]")}});
	  </script>
However, it would be even nicer if it didn't pause the animation when right clicking - I mean, it's a nice effect, but in my case it wouldn't be desirable (especially for the live, aka UTC time based, animation), but I guess in this case the bang is blocking (not sure why). It's an excellent direction though, and might be useful for further skin related actions (like dragging the skin instead of using the "default" JS orbit controls when I press CTRL).

Currently, I'm in the process of merging some small Python scripts to achieve a local server in the current folder, but with both start and stop abilities (so I can stop it in the [Rainmeter]'s OnCloseAction option), and permissive CORS headers for local file handling and usage. I know this is possible via Node.js' npm, but I like vanilla JS and avoid other flavors or dependencies and since I already have Python installed, well, you get the idea. I absolutely need to get this out of the way before I start experimenting with other things and polish stuff out so it resembles or even surpass my current native Rainmeter implementation. Using data URLs for images is fine, but still, having to convert images to that is a bit odd for the current scenario.