Skip to content

Commit 3494562

Browse files
Piotr Trochimalimuldal
authored andcommitted
Extract FullscreenQuadRenderer class to a dedicated file.
PiperOrigin-RevId: 269292716 Change-Id: Ib0798910b99ce70d41ffacdf18932f3bbb30897f Remove trailing whitespace in dm_control/viewer/gui/__init__.py PiperOrigin-RevId: 271228095 Change-Id: I7e60f4038b08b884c04e9be90559b02ff2326542
1 parent 2fe4cc2 commit 3494562

4 files changed

Lines changed: 139 additions & 116 deletions

File tree

dm_control/viewer/gui/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121

2222
RenderWindow = None
2323

24-
if _render.BACKEND == 'glfw':
25-
try:
26-
from dm_control.viewer.gui import glfw_gui
27-
RenderWindow = glfw_gui.GlfwWindow
28-
except ImportError:
29-
pass
30-
else:
24+
try:
25+
from dm_control.viewer.gui import glfw_gui
26+
RenderWindow = glfw_gui.GlfwWindow
27+
except ImportError:
28+
pass
29+
30+
if RenderWindow is None:
3131

3232
def ErrorRenderWindow(*args, **kwargs):
3333
del args, kwargs

dm_control/viewer/gui/base.py

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -19,52 +19,14 @@
1919
from __future__ import print_function
2020

2121
import abc
22-
import ctypes
2322
import threading
2423
import time
2524

2625
from dm_control.viewer import user_input
27-
import numpy as np
28-
from OpenGL import GL
29-
from OpenGL.GL import shaders
3026
import six
3127

3228
_DOUBLE_CLICK_INTERVAL = 0.25 # seconds
3329

34-
# This array contains packed position and texture cooridnates of a fullscreen
35-
# quad.
36-
# It contains definition of 4 vertices that will be rendered as a triangle
37-
# strip. Each vertex is described by a tuple:
38-
# (VertexPosition.X, VertexPosition.Y, TextureCoord.U, TextureCoord.V)
39-
_FULLSCREEN_QUAD_VERTEX_POSITONS_AND_TEXTURE_COORDS = np.array([
40-
-1, -1, 0, 1,
41-
-1, 1, 0, 0,
42-
1, -1, 1, 1,
43-
1, 1, 1, 0], dtype=np.float32)
44-
_FLOATS_PER_XY = 2
45-
_FLOATS_PER_VERTEX = 4
46-
_SIZE_OF_FLOAT = ctypes.sizeof(ctypes.c_float)
47-
48-
_VERTEX_SHADER = """
49-
#version 120
50-
attribute vec2 position;
51-
attribute vec2 uv;
52-
void main() {
53-
gl_Position = vec4(position, 0, 1);
54-
gl_TexCoord[0].st = uv;
55-
}
56-
"""
57-
_FRAGMENT_SHADER = """
58-
#version 120
59-
uniform sampler2D tex;
60-
void main() {
61-
gl_FragColor = texture2D(tex, gl_TexCoord[0].st);
62-
}
63-
"""
64-
_VAR_POSITION = 'position'
65-
_VAR_UV = 'uv'
66-
_VAR_TEXTURE_SAMPLER = 'tex'
67-
6830

6931
@six.add_metaclass(abc.ABCMeta)
7032
class InputEventsProcessor(object):
@@ -131,73 +93,3 @@ def process(self, button, action):
13193
# timer.
13294
self._double_clicks[button] = curr_time
13395
return False
134-
135-
136-
class FullscreenQuadRenderer(object):
137-
"""Renders pixmaps on a fullscreen quad using OpenGL."""
138-
139-
def __init__(self):
140-
"""Initializes the fullscreen quad renderer."""
141-
GL.glClearColor(0, 0, 0, 0)
142-
self._init_geometry()
143-
self._init_texture()
144-
self._init_shaders()
145-
146-
def _init_geometry(self):
147-
"""Initializes the fullscreen quad geometry."""
148-
vertex_buffer = GL.glGenBuffers(1)
149-
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vertex_buffer)
150-
GL.glBufferData(
151-
GL.GL_ARRAY_BUFFER,
152-
_FULLSCREEN_QUAD_VERTEX_POSITONS_AND_TEXTURE_COORDS.nbytes,
153-
_FULLSCREEN_QUAD_VERTEX_POSITONS_AND_TEXTURE_COORDS, GL.GL_STATIC_DRAW)
154-
155-
def _init_texture(self):
156-
"""Initializes the texture storage."""
157-
self._texture = GL.glGenTextures(1)
158-
GL.glBindTexture(GL.GL_TEXTURE_2D, self._texture)
159-
GL.glTexParameteri(
160-
GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST)
161-
GL.glTexParameteri(
162-
GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST)
163-
164-
def _init_shaders(self):
165-
"""Initializes the shaders used to render the textures fullscreen quad."""
166-
vs = shaders.compileShader(_VERTEX_SHADER, GL.GL_VERTEX_SHADER)
167-
fs = shaders.compileShader(_FRAGMENT_SHADER, GL.GL_FRAGMENT_SHADER)
168-
self._shader = shaders.compileProgram(vs, fs)
169-
170-
stride = _FLOATS_PER_VERTEX * _SIZE_OF_FLOAT
171-
var_position = GL.glGetAttribLocation(self._shader, _VAR_POSITION)
172-
GL.glVertexAttribPointer(
173-
var_position, 2, GL.GL_FLOAT, GL.GL_FALSE, stride, None)
174-
GL.glEnableVertexAttribArray(var_position)
175-
176-
var_uv = GL.glGetAttribLocation(self._shader, _VAR_UV)
177-
uv_offset = ctypes.c_void_p(_FLOATS_PER_XY * _SIZE_OF_FLOAT)
178-
GL.glVertexAttribPointer(
179-
var_uv, 2, GL.GL_FLOAT, GL.GL_FALSE, stride, uv_offset)
180-
GL.glEnableVertexAttribArray(var_uv)
181-
182-
self._var_texture_sampler = GL.glGetUniformLocation(
183-
self._shader, _VAR_TEXTURE_SAMPLER)
184-
185-
def render(self, pixmap, viewport_shape):
186-
"""Renders the pixmap on a fullscreen quad.
187-
188-
Args:
189-
pixmap: A 3D numpy array of bytes (np.uint8), with dimensions
190-
(width, height, 3).
191-
viewport_shape: A tuple of two elements, (width, height).
192-
"""
193-
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
194-
GL.glViewport(0, 0, *viewport_shape)
195-
GL.glUseProgram(self._shader)
196-
GL.glActiveTexture(GL.GL_TEXTURE0)
197-
GL.glBindTexture(GL.GL_TEXTURE_2D, self._texture)
198-
GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1)
199-
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, pixmap.shape[1],
200-
pixmap.shape[0], 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
201-
pixmap)
202-
GL.glUniform1i(self._var_texture_sampler, 0)
203-
GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Copyright 2018 The dm_control Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ============================================================================
15+
# Lint as: python3
16+
"""OpenGL utility for rendering numpy arrays as images on a quad surface."""
17+
18+
from __future__ import absolute_import
19+
from __future__ import division
20+
from __future__ import print_function
21+
22+
import ctypes
23+
24+
import numpy as np
25+
from OpenGL import GL
26+
from OpenGL.GL import shaders
27+
28+
# This array contains packed position and texture cooridnates of a fullscreen
29+
# quad.
30+
# It contains definition of 4 vertices that will be rendered as a triangle
31+
# strip. Each vertex is described by a tuple:
32+
# (VertexPosition.X, VertexPosition.Y, TextureCoord.U, TextureCoord.V)
33+
_FULLSCREEN_QUAD_VERTEX_POSITONS_AND_TEXTURE_COORDS = np.array([
34+
-1, -1, 0, 1,
35+
-1, 1, 0, 0,
36+
1, -1, 1, 1,
37+
1, 1, 1, 0], dtype=np.float32)
38+
_FLOATS_PER_XY = 2
39+
_FLOATS_PER_VERTEX = 4
40+
_SIZE_OF_FLOAT = ctypes.sizeof(ctypes.c_float)
41+
42+
_VERTEX_SHADER = """
43+
#version 120
44+
attribute vec2 position;
45+
attribute vec2 uv;
46+
void main() {
47+
gl_Position = vec4(position, 0, 1);
48+
gl_TexCoord[0].st = uv;
49+
}
50+
"""
51+
_FRAGMENT_SHADER = """
52+
#version 120
53+
uniform sampler2D tex;
54+
void main() {
55+
gl_FragColor = texture2D(tex, gl_TexCoord[0].st);
56+
}
57+
"""
58+
_VAR_POSITION = 'position'
59+
_VAR_UV = 'uv'
60+
_VAR_TEXTURE_SAMPLER = 'tex'
61+
62+
63+
class FullscreenQuadRenderer(object):
64+
"""Renders pixmaps on a fullscreen quad using OpenGL."""
65+
66+
def __init__(self):
67+
"""Initializes the fullscreen quad renderer."""
68+
GL.glClearColor(0, 0, 0, 0)
69+
self._init_geometry()
70+
self._init_texture()
71+
self._init_shaders()
72+
73+
def _init_geometry(self):
74+
"""Initializes the fullscreen quad geometry."""
75+
vertex_buffer = GL.glGenBuffers(1)
76+
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vertex_buffer)
77+
GL.glBufferData(
78+
GL.GL_ARRAY_BUFFER,
79+
_FULLSCREEN_QUAD_VERTEX_POSITONS_AND_TEXTURE_COORDS.nbytes,
80+
_FULLSCREEN_QUAD_VERTEX_POSITONS_AND_TEXTURE_COORDS, GL.GL_STATIC_DRAW)
81+
82+
def _init_texture(self):
83+
"""Initializes the texture storage."""
84+
self._texture = GL.glGenTextures(1)
85+
GL.glBindTexture(GL.GL_TEXTURE_2D, self._texture)
86+
GL.glTexParameteri(
87+
GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST)
88+
GL.glTexParameteri(
89+
GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST)
90+
91+
def _init_shaders(self):
92+
"""Initializes the shaders used to render the textures fullscreen quad."""
93+
vs = shaders.compileShader(_VERTEX_SHADER, GL.GL_VERTEX_SHADER)
94+
fs = shaders.compileShader(_FRAGMENT_SHADER, GL.GL_FRAGMENT_SHADER)
95+
self._shader = shaders.compileProgram(vs, fs)
96+
97+
stride = _FLOATS_PER_VERTEX * _SIZE_OF_FLOAT
98+
var_position = GL.glGetAttribLocation(self._shader, _VAR_POSITION)
99+
GL.glVertexAttribPointer(
100+
var_position, 2, GL.GL_FLOAT, GL.GL_FALSE, stride, None)
101+
GL.glEnableVertexAttribArray(var_position)
102+
103+
var_uv = GL.glGetAttribLocation(self._shader, _VAR_UV)
104+
uv_offset = ctypes.c_void_p(_FLOATS_PER_XY * _SIZE_OF_FLOAT)
105+
GL.glVertexAttribPointer(
106+
var_uv, 2, GL.GL_FLOAT, GL.GL_FALSE, stride, uv_offset)
107+
GL.glEnableVertexAttribArray(var_uv)
108+
109+
self._var_texture_sampler = GL.glGetUniformLocation(
110+
self._shader, _VAR_TEXTURE_SAMPLER)
111+
112+
def render(self, pixmap, viewport_shape):
113+
"""Renders the pixmap on a fullscreen quad.
114+
115+
Args:
116+
pixmap: A 3D numpy array of bytes (np.uint8), with dimensions
117+
(width, height, 3).
118+
viewport_shape: A tuple of two elements, (width, height).
119+
"""
120+
GL.glClear(GL.GL_COLOR_BUFFER_BIT)
121+
GL.glViewport(0, 0, *viewport_shape)
122+
GL.glUseProgram(self._shader)
123+
GL.glActiveTexture(GL.GL_TEXTURE0)
124+
GL.glBindTexture(GL.GL_TEXTURE_2D, self._texture)
125+
GL.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1)
126+
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, pixmap.shape[1],
127+
pixmap.shape[0], 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE,
128+
pixmap)
129+
GL.glUniform1i(self._var_texture_sampler, 0)
130+
GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4)

dm_control/viewer/gui/glfw_gui.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from dm_control._render import glfw_renderer
2424
from dm_control.viewer import util
2525
from dm_control.viewer.gui import base
26+
from dm_control.viewer.gui import fullscreen_quad
2627
import glfw
2728
import numpy as np
2829

@@ -205,7 +206,7 @@ def __init__(self, width, height, title, context=None):
205206

206207
def _glfw_setup(self, window):
207208
glfw.set_drop_callback(window, self._handle_file_drop)
208-
return base.FullscreenQuadRenderer()
209+
return fullscreen_quad.FullscreenQuadRenderer()
209210

210211
@property
211212
def shape(self):

0 commit comments

Comments
 (0)