rotation gizmo, work on the blender plugin
parent
4bf6f3728c
commit
1df8255a30
|
@ -18,27 +18,33 @@
|
|||
|
||||
import os
|
||||
|
||||
bl_addon_info = {
|
||||
bl_info = {
|
||||
"name": "Mitsuba",
|
||||
"author": "Wenzel Jakob",
|
||||
"version": (0, 1),
|
||||
"blender": (2, 5, 5),
|
||||
"api": 31667,
|
||||
"version": (0, 2, 1),
|
||||
"blender": (2, 5, 6),
|
||||
"api": 35669,
|
||||
"category": "Render",
|
||||
"location": "Render > Engine > Mitsuba",
|
||||
"description": "Basic Mitsuba integration for Blender",
|
||||
"warning": "",
|
||||
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
|
||||
"Scripts/Render/Mitsuba",
|
||||
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba",
|
||||
"category": "Render"}
|
||||
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba"}
|
||||
|
||||
def plugin_path():
|
||||
return os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
from .core import RENDERENGINE_mitsuba
|
||||
if 'core' in locals():
|
||||
import imp
|
||||
imp.reload(core)
|
||||
else:
|
||||
import bpy
|
||||
|
||||
from extensions_framework import Addon
|
||||
MitsubaAddon = Addon(bl_info)
|
||||
register, unregister = MitsubaAddon.init_functions()
|
||||
|
||||
def register():
|
||||
RENDERENGINE_mitsuba.install()
|
||||
|
||||
def unregister():
|
||||
RENDERENGINE_mitsuba.uninstall()
|
||||
# Importing the core package causes extensions_framework managed
|
||||
# RNA class registration via @MitsubaAddon.addon_register_class
|
||||
from . import core
|
||||
|
|
|
@ -20,93 +20,61 @@
|
|||
import os, time, threading, subprocess, sys, copy
|
||||
|
||||
# Blender libs
|
||||
import bpy
|
||||
import bpy, bl_ui
|
||||
|
||||
# Framework libs
|
||||
from extensions_framework.engine import engine_base
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
# Mitsuba-related classes
|
||||
from mitsuba import plugin_path
|
||||
from mitsuba.properties.engine import mitsuba_engine
|
||||
from mitsuba.properties.sampler import mitsuba_sampler
|
||||
from mitsuba.properties.integrator import mitsuba_integrator
|
||||
from mitsuba.properties.lamp import mitsuba_lamp
|
||||
from mitsuba.properties.texture import mitsuba_texture, \
|
||||
mitsuba_tex_ldrtexture, mitsuba_tex_checkerboard, \
|
||||
mitsuba_tex_gridtexture, mitsuba_tex_mapping
|
||||
from mitsuba.properties.material import mitsuba_material, \
|
||||
mitsuba_mat_lambertian, mitsuba_mat_phong, mitsuba_mat_ward, \
|
||||
mitsuba_mat_microfacet, mitsuba_mat_roughglass, \
|
||||
mitsuba_mat_roughmetal, mitsuba_mat_dielectric, \
|
||||
mitsuba_mat_mirror, mitsuba_mat_difftrans, \
|
||||
mitsuba_mat_composite, mitsuba_emission
|
||||
from mitsuba.operators import MITSUBA_OT_preset_engine_add, EXPORT_OT_mitsuba
|
||||
from mitsuba.outputs import MtsLog, MtsFilmDisplay
|
||||
from mitsuba.export.adjustments import MtsAdjustments
|
||||
from mitsuba.export import translate_id
|
||||
from mitsuba.export.film import resolution
|
||||
from mitsuba.export import get_instance_materials
|
||||
from mitsuba.ui import render_panels, lamps
|
||||
from mitsuba.ui.textures import TEXTURE_PT_context_texture_mts
|
||||
from mitsuba.ui.textures import main, ldrtexture, checkerboard, \
|
||||
gridtexture, mapping
|
||||
from mitsuba.ui.materials import MATERIAL_PT_context_material_mts
|
||||
from mitsuba.ui.materials import main, lambertian, phong, ward, \
|
||||
microfacet, roughglass, roughmetal, dielectric, \
|
||||
mirror, difftrans, composite, emission
|
||||
from .. import MitsubaAddon, plugin_path
|
||||
|
||||
from ..outputs import MtsLog, MtsFilmDisplay
|
||||
from ..export.adjustments import MtsAdjustments
|
||||
from ..export.film import resolution
|
||||
from ..export import get_instance_materials, translate_id
|
||||
|
||||
from ..properties import (
|
||||
engine, sampler, integrator, lamp, texture, material
|
||||
);
|
||||
|
||||
from ..ui import (
|
||||
render_panels, lamps, materials
|
||||
)
|
||||
|
||||
from ..ui.textures import (
|
||||
main, ldrtexture, checkerboard, gridtexture, mapping
|
||||
)
|
||||
|
||||
from ..ui.materials import (
|
||||
main, lambertian, phong, ward, microfacet, roughglass,
|
||||
roughmetal, dielectric, mirror, difftrans, composite,
|
||||
emission
|
||||
)
|
||||
|
||||
from .. import operators
|
||||
|
||||
def compatible(mod):
|
||||
mod = __import__(mod)
|
||||
mod = __import__('bl_ui.' + mod)
|
||||
for subclass in mod.__dict__.values():
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('mitsuba')
|
||||
subclass.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
|
||||
except:
|
||||
pass
|
||||
del mod
|
||||
|
||||
import properties_data_lamp
|
||||
properties_data_lamp.DATA_PT_context_lamp.COMPAT_ENGINES.add('mitsuba')
|
||||
del properties_data_lamp
|
||||
|
||||
import properties_render
|
||||
properties_render.RENDER_PT_render.COMPAT_ENGINES.add('mitsuba')
|
||||
properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('mitsuba')
|
||||
properties_render.RENDER_PT_output.COMPAT_ENGINES.add('mitsuba')
|
||||
del properties_render
|
||||
bl_ui.properties_data_lamp.DATA_PT_context_lamp.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
|
||||
bl_ui.properties_render.RENDER_PT_render.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
|
||||
bl_ui.properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
|
||||
bl_ui.properties_render.RENDER_PT_output.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
|
||||
|
||||
compatible("properties_data_mesh")
|
||||
compatible("properties_data_camera")
|
||||
|
||||
class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
|
||||
bl_idname = 'mitsuba'
|
||||
@MitsubaAddon.addon_register_class
|
||||
class RENDERENGINE_mitsuba(bpy.types.RenderEngine):
|
||||
bl_idname = MitsubaAddon.BL_IDNAME
|
||||
bl_label = 'Mitsuba'
|
||||
bl_use_preview = True
|
||||
|
||||
property_groups = [
|
||||
('Scene', mitsuba_engine),
|
||||
('Scene', mitsuba_integrator),
|
||||
('Scene', mitsuba_sampler),
|
||||
('Lamp', mitsuba_lamp),
|
||||
('Texture', mitsuba_texture),
|
||||
('mitsuba_texture', mitsuba_tex_ldrtexture),
|
||||
('mitsuba_texture', mitsuba_tex_checkerboard),
|
||||
('mitsuba_texture', mitsuba_tex_gridtexture),
|
||||
('mitsuba_texture', mitsuba_tex_mapping),
|
||||
('Material', mitsuba_material),
|
||||
('Material', mitsuba_emission),
|
||||
('mitsuba_material', mitsuba_mat_lambertian),
|
||||
('mitsuba_material', mitsuba_mat_phong),
|
||||
('mitsuba_material', mitsuba_mat_ward),
|
||||
('mitsuba_material', mitsuba_mat_microfacet),
|
||||
('mitsuba_material', mitsuba_mat_roughglass),
|
||||
('mitsuba_material', mitsuba_mat_roughmetal),
|
||||
('mitsuba_material', mitsuba_mat_dielectric),
|
||||
('mitsuba_material', mitsuba_mat_difftrans),
|
||||
('mitsuba_material', mitsuba_mat_mirror),
|
||||
('mitsuba_material', mitsuba_mat_composite)
|
||||
]
|
||||
|
||||
render_lock = threading.Lock()
|
||||
|
||||
def process_wait_timer(self):
|
||||
|
|
|
@ -20,51 +20,46 @@
|
|||
import os, sys, copy, subprocess, traceback, string
|
||||
|
||||
# Blender Libs
|
||||
import bpy
|
||||
from presets import AddPresetBase
|
||||
import bpy, bl_operators
|
||||
|
||||
# Extensions_Framework Libs
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
from mitsuba.outputs import MtsLog
|
||||
from mitsuba.export.adjustments import MtsAdjustments
|
||||
from .. import MitsubaAddon
|
||||
from ..outputs import MtsLog
|
||||
from ..export.adjustments import MtsAdjustments
|
||||
|
||||
def try_preset_path_create(preset_subdir):
|
||||
target_path = os.path.join(bpy.utils.preset_paths('')[0], preset_subdir)
|
||||
if not os.path.exists(target_path):
|
||||
os.makedirs(target_path)
|
||||
|
||||
class MITSUBA_MT_base(object):
|
||||
class MITSUBA_MT_base(bpy.types.Menu):
|
||||
preset_operator = "script.execute_preset"
|
||||
def draw(self, context):
|
||||
try_preset_path_create(self.preset_subdir)
|
||||
return bpy.types.Menu.draw_preset(self, context)
|
||||
return self.draw_preset(context)
|
||||
|
||||
class MITSUBA_OT_preset_base(AddPresetBase):
|
||||
def execute(self, context):
|
||||
try_preset_path_create(self.preset_subdir)
|
||||
return super().execute(context)
|
||||
|
||||
class MITSUBA_MT_presets_engine(MITSUBA_MT_base, bpy.types.Menu):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_MT_presets_engine(MITSUBA_MT_base):
|
||||
bl_label = "Mitsuba Engine Presets"
|
||||
preset_subdir = "mitsuba/engine"
|
||||
|
||||
class MITSUBA_OT_preset_engine_add(MITSUBA_OT_preset_base, bpy.types.Operator):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_OT_preset_engine_add(bl_operators.presets.AddPresetBase, bpy.types.Operator):
|
||||
'''Save the current settings as a preset'''
|
||||
bl_idname = 'mitsuba.preset_engine_add'
|
||||
bl_label = 'Add Mitsuba Engine settings preset'
|
||||
preset_menu = 'MITSUBA_MT_presets_engine'
|
||||
preset_values = [
|
||||
'bpy.context.scene.mitsuba_engine.%s'%v['attr'] for v in bpy.types.mitsuba_engine.get_exportable_properties()
|
||||
]
|
||||
preset_subdir = 'mitsuba/engine'
|
||||
|
||||
def execute(self, context):
|
||||
self.preset_values = [
|
||||
'bpy.context.scene.mitsuba_engine.%s'%v['attr'] for v in bpy.types.mitsuba_engine.get_exportable_properties()
|
||||
]
|
||||
return super().execute(context)
|
||||
|
||||
|
||||
class MITSUBA_MT_presets_texture(MITSUBA_MT_base, bpy.types.Menu):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_MT_presets_texture(MITSUBA_MT_base):
|
||||
bl_label = "Mitsuba Texture Presets"
|
||||
preset_subdir = "mitsuba/texture"
|
||||
|
||||
class MITSUBA_OT_preset_texture_add(MITSUBA_OT_preset_base, bpy.types.Operator):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_OT_preset_texture_add(bl_operators.presets.AddPresetBase, bpy.types.Operator):
|
||||
'''Save the current settings as a preset'''
|
||||
bl_idname = 'mitsuba.preset_texture_add'
|
||||
bl_label = 'Add Mitsuba Texture settings preset'
|
||||
|
@ -89,12 +84,13 @@ class MITSUBA_OT_preset_texture_add(MITSUBA_OT_preset_base, bpy.types.Operator):
|
|||
self.preset_values = pv
|
||||
return super().execute(context)
|
||||
|
||||
|
||||
class MITSUBA_MT_presets_material(MITSUBA_MT_base, bpy.types.Menu):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_MT_presets_material(MITSUBA_MT_base):
|
||||
bl_label = "Mitsuba Material Presets"
|
||||
preset_subdir = "mitsuba/material"
|
||||
|
||||
class MITSUBA_OT_preset_material_add(MITSUBA_OT_preset_base, bpy.types.Operator):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_OT_preset_material_add(bl_operators.presets.AddPresetBase, bpy.types.Operator):
|
||||
'''Save the current settings as a preset'''
|
||||
bl_idname = 'mitsuba.preset_material_add'
|
||||
bl_label = 'Add Mitsuba Material settings preset'
|
||||
|
@ -121,6 +117,7 @@ class MITSUBA_OT_preset_material_add(MITSUBA_OT_preset_base, bpy.types.Operator)
|
|||
self.preset_values = pv
|
||||
return super().execute(context)
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class EXPORT_OT_mitsuba(bpy.types.Operator):
|
||||
bl_idname = 'export.mitsuba'
|
||||
bl_label = 'Export Mitsuba Scene (.xml)'
|
||||
|
@ -215,6 +212,7 @@ def menu_func(self, context):
|
|||
|
||||
bpy.types.INFO_MT_file_export.append(menu_func)
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_OT_material_slot_move(bpy.types.Operator):
|
||||
''' Rearrange the material slots '''
|
||||
bl_idname = 'mitsuba.material_slot_move'
|
||||
|
@ -245,6 +243,7 @@ class MITSUBA_OT_material_slot_move(bpy.types.Operator):
|
|||
obj.active_material_index = new_index
|
||||
return {'FINISHED'}
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MITSUBA_OT_material_add(bpy.types.Operator):
|
||||
''' Append a new material '''
|
||||
bl_idname = 'mitsuba.material_add'
|
||||
|
|
|
@ -16,15 +16,14 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_engine(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Engine settings.
|
||||
This class will be instantiated within a Blender scene
|
||||
object.
|
||||
'''
|
||||
ef_attach_to = ['Scene']
|
||||
|
||||
controls = [
|
||||
'export_mode',
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from .. import MitsubaAddon
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_integrator(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Integrator settings.
|
||||
|
@ -26,6 +28,8 @@ class mitsuba_integrator(declarative_property_group):
|
|||
object.
|
||||
'''
|
||||
|
||||
ef_attach_to = ['Scene']
|
||||
|
||||
controls = [
|
||||
'type',
|
||||
['motionblur',
|
||||
|
@ -42,7 +46,7 @@ class mitsuba_integrator(declarative_property_group):
|
|||
'attr': 'type',
|
||||
'name': 'Type',
|
||||
'description': 'Specifies the type of integrator to use',
|
||||
'default': 'ldintegrator',
|
||||
'default': 'direct',
|
||||
'items': [
|
||||
('direct', 'Direct Illumination', 'direct'),
|
||||
('path', 'Path tracer', 'path'),
|
||||
|
|
|
@ -16,9 +16,14 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_lamp(declarative_property_group):
|
||||
ef_attach_to = ['Lamp']
|
||||
|
||||
controls = [
|
||||
'samplingWeight',
|
||||
'envmap_type',
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
import math
|
||||
# ##### 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 #####
|
||||
|
||||
import bpy, math
|
||||
from copy import deepcopy
|
||||
|
||||
import bpy
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
from extensions_framework.validate import Logic_Operator
|
||||
from mitsuba.properties.texture import TextureParameter
|
||||
from mitsuba.export import ParamSet
|
||||
from ..properties.texture import TextureParameter
|
||||
from ..export import ParamSet
|
||||
|
||||
param_reflectance = TextureParameter('reflectance', 'Reflectance', \
|
||||
'Diffuse reflectance value', default=(0.5, 0.5, 0.5))
|
||||
|
@ -23,12 +41,15 @@ def dict_merge(*args):
|
|||
return vis
|
||||
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_material(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Material settings.
|
||||
This class will be instantiated within a Blender Material
|
||||
object.
|
||||
'''
|
||||
|
||||
ef_attach_to = ['Material']
|
||||
|
||||
controls = [
|
||||
'type',
|
||||
|
@ -41,7 +62,7 @@ class mitsuba_material(declarative_property_group):
|
|||
'attr': 'type',
|
||||
'name': 'Type',
|
||||
'description': 'Mitsuba material type',
|
||||
'default': 'matte',
|
||||
'default': 'lambertian',
|
||||
'items': [
|
||||
('lambertian', 'Lambertian', 'Lambertian (i.e. ideally diffuse) material'),
|
||||
('phong', 'Phong', 'Modified Phong BRDF'),
|
||||
|
@ -62,6 +83,7 @@ class mitsuba_material(declarative_property_group):
|
|||
sub_type = getattr(self, 'mitsuba_mat_%s' % self.type)
|
||||
return sub_type.get_params()
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_emission(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Material emission settings.
|
||||
|
@ -69,6 +91,8 @@ class mitsuba_emission(declarative_property_group):
|
|||
object.
|
||||
'''
|
||||
|
||||
ef_attach_to = ['Material']
|
||||
|
||||
controls = [
|
||||
'color',
|
||||
'intensity',
|
||||
|
@ -136,7 +160,9 @@ class mitsuba_emission(declarative_property_group):
|
|||
params.add_float('samplingWeight', self.samplingWeight)
|
||||
return params
|
||||
|
||||
class mitsuba_mat_lambertian(declarative_property_group):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_lambertian(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = param_reflectance.controls
|
||||
|
||||
properties = param_reflectance.properties
|
||||
|
@ -148,7 +174,9 @@ class mitsuba_mat_lambertian(declarative_property_group):
|
|||
params.update(param_reflectance.get_params(self))
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_phong(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'diffuseAmount',
|
||||
'specularAmount',
|
||||
|
@ -204,7 +232,9 @@ class mitsuba_mat_phong(declarative_property_group):
|
|||
params.add_float('exponent', self.exponent)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_ward(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'diffuseAmount',
|
||||
'specularAmount',
|
||||
|
@ -271,7 +301,9 @@ class mitsuba_mat_ward(declarative_property_group):
|
|||
params.add_float('alphaY', self.alphaY)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_microfacet(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'diffuseAmount',
|
||||
'specularAmount',
|
||||
|
@ -350,7 +382,9 @@ class mitsuba_mat_microfacet(declarative_property_group):
|
|||
params.add_float('intIOR', self.intIOR)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_roughglass(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'specularReflectance',
|
||||
'specularTransmittance',
|
||||
|
@ -422,7 +456,9 @@ class mitsuba_mat_roughglass(declarative_property_group):
|
|||
params.add_float('intIOR', self.intIOR)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_roughmetal(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'alphaB',
|
||||
'ior', 'k'
|
||||
|
@ -473,7 +509,9 @@ class mitsuba_mat_roughmetal(declarative_property_group):
|
|||
params.add_color('k', self.k)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_dielectric(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'specularReflectance',
|
||||
'specularTransmittance',
|
||||
|
@ -533,7 +571,9 @@ class mitsuba_mat_dielectric(declarative_property_group):
|
|||
params.add_float('intIOR', self.intIOR)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_mirror(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'specularReflectance'
|
||||
]
|
||||
|
@ -557,7 +597,9 @@ class mitsuba_mat_mirror(declarative_property_group):
|
|||
params.add_color('specularReflectance', self.specularReflectance)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_difftrans(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'transmittance'
|
||||
]
|
||||
|
@ -631,7 +673,9 @@ def mitsuba_mat_composite_visibility():
|
|||
result["mat%i_weight" % i] = {'nElements' : Logic_Operator({'gte' : i})}
|
||||
return result
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_mat_composite(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_material']
|
||||
controls = [
|
||||
'nElements'
|
||||
] + sum(map(lambda x: x.get_controls(), param_mat), [])
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_sampler(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Sampler settings.
|
||||
|
@ -26,6 +29,8 @@ class mitsuba_sampler(declarative_property_group):
|
|||
object.
|
||||
'''
|
||||
|
||||
ef_attach_to = ['Scene']
|
||||
|
||||
controls = [
|
||||
'type',
|
||||
'sampleCount'
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework import declarative_property_group
|
||||
from extensions_framework import util as efutil
|
||||
from extensions_framework.validate import Logic_OR as O
|
||||
|
@ -214,12 +216,15 @@ class TextureParameter(TextureParameterBase):
|
|||
)
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_texture(declarative_property_group):
|
||||
'''
|
||||
Storage class for Mitsuba Texture settings.
|
||||
This class will be instantiated within a Blender Texture
|
||||
object.
|
||||
'''
|
||||
|
||||
ef_attach_to = ['Texture']
|
||||
|
||||
controls = [
|
||||
'type'
|
||||
|
@ -249,7 +254,10 @@ class mitsuba_texture(declarative_property_group):
|
|||
else:
|
||||
return ParamSet()
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_tex_mapping(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_texture']
|
||||
|
||||
controls = [
|
||||
['uscale', 'vscale'],
|
||||
['uoffset', 'voffset']
|
||||
|
@ -310,7 +318,10 @@ class mitsuba_tex_mapping(declarative_property_group):
|
|||
mapping_params.add_float('voffset', self.voffset)
|
||||
return mapping_params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_tex_ldrtexture(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_texture']
|
||||
|
||||
controls = [
|
||||
'filename',
|
||||
'wrapMode',
|
||||
|
@ -399,7 +410,10 @@ class mitsuba_tex_ldrtexture(declarative_property_group):
|
|||
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_tex_checkerboard(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_texture']
|
||||
|
||||
controls = [
|
||||
'darkColor',
|
||||
'brightColor'
|
||||
|
@ -438,7 +452,10 @@ class mitsuba_tex_checkerboard(declarative_property_group):
|
|||
|
||||
return params
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class mitsuba_tex_gridtexture(declarative_property_group):
|
||||
ef_attach_to = ['mitsuba_texture']
|
||||
|
||||
controls = [
|
||||
'darkColor',
|
||||
'brightColor',
|
||||
|
|
|
@ -16,14 +16,16 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from properties_data_lamp import DataButtonsPanel
|
||||
import bpy, bl_ui
|
||||
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework.ui import property_group_renderer
|
||||
|
||||
narrowui = 180
|
||||
|
||||
class lamps(DataButtonsPanel, property_group_renderer, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class lamps(bl_ui.properties_data_lamp.DataButtonsPanel, property_group_renderer, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Lamps'
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from properties_material import MaterialButtonsPanel
|
||||
import bpy, bl_ui
|
||||
|
||||
from ... import MitsubaAddon
|
||||
from ...outputs import MtsLog
|
||||
|
||||
from extensions_framework.ui import property_group_renderer
|
||||
from mitsuba.outputs import MtsLog
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
material_cache = {}
|
||||
|
@ -36,8 +37,8 @@ def copy(value):
|
|||
else:
|
||||
raise Exception("Copy: don't know how to handle '%s'" % str(vlaue))
|
||||
|
||||
class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer):
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
class mitsuba_material_base(bl_ui.properties_material.MaterialButtonsPanel, property_group_renderer):
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
MTS_PROPS = ['type']
|
||||
|
||||
def validate(self, context):
|
||||
|
@ -71,8 +72,8 @@ class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer):
|
|||
def get_contents(self, mat):
|
||||
return mat.mitsuba_material
|
||||
|
||||
class mitsuba_material_sub(MaterialButtonsPanel, property_group_renderer):
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
class mitsuba_material_sub(bl_ui.properties_material.MaterialButtonsPanel, property_group_renderer):
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
MTS_COMPAT = set()
|
||||
MTS_PROPS = []
|
||||
|
||||
|
@ -116,9 +117,10 @@ class mitsuba_material_sub(MaterialButtonsPanel, property_group_renderer):
|
|||
context.material.preview_render_type = context.material.preview_render_type
|
||||
return super().draw(context)
|
||||
|
||||
class MATERIAL_PT_preview_mts(MaterialButtonsPanel, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MATERIAL_PT_preview_mts(bl_ui.properties_material.MaterialButtonsPanel, bpy.types.Panel):
|
||||
bl_label = "Preview"
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
|
||||
def draw(self, context):
|
||||
if not hasattr(context, 'material'):
|
||||
|
@ -141,11 +143,11 @@ class MATERIAL_PT_preview_mts(MaterialButtonsPanel, bpy.types.Panel):
|
|||
efutil.write_config_value('mitsuba', 'defaults', 'preview_spp', str(cached_spp))
|
||||
efutil.write_config_value('mitsuba', 'defaults', 'preview_depth', str(cached_depth))
|
||||
|
||||
|
||||
class MATERIAL_PT_context_material_mts(MaterialButtonsPanel, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class MATERIAL_PT_context_material_mts(bl_ui.properties_material.MaterialButtonsPanel, bpy.types.Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
from properties_material import active_node_mat
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Composite Material'
|
||||
|
||||
|
@ -33,7 +33,7 @@ class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
|
|||
def draw(self, context):
|
||||
super().draw(context)
|
||||
|
||||
mat = active_node_mat(context.material).mitsuba_material.mitsuba_mat_composite
|
||||
mat = bl_ui.properties_material.active_node_mat(context.material).mitsuba_material.mitsuba_mat_composite
|
||||
weight = 0
|
||||
missing = False
|
||||
selfRef = False
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_dielectric(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Dielectric Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_difftrans(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Diffuse Transmitter Material'
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_base
|
||||
from properties_material import active_node_mat
|
||||
import bpy, bl_ui
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class emission(mitsuba_material_base, bpy.types.Panel):
|
||||
'''
|
||||
Material Emission Settings
|
||||
|
@ -39,6 +39,6 @@ class emission(mitsuba_material_base, bpy.types.Panel):
|
|||
|
||||
def draw_header(self, context):
|
||||
if hasattr(context, "material"):
|
||||
mat = active_node_mat(context.material)
|
||||
mat = bl_ui.properties_material.active_node_mat(context.material)
|
||||
self.layout.prop(mat.mitsuba_emission, "use_emission", text="")
|
||||
self.validate(context)
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_lambertian(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Lambertian Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_base
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class main(mitsuba_material_base, bpy.types.Panel):
|
||||
'''
|
||||
Material Editor UI Panel
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_microfacet(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Microfacet Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_mirror(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Mirror Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_phong(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Phong Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_roughglass(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Rough Glass Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_roughmetal(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Rough Metal Material'
|
||||
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.materials import mitsuba_material_sub
|
||||
|
||||
from mitsuba.ui.materials import mitsuba_material_sub
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_material_ward(mitsuba_material_sub, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Ward Material'
|
||||
|
||||
|
|
|
@ -16,22 +16,24 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import os, bpy
|
||||
from properties_render import RenderButtonsPanel
|
||||
import os, bpy, bl_ui
|
||||
|
||||
from .. import MitsubaAddon
|
||||
|
||||
from extensions_framework.ui import property_group_renderer
|
||||
from extensions_framework import util as efutil
|
||||
|
||||
cached_binary_path = None
|
||||
|
||||
class render_described_context(RenderButtonsPanel, property_group_renderer):
|
||||
class render_panel(bl_ui.properties_render.RenderButtonsPanel, property_group_renderer):
|
||||
'''
|
||||
Base class for render engine settings panels
|
||||
'''
|
||||
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
|
||||
class setup_preset(render_described_context, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class setup_preset(render_panel, bpy.types.Panel):
|
||||
'''
|
||||
Engine settings presets UI Panel
|
||||
'''
|
||||
|
@ -46,7 +48,8 @@ class setup_preset(render_described_context, bpy.types.Panel):
|
|||
|
||||
super().draw(context)
|
||||
|
||||
class engine(render_described_context, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class engine(render_panel, bpy.types.Panel):
|
||||
'''
|
||||
Engine settings UI Panel
|
||||
'''
|
||||
|
@ -71,7 +74,8 @@ class engine(render_described_context, bpy.types.Panel):
|
|||
efutil.write_config_value('mitsuba', 'defaults', 'binary_path', binary_path)
|
||||
super().draw(context)
|
||||
|
||||
class integrator(render_described_context, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class integrator(render_panel, bpy.types.Panel):
|
||||
'''
|
||||
Integrator settings UI Panel
|
||||
'''
|
||||
|
@ -82,8 +86,8 @@ class integrator(render_described_context, bpy.types.Panel):
|
|||
( ('scene',), 'mitsuba_integrator' )
|
||||
]
|
||||
|
||||
|
||||
class sampler(render_described_context, bpy.types.Panel):
|
||||
@MitsubaAddon.addon_register_class
|
||||
class sampler(render_panel, bpy.types.Panel):
|
||||
'''
|
||||
Sampler settings UI Panel
|
||||
'''
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
|
||||
from properties_texture import TextureButtonsPanel
|
||||
from properties_texture import context_tex_datablock
|
||||
import bpy, bl_ui
|
||||
|
||||
from extensions_framework.ui import property_group_renderer
|
||||
|
||||
class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
|
||||
from ... import MitsubaAddon
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class TEXTURE_PT_context_texture_mts(bl_ui.properties_texture.TextureButtonsPanel, bpy.types.Panel):
|
||||
bl_label = ""
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
@ -42,7 +42,7 @@ class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
|
|||
node = context.texture_node
|
||||
space = context.space_data
|
||||
tex = context.texture
|
||||
idblock = context_tex_datablock(context)
|
||||
idblock = bl_ui.properties_texture.context_tex_datablock(context)
|
||||
tex_collection = space.pin_id is None and type(idblock) != bpy.types.Brush and not node
|
||||
|
||||
if tex_collection:
|
||||
|
@ -70,12 +70,12 @@ class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
|
|||
|
||||
col = split.column()
|
||||
|
||||
class mitsuba_texture_base(TextureButtonsPanel, property_group_renderer):
|
||||
class mitsuba_texture_base(bl_ui.properties_texture.TextureButtonsPanel, property_group_renderer):
|
||||
'''
|
||||
This is the base class for all Mitsuba texture sub-panels.
|
||||
'''
|
||||
|
||||
COMPAT_ENGINES = {'mitsuba'}
|
||||
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
|
||||
MTS_COMPAT = set()
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from mitsuba.ui.textures import mitsuba_texture_base
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.textures import mitsuba_texture_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_texture_checkerboard(mitsuba_texture_base, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Checkerboard Texture'
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from mitsuba.ui.textures import mitsuba_texture_base
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.textures import mitsuba_texture_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_texture_gridtexture(mitsuba_texture_base, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Grid Texture'
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from mitsuba.ui.textures import mitsuba_texture_base
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.textures import mitsuba_texture_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_texture_ldrtexture(mitsuba_texture_base, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba Bitmap Texture'
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from mitsuba.ui.textures import mitsuba_texture_base
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.textures import mitsuba_texture_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_texture_main(mitsuba_texture_base, bpy.types.Panel):
|
||||
'''
|
||||
Texture Editor UI Panel
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from mitsuba.ui.textures import mitsuba_texture_base
|
||||
from ... import MitsubaAddon
|
||||
from ...ui.textures import mitsuba_texture_base
|
||||
|
||||
@MitsubaAddon.addon_register_class
|
||||
class ui_texture_mapping(mitsuba_texture_base, bpy.types.Panel):
|
||||
bl_label = 'Mitsuba UV Mapping'
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2010 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined(__GIZMO_H)
|
||||
#define __GIZMO_H
|
||||
|
||||
#include <mitsuba/hw/renderer.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/**
|
||||
* This class is responsible for rendering `gizmos', which are
|
||||
* intuitive controls for navigating through 3D space.
|
||||
*/
|
||||
class MTS_EXPORT_HW Gizmo : public Object {
|
||||
public:
|
||||
Gizmo();
|
||||
|
||||
/// Initialize the gizmo for the specified bounding sphere
|
||||
void init(const BSphere &bsphere);
|
||||
|
||||
/// Start a new drag operation
|
||||
void startDrag(const Ray &ray);
|
||||
|
||||
//// Perform a drag to the specified ray
|
||||
void dragTo(const Ray &ray, const Camera *camera);
|
||||
|
||||
/// Check whether the gizmo is currently active
|
||||
inline bool isActive() const { return m_active; }
|
||||
|
||||
/// Check whether the gizmo is currently used in a drag operation
|
||||
inline bool isDragging() const { return m_drag; }
|
||||
|
||||
/// Check whether a certain ray intersects the gizmo
|
||||
inline void rayIntersect(const Ray &ray, Float &t) const {
|
||||
Float farT;
|
||||
if (!m_active || !m_bsphere.rayIntersect(ray, t, farT)) {
|
||||
t = std::numeric_limits<Float>::infinity();
|
||||
} else {
|
||||
if (t <= 0)
|
||||
t = farT;
|
||||
if (t <= 0)
|
||||
t = std::numeric_limits<Float>::infinity();
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw the gizmo
|
||||
void draw(Renderer *renderer, const Camera *camera);
|
||||
|
||||
/// Return the transformation associated with the gizmo
|
||||
Transform getTransform() const;
|
||||
|
||||
/// Reset the gizmo
|
||||
inline void reset() { m_active = m_drag = false; }
|
||||
|
||||
/// Stop dragging
|
||||
inline void stopDrag() { m_drag = false; }
|
||||
|
||||
/// Return the bounding sphere associated with the gizmo
|
||||
inline const BSphere &getBSphere() const { return m_bsphere; }
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
protected:
|
||||
/// Virtual destructor
|
||||
virtual ~Gizmo();
|
||||
private:
|
||||
BSphere m_bsphere;
|
||||
Point m_dragStart, m_dragEnd;
|
||||
bool m_active, m_drag;
|
||||
};
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
||||
#endif /* __GIZMO_H */
|
|
@ -53,6 +53,9 @@ public:
|
|||
/// Set a float parameter
|
||||
void setParameter(int id, Float value);
|
||||
|
||||
/// Set a integer parameter
|
||||
void setParameter(int id, int value);
|
||||
|
||||
/// Set a Vector parameter
|
||||
void setParameter(int id, const Vector &value);
|
||||
|
||||
|
@ -97,7 +100,7 @@ public:
|
|||
|
||||
/** Set a GPUTexture parameter. Must be executed after
|
||||
binding the texture to a texture unit */
|
||||
void setParameter(int id, const GPUTexture *value);
|
||||
void setParameter(int id, const GPUTexture *value);
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
protected:
|
||||
|
|
|
@ -102,6 +102,13 @@ public:
|
|||
bool centerHoriz = true, bool centerVert = true,
|
||||
const Vector2i &offset = Vector2i(0, 0));
|
||||
|
||||
/// Draw a planar circle with the specified center, normal and radius
|
||||
void drawCircle(const Point ¢er, const Normal &normal, Float radius);
|
||||
|
||||
/// Draw a 3D arc connecting \c p1 and \c p2
|
||||
void drawArc(const Point ¢er,
|
||||
const Point &p1, const Point &p2, bool shorterPiece);
|
||||
|
||||
/// Clean up the renderer after drawing triangle geometry
|
||||
void endDrawingMeshes();
|
||||
|
||||
|
|
|
@ -39,9 +39,19 @@ public:
|
|||
|
||||
/// Free the texture from GPU memory
|
||||
void cleanup();
|
||||
|
||||
/// Bind the texture and enable texturing
|
||||
void bind(int textureUnit = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Bind the texture and enable texturing
|
||||
*
|
||||
* \param textureUnit
|
||||
* Specifies the unit to which this texture should be bound
|
||||
* \param textureIndex
|
||||
* When this texture has multiple sub-textures (e.g.
|
||||
* a color and depth map in the case of a
|
||||
* \ref EColorAndDepthBuffer texture), this parameter
|
||||
* specifies the one to be bound
|
||||
*/
|
||||
void bind(int textureUnit = 0, int textureIndex = 0) const;
|
||||
|
||||
/// Download the texture (only for render target textures)
|
||||
void download(Bitmap *bitmap = NULL);
|
||||
|
@ -61,8 +71,35 @@ public:
|
|||
/// Deactivate the render target
|
||||
void releaseTarget();
|
||||
|
||||
/// Blit a float render buffer into another render buffer
|
||||
void blit(GPUTexture *texture) const;
|
||||
/**
|
||||
* \brief Blit a render buffer into another render buffer
|
||||
*
|
||||
* \param target
|
||||
* Specifies the target render buffer (or NULL for the framebuffer)
|
||||
* \param what
|
||||
* A bitwise-OR of the components in \ref EFrameBufferType to copy
|
||||
*/
|
||||
void blit(GPUTexture *target, int what) const;
|
||||
|
||||
/**
|
||||
* \brief Blit a render buffer into another render buffer
|
||||
*
|
||||
* \param target
|
||||
* Specifies the target render buffer (or NULL for the framebuffer)
|
||||
* \param what
|
||||
* A bitwise-OR of the components in \ref EFrameBufferType to copy
|
||||
* \param sourceOffset
|
||||
* Offset in the source render buffer
|
||||
* \param sourceOffset
|
||||
* Size of the region to be copied from the source render buffer
|
||||
* \param destOffset
|
||||
* Offset in the destination render buffer
|
||||
* \param destOffset
|
||||
* Size of the region to be copied into the dest destination buffer
|
||||
*/
|
||||
void blit(GPUTexture *target, int what, const Point2i &sourceOffset,
|
||||
const Vector2i &sourceSize, const Point2i &destOffset,
|
||||
const Vector2i &destSize) const;
|
||||
|
||||
/// Clear (assuming that this is a render buffer)
|
||||
void clear();
|
||||
|
@ -86,9 +123,7 @@ protected:
|
|||
GLuint m_format;
|
||||
GLuint m_internalFormat;
|
||||
GLuint m_dataFormat;
|
||||
/* For render targets */
|
||||
GLuint m_fboId, m_depthId;
|
||||
GLuint m_extraId;
|
||||
mutable bool m_needsUpdate;
|
||||
};
|
||||
|
||||
|
|
|
@ -72,6 +72,12 @@ public:
|
|||
setParameter(getParameterID(name, failIfMissing), value);
|
||||
}
|
||||
|
||||
/// Set a integer parameter by name
|
||||
inline void setParameter(const std::string &name, int value,
|
||||
bool failIfMissing = true) {
|
||||
setParameter(getParameterID(name, failIfMissing), value);
|
||||
}
|
||||
|
||||
/// Set a float parameter by name
|
||||
inline void setParameter(const std::string &name, Float value,
|
||||
bool failIfMissing = true) {
|
||||
|
@ -181,6 +187,9 @@ public:
|
|||
/// Set a float parameter
|
||||
virtual void setParameter(int id, Float value) = 0;
|
||||
|
||||
/// Set a int parameter
|
||||
virtual void setParameter(int id, int value) = 0;
|
||||
|
||||
/// Set a Vector parameter
|
||||
virtual void setParameter(int id, const Vector &value) = 0;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
/// Available texture types
|
||||
enum ETextureType {
|
||||
/**
|
||||
* 1-D texture, useful for the storage of pre-calculated functions
|
||||
* \brief 1-D texture, useful for the storage of pre-calculated functions
|
||||
* in conjunction with pixel shaders. Needs 1D texture coordinates
|
||||
*/
|
||||
ETexture1D = 0,
|
||||
|
@ -48,16 +48,22 @@ public:
|
|||
};
|
||||
|
||||
/** \brief If the texture type is set to EFrameBuffer, the
|
||||
* configuration must be specified */
|
||||
* configuration must be one of the following constants */
|
||||
enum EFrameBufferType {
|
||||
/// This is not a framebuffer
|
||||
ENone = 0,
|
||||
ENone = 0x00,
|
||||
|
||||
/// Z-buffered color framebuffer
|
||||
EColorBuffer,
|
||||
/**
|
||||
* \brief Color framebuffer (\a including an internal depth
|
||||
* buffer that cannot be accessed as a texture)
|
||||
*/
|
||||
EColorBuffer = 0x01,
|
||||
|
||||
/// Depth-only framebuffer (e.g. for shadow mapping)
|
||||
EDepthBuffer
|
||||
EDepthBuffer = 0x02,
|
||||
|
||||
/// Color and texture framebuffer (both exposed as textures)
|
||||
EColorAndDepthBuffer = 0x03
|
||||
};
|
||||
|
||||
/// A texture has one more slots into which bitmaps can be placed
|
||||
|
@ -260,8 +266,18 @@ public:
|
|||
/// Free the texture from GPU memory
|
||||
virtual void cleanup() = 0;
|
||||
|
||||
/// Bind the texture and enable texturing
|
||||
virtual void bind(int textureUnit = 0) const = 0;
|
||||
/**
|
||||
* \brief Bind the texture and enable texturing
|
||||
*
|
||||
* \param textureUnit
|
||||
* Specifies the unit to which this texture should be bound
|
||||
* \param textureIndex
|
||||
* When this texture has multiple sub-textures (e.g.
|
||||
* a color and depth map in the case of a
|
||||
* \ref EColorAndDepthBuffer texture), this parameter
|
||||
* specifies the one to be bound
|
||||
*/
|
||||
virtual void bind(int textureUnit = 0, int textureIndex = 0) const = 0;
|
||||
|
||||
/// Unbind the texture and disable texturing
|
||||
virtual void unbind() const = 0;
|
||||
|
@ -294,8 +310,35 @@ public:
|
|||
/// Return the number of samples (for multisample color render targets)
|
||||
inline int getSampleCount() const { return m_samples; }
|
||||
|
||||
/// Blit a float render buffer into another render buffer
|
||||
virtual void blit(GPUTexture *texture) const = 0;
|
||||
/**
|
||||
* \brief Blit a render buffer into another render buffer
|
||||
*
|
||||
* \param target
|
||||
* Specifies the target render buffer
|
||||
* \param what
|
||||
* A bitwise-OR of the components in \ref EFrameBufferType to copy
|
||||
*/
|
||||
virtual void blit(GPUTexture *target, int what) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Blit a render buffer into another render buffer
|
||||
*
|
||||
* \param target
|
||||
* Specifies the target render buffer (or NULL for the framebuffer)
|
||||
* \param what
|
||||
* A bitwise-OR of the components in \ref EFrameBufferType to copy
|
||||
* \param sourceOffset
|
||||
* Offset in the source render buffer
|
||||
* \param sourceOffset
|
||||
* Size of the region to be copied from the source render buffer
|
||||
* \param destOffset
|
||||
* Offset in the destination render buffer
|
||||
* \param destOffset
|
||||
* Size of the region to be copied into the dest destination buffer
|
||||
*/
|
||||
virtual void blit(GPUTexture *target, int what, const Point2i &sourceOffset,
|
||||
const Vector2i &sourceSize, const Point2i &destOffset,
|
||||
const Vector2i &destSize) const = 0;
|
||||
|
||||
/// Clear (assuming that this is a render buffer)
|
||||
virtual void clear() = 0;
|
||||
|
|
|
@ -76,9 +76,9 @@ class MTS_EXPORT_HW Renderer : public Object {
|
|||
public:
|
||||
/* Possible blending modes */
|
||||
enum EBlendMode {
|
||||
EBlendNone, // Blending turned off
|
||||
EBlendAlpha, // Normal alpha blending
|
||||
EBlendAdditive // Additive blending
|
||||
EBlendNone, // Blending turned off
|
||||
EBlendAlpha, // Normal alpha blending
|
||||
EBlendAdditive // Additive blending
|
||||
};
|
||||
|
||||
/* Possible culling modes */
|
||||
|
@ -162,6 +162,14 @@ public:
|
|||
bool centerHoriz = true, bool centerVert = true,
|
||||
const Vector2i &offset = Vector2i(0, 0)) = 0;
|
||||
|
||||
/// Draw a planar circle with the specified center, normal and radius
|
||||
virtual void drawCircle(const Point ¢er,
|
||||
const Normal &normal, Float radius) = 0;
|
||||
|
||||
/// Draw a 3D arc connecting \c p1 and \c p2
|
||||
virtual void drawArc(const Point ¢er,
|
||||
const Point &p1, const Point &p2, bool shorterPiece) = 0;
|
||||
|
||||
/// Blit a screen-sized quad
|
||||
virtual void blitQuad(bool flipVertically) = 0;
|
||||
|
||||
|
|
|
@ -255,8 +255,6 @@ public:
|
|||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
Float m_beta;
|
||||
};
|
||||
|
||||
MTS_IMPLEMENT_CLASS_S(SimpleVolumetricPathTracer, false, MonteCarloIntegrator)
|
||||
|
|
|
@ -4,7 +4,7 @@ libhw_objects = [
|
|||
'session.cpp', 'device.cpp', 'gputexture.cpp', 'gpugeometry.cpp',
|
||||
'gpuprogram.cpp', 'renderer.cpp', 'glrenderer.cpp', 'glprogram.cpp',
|
||||
'glgeometry.cpp', 'gltexture.cpp', 'gpusync.cpp', 'glsync.cpp',
|
||||
'vpl.cpp', 'font.cpp', 'viewer.cpp']
|
||||
'vpl.cpp', 'font.cpp', 'viewer.cpp', 'gizmo.cpp']
|
||||
|
||||
if sys.platform == 'win32':
|
||||
libhw_objects += ['wglsession.cpp',
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2010 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mitsuba/hw/gizmo.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
Gizmo::Gizmo() : m_active(false), m_drag(false) { }
|
||||
|
||||
Gizmo::~Gizmo() { }
|
||||
|
||||
void Gizmo::init(const BSphere &bsphere) {
|
||||
m_bsphere = bsphere;
|
||||
m_active = true;
|
||||
m_drag = false;
|
||||
}
|
||||
|
||||
Transform Gizmo::getTransform() const {
|
||||
Vector leg1 = normalize(m_dragStart - m_bsphere.center);
|
||||
Vector leg2 = normalize(m_dragEnd - m_bsphere.center);
|
||||
Vector rotAxis = normalize(cross(leg1, leg2));
|
||||
Float angle = unitAngle(leg1, leg2) * 180/M_PI;
|
||||
|
||||
return Transform::translate(Vector(m_bsphere.center)) *
|
||||
Transform::rotate(rotAxis, angle) *
|
||||
Transform::translate(-Vector(m_bsphere.center));
|
||||
}
|
||||
|
||||
void Gizmo::startDrag(const Ray &ray) {
|
||||
m_drag = false;
|
||||
Float nearT, farT;
|
||||
if (!m_bsphere.rayIntersect(ray, nearT, farT)
|
||||
|| (nearT < 0 && farT < 0)) {
|
||||
Log(EWarn, "Gizmo::init(): Internal error (no intersection found)!");
|
||||
return;
|
||||
} else if (nearT < 0) {
|
||||
m_dragStart = ray(farT);
|
||||
} else {
|
||||
m_dragStart = ray(nearT);
|
||||
}
|
||||
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
void Gizmo::dragTo(const Ray &ray, const Camera *camera) {
|
||||
Float nearT, farT;
|
||||
if (m_bsphere.rayIntersect(ray, nearT, farT)) {
|
||||
if (nearT < 0)
|
||||
m_dragEnd = ray(farT);
|
||||
else
|
||||
m_dragEnd = ray(nearT);
|
||||
} else {
|
||||
Normal n(normalize(m_bsphere.center - camera->getPosition()));
|
||||
Float t = (dot(n, Vector(m_bsphere.center)) - dot(n, Vector(ray.o)))/dot(n, ray.d);
|
||||
Point closest = ray(t);
|
||||
m_dragEnd = m_bsphere.center + normalize(closest -
|
||||
m_bsphere.center) * m_bsphere.radius;
|
||||
}
|
||||
m_drag = true;
|
||||
}
|
||||
|
||||
void Gizmo::draw(Renderer *renderer, const Camera *camera) {
|
||||
if (m_bsphere.isEmpty())
|
||||
return;
|
||||
|
||||
/* Compute the tangent circle */
|
||||
Vector camToSphere(m_bsphere.center - camera->getPosition());
|
||||
const Float length = camToSphere.length(), radius = m_bsphere.radius;
|
||||
camToSphere /= length;
|
||||
|
||||
Float tcRadius = std::sqrt(length*length - radius*radius)*radius/length;
|
||||
Float tcDist = std::sqrt(radius*radius - tcRadius*tcRadius);
|
||||
|
||||
renderer->drawCircle(m_bsphere.center - camToSphere * tcDist,
|
||||
camToSphere, tcRadius);
|
||||
|
||||
if (m_drag) {
|
||||
Spectrum color1, color2;
|
||||
color1.fromLinearRGB(0.7f, 0.7f, 1.0f);
|
||||
color2.fromLinearRGB(0.3f, 0.3f, 0.3f);
|
||||
Transform trafo = getTransform().inverse();
|
||||
Point dragEnd = trafo(trafo(m_dragEnd));
|
||||
|
||||
renderer->setColor(color1);
|
||||
renderer->drawArc(m_bsphere.center, m_dragStart, dragEnd, true);
|
||||
renderer->setColor(color2);
|
||||
renderer->drawArc(m_bsphere.center, m_dragStart, dragEnd, false);
|
||||
|
||||
Vector rotAxis = normalize(cross(m_dragStart-m_bsphere.center,
|
||||
dragEnd-m_bsphere.center));
|
||||
Vector circle2Axis = cross(normalize(m_dragStart-m_bsphere.center), rotAxis);
|
||||
renderer->drawCircle(m_bsphere.center, Normal(circle2Axis), radius);
|
||||
renderer->setColor(Spectrum(1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS(Gizmo, false, Object)
|
||||
MTS_NAMESPACE_END
|
|
@ -170,6 +170,12 @@ void GLProgram::setParameter(int id, Float value) {
|
|||
glUniform1f(id, (GLfloat) value);
|
||||
}
|
||||
|
||||
void GLProgram::setParameter(int id, int value) {
|
||||
if (id == -1)
|
||||
return;
|
||||
glUniform1i(id, value);
|
||||
}
|
||||
|
||||
void GLProgram::setParameter(int id, const Vector &value) {
|
||||
if (id == -1)
|
||||
return;
|
||||
|
|
|
@ -741,6 +741,51 @@ void GLRenderer::blitQuad(bool flipVertically) {
|
|||
glEnd();
|
||||
}
|
||||
|
||||
void GLRenderer::drawCircle(const Point ¢er,
|
||||
const Normal &normal, Float radius) {
|
||||
int nDiscr = 80;
|
||||
Vector X, Y;
|
||||
Float stepSize = 2*M_PI/nDiscr;
|
||||
coordinateSystem(normal, X, Y);
|
||||
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (int i=0; i<nDiscr; ++i) {
|
||||
Float sinTheta = std::sin(i * stepSize) * radius;
|
||||
Float cosTheta = std::cos(i * stepSize) * radius;
|
||||
Point p = center + X*cosTheta + Y*sinTheta;
|
||||
glVertex3f(p.x, p.y, p.z);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void GLRenderer::drawArc(const Point ¢er,
|
||||
const Point &p1, const Point &p2, bool shorterPiece) {
|
||||
if (p1 == p2 || p1 == center || p2 == center)
|
||||
return;
|
||||
Vector X = normalize(p1 - center), Y = p2 - center;
|
||||
Float radius = Y.length(); Y /= radius;
|
||||
Float angle = unitAngle(X, Y);
|
||||
|
||||
Y = normalize(Y - dot(Y, X) * X);
|
||||
|
||||
if (!shorterPiece) {
|
||||
angle = 2*M_PI - angle;
|
||||
Y = -Y;
|
||||
}
|
||||
|
||||
int nDiscr = 80;
|
||||
Float stepSize = angle/(nDiscr-1);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (int i=0; i<nDiscr; ++i) {
|
||||
Float sinTheta = std::sin(i * stepSize) * radius;
|
||||
Float cosTheta = std::cos(i * stepSize) * radius;
|
||||
|
||||
Point p = center + X*cosTheta + Y*sinTheta;
|
||||
glVertex3f(p.x, p.y, p.z);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void GLRenderer::drawText(const Point2i &_pos,
|
||||
const Font *font, const std::string &text) {
|
||||
int viewport[4];
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
GLTexture::GLTexture(const std::string &name, Bitmap *bitmap)
|
||||
: GPUTexture(name, bitmap), m_id(0), m_extraId(0), m_needsUpdate(true) {
|
||||
: GPUTexture(name, bitmap), m_id(0), m_needsUpdate(true) {
|
||||
}
|
||||
|
||||
void GLTexture::init() {
|
||||
|
@ -48,11 +48,25 @@ void GLTexture::init() {
|
|||
/* Bind to the texture */
|
||||
glBindTexture(m_glType, m_id);
|
||||
|
||||
/* Set the texture filtering / wrapping modes */
|
||||
if (!(m_fbType == EColorBuffer && m_samples > 1))
|
||||
/* Set the texture filtering / wrapping modes
|
||||
(don't do this for multisample textures)*/
|
||||
if (!((m_fbType & EColorBuffer) && m_samples > 1))
|
||||
configureTexture(); /* Multisample textures don't have parameters */
|
||||
|
||||
if (m_samples > 1) {
|
||||
int samples;
|
||||
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
|
||||
if (m_samples > samples) {
|
||||
Log(EWarn, "Attempted to create a multisample framebuffer "
|
||||
"with an unsupported # of samples (requested=%i, supported=%i)",
|
||||
m_samples, samples);
|
||||
m_samples = samples;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_fbType == ENone) {
|
||||
Assert(m_samples == 1);
|
||||
refresh();
|
||||
} else {
|
||||
/* Create the FBO and bind it */
|
||||
|
@ -60,64 +74,73 @@ void GLTexture::init() {
|
|||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
|
||||
|
||||
AssertEx(glIsFramebufferEXT(m_fboId), "Creating an FBO failed");
|
||||
bool depthAsTexture = m_fbType & EDepthBuffer;
|
||||
|
||||
switch (m_fbType) {
|
||||
case EColorAndDepthBuffer:
|
||||
case EColorBuffer: {
|
||||
if (m_type == ETexture2D) {
|
||||
/* Create a depth buffer */
|
||||
glGenRenderbuffersEXT(1, &m_depthId);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId);
|
||||
|
||||
if (m_samples == 1) {
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
|
||||
GL_DEPTH_COMPONENT, m_size.x, m_size.y);
|
||||
|
||||
/* Allocate the texture memory */
|
||||
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
|
||||
0, m_format, m_dataFormat, NULL);
|
||||
if (!depthAsTexture) {
|
||||
glGenRenderbuffersEXT(1, &m_depthId);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId);
|
||||
if (m_samples == 1)
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
|
||||
GL_DEPTH_COMPONENT, m_size.x, m_size.y);
|
||||
else
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
|
||||
m_samples, GL_DEPTH_COMPONENT, m_size.x, m_size.y);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
|
||||
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthId);
|
||||
} else {
|
||||
int samples;
|
||||
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
|
||||
if (m_samples > samples) {
|
||||
Log(EWarn, "Attempted to create a multisample framebuffer "
|
||||
"with an unsupported # of samples (requested=%i, supported=%i)", m_samples, samples);
|
||||
m_samples = samples;
|
||||
}
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
|
||||
m_samples, GL_DEPTH_COMPONENT, m_size.x, m_size.y);
|
||||
glTexImage2DMultisample(m_glType,
|
||||
m_samples, m_internalFormat, m_size.x, m_size.y, GL_FALSE);
|
||||
glGenTextures(1, &m_depthId);
|
||||
glBindTexture(m_glType, m_depthId);
|
||||
configureTexture();
|
||||
glTexParameteri(m_glType, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
glTexParameteri(m_glType, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
|
||||
if (m_samples == 1)
|
||||
glTexImage2D(m_glType, 0, GL_DEPTH_COMPONENT24, m_size.x, m_size.y,
|
||||
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
else
|
||||
glTexImage2DMultisample(m_glType,
|
||||
m_samples, GL_DEPTH_COMPONENT24, m_size.x, m_size.y, GL_FALSE);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
|
||||
GL_DEPTH_ATTACHMENT, m_glType, m_depthId, 0);
|
||||
glBindTexture(m_glType, m_id);
|
||||
}
|
||||
|
||||
if (m_samples == 1)
|
||||
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
|
||||
0, m_format, m_dataFormat, NULL);
|
||||
else
|
||||
glTexImage2DMultisample(m_glType,
|
||||
m_samples, m_internalFormat, m_size.x, m_size.y, GL_FALSE);
|
||||
|
||||
if (isMipMapped())
|
||||
glGenerateMipmapEXT(m_glType);
|
||||
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
|
||||
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthId);
|
||||
|
||||
/* Attach the texture as a color target */
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
|
||||
GL_COLOR_ATTACHMENT0_EXT, m_glType, m_id, 0);
|
||||
} else if (m_type == ETextureCubeMap) {
|
||||
Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x));
|
||||
Assert(m_fbType == EColorBuffer);
|
||||
Assert(m_samples == 1);
|
||||
|
||||
for (int i=0; i<6; i++)
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat, m_size.x, m_size.y,
|
||||
0, m_format, m_dataFormat, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
|
||||
m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
|
||||
|
||||
if (isMipMapped())
|
||||
glGenerateMipmapEXT(m_glType);
|
||||
|
||||
/* Generate an identifier */
|
||||
glGenTextures(1, &m_extraId);
|
||||
glBindTexture(m_glType, m_extraId);
|
||||
glGenTextures(1, &m_depthId);
|
||||
glBindTexture(m_glType, m_depthId);
|
||||
glTexParameteri(m_glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(m_glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
for (int i=0; i<6; i++)
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24, m_size.x, m_size.y,
|
||||
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24,
|
||||
m_size.x, m_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
if (glewIsSupported("GL_EXT_geometry_shader4"))
|
||||
activateSide(-1);
|
||||
|
@ -147,8 +170,8 @@ void GLTexture::init() {
|
|||
} else if (m_type == ETextureCubeMap) {
|
||||
Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x));
|
||||
for (int i=0; i<6; i++)
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat, m_size.x, m_size.y,
|
||||
0, m_format, m_dataFormat, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
|
||||
m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
|
||||
|
||||
if (glewIsSupported("GL_EXT_geometry_shader4"))
|
||||
activateSide(-1);
|
||||
|
@ -229,12 +252,6 @@ void GLTexture::refresh() {
|
|||
}
|
||||
}
|
||||
|
||||
/* Does not support floating point textures on all platforms
|
||||
if (isMipMapped())
|
||||
gluBuild2DMipmaps(m_glType, m_internalFormat, m_size.x, m_size.y,
|
||||
m_format, m_dataFormat, bitmap->getData());
|
||||
else
|
||||
*/
|
||||
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
|
||||
0, m_format, m_dataFormat, bitmap->getData());
|
||||
|
||||
|
@ -480,19 +497,23 @@ void GLTexture::activateSide(int side) {
|
|||
if (side == -1) {
|
||||
if (m_fbType == EColorBuffer) {
|
||||
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0);
|
||||
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_extraId, 0);
|
||||
} else {
|
||||
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_depthId, 0);
|
||||
} else if (m_fbType == EDepthBuffer) {
|
||||
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0);
|
||||
} else {
|
||||
Log(EError, "Unsupported framebuffer type!");
|
||||
}
|
||||
} else {
|
||||
if (m_fbType == EColorBuffer) {
|
||||
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side);
|
||||
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_extraId, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_extraId, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_depthId, 0);
|
||||
} else if (m_fbType == EDepthBuffer) {
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
|
||||
} else {
|
||||
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
|
||||
Log(EError, "Unsupported framebuffer type!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -509,16 +530,21 @@ void GLTexture::releaseTarget() {
|
|||
m_needsUpdate = true;
|
||||
}
|
||||
|
||||
void GLTexture::bind(int textureUnit) const {
|
||||
void GLTexture::bind(int textureUnit, int textureIndex) const {
|
||||
/* Bind to the texture */
|
||||
if (GLEW_VERSION_1_3) {
|
||||
m_textureUnits.get().insert(textureUnit);
|
||||
glActiveTexture(GL_TEXTURE0 + textureUnit);
|
||||
} else {
|
||||
AssertEx(textureUnit == 0, "Multitexture is not supported");
|
||||
if (textureUnit != 0)
|
||||
Log(EError, "Multitexturing is not supported");
|
||||
}
|
||||
|
||||
glEnable(m_glType);
|
||||
glBindTexture(m_glType, m_id);
|
||||
if (textureIndex == 1 && m_fbType == EColorAndDepthBuffer)
|
||||
glBindTexture(m_glType, m_depthId);
|
||||
else
|
||||
glBindTexture(m_glType, m_id);
|
||||
|
||||
if (isMipMapped() && m_needsUpdate) {
|
||||
glGenerateMipmapEXT(m_glType);
|
||||
|
@ -530,7 +556,7 @@ void GLTexture::unbind() const {
|
|||
if (GLEW_VERSION_1_3) {
|
||||
std::set<int> &textureUnits = m_textureUnits.get();
|
||||
for (std::set<int>::iterator it = textureUnits.begin();
|
||||
it != textureUnits.end(); ++it) {
|
||||
it != textureUnits.end(); ++it) {
|
||||
glActiveTexture(GL_TEXTURE0 + *it);
|
||||
glDisable(m_glType);
|
||||
}
|
||||
|
@ -545,41 +571,85 @@ void GLTexture::cleanup() {
|
|||
return;
|
||||
if (m_fbType != ENone) {
|
||||
Log(ETrace, "Freeing framebuffer \"%s\"", m_name.c_str());
|
||||
switch (m_fbType) {
|
||||
case EColorBuffer:
|
||||
glDeleteRenderbuffersEXT(1, &m_depthId);
|
||||
break;
|
||||
case EDepthBuffer:
|
||||
break;
|
||||
default:
|
||||
Log(EError, "Invalid framebuffer type!");
|
||||
if (m_fbType == EColorAndDepthBuffer || (m_fbType == EColorBuffer && m_type == ETextureCubeMap)) {
|
||||
glDeleteTextures(1, &m_depthId);
|
||||
} else if (m_fbType == EColorBuffer) {
|
||||
glDeleteRenderbuffersEXT(1, &m_depthId);
|
||||
}
|
||||
|
||||
glDeleteFramebuffersEXT(1, &m_fboId);
|
||||
} else {
|
||||
Log(ETrace, "Freeing texture \"%s\"", m_name.c_str());
|
||||
}
|
||||
glDeleteTextures(1, &m_id);
|
||||
m_id = 0;
|
||||
if (m_extraId != 0) {
|
||||
glDeleteTextures(1, &m_extraId);
|
||||
m_extraId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GLTexture::blit(GPUTexture *texture) const {
|
||||
GLTexture *dest = static_cast<GLTexture *>(texture);
|
||||
void GLTexture::blit(GPUTexture *target, int what) const {
|
||||
GLTexture *dest = static_cast<GLTexture *>(target);
|
||||
Assert(m_fbType != ENone && (dest == NULL || dest->m_fbType != ENone));
|
||||
|
||||
Assert(m_fbType == EColorBuffer && dest->m_fbType == EColorBuffer);
|
||||
if (!GLEW_EXT_framebuffer_blit)
|
||||
Log(EError, "Your OpenGL driver does not support fast "
|
||||
"framebuffer blitting!");
|
||||
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dest->m_fboId);
|
||||
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
|
||||
dest->m_size.x, dest->m_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
|
||||
(dest == NULL) ? GL_NONE : dest->m_fboId);
|
||||
|
||||
int flags = 0;
|
||||
if (what & EDepthBuffer)
|
||||
flags |= GL_DEPTH_BUFFER_BIT;
|
||||
if (what & EColorBuffer)
|
||||
flags |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
if (!dest) {
|
||||
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
|
||||
m_size.x, m_size.y, flags, GL_NEAREST);
|
||||
} else {
|
||||
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
|
||||
dest->m_size.x, dest->m_size.y, flags,
|
||||
(m_size == dest->m_size) ? GL_NEAREST : GL_LINEAR);
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_NONE);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_NONE);
|
||||
}
|
||||
|
||||
void GLTexture::blit(GPUTexture *target, int what, const Point2i &sourceOffset,
|
||||
const Vector2i &sourceSize, const Point2i &destOffset,
|
||||
const Vector2i &destSize) const {
|
||||
GLTexture *dest = static_cast<GLTexture *>(target);
|
||||
Assert(m_fbType != ENone && (dest == NULL || dest->m_fbType != ENone));
|
||||
|
||||
if (!GLEW_EXT_framebuffer_blit)
|
||||
Log(EError, "Your OpenGL driver does not support fast "
|
||||
"framebuffer blitting!");
|
||||
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
|
||||
(dest == NULL) ? GL_NONE : dest->m_fboId);
|
||||
|
||||
int flags = 0;
|
||||
if (what & EDepthBuffer)
|
||||
flags |= GL_DEPTH_BUFFER_BIT;
|
||||
if (what & EColorBuffer)
|
||||
flags |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
glBlitFramebufferEXT(sourceOffset.x, sourceOffset.y,
|
||||
sourceOffset.x + sourceSize.x, sourceOffset.x + sourceSize.y,
|
||||
destOffset.x, destOffset.y, destOffset.x + destSize.x,
|
||||
destOffset.y + destSize.y, flags,
|
||||
(sourceSize == destSize) ? GL_NEAREST : GL_LINEAR);
|
||||
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_NONE);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_NONE);
|
||||
}
|
||||
|
||||
void GLTexture::clear() {
|
||||
Assert(m_fbType != ENone);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | (m_fbType == EColorBuffer ? GL_COLOR_BUFFER_BIT : 0));
|
||||
glClear(GL_DEPTH_BUFFER_BIT
|
||||
| ((m_fbType & EColorBuffer) ? GL_COLOR_BUFFER_BIT : 0));
|
||||
}
|
||||
|
||||
GLTexture::~GLTexture() {
|
||||
|
|
|
@ -87,6 +87,7 @@ void GPUTexture::setFrameBufferType(EFrameBufferType type) {
|
|||
|
||||
switch (m_fbType) {
|
||||
case EColorBuffer:
|
||||
case EColorAndDepthBuffer:
|
||||
break;
|
||||
case EDepthBuffer:
|
||||
m_format = EDepth;
|
||||
|
@ -164,6 +165,7 @@ static const char *toString(GPUTexture::EFrameBufferType fbType) {
|
|||
case GPUTexture::ENone: return "none";
|
||||
case GPUTexture::EDepthBuffer: return "depthBuffer";
|
||||
case GPUTexture::EColorBuffer: return "colorBuffer";
|
||||
case GPUTexture::EColorAndDepthBuffer: return "colorAndDepthBuffer";
|
||||
default: SLog(EError, "Invalid framebuffer type"); return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -343,10 +343,9 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
|||
<< "varying out vec3 vertexColor;" << endl
|
||||
<< endl
|
||||
<< "void main() {" << endl
|
||||
<< " vec3 p0 = gl_PositionIn[0].xyz / gl_PositionIn[0].w;" << endl
|
||||
<< " vec3 p1 = gl_PositionIn[1].xyz / gl_PositionIn[1].w;" << endl
|
||||
<< " vec3 p2 = gl_PositionIn[2].xyz / gl_PositionIn[2].w;" << endl
|
||||
<< " normal = normalize(cross(p1 - p0, p2 - p0));" << endl
|
||||
<< " vec3 edge1 = camVec_vertex[0]-camVec_vertex[1];" << endl
|
||||
<< " vec3 edge2 = camVec_vertex[0]-camVec_vertex[2];" << endl
|
||||
<< " normal = normalize(cross(edge1, edge2));" << endl
|
||||
<< " gl_Position = vec4(0.0);" << endl
|
||||
<< " lightVec = camVec = vec3(0.0);" << endl
|
||||
<< " for (int i=0; i<gl_VerticesIn; ++i) {" << endl
|
||||
|
|
|
@ -33,10 +33,17 @@ enum EConnectionType {
|
|||
};
|
||||
|
||||
enum ENavigationMode {
|
||||
EFlythroughFixedYaw = 0,
|
||||
EArcBall = 0,
|
||||
EFlythroughFixedYaw,
|
||||
EFlythrough
|
||||
};
|
||||
|
||||
enum ESelectionMode {
|
||||
ENothing = 0,
|
||||
EShape,
|
||||
EScene
|
||||
};
|
||||
|
||||
namespace mitsuba {
|
||||
class RemoteWorker;
|
||||
};
|
||||
|
@ -184,13 +191,16 @@ struct SceneContext {
|
|||
bool diffuseReceivers;
|
||||
bool showKDTree;
|
||||
int shownKDTreeLevel;
|
||||
ESelectionMode selectionMode;
|
||||
const Shape *selectedShape;
|
||||
|
||||
/* Preview state */
|
||||
std::deque<VPL> vpls;
|
||||
PreviewQueueEntry previewBuffer;
|
||||
|
||||
SceneContext() : scene(NULL), sceneResID(-1), renderJob(NULL) {
|
||||
}
|
||||
SceneContext() : scene(NULL), sceneResID(-1),
|
||||
renderJob(NULL), selectionMode(ENothing),
|
||||
selectedShape(NULL) { }
|
||||
|
||||
/// Detect the path length
|
||||
int detectPathLength() const;
|
||||
|
|
|
@ -38,12 +38,14 @@ GLWidget::GLWidget(QWidget *parent) :
|
|||
m_movementTimer = new QTimer(parent);
|
||||
m_movementTimer->setInterval(20);
|
||||
m_movementTimer->setSingleShot(false);
|
||||
m_wheelTimer = new Timer();
|
||||
m_redrawTimer = new QTimer(parent);
|
||||
m_redrawTimer->setInterval(200);
|
||||
connect(m_movementTimer, SIGNAL(timeout()), this, SLOT(timerImpulse()));
|
||||
connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(updateGL()));
|
||||
m_renderer = Renderer::create(NULL);
|
||||
m_device = new QtDevice(this);
|
||||
m_gizmo = new Gizmo();
|
||||
m_preview = new PreviewThread(m_device, m_renderer);
|
||||
connect(m_preview, SIGNAL(caughtException(const QString &)),
|
||||
this, SLOT(onException(const QString &)), Qt::QueuedConnection);
|
||||
|
@ -114,6 +116,9 @@ void GLWidget::initializeGL() {
|
|||
if (!m_renderer->getCapabilities()->isSupported(
|
||||
RendererCapabilities::EVertexBufferObjects))
|
||||
missingExtensions.push_back("Vertex buffer objects");
|
||||
if (!m_renderer->getCapabilities()->isSupported(
|
||||
RendererCapabilities::EBufferBlit))
|
||||
missingExtensions.push_back("Fast blitting");
|
||||
|
||||
if (missingExtensions.size() > 0 || m_softwareFallback) {
|
||||
#if !defined(MTS_GUI_SOFTWARE_FALLBACK)
|
||||
|
@ -149,6 +154,7 @@ void GLWidget::initializeGL() {
|
|||
);
|
||||
|
||||
m_gammaTonemap->setSource(GPUProgram::EFragmentProgram,
|
||||
"#version 120\n"
|
||||
"uniform sampler2D source;\n"
|
||||
"uniform float invWhitePoint, invGamma;\n"
|
||||
"uniform bool sRGB;\n"
|
||||
|
@ -162,7 +168,7 @@ void GLWidget::initializeGL() {
|
|||
"void main() {\n"
|
||||
" vec4 color = texture2D(source, gl_TexCoord[0].xy) * invWhitePoint;\n"
|
||||
" if (sRGB)\n"
|
||||
" gl_FragColor = vec4(toSRGB(color.r), toSRGB(color.g), toSRGB(color.b), 1);"
|
||||
" gl_FragColor = vec4(toSRGB(color.r), toSRGB(color.g), toSRGB(color.b), 1);\n"
|
||||
" else\n"
|
||||
" gl_FragColor = vec4(pow(color.rgb, vec3(invGamma)), 1);\n"
|
||||
"}\n"
|
||||
|
@ -176,6 +182,7 @@ void GLWidget::initializeGL() {
|
|||
);
|
||||
|
||||
m_reinhardTonemap->setSource(GPUProgram::EFragmentProgram,
|
||||
"#version 120\n"
|
||||
"uniform sampler2D source;\n"
|
||||
"uniform float key, invWpSqr, invGamma, multiplier;\n"
|
||||
"uniform bool sRGB;\n"
|
||||
|
@ -288,6 +295,9 @@ void GLWidget::initializeGL() {
|
|||
m_logoTexture->init();
|
||||
m_font->init(m_renderer);
|
||||
m_redrawTimer->start();
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glLineWidth(0.6f);
|
||||
}
|
||||
|
||||
void GLWidget::setScene(SceneContext *context) {
|
||||
|
@ -301,6 +311,7 @@ void GLWidget::setScene(SceneContext *context) {
|
|||
m_framebufferChanged = true;
|
||||
m_mouseButtonDown = false;
|
||||
m_leftKeyDown = m_rightKeyDown = m_upKeyDown = m_downKeyDown = false;
|
||||
m_gizmo->reset();
|
||||
updateGeometry();
|
||||
updateScrollBars();
|
||||
updateGL();
|
||||
|
@ -509,7 +520,8 @@ void GLWidget::resetPreview() {
|
|||
if (!m_context || !m_context->scene || !m_preview->isRunning())
|
||||
return;
|
||||
bool motion = m_leftKeyDown || m_rightKeyDown ||
|
||||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown;
|
||||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown ||
|
||||
m_wheelTimer->getMilliseconds() < 200;
|
||||
m_preview->setSceneContext(m_context, false, motion);
|
||||
updateGL();
|
||||
}
|
||||
|
@ -522,22 +534,50 @@ void GLWidget::keyPressEvent(QKeyEvent *event) {
|
|||
|
||||
if (event->isAutoRepeat() || !m_context)
|
||||
return;
|
||||
|
||||
PinholeCamera *camera = static_cast<PinholeCamera *>(m_context->scene->getCamera());
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_PageUp: m_context->movementScale *= 2; break;
|
||||
case Qt::Key_PageDown: m_context->movementScale /= 2; break;
|
||||
case Qt::Key_A:
|
||||
case Qt::Key_Left:
|
||||
m_leftKeyDown = true; break;
|
||||
case Qt::Key_D:
|
||||
case Qt::Key_Right:
|
||||
m_rightKeyDown = true; break;
|
||||
case Qt::Key_W:
|
||||
case Qt::Key_Up:
|
||||
m_upKeyDown = true; break;
|
||||
case Qt::Key_S:
|
||||
case Qt::Key_Down:
|
||||
m_downKeyDown = true; break;
|
||||
case Qt::Key_A: {
|
||||
if (m_context->selectionMode == ENothing) {
|
||||
m_context->selectionMode = EScene;
|
||||
m_gizmo->init(m_context->scene->getBSphere());
|
||||
} else {
|
||||
m_context->selectionMode = ENothing;
|
||||
m_gizmo->reset();
|
||||
}
|
||||
m_context->selectedShape = NULL;
|
||||
updateGL();
|
||||
}
|
||||
// break intentionally missing
|
||||
case Qt::Key_F: {
|
||||
if (!m_gizmo->isActive())
|
||||
return;
|
||||
Vector up;
|
||||
if (m_navigationMode == EFlythroughFixedYaw)
|
||||
up = m_context->up;
|
||||
else
|
||||
up = camera->getInverseViewTransform()(Vector(0,1,0));
|
||||
Vector d = Vector(camera->getImagePlaneNormal());
|
||||
Float fov = std::min(camera->getXFov(), camera->getYFov())*0.8/2;
|
||||
const BSphere &bs = m_gizmo->getBSphere();
|
||||
Float distance = bs.radius/std::tan(fov * M_PI/180);
|
||||
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(bs.center - distance*d, bs.center, up));
|
||||
resetPreview();
|
||||
};
|
||||
break;
|
||||
}
|
||||
if (!m_movementTimer->isActive() && (m_leftKeyDown || m_rightKeyDown || m_upKeyDown || m_downKeyDown)) {
|
||||
m_clock->reset();
|
||||
|
@ -549,16 +589,12 @@ void GLWidget::keyReleaseEvent(QKeyEvent *event) {
|
|||
if (event->isAutoRepeat() || !m_context || !m_preview->isRunning())
|
||||
return;
|
||||
switch (event->key()) {
|
||||
case Qt::Key_A:
|
||||
case Qt::Key_Left:
|
||||
m_leftKeyDown = false; break;
|
||||
case Qt::Key_D:
|
||||
case Qt::Key_Right:
|
||||
m_rightKeyDown = false; break;
|
||||
case Qt::Key_W:
|
||||
case Qt::Key_Up:
|
||||
m_upKeyDown = false; break;
|
||||
case Qt::Key_S:
|
||||
case Qt::Key_Down:
|
||||
m_downKeyDown = false; break;
|
||||
case Qt::Key_BracketLeft:
|
||||
|
@ -589,7 +625,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
return;
|
||||
|
||||
QPoint previousPos = m_mousePos,
|
||||
rel = event->pos() - m_mousePos;
|
||||
rel = event->pos() - m_mousePos;
|
||||
m_mousePos = event->pos();
|
||||
|
||||
if (!m_context || !m_context->scene || !m_mouseButtonDown || rel == QPoint(0,0))
|
||||
|
@ -601,7 +637,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!m_didSetCursor) {
|
||||
if (!m_didSetCursor && !(m_navigationMode == EArcBall && event->buttons() & Qt::LeftButton)) {
|
||||
QApplication::setOverrideCursor(Qt::BlankCursor);
|
||||
m_didSetCursor = true;
|
||||
}
|
||||
|
@ -610,54 +646,66 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
Point p = camera->getInverseViewTransform()(Point(0,0,0));
|
||||
Vector direction = camera->getInverseViewTransform()(Vector(0,0,1));
|
||||
Vector up;
|
||||
|
||||
if (m_navigationMode == EFlythrough)
|
||||
up = camera->getInverseViewTransform()(Vector(0,1,0));
|
||||
else if (m_navigationMode == EFlythroughFixedYaw)
|
||||
up = m_context->up;
|
||||
else
|
||||
SLog(EError, "Unknown navigation mode encountered!");
|
||||
|
||||
bool didMove = false;
|
||||
|
||||
if (event->buttons() & Qt::LeftButton) {
|
||||
Float yaw = -.03f * rel.x() * m_mouseSensitivity;
|
||||
Float pitch = -.03f * rel.y() * m_mouseSensitivity;
|
||||
if (m_invertMouse)
|
||||
pitch *= -1;
|
||||
|
||||
Transform trafo = Transform::rotate(Vector(0,1,0), yaw)
|
||||
* Transform::rotate(Vector(1,0,0), pitch)
|
||||
* camera->getViewTransform();
|
||||
direction = trafo.inverse()(Vector(0,0,1));
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0) {
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, up));
|
||||
} else {
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(p, p+direction, up) *
|
||||
Transform::scale(Vector(-1,1,1))
|
||||
);
|
||||
|
||||
if (m_navigationMode == EArcBall) {
|
||||
if (event->buttons() & Qt::LeftButton) {
|
||||
Ray ray;
|
||||
Point2i offset = upperLeft();
|
||||
Point2 sample = Point2(m_mousePos.x() - offset.x, m_mousePos.y() - offset.y);
|
||||
camera->setViewTransform(m_storedViewTransform);
|
||||
camera->generateRay(sample, Point2(0, 0), 0, ray);
|
||||
m_gizmo->dragTo(ray, camera);
|
||||
camera->setViewTransform(m_storedViewTransform * m_gizmo->getTransform());
|
||||
didMove = true;
|
||||
}
|
||||
didMove = true;
|
||||
}
|
||||
} else {
|
||||
if (m_navigationMode == EFlythrough)
|
||||
up = camera->getInverseViewTransform()(Vector(0,1,0));
|
||||
else if (m_navigationMode == EFlythroughFixedYaw)
|
||||
up = m_context->up;
|
||||
else
|
||||
SLog(EError, "Unknown navigation mode encountered!");
|
||||
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
Float roll = rel.x() * m_mouseSensitivity * .02f;
|
||||
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
|
||||
if (event->buttons() & Qt::LeftButton) {
|
||||
Float yaw = -.03f * rel.x() * m_mouseSensitivity;
|
||||
Float pitch = -.03f * rel.y() * m_mouseSensitivity;
|
||||
if (m_invertMouse)
|
||||
pitch *= -1;
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0) {
|
||||
m_context->up = Transform::rotate(direction, roll)(up);
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
|
||||
} else {
|
||||
m_context->up = Transform::rotate(direction, -roll)(up);
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(p, p+direction, m_context->up) *
|
||||
Transform::scale(Vector(-1,1,1))
|
||||
);
|
||||
Transform trafo = Transform::rotate(Vector(0,1,0), yaw)
|
||||
* Transform::rotate(Vector(1,0,0), pitch)
|
||||
* camera->getViewTransform();
|
||||
direction = trafo.inverse()(Vector(0,0,1));
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0) {
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, up));
|
||||
} else {
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(p, p+direction, up) *
|
||||
Transform::scale(Vector(-1,1,1))
|
||||
);
|
||||
}
|
||||
didMove = true;
|
||||
}
|
||||
|
||||
camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f));
|
||||
if (event->buttons() & Qt::RightButton) {
|
||||
Float roll = rel.x() * m_mouseSensitivity * .02f;
|
||||
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0) {
|
||||
m_context->up = Transform::rotate(direction, roll)(up);
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
|
||||
} else {
|
||||
m_context->up = Transform::rotate(direction, -roll)(up);
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(p, p+direction, m_context->up) *
|
||||
Transform::scale(Vector(-1,1,1))
|
||||
);
|
||||
}
|
||||
|
||||
camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f));
|
||||
}
|
||||
camera->configure();
|
||||
|
||||
didMove = true;
|
||||
|
@ -671,15 +719,17 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
didMove = true;
|
||||
}
|
||||
|
||||
QPoint global = mapToGlobal(m_mousePos);
|
||||
QDesktopWidget *desktop = QApplication::desktop();
|
||||
if (m_navigationMode != EArcBall) {
|
||||
QPoint global = mapToGlobal(m_mousePos);
|
||||
QDesktopWidget *desktop = QApplication::desktop();
|
||||
|
||||
if (global.x() < 50 || global.y() < 50 ||
|
||||
global.x() > desktop->width()-50 ||
|
||||
global.y() > desktop->height()-50) {
|
||||
QPoint target(desktop->width()/2, desktop->height()/2);
|
||||
m_ignoreMouseEvent = target - global;
|
||||
QCursor::setPos(target);
|
||||
if (global.x() < 50 || global.y() < 50 ||
|
||||
global.x() > desktop->width()-50 ||
|
||||
global.y() > desktop->height()-50) {
|
||||
QPoint target(desktop->width()/2, desktop->height()/2);
|
||||
m_ignoreMouseEvent = target - global;
|
||||
QCursor::setPos(target);
|
||||
}
|
||||
}
|
||||
|
||||
if (didMove)
|
||||
|
@ -689,22 +739,45 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
void GLWidget::wheelEvent(QWheelEvent *event) {
|
||||
QScrollBar *bar = event->orientation() == Qt::Vertical
|
||||
? m_vScroll : m_hScroll;
|
||||
|
||||
if (!bar->isVisible() || !m_preview->isRunning())
|
||||
if (!m_preview->isRunning())
|
||||
return;
|
||||
|
||||
int oldStep = bar->singleStep();
|
||||
bar->setSingleStep(event->delta()/4);
|
||||
if (bar->isVisible()) {
|
||||
int oldStep = bar->singleStep();
|
||||
bar->setSingleStep(event->delta()/4);
|
||||
#if defined(__OSX__)
|
||||
/* Support two-finger swipes */
|
||||
if (std::abs(event->delta()) < 8*15)
|
||||
bar->setSingleStep(event->delta());
|
||||
/* Support two-finger swipes */
|
||||
if (std::abs(event->delta()) < 8*15)
|
||||
bar->setSingleStep(event->delta());
|
||||
#endif
|
||||
|
||||
bar->triggerAction(event->delta() > 0 ?
|
||||
QAbstractSlider::SliderSingleStepSub
|
||||
: QAbstractSlider::SliderSingleStepAdd);
|
||||
bar->setSingleStep(oldStep);
|
||||
bar->triggerAction(event->delta() > 0 ?
|
||||
QAbstractSlider::SliderSingleStepSub
|
||||
: QAbstractSlider::SliderSingleStepAdd);
|
||||
bar->setSingleStep(oldStep);
|
||||
} else {
|
||||
ProjectiveCamera *camera
|
||||
= static_cast<ProjectiveCamera *>(m_context->scene->getCamera());
|
||||
Vector up;
|
||||
if (m_navigationMode == EFlythroughFixedYaw)
|
||||
up = m_context->up;
|
||||
else
|
||||
up = camera->getInverseViewTransform()(Vector(0,1,0));
|
||||
Vector d = Vector(camera->getImagePlaneNormal());
|
||||
Point o = camera->getPosition();
|
||||
Intersection its;
|
||||
|
||||
if (m_context->scene->rayIntersect(Ray(o, d, 0), its)) {
|
||||
Float length = (its.p - o).length();
|
||||
|
||||
length *= std::pow(1 - 1e-3f, event->delta());
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(its.p - length*d, its.p, up));
|
||||
m_wheelTimer->reset();
|
||||
resetPreview();
|
||||
}
|
||||
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
|
@ -714,6 +787,37 @@ void GLWidget::mousePressEvent(QMouseEvent *event) {
|
|||
m_mousePos = event->pos();
|
||||
m_initialMousePos = mapToGlobal(m_mousePos);
|
||||
m_mouseButtonDown = true;
|
||||
ProjectiveCamera *camera = static_cast<ProjectiveCamera *>(m_context->scene->getCamera());
|
||||
|
||||
if (m_navigationMode == EArcBall && event->buttons() & Qt::LeftButton) {
|
||||
Point2i offset = upperLeft();
|
||||
Point2 sample = Point2(m_mousePos.x() - offset.x, m_mousePos.y() - offset.y);
|
||||
Intersection its;
|
||||
Ray ray;
|
||||
Float t;
|
||||
|
||||
camera->generateRay(sample, Point2(0, 0), 0, ray);
|
||||
m_gizmo->rayIntersect(ray, t);
|
||||
|
||||
if (m_context->scene->rayIntersect(ray, its)) {
|
||||
if (its.t < t) {
|
||||
SLog(EInfo, "Selected shape \"%s\"", its.shape->getName().c_str());
|
||||
m_context->selectedShape = its.shape;
|
||||
m_gizmo->init(its.shape->getAABB().getBSphere());
|
||||
m_context->selectionMode = EShape;
|
||||
}
|
||||
} else {
|
||||
if (t == std::numeric_limits<Float>::infinity()) {
|
||||
m_gizmo->reset();
|
||||
m_context->selectionMode = ENothing;
|
||||
m_context->selectedShape = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_gizmo->startDrag(ray);
|
||||
m_storedViewTransform = camera->getViewTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
|
@ -721,17 +825,20 @@ void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
|
|||
return;
|
||||
if (event->buttons() == 0) {
|
||||
m_mouseButtonDown = false;
|
||||
|
||||
if (m_didSetCursor) {
|
||||
resetPreview();
|
||||
QApplication::restoreOverrideCursor();
|
||||
QCursor::setPos(m_initialMousePos);
|
||||
m_didSetCursor = false;
|
||||
} else if (m_gizmo->isDragging()) {
|
||||
m_gizmo->stopDrag();
|
||||
resetPreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLWidget::paintGL() {
|
||||
m_renderer->setDepthMask(false);
|
||||
m_renderer->setDepthTest(false);
|
||||
if (m_context == NULL) {
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
@ -740,7 +847,7 @@ void GLWidget::paintGL() {
|
|||
m_renderer->blitTexture(m_logoTexture);
|
||||
m_renderer->setBlendMode(Renderer::EBlendNone);
|
||||
} else if (m_context != NULL) {
|
||||
Point3i size;
|
||||
Vector2i size;
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
PreviewQueueEntry entry;
|
||||
|
@ -753,14 +860,15 @@ void GLWidget::paintGL() {
|
|||
return;
|
||||
}
|
||||
bool motion = m_leftKeyDown || m_rightKeyDown ||
|
||||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown;
|
||||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown ||
|
||||
m_wheelTimer->getMilliseconds() < 200;
|
||||
entry = m_preview->acquireBuffer(motion ? -1 : 50);
|
||||
if (entry.buffer == NULL) {
|
||||
/* Unsuccessful at acquiring a buffer in the
|
||||
alloted time - just leave and keep the current display */
|
||||
return;
|
||||
}
|
||||
size = entry.buffer->getSize();
|
||||
size = Vector2i(entry.buffer->getSize().x, entry.buffer->getSize().y);
|
||||
buffer = entry.buffer;
|
||||
} else if (m_context->mode == ERender) {
|
||||
if (m_framebuffer == NULL ||
|
||||
|
@ -806,7 +914,7 @@ void GLWidget::paintGL() {
|
|||
m_framebufferChanged = false;
|
||||
}
|
||||
|
||||
size = m_framebuffer->getSize();
|
||||
size = Vector2i(m_framebuffer->getSize().x, m_framebuffer->getSize().y);
|
||||
buffer = m_framebuffer;
|
||||
}
|
||||
|
||||
|
@ -822,9 +930,8 @@ void GLWidget::paintGL() {
|
|||
if (m_context->mode == EPreview)
|
||||
invWhitePoint /= entry.vplSampleOffset;
|
||||
|
||||
buffer->bind();
|
||||
m_gammaTonemap->bind();
|
||||
m_gammaTonemap->setParameter("source", buffer);
|
||||
m_gammaTonemap->setParameter("source", 0);
|
||||
m_gammaTonemap->setParameter("invWhitePoint", invWhitePoint);
|
||||
m_gammaTonemap->setParameter("invGamma", 1/m_context->gamma);
|
||||
m_gammaTonemap->setParameter("sRGB", m_context->srgb);
|
||||
|
@ -832,7 +939,6 @@ void GLWidget::paintGL() {
|
|||
!m_hScroll->isVisible(), !m_vScroll->isVisible(),
|
||||
-m_context->scrollOffset);
|
||||
m_gammaTonemap->unbind();
|
||||
buffer->unbind();
|
||||
} else if (m_context->toneMappingMethod == EReinhard) {
|
||||
if (m_luminanceBuffer[0] == NULL || m_luminanceBuffer[0]->getSize() != Point3i(size.x, size.y, 1)) {
|
||||
for (int i=0; i<2; ++i) {
|
||||
|
@ -892,9 +998,8 @@ void GLWidget::paintGL() {
|
|||
logLuminance = 1;
|
||||
}
|
||||
|
||||
buffer->bind();
|
||||
m_reinhardTonemap->bind();
|
||||
m_reinhardTonemap->setParameter("source", buffer);
|
||||
m_reinhardTonemap->setParameter("source", 0);
|
||||
m_reinhardTonemap->setParameter("key", m_context->reinhardKey/logLuminance);
|
||||
m_reinhardTonemap->setParameter("multiplier", multiplier);
|
||||
m_reinhardTonemap->setParameter("invWpSqr", std::pow((Float) 2, m_context->reinhardBurn));
|
||||
|
@ -904,7 +1009,6 @@ void GLWidget::paintGL() {
|
|||
!m_hScroll->isVisible(), !m_vScroll->isVisible(),
|
||||
-m_context->scrollOffset);
|
||||
m_reinhardTonemap->unbind();
|
||||
buffer->unbind();
|
||||
}
|
||||
|
||||
if (m_context->mode == EPreview) {
|
||||
|
@ -917,19 +1021,14 @@ void GLWidget::paintGL() {
|
|||
}
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
Vector2 scrSize(viewport[2], viewport[3]);
|
||||
|
||||
if (scrSize.x > size.x || scrSize.y > size.y) {
|
||||
if (viewport[2] > size.x || viewport[3] > size.y) {
|
||||
/* Draw a border to highlight the region occupied by the image */
|
||||
Vector2i upperLeft((scrSize.x - size.x)/2,
|
||||
(scrSize.y - size.y)/2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
Vector2i upperLeft((viewport[2] - size.x)/2, (viewport[3] - size.y)/2);
|
||||
Vector2i lowerRight = upperLeft + Vector2i(size.x, size.y);
|
||||
|
||||
glColor4f(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(upperLeft.x, upperLeft.y);
|
||||
|
@ -939,10 +1038,81 @@ void GLWidget::paintGL() {
|
|||
glEnd();
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (m_context->mode == EPreview) {
|
||||
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>
|
||||
(m_context->scene->getCamera());
|
||||
m_renderer->setCamera(camera);
|
||||
|
||||
Point2i offset = upperLeft(true);
|
||||
|
||||
buffer->blit(NULL, GPUTexture::EDepthBuffer, Point2i(0, 0),
|
||||
size, offset, size);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
glViewport(offset.x, offset.y, size.x, size.y);
|
||||
m_renderer->setDepthTest(true);
|
||||
m_renderer->setDepthMask(false);
|
||||
m_renderer->setBlendMode(Renderer::EBlendAdditive);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
if (m_context->showKDTree) {
|
||||
oglRenderKDTree(m_context->scene->getKDTree());
|
||||
const std::vector<Shape *> shapes = m_context->scene->getShapes();
|
||||
for (size_t j=0; j<shapes.size(); ++j)
|
||||
if (shapes[j]->getKDTree())
|
||||
oglRenderKDTree(shapes[j]->getKDTree());
|
||||
}
|
||||
|
||||
if (m_navigationMode == EArcBall && m_gizmo->isActive())
|
||||
m_gizmo->draw(m_renderer, camera);
|
||||
|
||||
m_renderer->setBlendMode(Renderer::EBlendNone);
|
||||
m_renderer->setDepthTest(false);
|
||||
m_renderer->setDepthMask(true);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
}
|
||||
}
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void GLWidget::oglRenderKDTree(const KDTreeBase<AABB> *kdtree) {
|
||||
std::stack<boost::tuple<const KDTreeBase<AABB>::KDNode *, AABB, uint32_t> > stack;
|
||||
|
||||
stack.push(boost::make_tuple(kdtree->getRoot(), kdtree->getTightAABB(), 0));
|
||||
Float brightness = 0.1f;
|
||||
|
||||
while (!stack.empty()) {
|
||||
const KDTreeBase<AABB>::KDNode *node = boost::get<0>(stack.top());
|
||||
AABB aabb = boost::get<1>(stack.top());
|
||||
int level = boost::get<2>(stack.top());
|
||||
stack.pop();
|
||||
m_renderer->setColor(Spectrum(brightness));
|
||||
m_renderer->drawAABB(aabb);
|
||||
|
||||
if (!node->isLeaf()) {
|
||||
int axis = node->getAxis();
|
||||
float split = node->getSplit();
|
||||
if (level + 1 <= m_context->shownKDTreeLevel) {
|
||||
Float tmp = aabb.max[axis];
|
||||
aabb.max[axis] = split;
|
||||
stack.push(boost::make_tuple(node->getLeft(), aabb, level+1));
|
||||
aabb.max[axis] = tmp;
|
||||
aabb.min[axis] = split;
|
||||
stack.push(boost::make_tuple(node->getRight(), aabb, level+1));
|
||||
} else {
|
||||
aabb.min[axis] = split;
|
||||
aabb.max[axis] = split;
|
||||
Spectrum color;
|
||||
color.fromLinearRGB(0, 0, 4*brightness);
|
||||
m_renderer->setColor(color);
|
||||
m_renderer->drawAABB(aabb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLWidget::resizeEvent(QResizeEvent *event) {
|
||||
if (m_context && m_ignoreResizeEvents) {
|
||||
event->accept();
|
||||
|
@ -1052,6 +1222,18 @@ void GLWidget::onUpdateView() {
|
|||
m_framebufferChanged = true;
|
||||
}
|
||||
|
||||
Point2i GLWidget::upperLeft(bool flipY) const {
|
||||
if (!m_context)
|
||||
return Point2i(0, 0);
|
||||
Vector2i filmSize = m_context->scene->getCamera()->getFilm()->getSize();
|
||||
Vector2i deviceSize = m_device->getSize();
|
||||
|
||||
return Point2i(
|
||||
deviceSize.x < filmSize.x ? (-m_context->scrollOffset.x) : (deviceSize.x - filmSize.x)/2,
|
||||
deviceSize.y < filmSize.y ? (flipY ? (deviceSize.y-filmSize.y
|
||||
+ m_context->scrollOffset.y) : -m_context->scrollOffset.y) : (deviceSize.y - filmSize.y)/2);
|
||||
}
|
||||
|
||||
void GLWidget::resizeGL(int width, int height) {
|
||||
glViewport(0, 0, (GLint) width, (GLint) height);
|
||||
m_device->setSize(Vector2i(width, height));
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <mitsuba/hw/gpuprogram.h>
|
||||
#include <mitsuba/hw/gpusync.h>
|
||||
#include <mitsuba/hw/vpl.h>
|
||||
#include <mitsuba/hw/gizmo.h>
|
||||
#if defined(WIN32)
|
||||
#include <mitsuba/hw/wgldevice.h>
|
||||
#endif
|
||||
|
@ -99,6 +100,8 @@ protected:
|
|||
void wheelEvent(QWheelEvent *event);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void oglRenderKDTree(const KDTreeBase<AABB> *kdtree);
|
||||
Point2i upperLeft(bool flipY = false) const;
|
||||
|
||||
/* Masquerade QGLWidget as a GL device for libhw */
|
||||
#if defined(WIN32)
|
||||
|
@ -130,6 +133,7 @@ private:
|
|||
ref<GPUProgram> m_downsamplingProgram, m_luminanceProgram;
|
||||
ref<QtDevice> m_device;
|
||||
ref<Font> m_font;
|
||||
ref<Gizmo> m_gizmo;
|
||||
SceneContext *m_context;
|
||||
bool m_framebufferChanged, m_mouseButtonDown;
|
||||
bool m_leftKeyDown, m_rightKeyDown;
|
||||
|
@ -145,7 +149,9 @@ private:
|
|||
bool m_ignoreScrollEvents, m_ignoreResizeEvents;
|
||||
int m_mouseSensitivity, m_softwareFallback;
|
||||
ref<Bitmap> m_fallbackBitmap;
|
||||
ref<Timer> m_wheelTimer;
|
||||
QString m_errorString;
|
||||
Transform m_storedViewTransform;
|
||||
};
|
||||
|
||||
#endif /* __GLWIDGET_H */
|
||||
|
|
|
@ -141,7 +141,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
ui->glView->setInvertMouse(settings.value("invertMouse", false).toBool());
|
||||
ui->glView->setMouseSensitivity(settings.value("mouseSensitivity", 3).toInt());
|
||||
ui->glView->setNavigationMode((ENavigationMode) settings.value("navigationMode",
|
||||
EFlythrough).toInt());
|
||||
EArcBall).toInt());
|
||||
m_searchPaths = settings.value("searchPaths", QStringList()).toStringList();
|
||||
m_blockSize = settings.value("blockSize", 32).toInt();
|
||||
m_listenPort = settings.value("listenPort", MTS_DEFAULT_PORT).toInt();
|
||||
|
@ -1649,6 +1649,13 @@ QString ServerConnection::toString() const {
|
|||
|
||||
SceneContext::SceneContext(SceneContext *ctx) {
|
||||
if (ctx->scene) {
|
||||
/* Temporarily set up a new file resolver */
|
||||
ref<Thread> thread = Thread::getThread();
|
||||
ref<FileResolver> oldResolver = thread->getFileResolver();
|
||||
ref<FileResolver> newResolver = oldResolver->clone();
|
||||
newResolver->addPath(fs::complete(ctx->scene->getSourceFile()).parent_path());
|
||||
thread->setFileResolver(newResolver);
|
||||
|
||||
scene = new Scene(ctx->scene);
|
||||
ref<PluginManager> pluginMgr = PluginManager::getInstance();
|
||||
ref<PinholeCamera> oldCamera = static_cast<PinholeCamera *>(ctx->scene->getCamera());
|
||||
|
@ -1696,6 +1703,7 @@ SceneContext::SceneContext(SceneContext *ctx) {
|
|||
scene->configure();
|
||||
sceneResID = ctx->sceneResID;
|
||||
Scheduler::getInstance()->retainResource(sceneResID);
|
||||
thread->setFileResolver(oldResolver);
|
||||
} else {
|
||||
sceneResID = -1;
|
||||
renderJob = NULL;
|
||||
|
@ -1726,6 +1734,8 @@ SceneContext::SceneContext(SceneContext *ctx) {
|
|||
diffuseSources = ctx->diffuseSources;
|
||||
showKDTree = ctx->showKDTree;
|
||||
shownKDTreeLevel = ctx->shownKDTreeLevel;
|
||||
selectedShape = ctx->selectedShape;
|
||||
selectionMode = ctx->selectionMode;
|
||||
}
|
||||
|
||||
SceneContext::~SceneContext() {
|
||||
|
|
|
@ -469,7 +469,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_shaderManager->setVPL(vpl);
|
||||
|
||||
Point2 jitter(.5f, .5f);
|
||||
if (!m_motion && !m_context->showKDTree)
|
||||
if (!m_motion && !m_context->showKDTree && m_accumBuffer != NULL)
|
||||
jitter -= Vector2(m_random->nextFloat(), m_random->nextFloat());
|
||||
|
||||
m_mutex->lock();
|
||||
|
@ -494,13 +494,6 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_shaderManager->unbind();
|
||||
}
|
||||
m_renderer->endDrawingMeshes();
|
||||
if (m_context->showKDTree) {
|
||||
oglRenderKDTree(m_context->scene->getKDTree());
|
||||
const std::vector<Shape *> shapes = m_context->scene->getShapes();
|
||||
for (size_t j=0; j<shapes.size(); ++j)
|
||||
if (shapes[j]->getKDTree())
|
||||
oglRenderKDTree(shapes[j]->getKDTree());
|
||||
}
|
||||
m_shaderManager->drawBackground(clipToWorld, camPos);
|
||||
m_framebuffer->releaseTarget();
|
||||
|
||||
|
@ -511,6 +504,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
if (m_accumBuffer == NULL) {
|
||||
target.buffer->clear();
|
||||
m_renderer->blitTexture(m_framebuffer, true);
|
||||
m_framebuffer->blit(target.buffer, GPUTexture::EDepthBuffer);
|
||||
} else {
|
||||
m_accumBuffer->bind(1);
|
||||
m_accumProgram->bind();
|
||||
|
@ -519,9 +513,11 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
m_renderer->blitQuad(true);
|
||||
m_accumProgram->unbind();
|
||||
m_accumBuffer->unbind();
|
||||
m_accumBuffer->blit(target.buffer, GPUTexture::EDepthBuffer);
|
||||
}
|
||||
m_framebuffer->unbind();
|
||||
|
||||
m_renderer->setDepthMask(true);
|
||||
m_framebuffer->unbind();
|
||||
m_renderer->setDepthTest(true);
|
||||
target.buffer->releaseTarget();
|
||||
m_accumBuffer = target.buffer;
|
||||
|
@ -541,42 +537,6 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewThread::oglRenderKDTree(const KDTreeBase<AABB> *kdtree) {
|
||||
std::stack<boost::tuple<const KDTreeBase<AABB>::KDNode *, AABB, uint32_t> > stack;
|
||||
|
||||
stack.push(boost::make_tuple(kdtree->getRoot(), kdtree->getTightAABB(), 0));
|
||||
Float brightness = 10.0f;
|
||||
|
||||
while (!stack.empty()) {
|
||||
const KDTreeBase<AABB>::KDNode *node = boost::get<0>(stack.top());
|
||||
AABB aabb = boost::get<1>(stack.top());
|
||||
int level = boost::get<2>(stack.top());
|
||||
stack.pop();
|
||||
m_renderer->setColor(Spectrum(brightness));
|
||||
m_renderer->drawAABB(aabb);
|
||||
|
||||
if (!node->isLeaf()) {
|
||||
int axis = node->getAxis();
|
||||
float split = node->getSplit();
|
||||
if (level + 1 <= m_context->shownKDTreeLevel) {
|
||||
Float tmp = aabb.max[axis];
|
||||
aabb.max[axis] = split;
|
||||
stack.push(boost::make_tuple(node->getLeft(), aabb, level+1));
|
||||
aabb.max[axis] = tmp;
|
||||
aabb.min[axis] = split;
|
||||
stack.push(boost::make_tuple(node->getRight(), aabb, level+1));
|
||||
} else {
|
||||
aabb.min[axis] = split;
|
||||
aabb.max[axis] = split;
|
||||
Spectrum color;
|
||||
color.fromLinearRGB(0, 0, 2*brightness);
|
||||
m_renderer->setColor(color);
|
||||
m_renderer->drawAABB(aabb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||
Float nearClip = std::numeric_limits<Float>::infinity(),
|
||||
|
|
|
@ -74,8 +74,6 @@ protected:
|
|||
virtual ~PreviewThread();
|
||||
/// Render a single VPL using OpenGL
|
||||
void oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
|
||||
/// Render a wireframe visualization of a kd-tree
|
||||
void oglRenderKDTree(const KDTreeBase<AABB> *kdtree);
|
||||
/// Render a single VPL using real-time coherent ray tracing
|
||||
void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
|
||||
private:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>378</width>
|
||||
<height>531</height>
|
||||
<height>533</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -455,12 +455,14 @@ movements while navigating in the realt-time preview.</string>
|
|||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body>
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This option specifies the camera behavior when navigating within the realtime preview.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through (Fix yaw)</span>: Always yaw around a fixed &quot;up&quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Arcball</span>: Rotate around the scene or the currently selected object.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through</span>: Always yaw around the current camera &quot;up&quot; axis.</p></body></html></string>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">First person (Fix yaw)</span>: A first-person navigation mode that resembles walking through a scene (e.g. in a 3D game). This variant always yaws around a fixed &quot;up&quot; axis that is determined when the scene is loaded -- this is intuitive but assumes that the camera has already been set up correctly.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">First person</span>: As above, but always yaw around the current camera &quot;up&quot; axis.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Navigation :</string>
|
||||
|
@ -476,21 +478,28 @@ p, li { white-space: pre-wrap; }
|
|||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body>
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This option specifies the camera behavior when navigating within the realtime preview.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through (Fix yaw)</span>: Always yaw around a fixed &quot;up&quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Arcball</span>: Rotate around the scene or the currently selected object.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fly-through</span>: Always yaw around the current camera &quot;up&quot; axis.</p></body></html></string>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">First person (Fix yaw)</span>: A first-person navigation mode that resembles walking through a scene (e.g. in a 3D game). This variant always yaws around a fixed &quot;up&quot; axis that is determined when the scene is loaded -- this is intuitive but assumes that the camera has already been set up correctly.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">First person</span>: As above, but always yaw around the current camera &quot;up&quot; axis.</p></body></html></string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fly-through (Fix yaw)</string>
|
||||
<string>Arcball</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fly-through</string>
|
||||
<string>First person (Fix yaw)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>First Person</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "rendersettingsdlg.h"
|
||||
#include "ui_rendersettingsdlg.h"
|
||||
#include <mitsuba/core/plugin.h>
|
||||
#include <mitsuba/core/fresolver.h>
|
||||
|
||||
/* ====================== Some helper routines ====================== */
|
||||
|
||||
|
@ -305,6 +306,13 @@ void RenderSettingsDialog::apply(SceneContext *ctx) {
|
|||
Properties filmProps = oldCamera->getFilm()->getProperties();
|
||||
ref<PluginManager> pluginMgr = PluginManager::getInstance();
|
||||
|
||||
/* Temporarily set up a new file resolver */
|
||||
ref<Thread> thread = Thread::getThread();
|
||||
ref<FileResolver> oldResolver = thread->getFileResolver();
|
||||
ref<FileResolver> newResolver = oldResolver->clone();
|
||||
newResolver->addPath(fs::complete(scene->getSourceFile()).parent_path());
|
||||
thread->setFileResolver(newResolver);
|
||||
|
||||
/* Configure the reconstruction filter */
|
||||
Properties rFilterProps(getPluginName(ui->rFilterBox));
|
||||
if (m_rFilterNode != NULL)
|
||||
|
@ -384,6 +392,7 @@ void RenderSettingsDialog::apply(SceneContext *ctx) {
|
|||
scene->configure();
|
||||
|
||||
ctx->scene = scene;
|
||||
thread->setFileResolver(oldResolver);
|
||||
}
|
||||
|
||||
RenderSettingsDialog::~RenderSettingsDialog() {
|
||||
|
|
Loading…
Reference in New Issue