e955c94ed3
Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
835 lines
19 KiB
Python
835 lines
19 KiB
Python
# SPDX-FileCopyrightText: 2012-2022 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
# Currently this script only generates images from different modifier
|
|
# combinations and does not validate they work correctly,
|
|
# this is because we don't get 1:1 match with bmesh.
|
|
#
|
|
# Later, we may have a way to check the results are valid.
|
|
|
|
|
|
# ./blender.bin --factory-startup --python tests/python/bl_mesh_modifiers.py
|
|
#
|
|
|
|
import math
|
|
|
|
USE_QUICK_RENDER = False
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# utility functions
|
|
|
|
|
|
def render_gl(context, filepath, shade):
|
|
|
|
def ctx_shading_type(context, shade):
|
|
for area in context.window.screen.areas:
|
|
if area.type == 'VIEW_3D':
|
|
space = area.spaces.active
|
|
# rv3d = space.region_3d
|
|
space.shading.type = shade
|
|
|
|
import bpy
|
|
scene = context.scene
|
|
render = scene.render
|
|
render.filepath = filepath
|
|
render.image_settings.file_format = 'PNG'
|
|
render.image_settings.color_mode = 'RGB'
|
|
render.use_file_extension = True
|
|
render.use_antialiasing = False
|
|
|
|
# render size
|
|
render.resolution_percentage = 100
|
|
render.resolution_x = 512
|
|
render.resolution_y = 512
|
|
|
|
ctx_shading_type(context, shade)
|
|
|
|
# stop to inspect!
|
|
# if filepath == "test_cube_shell_solidify_subsurf_wp_wire":
|
|
# assert(0)
|
|
# else:
|
|
# return
|
|
|
|
bpy.ops.render.opengl(write_still=True,
|
|
view_context=True)
|
|
|
|
|
|
def render_gl_all_modes(context, obj, filepath=""):
|
|
|
|
assert obj is not None
|
|
assert filepath != ""
|
|
|
|
scene = context.scene
|
|
|
|
# avoid drawing outline/center dot
|
|
bpy.ops.object.select_all(action='DESELECT')
|
|
scene.objects.active = None
|
|
|
|
# editmode
|
|
scene.tool_settings.mesh_select_mode = False, True, False
|
|
|
|
# render
|
|
render_gl(context, filepath + "_ob_solid", shade='SOLID')
|
|
|
|
if USE_QUICK_RENDER:
|
|
return
|
|
|
|
render_gl(context, filepath + "_ob_wire", shade='WIREFRAME')
|
|
render_gl(context, filepath + "_ob_textured", shade='TEXTURED')
|
|
|
|
# -------------------------------------------------------------------------
|
|
# not just draw modes, but object modes!
|
|
scene.objects.active = obj
|
|
|
|
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
|
|
bpy.ops.mesh.select_all(action='DESELECT')
|
|
render_gl(context, filepath + "_edit_wire", shade='WIREFRAME')
|
|
render_gl(context, filepath + "_edit_solid", shade='SOLID')
|
|
render_gl(context, filepath + "_edit_textured", shade='TEXTURED')
|
|
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
|
|
|
bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)
|
|
|
|
render_gl(context, filepath + "_wp_wire", shade='WIREFRAME')
|
|
|
|
assert 1
|
|
|
|
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
|
|
|
scene.objects.active = None
|
|
|
|
|
|
def ctx_clear_scene(): # copied from batch_import.py
|
|
import bpy
|
|
unique_obs = set()
|
|
for scene in bpy.data.scenes:
|
|
for obj in scene.objects[:]:
|
|
scene.objects.unlink(obj)
|
|
unique_obs.add(obj)
|
|
|
|
# remove obdata, for now only worry about the startup scene
|
|
for bpy_data_iter in (bpy.data.objects,
|
|
bpy.data.meshes,
|
|
bpy.data.lights,
|
|
bpy.data.cameras,
|
|
):
|
|
|
|
for id_data in bpy_data_iter:
|
|
bpy_data_iter.remove(id_data)
|
|
|
|
|
|
def ctx_viewport_camera(context):
|
|
# because gl render without view_context has no shading option.
|
|
for area in context.window.screen.areas:
|
|
if area.type == 'VIEW_3D':
|
|
space = area.spaces.active
|
|
space.region_3d.view_perspective = 'CAMERA'
|
|
|
|
|
|
def ctx_camera_setup(context,
|
|
location=(0.0, 0.0, 0.0),
|
|
lookat=(0.0, 0.0, 0.0),
|
|
# most likely the following vars can be left as defaults
|
|
up=(0.0, 0.0, 1.0),
|
|
lookat_axis='-Z',
|
|
up_axis='Y',
|
|
):
|
|
|
|
camera = bpy.data.cameras.new(whoami())
|
|
obj = bpy.data.objects.new(whoami(), camera)
|
|
|
|
scene = context.scene
|
|
scene.objects.link(obj)
|
|
scene.camera = obj
|
|
|
|
from mathutils import Vector, Matrix
|
|
|
|
# setup transform
|
|
view_vec = Vector(lookat) - Vector(location)
|
|
rot_mat = view_vec.to_track_quat(lookat_axis, up_axis).to_matrix().to_4x4()
|
|
tra_mat = Matrix.Translation(location)
|
|
|
|
obj.matrix_world = tra_mat * rot_mat
|
|
|
|
ctx_viewport_camera(context)
|
|
|
|
return obj
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# inspect functions
|
|
|
|
import inspect
|
|
|
|
|
|
# functions
|
|
|
|
def whoami():
|
|
return inspect.stack()[1][3]
|
|
|
|
|
|
def whosdaddy():
|
|
return inspect.stack()[2][3]
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# models (defaults)
|
|
|
|
def defaults_object(obj):
|
|
obj.show_wire = True
|
|
|
|
if obj.type == 'MESH':
|
|
obj.show_all_edges = True
|
|
|
|
mesh = obj.data
|
|
|
|
mesh.show_normal_vertex = True
|
|
|
|
for poly in mesh.polygons:
|
|
poly.use_smooth = True
|
|
|
|
|
|
def defaults_modifier(mod):
|
|
mod.show_in_editmode = True
|
|
mod.show_on_cage = True
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# models (utils)
|
|
|
|
def mesh_bmesh_poly_elems(poly, elems):
|
|
vert_start = poly.loop_start
|
|
vert_total = poly.loop_total
|
|
return elems[vert_start:vert_start + vert_total]
|
|
|
|
|
|
def mesh_bmesh_poly_vertices(poly):
|
|
return [loop.vertex_index
|
|
for loop in mesh_bmesh_poly_elems(poly, poly.id_data.loops)]
|
|
|
|
|
|
def mesh_bounds(mesh):
|
|
xmin = ymin = zmin = +100000000.0
|
|
xmax = ymax = zmax = -100000000.0
|
|
|
|
for v in mesh.vertices:
|
|
x, y, z = v.co
|
|
xmax = max(x, xmax)
|
|
ymax = max(y, ymax)
|
|
zmax = max(z, zmax)
|
|
|
|
xmin = min(x, xmin)
|
|
ymin = min(y, ymin)
|
|
zmin = min(z, zmin)
|
|
|
|
return (xmin, ymin, zmin), (xmax, ymax, zmax)
|
|
|
|
|
|
def mesh_uv_add(obj):
|
|
|
|
uvs = ((0.0, 0.0),
|
|
(0.0, 1.0),
|
|
(1.0, 1.0),
|
|
(1.0, 0.0))
|
|
|
|
uv_lay = obj.data.uv_layers.new()
|
|
|
|
# XXX, odd that we need to do this. until UV's and texface
|
|
# are separated we will need to keep it
|
|
uv_loops = obj.data.uv_layers[-1]
|
|
uv_list = uv_loops.data[:]
|
|
for poly in obj.data.polygons:
|
|
poly_uvs = mesh_bmesh_poly_elems(poly, uv_list)
|
|
for i, c in enumerate(poly_uvs):
|
|
c.uv = uvs[i % 4]
|
|
|
|
return uv_lay
|
|
|
|
|
|
def mesh_vcol_add(obj, mode=0):
|
|
|
|
colors = ((0.0, 0.0, 0.0), # black
|
|
(1.0, 0.0, 0.0), # red
|
|
(0.0, 1.0, 0.0), # green
|
|
(0.0, 0.0, 1.0), # blue
|
|
(1.0, 1.0, 0.0), # yellow
|
|
(0.0, 1.0, 1.0), # cyan
|
|
(1.0, 0.0, 1.0), # magenta
|
|
(1.0, 1.0, 1.0), # white
|
|
)
|
|
|
|
def colors_get(i):
|
|
return colors[i % len(colors)]
|
|
|
|
vcol_lay = obj.data.vertex_colors.new()
|
|
|
|
mesh = obj.data
|
|
|
|
col_list = vcol_lay.data[:]
|
|
for poly in mesh.polygons:
|
|
face_verts = mesh_bmesh_poly_vertices(poly)
|
|
poly_cols = mesh_bmesh_poly_elems(poly, col_list)
|
|
for i, c in enumerate(poly_cols):
|
|
c.color = colors_get(face_verts[i])
|
|
|
|
return vcol_lay
|
|
|
|
|
|
def mesh_vgroup_add(obj, name="Group", axis=0, invert=False, mode=0):
|
|
mesh = obj.data
|
|
vgroup = obj.vertex_groups.new(name=name)
|
|
vgroup.add(list(range(len(mesh.vertices))), 1.0, 'REPLACE')
|
|
group_index = len(obj.vertex_groups) - 1
|
|
|
|
min_bb, max_bb = mesh_bounds(mesh)
|
|
|
|
range_axis = max_bb[axis] - min_bb[axis]
|
|
|
|
# gradient
|
|
for v in mesh.vertices:
|
|
for vg in v.groups:
|
|
if vg.group == group_index:
|
|
f = (v.co[axis] - min_bb[axis]) / range_axis
|
|
vg.weight = 1.0 - f if invert else f
|
|
|
|
return vgroup
|
|
|
|
|
|
def mesh_shape_add(obj, mode=0):
|
|
pass
|
|
|
|
|
|
def mesh_armature_add(obj, mode=0):
|
|
pass
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# modifiers
|
|
|
|
def modifier_subsurf_add(scene, obj, levels=2):
|
|
mod = obj.modifiers.new(name=whoami(), type='SUBSURF')
|
|
defaults_modifier(mod)
|
|
|
|
mod.levels = levels
|
|
mod.render_levels = levels
|
|
return mod
|
|
|
|
|
|
def modifier_armature_add(scene, obj):
|
|
mod = obj.modifiers.new(name=whoami(), type='ARMATURE')
|
|
defaults_modifier(mod)
|
|
|
|
arm_data = bpy.data.armatures.new(whoami())
|
|
obj_arm = bpy.data.objects.new(whoami(), arm_data)
|
|
|
|
scene.objects.link(obj_arm)
|
|
|
|
obj_arm.select = True
|
|
scene.objects.active = obj_arm
|
|
|
|
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
|
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
|
|
|
|
# XXX, annoying, remove bone.
|
|
while arm_data.edit_bones:
|
|
obj_arm.edit_bones.remove(arm_data.edit_bones[-1])
|
|
|
|
bone_a = arm_data.edit_bones.new("Bone.A")
|
|
bone_b = arm_data.edit_bones.new("Bone.B")
|
|
bone_b.parent = bone_a
|
|
|
|
bone_a.head = -1, 0, 0
|
|
bone_a.tail = 0, 0, 0
|
|
bone_b.head = 0, 0, 0
|
|
bone_b.tail = 1, 0, 0
|
|
|
|
# Get armature animation data
|
|
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
|
|
|
# 45d armature
|
|
obj_arm.pose.bones["Bone.B"].rotation_quaternion = 1, -0.5, 0, 0
|
|
|
|
# set back to the original
|
|
scene.objects.active = obj
|
|
|
|
# display options
|
|
obj_arm.show_in_front = True
|
|
arm_data.draw_type = 'STICK'
|
|
|
|
# apply to modifier
|
|
mod.object = obj_arm
|
|
|
|
mesh_vgroup_add(obj, name="Bone.A", axis=0, invert=True)
|
|
mesh_vgroup_add(obj, name="Bone.B", axis=0, invert=False)
|
|
|
|
return mod
|
|
|
|
|
|
def modifier_mirror_add(scene, obj):
|
|
mod = obj.modifiers.new(name=whoami(), type='MIRROR')
|
|
defaults_modifier(mod)
|
|
|
|
return mod
|
|
|
|
|
|
def modifier_solidify_add(scene, obj, thickness=0.25):
|
|
mod = obj.modifiers.new(name=whoami(), type='SOLIDIFY')
|
|
defaults_modifier(mod)
|
|
|
|
mod.thickness = thickness
|
|
|
|
return mod
|
|
|
|
|
|
def modifier_hook_add(scene, obj, use_vgroup=True):
|
|
scene.objects.active = obj
|
|
|
|
# no nice way to add hooks from py api yet
|
|
# assume object mode, hook first face!
|
|
mesh = obj.data
|
|
|
|
if use_vgroup:
|
|
for v in mesh.vertices:
|
|
v.select = True
|
|
else:
|
|
for v in mesh.vertices:
|
|
v.select = False
|
|
|
|
for i in mesh.faces[0].vertices:
|
|
mesh.vertices[i].select = True
|
|
|
|
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
|
|
bpy.ops.object.hook_add_newob()
|
|
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
|
|
|
# mod = obj.modifiers.new(name=whoami(), type='HOOK')
|
|
mod = obj.modifiers[-1]
|
|
defaults_modifier(mod)
|
|
|
|
obj_hook = mod.object
|
|
obj_hook.rotation_euler = 0, math.radians(45), 0
|
|
obj_hook.show_in_front = True
|
|
|
|
if use_vgroup:
|
|
mod.vertex_group = obj.vertex_groups[0].name
|
|
|
|
return mod
|
|
|
|
|
|
def modifier_decimate_add(scene, obj):
|
|
mod = obj.modifiers.new(name=whoami(), type='DECIMATE')
|
|
defaults_modifier(mod)
|
|
|
|
mod.ratio = 1 / 3
|
|
|
|
return mod
|
|
|
|
|
|
def modifier_build_add(scene, obj):
|
|
mod = obj.modifiers.new(name=whoami(), type='BUILD')
|
|
defaults_modifier(mod)
|
|
|
|
# ensure we display some faces
|
|
totface = len(obj.data.polygons)
|
|
|
|
mod.frame_start = totface // 2
|
|
mod.frame_duration = totface
|
|
|
|
return mod
|
|
|
|
|
|
def modifier_mask_add(scene, obj):
|
|
mod = obj.modifiers.new(name=whoami(), type='MASK')
|
|
defaults_modifier(mod)
|
|
|
|
mod.vertex_group = obj.vertex_groups[0].name
|
|
|
|
return mod
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# models
|
|
|
|
# useful since its solid boxy shape but simple enough to debug errors
|
|
cube_like_vertices = (
|
|
(1, 1, -1),
|
|
(1, -1, -1),
|
|
(-1, -1, -1),
|
|
(-1, 1, -1),
|
|
(1, 1, 1),
|
|
(1, -1, 1),
|
|
(-1, -1, 1),
|
|
(-1, 1, 1),
|
|
(0, -1, -1),
|
|
(1, 0, -1),
|
|
(0, 1, -1),
|
|
(-1, 0, -1),
|
|
(1, 0, 1),
|
|
(0, -1, 1),
|
|
(-1, 0, 1),
|
|
(0, 1, 1),
|
|
(1, -1, 0),
|
|
(1, 1, 0),
|
|
(-1, -1, 0),
|
|
(-1, 1, 0),
|
|
(0, 0, -1),
|
|
(0, 0, 1),
|
|
(1, 0, 0),
|
|
(0, -1, 0),
|
|
(-1, 0, 0),
|
|
(2, 0, 0),
|
|
(2, 0, -1),
|
|
(2, 1, 0),
|
|
(2, 1, -1),
|
|
(0, 1, 2),
|
|
(0, 0, 2),
|
|
(-1, 0, 2),
|
|
(-1, 1, 2),
|
|
(-1, 0, 3),
|
|
(-1, 1, 3),
|
|
(0, 1, 3),
|
|
(0, 0, 3),
|
|
)
|
|
|
|
|
|
cube_like_faces = (
|
|
(0, 9, 20, 10),
|
|
(0, 10, 17),
|
|
(0, 17, 27, 28),
|
|
(1, 16, 23, 8),
|
|
(2, 18, 24, 11),
|
|
(3, 19, 10),
|
|
(4, 15, 21, 12),
|
|
(4, 17, 15),
|
|
(7, 14, 31, 32),
|
|
(7, 15, 19),
|
|
(8, 23, 18, 2),
|
|
(9, 0, 28, 26),
|
|
(9, 1, 8, 20),
|
|
(9, 22, 16, 1),
|
|
(10, 20, 11, 3),
|
|
(11, 24, 19, 3),
|
|
(12, 21, 13, 5),
|
|
(13, 6, 18),
|
|
(14, 21, 30, 31),
|
|
(15, 7, 32, 29),
|
|
(15, 17, 10, 19),
|
|
(16, 5, 13, 23),
|
|
(17, 4, 12, 22),
|
|
(17, 22, 25, 27),
|
|
(18, 6, 14, 24),
|
|
(20, 8, 2, 11),
|
|
(21, 14, 6, 13),
|
|
(21, 15, 29, 30),
|
|
(22, 9, 26, 25),
|
|
(22, 12, 5, 16),
|
|
(23, 13, 18),
|
|
(24, 14, 7, 19),
|
|
(28, 27, 25, 26),
|
|
(29, 32, 34, 35),
|
|
(30, 29, 35, 36),
|
|
(31, 30, 36, 33),
|
|
(32, 31, 33, 34),
|
|
(35, 34, 33, 36),
|
|
)
|
|
|
|
|
|
# useful since its a shell for solidify and it can be mirrored
|
|
cube_shell_vertices = (
|
|
(0, 0, 1),
|
|
(0, 1, 1),
|
|
(-1, 1, 1),
|
|
(-1, 0, 1),
|
|
(0, 0, 0),
|
|
(0, 1, 0),
|
|
(-1, 1, 0),
|
|
(-1, 0, 0),
|
|
(-1, -1, 0),
|
|
(0, -1, 0),
|
|
(0, 0, -1),
|
|
(0, 1, -1),
|
|
)
|
|
|
|
|
|
cube_shell_face = (
|
|
(0, 1, 2, 3),
|
|
(0, 3, 8, 9),
|
|
(1, 5, 6, 2),
|
|
(2, 6, 7, 3),
|
|
(3, 7, 8),
|
|
(4, 7, 10),
|
|
(6, 5, 11),
|
|
(7, 4, 9, 8),
|
|
(10, 7, 6, 11),
|
|
)
|
|
|
|
|
|
def make_cube(scene):
|
|
bpy.ops.mesh.primitive_cube_add(align='WORLD',
|
|
enter_editmode=False,
|
|
location=(0, 0, 0),
|
|
rotation=(0, 0, 0),
|
|
)
|
|
|
|
obj = scene.objects.active
|
|
|
|
defaults_object(obj)
|
|
return obj
|
|
|
|
|
|
def make_cube_extra(scene):
|
|
obj = make_cube(scene)
|
|
|
|
# extra data layers
|
|
mesh_uv_add(obj)
|
|
mesh_vcol_add(obj)
|
|
mesh_vgroup_add(obj)
|
|
|
|
return obj
|
|
|
|
|
|
def make_cube_like(scene):
|
|
mesh = bpy.data.meshes.new(whoami())
|
|
|
|
mesh.from_pydata(cube_like_vertices, (), cube_like_faces)
|
|
mesh.update() # add edges
|
|
obj = bpy.data.objects.new(whoami(), mesh)
|
|
scene.objects.link(obj)
|
|
|
|
defaults_object(obj)
|
|
return obj
|
|
|
|
|
|
def make_cube_like_extra(scene):
|
|
obj = make_cube_like(scene)
|
|
|
|
# extra data layers
|
|
mesh_uv_add(obj)
|
|
mesh_vcol_add(obj)
|
|
mesh_vgroup_add(obj)
|
|
|
|
return obj
|
|
|
|
|
|
def make_cube_shell(scene):
|
|
mesh = bpy.data.meshes.new(whoami())
|
|
|
|
mesh.from_pydata(cube_shell_vertices, (), cube_shell_face)
|
|
mesh.update() # add edges
|
|
obj = bpy.data.objects.new(whoami(), mesh)
|
|
scene.objects.link(obj)
|
|
|
|
defaults_object(obj)
|
|
return obj
|
|
|
|
|
|
def make_cube_shell_extra(scene):
|
|
obj = make_cube_shell(scene)
|
|
|
|
# extra data layers
|
|
mesh_uv_add(obj)
|
|
mesh_vcol_add(obj)
|
|
mesh_vgroup_add(obj)
|
|
|
|
return obj
|
|
|
|
|
|
def make_monkey(scene):
|
|
bpy.ops.mesh.primitive_monkey_add(align='WORLD',
|
|
enter_editmode=False,
|
|
location=(0, 0, 0),
|
|
rotation=(0, 0, 0),
|
|
)
|
|
obj = scene.objects.active
|
|
|
|
defaults_object(obj)
|
|
return obj
|
|
|
|
|
|
def make_monkey_extra(scene):
|
|
obj = make_monkey(scene)
|
|
|
|
# extra data layers
|
|
mesh_uv_add(obj)
|
|
mesh_vcol_add(obj)
|
|
mesh_vgroup_add(obj)
|
|
|
|
return obj
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# tests (utils)
|
|
|
|
global_tests = []
|
|
|
|
global_tests.append(
|
|
("none",
|
|
(),
|
|
)
|
|
)
|
|
# single
|
|
global_tests.append(
|
|
("subsurf_single",
|
|
((modifier_subsurf_add, dict(levels=2)), ),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("armature_single",
|
|
((modifier_armature_add, dict()), ),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("mirror_single",
|
|
((modifier_mirror_add, dict()), ),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("hook_single",
|
|
((modifier_hook_add, dict()), ),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("decimate_single",
|
|
((modifier_decimate_add, dict()), ),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("build_single",
|
|
((modifier_build_add, dict()), ),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("mask_single",
|
|
((modifier_mask_add, dict()), ),
|
|
)
|
|
)
|
|
|
|
|
|
# combinations
|
|
global_tests.append(
|
|
("mirror_subsurf",
|
|
((modifier_mirror_add, dict()),
|
|
(modifier_subsurf_add, dict(levels=2))),
|
|
)
|
|
)
|
|
|
|
global_tests.append(
|
|
("solidify_subsurf",
|
|
((modifier_solidify_add, dict()),
|
|
(modifier_subsurf_add, dict(levels=2))),
|
|
)
|
|
)
|
|
|
|
|
|
def apply_test(
|
|
test, scene, obj,
|
|
render_func=None,
|
|
render_args=None,
|
|
render_kwargs=None,
|
|
):
|
|
|
|
test_name, test_funcs = test
|
|
|
|
for cb, kwargs in test_funcs:
|
|
cb(scene, obj, **kwargs)
|
|
|
|
render_kwargs_copy = render_kwargs.copy()
|
|
|
|
# add test name in filepath
|
|
render_kwargs_copy["filepath"] += "_%s" % test_name
|
|
|
|
render_func(*render_args, **render_kwargs_copy)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# tests themselves!
|
|
# having the 'test_' prefix automatically means these functions are called
|
|
# for testing
|
|
|
|
|
|
def test_cube(context, test):
|
|
scene = context.scene
|
|
obj = make_cube_extra(scene)
|
|
ctx_camera_setup(context, location=(3, 3, 3))
|
|
|
|
apply_test(
|
|
test, scene, obj,
|
|
render_func=render_gl_all_modes,
|
|
render_args=(context, obj),
|
|
render_kwargs=dict(filepath=whoami())
|
|
)
|
|
|
|
|
|
def test_cube_like(context, test):
|
|
scene = context.scene
|
|
obj = make_cube_like_extra(scene)
|
|
ctx_camera_setup(context, location=(5, 5, 5))
|
|
|
|
apply_test(
|
|
test, scene, obj,
|
|
render_func=render_gl_all_modes,
|
|
render_args=(context, obj),
|
|
render_kwargs=dict(filepath=whoami())
|
|
)
|
|
|
|
|
|
def test_cube_shell(context, test):
|
|
scene = context.scene
|
|
obj = make_cube_shell_extra(scene)
|
|
ctx_camera_setup(context, location=(4, 4, 4))
|
|
|
|
apply_test(
|
|
test, scene, obj,
|
|
render_func=render_gl_all_modes,
|
|
render_args=(context, obj),
|
|
render_kwargs=dict(filepath=whoami())
|
|
)
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# call all tests
|
|
|
|
def main():
|
|
print("Calling main!")
|
|
# render_gl(bpy.context, "/testme")
|
|
# ctx_clear_scene()
|
|
|
|
context = bpy.context
|
|
|
|
ctx_clear_scene()
|
|
|
|
# run all tests
|
|
for key, val in sorted(globals().items()):
|
|
if key.startswith("test_") and hasattr(val, "__call__"):
|
|
print("calling:", key)
|
|
for t in global_tests:
|
|
val(context, test=t)
|
|
ctx_clear_scene()
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# annoying workaround for theme initialization
|
|
|
|
if __name__ == "__main__":
|
|
import bpy
|
|
from bpy.app.handlers import persistent
|
|
|
|
@persistent
|
|
def load_handler(dummy):
|
|
print("Load Handler:", bpy.data.filepath)
|
|
if load_handler.first is False:
|
|
bpy.app.handlers.scene_update_post.remove(load_handler)
|
|
main()
|
|
else:
|
|
load_handler.first = False
|
|
|
|
load_handler.first = True
|
|
bpy.app.handlers.scene_update_post.append(load_handler)
|