kxgames / glooey

An object-oriented GUI library for pyglet.
MIT License
91 stars 6 forks source link

Size of rect property of widget (left, bottom, width, height) on macOS #27

Closed wkentaro closed 5 years ago

wkentaro commented 5 years ago

The size information of rect property (e.g., Widget.rect.left) seems to be half of the actual.

This script runs without any problem on Linux https://gist.github.com/wkentaro/ff4b804df77d8292fdb7043c3e2489f9

but it looks like below on macOS:

Screen Shot 2019-04-21 at 17 21 38

If I change like below

diff --git a/spam.py b/spam.py
index a8e5067..4059f53 100644
--- a/spam.py
+++ b/spam.py
@@ -17,10 +17,10 @@ class SceneGroup(pyglet.graphics.Group):
         glPushAttrib(GL_ENABLE_BIT)
         glEnable(GL_SCISSOR_TEST)
         glScissor(
-            int(self.rect.left),
-            int(self.rect.bottom),
-            int(self.rect.width),
-            int(self.rect.height),
+            2 * int(self.rect.left),
+            2 * int(self.rect.bottom),
+            2 * int(self.rect.width),
+            2 * int(self.rect.height),
         )

         self._mode = (GLint)()
@@ -28,8 +28,8 @@ class SceneGroup(pyglet.graphics.Group):
         self._viewport = (GLint * 4)()
         glGetIntegerv(GL_VIEWPORT, self._viewport)

-        left, bottom = int(self.rect.left), int(self.rect.bottom)
-        width, height = int(self.rect.width), int(self.rect.height)
+        left, bottom = 2 * int(self.rect.left), 2 * int(self.rect.bottom)
+        width, height = 2 * int(self.rect.width), 2 * int(self.rect.height)
         glViewport(left, bottom, width, height)
         glMatrixMode(GL_PROJECTION)
         glPushMatrix()

It looks ok.

Screen Shot 2019-04-21 at 17 23 44

Is this an expected behavior? Should I always double the size of rect?

kalekundert commented 5 years ago

Looking at the two screenshots, the problem is that the MacOS window has twice as many pixels as it should have. Specifically, pyglet requests a window that is 1280 px wide, and glooey bases all of its calculations on that. But looking at the dimensions of the screenshots, the linux window is in fact 1280 px wide, while the MacOS window is 2554 px wide (2*1280=2560, I'm not sure why the window is 6 px narrower than that).

Does your Mac have a retina display, by any chance? That seems like the most likely cause of the problem. If so, this link might be helpful: https://stackoverflow.com/questions/36672935/why-retina-screen-coordinate-value-is-twice-the-value-of-pixel-value

wkentaro commented 5 years ago

Thanks! You're right. I'm using retina display, and below change fixed the issue.

commit f1869ed3efe6ae6caa599d286481678cde6c03d7
Author: Kentaro Wada <www.kentaro.wada@gmail.com>

    Fix size of widget.rect for retina display

diff --git a/scene_widget.py b/scene_widget.py
index 69bf0e0..9b2bb4f 100644
--- a/scene_widget.py
+++ b/scene_widget.py
@@ -17,6 +17,7 @@ class SceneGroup(pyglet.graphics.Group):
         camera_transform=None,
         view_transform=None,
         parent=None,
+        pixel_per_point=(1, 1),
     ):
         super().__init__(parent)
         self.rect = rect
@@ -33,23 +34,28 @@ class SceneGroup(pyglet.graphics.Group):
             view_transform = np.eye(4)
         self.view_transform = view_transform

+        self._pixel_per_point = pixel_per_point
+
     def set_state(self):
+        left = int(self.rect.left)
+        bottom = int(self.rect.bottom)
+        width = int(self.rect.width)
+        height = int(self.rect.height)
+
+        left = int(self._pixel_per_point[0] * left)
+        bottom = int(self._pixel_per_point[1] * bottom)
+        width = int(self._pixel_per_point[0] * width)
+        height = int(self._pixel_per_point[1] * height)
+
         glPushAttrib(GL_ENABLE_BIT)
         glEnable(GL_SCISSOR_TEST)
-        glScissor(
-            int(self.rect.left),
-            int(self.rect.bottom),
-            int(self.rect.width),
-            int(self.rect.height),
-        )
+        glScissor(left, bottom, width, height)

         self._mode = (GLint)()
         glGetIntegerv(GL_MATRIX_MODE, self._mode)
         self._viewport = (GLint * 4)()
         glGetIntegerv(GL_VIEWPORT, self._viewport)

-        left, bottom = int(self.rect.left), int(self.rect.bottom)
-        width, height = int(self.rect.width), int(self.rect.height)
         glViewport(left, bottom, width, height)
         glMatrixMode(GL_PROJECTION)
         glPushMatrix()
@@ -211,12 +217,15 @@ class SceneWidget(glooey.Widget):
         if self.vertex_list:
             return

+        pixel_per_point = np.array(self.window.get_viewport_size()) / \
+            np.array(self.window.get_size()),
         self.scene_group = SceneGroup(
             rect=self.rect,
             camera_fovy=self.scene.camera.fov[1],
             camera_transform=np.linalg.inv(self.scene.camera.transform),
             view_transform=self._trackball.pose.copy(),
             parent=self.group,
+            pixel_per_point=pixel_per_point,
         )

         node_names = self.scene.graph.nodes_geometry

https://github.com/wkentaro/trimesh-glooey/blob/master/scene_widget.py