pax_global_header 0000666 0000000 0000000 00000000064 12610116756 0014517 g ustar 00root root 0000000 0000000 52 comment=ebed8a107c739355d0eb37881bc04bba759d9600
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/ 0000775 0000000 0000000 00000000000 12610116756 0023676 5 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/.gitignore 0000664 0000000 0000000 00000000006 12610116756 0025662 0 ustar 00root root 0000000 0000000 *.swp
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/.gitmodules 0000664 0000000 0000000 00000000526 12610116756 0026056 0 ustar 00root root 0000000 0000000 [submodule "space_view3d_virtual_reality/lib/python-ovrsdk"]
path = space_view3d_virtual_reality/lib/python-ovrsdk
url = https://github.com/dfelinto/python-ovrsdk.git
[submodule "space_view3d_virtual_reality/oculus_sdk_bridge"]
path = space_view3d_virtual_reality/oculus_sdk_bridge
url = http://git.impa.br/dfelinto/oculus_sdk_bridge.git
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/README.md 0000664 0000000 0000000 00000004562 12610116756 0025164 0 ustar 00root root 0000000 0000000 # Virtual Reality Viewport
Addon to bring virtual reality devices to the Blender viewport.
This is work in progress/pre-alpha state, use at your own risk.
Pre-Requisite
============
Custom Blender build, from https://github.com/dfelinto/blender/tree/oculus
How to Use
==========
In the viewport go to the toolshelf, select the ``Virtual Reality`` tab, click on the ``Virtual Reality`` button and follow the on-screen instructions.
Current State
=============
Video of plugin working:
[![Video of plugin in action](http://img.youtube.com/vi/saSn2qvW0aE/0.jpg)](https://www.youtube.com/watch?v=saSn2qvW0aE)
Oculus SDK 0.5 is working across Windows, Mac and Linux.
Installation
============
In a terminal paste the following commands:
```
$ git clone https://github.com/dfelinto/virtual_reality_viewport.git
$ cd virtual_reality_viewport
$ git submodule update --init --recursive --remote
$ zip -x __pycache__ -x */.git* -r9 space_view3d_virtual_reality.zip space_view3d_virtual_reality
```
Now install the space_view3d_virtual_reality.zip in Blender as an addon.
Update
======
In a terminal paste the following commands:
```
$ git pull origin
$ git submodule update --recursive --remote
```
Followed by the rsync command for your OS:
Mac:
```
$ rsync -rv --exclude=.DS_Store --exclude=.git --exclude=*.blend1 --exclude=*.blend2 --exclude=*.swp --exclude=*.swo space_view3d_virtual_reality ~/Library/Application\ Support/Blender/2.76/scripts/addons/
```
Linux:
```
$ rsync -rv --exclude=.DS_Store --exclude=.git --exclude=*.blend1 --exclude=*.blend2 --exclude=*.swp --exclude=*.swo space_view3d_virtual_reality ~/.config/blender/2.76/scripts/addons/
```
Optionally, instead of rsync you can generate a new ``.zip``, remove the previous version of the addon and re-install it.
Roadmap
=======
Oculus SDK 0.7 is still in progress.
Later we can also extend the external bridge library to support other HMD devices.
Also, we need to decide how to better handle the externals (bridge and python-ovrsdk).
Credits
=======
* Oculus SDK 0.5 wrapper by https://github.com/jherico/python-ovrsdk
* Oculus SDK 0.7 bridge: Dalai Felinto and Djalma Lucio @ Visgraf / IMPA
* Blender Addon - Dalai Felinto - http://www.dalaifelinto.com
Acknowledgements
================
Visgraf / IMPA - for supporting the core of the addon development
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/ 0000775 0000000 0000000 00000000000 12610116756 0031551 5 ustar 00root root 0000000 0000000 __init__.py 0000664 0000000 0000000 00000004573 12610116756 0033614 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality #====================== BEGIN GPL LICENSE BLOCK ======================
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#======================= END GPL LICENSE BLOCK ========================
#
bl_info = {
"name": "Virtual Reality Viewport",
"author": "Dalai Felinto, Visgraf/IMPA",
"version": (0, 9),
"blender": (2, 7, 7),
"location": "View 3D Tools",
"description": "",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "3D View"}
import bpy
from . import ui
from . import operator
# ############################################################
# User Preferences
# ############################################################
# Preferences
class VirtualRealityPreferences(bpy.types.AddonPreferences):
bl_idname = __name__
display_backend = bpy.props.EnumProperty(
name="Display Backend",
description="Library to use for the display",
items=(("OCULUS", "Oculus", "Oculus - oculus.com"),
("OCULUS_LEGACY", "Oculus Legacy", "Oculus 0.5 - oculus.com"),
("DEBUG", "Debug", "Debug backend - no real HMD"),
),
default="OCULUS",
)
def draw(self, context):
layout = self.layout
row = layout.row()
row.prop(self, "display_backend")
# ############################################################
# Un/Registration
# ############################################################
def register():
bpy.utils.register_class(VirtualRealityPreferences)
operator.register()
ui.register()
def unregister():
bpy.utils.unregister_class(VirtualRealityPreferences)
operator.unregister()
ui.unregister()
if __name__ == '__main__':
register()
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/hmd/ 0000775 0000000 0000000 00000000000 12610116756 0032321 5 ustar 00root root 0000000 0000000 __init__.py 0000664 0000000 0000000 00000020302 12610116756 0034350 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/hmd
TODO = True
from mathutils import (
Matrix,
Quaternion,
)
import gpu
VERBOSE = True
# ############################################################
# Data structs
# ############################################################
def HMD(display_backend, context, error_callback):
"""
return the head mounted display device class
(defined in another file)
:param display_backend: backend engine
:type display_backend: str
:param context: BPY context
:type context: bpy.types.Context
:param error_callback: error handler
:type error_callback: func(message, is_fatal)
"""
from .oculus import Oculus
from .oculus_legacy import OculusLegacy
from .debug import Debug
displays = {
'OCULUS':Oculus,
'OCULUS_LEGACY':OculusLegacy,
'DEBUG':Debug,
}
if display_backend not in displays:
assert False, "Display Backend \"{0}\" not implemented".format(display_backend)
return displays[display_backend](context, error_callback)
# ############################################################
# Base class inherited by HMD devices
# ############################################################
class HMD_Base:
__slots__ = {
"_name",
"_current_eye",
"_error_callback",
"_width",
"_height",
"_projection_matrix",
"_head_transformation",
"_is_direct_mode",
"_eye_pose",
"_offscreen_object",
"_framebuffer_object",
"_color_object",
"_modelview_matrix",
"_near",
"_far",
}
def __init__(self, name, is_direct_mode, context, error_callback):
self._name = name
self._is_direct_mode = is_direct_mode
self._error_callback = error_callback
self._current_eye = 0
self._width = [0, 0]
self._height = [0, 0]
self._projection_matrix = [Matrix.Identity(4), Matrix.Identity(4)]
self._modelview_matrix = [Matrix.Identity(4), Matrix.Identity(4)]
self._framebuffer_object = [0, 0]
self._color_object = [0, 0]
self._offscreen_object = [None, None]
self._eye_orientation_raw = [[1.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0]]
self._eye_position_raw = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
self._scale = self._calculateScale(context)
self._updateViewClipping(context)
@property
def is_direct_mode(self):
return self._is_direct_mode
@property
def width(self):
return self._width[self._current_eye]
@width.setter
def width(self, value):
self._width[self._current_eye] = value
@property
def height(self):
return self._height[self._current_eye]
@height.setter
def height(self, value):
self._height[self._current_eye] = value
@property
def offscreen_object(self):
return self._offscreen_object[self._current_eye]
@property
def framebuffer_object(self):
return self._framebuffer_object[self._current_eye]
@property
def color_object(self):
return self._color_object[self._current_eye]
@property
def projection_matrix(self):
return self._projection_matrix[self._current_eye]
@property
def modelview_matrix(self):
return self._modelview_matrix[self._current_eye]
def setEye(self, eye):
self._current_eye = int(bool(eye))
def init(self):
"""
Initialize device
:return: return True if the device was properly initialized
:rtype: bool
"""
try:
for i in range(2):
self._offscreen_object[i] = gpu.offscreen.new(self._width[i], self._height[i], 0)
self._framebuffer_object[i] = self._offscreen_object[i].framebuffer_object
self._color_object[i] = self._offscreen_object[i].color_object
except Exception as E:
print(E)
self._offscreen_object[0] = None
self._offscreen_object[1] = None
return False
else:
return True
def loop(self, context):
"""
Get fresh tracking data
"""
self._updateViewClipping(context)
self.updateMatrices(context)
def frameReady(self):
"""
The frame is ready to be sent to the device
"""
assert False, "frameReady() not implemented for the \"{0}\" device".format(self._name)
def reCenter(self):
"""
Re-center the HMD device
:return: return True if success
:rtype: bool
"""
assert False, "reCenter() not implemented for the \"{0}\" device".format(self._name)
def quit(self):
"""
Garbage collection
"""
try:
for i in range(2):
self._offscreen_object[i] = None
except Exception as E:
print(E)
def error(self, function, exception, is_fatal):
"""
Handle error messages
"""
if VERBOSE:
print("ADD-ON :: {0}() : {1}".format(function, exception))
import sys
traceback = sys.exc_info()
if traceback and traceback[0]:
print(traceback[0])
if hasattr(exception, "strerror"):
message = exception.strerror
else:
message = str(exception)
# send the error the interface
self._error_callback(message, is_fatal)
def updateMatrices(self, context):
"""
Update OpenGL drawing matrices
"""
tracking_mode = context.window_manager.virtual_reality.tracking_mode
view_matrix = self._getViewMatrix(context)
for i in range(2):
if tracking_mode == 'NONE':
self._modelview_matrix[i] = view_matrix
continue
rotation_raw = self._eye_orientation_raw[i]
rotation = Quaternion(rotation_raw).to_matrix().to_4x4()
if tracking_mode == 'ALL':
position_raw = self._eye_position_raw[i]
# take scene units into consideration
position_raw = self._scaleMovement(position_raw)
position = Matrix.Translation(position_raw)
transformation = position * rotation
else: # 'ROTATION'
# rotation only, ignore the positional data
transformation = rotation
self._modelview_matrix[i] = transformation.inverted() * view_matrix
def _getViewMatrix(self, context):
region = context.region_data
if region.view_perspective == 'CAMERA':
space = context.space_data
camera = space.camera
return camera.matrix_world.inverted()
else:
return region.view_matrix.copy()
def _updateViewClipping(self, context):
space = context.space_data
region = context.region_data
if region.view_perspective == 'CAMERA':
camera_ob = space.camera
camera = camera_ob.data
self._near = camera.clip_start
self._far = camera.clip_end
else:
self._near = space.clip_start
self._far = space.clip_end
def _calculateScale(self, context):
"""
if BU != 1 meter, scale the transformations
"""
scene = context.scene
unit_settings = scene.unit_settings
system = unit_settings.system
if system == 'NONE':
return None
elif system == 'METRIC':
return 1.0 / unit_settings.scale_length
elif system == 'IMPERIAL':
return 0.3048 / unit_settings.scale_length
else:
assert('Unit system not supported ({0})'.format(system))
def _scaleMovement(self, position):
"""
if BU != 1 meter, scale the transformations
"""
if self._scale is None:
return position
return [position[0] * self._scale,
position[1] * self._scale,
position[2] * self._scale]
def _convertMatrixTo4x4(self, value):
matrix = Matrix()
matrix[0] = value[0:4]
matrix[1] = value[4:8]
matrix[2] = value[8:12]
matrix[3] = value[12:16]
return matrix.transposed()
debug.py 0000664 0000000 0000000 00000004176 12610116756 0033712 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/hmd """
Debug
=====
Debug device for testing
"""
from . import HMD_Base
VERBOSE = False
def print_debug(*args):
if VERBOSE:
print("Debug: {0}".format(*args))
class Debug(HMD_Base):
def __init__(self, context, error_callback):
super(Debug, self).__init__('Debug', False, context, error_callback)
def init(self, context):
"""
Initialize device
:return: return True if the device was properly initialized
:rtype: bool
"""
print_debug('init()')
self._width = [512, 512]
self._height = [512, 512]
return super(Debug, self).init()
def loop(self, context):
"""
Get fresh tracking data
"""
print_debug('loop()')
from math import fmod, radians
from mathutils import Matrix
global time
speed = 0.001
_range = 45.0
time = fmod(time + speed, 1.0)
factor = time * 2.0
if factor > 1.0:
factor = 2.0 - factor
one = 1.0 - factor
# one goes from 0.0 to 1.0, and then from 1.0 to 0.0
# angle goes from - range * 0.5 to + range * 0.5
angle = (one * _range) - (_range * 0.5)
quaternion = list(Matrix.Rotation(radians(angle), 4, 'Y').to_quaternion())
projection_matrix = self._getProjectionMatrix(context)
for eye in range(2):
self._eye_orientation_raw[eye] = quaternion
self._projection_matrix[eye] = projection_matrix
super(Debug, self).loop(context)
def _getProjectionMatrix(self, context):
region = context.region_data
if region.view_perspective == 'CAMERA':
space = context.space_data
camera = space.camera
return camera.calc_matrix_camera()
else:
return region.perspective_matrix.copy()
def frameReady(self):
"""
The frame is ready to be send to the device
"""
print_debug('frameReady()')
def quit(self):
"""
Garbage collection
"""
print_debug('quit()')
return super(Debug, self).quit()
global time
time = 0.0
oculus.py 0000664 0000000 0000000 00000006172 12610116756 0034134 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/hmd """
Oculus
======
Oculus (oculus.com) head mounted display
It uses a C app to connect with the SDK
The bridge code is hosted at Visgraf:
http://git.impa.br/dfelinto/oculus_sdk_bridge
"""
from . import HMD_Base
from ..lib import (
checkModule,
)
class Oculus(HMD_Base):
def __init__(self, context, error_callback):
super(Oculus, self).__init__('Oculus', True, context, error_callback)
checkModule('hmd_sdk_bridge')
def _getHMDClass(self):
from bridge.oculus import HMD
return HMD
@property
def projection_matrix(self):
if self._current_eye:
matrix = self._hmd.getProjectionMatrixRight(self._near, self._far)
else:
matrix = self._hmd.getProjectionMatrixLeft(self._near, self._far)
self.projection_matrix = matrix
return super(Oculus, self).projection_matrix
@projection_matrix.setter
def projection_matrix(self, value):
self._projection_matrix[self._current_eye] = \
self._convertMatrixTo4x4(value)
def init(self, context):
"""
Initialize device
:return: return True if the device was properly initialized
:rtype: bool
"""
try:
HMD = self._getHMDClass()
self._hmd = HMD()
# gather arguments from HMD
self.setEye(0)
self.width = self._hmd.width_left
self.height = self._hmd.height_left
self.setEye(1)
self.width = self._hmd.width_right
self.height = self._hmd.height_right
# initialize FBO
super(Oculus, self).init()
# send it back to HMD
if not self._setup():
raise Exception("Failed to setup HMD")
except Exception as E:
self.error("init", E, True)
self._hmd = None
return False
else:
return True
def _setup(self):
return self._hmd.setup(self._framebuffer_object[0], self._framebuffer_object[1])
def loop(self, context):
"""
Get fresh tracking data
"""
try:
data = self._hmd.update()
self._eye_orientation_raw[0] = data[0]
self._eye_orientation_raw[1] = data[2]
self._eye_position_raw[0] = data[1]
self._eye_position_raw[1] = data[3]
# update matrices
super(Oculus, self).loop(context)
except Exception as E:
self.error("loop", E, False)
return False
return True
def frameReady(self):
"""
The frame is ready to be sent to the device
"""
try:
self._hmd.frameReady()
except Exception as E:
self.error("frameReady", E, False)
return False
return True
def reCenter(self):
"""
Re-center the HMD device
:return: return True if success
:rtype: bool
"""
return self._hmd.reCenter()
def quit(self):
"""
Garbage collection
"""
self._hmd = None
return super(Oculus, self).quit()
oculus_legacy.py 0000664 0000000 0000000 00000001177 12610116756 0035460 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/hmd """
Oculus Legacy
=============
Oculus (oculus.com) head mounted display for OSX and Linux
It uses a python wrapper to connect with the SDK
"""
from . import HMD_Base
from .oculus import Oculus
from ..lib import (
checkModule,
)
class OculusLegacy(Oculus):
def __init__(self, context, error_callback):
HMD_Base.__init__(self, 'Oculus Legacy', False, context, error_callback)
checkModule('hmd_sdk_bridge')
def _getHMDClass(self):
from bridge.oculus_legacy import HMD
return HMD
def _setup(self):
return self._hmd.setup(self._color_object[0], self._color_object[1])
lib.py 0000664 0000000 0000000 00000001376 12610116756 0032621 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality """
Library
=======
Sorted util functions
"""
def getAddonName():
return __name__.split('.')[0]
def getDisplayBackend(context):
"""
Preference set in the addon
"""
addon = getAddonName()
preferences = context.user_preferences.addons[addon].preferences
return preferences.display_backend
def checkModule(path):
"""
If library exists append it to sys.path
"""
import sys
import os
addon_path = os.path.dirname(os.path.abspath(__file__))
library_path = os.path.join(addon_path, "lib", path)
if library_path not in sys.path:
sys.path.append(library_path)
def isMac():
"""
Return True if OS is Mac OSX
"""
from sys import platform as _platform
return _platform == "darwin"
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/lib/ 0000775 0000000 0000000 00000000000 12610116756 0032317 5 ustar 00root root 0000000 0000000 python-ovrsdk/ 0000775 0000000 0000000 00000000000 12610116756 0035067 5 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/lib opengl_helper.py 0000664 0000000 0000000 00000027164 12610116756 0034701 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality import bpy
from bgl import *
from mathutils import Matrix, Euler
SpaceView3D = bpy.types.SpaceView3D
callback_handle = []
fragment_shader ="""
#version 120
uniform sampler2D color_buffer;
void main(void)
{
vec2 coords = gl_TexCoord[0].st;
vec4 foreground = texture2D(color_buffer, coords);
gl_FragColor = mix(foreground, vec4(1.0, 0.0, 0.0, 1.0), 0.5);
}
"""
# ##################
# GLSL Debug
# ##################
def print_shader_errors(shader):
""""""
log = Buffer(GL_BYTE, len(fragment_shader))
length = Buffer(GL_INT, 1)
print('Shader Code:')
glGetShaderSource(shader, len(log), length, log)
line = 1
msg = " 1 "
for i in range(length[0]):
if chr(log[i-1]) == '\n':
line += 1
msg += "%3d %s" %(line, chr(log[i]))
else:
msg += chr(log[i])
print(msg)
glGetShaderInfoLog(shader, len(log), length, log)
print("Error in GLSL Shader:\n")
msg = ""
for i in range(length[0]):
msg += chr(log[i])
print (msg)
def print_program_errors(program):
""""""
log = Buffer(GL_BYTE, 1024)
length = Buffer(GL_INT, 1)
glGetProgramInfoLog(program, len(log), length, log)
print("Error in GLSL Program:\n")
msg = ""
for i in range(length[0]):
msg += chr(log[i])
print (msg)
# ######################
# OpenGL Image Routines
# ######################
def resize(self, context):
"""we can run every frame or only when width/height change"""
# remove old textures
self.quit()
self.width = context.region.width
self.height = context.region.height
self.buffer_width, self.buffer_height = calculate_image_size(self.width, self.height)
# image to dump screen
self.color_id = create_image(self.buffer_width, self.buffer_height, GL_RGBA)
def calculate_image_size(width, height):
"""get a power of 2 size"""
buffer_width, buffer_height = 0,0
i = 0
while (1 << i) <= width:i+= 1
buffer_width = 1 << i
i = 0
while (1 << i) <= height:i+= 1
buffer_height = 1 << i
return buffer_width, buffer_height
def update_image(tex_id, viewport, target=GL_RGBA, texture=GL_TEXTURE0):
"""copy the current buffer to the image"""
glActiveTexture(texture)
glBindTexture(GL_TEXTURE_2D, tex_id)
glCopyTexImage2D(GL_TEXTURE_2D, 0, target, viewport[0], viewport[1], viewport[2], viewport[3], 0)
glBindTexture(GL_TEXTURE_2D, 0)
def create_image(width, height, target=GL_RGBA):
"""create an empty image, dimensions pow2"""
if target == GL_RGBA:
target, internal_format, dimension = GL_RGBA, GL_RGB, 3
else:
target, internal_format, dimension = GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, 1
null_buffer = Buffer(GL_BYTE, [(width + 1) * (height + 1) * dimension])
id_buf = Buffer(GL_INT, 1)
glGenTextures(1, id_buf)
tex_id = id_buf.to_list()[0]
glBindTexture(GL_TEXTURE_2D, tex_id)
glTexImage2D(GL_TEXTURE_2D, 0, target, width, height, 0, internal_format, GL_UNSIGNED_BYTE, null_buffer)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
if target == GL_DEPTH_COMPONENT32:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE)
glCopyTexImage2D(GL_TEXTURE_2D, 0, target, 0, 0, width, height, 0)
glBindTexture(GL_TEXTURE_2D, 0)
del null_buffer
return tex_id
def delete_image(tex_id):
"""clear created image"""
id_buf = Buffer(GL_INT, 1)
id_buf.to_list()[0] = tex_id
if glIsTexture(tex_id):
glDeleteTextures(1, id_buf)
# ##################
# Framebuffer Routines
# ##################
def check_framebuffer_status(target):
status = glCheckFramebufferStatus(target)
if status == GL_FRAMEBUFFER_COMPLETE:
return True
elif status == GL_FRAMEBUFFER_UNDEFINED:
print("framebuffer not complete: GL_FRAMEBUFFER_UNDEFINED - returned if the specified framebuffer is the default read or draw framebuffer, but the default framebuffer does not exist.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT - returned if any of the framebuffer attachment points are framebuffer incomplete.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT - returned if the framebuffer does not have at least one image attached to it.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point named by GL_DRAW_BUFFERi.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - returned if GL_READ_BUFFER is not GL_NONE and the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER.")
elif status == GL_FRAMEBUFFER_UNSUPPORTED:
print("framebuffer not complete: GL_FRAMEBUFFER_UNSUPPORTED - returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE - returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES. also returned if the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS i s not the same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_TEXTURE_FIXED_SAMPLE_LOCATIONS is not GL_TRUE for all attached textures.")
elif status == GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
print("framebuffer not complete: GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS - returned if any framebuffer attachment is layered, and any populated attachment is not layered, or if all populated color attachments are not from textures of the same target.")
else:
print("framebuffer not complete: status 0x%x (unknown)" % (status,))
return False
def create_framebuffer(width, height, target=GL_RGBA):
"""create an empty framebuffer"""
id_buf = Buffer(GL_INT, 1)
glGenFramebuffers(1, id_buf)
fbo_id = id_buf.to_list()[0]
if fbo_id == 0:
print("Framebuffer error on creation")
return -1
tex_id = create_image(width, height)
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_id, 0)
glGenRenderbuffers(1, id_buf)
depth_id = id_buf.to_list()[0]
glBindRenderbuffer(GL_RENDERBUFFER, depth_id)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height)
# attach the depth buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_id)
#glDrawBuffers(fbo_id, GL_COLOR_ATTACHMENT0)
if not check_framebuffer_status(GL_DRAW_FRAMEBUFFER):
delete_framebuffer(fbo_id)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
return -1
glBindFramebuffer(GL_FRAMEBUFFER, 0)
return fbo_id
def delete_framebuffer(fbo_id):
"""clear created framebuffer"""
id_buf = Buffer(GL_INT, 1)
id_buf.to_list()[0] = fbo_id
if glIsFramebuffer(fbo_id):
glDeleteFramebuffers(1, id_buf)
# ##################
# GLSL Screen Shader
# ##################
def create_shader(source, program=None, type=GL_FRAGMENT_SHADER):
""""""
if program == None:
program = glCreateProgram()
shader = glCreateShader(type)
glShaderSource(shader, source)
glCompileShader(shader)
success = Buffer(GL_INT, 1)
glGetShaderiv(shader, GL_COMPILE_STATUS, success)
if not success[0]:
print_shader_errors(shader)
glAttachShader(program, shader)
glLinkProgram(program)
return program
def setup_uniforms(program, color_id, width, height, is_left):
""""""
uniform = glGetUniformLocation(program, "bgl_RenderedTexture")
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, color_id)
if uniform != -1: glUniform1i(uniform, 0)
uniform = glGetUniformLocation(program, "bgl_RenderedTextureWidth")
if uniform != -1: glUniform1f(uniform, width)
uniform = glGetUniformLocation(program, "bgl_RenderedTextureHeight")
if uniform != -1: glUniform1f(uniform, height)
uniform = glGetUniformLocation(program, "bgl_RenderedStereoEye")
if uniform != -1: glUniform1i(uniform, 0 if is_left else 1)
def bindcode(image):
"""load the image in the graphic card if necessary"""
image.gl_touch(GL_NEAREST)
return image.bindcode
# ##################
# Drawing Routines
# ##################
def view_setup():
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
glMatrixMode(GL_TEXTURE)
glPushMatrix()
glLoadIdentity()
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
glLoadIdentity()
glOrtho(-1, 1, -1, 1, -20, 20)
gluLookAt(0.0, 0.0, 1.0, 0.0,0.0,0.0, 0.0,1.0,0.0)
def view_reset():
# Get texture info
glMatrixMode(GL_PROJECTION)
glPopMatrix()
glMatrixMode(GL_TEXTURE)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)
glPopMatrix()
def draw_rectangle_rainbow(zed=0.0):
texco = [(1, 1), (0, 1), (0, 0), (1,0)]
verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), ( 1.0, -1.0)]
colors = [(1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (1.0, 1.0, 0.0, 0.0)]
glPolygonMode(GL_FRONT_AND_BACK , GL_FILL)
glBegin(GL_QUADS)
for i in range(4):
color = colors[i]
glColor4f(color[0], color[1], color[2], color[3])
glTexCoord3f(texco[i][0], texco[i][1], zed)
glVertex2f(verco[i][0], verco[i][1])
glEnd()
def draw_rectangle(zed=0.0):
texco = [(1, 1), (0, 1), (0, 0), (1,0)]
verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), ( 1.0, -1.0)]
glPolygonMode(GL_FRONT_AND_BACK , GL_FILL)
glColor4f(1.0, 1.0, 1.0, 0.0)
glBegin(GL_QUADS)
for i in range(4):
glTexCoord3f(texco[i][0], texco[i][1], zed)
glVertex2f(verco[i][0], verco[i][1])
glEnd()
def draw_callback_px(self, context):
"""core function"""
if not self._enabled: return
is_left = self.is_stereo_left(context)
act_tex = Buffer(GL_INT, 1)
glGetIntegerv(GL_ACTIVE_TEXTURE, act_tex)
glGetIntegerv(GL_VIEWPORT, self.viewport)
# (1) dump buffer in texture
update_image(self.color_id, self.viewport, GL_RGBA, GL_TEXTURE0)
# (2) run screenshader
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS)
pjm = Buffer(GL_FLOAT, 16)
mvm = Buffer(GL_FLOAT, 16)
cam_pos = context.scene.camera.location.copy()
glMatrixMode(GL_MODELVIEW)
glTranslatef(cam_pos[0], cam_pos[1], cam_pos[2])
glGetFloatv(GL_PROJECTION_MATRIX, pjm)
glGetFloatv(GL_MODELVIEW_MATRIX, mvm)
# set identity matrices
view_setup()
# update shader
glUseProgram(self.program_shader)
setup_uniforms(self.program_shader, self.color_id, self.width, self.height, is_left)
draw_rectangle()
# (3) restore opengl defaults
glUseProgram(0)
glActiveTexture(act_tex[0])
glBindTexture(GL_TEXTURE_2D, 0)
view_reset()
glViewport(self.viewport[0], self.viewport[1], self.viewport[2], self.viewport[3])
glMatrixMode(GL_MODELVIEW)
glTranslatef(-cam_pos[0], -cam_pos[1], -cam_pos[2])
operator.py 0000664 0000000 0000000 00000043353 12610116756 0033707 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality import bpy
from bpy.app.handlers import persistent
from .hmd import HMD
from .preview import Preview
from .lib import (
getDisplayBackend,
isMac,
)
TODO = False
# ############################################################
# Commands
# ############################################################
class Commands:
recenter = 'RECENTER'
fullscreen = 'FULLSCREEN'
play = 'PLAY'
pause = 'PAUSE'
test = 'TEST'
class SlaveStatus:
non_setup = 0 # initial
dupli = 1 # view3d duplicated
uiless = 2 # view3d without UI
waituser = 3 # waiting for user to move window to HMD
usermoved = 4 # user moved window
ready = 5 # all went well
play = 6 # play
pause = 7 # pause
paused = 8 # paused
error = 9 # something didn't work
# ############################################################
# Main Operator
# ############################################################
class VirtualRealityDisplayOperator(bpy.types.Operator):
""""""
bl_idname = "view3d.virtual_reality_display"
bl_label = "Toggle Virtual Reality Display"
bl_description = ""
# update the values in def _init_static
_hmd = None
_timer = None
_handle = None
_hash_slave = -1
_hash_master = -1
_slave_status = 0
_slave_window = None
_slave_area = None
_is_mac = False
action = bpy.props.EnumProperty(
description="",
items=(("ENABLE", "Enable", "Enable"),
("DISABLE", "Disable", "Disable"),
("TOGGLE", "Toggle", "Toggle"),
("RECENTER", "Re-Center", "Re-Center tracking data"),
("FULLSCREEN", "Fullscreen", "Make slave fullscreen"),
("PLAY", "Play", ""),
("PAUSE", "Pause", ""),
),
default="TOGGLE",
options={'SKIP_SAVE'},
)
@classmethod
def poll(cls, context):
return context.area.type == 'VIEW_3D'
def modal(self, context, event):
wm = context.window_manager
vr = wm.virtual_reality
area = context.area
if not area:
self.quit(context)
self._quit(context)
return {'FINISHED'}
if not vr.is_enabled:
self._quit(context)
area.tag_redraw()
return {'FINISHED'}
if event.type == 'TIMER' and \
not vr.is_paused:
if self._slave_area:
self._slave_area.tag_redraw()
if vr.use_preview:
area.tag_redraw()
return {'PASS_THROUGH'}
def invoke(self, context, event):
wm = context.window_manager
vr = wm.virtual_reality
is_enabled = vr.is_enabled
if self.action == 'TOGGLE':
self.action = 'DISABLE' if is_enabled else 'ENABLE'
if self.action == 'DISABLE':
if is_enabled:
self.quit(context)
return {'FINISHED'}
else:
self.report({'ERROR'}, "Virtual Reality Display is not enabled")
return {'CANCELLED'}
elif self.action == 'ENABLE':
if is_enabled:
self.report({'ERROR'}, "Virtual Reality Display is already enabled")
return {'CANCELLED'}
if self.init(context):
return {'RUNNING_MODAL'}
else:
# quit right away
vr.is_enabled = False
self._quit(context)
elif self.action == 'RECENTER':
vr.command_push(Commands.recenter)
return {'FINISHED'}
elif self.action == 'FULLSCREEN':
vr.command_push(Commands.fullscreen)
return {'FINISHED'}
elif self.action == 'PLAY':
vr.command_push(Commands.play)
# we define is_paused right away, so
# the next MODAL loop already tag_redraw
vr.is_paused = False
return {'FINISHED'}
elif self.action == 'PAUSE':
vr.command_push(Commands.pause)
self._redraw(context)
return {'FINISHED'}
else:
assert False, "action \"{0}\" not implemented".format(self.action)
return {'CANCELLED'}
def _redraw(self, context, redraw_master=True, redraw_slave=True):
if redraw_slave and self._slave_area:
self._slave_area.tag_redraw()
if redraw_master:
context.area.tag_redraw()
def quit(self, context):
"""garbage collect"""
# change it so the original modal operator will clean things up
wm = context.window_manager
wm.virtual_reality.reset()
def _quit(self, context):
"""actual quit"""
if self._timer:
wm = context.window_manager
wm.event_timer_remove(self._timer)
self._timer = None
if self._handle:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
self._handle = None
self._preview.quit()
if self._hmd:
self._hmd.quit()
if self._slave_window:
if hasattr(self._slave_window, "close"):
self._slave_window.close()
else:
print("Error closing HMD window")
# cleanup viewport
if context.area:
context.area.tag_redraw()
def _init_static(self):
self._hmd = None
self._timer = None
self._handle = None
self._hash_slave = -1
self._hash_master = -1
self._slave_status = 0
self._slave_window = None
self._slave_area = None
self._is_mac = isMac()
def init(self, context):
"""
Initialize the callbacks and the external devices
"""
wm = context.window_manager
vr = wm.virtual_reality
vr.reset()
vr.is_enabled = True
self._init_static()
display_backend = getDisplayBackend(context)
self._hmd = HMD(display_backend, context, self._error_callback)
self._preview = Preview()
self._hash_master = hash(context.area)
# setup modal
self._timer = wm.event_timer_add(1.0 / 75.0, context.window) # 75 Hz
self._handle = bpy.types.SpaceView3D.draw_handler_add(self._draw_callback_px, (context,), 'WINDOW', 'POST_PIXEL')
wm.modal_handler_add(self)
if self._hmd.is_direct_mode:
self._init(context)
else:
vr.is_slave_setup = True
return self._slaveSetup(context)
return True
def _init(self, context):
if not self._hmd.init(context):
self.report({'ERROR'}, "Error initializing device")
return False
# get the data from device
color_object = [0, 0]
for i in range(2):
self._hmd.setEye(i)
color_object[i] = self._hmd.color_object
self._preview.init(color_object[0], color_object[1])
return True
def _slaveSetup(self, context):
ok = True
if self._slave_status == SlaveStatus.error:
return False
elif self._slave_status == SlaveStatus.non_setup:
ok = self._slaveHook(context, SlaveStatus.dupli)
self._slave_status = SlaveStatus.dupli
elif self._slave_status == SlaveStatus.dupli:
ok = self._slaveHook(context, SlaveStatus.uiless)
self._slave_status = SlaveStatus.waituser
elif self._slave_status == SlaveStatus.waituser:
# waiting for the user input
return True
elif self._slave_status == SlaveStatus.usermoved:
if not self._is_mac:
bpy.ops.wm.window_fullscreen_toggle()
context.window_manager.virtual_reality.is_slave_setup = False
ok = self._init(context)
self._slave_status = SlaveStatus.ready
elif self._slave_status == SlaveStatus.play:
context.window_manager.virtual_reality.is_paused = False
self._slave_status = SlaveStatus.ready
elif self._slave_status == SlaveStatus.pause:
context.window_manager.virtual_reality.is_paused = True
context.area.tag_redraw()
self._slave_status = SlaveStatus.paused
else:
assert False, "_slaveSetup: Slave status \"{0}\" not defined".format(self._slave_status)
if not ok:
self._slave_status = SlaveStatus.error
self.quit(context)
self._slave_window = context.window
return ok
def _slaveHook(self, context, mode=''):
self._hash_slave = -1
self._slave_area = None
self._slave_status = SlaveStatus.non_setup
hashes = []
for screen in bpy.data.screens:
for area in screen.areas:
if area.type == 'VIEW_3D':
hashes.append(hash(area))
if mode == SlaveStatus.dupli:
bpy.ops.screen.area_dupli('INVOKE_DEFAULT')
elif mode == SlaveStatus.uiless:
bpy.ops.screen.screen_full_area(use_hide_panels=True)
else:
assert False, "_slaveHook: Slave status \"{0}\" not defined".format(self._slave_status)
for screen in bpy.data.screens:
for area in screen.areas:
if area.type != 'VIEW_3D':
continue
_hash = hash(area)
try:
hashes.remove(_hash)
except ValueError:
self._hash_slave = _hash
self._slave_area = area
print('Success finding slave')
return True
return False
def _commands(self, context):
"""
Process any pending command from the main window
"""
wm = context.window_manager
vr = wm.virtual_reality
while vr.commands:
command = vr.command_pop()
if command == Commands.recenter:
if self._hmd:
self._hmd.reCenter()
elif command == Commands.fullscreen:
self._slave_status = SlaveStatus.usermoved
self._slaveSetup(context)
elif command == Commands.play:
self._slave_status = SlaveStatus.play
self._slaveSetup(context)
elif command == Commands.pause:
self._slave_status = SlaveStatus.pause
self._slaveSetup(context)
elif command == Commands.test:
print("Testing !!!")
else:
assert False, "_commands: command \"{0}\" not implemented"
def _loop(self, context):
"""
Get fresh tracking data and render into the FBO
"""
self._hmd.loop(context)
for i in range(2):
self._hmd.setEye(i)
offscreen_object = self._hmd.offscreen_object
projection_matrix = self._hmd.projection_matrix
modelview_matrix = self._hmd.modelview_matrix
# drawing
offscreen_object.draw_view3d(projection_matrix, modelview_matrix)
self._hmd.frameReady()
def _drawMaster(self, context):
wm = context.window_manager
vr = wm.virtual_reality
if self._hmd.is_direct_mode:
self._commands(context)
if vr.is_paused:
return
if self._hmd.is_direct_mode:
self._loop(context)
if vr.use_preview:
self._preview.loop(vr.preview_scale)
def _drawSlave(self, context):
wm = context.window_manager
vr = wm.virtual_reality
if self._hmd.is_direct_mode:
return
self._commands(context)
if vr.is_paused:
return
if self._slave_status == SlaveStatus.ready:
self._loop(context)
elif self._slave_status == SlaveStatus.paused:
return
elif self._slave_status == SlaveStatus.waituser:
self._drawDisplayMessage(context)
else:
self._slaveSetup(context)
def _drawDisplayMessage(self, context):
"""
Message telling user to move the window the HMD display
"""
window = context.window
width = window.width
height = window.height
#glColor4f(1.0, 1.0, 1.0, 1.0)
font_id = 0
# draw some text
x = int(0.1 * width)
y = int(0.5 * height)
font_size = int(width * 0.035)
line_gap = int(font_size * 1.5)
from blf import (
SHADOW,
enable,
shadow,
shadow_offset,
position,
size,
draw,
disable,
)
enable(font_id, SHADOW)
shadow(font_id, 5, 0.0, 0.0, 0.0, 1.0)
shadow_offset(font_id, -2, -2)
size(font_id, font_size, 72)
if self._is_mac:
position(font_id, x, y + line_gap, 0)
draw(font_id, "1. Move this window to the external HMD display")
position(font_id, x, y, 0)
draw(font_id, "2. Set this window to fullscreen (Alt + F11)")
position(font_id, x, y - line_gap, 0)
draw(font_id, "3. Select \"Start\" in the main window")
else:
position(font_id, x, y, 0)
draw(font_id, "1. Move this window to the external HMD display")
position(font_id, x, y - line_gap, 0)
draw(font_id, "2. Select \"Start\" in the main window")
disable(font_id, SHADOW)
def _draw_callback_px(self, context):
"""
callback function, run every time the viewport is refreshed
"""
area = context.area
hash_area = hash(area)
if (hash_area == self._hash_slave):
self._drawSlave(context)
elif hash_area == self._hash_master:
self._drawMaster(context)
def _error_callback(self, message, is_fatal):
"""
Error handler, called from HMD class
"""
context = bpy.context
wm = context.window_manager
vr = wm.virtual_reality
if is_fatal:
self.report({'ERROR'}, message)
self.quit(context)
vr.error_message = message
# ############################################################
# Global Properties
# ############################################################
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
StringProperty,
IntProperty,
)
class VirtualRealityCommandInfo(bpy.types.PropertyGroup):
action = EnumProperty(
name="Action",
items=(("NONE", "None", ""),
(Commands.recenter, "Re-Center", ""),
(Commands.fullscreen, "Fullscreen", ""),
(Commands.play, "Play", ""),
(Commands.pause, "Pause", ""),
(Commands.test, "Test", ""),
),
default="NONE",
)
class VirtualRealityInfo(bpy.types.PropertyGroup):
is_enabled = BoolProperty(
name="Enabled",
default=False,
)
is_paused = BoolProperty(
name="Paused",
default=False,
)
use_preview = BoolProperty(
name="Preview",
default=False,
)
preview_scale = IntProperty(
name="Preview Scale",
min=0,
max=100,
default=20,
subtype='PERCENTAGE',
)
error_message = StringProperty(
name="Error Message",
)
tracking_mode = EnumProperty(
name="Tracking Mode",
description="",
items=(("ALL", "All", ""),
("ROTATION", "Rotation Only", "Ignore positional tracking data"),
("NONE", "None", "No tracking"),
),
default="ALL",
)
is_slave_setup = BoolProperty(
default = False,
)
commands = CollectionProperty(type=VirtualRealityCommandInfo)
def command_push(self, action):
command = self.commands.add()
command.action = action
def command_pop(self):
command = self.commands[0]
action = command.action
self.commands.remove(0)
return action
def reset(self):
while self.commands:
self.commands.remove(0)
self.use_preview = False
self.error_message = ""
self.is_enabled = False
self.is_slave_setup = False
self.is_paused = False
# ############################################################
# Callbacks
# ############################################################
@persistent
def virtual_reality_load_pre(dummy):
wm = bpy.context.window_manager
wm.virtual_reality.reset()
@persistent
def virtual_reality_load_post(dummy):
wm = bpy.context.window_manager
wm.virtual_reality.reset()
# ############################################################
# Un/Registration
# ############################################################
def register():
bpy.app.handlers.load_pre.append(virtual_reality_load_pre)
bpy.app.handlers.load_pre.append(virtual_reality_load_post)
bpy.utils.register_class(VirtualRealityDisplayOperator)
bpy.utils.register_class(VirtualRealityCommandInfo)
bpy.utils.register_class(VirtualRealityInfo)
bpy.types.WindowManager.virtual_reality = bpy.props.PointerProperty(
name="virtual_reality",
type=VirtualRealityInfo,
options={'HIDDEN'},
)
def unregister():
bpy.app.handlers.load_pre.remove(virtual_reality_load_pre)
bpy.app.handlers.load_pre.remove(virtual_reality_load_post)
bpy.utils.unregister_class(VirtualRealityDisplayOperator)
del bpy.types.WindowManager.virtual_reality
bpy.utils.unregister_class(VirtualRealityInfo)
bpy.utils.unregister_class(VirtualRealityCommandInfo)
preview.py 0000664 0000000 0000000 00000006035 12610116756 0033531 0 ustar 00root root 0000000 0000000 virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality """
Viewport Preview Drawing
************************
Routines to draw in the viewport the result
that is projected in the HMD
"""
from .opengl_helper import (
view_reset,
view_setup,
)
from bgl import *
class Preview:
__slots__ = {
"_color_object_left",
"_color_object_right",
}
def init(self, color_object_left, color_object_right):
"""
Initialize preview window
:param color_object_left: 2D Texture binding ID (bind to the Framebuffer Object) for left eye
:type color_object_left: bgl.GLuint
:param color_object_right: 2D Texture binding ID (bind to the Framebuffer Object) for right eye
:type color_object_right: bgl.GLuint
"""
self.update(color_object_left, color_object_right)
def quit(self):
"""
Destroy preview window
"""
pass
def update(self, color_object_left, color_object_right):
"""
Update OpenGL binding textures
:param color_object_left: 2D Texture binding ID (bind to the Framebuffer Object) for left eye
:type color_object_left: bgl.GLuint
:param color_object_right: 2D Texture binding ID (bind to the Framebuffer Object) for right eye
:type color_object_right: bgl.GLuint
"""
self._color_object_left = color_object_left
self._color_object_right = color_object_right
def _drawRectangle(self, eye):
texco = [(1, 1), (0, 1), (0, 0), (1,0)]
verco = [[(0.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), ( 0.0, -1.0)],
[(1.0, 1.0), ( 0.0, 1.0), ( 0.0, -1.0), ( 1.0, -1.0)]]
glPolygonMode(GL_FRONT_AND_BACK , GL_FILL)
glColor4f(1.0, 1.0, 1.0, 0.0)
glBegin(GL_QUADS)
for i in range(4):
glTexCoord3f(texco[i][0], texco[i][1], 0.0)
glVertex2f(verco[eye][i][0], verco[eye][i][1])
glEnd()
def loop(self, scale):
"""
Draw in the preview window
"""
if not scale:
return
act_tex = Buffer(GL_INT, 1)
glGetIntegerv(GL_TEXTURE_2D, act_tex)
if scale != 100:
viewport = Buffer(GL_INT, 4)
glGetIntegerv(GL_VIEWPORT, viewport)
width = int(scale * 0.01 * viewport[2])
height = int(scale * 0.01 * viewport[3])
glViewport(viewport[0], viewport[1], width, height)
glScissor(viewport[0], viewport[1], width, height)
glDisable(GL_DEPTH_TEST)
view_setup()
glEnable(GL_TEXTURE_2D)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self._color_object_left)
self._drawRectangle(0)
glBindTexture(GL_TEXTURE_2D, self._color_object_right)
self._drawRectangle(1)
glBindTexture(GL_TEXTURE_2D, act_tex[0])
glDisable(GL_TEXTURE_2D)
view_reset()
if scale != 100:
glViewport(viewport[0], viewport[1], viewport[2], viewport[3])
glScissor(viewport[0], viewport[1], viewport[2], viewport[3])
virtual_reality_viewport-ebed8a107c739355d0eb37881bc04bba759d9600/space_view3d_virtual_reality/ui.py0000664 0000000 0000000 00000004150 12610116756 0032540 0 ustar 00root root 0000000 0000000 import bpy
# ############################################################
# User Interface
# ############################################################
class VirtualRealityPanel(bpy.types.Panel):
bl_label = "Head Mounted Display"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = 'Virtual Reality'
@staticmethod
def draw(self, context):
layout = self.layout
wm = context.window_manager
vr = wm.virtual_reality
col = layout.column()
if not vr.is_enabled:
col.operator("view3d.virtual_reality_display", text="Virtual Reality").action='ENABLE'
else:
col.operator("view3d.virtual_reality_display", text="Virtual Reality", icon="X").action='DISABLE'
box = col.box()
col = box.column()
if vr.is_slave_setup:
col.operator("view3d.virtual_reality_display", text="Start", icon="CAMERA_STEREO").action='FULLSCREEN'
else:
if vr.is_paused:
col.operator("view3d.virtual_reality_display", text="Play", icon="PLAY").action='PLAY'
else:
col.operator("view3d.virtual_reality_display", text="Pause", icon="PAUSE").action='PAUSE'
row = col.row()
row.prop(vr, "use_preview")
sub = row.column()
sub.active = vr.use_preview
sub.prop(vr, "preview_scale", text="Scale")
col.operator("view3d.virtual_reality_display", text="Re-Center").action='RECENTER'
col.label(text="Tracking:")
col.row().prop(vr, "tracking_mode", expand=True)
if vr.error_message:
col.separator()
col.label(text=vr.error_message)
# ############################################################
# Un/Registration
# ############################################################
def register():
bpy.utils.register_class(VirtualRealityPanel)
def unregister():
bpy.utils.unregister_class(VirtualRealityPanel)