"""
Unproject
"""
from typing import Optional, Tuple
import numpy as np
from OpenGL.GL import glGetDoublev, glGetIntegerv
from OpenGL.GLU import gluUnProject
from OpenGL.raw.GL._types import GL_FLOAT
from OpenGL.raw.GL.VERSION.GL_1_0 import (
GL_DEPTH_COMPONENT,
GL_DEPTH_TEST,
GL_MODELVIEW_MATRIX,
GL_PROJECTION_MATRIX,
GL_VIEWPORT,
glFlush,
glIsEnabled,
glReadPixels,
)
from picogl.logger import Logger as log
[docs]
def unproject(x: int, y: int) -> Optional[Tuple[float, float, float]]:
"""
unproject
:param x: x coordinate
:param y: y coordinate
:return: Tuple[int, int, int] coordinate_data_main
Un-projects screen coordinate_data_main (x, y) into 3D world coordinate_data_main.
Assumes OpenGL context is current -Ensure OpenGL context is current if needed
i.e. self.makeCurrent() ← must be called before this if in Qt widget
"""
model_view = glGetDoublev(GL_MODELVIEW_MATRIX)
log.parameter("model_view", model_view, silent=True)
projection = glGetDoublev(GL_PROJECTION_MATRIX)
log.parameter("projection", projection, silent=True)
viewport = glGetIntegerv(GL_VIEWPORT)
log.parameter("viewport", viewport, silent=True)
y_gl = viewport[3] - y
log.parameter("y_gl", y_gl, silent=True)
if not (0 <= x < viewport[2] and 0 <= y_gl < viewport[3]):
log.message(f"Coordinates out of bounds: ({x}, {y_gl})")
return None
if not glIsEnabled(GL_DEPTH_TEST):
log.warning("Warning: GL_DEPTH_TEST is not enabled")
# Read depth safely
depth = np.array([0.0], dtype=np.float32)
# log.parameter("depth", depth)
try:
glFlush()
glReadPixels(x, y_gl, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth)
except Exception as ex:
log.error(f"glReadPixels failed: {ex}")
return None
wz = float(depth[0])
if wz == 1.0:
return None
log.parameter("depth", depth, silent=True)
wx, wy, wz = gluUnProject(x, y_gl, wz, model_view, projection, viewport)
log.parameter("wx", wx, silent=True)
log.parameter("wy", wy, silent=True)
log.parameter("wz", wz, silent=True)
return wx, wy, wz